Path: blob/master/arch/cris/arch-v32/drivers/sync_serial.c
15126 views
/*1* Simple synchronous serial port driver for ETRAX FS and Artpec-3.2*3* Copyright (c) 2005 Axis Communications AB4*5* Author: Mikael Starvik6*7*/89#include <linux/module.h>10#include <linux/kernel.h>11#include <linux/types.h>12#include <linux/errno.h>13#include <linux/major.h>14#include <linux/sched.h>15#include <linux/mutex.h>16#include <linux/interrupt.h>17#include <linux/poll.h>18#include <linux/init.h>19#include <linux/timer.h>20#include <linux/spinlock.h>2122#include <asm/io.h>23#include <dma.h>24#include <pinmux.h>25#include <hwregs/reg_rdwr.h>26#include <hwregs/sser_defs.h>27#include <hwregs/dma_defs.h>28#include <hwregs/dma.h>29#include <hwregs/intr_vect_defs.h>30#include <hwregs/intr_vect.h>31#include <hwregs/reg_map.h>32#include <asm/sync_serial.h>333435/* The receiver is a bit tricky because of the continuous stream of data.*/36/* */37/* Three DMA descriptors are linked together. Each DMA descriptor is */38/* responsible for port->bufchunk of a common buffer. */39/* */40/* +---------------------------------------------+ */41/* | +----------+ +----------+ +----------+ | */42/* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+ */43/* +----------+ +----------+ +----------+ */44/* | | | */45/* v v v */46/* +-------------------------------------+ */47/* | BUFFER | */48/* +-------------------------------------+ */49/* |<- data_avail ->| */50/* readp writep */51/* */52/* If the application keeps up the pace readp will be right after writep.*/53/* If the application can't keep the pace we have to throw away data. */54/* The idea is that readp should be ready with the data pointed out by */55/* Descr[i] when the DMA has filled in Descr[i+1]. */56/* Otherwise we will discard */57/* the rest of the data pointed out by Descr1 and set readp to the start */58/* of Descr2 */5960#define SYNC_SERIAL_MAJOR 1256162/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */63/* words can be handled */64#define IN_BUFFER_SIZE 1228865#define IN_DESCR_SIZE 25666#define NBR_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE)6768#define OUT_BUFFER_SIZE 1024*869#define NBR_OUT_DESCR 87071#define DEFAULT_FRAME_RATE 072#define DEFAULT_WORD_RATE 77374/* NOTE: Enabling some debug will likely cause overrun or underrun,75* especially if manual mode is use.76*/77#define DEBUG(x)78#define DEBUGREAD(x)79#define DEBUGWRITE(x)80#define DEBUGPOLL(x)81#define DEBUGRXINT(x)82#define DEBUGTXINT(x)83#define DEBUGTRDMA(x)84#define DEBUGOUTBUF(x)8586typedef struct sync_port87{88reg_scope_instances regi_sser;89reg_scope_instances regi_dmain;90reg_scope_instances regi_dmaout;9192char started; /* 1 if port has been started */93char port_nbr; /* Port 0 or 1 */94char busy; /* 1 if port is busy */9596char enabled; /* 1 if port is enabled */97char use_dma; /* 1 if port uses dma */98char tr_running;99100char init_irqs;101int output;102int input;103104/* Next byte to be read by application */105volatile unsigned char *volatile readp;106/* Next byte to be written by etrax */107volatile unsigned char *volatile writep;108109unsigned int in_buffer_size;110unsigned int inbufchunk;111unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32)));112unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32)));113unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32)));114struct dma_descr_data* next_rx_desc;115struct dma_descr_data* prev_rx_desc;116117/* Pointer to the first available descriptor in the ring,118* unless active_tr_descr == catch_tr_descr and a dma119* transfer is active */120struct dma_descr_data *active_tr_descr;121122/* Pointer to the first allocated descriptor in the ring */123struct dma_descr_data *catch_tr_descr;124125/* Pointer to the descriptor with the current end-of-list */126struct dma_descr_data *prev_tr_descr;127int full;128129/* Pointer to the first byte being read by DMA130* or current position in out_buffer if not using DMA. */131unsigned char *out_rd_ptr;132133/* Number of bytes currently locked for being read by DMA */134int out_buf_count;135136dma_descr_data in_descr[NBR_IN_DESCR] __attribute__ ((__aligned__(16)));137dma_descr_context in_context __attribute__ ((__aligned__(32)));138dma_descr_data out_descr[NBR_OUT_DESCR]139__attribute__ ((__aligned__(16)));140dma_descr_context out_context __attribute__ ((__aligned__(32)));141wait_queue_head_t out_wait_q;142wait_queue_head_t in_wait_q;143144spinlock_t lock;145} sync_port;146147static DEFINE_MUTEX(sync_serial_mutex);148static int etrax_sync_serial_init(void);149static void initialize_port(int portnbr);150static inline int sync_data_avail(struct sync_port *port);151152static int sync_serial_open(struct inode *, struct file*);153static int sync_serial_release(struct inode*, struct file*);154static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);155156static int sync_serial_ioctl(struct file *,157unsigned int cmd, unsigned long arg);158static ssize_t sync_serial_write(struct file * file, const char * buf,159size_t count, loff_t *ppos);160static ssize_t sync_serial_read(struct file *file, char *buf,161size_t count, loff_t *ppos);162163#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \164defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \165(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \166defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))167#define SYNC_SER_DMA168#endif169170static void send_word(sync_port* port);171static void start_dma_out(struct sync_port *port, const char *data, int count);172static void start_dma_in(sync_port* port);173#ifdef SYNC_SER_DMA174static irqreturn_t tr_interrupt(int irq, void *dev_id);175static irqreturn_t rx_interrupt(int irq, void *dev_id);176#endif177178#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \179!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \180(defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \181!defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))182#define SYNC_SER_MANUAL183#endif184#ifdef SYNC_SER_MANUAL185static irqreturn_t manual_interrupt(int irq, void *dev_id);186#endif187188#ifdef CONFIG_ETRAXFS /* ETRAX FS */189#define OUT_DMA_NBR 4190#define IN_DMA_NBR 5191#define PINMUX_SSER pinmux_sser0192#define SYNCSER_INST regi_sser0193#define SYNCSER_INTR_VECT SSER0_INTR_VECT194#define OUT_DMA_INST regi_dma4195#define IN_DMA_INST regi_dma5196#define DMA_OUT_INTR_VECT DMA4_INTR_VECT197#define DMA_IN_INTR_VECT DMA5_INTR_VECT198#define REQ_DMA_SYNCSER dma_sser0199#else /* Artpec-3 */200#define OUT_DMA_NBR 6201#define IN_DMA_NBR 7202#define PINMUX_SSER pinmux_sser203#define SYNCSER_INST regi_sser204#define SYNCSER_INTR_VECT SSER_INTR_VECT205#define OUT_DMA_INST regi_dma6206#define IN_DMA_INST regi_dma7207#define DMA_OUT_INTR_VECT DMA6_INTR_VECT208#define DMA_IN_INTR_VECT DMA7_INTR_VECT209#define REQ_DMA_SYNCSER dma_sser210#endif211212/* The ports */213static struct sync_port ports[]=214{215{216.regi_sser = SYNCSER_INST,217.regi_dmaout = OUT_DMA_INST,218.regi_dmain = IN_DMA_INST,219#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)220.use_dma = 1,221#else222.use_dma = 0,223#endif224}225#ifdef CONFIG_ETRAXFS226,227228{229.regi_sser = regi_sser1,230.regi_dmaout = regi_dma6,231.regi_dmain = regi_dma7,232#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)233.use_dma = 1,234#else235.use_dma = 0,236#endif237}238#endif239};240241#define NBR_PORTS ARRAY_SIZE(ports)242243static const struct file_operations sync_serial_fops = {244.owner = THIS_MODULE,245.write = sync_serial_write,246.read = sync_serial_read,247.poll = sync_serial_poll,248.unlocked_ioctl = sync_serial_ioctl,249.open = sync_serial_open,250.release = sync_serial_release,251.llseek = noop_llseek,252};253254static int __init etrax_sync_serial_init(void)255{256ports[0].enabled = 0;257#ifdef CONFIG_ETRAXFS258ports[1].enabled = 0;259#endif260if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial",261&sync_serial_fops) < 0) {262printk(KERN_WARNING263"Unable to get major for synchronous serial port\n");264return -EBUSY;265}266267/* Initialize Ports */268#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0)269if (crisv32_pinmux_alloc_fixed(PINMUX_SSER)) {270printk(KERN_WARNING271"Unable to alloc pins for synchronous serial port 0\n");272return -EIO;273}274ports[0].enabled = 1;275initialize_port(0);276#endif277278#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)279if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) {280printk(KERN_WARNING281"Unable to alloc pins for synchronous serial port 0\n");282return -EIO;283}284ports[1].enabled = 1;285initialize_port(1);286#endif287288#ifdef CONFIG_ETRAXFS289printk(KERN_INFO "ETRAX FS synchronous serial port driver\n");290#else291printk(KERN_INFO "Artpec-3 synchronous serial port driver\n");292#endif293return 0;294}295296static void __init initialize_port(int portnbr)297{298int __attribute__((unused)) i;299struct sync_port *port = &ports[portnbr];300reg_sser_rw_cfg cfg = {0};301reg_sser_rw_frm_cfg frm_cfg = {0};302reg_sser_rw_tr_cfg tr_cfg = {0};303reg_sser_rw_rec_cfg rec_cfg = {0};304305DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr));306307port->port_nbr = portnbr;308port->init_irqs = 1;309310port->out_rd_ptr = port->out_buffer;311port->out_buf_count = 0;312313port->output = 1;314port->input = 0;315316port->readp = port->flip;317port->writep = port->flip;318port->in_buffer_size = IN_BUFFER_SIZE;319port->inbufchunk = IN_DESCR_SIZE;320port->next_rx_desc = &port->in_descr[0];321port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR-1];322port->prev_rx_desc->eol = 1;323324init_waitqueue_head(&port->out_wait_q);325init_waitqueue_head(&port->in_wait_q);326327spin_lock_init(&port->lock);328329cfg.out_clk_src = regk_sser_intern_clk;330cfg.out_clk_pol = regk_sser_pos;331cfg.clk_od_mode = regk_sser_no;332cfg.clk_dir = regk_sser_out;333cfg.gate_clk = regk_sser_no;334cfg.base_freq = regk_sser_f29_493;335cfg.clk_div = 256;336REG_WR(sser, port->regi_sser, rw_cfg, cfg);337338frm_cfg.wordrate = DEFAULT_WORD_RATE;339frm_cfg.type = regk_sser_edge;340frm_cfg.frame_pin_dir = regk_sser_out;341frm_cfg.frame_pin_use = regk_sser_frm;342frm_cfg.status_pin_dir = regk_sser_in;343frm_cfg.status_pin_use = regk_sser_hold;344frm_cfg.out_on = regk_sser_tr;345frm_cfg.tr_delay = 1;346REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg);347348tr_cfg.urun_stop = regk_sser_no;349tr_cfg.sample_size = 7;350tr_cfg.sh_dir = regk_sser_msbfirst;351tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;352#if 0353tr_cfg.rate_ctrl = regk_sser_bulk;354tr_cfg.data_pin_use = regk_sser_dout;355#else356tr_cfg.rate_ctrl = regk_sser_iso;357tr_cfg.data_pin_use = regk_sser_dout;358#endif359tr_cfg.bulk_wspace = 1;360REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);361362rec_cfg.sample_size = 7;363rec_cfg.sh_dir = regk_sser_msbfirst;364rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no;365rec_cfg.fifo_thr = regk_sser_inf;366REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);367368#ifdef SYNC_SER_DMA369/* Setup the descriptor ring for dma out/transmit. */370for (i = 0; i < NBR_OUT_DESCR; i++) {371port->out_descr[i].wait = 0;372port->out_descr[i].intr = 1;373port->out_descr[i].eol = 0;374port->out_descr[i].out_eop = 0;375port->out_descr[i].next =376(dma_descr_data *)virt_to_phys(&port->out_descr[i+1]);377}378379/* Create a ring from the list. */380port->out_descr[NBR_OUT_DESCR-1].next =381(dma_descr_data *)virt_to_phys(&port->out_descr[0]);382383/* Setup context for traversing the ring. */384port->active_tr_descr = &port->out_descr[0];385port->prev_tr_descr = &port->out_descr[NBR_OUT_DESCR-1];386port->catch_tr_descr = &port->out_descr[0];387#endif388}389390static inline int sync_data_avail(struct sync_port *port)391{392int avail;393unsigned char *start;394unsigned char *end;395396start = (unsigned char*)port->readp; /* cast away volatile */397end = (unsigned char*)port->writep; /* cast away volatile */398/* 0123456789 0123456789399* ----- - -----400* ^rp ^wp ^wp ^rp401*/402403if (end >= start)404avail = end - start;405else406avail = port->in_buffer_size - (start - end);407return avail;408}409410static inline int sync_data_avail_to_end(struct sync_port *port)411{412int avail;413unsigned char *start;414unsigned char *end;415416start = (unsigned char*)port->readp; /* cast away volatile */417end = (unsigned char*)port->writep; /* cast away volatile */418/* 0123456789 0123456789419* ----- -----420* ^rp ^wp ^wp ^rp421*/422423if (end >= start)424avail = end - start;425else426avail = port->flip + port->in_buffer_size - start;427return avail;428}429430static int sync_serial_open(struct inode *inode, struct file *file)431{432int dev = iminor(inode);433int ret = -EBUSY;434sync_port *port;435reg_dma_rw_cfg cfg = {.en = regk_dma_yes};436reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes};437438mutex_lock(&sync_serial_mutex);439DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev));440441if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)442{443DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev));444ret = -ENODEV;445goto out;446}447port = &ports[dev];448/* Allow open this device twice (assuming one reader and one writer) */449if (port->busy == 2)450{451DEBUG(printk(KERN_DEBUG "Device is busy.. \n"));452goto out;453}454455456if (port->init_irqs) {457if (port->use_dma) {458if (port == &ports[0]) {459#ifdef SYNC_SER_DMA460if (request_irq(DMA_OUT_INTR_VECT,461tr_interrupt,4620,463"synchronous serial 0 dma tr",464&ports[0])) {465printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ");466goto out;467} else if (request_irq(DMA_IN_INTR_VECT,468rx_interrupt,4690,470"synchronous serial 1 dma rx",471&ports[0])) {472free_irq(DMA_OUT_INTR_VECT, &port[0]);473printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ");474goto out;475} else if (crisv32_request_dma(OUT_DMA_NBR,476"synchronous serial 0 dma tr",477DMA_VERBOSE_ON_ERROR,4780,479REQ_DMA_SYNCSER)) {480free_irq(DMA_OUT_INTR_VECT, &port[0]);481free_irq(DMA_IN_INTR_VECT, &port[0]);482printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel");483goto out;484} else if (crisv32_request_dma(IN_DMA_NBR,485"synchronous serial 0 dma rec",486DMA_VERBOSE_ON_ERROR,4870,488REQ_DMA_SYNCSER)) {489crisv32_free_dma(OUT_DMA_NBR);490free_irq(DMA_OUT_INTR_VECT, &port[0]);491free_irq(DMA_IN_INTR_VECT, &port[0]);492printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel");493goto out;494}495#endif496}497#ifdef CONFIG_ETRAXFS498else if (port == &ports[1]) {499#ifdef SYNC_SER_DMA500if (request_irq(DMA6_INTR_VECT,501tr_interrupt,5020,503"synchronous serial 1 dma tr",504&ports[1])) {505printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ");506goto out;507} else if (request_irq(DMA7_INTR_VECT,508rx_interrupt,5090,510"synchronous serial 1 dma rx",511&ports[1])) {512free_irq(DMA6_INTR_VECT, &ports[1]);513printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ");514goto out;515} else if (crisv32_request_dma(516SYNC_SER1_TX_DMA_NBR,517"synchronous serial 1 dma tr",518DMA_VERBOSE_ON_ERROR,5190,520dma_sser1)) {521free_irq(DMA6_INTR_VECT, &ports[1]);522free_irq(DMA7_INTR_VECT, &ports[1]);523printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel");524goto out;525} else if (crisv32_request_dma(526SYNC_SER1_RX_DMA_NBR,527"synchronous serial 3 dma rec",528DMA_VERBOSE_ON_ERROR,5290,530dma_sser1)) {531crisv32_free_dma(SYNC_SER1_TX_DMA_NBR);532free_irq(DMA6_INTR_VECT, &ports[1]);533free_irq(DMA7_INTR_VECT, &ports[1]);534printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel");535goto out;536}537#endif538}539#endif540/* Enable DMAs */541REG_WR(dma, port->regi_dmain, rw_cfg, cfg);542REG_WR(dma, port->regi_dmaout, rw_cfg, cfg);543/* Enable DMA IRQs */544REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask);545REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask);546/* Set up wordsize = 1 for DMAs. */547DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1);548DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1);549550start_dma_in(port);551port->init_irqs = 0;552} else { /* !port->use_dma */553#ifdef SYNC_SER_MANUAL554if (port == &ports[0]) {555if (request_irq(SYNCSER_INTR_VECT,556manual_interrupt,5570,558"synchronous serial manual irq",559&ports[0])) {560printk("Can't allocate sync serial manual irq");561goto out;562}563}564#ifdef CONFIG_ETRAXFS565else if (port == &ports[1]) {566if (request_irq(SSER1_INTR_VECT,567manual_interrupt,5680,569"synchronous serial manual irq",570&ports[1])) {571printk(KERN_CRIT "Can't allocate sync serial manual irq");572goto out;573}574}575#endif576port->init_irqs = 0;577#else578panic("sync_serial: Manual mode not supported.\n");579#endif /* SYNC_SER_MANUAL */580}581582} /* port->init_irqs */583584port->busy++;585ret = 0;586out:587mutex_unlock(&sync_serial_mutex);588return ret;589}590591static int sync_serial_release(struct inode *inode, struct file *file)592{593int dev = iminor(inode);594sync_port *port;595596if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)597{598DEBUG(printk("Invalid minor %d\n", dev));599return -ENODEV;600}601port = &ports[dev];602if (port->busy)603port->busy--;604if (!port->busy)605/* XXX */ ;606return 0;607}608609static unsigned int sync_serial_poll(struct file *file, poll_table *wait)610{611int dev = iminor(file->f_path.dentry->d_inode);612unsigned int mask = 0;613sync_port *port;614DEBUGPOLL( static unsigned int prev_mask = 0; );615616port = &ports[dev];617618if (!port->started) {619reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);620reg_sser_rw_rec_cfg rec_cfg =621REG_RD(sser, port->regi_sser, rw_rec_cfg);622cfg.en = regk_sser_yes;623rec_cfg.rec_en = port->input;624REG_WR(sser, port->regi_sser, rw_cfg, cfg);625REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);626port->started = 1;627}628629poll_wait(file, &port->out_wait_q, wait);630poll_wait(file, &port->in_wait_q, wait);631632/* No active transfer, descriptors are available */633if (port->output && !port->tr_running)634mask |= POLLOUT | POLLWRNORM;635636/* Descriptor and buffer space available. */637if (port->output &&638port->active_tr_descr != port->catch_tr_descr &&639port->out_buf_count < OUT_BUFFER_SIZE)640mask |= POLLOUT | POLLWRNORM;641642/* At least an inbufchunk of data */643if (port->input && sync_data_avail(port) >= port->inbufchunk)644mask |= POLLIN | POLLRDNORM;645646DEBUGPOLL(if (mask != prev_mask)647printk("sync_serial_poll: mask 0x%08X %s %s\n", mask,648mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":"");649prev_mask = mask;650);651return mask;652}653654static int sync_serial_ioctl(struct file *file,655unsigned int cmd, unsigned long arg)656{657int return_val = 0;658int dma_w_size = regk_dma_set_w_size1;659int dev = iminor(file->f_path.dentry->d_inode);660sync_port *port;661reg_sser_rw_tr_cfg tr_cfg;662reg_sser_rw_rec_cfg rec_cfg;663reg_sser_rw_frm_cfg frm_cfg;664reg_sser_rw_cfg gen_cfg;665reg_sser_rw_intr_mask intr_mask;666667if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)668{669DEBUG(printk("Invalid minor %d\n", dev));670return -1;671}672port = &ports[dev];673spin_lock_irq(&port->lock);674675tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);676rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);677frm_cfg = REG_RD(sser, port->regi_sser, rw_frm_cfg);678gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg);679intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);680681switch(cmd)682{683case SSP_SPEED:684if (GET_SPEED(arg) == CODEC)685{686unsigned int freq;687688gen_cfg.base_freq = regk_sser_f32;689690/* Clock divider will internally be691* gen_cfg.clk_div + 1.692*/693694freq = GET_FREQ(arg);695switch (freq) {696case FREQ_32kHz:697case FREQ_64kHz:698case FREQ_128kHz:699case FREQ_256kHz:700gen_cfg.clk_div = 125 *701(1 << (freq - FREQ_256kHz)) - 1;702break;703case FREQ_512kHz:704gen_cfg.clk_div = 62;705break;706case FREQ_1MHz:707case FREQ_2MHz:708case FREQ_4MHz:709gen_cfg.clk_div = 8 * (1 << freq) - 1;710break;711}712} else {713gen_cfg.base_freq = regk_sser_f29_493;714switch (GET_SPEED(arg)) {715case SSP150:716gen_cfg.clk_div = 29493000 / (150 * 8) - 1;717break;718case SSP300:719gen_cfg.clk_div = 29493000 / (300 * 8) - 1;720break;721case SSP600:722gen_cfg.clk_div = 29493000 / (600 * 8) - 1;723break;724case SSP1200:725gen_cfg.clk_div = 29493000 / (1200 * 8) - 1;726break;727case SSP2400:728gen_cfg.clk_div = 29493000 / (2400 * 8) - 1;729break;730case SSP4800:731gen_cfg.clk_div = 29493000 / (4800 * 8) - 1;732break;733case SSP9600:734gen_cfg.clk_div = 29493000 / (9600 * 8) - 1;735break;736case SSP19200:737gen_cfg.clk_div = 29493000 / (19200 * 8) - 1;738break;739case SSP28800:740gen_cfg.clk_div = 29493000 / (28800 * 8) - 1;741break;742case SSP57600:743gen_cfg.clk_div = 29493000 / (57600 * 8) - 1;744break;745case SSP115200:746gen_cfg.clk_div = 29493000 / (115200 * 8) - 1;747break;748case SSP230400:749gen_cfg.clk_div = 29493000 / (230400 * 8) - 1;750break;751case SSP460800:752gen_cfg.clk_div = 29493000 / (460800 * 8) - 1;753break;754case SSP921600:755gen_cfg.clk_div = 29493000 / (921600 * 8) - 1;756break;757case SSP3125000:758gen_cfg.base_freq = regk_sser_f100;759gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1;760break;761762}763}764frm_cfg.wordrate = GET_WORD_RATE(arg);765766break;767case SSP_MODE:768switch(arg)769{770case MASTER_OUTPUT:771port->output = 1;772port->input = 0;773frm_cfg.out_on = regk_sser_tr;774frm_cfg.frame_pin_dir = regk_sser_out;775gen_cfg.clk_dir = regk_sser_out;776break;777case SLAVE_OUTPUT:778port->output = 1;779port->input = 0;780frm_cfg.frame_pin_dir = regk_sser_in;781gen_cfg.clk_dir = regk_sser_in;782break;783case MASTER_INPUT:784port->output = 0;785port->input = 1;786frm_cfg.frame_pin_dir = regk_sser_out;787frm_cfg.out_on = regk_sser_intern_tb;788gen_cfg.clk_dir = regk_sser_out;789break;790case SLAVE_INPUT:791port->output = 0;792port->input = 1;793frm_cfg.frame_pin_dir = regk_sser_in;794gen_cfg.clk_dir = regk_sser_in;795break;796case MASTER_BIDIR:797port->output = 1;798port->input = 1;799frm_cfg.frame_pin_dir = regk_sser_out;800frm_cfg.out_on = regk_sser_intern_tb;801gen_cfg.clk_dir = regk_sser_out;802break;803case SLAVE_BIDIR:804port->output = 1;805port->input = 1;806frm_cfg.frame_pin_dir = regk_sser_in;807gen_cfg.clk_dir = regk_sser_in;808break;809default:810spin_unlock_irq(&port->lock);811return -EINVAL;812}813if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT))814intr_mask.rdav = regk_sser_yes;815break;816case SSP_FRAME_SYNC:817if (arg & NORMAL_SYNC) {818frm_cfg.rec_delay = 1;819frm_cfg.tr_delay = 1;820}821else if (arg & EARLY_SYNC)822frm_cfg.rec_delay = frm_cfg.tr_delay = 0;823else if (arg & SECOND_WORD_SYNC) {824frm_cfg.rec_delay = 7;825frm_cfg.tr_delay = 1;826}827828tr_cfg.bulk_wspace = frm_cfg.tr_delay;829frm_cfg.early_wend = regk_sser_yes;830if (arg & BIT_SYNC)831frm_cfg.type = regk_sser_edge;832else if (arg & WORD_SYNC)833frm_cfg.type = regk_sser_level;834else if (arg & EXTENDED_SYNC)835frm_cfg.early_wend = regk_sser_no;836837if (arg & SYNC_ON)838frm_cfg.frame_pin_use = regk_sser_frm;839else if (arg & SYNC_OFF)840frm_cfg.frame_pin_use = regk_sser_gio0;841842dma_w_size = regk_dma_set_w_size2;843if (arg & WORD_SIZE_8) {844rec_cfg.sample_size = tr_cfg.sample_size = 7;845dma_w_size = regk_dma_set_w_size1;846} else if (arg & WORD_SIZE_12)847rec_cfg.sample_size = tr_cfg.sample_size = 11;848else if (arg & WORD_SIZE_16)849rec_cfg.sample_size = tr_cfg.sample_size = 15;850else if (arg & WORD_SIZE_24)851rec_cfg.sample_size = tr_cfg.sample_size = 23;852else if (arg & WORD_SIZE_32)853rec_cfg.sample_size = tr_cfg.sample_size = 31;854855if (arg & BIT_ORDER_MSB)856rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst;857else if (arg & BIT_ORDER_LSB)858rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst;859860if (arg & FLOW_CONTROL_ENABLE) {861frm_cfg.status_pin_use = regk_sser_frm;862rec_cfg.fifo_thr = regk_sser_thr16;863} else if (arg & FLOW_CONTROL_DISABLE) {864frm_cfg.status_pin_use = regk_sser_gio0;865rec_cfg.fifo_thr = regk_sser_inf;866}867868if (arg & CLOCK_NOT_GATED)869gen_cfg.gate_clk = regk_sser_no;870else if (arg & CLOCK_GATED)871gen_cfg.gate_clk = regk_sser_yes;872873break;874case SSP_IPOLARITY:875/* NOTE!! negedge is considered NORMAL */876if (arg & CLOCK_NORMAL)877rec_cfg.clk_pol = regk_sser_neg;878else if (arg & CLOCK_INVERT)879rec_cfg.clk_pol = regk_sser_pos;880881if (arg & FRAME_NORMAL)882frm_cfg.level = regk_sser_pos_hi;883else if (arg & FRAME_INVERT)884frm_cfg.level = regk_sser_neg_lo;885886if (arg & STATUS_NORMAL)887gen_cfg.hold_pol = regk_sser_pos;888else if (arg & STATUS_INVERT)889gen_cfg.hold_pol = regk_sser_neg;890break;891case SSP_OPOLARITY:892if (arg & CLOCK_NORMAL)893gen_cfg.out_clk_pol = regk_sser_pos;894else if (arg & CLOCK_INVERT)895gen_cfg.out_clk_pol = regk_sser_neg;896897if (arg & FRAME_NORMAL)898frm_cfg.level = regk_sser_pos_hi;899else if (arg & FRAME_INVERT)900frm_cfg.level = regk_sser_neg_lo;901902if (arg & STATUS_NORMAL)903gen_cfg.hold_pol = regk_sser_pos;904else if (arg & STATUS_INVERT)905gen_cfg.hold_pol = regk_sser_neg;906break;907case SSP_SPI:908rec_cfg.fifo_thr = regk_sser_inf;909rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst;910rec_cfg.sample_size = tr_cfg.sample_size = 7;911frm_cfg.frame_pin_use = regk_sser_frm;912frm_cfg.type = regk_sser_level;913frm_cfg.tr_delay = 1;914frm_cfg.level = regk_sser_neg_lo;915if (arg & SPI_SLAVE)916{917rec_cfg.clk_pol = regk_sser_neg;918gen_cfg.clk_dir = regk_sser_in;919port->input = 1;920port->output = 0;921}922else923{924gen_cfg.out_clk_pol = regk_sser_pos;925port->input = 0;926port->output = 1;927gen_cfg.clk_dir = regk_sser_out;928}929break;930case SSP_INBUFCHUNK:931break;932default:933return_val = -1;934}935936937if (port->started) {938rec_cfg.rec_en = port->input;939gen_cfg.en = (port->output | port->input);940}941942REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);943REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);944REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg);945REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);946REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);947948949if (cmd == SSP_FRAME_SYNC && (arg & (WORD_SIZE_8 | WORD_SIZE_12 |950WORD_SIZE_16 | WORD_SIZE_24 | WORD_SIZE_32))) {951int en = gen_cfg.en;952gen_cfg.en = 0;953REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);954/* ##### Should DMA be stoped before we change dma size? */955DMA_WR_CMD(port->regi_dmain, dma_w_size);956DMA_WR_CMD(port->regi_dmaout, dma_w_size);957gen_cfg.en = en;958REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg);959}960961spin_unlock_irq(&port->lock);962return return_val;963}964965static long sync_serial_ioctl(struct file *file,966unsigned int cmd, unsigned long arg)967{968long ret;969970mutex_lock(&sync_serial_mutex);971ret = sync_serial_ioctl_unlocked(file, cmd, arg);972mutex_unlock(&sync_serial_mutex);973974return ret;975}976977/* NOTE: sync_serial_write does not support concurrency */978static ssize_t sync_serial_write(struct file *file, const char *buf,979size_t count, loff_t *ppos)980{981int dev = iminor(file->f_path.dentry->d_inode);982DECLARE_WAITQUEUE(wait, current);983struct sync_port *port;984int trunc_count;985unsigned long flags;986int bytes_free;987int out_buf_count;988989unsigned char *rd_ptr; /* First allocated byte in the buffer */990unsigned char *wr_ptr; /* First free byte in the buffer */991unsigned char *buf_stop_ptr; /* Last byte + 1 */992993if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) {994DEBUG(printk("Invalid minor %d\n", dev));995return -ENODEV;996}997port = &ports[dev];998999/* |<- OUT_BUFFER_SIZE ->|1000* |<- out_buf_count ->|1001* |<- trunc_count ->| ...->|1002* ______________________________________________________1003* | free | data | free |1004* |_________|___________________|________________________|1005* ^ rd_ptr ^ wr_ptr1006*/1007DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu a: %p c: %p\n",1008port->port_nbr, count, port->active_tr_descr,1009port->catch_tr_descr));10101011/* Read variables that may be updated by interrupts */1012spin_lock_irqsave(&port->lock, flags);1013rd_ptr = port->out_rd_ptr;1014out_buf_count = port->out_buf_count;1015spin_unlock_irqrestore(&port->lock, flags);10161017/* Check if resources are available */1018if (port->tr_running &&1019((port->use_dma && port->active_tr_descr == port->catch_tr_descr) ||1020out_buf_count >= OUT_BUFFER_SIZE)) {1021DEBUGWRITE(printk(KERN_DEBUG "sser%d full\n", dev));1022return -EAGAIN;1023}10241025buf_stop_ptr = port->out_buffer + OUT_BUFFER_SIZE;10261027/* Determine pointer to the first free byte, before copying. */1028wr_ptr = rd_ptr + out_buf_count;1029if (wr_ptr >= buf_stop_ptr)1030wr_ptr -= OUT_BUFFER_SIZE;10311032/* If we wrap the ring buffer, let the user space program handle it by1033* truncating the data. This could be more elegant, small buffer1034* fragments may occur.1035*/1036bytes_free = OUT_BUFFER_SIZE - out_buf_count;1037if (wr_ptr + bytes_free > buf_stop_ptr)1038bytes_free = buf_stop_ptr - wr_ptr;1039trunc_count = (count < bytes_free) ? count : bytes_free;10401041if (copy_from_user(wr_ptr, buf, trunc_count))1042return -EFAULT;10431044DEBUGOUTBUF(printk(KERN_DEBUG "%-4d + %-4d = %-4d %p %p %p\n",1045out_buf_count, trunc_count,1046port->out_buf_count, port->out_buffer,1047wr_ptr, buf_stop_ptr));10481049/* Make sure transmitter/receiver is running */1050if (!port->started) {1051reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);1052reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);1053cfg.en = regk_sser_yes;1054rec_cfg.rec_en = port->input;1055REG_WR(sser, port->regi_sser, rw_cfg, cfg);1056REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);1057port->started = 1;1058}10591060/* Setup wait if blocking */1061if (!(file->f_flags & O_NONBLOCK)) {1062add_wait_queue(&port->out_wait_q, &wait);1063set_current_state(TASK_INTERRUPTIBLE);1064}10651066spin_lock_irqsave(&port->lock, flags);1067port->out_buf_count += trunc_count;1068if (port->use_dma) {1069start_dma_out(port, wr_ptr, trunc_count);1070} else if (!port->tr_running) {1071reg_sser_rw_intr_mask intr_mask;1072intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);1073/* Start sender by writing data */1074send_word(port);1075/* and enable transmitter ready IRQ */1076intr_mask.trdy = 1;1077REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);1078}1079spin_unlock_irqrestore(&port->lock, flags);10801081/* Exit if non blocking */1082if (file->f_flags & O_NONBLOCK) {1083DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu %08x\n",1084port->port_nbr, trunc_count,1085REG_RD_INT(dma, port->regi_dmaout, r_intr)));1086return trunc_count;1087}10881089schedule();1090set_current_state(TASK_RUNNING);1091remove_wait_queue(&port->out_wait_q, &wait);10921093if (signal_pending(current))1094return -EINTR;10951096DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n",1097port->port_nbr, trunc_count));1098return trunc_count;1099}11001101static ssize_t sync_serial_read(struct file * file, char * buf,1102size_t count, loff_t *ppos)1103{1104int dev = iminor(file->f_path.dentry->d_inode);1105int avail;1106sync_port *port;1107unsigned char* start;1108unsigned char* end;1109unsigned long flags;11101111if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled)1112{1113DEBUG(printk("Invalid minor %d\n", dev));1114return -ENODEV;1115}1116port = &ports[dev];11171118DEBUGREAD(printk("R%d c %d ri %lu wi %lu /%lu\n", dev, count, port->readp - port->flip, port->writep - port->flip, port->in_buffer_size));11191120if (!port->started)1121{1122reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg);1123reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);1124reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);1125cfg.en = regk_sser_yes;1126tr_cfg.tr_en = regk_sser_yes;1127rec_cfg.rec_en = regk_sser_yes;1128REG_WR(sser, port->regi_sser, rw_cfg, cfg);1129REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);1130REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg);1131port->started = 1;1132}11331134/* Calculate number of available bytes */1135/* Save pointers to avoid that they are modified by interrupt */1136spin_lock_irqsave(&port->lock, flags);1137start = (unsigned char*)port->readp; /* cast away volatile */1138end = (unsigned char*)port->writep; /* cast away volatile */1139spin_unlock_irqrestore(&port->lock, flags);1140while ((start == end) && !port->full) /* No data */1141{1142DEBUGREAD(printk(KERN_DEBUG "&"));1143if (file->f_flags & O_NONBLOCK)1144return -EAGAIN;11451146interruptible_sleep_on(&port->in_wait_q);1147if (signal_pending(current))1148return -EINTR;11491150spin_lock_irqsave(&port->lock, flags);1151start = (unsigned char*)port->readp; /* cast away volatile */1152end = (unsigned char*)port->writep; /* cast away volatile */1153spin_unlock_irqrestore(&port->lock, flags);1154}11551156/* Lazy read, never return wrapped data. */1157if (port->full)1158avail = port->in_buffer_size;1159else if (end > start)1160avail = end - start;1161else1162avail = port->flip + port->in_buffer_size - start;11631164count = count > avail ? avail : count;1165if (copy_to_user(buf, start, count))1166return -EFAULT;1167/* Disable interrupts while updating readp */1168spin_lock_irqsave(&port->lock, flags);1169port->readp += count;1170if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */1171port->readp = port->flip;1172port->full = 0;1173spin_unlock_irqrestore(&port->lock, flags);1174DEBUGREAD(printk("r %d\n", count));1175return count;1176}11771178static void send_word(sync_port* port)1179{1180reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg);1181reg_sser_rw_tr_data tr_data = {0};11821183switch(tr_cfg.sample_size)1184{1185case 8:1186port->out_buf_count--;1187tr_data.data = *port->out_rd_ptr++;1188REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1189if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)1190port->out_rd_ptr = port->out_buffer;1191break;1192case 12:1193{1194int data = (*port->out_rd_ptr++) << 8;1195data |= *port->out_rd_ptr++;1196port->out_buf_count -= 2;1197tr_data.data = data;1198REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1199if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)1200port->out_rd_ptr = port->out_buffer;1201}1202break;1203case 16:1204port->out_buf_count -= 2;1205tr_data.data = *(unsigned short *)port->out_rd_ptr;1206REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1207port->out_rd_ptr += 2;1208if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)1209port->out_rd_ptr = port->out_buffer;1210break;1211case 24:1212port->out_buf_count -= 3;1213tr_data.data = *(unsigned short *)port->out_rd_ptr;1214REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1215port->out_rd_ptr += 2;1216tr_data.data = *port->out_rd_ptr++;1217REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1218if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)1219port->out_rd_ptr = port->out_buffer;1220break;1221case 32:1222port->out_buf_count -= 4;1223tr_data.data = *(unsigned short *)port->out_rd_ptr;1224REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1225port->out_rd_ptr += 2;1226tr_data.data = *(unsigned short *)port->out_rd_ptr;1227REG_WR(sser, port->regi_sser, rw_tr_data, tr_data);1228port->out_rd_ptr += 2;1229if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE)1230port->out_rd_ptr = port->out_buffer;1231break;1232}1233}12341235static void start_dma_out(struct sync_port *port,1236const char *data, int count)1237{1238port->active_tr_descr->buf = (char *) virt_to_phys((char *) data);1239port->active_tr_descr->after = port->active_tr_descr->buf + count;1240port->active_tr_descr->intr = 1;12411242port->active_tr_descr->eol = 1;1243port->prev_tr_descr->eol = 0;12441245DEBUGTRDMA(printk(KERN_DEBUG "Inserting eolr:%p eol@:%p\n",1246port->prev_tr_descr, port->active_tr_descr));1247port->prev_tr_descr = port->active_tr_descr;1248port->active_tr_descr = phys_to_virt((int) port->active_tr_descr->next);12491250if (!port->tr_running) {1251reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser,1252rw_tr_cfg);12531254port->out_context.next = 0;1255port->out_context.saved_data =1256(dma_descr_data *)virt_to_phys(port->prev_tr_descr);1257port->out_context.saved_data_buf = port->prev_tr_descr->buf;12581259DMA_START_CONTEXT(port->regi_dmaout,1260virt_to_phys((char *)&port->out_context));12611262tr_cfg.tr_en = regk_sser_yes;1263REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);1264DEBUGTRDMA(printk(KERN_DEBUG "dma s\n"););1265} else {1266DMA_CONTINUE_DATA(port->regi_dmaout);1267DEBUGTRDMA(printk(KERN_DEBUG "dma c\n"););1268}12691270port->tr_running = 1;1271}12721273static void start_dma_in(sync_port *port)1274{1275int i;1276char *buf;1277port->writep = port->flip;12781279if (port->writep > port->flip + port->in_buffer_size) {1280panic("Offset too large in sync serial driver\n");1281return;1282}1283buf = (char*)virt_to_phys(port->in_buffer);1284for (i = 0; i < NBR_IN_DESCR; i++) {1285port->in_descr[i].buf = buf;1286port->in_descr[i].after = buf + port->inbufchunk;1287port->in_descr[i].intr = 1;1288port->in_descr[i].next = (dma_descr_data*)virt_to_phys(&port->in_descr[i+1]);1289port->in_descr[i].buf = buf;1290buf += port->inbufchunk;1291}1292/* Link the last descriptor to the first */1293port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]);1294port->in_descr[i-1].eol = regk_sser_yes;1295port->next_rx_desc = &port->in_descr[0];1296port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1];1297port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]);1298port->in_context.saved_data_buf = port->in_descr[0].buf;1299DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context));1300}13011302#ifdef SYNC_SER_DMA1303static irqreturn_t tr_interrupt(int irq, void *dev_id)1304{1305reg_dma_r_masked_intr masked;1306reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};1307reg_dma_rw_stat stat;1308int i;1309int found = 0;1310int stop_sser = 0;13111312for (i = 0; i < NBR_PORTS; i++) {1313sync_port *port = &ports[i];1314if (!port->enabled || !port->use_dma)1315continue;13161317/* IRQ active for the port? */1318masked = REG_RD(dma, port->regi_dmaout, r_masked_intr);1319if (!masked.data)1320continue;13211322found = 1;13231324/* Check if we should stop the DMA transfer */1325stat = REG_RD(dma, port->regi_dmaout, rw_stat);1326if (stat.list_state == regk_dma_data_at_eol)1327stop_sser = 1;13281329/* Clear IRQ */1330REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr);13311332if (!stop_sser) {1333/* The DMA has completed a descriptor, EOL was not1334* encountered, so step relevant descriptor and1335* datapointers forward. */1336int sent;1337sent = port->catch_tr_descr->after -1338port->catch_tr_descr->buf;1339DEBUGTXINT(printk(KERN_DEBUG "%-4d - %-4d = %-4d\t"1340"in descr %p (ac: %p)\n",1341port->out_buf_count, sent,1342port->out_buf_count - sent,1343port->catch_tr_descr,1344port->active_tr_descr););1345port->out_buf_count -= sent;1346port->catch_tr_descr =1347phys_to_virt((int) port->catch_tr_descr->next);1348port->out_rd_ptr =1349phys_to_virt((int) port->catch_tr_descr->buf);1350} else {1351int i, sent;1352/* EOL handler.1353* Note that if an EOL was encountered during the irq1354* locked section of sync_ser_write the DMA will be1355* restarted and the eol flag will be cleared.1356* The remaining descriptors will be traversed by1357* the descriptor interrupts as usual.1358*/1359i = 0;1360while (!port->catch_tr_descr->eol) {1361sent = port->catch_tr_descr->after -1362port->catch_tr_descr->buf;1363DEBUGOUTBUF(printk(KERN_DEBUG1364"traversing descr %p -%d (%d)\n",1365port->catch_tr_descr,1366sent,1367port->out_buf_count));1368port->out_buf_count -= sent;1369port->catch_tr_descr = phys_to_virt(1370(int)port->catch_tr_descr->next);1371i++;1372if (i >= NBR_OUT_DESCR) {1373/* TODO: Reset and recover */1374panic("sync_serial: missing eol");1375}1376}1377sent = port->catch_tr_descr->after -1378port->catch_tr_descr->buf;1379DEBUGOUTBUF(printk(KERN_DEBUG1380"eol at descr %p -%d (%d)\n",1381port->catch_tr_descr,1382sent,1383port->out_buf_count));13841385port->out_buf_count -= sent;13861387/* Update read pointer to first free byte, we1388* may already be writing data there. */1389port->out_rd_ptr =1390phys_to_virt((int) port->catch_tr_descr->after);1391if (port->out_rd_ptr > port->out_buffer +1392OUT_BUFFER_SIZE)1393port->out_rd_ptr = port->out_buffer;13941395reg_sser_rw_tr_cfg tr_cfg =1396REG_RD(sser, port->regi_sser, rw_tr_cfg);1397DEBUGTXINT(printk(KERN_DEBUG1398"tr_int DMA stop %d, set catch @ %p\n",1399port->out_buf_count,1400port->active_tr_descr));1401if (port->out_buf_count != 0)1402printk(KERN_CRIT "sync_ser: buffer not "1403"empty after eol.\n");1404port->catch_tr_descr = port->active_tr_descr;1405port->tr_running = 0;1406tr_cfg.tr_en = regk_sser_no;1407REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg);1408}1409/* wake up the waiting process */1410wake_up_interruptible(&port->out_wait_q);1411}1412return IRQ_RETVAL(found);1413} /* tr_interrupt */14141415static irqreturn_t rx_interrupt(int irq, void *dev_id)1416{1417reg_dma_r_masked_intr masked;1418reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes};14191420int i;1421int found = 0;14221423for (i = 0; i < NBR_PORTS; i++)1424{1425sync_port *port = &ports[i];14261427if (!port->enabled || !port->use_dma )1428continue;14291430masked = REG_RD(dma, port->regi_dmain, r_masked_intr);14311432if (masked.data) /* Descriptor interrupt */1433{1434found = 1;1435while (REG_RD(dma, port->regi_dmain, rw_data) !=1436virt_to_phys(port->next_rx_desc)) {1437DEBUGRXINT(printk(KERN_DEBUG "!"));1438if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) {1439int first_size = port->flip + port->in_buffer_size - port->writep;1440memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size);1441memcpy(port->flip, phys_to_virt((unsigned)port->next_rx_desc->buf+first_size), port->inbufchunk - first_size);1442port->writep = port->flip + port->inbufchunk - first_size;1443} else {1444memcpy((char*)port->writep,1445phys_to_virt((unsigned)port->next_rx_desc->buf),1446port->inbufchunk);1447port->writep += port->inbufchunk;1448if (port->writep >= port->flip + port->in_buffer_size)1449port->writep = port->flip;1450}1451if (port->writep == port->readp)1452{1453port->full = 1;1454}14551456port->next_rx_desc->eol = 1;1457port->prev_rx_desc->eol = 0;1458/* Cache bug workaround */1459flush_dma_descr(port->prev_rx_desc, 0);1460port->prev_rx_desc = port->next_rx_desc;1461port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next);1462/* Cache bug workaround */1463flush_dma_descr(port->prev_rx_desc, 1);1464/* wake up the waiting process */1465wake_up_interruptible(&port->in_wait_q);1466DMA_CONTINUE(port->regi_dmain);1467REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr);14681469}1470}1471}1472return IRQ_RETVAL(found);1473} /* rx_interrupt */1474#endif /* SYNC_SER_DMA */14751476#ifdef SYNC_SER_MANUAL1477static irqreturn_t manual_interrupt(int irq, void *dev_id)1478{1479int i;1480int found = 0;1481reg_sser_r_masked_intr masked;14821483for (i = 0; i < NBR_PORTS; i++)1484{1485sync_port *port = &ports[i];14861487if (!port->enabled || port->use_dma)1488{1489continue;1490}14911492masked = REG_RD(sser, port->regi_sser, r_masked_intr);1493if (masked.rdav) /* Data received? */1494{1495reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg);1496reg_sser_r_rec_data data = REG_RD(sser, port->regi_sser, r_rec_data);1497found = 1;1498/* Read data */1499switch(rec_cfg.sample_size)1500{1501case 8:1502*port->writep++ = data.data & 0xff;1503break;1504case 12:1505*port->writep = (data.data & 0x0ff0) >> 4;1506*(port->writep + 1) = data.data & 0x0f;1507port->writep+=2;1508break;1509case 16:1510*(unsigned short*)port->writep = data.data;1511port->writep+=2;1512break;1513case 24:1514*(unsigned int*)port->writep = data.data;1515port->writep+=3;1516break;1517case 32:1518*(unsigned int*)port->writep = data.data;1519port->writep+=4;1520break;1521}15221523if (port->writep >= port->flip + port->in_buffer_size) /* Wrap? */1524port->writep = port->flip;1525if (port->writep == port->readp) {1526/* receive buffer overrun, discard oldest data1527*/1528port->readp++;1529if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */1530port->readp = port->flip;1531}1532if (sync_data_avail(port) >= port->inbufchunk)1533wake_up_interruptible(&port->in_wait_q); /* Wake up application */1534}15351536if (masked.trdy) /* Transmitter ready? */1537{1538found = 1;1539if (port->out_buf_count > 0) /* More data to send */1540send_word(port);1541else /* transmission finished */1542{1543reg_sser_rw_intr_mask intr_mask;1544intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask);1545intr_mask.trdy = 0;1546REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask);1547wake_up_interruptible(&port->out_wait_q); /* Wake up application */1548}1549}1550}1551return IRQ_RETVAL(found);1552}1553#endif15541555module_init(etrax_sync_serial_init);155615571558