/* other forward declarations */
static unsigned int ifx_ssc_get_kernel_clk (struct ifx_ssc_port *info);
-#ifdef SSC_FRAME_INT_ENABLE
-static void ifx_ssc_frm_int (int, void *, struct pt_regs *);
-#endif
static void tx_int (struct ifx_ssc_port *);
static int ifx_ssc1_read_proc (char *, char **, off_t, int, int *, void *);
-static void ifx_gpio_init (void);
-/************************************************************************
- * Function declaration
- ************************************************************************/
-//interrupt.c
+
extern unsigned int danube_get_fpi_hz (void);
-extern void disable_danube_irq (unsigned int irq_nr);
-extern void enable_danube_irq (unsigned int irq_nr);
extern void mask_and_ack_danube_irq (unsigned int irq_nr);
-/*****************************************************************/
-typedef struct {
- int (*request) (unsigned int, irq_handler_t handler,
- unsigned long, const char *, void *);
- void (*free) (unsigned int irq, void *dev_id);
- void (*enable) (unsigned int irq);
- void (*disable) (unsigned int irq);
- void (*clear) (unsigned int irq);
-} ifx_int_wrapper_t;
-
-static ifx_int_wrapper_t ifx_int_wrapper = {
- request:request_irq, // IM action: enable int
- free:free_irq, // IM action: disable int
- enable:enable_danube_irq,
- disable:disable_danube_irq,
- clear:mask_and_ack_danube_irq,
- //end:
-};
-
-/* Fops-struct */
static struct file_operations ifx_ssc_fops = {
- owner:THIS_MODULE,
- read:ifx_ssc_read, /* read */
- write:ifx_ssc_write, /* write */
-// poll: ifx_ssc_poll, /* poll */
- ioctl:ifx_ssc_ioctl, /* ioctl */
- open:ifx_ssc_open, /* open */
- release:ifx_ssc_close, /* release */
+ .owner = THIS_MODULE,
+ .read = ifx_ssc_read,
+ .write = ifx_ssc_write,
+ .ioctl = ifx_ssc_ioctl,
+ .open = ifx_ssc_open,
+ .release = ifx_ssc_close,
};
static inline unsigned int
info->event |= 1 << event; /* remember what kind of event and who */
queue_task (&info->tqueue, &tq_cyclades); /* it belongs to */
mark_bh (CYCLADES_BH); /* then trigger event */
-} /* ifx_ssc_sched_event */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using ifx_ssc_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue. When the time is right,
- * do_ifx_ssc_bh is called (because of the mark_bh) and it requests
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the ifx_ssc_port
- * structure) to the bottom half of the driver. Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_ifx_ssc_bh (void)
-{
- run_task_queue (&tq_cyclades);
-} /* do_ifx_ssc_bh */
+}
static void
do_softint (void *private_)
// check if transfer is complete
if (info->rxbuf_ptr >= info->rxbuf_end) {
- ifx_int_wrapper.disable (info->rxirq);
+ disable_irq(info->rxirq);
/* wakeup any processes waiting in read() */
wake_up_interruptible (&info->rwait);
/* and in poll() */
info->mapbase +
IFX_SSC_RXREQ);
}
-} // rx_int
+}
inline static void
tx_int (struct ifx_ssc_port *info)
// check if transmission complete
if (info->txbuf_ptr >= info->txbuf_end) {
- ifx_int_wrapper.disable (info->txirq);
+ disable_irq(info->txirq);
kfree (info->txbuf);
info->txbuf = NULL;
/* wake up any process waiting in poll() */
//wake_up_interruptible(&info->pwait);
}
-} // tx_int
+}
irqreturn_t
ifx_ssc_rx_int (int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef SSC_FRAME_INT_ENABLE
-static void
-ifx_ssc_frm_int (int irq, void *dev_id, struct pt_regs *regs)
-{
- // ### TO DO: wake up framing wait-queue in conjunction with batch execution
-}
-#endif
-
static void
ifx_ssc_abort (struct ifx_ssc_port *info)
{
local_irq_save (flags);
- // disable all int's
- ifx_int_wrapper.disable (info->rxirq);
- ifx_int_wrapper.disable (info->txirq);
- ifx_int_wrapper.disable (info->errirq);
-/*
- ifx_int_wrapper.disable(info->frmirq);
-*/
+ disable_irq(info->rxirq);
+ disable_irq(info->txirq);
+ disable_irq(info->errirq);
+
local_irq_restore (flags);
// disable SSC (also aborts a receive request!)
wake_up_interruptible (&info->rwait);
// clear pending int's
- ifx_int_wrapper.clear (info->rxirq);
- ifx_int_wrapper.clear (info->txirq);
- ifx_int_wrapper.clear (info->errirq);
-/*
- ifx_int_wrapper.clear(info->frmirq);
-*/
+ mask_and_ack_danube_irq(info->rxirq);
+ mask_and_ack_danube_irq(info->txirq);
+ mask_and_ack_danube_irq(info->errirq);
// clear error flags
WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ALL_ERROR,
info->mapbase + IFX_SSC_WHBSTATE);
- //printk("IFX SSC%d: Transmission aborted\n", info->port_nr);
- // enable SSC
if (enabled)
WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE,
info->mapbase + IFX_SSC_WHBSTATE);
-} // ifx_ssc_abort
+}
/*
* This routine is called whenever a port is opened. It enforces
return -EBUSY;
info->port_is_open++;
- ifx_int_wrapper.disable (info->rxirq);
- ifx_int_wrapper.disable (info->txirq);
- ifx_int_wrapper.disable (info->errirq);
-/*
- ifx_int_wrapper.disable(info->frmirq);
-*/
+ disable_irq(info->rxirq);
+ disable_irq(info->txirq);
+ disable_irq(info->errirq);
/* Flush and enable TX/RX FIFO */
WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL <<
info->mapbase + IFX_SSC_WHBSTATE);
// clear pending interrupts
- ifx_int_wrapper.clear (info->rxirq);
- ifx_int_wrapper.clear (info->txirq);
- ifx_int_wrapper.clear (info->errirq);
-/*
- ifx_int_wrapper.clear(info->frmirq);
-*/
+ mask_and_ack_danube_irq(info->rxirq);
+ mask_and_ack_danube_irq(info->txirq);
+ mask_and_ack_danube_irq(info->errirq);
- // enable SSC
WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE,
info->mapbase + IFX_SSC_WHBSTATE);
return 0;
-} /* ifx_ssc_open */
-
+}
EXPORT_SYMBOL (ifx_ssc_open);
/*
info->port_is_open--;
return 0;
-} /* ifx_ssc_close */
-
+}
EXPORT_SYMBOL (ifx_ssc_close);
/* added by bingtao */
ret_val = info->rxbuf_ptr - info->rxbuf;
return (ret_val);
-} // ifx_ssc_read_helper_poll
+}
/* helper routine to handle reads from the kernel or user-space */
/* info->rx_buf : never kfree and contains valid data */
(info->txbuf != info->txbuf_ptr) ||
(info->txbuf_end != len + info->txbuf)) {
local_irq_restore (flags);
- printk ("IFX SSC - %s: write must be called before calling " "read in combined RX/TX!\n", __FUNCTION__);
+ printk ("IFX SSC - %s: write must be called before calling " "read in combined RX/TX!\n", __func__);
return -EFAULT;
}
local_irq_restore (flags);
/* should enable tx, right? */
tx_int (info);
- if (info->txbuf_ptr < info->txbuf_end) {
- ifx_int_wrapper.enable (info->txirq);
- }
+ if (info->txbuf_ptr < info->txbuf_end)
+ enable_irq(info->txirq);
- ifx_int_wrapper.enable (info->rxirq);
+ enable_irq(info->rxirq);
}
else { // rx mode
local_irq_restore (flags);
if (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) &
IFX_SSC_RXCNT_TODO_MASK)
return -EBUSY;
- ifx_int_wrapper.enable (info->rxirq);
+ enable_irq(info->rxirq);
// rx request limited to ' bytes
/*
if (len < 65536)
break;
local_irq_restore (flags);
-// if (filp->f_flags & O_NONBLOCK)
-// {
-// N = -EAGAIN;
-// goto out;
-// }
if (signal_pending (current)) {
ret_val = -ERESTARTSYS;
goto out;
schedule ();
} while (1);
- ret_val = info->rxbuf_ptr - info->rxbuf; // should be equal to len
+ ret_val = info->rxbuf_ptr - info->rxbuf;
local_irq_restore (flags);
out:
current->state = TASK_RUNNING;
__remove_wait_queue (&info->rwait, &wait);
return (ret_val);
-} // ifx_ssc_read_helper
+}
/* helper routine to handle writes to the kernel or user-space */
if (info->opts.modeRxTx == IFX_SSC_MODE_TX) {
tx_int (info);
if (info->txbuf_ptr < info->txbuf_end) {
- ifx_int_wrapper.enable (info->txirq);
+ enable_irq(info->txirq);
}
}
//local_irq_restore(flags);
info->rxbuf = NULL;
// ### TO DO: perhaps warn if ret_val != len
- ifx_int_wrapper.disable (info->rxirq);
+ disable_irq(info->rxirq);
return (ret_val);
} // ifx_ssc_kread
int idx;
struct ifx_ssc_port *info;
-/*
- if (len == 0)
- return (0);
-*/
idx = MINOR (filp->f_dentry->d_inode->i_rdev);
info = &isp[idx];
if (copy_to_user ((void *) ubuf, info->rxbuf, ret_val) != 0)
ret_val = -EFAULT;
- ifx_int_wrapper.disable (info->rxirq);
+ disable_irq(info->rxirq);
kfree (info->rxbuf);
info->rxbuf = NULL;
return (ret_val);
-} // ifx_ssc_read
+}
/*
* As many bytes as we have free space for are copied from the user
info->txbuf = NULL;
}
return (ret_val);
-} /* ifx_ssc_write */
-
-/*
- * ------------------------------------------------------------
- * ifx_ssc_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-/*-----------------------------------------------------------------------------
- FUNC-NAME : ifx_ssc_frm_status_get
- LONG-NAME : framing status get
- PURPOSE : Get the actual status of the framing.
-
- PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
-
- RESULT : pointer to a structure ifx_ssc_frm_status which holds busy and
- count values.
+}
- REMARKS : Returns a register value independent of framing is enabled or
- not! Changes structure inside of info, so the return value isn't
- needed at all, but could be used for simple access.
------------------------------------------------------------------------------*/
static struct ifx_ssc_frm_status *
ifx_ssc_frm_status_get (struct ifx_ssc_port *info)
{
info->frm_status.EnIntAfterPause =
(tmp & IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE) > 0;
return (&info->frm_status);
-} // ifx_ssc_frm_status_get
-
-/*-----------------------------------------------------------------------------
- FUNC-NAME : ifx_ssc_frm_control_get
- LONG-NAME : framing control get
- PURPOSE : Get the actual control values of the framing.
-
- PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+}
- RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
- and count reload values.
- REMARKS : Changes structure inside of info, so the return value isn't
- needed at all, but could be used for simple access.
------------------------------------------------------------------------------*/
static struct ifx_ssc_frm_opts *
ifx_ssc_frm_control_get (struct ifx_ssc_port *info)
{
info->frm_opts.StopAfterPause =
(tmp & IFX_SSC_SFCON_STOP_AFTER_PAUSE) > 0;
return (&info->frm_opts);
-} // ifx_ssc_frm_control_get
-
-/*-----------------------------------------------------------------------------
- FUNC-NAME : ifx_ssc_frm_control_set
- LONG-NAME : framing control set
- PURPOSE : Set the actual control values of the framing.
-
- PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
-
- RESULT : pointer to a structure ifx_ssc_frm_opts which holds control bits
- and count reload values.
+}
- REMARKS :
------------------------------------------------------------------------------*/
static int
ifx_ssc_frm_control_set (struct ifx_ssc_port *info)
{
unsigned long tmp;
// check parameters
- if ((info->frm_opts.DataLength > IFX_SSC_SFCON_DATA_LENGTH_MAX) ||
- (info->frm_opts.DataLength < 1) ||
- (info->frm_opts.PauseLength > IFX_SSC_SFCON_PAUSE_LENGTH_MAX) ||
- (info->frm_opts.PauseLength < 1) ||
- ((info->frm_opts.IdleData & ~(IFX_SSC_SFCON_PAUSE_DATA_MASK >>
- IFX_SSC_SFCON_PAUSE_DATA_OFFSET)) !=
- 0)
- ||
- ((info->frm_opts.
- IdleClock & ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK >>
- IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET)) != 0))
+ if ((info->frm_opts.DataLength > IFX_SSC_SFCON_DATA_LENGTH_MAX)
+ || (info->frm_opts.DataLength < 1)
+ || (info->frm_opts.PauseLength > IFX_SSC_SFCON_PAUSE_LENGTH_MAX)
+ || (info->frm_opts.PauseLength < 1)
+ || (info->frm_opts.IdleData & ~(IFX_SSC_SFCON_PAUSE_DATA_MASK >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET))
+ || (info->frm_opts.IdleClock & ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET)))
return -EINVAL;
// read interrupt bits (they're not changed here)
tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON) &
- (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE |
- IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE);
+ (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE | IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE);
// set all values with respect to it's bit position (for data and pause
// length set N-1)
- tmp = (info->frm_opts.DataLength -
- 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET;
- tmp |= (info->frm_opts.PauseLength -
- 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET;
+ tmp = (info->frm_opts.DataLength - 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET;
+ tmp |= (info->frm_opts.PauseLength - 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET;
tmp |= info->frm_opts.IdleData << IFX_SSC_SFCON_PAUSE_DATA_OFFSET;
tmp |= info->frm_opts.IdleClock << IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET;
tmp |= info->frm_opts.FrameEnable * IFX_SSC_SFCON_SF_ENABLE;
tmp |= info->frm_opts.StopAfterPause * IFX_SSC_SFCON_STOP_AFTER_PAUSE;
- WRITE_PERIPHERAL_REGISTER (tmp, info->mapbase + IFX_SSC_SFCON);
+ WRITE_PERIPHERAL_REGISTER(tmp, info->mapbase + IFX_SSC_SFCON);
return 0;
-} // ifx_ssc_frm_control_set
-
-/*-----------------------------------------------------------------------------
- FUNC-NAME : ifx_ssc_rxtx_mode_set
- LONG-NAME : rxtx mode set
- PURPOSE : Set the transmission mode.
-
- PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
-
- RESULT : Returns error code
+}
- REMARKS : Assumes that SSC not used (SSC disabled, device not opened yet
- or just closed)
------------------------------------------------------------------------------*/
static int
ifx_ssc_rxtx_mode_set (struct ifx_ssc_port *info, unsigned int val)
{
unsigned long tmp;
- // check parameters
if (!(info) || (val & ~(IFX_SSC_MODE_MASK)))
return -EINVAL;
- /*check BUSY and RXCNT */
- if (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) &
- IFX_SSC_STATE_BUSY
- || READ_PERIPHERAL_REGISTER (info->mapbase +
- IFX_SSC_RXCNT) &
- IFX_SSC_RXCNT_TODO_MASK)
+
+ if ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_BUSY)
+ || (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK))
return -EBUSY;
- // modify
- tmp = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) &
- ~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)) | (val);
+
+ tmp = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) & ~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)) | (val);
WRITE_PERIPHERAL_REGISTER (tmp, info->mapbase + IFX_SSC_CON);
info->opts.modeRxTx = val;
-/*
- printk(KERN_DEBUG "IFX SSC%d: Setting mode to %s%s\n",
- info->port_nr,
- ((val & IFX_SSC_CON_RX_OFF) == 0) ? "rx ":"",
- ((val & IFX_SSC_CON_TX_OFF) == 0) ? "tx":"");
-*/
- return 0;
-} // ifx_ssc_rxtx_mode_set
-
-void
-ifx_gpio_init (void)
-{
- /* TODO: P0.9 SPI_CS4, P0.10 SPI_CS5, P 0.11 SPI_CS6, because of ASC0 */
- /* p0.15 SPI_CS1(EEPROM), P0.13 SPI_CS3, */
- /* Set p0.15 to alternative 01, others to 00 (In/OUT) */
- *(DANUBE_GPIO_P0_DIR) = (*DANUBE_GPIO_P0_DIR) | (0xA000);
- *(DANUBE_GPIO_P0_ALTSEL0) =
- (((*DANUBE_GPIO_P0_ALTSEL0) | (0x8000)) & (~(0x2000)));
- *(DANUBE_GPIO_P0_ALTSEL1) =
- (((*DANUBE_GPIO_P0_ALTSEL1) & (~0x8000)) & (~(0x2000)));
- *(DANUBE_GPIO_P0_OD) = (*DANUBE_GPIO_P0_OD) | 0xA000;
-
- /* p1.6 SPI_CS2(SFLASH), p1.0 SPI_DIN, p1.1 SPI_DOUT, p1.2 SPI_CLK */
- *(DANUBE_GPIO_P1_DIR) = ((*DANUBE_GPIO_P1_DIR) | (0x46)) & (~1);
- *(DANUBE_GPIO_P1_ALTSEL0) = ((*DANUBE_GPIO_P1_ALTSEL0) | (0x47));
- *(DANUBE_GPIO_P1_ALTSEL1) = (*DANUBE_GPIO_P1_ALTSEL1) & (~0x47);
- *(DANUBE_GPIO_P1_OD) = (*DANUBE_GPIO_P1_OD) | 0x0046;
-
- /*CS3 */
- /*TODO: CS4 CS5 CS6 */
- *DANUBE_GPIO_P0_OUT = ((*DANUBE_GPIO_P0_OUT) | 0x2000);
+ return 0;
}
-/*
- * This routine intializes the SSC appropriately depending
- * on slave/master and full-/half-duplex mode.
- * It assumes that the SSC is disabled and the fifo's and buffers
- * are flushes later on.
- */
static int
ifx_ssc_sethwopts (struct ifx_ssc_port *info)
{
unsigned long flags, bits;
struct ifx_ssc_hwopts *opts = &info->opts;
- /* sanity checks */
- if ((opts->dataWidth < IFX_SSC_MIN_DATA_WIDTH) ||
- (opts->dataWidth > IFX_SSC_MAX_DATA_WIDTH)) {
- printk ("%s: sanity check failed\n", __FUNCTION__);
+ if ((opts->dataWidth < IFX_SSC_MIN_DATA_WIDTH)
+ || (opts->dataWidth > IFX_SSC_MAX_DATA_WIDTH))
return -EINVAL;
- }
+
bits = (opts->dataWidth - 1) << IFX_SSC_CON_DATA_WIDTH_OFFSET;
bits |= IFX_SSC_CON_ENABLE_BYTE_VALID;
- // if (opts->abortErrDetect)
- // bits |= IFX_SSC_CON_ABORT_ERR_CHECK;
+
if (opts->rxOvErrDetect)
bits |= IFX_SSC_CON_RX_OFL_CHECK;
if (opts->rxUndErrDetect)
bits |= IFX_SSC_CON_LATCH_THEN_SHIFT;
if (opts->clockPolarity)
bits |= IFX_SSC_CON_CLOCK_FALL;
- switch (opts->modeRxTx) {
+
+ switch (opts->modeRxTx)
+ {
case IFX_SSC_MODE_TX:
bits |= IFX_SSC_CON_RX_OFF;
break;
case IFX_SSC_MODE_RX:
bits |= IFX_SSC_CON_TX_OFF;
break;
- } // switch (opts->modeRxT)
+ }
+
local_irq_save (flags);
+
WRITE_PERIPHERAL_REGISTER (bits, info->mapbase + IFX_SSC_CON);
- WRITE_PERIPHERAL_REGISTER ((info->opts.
- gpoCs << IFX_SSC_GPOCON_ISCSB0_POS) |
- (info->opts.
- gpoInv << IFX_SSC_GPOCON_INVOUT0_POS),
- info->mapbase + IFX_SSC_GPOCON);
- /*TODO: disable cs */
- WRITE_PERIPHERAL_REGISTER (info->opts.
- gpoCs << IFX_SSC_WHBGPOSTAT_SETOUT0_POS,
- info->mapbase + IFX_SSC_WHBGPOSTAT);
+ WRITE_PERIPHERAL_REGISTER ((info->opts.gpoCs << IFX_SSC_GPOCON_ISCSB0_POS) |
+ (info->opts.gpoInv << IFX_SSC_GPOCON_INVOUT0_POS), info->mapbase + IFX_SSC_GPOCON);
+
+ WRITE_PERIPHERAL_REGISTER (info->opts.gpoCs << IFX_SSC_WHBGPOSTAT_SETOUT0_POS, info->mapbase + IFX_SSC_WHBGPOSTAT);
//master mode
- if (opts->masterSelect) {
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_MASTER_SELECT,
- info->mapbase + IFX_SSC_WHBSTATE);
- }
- else {
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_MASTER_SELECT,
- info->mapbase + IFX_SSC_WHBSTATE);
- }
+ if (opts->masterSelect)
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE);
+ else
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE);
+
// init serial framing
WRITE_PERIPHERAL_REGISTER (0, info->mapbase + IFX_SSC_SFCON);
/* set up the port pins */
//check for general requirements to switch (external) pad/pin characteristics
- ifx_gpio_init ();
+ /* TODO: P0.9 SPI_CS4, P0.10 SPI_CS5, P 0.11 SPI_CS6, because of ASC0 */
+ /* p0.15 SPI_CS1(EEPROM), P0.13 SPI_CS3, */
+ /* Set p0.15 to alternative 01, others to 00 (In/OUT) */
+ *(DANUBE_GPIO_P0_DIR) = (*DANUBE_GPIO_P0_DIR) | (0xA000);
+ *(DANUBE_GPIO_P0_ALTSEL0) = (((*DANUBE_GPIO_P0_ALTSEL0) | (0x8000)) & (~(0x2000)));
+ *(DANUBE_GPIO_P0_ALTSEL1) = (((*DANUBE_GPIO_P0_ALTSEL1) & (~0x8000)) & (~(0x2000)));
+ *(DANUBE_GPIO_P0_OD) = (*DANUBE_GPIO_P0_OD) | 0xA000;
+
+ /* p1.6 SPI_CS2(SFLASH), p1.0 SPI_DIN, p1.1 SPI_DOUT, p1.2 SPI_CLK */
+ *(DANUBE_GPIO_P1_DIR) = ((*DANUBE_GPIO_P1_DIR) | (0x46)) & (~1);
+ *(DANUBE_GPIO_P1_ALTSEL0) = ((*DANUBE_GPIO_P1_ALTSEL0) | (0x47));
+ *(DANUBE_GPIO_P1_ALTSEL1) = (*DANUBE_GPIO_P1_ALTSEL1) & (~0x47);
+ *(DANUBE_GPIO_P1_OD) = (*DANUBE_GPIO_P1_OD) | 0x0046;
+
+ /*CS3 */
+ /*TODO: CS4 CS5 CS6 */
+ *DANUBE_GPIO_P0_OUT = ((*DANUBE_GPIO_P0_OUT) | 0x2000);
+
local_irq_restore (flags);
return 0;
-} // ifx_ssc_sethwopts
+}
static int
ifx_ssc_set_baud (struct ifx_ssc_port *info, unsigned int baud)
unsigned int br;
unsigned long flags;
bool enabled;
+ int retval = 0;
- ifx_ssc_clock = ifx_ssc_get_kernel_clk (info);
+ ifx_ssc_clock = ifx_ssc_get_kernel_clk(info);
if (ifx_ssc_clock == 0)
- return -EINVAL;
+ {
+ retval = -EINVAL;
+ goto out;
+ }
+
local_irq_save (flags);
- /* have to disable the SSC to set the baudrate */
- enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE)
- & IFX_SSC_STATE_IS_ENABLED) != 0;
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE,
- info->mapbase + IFX_SSC_WHBSTATE);
- // compute divider
+ enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED);
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE);
+
br = (((ifx_ssc_clock >> 1) + baud / 2) / baud) - 1;
- asm ("SYNC");
- if (br > 0xffff ||
- ((br == 0) &&
- ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) &
- IFX_SSC_STATE_IS_MASTER) == 0))) {
+ wmb();
+
+ if (br > 0xffff || ((br == 0) &&
+ ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_MASTER) == 0))) {
local_irq_restore (flags);
- printk ("%s: illegal baudrate %u\n", __FUNCTION__, baud);
+ printk ("%s: invalid baudrate %u\n", __func__, baud);
return -EINVAL;
}
+
WRITE_PERIPHERAL_REGISTER (br, info->mapbase + IFX_SSC_BR);
+
if (enabled)
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE,
- info->mapbase + IFX_SSC_WHBSTATE);
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE);
- local_irq_restore (flags);
- return 0;
-} // ifx_ssc_set_baud
+ local_irq_restore(flags);
+
+out:
+ return retval;
+}
static int
ifx_ssc_hwinit (struct ifx_ssc_port *info)
unsigned long flags;
bool enabled;
- /* have to disable the SSC */
- enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE)
- & IFX_SSC_STATE_IS_ENABLED) != 0;
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE,
- info->mapbase + IFX_SSC_WHBSTATE);
+ enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED);
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE);
- if (ifx_ssc_sethwopts (info) < 0) {
- printk ("%s: setting the hardware options failed\n",
- __FUNCTION__);
+ if (ifx_ssc_sethwopts (info) < 0)
+ {
+ printk ("%s: setting the hardware options failed\n", __func__);
return -EINVAL;
}
- if (ifx_ssc_set_baud (info, info->baud) < 0) {
- printk ("%s: setting the baud rate failed\n", __FUNCTION__);
+ if (ifx_ssc_set_baud (info, info->baud) < 0)
+ {
+ printk ("%s: setting the baud rate failed\n", __func__);
return -EINVAL;
}
+
local_irq_save (flags);
+
/* TX FIFO */
- WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL <<
- IFX_SSC_XFCON_ITL_OFFSET) |
- IFX_SSC_XFCON_FIFO_ENABLE,
+ WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE,
info->mapbase + IFX_SSC_TXFCON);
/* RX FIFO */
- WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL <<
- IFX_SSC_XFCON_ITL_OFFSET) |
- IFX_SSC_XFCON_FIFO_ENABLE,
+ WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE,
info->mapbase + IFX_SSC_RXFCON);
- local_irq_restore (flags);
- if (enabled)
- WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE,
- info->mapbase + IFX_SSC_WHBSTATE);
- return 0;
-} // ifx_ssc_hwinit
-
-/*-----------------------------------------------------------------------------
- FUNC-NAME : ifx_ssc_batch_exec
- LONG-NAME :
- PURPOSE :
- PARAMETER : *info pointer to the port-specific structure ifx_ssc_port.
+ local_irq_restore (flags);
- RESULT : Returns error code
+ if (enabled)
+ WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE);
- REMARKS :
------------------------------------------------------------------------------*/
-static int
-ifx_ssc_batch_exec (struct ifx_ssc_port *info,
- struct ifx_ssc_batch_list *batch_anchor)
-{
- // ### TO DO: implement user space batch execution
- // first, copy the whole linked list from user to kernel space
- // save some hardware options
- // execute list
- // restore hardware options if selected
- return -EFAULT;
-} // ifx_ssc_batch_exec
+ return 0;
+}
-/*
- * This routine allows the driver to implement device-
- * specific ioctl's. If the ioctl number passed in cmd is
- * not recognized by the driver, it should return ENOIOCTLCMD.
- */
int
-ifx_ssc_ioctl (struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long data)
+ifx_ssc_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
{
struct ifx_ssc_port *info;
int line, ret_val = 0;
unsigned long tmp;
int from_kernel = 0;
- if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) {
+ if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1))
+ {
from_kernel = 1;
line = (int) inode;
- }
- else
+ } else {
line = MINOR (filp->f_dentry->d_inode->i_rdev);
+ }
- /* don't use more minor devices than we can support */
if (line < 0 || line >= PORT_CNT)
return -ENXIO;
info = &isp[line];
- switch (cmd) {
+ switch (cmd)
+ {
case IFX_SSC_STATS_READ:
/* data must be a pointer to a struct ifx_ssc_statistics */
if (from_kernel)
}
return ret_val;
-} /* ifx_ssc_ioctl */
+}
EXPORT_SYMBOL (ifx_ssc_ioctl);
-///* the poll routine */
-//static unsigned int
-//ifx_ssc_poll(struct file *filp, struct poll_table_struct *pts)
-//{
-// int unit = MINOR(filp->f_dentry->d_inode->i_rdev);
-// struct ifx_ssc_port *info;
-// unsigned int mask = 0;
-// int spc;
-//
-// info = &isp[unit];
-//
-// /* add event to the wait queues */
-// /* DO NOT FORGET TO DO A WAKEUP ON THESE !!!! */
-// poll_wait(filp, &info->pwait, pts);
-//
-// /* are there bytes in the RX SW-FIFO? */
-// if (info->rxrp != info->rxwp)
-// mask |= POLLIN | POLLRDNORM;
-//
-// /* free space in the TX SW-FIFO */
-// spc = info->txrp - info->txwp - 1;
-// if (spc < 0)
-// spc += TX_BUFSIZE;
-//#ifdef IFX_SSC_USEDMA
-// /* writing always works, except in the DMA case when all descriptors */
-// /* are used up */
-// if (unit == 1 && info->dma_freecnt == 0)
-// spc = 0;
-//#endif
-// if (spc > 0)
-// mask |= POLLOUT | POLLWRNORM;
-//
-// return (mask);
-//}
-
static int
ifx_ssc1_read_proc (char *page, char **start, off_t offset, int count,
int *eof, void *data)
off += sprintf (page + off, "RX Bytes %d\n", isp[0].stats.rxBytes);
off += sprintf (page + off, "TX Bytes %d\n", isp[0].stats.txBytes);
- local_irq_restore(flags); /* XXXXX */
+ local_irq_restore(flags);
*eof = 1;
return (off);
}
-/*
- * This routine prints out the appropriate serial driver version number
- */
-static inline void
-show_version (void)
-{
-#if 0
- printk ("Infineon Technologies Synchronous Serial Controller (SSC) driver\n" " version %s - built %s %s\n", IFX_SSC_DRV_VERSION, __DATE__, __TIME__);
-#endif
-} /* show_version */
-
/*
* Due to the fact that a port can be dynamically switched between slave
* and master mode using an IOCTL the hardware is not initialized here,
nbytes = PORT_CNT * sizeof (struct ifx_ssc_port);
isp = (struct ifx_ssc_port *) kmalloc (nbytes, GFP_KERNEL);
if (isp == NULL) {
- printk ("%s: no memory for isp\n", __FUNCTION__);
+ printk ("%s: no memory for isp\n", __func__);
return (ret_val);
}
memset (isp, 0, nbytes);
- show_version ();
-
/* register the device */
ret_val = -ENXIO;
/*
/* try to get the interrupts */
// ### TO DO: interrupt handling with multiple instances
ret_val =
- ifx_int_wrapper.request (info->txirq, ifx_ssc_tx_int, SA_INTERRUPT, "ifx_ssc_tx", info);
+ request_irq(info->txirq, ifx_ssc_tx_int, SA_INTERRUPT, "ifx_ssc_tx", info);
if (ret_val) {
- printk ("%s: unable to get irq %d\n", __FUNCTION__,
+ printk ("%s: unable to get irq %d\n", __func__,
info->txirq);
local_irq_restore (flags);
goto errout;
}
ret_val =
- ifx_int_wrapper.request (info->rxirq, ifx_ssc_rx_int, SA_INTERRUPT, "ifx_ssc_rx", info);
+ request_irq(info->rxirq, ifx_ssc_rx_int, SA_INTERRUPT, "ifx_ssc_rx", info);
if (ret_val) {
- printk ("%s: unable to get irq %d\n", __FUNCTION__,
+ printk ("%s: unable to get irq %d\n", __func__,
info->rxirq);
local_irq_restore (flags);
goto irqerr;
}
ret_val =
- ifx_int_wrapper.request (info->errirq, ifx_ssc_err_int, SA_INTERRUPT,"ifx_ssc_err", info);
+ request_irq(info->errirq, ifx_ssc_err_int, SA_INTERRUPT,"ifx_ssc_err", info);
if (ret_val) {
- printk ("%s: unable to get irq %d\n", __FUNCTION__,
+ printk ("%s: unable to get irq %d\n", __func__,
info->errirq);
local_irq_restore (flags);
goto irqerr;
}
-/*
- ret_val = ifx_int_wrapper.request(info->frmirq, ifx_ssc_frm_int,
- 0, "ifx_ssc_frm", info);
- if (ret_val){
- printk("%s: unable to get irq %d\n", __FUNCTION__,
- info->frmirq);
- local_irq_restore(flags);
- goto irqerr;
- }
-
-*/
WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_IRNEN,
info->mapbase + IFX_SSC_IRN_EN);
- ifx_int_wrapper.enable (info->txirq);
- ifx_int_wrapper.enable (info->rxirq);
- ifx_int_wrapper.enable (info->errirq);
+ enable_irq(info->txirq);
+ enable_irq(info->rxirq);
+ enable_irq(info->errirq);
local_irq_restore (flags);
- } // for (i = 0; i < PORT_CNT; i++)
+ }
/* init the SSCs with default values */
for (i = 0; i < PORT_CNT; i++) {
info = &isp[i];
if (ifx_ssc_hwinit (info) < 0) {
printk ("%s: hardware init failed for port %d\n",
- __FUNCTION__, i);
+ __func__, i);
goto irqerr;
}
}
NULL);
return 0;
- irqerr:
+irqerr:
// ### TO DO: multiple instances
- ifx_int_wrapper.free (isp[0].txirq, &isp[0]);
- ifx_int_wrapper.free (isp[0].rxirq, &isp[0]);
- ifx_int_wrapper.free (isp[0].errirq, &isp[0]);
-/*
- ifx_int_wrapper.free(isp[0].frmirq, &isp[0]);
-*/
- errout:
+ free_irq(isp[0].txirq, &isp[0]);
+ free_irq(isp[0].rxirq, &isp[0]);
+ free_irq(isp[0].errirq, &isp[0]);
+errout:
/* free up any allocated memory in the error case */
kfree (isp);
return (ret_val);
WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE,
isp[i].mapbase + IFX_SSC_WHBSTATE);
/* free the interrupts */
- ifx_int_wrapper.free (isp[i].txirq, &isp[i]);
- ifx_int_wrapper.free (isp[i].rxirq, &isp[i]);
- ifx_int_wrapper.free (isp[i].errirq, &isp[i]);
-/*
- ifx_int_wrapper.free(isp[i].frmirq, &isp[i]);
-
- if (isp[i].rxbuf != NULL)
- kfree(isp[i].rxbuf);
- if (isp[i].txbuf != NULL)
- kfree(isp[i].txbuf);
-*/
+ free_irq(isp[i].txirq, &isp[i]);
+ free_irq(isp[i].rxirq, &isp[i]);
+ free_irq(isp[i].errirq, &isp[i]);
}
kfree (isp);
- /* unregister the device */
-// if (unregister_chrdev (maj, "ssc")) {
-// printk ("Unable to unregister major %d for the SSC\n", maj);
-// }
/* delete /proc read handler */
remove_proc_entry ("driver/ssc1", NULL);
remove_proc_entry ("driver/ssc2", NULL);
-} /* ifx_ssc_cleanup_module */
-
-module_exit (ifx_ssc_cleanup_module);
-
-/* Module entry-points */
-module_init (ifx_ssc_init);
-
-#ifndef MODULE
-static int __init
-ifx_ssc_set_maj (char *str)
-{
- maj = simple_strtol (str, NULL, 0);
- return 1;
}
-__setup ("ssc_maj=", ifx_ssc_set_maj);
-#endif /* !MODULE */
+module_init(ifx_ssc_init);
+module_exit(ifx_ssc_cleanup_module);
+
-#define DANUBE_SSC_EMSG(fmt,arg...) printk("%s: "fmt,__FUNCTION__, ##arg)
-/* Brief: chip select enable
- */
inline int
ifx_ssc_cs_low (u32 pin)
{
int ret = 0;
- if ((ret =
- ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_CLR,
- (unsigned long) &pin))) {
- DANUBE_SSC_EMSG ("clear CS %d fails\n", pin);
- }
+ if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_CLR, (unsigned long) &pin)))
+ printk ("clear CS %d fails\n", pin);
wmb ();
+
return ret;
}
+EXPORT_SYMBOL(ifx_ssc_cs_low);
-EXPORT_SYMBOL (ifx_ssc_cs_low);
-/* Brief: chip select disable
- */
inline int
ifx_ssc_cs_high (u32 pin)
{
int ret = 0;
- if ((ret =
- ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_SET,
- (unsigned long) &pin))) {
- DANUBE_SSC_EMSG ("set CS %d fails\n", pin);
- }
+ if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_SET, (unsigned long) &pin)))
+ printk ("set CS %d fails\n", pin);
wmb ();
+
return ret;
}
+EXPORT_SYMBOL(ifx_ssc_cs_high);
-EXPORT_SYMBOL (ifx_ssc_cs_high);
-/* Brief: one SSC session
- * Parameter:
- * tx_buf
- * tx_len
- * rx_buf
- * rx_len
- * session_mode: IFX_SSC_MODE_RXTX or IFX_SSC_MODE_TX
- * Return: >=0 number of bytes received (if rx_buf != 0) or transmitted
- * <0 error code
- * Description:
- * 0. copy data to internal buffer
- * 1. Write command
- * 2a. If SSC_SESSION_MODE_TXONLY, read tx_len data
- * 2b. If not Read back (tx_len + rx_len) data
- * 3. copy internal buffer to rx buf if necessary
- */
static int
ssc_session (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len)
{
char *ssc_tx_buf = NULL;
char *ssc_rx_buf = NULL;
-
-// volatile char ssc_tx_buf[128]={0};
-// volatile char ssc_rx_buf[128]={0};
-
int eff_size = 0;
u8 mode = 0;
if (tx_buf == NULL && tx_len == 0 && rx_buf == NULL && rx_len == 0) {
- DANUBE_SSC_EMSG ("invalid parameters\n");
+ printk ("invalid parameters\n");
ret = -EINVAL;
goto ssc_session_exit;
}
mode = IFX_SSC_MODE_RX;
}
else {
- DANUBE_SSC_EMSG ("invalid parameters\n");
+ printk ("invalid parameters\n");
ret = -EINVAL;
goto ssc_session_exit;
}
mode = IFX_SSC_MODE_TX;
}
else {
- DANUBE_SSC_EMSG ("invalid parameters\n");
+ printk ("invalid parameters\n");
ret = -EINVAL;
goto ssc_session_exit;
}
GFP_KERNEL);
}
if (ssc_tx_buf == NULL || ssc_rx_buf == NULL) {
- DANUBE_SSC_EMSG ("no memory for size of %d\n", eff_size);
+ printk ("no memory for size of %d\n", eff_size);
ret = -ENOMEM;
goto ssc_session_exit;
}
}
if (ret != eff_size) {
- DANUBE_SSC_EMSG ("ifx_ssc_write return %d\n", ret);
+ printk ("ifx_ssc_write return %d\n", ret);
goto ssc_session_exit;
}
ret = ifx_ssc_kread (0, ssc_rx_buf, eff_size);
if (ret != eff_size) {
- DANUBE_SSC_EMSG ("ifx_ssc_read return %d\n", ret);
+ printk ("ifx_ssc_read return %d\n", ret);
goto ssc_session_exit;
}
return ret;
}
-/* Brief: TX-RX session
- * Parameter:
- * tx_buf
- * tx_len
- * rx_buf
- * rx_len
- * Return: >=0 number of bytes received
- * <0 error code
- * Description:
- * 1. TX session
- * 2. RX session
- */
int
ifx_ssc_txrx (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len)
{
- return ssc_session (tx_buf, tx_len, rx_buf, rx_len);
+ return ssc_session(tx_buf, tx_len, rx_buf, rx_len);
}
+EXPORT_SYMBOL(ifx_ssc_txrx);
-EXPORT_SYMBOL (ifx_ssc_txrx);
-/* Brief: TX only session
- * Parameter:
- * tx_buf
- * tx_len
- * Return: >=0 number of bytes transmitted
- * <0 error code
- */
int
ifx_ssc_tx (char *tx_buf, u32 tx_len)
{
- return ssc_session (tx_buf, tx_len, NULL, 0);
+ return ssc_session(tx_buf, tx_len, NULL, 0);
}
+EXPORT_SYMBOL(ifx_ssc_tx);
-EXPORT_SYMBOL (ifx_ssc_tx);
-/* Brief: RX only session
- * Parameter:
- * rx_buf
- * rx_len
- * Return: >=0 number of bytes received
- * <0 error code
- */
int
ifx_ssc_rx (char *rx_buf, u32 rx_len)
{
- return ssc_session (NULL, 0, rx_buf, rx_len);
+ return ssc_session(NULL, 0, rx_buf, rx_len);
}
-
-EXPORT_SYMBOL (ifx_ssc_rx);
+EXPORT_SYMBOL(ifx_ssc_rx);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");