summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/spi/spictrl.c')
-rw-r--r--c/src/lib/libbsp/sparc/shared/spi/spictrl.c1017
1 files changed, 0 insertions, 1017 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/spi/spictrl.c b/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
deleted file mode 100644
index 2d639882b2..0000000000
--- a/c/src/lib/libbsp/sparc/shared/spi/spictrl.c
+++ /dev/null
@@ -1,1017 +0,0 @@
-/*
- * SPICTRL SPI driver implmenetation
- *
- * COPYRIGHT (c) 2009.
- * Cobham Gaisler AB.
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#include <bsp.h>
-#include <rtems/libio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <rtems/bspIo.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <drvmgr/drvmgr.h>
-#include <drvmgr/ambapp_bus.h>
-#include <bsp/spictrl.h>
-#include <ambapp.h>
-
-#include <rtems/libi2c.h>
-
-/*#define DEBUG 1*/
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#define STATIC
-#else
-#define DBG(x...)
-#define STATIC static
-#endif
-
-/*** CAPABILITY REGISTER 0x00 ***/
-#define SPICTRL_CAP_SSSZ_BIT 24
-#define SPICTRL_CAP_AMODE_BIT 18
-#define SPICTRL_CAP_ASELA_BIT 17
-#define SPICTRL_CAP_SSEN_BIT 16
-#define SPICTRL_CAP_FDEPTH_BIT 8
-#define SPICTRL_CAP_REV_BIT 0
-
-#define SPICTRL_CAP_SSSZ (0xff << SPICTRL_CAP_SSSZ_BIT)
-#define SPICTRL_CAP_AMODE (1<<SPICTRL_CAP_AMODE_BIT)
-#define SPICTRL_CAP_ASELA (1<<SPICTRL_CAP_ASELA_BIT)
-#define SPICTRL_CAP_SSEN (1 << SPICTRL_CAP_SSEN_BIT)
-#define SPICTRL_CAP_FDEPTH (0xff << SPICTRL_CAP_FDEPTH_BIT)
-#define SPICTRL_CAP_REV (0xff << SPICTRL_CAP_REV_BIT)
-
-/*** MODE REGISTER 0x20 ***/
-#define SPICTRL_MODE_AMEN_BIT 31
-#define SPICTRL_MODE_LOOP_BIT 30
-#define SPICTRL_MODE_CPOL_BIT 29
-#define SPICTRL_MODE_CPHA_BIT 28
-#define SPICTRL_MODE_DIV16_BIT 27
-#define SPICTRL_MODE_REV_BIT 26
-#define SPICTRL_MODE_MS_BIT 25
-#define SPICTRL_MODE_EN_BIT 24
-#define SPICTRL_MODE_LEN_BIT 20
-#define SPICTRL_MODE_PM_BIT 16
-#define SPICTRL_MODE_ASEL_BIT 14
-#define SPICTRL_MODE_FACT_BIT 13
-#define SPICTRL_MODE_CG_BIT 7
-#define SPICTRL_MODE_TAC_BIT 4
-
-#define SPICTRL_MODE_AMEN (1 << SPICTRL_MODE_AMEN_BIT)
-#define SPICTRL_MODE_LOOP (1 << SPICTRL_MODE_LOOP_BIT)
-#define SPICTRL_MODE_CPOL (1 << SPICTRL_MODE_CPOL_BIT)
-#define SPICTRL_MODE_CPHA (1 << SPICTRL_MODE_CPHA_BIT)
-#define SPICTRL_MODE_DIV16 (1 << SPICTRL_MODE_DIV16_BIT)
-#define SPICTRL_MODE_REV (1 << SPICTRL_MODE_REV_BIT)
-#define SPICTRL_MODE_MS (1 << SPICTRL_MODE_MS_BIT)
-#define SPICTRL_MODE_EN (1 << SPICTRL_MODE_EN_BIT)
-#define SPICTRL_MODE_LEN (0xf << SPICTRL_MODE_LEN_BIT)
-#define SPICTRL_MODE_PM (0xf << SPICTRL_MODE_PM_BIT)
-#define SPICTRL_MODE_ASEL (1 << SPICTRL_MODE_ASEL_BIT)
-#define SPICTRL_MODE_FACT (1 << SPICTRL_MODE_FACT_BIT)
-#define SPICTRL_MODE_CG (0x1f << SPICTRL_MODE_CG_BIT)
-#define SPICTRL_MODE_TAC (0x1 << SPICTRL_MODE_TAC_BIT)
-
-/*** EVENT REGISTER 0x24 ***/
-#define SPICTRL_EVENT_AT_BIT 15
-#define SPICTRL_EVENT_LT_BIT 14
-#define SPICTRL_EVENT_OV_BIT 12
-#define SPICTRL_EVENT_UN_BIT 11
-#define SPICTRL_EVENT_MME_BIT 10
-#define SPICTRL_EVENT_NE_BIT 9
-#define SPICTRL_EVENT_NF_BIT 8
-
-#define SPICTRL_EVENT_AT (1 << SPICTRL_EVENT_AT_BIT)
-#define SPICTRL_EVENT_LT (1 << SPICTRL_EVENT_LT_BIT)
-#define SPICTRL_EVENT_OV (1 << SPICTRL_EVENT_OV_BIT)
-#define SPICTRL_EVENT_UN (1 << SPICTRL_EVENT_UN_BIT)
-#define SPICTRL_EVENT_MME (1 << SPICTRL_EVENT_MME_BIT)
-#define SPICTRL_EVENT_NE (1 << SPICTRL_EVENT_NE_BIT)
-#define SPICTRL_EVENT_NF (1 << SPICTRL_EVENT_NF_BIT)
-
-/*** MASK REGISTER 0x28 ***/
-#define SPICTRL_MASK_ATE_BIT 15
-#define SPICTRL_MASK_LTE_BIT 14
-#define SPICTRL_MASK_OVE_BIT 12
-#define SPICTRL_MASK_UNE_BIT 11
-#define SPICTRL_MASK_MMEE_BIT 10
-#define SPICTRL_MASK_NEE_BIT 9
-#define SPICTRL_MASK_NFE_BIT 8
-
-#define SPICTRL_MASK_ATE (1 << SPICTRL_MASK_ATE_BIT)
-#define SPICTRL_MASK_LTE (1 << SPICTRL_MASK_LTE_BIT)
-#define SPICTRL_MASK_OVE (1 << SPICTRL_MASK_OVE_BIT)
-#define SPICTRL_MASK_UNE (1 << SPICTRL_MASK_UNE_BIT)
-#define SPICTRL_MASK_MMEE (1 << SPICTRL_MASK_MMEE_BIT)
-#define SPICTRL_MASK_NEE (1 << SPICTRL_MASK_NEE_BIT)
-#define SPICTRL_MASK_NFE (1 << SPICTRL_MASK_NFE_BIT)
-
-/*** COMMAND REGISTER 0x2c ***/
-#define SPICTRL_CMD_LST_BIT 22
-#define SPICTRL_CMD_LST (1 << SPICTRL_CMD_LST_BIT)
-
-/*** TRANSMIT REGISTER 0x30 ***/
-#define SPICTRL_TX_TDATA_BIT 0
-#define SPICTRL_TX_TDATA 0xffffffff
-
-/*** RECEIVE REGISTER 0x34 ***/
-#define SPICTRL_RX_RDATA_BIT 0
-#define SPICTRL_RX_RDATA 0xffffffff
-
-/*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/
-
-/*** AM CONFIGURATION REGISTER 0x40 ***/
-#define SPICTRL_AMCFG_ERPT_BIT 6
-#define SPICTRL_AMCFG_SEQ_BIT 5
-#define SPICTRL_AMCFG_STRICT_BIT 4
-#define SPICTRL_AMCFG_OVTB_BIT 3
-#define SPICTRL_AMCFG_OVDB_BIT 2
-#define SPICTRL_AMCFG_ACT_BIT 1
-#define SPICTRL_AMCFG_EACT_BIT 0
-
-#define SPICTRL_AMCFG_ERPT (1<<SPICTRL_AMCFG_ERPT_BIT)
-#define SPICTRL_AMCFG_SEQ (1<<SPICTRL_AMCFG_SEQ_BIT)
-#define SPICTRL_AMCFG_STRICT (1<<SPICTRL_AMCFG_STRICT_BIT)
-#define SPICTRL_AMCFG_OVTB (1<<SPICTRL_AMCFG_OVTB_BIT)
-#define SPICTRL_AMCFG_OVDB (1<<SPICTRL_AMCFG_OVDB_BIT)
-#define SPICTRL_AMCFG_ACT (1<<SPICTRL_AMCFG_ACT_BIT)
-#define SPICTRL_AMCFG_EACT (1<<SPICTRL_AMCFG_EACT_BIT)
-
-struct spictrl_priv {
- rtems_libi2c_bus_t i2clib_desc;
- struct drvmgr_dev *dev;
- struct spictrl_regs *regs;
- int irq;
- int minor;
- unsigned int core_freq_hz;
-
- /* Driver */
- int fdepth;
- int bits_per_char;
- int lsb_first;
- int txshift;
- int rxshift;
- unsigned int idle_char;
- int (*slvSelFunc)(void *regs, uint32_t addr, int select);
-
- /* Automated Periodic transfers */
- int periodic_started;
- struct spictrl_ioctl_config periodic_cfg;
-};
-
-/******************* Driver Manager Part ***********************/
-
-int spictrl_device_init(struct spictrl_priv *priv);
-
-int spictrl_init2(struct drvmgr_dev *dev);
-int spictrl_init3(struct drvmgr_dev *dev);
-
-struct drvmgr_drv_ops spictrl_ops =
-{
- .init = {NULL, spictrl_init2, spictrl_init3, NULL},
- .remove = NULL,
- .info = NULL
-};
-
-struct amba_dev_id spictrl_ids[] =
-{
- {VENDOR_GAISLER, GAISLER_SPICTRL},
- {0, 0} /* Mark end of table */
-};
-
-struct amba_drv_info spictrl_drv_info =
-{
- {
- DRVMGR_OBJ_DRV, /* Driver */
- NULL, /* Next driver */
- NULL, /* Device list */
- DRIVER_AMBAPP_GAISLER_SPICTRL_ID, /* Driver ID */
- "SPICTRL_DRV", /* Driver Name */
- DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
- &spictrl_ops,
- NULL, /* Funcs */
- 0, /* No devices yet */
- 0,
- },
- &spictrl_ids[0]
-};
-
-void spictrl_register_drv (void)
-{
- DBG("Registering SPICTRL driver\n");
- drvmgr_drv_register(&spictrl_drv_info.general);
-}
-
-int spictrl_init2(struct drvmgr_dev *dev)
-{
- struct spictrl_priv *priv;
-
- DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
-
- priv = dev->priv = malloc(sizeof(struct spictrl_priv));
- if ( !priv )
- return DRVMGR_NOMEM;
- memset(priv, 0, sizeof(*priv));
- priv->dev = dev;
-
- /* This core will not find other cores, so we wait for init2() */
-
- return DRVMGR_OK;
-}
-
-int spictrl_init3(struct drvmgr_dev *dev)
-{
- struct spictrl_priv *priv;
- char prefix[32];
- char devName[32];
- int rc;
-
- priv = (struct spictrl_priv *)dev->priv;
-
- /* Do initialization */
-
- /* Initialize i2c library */
- rc = rtems_libi2c_initialize();
- if (rc != 0) {
- DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n");
- free(dev->priv);
- dev->priv = NULL;
- return DRVMGR_FAIL;
- }
-
- /* I/O system registered and initialized
- * Now we take care of device initialization.
- */
-
- /* Get frequency */
- if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) {
- return DRVMGR_FAIL;
- }
-
- if ( spictrl_device_init(priv) ) {
- free(dev->priv);
- dev->priv = NULL;
- return DRVMGR_FAIL;
- }
-
- /* Get Filesystem name prefix */
- prefix[0] = '\0';
- if ( drvmgr_get_dev_prefix(dev, prefix) ) {
- /* Failed to get prefix, make sure of a unique FS name
- * by using the driver minor.
- */
- sprintf(devName, "/dev/spi%d", dev->minor_drv+1);
- } else {
- /* Got special prefix, this means we have a bus prefix
- * And we should use our "bus minor"
- */
- sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1);
- }
-
- /* Register Bus for this Device */
- rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
- if (rc < 0) {
- DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName);
- free(dev->priv);
- dev->priv = NULL;
- return DRVMGR_FAIL;
- }
- priv->minor = rc;
-
- return DRVMGR_OK;
-}
-
-/******************* Driver Implementation ***********************/
-
-STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
- uint32_t addr, int rw);
-
-/* Set as high frequency of SCK as possible but not higher than
- * requested frequency (freq).
- */
-static int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq)
-{
- unsigned int core_freq_hz = priv->core_freq_hz;
- unsigned int lowest_freq_possible;
- unsigned int div, div16, pm, fact;
-
- /* Lowest possible when DIV16 is set and PM is 0xf */
- lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1));
-
- if ( freq < lowest_freq_possible ) {
- DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n",
- freq, core_freq_hz, lowest_freq_possible);
- return -1;
- }
-
- div = ((core_freq_hz / 2) + (freq-1)) / freq;
- DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq);
-
- /* Is DIV16 neccessary? */
- if ( div > 16 ) {
- div = (div + (16 - 1)) / 16;
- div16 = 1;
- } else {
- div16 = 0;
- }
-
- if ( div > 0xf ) {
- fact = 0; /* FACT adds an factor /2 */
- div = (div + (2 - 1)) / 2;
- } else {
- fact = 1;
- }
-
- pm = div-1;
-
- /* Update hardware */
- priv->regs->mode =
- (priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) |
- (pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) |
- (fact << SPICTRL_MODE_FACT_BIT);
-
- DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n",
- core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1)),
- freq, pm, fact, div16, core_freq_hz);
-
- return 0;
-}
-
-/* Start Automated Periodic transfers, after this call read can be done */
-static int spictrl_start_periodic(struct spictrl_priv *priv)
-{
- struct spictrl_ioctl_config *cfg = &priv->periodic_cfg;
- unsigned int am_cfg;
-
- /* Clear the events */
- priv->regs->event = 0xffffffff;
-
- /* Enable core */
- priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
-
- /* Update hardware config from flags and period */
- priv->regs->am_period = cfg->period;
-
- /* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */
- am_cfg = (cfg->period_flags & 0x1f8) >> 1;
- priv->regs->am_cfg = am_cfg;
-
- /* Start automated periodic transfers */
- if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) {
- /* Enable external triggering */
- priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT;
- } else {
- /* Activate periodic transfers */
- priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT;
- }
-
- return 0;
-}
-
-/* Stop Automated Periodic transfers */
-static void spictrl_stop_periodic(struct spictrl_priv *priv)
-{
- priv->regs->am_cfg = 0;
-}
-
-/* Return the status of the SPI controller (the event register),
- * it may be needed in periodic mode to look at the Not Full bit (NF)
- * in order not to hang in an infinte loop when read is called.
- */
-static inline unsigned int spictrl_status(struct spictrl_priv *priv)
-{
- return priv->regs->event;
-}
-
-static int spictrl_read_periodic(
- struct spictrl_priv *priv,
- struct spictrl_period_io *rarg)
-{
- int i, rxi, rxshift, bits_per_char, reg;
- unsigned int rx_word, mask;
- void *rxbuf;
-
- if ( rarg->options & 0x1 ) {
- /* Read mask registers */
- for (i=0; i<4; i++) {
- rarg->masks[i] = priv->regs->am_mask[i];
- }
- }
-
- if ( rarg->options & 0x2 ) {
- /* Read receive registers (after updating masks so that the caller can
- * read current buffer without knowning of actual register mask).
- */
-
- /* If not started we could be hanging here forever. */
- if ( !priv->periodic_started )
- return -1;
-
- rxshift = priv->rxshift;
- bits_per_char = priv->bits_per_char;
- rx_word = 0;
-
- rxbuf = rarg->data;
- if ( !rxbuf ) {
- /* If no data pointer specified we cannot copy data... */
- return -1;
- }
-
- /* Wait until all data is available (if started) */
- while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) {
- ;
- }
-
- rxi = 0;
- for (i=0; i<4; i++) {
- mask = rarg->masks[i];
- reg = 0;
- while ( mask ) {
- if ( mask & 1 ) {
- /* Update Register */
- rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift;
-
- if ( bits_per_char <= 8 ) {
- *((unsigned char *)rxbuf + rxi) = rx_word;
- } else if ( bits_per_char <= 16 ) {
- *((unsigned short *)rxbuf + rxi) = rx_word;
- } else {
- *((unsigned int *)rxbuf + rxi) = rx_word;
- }
- rxi++;
- }
-
- mask = mask>>1;
- reg++;
- }
- }
- }
-
- return 0;
-}
-
-static int spictrl_write_periodic(
- struct spictrl_priv *priv,
- struct spictrl_period_io *warg)
-{
- int i, txi, txshift, bits_per_char, reg;
- unsigned int tx_word, mask;
- void *txbuf;
-
- if ( warg->options & 0x2 ) {
-
- /* Make sure core is enabled, otherwise TX registers writes are lost */
- priv->regs->mode |= SPICTRL_MODE_EN;
-
- /* Update Transmit registers (before updating masks so that we do not
- * transmit invalid data)
- */
-
- txshift = priv->txshift;
- bits_per_char = priv->bits_per_char;
- tx_word = 0;
-
- txbuf = warg->data;
- if ( !txbuf ) {
- /* If no data pointer specified we fill up with
- * idle chars.
- */
- tx_word = priv->idle_char << txshift;
- }
-
- txi = 0;
- for (i=0; i<4; i++) {
- mask = warg->masks[i];
- reg = 0;
- while ( mask ) {
- if ( mask & 1 ) {
- if ( txbuf ) {
- if ( bits_per_char <= 8 ) {
- tx_word = *((unsigned char *)txbuf + txi);
- } else if ( bits_per_char <= 16 ) {
- tx_word = *((unsigned short *)txbuf + txi);
- } else {
- tx_word = *((unsigned int *)txbuf + txi);
- }
- tx_word = tx_word << txshift;
- txi++;
- }
-
- /* Update Register */
- DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]);
- priv->regs->am_tx[i*32 + reg] = tx_word;
- }
-
- mask = mask>>1;
- reg++;
- }
- }
- }
-
- if ( warg->options & 0x1 ) {
- /* Update mask registers */
- for (i=0; i<4; i++) {
- DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i);
- priv->regs->am_mask[i] = warg->masks[i];
- }
- }
-
- return 0;
-}
-
-static int spictrl_read_write(
- struct spictrl_priv *priv,
- void *rxbuf,
- void *txbuf,
- int len)
-{
- unsigned int tx_word, rx_word, tmp;
- int txshift = priv->txshift;
- int rxshift = priv->rxshift;
- int txi, rxi, bits_per_char;
- int length;
-
- /* Use IOCTL for periodic reads. The FIFO is not supported in automated
- * periodic mode
- */
- if ( priv->periodic_cfg.periodic_mode ) {
- return -1;
- }
-
- bits_per_char = priv->bits_per_char;
- tx_word = 0;
- if ( !txbuf ) {
- tx_word = priv->idle_char << txshift;
- }
-
- /* Clear the events */
- priv->regs->event = 0xffffffff;
-
- /* Enable core */
- priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
-
- length = len;
- if ( bits_per_char > 8 ) {
- length = length / 2;
- if ( bits_per_char > 16 )
- length = length / 2;
- }
- DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift);
-
- txi=0;
- rxi=0;
- while ( (rxi < length) || (txi < length) ) {
- /* Get transmit word */
- if ( length > txi ) {
- if ( txbuf ) {
- if ( bits_per_char <= 8 ) {
- tx_word = *((unsigned char *)txbuf + txi);
- } else if ( bits_per_char <= 16 ) {
- tx_word = *((unsigned short *)txbuf + txi);
- } else {
- tx_word = *((unsigned int *)txbuf + txi);
- }
- tx_word = tx_word << txshift;
- }
-
- /* Wait for SPICTRL to get ready for another TX char */
- while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) {
- /* Wait for all chars to transmit */
-/* Could implement waiting for SPICTRL IRQ here */
- }
-
- DBG("SPICTRL: Writing 0x%x\n", tx_word);
-
- /* Transmit word */
- priv->regs->tx = tx_word;
- txi++;
- }
-
- /* Read */
- while ( priv->regs->event & SPICTRL_EVENT_NE ) {
- /* Read to avoid overrun */
- tmp = priv->regs->rx;
- DBG("SPICTRL: Read 0x%x\n", tmp);
-
- if ( rxbuf && (length > rxi) ) {
- /* Copy word to user buffer */
- rx_word = (tmp >> rxshift);
-
- DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift);
-
- if ( bits_per_char <= 8 ) {
- *((unsigned char *)rxbuf + rxi) = rx_word;
- } else if ( bits_per_char <= 16 ) {
- *((unsigned short *)rxbuf + rxi) = rx_word;
- } else {
- *((unsigned int *)rxbuf + rxi) = rx_word;
- }
-
- }
- rxi++;
- }
- }
-
- return len;
-}
-
-
-STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
-
- DBG("SPICTRL: spictrl_libi2c_init\n");
-
- /* Disable SPICTTRL, Select Master mode */
- priv->regs->mode = SPICTRL_MODE_MS;
-
- /* Mask all Interrupts */
- priv->regs->mask = 0;
-
- /* Select no slave */
- priv->regs->slvsel = 0xffffffff;
-
- /* Clear all events */
- priv->regs->event = 0xffffffff;
-
- return 0;
-}
-
-/* Nothing to be done in start */
-STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl)
-{
- DBG("SPICTRL: spictrl_libi2c_send_start\n");
-
- return 0;
-}
-
-/* Inactivate all chip selects, indicates "End of command" */
-STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
-
- priv->regs->slvsel = 0xffffffff;
-
- if ( priv->slvSelFunc ) {
- /* unslect all */
- return priv->slvSelFunc(priv->regs, -1, 0);
- }
-
- DBG("SPICTRL: spictrl_libi2c_send_stop\n");
- return 0;
-}
-
-/* Select Slave address by selecting apropriate chip select */
-STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
- uint32_t addr, int rw)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
-
- DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr);
-
- if ( priv->slvSelFunc ) {
- /* Let user set spi select using for example GPIO */
- return priv->slvSelFunc(priv->regs, addr, 1);
- } else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) {
- int slaves;
-
- /* Maximum number of slaves the core support */
- slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT;
-
- if ( addr > slaves )
- return -1;
-
- if ( (priv->regs->capability & SPICTRL_CAP_ASELA) &&
- (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) {
- /* When automatic slave select is supported by hardware and
- * enabled by configuration the SPI address is determined by
- * the automatic slave select register and the "idle" slave
- * select register is set by configuration.
- */
- priv->regs->am_slvsel = ~(1<<(addr-1));
- priv->regs->slvsel = priv->periodic_cfg.period_slvsel;
- /* Enable automatic slave select */
- priv->regs->mode |= SPICTRL_MODE_ASEL;
- } else {
- /* Normal mode */
- priv->regs->slvsel = ~(1<<(addr-1));
- }
- }
-
- return 0;
-}
-
-/* Read a number of bytes */
-STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl,
- unsigned char *bytes, int nbytes)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
- int ret;
-
- DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes);
- ret = spictrl_read_write(priv, bytes, NULL, nbytes);
- if ( ret < 0 ) {
- printf("SPICTRL: Error Reading\n");
- }
-#ifdef DEBUG
- else {
- int i;
- for(i=0; i<nbytes; i+=16) {
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
- bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
- bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
- }
- }
-#endif
- return ret;
-}
-
-/* Write a number of bytes */
-STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl,
- unsigned char *bytes, int nbytes)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
-
-#ifdef DEBUG
- int i;
- DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes);
-
- for(i=0; i<nbytes; i+=16) {
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
- bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
- bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
- }
-#endif
-
- return spictrl_read_write(priv, NULL, bytes, nbytes);
-}
-
-/* Configure the interface and do simultaneous READ/WRITE operations */
-STATIC int spictrl_libi2c_ioctl(
- rtems_libi2c_bus_t * bushdl,
- int cmd,
- void *buffer)
-{
- struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
- int ret;
-
- DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer);
-
- switch (cmd) {
- case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
- {
- rtems_libi2c_tfr_mode_t *trf_mode = buffer;
- unsigned int mode;
-
- /* Must disable core to write new values */
- priv->regs->mode &= ~SPICTRL_MODE_EN;
-
- /* Change bit frequency */
- if ( spictrl_set_freq(priv, trf_mode->baudrate) ) {
- /* Unable to set such a low frequency. */
- return -1;
- }
-
- /* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */
- mode = (priv->regs->mode &
- ~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN));
- if ( trf_mode->clock_inv )
- mode |= SPICTRL_MODE_CPOL;
- if ( trf_mode->clock_phs )
- mode |= SPICTRL_MODE_CPHA;
- if ( trf_mode->lsb_first == 0 )
- mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */
-
- if ( (trf_mode->bits_per_char < 4) ||
- ((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) )
- return -1;
- if ( trf_mode->bits_per_char == 32 ) {
- priv->txshift = 0;
- priv->rxshift = 0;
- } else {
- mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT;
- if ( trf_mode->lsb_first == 0 ) {
- /* REV bit 1 */
- priv->txshift = 32 - trf_mode->bits_per_char;
- priv->rxshift = 16;
- } else {
- /* REV bit 0 */
- priv->txshift = 0;
- priv->rxshift = 16 - trf_mode->bits_per_char;
- }
- }
-
- priv->bits_per_char = trf_mode->bits_per_char;
- priv->lsb_first = trf_mode->lsb_first;
- priv->idle_char = trf_mode->idle_char;
-
- /* Update hardware */
- priv->regs->mode = mode;
-
- return 0;
- }
-
- case RTEMS_LIBI2C_IOCTL_READ_WRITE:
- {
- rtems_libi2c_read_write_t *arg = buffer;
-
- DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt);
-#ifdef DEBUG
- /* Printf out what is going to be transmitted */
- if ( arg->wr_buf ) {
- unsigned char *bytes = (unsigned char *)arg->wr_buf;
- int i;
- for(i=0; i<arg->byte_cnt; i+=16) {
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
- bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
- bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
- }
- }
-#endif
-
- ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf,
- arg->byte_cnt);
-#ifdef DEBUG
- /* Printf out what was read */
- if ( arg->rd_buf ) {
- unsigned char *bytes = (unsigned char *)arg->rd_buf;
- int i;
- for(i=0; i<arg->byte_cnt; i+=16) {
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
- bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
- DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
- bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
- }
- }
-#endif
- return ret;
- }
-
- /* Enable Periodic mode */
- case SPICTRL_IOCTL_CONFIG:
- {
- struct spictrl_ioctl_config *cfg;
-
- DBG("SPICTRL: Configuring Periodic mode\n");
-
- if ( priv->periodic_started ) {
- DBG("SPICTRL: Periodic mode already started, too late to configure\n");
- return -1;
- }
-
- cfg = buffer;
- if ( cfg == NULL ) {
- memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg));
- } else {
- priv->periodic_cfg = *cfg;
- }
- cfg = &priv->periodic_cfg;
- if ( cfg->periodic_mode ) {
- /* Enable Automated Periodic mode */
- priv->regs->mode |= SPICTRL_MODE_AMEN;
-
- /* Check that hardware has support for periodic mode */
- if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) {
- priv->periodic_cfg.periodic_mode = 0;
- DBG("SPICTRL: Periodic mode not supported by hardware\n");
- return -1;
- }
- } else {
- /* Disable Periodic mode */
- priv->regs->mode &= ~SPICTRL_MODE_AMEN;
- }
- priv->periodic_started = 0;
-
- /* Set clockgap and TAC */
- priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) |
- (cfg->clock_gap << SPICTRL_MODE_CG_BIT) |
- (cfg->flags & SPICTRL_MODE_TAC);
- return 0;
- }
- case SPICTRL_IOCTL_PERIOD_START:
- {
- if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) {
- return -1;
- }
- if ( spictrl_start_periodic(priv) == 0 ) {
- priv->periodic_started = 1;
- return 0;
- } else
- return -1;
- }
- case SPICTRL_IOCTL_PERIOD_STOP:
- {
- if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) {
- return -1;
- }
- spictrl_stop_periodic(priv);
- priv->periodic_started = 0;
- return 0;
- }
- case SPICTRL_IOCTL_STATUS:
- {
- if ( !buffer )
- return 0;
- *(unsigned int *)buffer = spictrl_status(priv);
- return 0;
- }
-
- case SPICTRL_IOCTL_PERIOD_WRITE:
- {
- if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
- return -1;
- }
- if ( spictrl_write_periodic(priv, (struct spictrl_period_io *)
- buffer) == 0 ) {
- return 0;
- } else
- return -1;
- }
-
- case SPICTRL_IOCTL_PERIOD_READ:
- {
- if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
- return -1;
- }
- if ( spictrl_read_periodic(priv, (struct spictrl_period_io *)
- buffer) == 0 ) {
- return 0;
- } else
- return -1;
- }
-
- case SPICTRL_IOCTL_REGS:
- {
- /* Copy Register Base Address to user space */
- if ( !buffer ) {
- return -1;
- }
- *(struct spictrl_regs **)buffer = priv->regs;
- return 0;
- }
-
- default:
- /* Unknown IOCTL */
- return -1;
- }
-
- return 0;
-}
-
-STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops =
-{
- .init = spictrl_libi2c_init,
- .send_start = spictrl_libi2c_send_start,
- .send_stop = spictrl_libi2c_send_stop,
- .send_addr = spictrl_libi2c_send_addr,
- .read_bytes = spictrl_libi2c_read_bytes,
- .write_bytes = spictrl_libi2c_write_bytes,
- .ioctl = spictrl_libi2c_ioctl
-};
-
-int spictrl_device_init(struct spictrl_priv *priv)
-{
- struct amba_dev_info *ambadev;
- struct ambapp_core *pnpinfo;
- union drvmgr_key_value *value;
-
- /* Get device information from AMBA PnP information */
- ambadev = (struct amba_dev_info *)priv->dev->businfo;
- if ( ambadev == NULL ) {
- return -1;
- }
- pnpinfo = &ambadev->info;
- priv->irq = pnpinfo->irq;
- priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start;
- priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT;
-
- DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth);
-
- /* Mask all Interrupts */
- priv->regs->mask = 0;
-
- /* Disable SPICTTRL */
- priv->regs->mode = 0;
-
- /* Get custom */
- value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", DRVMGR_KT_POINTER);
- if ( value ) {
- priv->slvSelFunc = value->ptr;
- }
-
- /* Prepare I2C layer */
- priv->i2clib_desc.ops = &spictrl_libi2c_ops;
- priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops);
- return 0;
-}