Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:07

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  SPICTRL SPI driver implmenetation
0005  *
0006  *  COPYRIGHT (c) 2009.
0007  *  Cobham Gaisler AB.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <bsp.h>
0032 #include <rtems/libio.h>
0033 #include <stdlib.h>
0034 #include <assert.h>
0035 #include <rtems/bspIo.h>
0036 #include <string.h>
0037 #include <stdio.h>
0038 
0039 #include <drvmgr/drvmgr.h>
0040 #include <grlib/ambapp_bus.h>
0041 #include <grlib/spictrl.h>
0042 #include <grlib/ambapp.h>
0043 
0044 #include <rtems/libi2c.h>
0045 
0046 #include <grlib/grlib_impl.h>
0047 
0048 /*#define DEBUG 1*/
0049 
0050 #ifdef DEBUG
0051 #define DBG(x...) printk(x)
0052 #define STATIC
0053 #else
0054 #define DBG(x...) 
0055 #define STATIC static
0056 #endif
0057 
0058 /*** CAPABILITY REGISTER 0x00 ***/
0059 #define SPICTRL_CAP_SSSZ_BIT    24
0060 #define SPICTRL_CAP_AMODE_BIT   18
0061 #define SPICTRL_CAP_ASELA_BIT   17
0062 #define SPICTRL_CAP_SSEN_BIT    16
0063 #define SPICTRL_CAP_FDEPTH_BIT  8
0064 #define SPICTRL_CAP_REV_BIT 0
0065 
0066 #define SPICTRL_CAP_SSSZ    (0xff << SPICTRL_CAP_SSSZ_BIT)
0067 #define SPICTRL_CAP_AMODE   (1<<SPICTRL_CAP_AMODE_BIT)
0068 #define SPICTRL_CAP_ASELA   (1<<SPICTRL_CAP_ASELA_BIT)
0069 #define SPICTRL_CAP_SSEN    (1 << SPICTRL_CAP_SSEN_BIT)
0070 #define SPICTRL_CAP_FDEPTH  (0xff << SPICTRL_CAP_FDEPTH_BIT)
0071 #define SPICTRL_CAP_REV     (0xff << SPICTRL_CAP_REV_BIT)
0072 
0073 /*** MODE REGISTER 0x20 ***/
0074 #define SPICTRL_MODE_AMEN_BIT   31
0075 #define SPICTRL_MODE_LOOP_BIT   30
0076 #define SPICTRL_MODE_CPOL_BIT   29
0077 #define SPICTRL_MODE_CPHA_BIT   28
0078 #define SPICTRL_MODE_DIV16_BIT  27
0079 #define SPICTRL_MODE_REV_BIT    26
0080 #define SPICTRL_MODE_MS_BIT 25
0081 #define SPICTRL_MODE_EN_BIT 24
0082 #define SPICTRL_MODE_LEN_BIT    20
0083 #define SPICTRL_MODE_PM_BIT 16
0084 #define SPICTRL_MODE_ASEL_BIT   14
0085 #define SPICTRL_MODE_FACT_BIT   13
0086 #define SPICTRL_MODE_CG_BIT 7
0087 #define SPICTRL_MODE_TAC_BIT    4
0088 
0089 #define SPICTRL_MODE_AMEN   (1 << SPICTRL_MODE_AMEN_BIT)
0090 #define SPICTRL_MODE_LOOP   (1 << SPICTRL_MODE_LOOP_BIT)
0091 #define SPICTRL_MODE_CPOL   (1 << SPICTRL_MODE_CPOL_BIT)
0092 #define SPICTRL_MODE_CPHA   (1 << SPICTRL_MODE_CPHA_BIT)
0093 #define SPICTRL_MODE_DIV16  (1 << SPICTRL_MODE_DIV16_BIT)
0094 #define SPICTRL_MODE_REV    (1 << SPICTRL_MODE_REV_BIT)
0095 #define SPICTRL_MODE_MS     (1 << SPICTRL_MODE_MS_BIT)
0096 #define SPICTRL_MODE_EN     (1 << SPICTRL_MODE_EN_BIT)
0097 #define SPICTRL_MODE_LEN    (0xf << SPICTRL_MODE_LEN_BIT)
0098 #define SPICTRL_MODE_PM     (0xf << SPICTRL_MODE_PM_BIT)
0099 #define SPICTRL_MODE_ASEL   (1 << SPICTRL_MODE_ASEL_BIT)
0100 #define SPICTRL_MODE_FACT   (1 << SPICTRL_MODE_FACT_BIT)
0101 #define SPICTRL_MODE_CG     (0x1f << SPICTRL_MODE_CG_BIT)
0102 #define SPICTRL_MODE_TAC    (0x1 << SPICTRL_MODE_TAC_BIT)
0103 
0104 /*** EVENT REGISTER 0x24 ***/
0105 #define SPICTRL_EVENT_AT_BIT    15
0106 #define SPICTRL_EVENT_LT_BIT    14
0107 #define SPICTRL_EVENT_OV_BIT    12
0108 #define SPICTRL_EVENT_UN_BIT    11
0109 #define SPICTRL_EVENT_MME_BIT   10
0110 #define SPICTRL_EVENT_NE_BIT    9
0111 #define SPICTRL_EVENT_NF_BIT    8
0112 
0113 #define SPICTRL_EVENT_AT    (1 << SPICTRL_EVENT_AT_BIT)
0114 #define SPICTRL_EVENT_LT    (1 << SPICTRL_EVENT_LT_BIT)
0115 #define SPICTRL_EVENT_OV    (1 << SPICTRL_EVENT_OV_BIT)
0116 #define SPICTRL_EVENT_UN    (1 << SPICTRL_EVENT_UN_BIT)
0117 #define SPICTRL_EVENT_MME   (1 << SPICTRL_EVENT_MME_BIT)
0118 #define SPICTRL_EVENT_NE    (1 << SPICTRL_EVENT_NE_BIT)
0119 #define SPICTRL_EVENT_NF    (1 << SPICTRL_EVENT_NF_BIT)
0120 
0121 /*** MASK REGISTER 0x28 ***/
0122 #define SPICTRL_MASK_ATE_BIT    15
0123 #define SPICTRL_MASK_LTE_BIT    14
0124 #define SPICTRL_MASK_OVE_BIT    12
0125 #define SPICTRL_MASK_UNE_BIT    11
0126 #define SPICTRL_MASK_MMEE_BIT   10
0127 #define SPICTRL_MASK_NEE_BIT    9
0128 #define SPICTRL_MASK_NFE_BIT    8
0129 
0130 #define SPICTRL_MASK_ATE    (1 << SPICTRL_MASK_ATE_BIT)
0131 #define SPICTRL_MASK_LTE    (1 << SPICTRL_MASK_LTE_BIT)
0132 #define SPICTRL_MASK_OVE    (1 << SPICTRL_MASK_OVE_BIT)
0133 #define SPICTRL_MASK_UNE    (1 << SPICTRL_MASK_UNE_BIT)
0134 #define SPICTRL_MASK_MMEE   (1 << SPICTRL_MASK_MMEE_BIT)
0135 #define SPICTRL_MASK_NEE    (1 << SPICTRL_MASK_NEE_BIT)
0136 #define SPICTRL_MASK_NFE    (1 << SPICTRL_MASK_NFE_BIT)
0137 
0138 /*** COMMAND REGISTER 0x2c ***/
0139 #define SPICTRL_CMD_LST_BIT 22
0140 #define SPICTRL_CMD_LST     (1 << SPICTRL_CMD_LST_BIT)
0141 
0142 /*** TRANSMIT REGISTER 0x30 ***/
0143 #define SPICTRL_TX_TDATA_BIT    0
0144 #define SPICTRL_TX_TDATA    0xffffffff
0145 
0146 /*** RECEIVE REGISTER 0x34 ***/
0147 #define SPICTRL_RX_RDATA_BIT    0
0148 #define SPICTRL_RX_RDATA    0xffffffff
0149 
0150 /*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/
0151 
0152 /*** AM CONFIGURATION REGISTER 0x40 ***/
0153 #define SPICTRL_AMCFG_ERPT_BIT      6
0154 #define SPICTRL_AMCFG_SEQ_BIT       5
0155 #define SPICTRL_AMCFG_STRICT_BIT    4
0156 #define SPICTRL_AMCFG_OVTB_BIT      3
0157 #define SPICTRL_AMCFG_OVDB_BIT      2
0158 #define SPICTRL_AMCFG_ACT_BIT       1
0159 #define SPICTRL_AMCFG_EACT_BIT      0
0160 
0161 #define SPICTRL_AMCFG_ERPT  (1<<SPICTRL_AMCFG_ERPT_BIT)
0162 #define SPICTRL_AMCFG_SEQ   (1<<SPICTRL_AMCFG_SEQ_BIT)
0163 #define SPICTRL_AMCFG_STRICT    (1<<SPICTRL_AMCFG_STRICT_BIT)
0164 #define SPICTRL_AMCFG_OVTB  (1<<SPICTRL_AMCFG_OVTB_BIT)
0165 #define SPICTRL_AMCFG_OVDB  (1<<SPICTRL_AMCFG_OVDB_BIT)
0166 #define SPICTRL_AMCFG_ACT   (1<<SPICTRL_AMCFG_ACT_BIT)
0167 #define SPICTRL_AMCFG_EACT  (1<<SPICTRL_AMCFG_EACT_BIT)
0168 
0169 struct spictrl_priv {
0170     rtems_libi2c_bus_t      i2clib_desc;
0171     struct drvmgr_dev   *dev;
0172     struct spictrl_regs     *regs;
0173     int             irq;
0174     int             minor;
0175     unsigned int            core_freq_hz;
0176 
0177     /* Driver */
0178     int             fdepth;
0179     int             bits_per_char;
0180     int             lsb_first;
0181     int             txshift;
0182     int             rxshift;
0183     unsigned int            idle_char;
0184     int             (*slvSelFunc)(void *regs, uint32_t addr, int select);
0185     
0186     /* Automated Periodic transfers */
0187     int             periodic_started;
0188     struct spictrl_ioctl_config periodic_cfg;
0189 };
0190 
0191 /******************* Driver Manager Part ***********************/
0192 
0193 int spictrl_device_init(struct spictrl_priv *priv);
0194 
0195 int spictrl_init2(struct drvmgr_dev *dev);
0196 int spictrl_init3(struct drvmgr_dev *dev);
0197 
0198 struct drvmgr_drv_ops spictrl_ops = 
0199 {
0200     .init = {NULL, spictrl_init2, spictrl_init3, NULL},
0201     .remove = NULL,
0202     .info = NULL
0203 };
0204 
0205 struct amba_dev_id spictrl_ids[] =
0206 {
0207     {VENDOR_GAISLER, GAISLER_SPICTRL},
0208     {0, 0}      /* Mark end of table */
0209 };
0210 
0211 struct amba_drv_info spictrl_drv_info =
0212 {
0213     {
0214         DRVMGR_OBJ_DRV,             /* Driver */
0215         NULL,                   /* Next driver */
0216         NULL,                   /* Device list */
0217         DRIVER_AMBAPP_GAISLER_SPICTRL_ID,   /* Driver ID */
0218         "SPICTRL_DRV",              /* Driver Name */
0219         DRVMGR_BUS_TYPE_AMBAPP,         /* Bus Type */
0220         &spictrl_ops,
0221         NULL,                   /* Funcs */
0222         0,                  /* No devices yet */
0223         0,
0224     },
0225     &spictrl_ids[0]
0226 };
0227 
0228 void spictrl_register_drv (void)
0229 {
0230     DBG("Registering SPICTRL driver\n");
0231     drvmgr_drv_register(&spictrl_drv_info.general);
0232 }
0233 
0234 int spictrl_init2(struct drvmgr_dev *dev)
0235 {
0236     struct spictrl_priv *priv;
0237 
0238     DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
0239 
0240     priv = dev->priv = grlib_calloc(1, sizeof(*priv));
0241     if ( !priv )
0242         return DRVMGR_NOMEM;
0243     priv->dev = dev;
0244 
0245     /* This core will not find other cores, so we wait for init2() */
0246 
0247     return DRVMGR_OK;
0248 }
0249 
0250 int spictrl_init3(struct drvmgr_dev *dev)
0251 {
0252     struct spictrl_priv *priv;
0253     char prefix[32];
0254     char devName[48];
0255     int rc;
0256 
0257     priv = (struct spictrl_priv *)dev->priv;
0258 
0259     /* Do initialization */
0260 
0261     /* Initialize i2c library */
0262     rc = rtems_libi2c_initialize();
0263     if (rc != 0) {
0264         DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n");
0265         free(dev->priv);
0266         dev->priv = NULL;
0267         return DRVMGR_FAIL;
0268     }
0269 
0270     /* I/O system registered and initialized 
0271      * Now we take care of device initialization.
0272      */
0273 
0274     /* Get frequency */
0275     if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) {
0276         return DRVMGR_FAIL;
0277     }
0278 
0279     if ( spictrl_device_init(priv) ) {
0280         free(dev->priv);
0281         dev->priv = NULL;
0282         return DRVMGR_FAIL;
0283     }
0284 
0285     /* Get Filesystem name prefix */
0286     prefix[0] = '\0';
0287     if ( drvmgr_get_dev_prefix(dev, prefix) ) {
0288         /* Failed to get prefix, make sure of a unique FS name
0289          * by using the driver minor.
0290          */
0291         sprintf(devName, "/dev/spi%d", dev->minor_drv+1);
0292     } else {
0293         /* Got special prefix, this means we have a bus prefix
0294          * And we should use our "bus minor"
0295          */
0296         sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1);
0297     }
0298 
0299     /* Register Bus for this Device */
0300     rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
0301     if (rc < 0) {
0302         DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName);
0303         free(dev->priv);
0304         dev->priv = NULL;
0305         return DRVMGR_FAIL;
0306     }
0307     priv->minor = rc;
0308 
0309     return DRVMGR_OK;
0310 }
0311 
0312 /******************* Driver Implementation ***********************/
0313 
0314 STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
0315                          uint32_t addr, int rw);
0316 
0317 /* Set as high frequency of SCK as possible but not higher than 
0318  * requested frequency (freq).
0319  */
0320 static int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq)
0321 {
0322     unsigned int core_freq_hz = priv->core_freq_hz;
0323     unsigned int lowest_freq_possible;
0324     unsigned int div, div16, pm, fact;
0325 
0326     /* Lowest possible when DIV16 is set and PM is 0xf */
0327     lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1));
0328 
0329     if ( freq < lowest_freq_possible ) {
0330         DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n", 
0331             freq, core_freq_hz, lowest_freq_possible);
0332         return -1;
0333     }
0334 
0335     div = ((core_freq_hz / 2) + (freq-1)) / freq;
0336     DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq);
0337 
0338     /* Is DIV16 neccessary? */
0339     if ( div > 16 ) {
0340         div = (div + (16 - 1)) / 16;
0341         div16 = 1;
0342     } else {
0343         div16 = 0;
0344     }
0345 
0346     if ( div > 0xf ) {
0347         fact = 0; /* FACT adds an factor /2 */
0348         div = (div + (2 - 1)) / 2;
0349     } else {
0350         fact = 1;
0351     }
0352 
0353     pm = div-1;
0354 
0355     /* Update hardware */
0356     priv->regs->mode = 
0357         (priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) | 
0358         (pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) |
0359         (fact << SPICTRL_MODE_FACT_BIT);
0360 
0361     DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n",
0362         core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1)),
0363         freq, pm, fact, div16, core_freq_hz);
0364 
0365     return 0;
0366 }
0367 
0368 /* Start Automated Periodic transfers, after this call read can be done */
0369 static int spictrl_start_periodic(struct spictrl_priv *priv)
0370 {
0371     struct spictrl_ioctl_config *cfg = &priv->periodic_cfg;
0372     unsigned int am_cfg;
0373 
0374     /* Clear the events */
0375     priv->regs->event = 0xffffffff;
0376 
0377     /* Enable core */
0378     priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
0379 
0380     /* Update hardware config from flags and period */
0381     priv->regs->am_period = cfg->period;
0382 
0383     /* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */
0384     am_cfg = (cfg->period_flags & 0x1f8) >> 1;
0385     priv->regs->am_cfg = am_cfg;
0386 
0387     /* Start automated periodic transfers */
0388     if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) {
0389         /* Enable external triggering */
0390         priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT;
0391     } else {
0392         /* Activate periodic transfers */
0393         priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT;
0394     }
0395 
0396     return 0;
0397 }
0398 
0399 /* Stop Automated Periodic transfers */
0400 static void spictrl_stop_periodic(struct spictrl_priv *priv)
0401 {
0402     priv->regs->am_cfg = 0;
0403 }
0404 
0405 /* Return the status of the SPI controller (the event register), 
0406  * it may be needed in periodic mode to look at the Not Full bit (NF)
0407  * in order not to hang in an infinte loop when read is called.
0408  */
0409 static inline unsigned int spictrl_status(struct spictrl_priv *priv)
0410 {
0411     return priv->regs->event;
0412 }
0413 
0414 static int spictrl_read_periodic(
0415     struct spictrl_priv *priv,
0416     struct spictrl_period_io *rarg)
0417 {
0418     int i, rxi, rxshift, bits_per_char, reg;
0419     unsigned int rx_word, mask;
0420     void *rxbuf;
0421 
0422     if ( rarg->options & 0x1 ) {
0423         /* Read mask registers */
0424         for (i=0; i<4; i++) {
0425             rarg->masks[i] = priv->regs->am_mask[i];
0426         }
0427     }
0428 
0429     if ( rarg->options & 0x2 ) {
0430         /* Read receive registers (after updating masks so that the caller can
0431          * read current buffer without knowning of actual register mask).
0432          */
0433 
0434         /* If not started we could be hanging here forever. */
0435         if ( !priv->periodic_started )
0436             return -1;
0437 
0438         rxshift = priv->rxshift;
0439         bits_per_char = priv->bits_per_char;
0440         rx_word = 0;
0441 
0442         rxbuf = rarg->data;
0443         if ( !rxbuf ) {
0444             /* If no data pointer specified we cannot copy data... */
0445             return -1;
0446         }
0447 
0448         /* Wait until all data is available (if started) */
0449         while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) {
0450             ;
0451         }
0452 
0453         rxi = 0;
0454         for (i=0; i<4; i++) {
0455             mask = rarg->masks[i];
0456             reg = 0;
0457             while ( mask ) {
0458                 if ( mask & 1 ) {
0459                     /* Update Register */
0460                     rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift;
0461 
0462                     if ( bits_per_char <= 8 ) {
0463                         *((unsigned char *)rxbuf + rxi) = rx_word;
0464                     } else if ( bits_per_char <= 16 ) {
0465                         *((unsigned short *)rxbuf + rxi) = rx_word;
0466                     } else {
0467                         *((unsigned int *)rxbuf + rxi) = rx_word;
0468                     }
0469                     rxi++;
0470                 }
0471 
0472                 mask = mask>>1;
0473                 reg++;
0474             }
0475         }
0476     }
0477 
0478     return 0;
0479 }
0480 
0481 static int spictrl_write_periodic(
0482     struct spictrl_priv *priv,
0483     struct spictrl_period_io *warg)
0484 {
0485     int i, txi, txshift, bits_per_char, reg;
0486     unsigned int tx_word, mask;
0487     void *txbuf;
0488 
0489     if ( warg->options & 0x2 ) {
0490 
0491         /* Make sure core is enabled, otherwise TX registers writes are lost */
0492         priv->regs->mode |= SPICTRL_MODE_EN;
0493 
0494         /* Update Transmit registers (before updating masks so that we do not
0495          * transmit invalid data)
0496          */
0497 
0498         txshift = priv->txshift;
0499         bits_per_char = priv->bits_per_char;
0500         tx_word = 0;
0501 
0502         txbuf = warg->data;
0503         if ( !txbuf ) {
0504             /* If no data pointer specified we fill up with
0505              * idle chars.
0506              */
0507             tx_word = priv->idle_char << txshift;
0508         }
0509 
0510         txi = 0;
0511         for (i=0; i<4; i++) {
0512             mask = warg->masks[i];
0513             reg = 0;
0514             while ( mask ) {
0515                 if ( mask & 1 ) {
0516                     if ( txbuf ) {
0517                         if ( bits_per_char <= 8 ) {
0518                             tx_word = *((unsigned char *)txbuf + txi);
0519                         } else if ( bits_per_char <= 16 ) {
0520                             tx_word = *((unsigned short *)txbuf + txi);
0521                         } else {
0522                             tx_word = *((unsigned int *)txbuf + txi);
0523                         }
0524                         tx_word = tx_word << txshift;
0525                         txi++;
0526                     }
0527 
0528                     /* Update Register */
0529                     DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]);
0530                     priv->regs->am_tx[i*32 + reg] = tx_word;
0531                 }
0532 
0533                 mask = mask>>1;
0534                 reg++;
0535             }
0536         }
0537     }
0538 
0539     if ( warg->options & 0x1 ) {
0540         /* Update mask registers */
0541         for (i=0; i<4; i++) {
0542             DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i);
0543             priv->regs->am_mask[i] = warg->masks[i];
0544         }
0545     }
0546 
0547     return 0;
0548 }
0549 
0550 static int spictrl_read_write(
0551     struct spictrl_priv *priv,
0552     void *rxbuf, 
0553     void *txbuf,
0554     int len)
0555 {
0556     unsigned int tx_word, rx_word, tmp;
0557     int txshift = priv->txshift;
0558     int rxshift = priv->rxshift;
0559     int txi, rxi, bits_per_char;
0560     int length;
0561 
0562     /* Use IOCTL for periodic reads. The FIFO is not supported in automated 
0563      * periodic mode 
0564      */
0565     if ( priv->periodic_cfg.periodic_mode ) {
0566         return -1;
0567     }
0568 
0569     bits_per_char = priv->bits_per_char;
0570     tx_word = 0;
0571     if ( !txbuf ) {
0572         tx_word = priv->idle_char << txshift;
0573     }
0574 
0575     /* Clear the events */
0576     priv->regs->event = 0xffffffff;
0577 
0578     /* Enable core */
0579     priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
0580 
0581     length = len;
0582     if ( bits_per_char > 8 ) {
0583         length = length / 2;
0584         if ( bits_per_char > 16 )
0585             length = length / 2;
0586     }
0587     DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift);
0588 
0589     txi=0;
0590     rxi=0;
0591     while ( (rxi < length) || (txi < length) ) {
0592         /* Get transmit word */
0593         if ( length > txi ) {
0594             if ( txbuf ) {
0595                 if ( bits_per_char <= 8 ) {
0596                     tx_word = *((unsigned char *)txbuf + txi);
0597                 } else if ( bits_per_char <= 16 ) {
0598                     tx_word = *((unsigned short *)txbuf + txi);
0599                 } else {
0600                     tx_word = *((unsigned int *)txbuf + txi);
0601                 }
0602                 tx_word = tx_word << txshift;
0603             }
0604 
0605             /* Wait for SPICTRL to get ready for another TX char */
0606             while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) {
0607                 /* Wait for all chars to transmit */
0608 /* Could implement waiting for SPICTRL IRQ here */
0609             }
0610 
0611             DBG("SPICTRL: Writing 0x%x\n", tx_word);
0612 
0613             /* Transmit word */
0614             priv->regs->tx = tx_word;
0615             txi++;
0616         }
0617 
0618         /* Read */
0619         while ( priv->regs->event & SPICTRL_EVENT_NE ) {
0620             /* Read to avoid overrun */
0621             tmp = priv->regs->rx;
0622             DBG("SPICTRL: Read 0x%x\n", tmp);
0623 
0624             if ( rxbuf && (length > rxi) ) {
0625                 /* Copy word to user buffer */
0626                 rx_word = (tmp >> rxshift);
0627 
0628                 DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift);
0629 
0630                 if ( bits_per_char <= 8 ) {
0631                     *((unsigned char *)rxbuf + rxi) = rx_word;
0632                 } else if ( bits_per_char <= 16 ) {
0633                     *((unsigned short *)rxbuf + rxi) = rx_word;
0634                 } else {
0635                     *((unsigned int *)rxbuf + rxi) = rx_word;
0636                 }
0637 
0638             }
0639             rxi++;
0640         }
0641     }
0642 
0643     return len;
0644 }
0645 
0646 
0647 STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl)
0648 {
0649     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0650 
0651     DBG("SPICTRL: spictrl_libi2c_init\n");
0652 
0653     /* Disable SPICTTRL, Select Master mode */
0654     priv->regs->mode = SPICTRL_MODE_MS;
0655 
0656     /* Mask all Interrupts */
0657     priv->regs->mask = 0;
0658 
0659     /* Select no slave */
0660     priv->regs->slvsel = 0xffffffff;
0661 
0662     /* Clear all events */
0663     priv->regs->event = 0xffffffff;
0664 
0665     return 0;
0666 }
0667 
0668 /* Nothing to be done in start */
0669 STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl)
0670 {
0671     DBG("SPICTRL: spictrl_libi2c_send_start\n");
0672 
0673     return 0;
0674 }
0675 
0676 /* Inactivate all chip selects, indicates "End of command" */
0677 STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl)
0678 {
0679     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0680 
0681     priv->regs->slvsel = 0xffffffff;
0682 
0683     if ( priv->slvSelFunc ) {
0684         /* unslect all */
0685         return priv->slvSelFunc(priv->regs, -1, 0);
0686     }
0687 
0688     DBG("SPICTRL: spictrl_libi2c_send_stop\n");
0689     return 0;
0690 }
0691 
0692 /* Select Slave address by selecting apropriate chip select */
0693 STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
0694                          uint32_t addr, int rw)
0695 {
0696     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0697 
0698     DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr);
0699 
0700     if ( priv->slvSelFunc ) {
0701         /* Let user set spi select using for example GPIO */
0702         return priv->slvSelFunc(priv->regs, addr, 1);
0703     } else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) {
0704         int slaves;
0705 
0706         /* Maximum number of slaves the core support */
0707         slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT;
0708 
0709         if ( addr > slaves )
0710             return -1;
0711 
0712         if ( (priv->regs->capability & SPICTRL_CAP_ASELA) &&
0713              (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) {
0714                 /* When automatic slave select is supported by hardware and
0715              * enabled by configuration the SPI address is determined by 
0716              * the automatic slave select register and the "idle" slave
0717              * select register is set by configuration.
0718              */
0719             priv->regs->am_slvsel = ~(1<<(addr-1));
0720             priv->regs->slvsel = priv->periodic_cfg.period_slvsel;
0721             /* Enable automatic slave select */
0722             priv->regs->mode |= SPICTRL_MODE_ASEL;
0723         } else {
0724             /* Normal mode */
0725             priv->regs->slvsel = ~(1<<(addr-1));
0726         }
0727     }
0728 
0729     return 0;
0730 }
0731 
0732 /* Read a number of bytes */
0733 STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl, 
0734                 unsigned char *bytes, int nbytes)
0735 {
0736     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0737     int ret;
0738 
0739     DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes);
0740     ret = spictrl_read_write(priv, bytes, NULL, nbytes);
0741     if ( ret < 0 ) {
0742         printk("SPICTRL: Error Reading\n");
0743     } 
0744 #ifdef DEBUG
0745     else {
0746         int i;
0747         for(i=0; i<nbytes; i+=16) {
0748             DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
0749                 bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
0750             DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
0751                 bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
0752         }
0753     }
0754 #endif
0755     return ret;
0756 }
0757 
0758 /* Write a number of bytes */
0759 STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl, 
0760                 unsigned char *bytes, int nbytes)
0761 {
0762     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0763 
0764 #ifdef DEBUG
0765     int i;
0766     DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes);
0767 
0768     for(i=0; i<nbytes; i+=16) {
0769         DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
0770             bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
0771         DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
0772             bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
0773     }
0774 #endif
0775 
0776     return spictrl_read_write(priv, NULL, bytes, nbytes);
0777 }
0778 
0779 /* Configure the interface and do simultaneous READ/WRITE operations */
0780 STATIC int spictrl_libi2c_ioctl(
0781     rtems_libi2c_bus_t * bushdl, 
0782     int   cmd,
0783     void *buffer)
0784 {
0785     struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
0786     int ret;
0787 
0788     DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer);
0789 
0790     switch (cmd) {
0791         case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
0792         {
0793             rtems_libi2c_tfr_mode_t *trf_mode = buffer;
0794             unsigned int mode;
0795 
0796             /* Must disable core to write new values */
0797             priv->regs->mode &= ~SPICTRL_MODE_EN;
0798 
0799             /* Change bit frequency */
0800             if ( spictrl_set_freq(priv, trf_mode->baudrate) ) {
0801                 /* Unable to set such a low frequency. */
0802                 return -1;
0803             }
0804 
0805             /* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */
0806             mode = (priv->regs->mode & 
0807                 ~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN));
0808             if ( trf_mode->clock_inv ) 
0809                 mode |= SPICTRL_MODE_CPOL;
0810             if ( trf_mode->clock_phs ) 
0811                 mode |= SPICTRL_MODE_CPHA;
0812             if ( trf_mode->lsb_first == 0 )
0813                 mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */
0814 
0815             if ( (trf_mode->bits_per_char < 4) || 
0816                 ((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) )
0817                 return -1;
0818             if ( trf_mode->bits_per_char == 32 ) {
0819                 priv->txshift = 0;
0820                 priv->rxshift = 0;
0821             } else {
0822                 mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT;
0823                 if ( trf_mode->lsb_first == 0 ) {
0824                     /* REV bit 1 */
0825                     priv->txshift = 32 - trf_mode->bits_per_char;
0826                     priv->rxshift = 16;
0827                 } else {
0828                     /* REV bit 0 */
0829                     priv->txshift = 0;
0830                     priv->rxshift = 16 - trf_mode->bits_per_char;
0831                 }
0832             }
0833 
0834             priv->bits_per_char = trf_mode->bits_per_char;
0835             priv->lsb_first = trf_mode->lsb_first;
0836             priv->idle_char = trf_mode->idle_char;
0837 
0838             /* Update hardware */
0839             priv->regs->mode = mode;
0840 
0841             return 0;
0842         }
0843 
0844         case RTEMS_LIBI2C_IOCTL_READ_WRITE:
0845         {
0846             rtems_libi2c_read_write_t *arg = buffer;
0847 
0848             DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt);
0849 #ifdef DEBUG
0850             /* Printf out what is going to be transmitted */
0851             if ( arg->wr_buf ) {
0852                 unsigned char *bytes = (unsigned char *)arg->wr_buf;
0853                 int i;
0854                 for(i=0; i<arg->byte_cnt; i+=16) {
0855                     DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
0856                         bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
0857                     DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
0858                         bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
0859                 }
0860             }
0861 #endif
0862 
0863             ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf,
0864                 arg->byte_cnt);
0865 #ifdef DEBUG
0866             /* Printf out what was read */
0867             if ( arg->rd_buf ) {
0868                 unsigned char *bytes = (unsigned char *)arg->rd_buf;
0869                 int i;
0870                 for(i=0; i<arg->byte_cnt; i+=16) {
0871                     DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", 
0872                         bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
0873                     DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", 
0874                         bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
0875                 }
0876             }
0877 #endif
0878             return ret;
0879         }
0880 
0881         /* Enable Periodic mode */
0882         case SPICTRL_IOCTL_CONFIG:
0883         {
0884             struct spictrl_ioctl_config *cfg;
0885 
0886             DBG("SPICTRL: Configuring Periodic mode\n");
0887 
0888             if ( priv->periodic_started ) {
0889                 DBG("SPICTRL: Periodic mode already started, too late to configure\n");
0890                 return -1;
0891             }
0892 
0893             cfg = buffer;
0894             if ( cfg == NULL ) {
0895                 memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg));
0896             } else {
0897                 priv->periodic_cfg = *cfg;
0898             }
0899             cfg = &priv->periodic_cfg;
0900             if ( cfg->periodic_mode ) {
0901                 /* Enable Automated Periodic mode */
0902                 priv->regs->mode |= SPICTRL_MODE_AMEN;
0903 
0904                 /* Check that hardware has support for periodic mode */
0905                 if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) {
0906                     priv->periodic_cfg.periodic_mode = 0;
0907                     DBG("SPICTRL: Periodic mode not supported by hardware\n");
0908                     return -1;
0909                 }
0910             } else {
0911                 /* Disable Periodic mode */
0912                 priv->regs->mode &= ~SPICTRL_MODE_AMEN;
0913             }
0914             priv->periodic_started = 0;
0915 
0916             /* Set clockgap and TAC */
0917             priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) |
0918                                (cfg->clock_gap << SPICTRL_MODE_CG_BIT) |
0919                        (cfg->flags & SPICTRL_MODE_TAC);
0920             return 0;
0921         }
0922         case SPICTRL_IOCTL_PERIOD_START:
0923         {
0924             if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) {
0925                 return -1;
0926             }
0927             if ( spictrl_start_periodic(priv) == 0 ) {
0928                 priv->periodic_started = 1;
0929                 return 0;
0930             } else
0931                 return -1;
0932         }
0933         case SPICTRL_IOCTL_PERIOD_STOP:
0934         {
0935             if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) {
0936                 return -1;
0937             }
0938             spictrl_stop_periodic(priv);
0939             priv->periodic_started = 0;
0940             return 0;
0941         }
0942         case SPICTRL_IOCTL_STATUS:
0943         {
0944             if ( !buffer )
0945                 return 0;
0946             *(unsigned int *)buffer = spictrl_status(priv);
0947             return 0;
0948         }
0949 
0950         case SPICTRL_IOCTL_PERIOD_WRITE:
0951         {
0952             if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
0953                 return -1;
0954             }
0955             if ( spictrl_write_periodic(priv, (struct spictrl_period_io *)
0956                                         buffer) == 0 ) {
0957                 return 0;
0958             } else
0959                 return -1;
0960         }
0961 
0962         case SPICTRL_IOCTL_PERIOD_READ:
0963         {
0964             if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
0965                 return -1;
0966             }
0967             if ( spictrl_read_periodic(priv, (struct spictrl_period_io *)
0968                                         buffer) == 0 ) {
0969                 return 0;
0970             } else
0971                 return -1;
0972         }
0973 
0974         case SPICTRL_IOCTL_REGS:
0975         {
0976             /* Copy Register Base Address to user space */
0977             if ( !buffer ) {
0978                 return -1;
0979             }
0980             *(struct spictrl_regs **)buffer = priv->regs;
0981             return 0;
0982         }
0983 
0984         default:
0985             /* Unknown IOCTL */
0986             return -1;
0987     }
0988 
0989     return 0;
0990 }
0991 
0992 STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops =
0993 {
0994     .init       = spictrl_libi2c_init,
0995     .send_start = spictrl_libi2c_send_start,
0996     .send_stop  = spictrl_libi2c_send_stop,
0997     .send_addr  = spictrl_libi2c_send_addr,
0998     .read_bytes = spictrl_libi2c_read_bytes,
0999     .write_bytes    = spictrl_libi2c_write_bytes,
1000     .ioctl      = spictrl_libi2c_ioctl
1001 };
1002 
1003 int spictrl_device_init(struct spictrl_priv *priv)
1004 {
1005     struct amba_dev_info *ambadev;
1006     struct ambapp_core *pnpinfo;
1007     union drvmgr_key_value *value;
1008 
1009     /* Get device information from AMBA PnP information */
1010     ambadev = (struct amba_dev_info *)priv->dev->businfo;
1011     if ( ambadev == NULL ) {
1012         return -1;
1013     }
1014     pnpinfo = &ambadev->info;
1015     priv->irq = pnpinfo->irq;
1016     priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start;
1017     priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT;
1018 
1019     DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth);
1020 
1021     /* Mask all Interrupts */
1022     priv->regs->mask = 0;
1023 
1024     /* Disable SPICTTRL */
1025     priv->regs->mode = 0;
1026 
1027     /* Get custom */
1028     value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", DRVMGR_KT_POINTER);
1029     if ( value ) {
1030         priv->slvSelFunc = value->ptr;
1031     }
1032 
1033     /* Prepare I2C layer */
1034     priv->i2clib_desc.ops = &spictrl_libi2c_ops;
1035     priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops);
1036     return 0;
1037 }