source: rtems/bsps/sparc/shared/spi/spictrl.c @ 11f3b9a

5
Last change on this file since 11f3b9a was 11f3b9a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/18 at 14:55:38

bsps/sparc: Add grlib_malloc(), grlib_calloc()

This avoids a dependency to errno in device driver code.

  • Property mode set to 100644
File size: 26.5 KB
Line 
1/*
2 *  SPICTRL SPI driver implmenetation
3 *
4 *  COPYRIGHT (c) 2009.
5 *  Cobham Gaisler AB.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.org/license/LICENSE.
10 */
11
12#include <bsp.h>
13#include <rtems/libio.h>
14#include <stdlib.h>
15#include <assert.h>
16#include <rtems/bspIo.h>
17#include <string.h>
18#include <stdio.h>
19
20#include <drvmgr/drvmgr.h>
21#include <drvmgr/ambapp_bus.h>
22#include <bsp/spictrl.h>
23#include <ambapp.h>
24
25#include <rtems/libi2c.h>
26
27#include <grlib_impl.h>
28
29/*#define DEBUG 1*/
30
31#ifdef DEBUG
32#define DBG(x...) printk(x)
33#define STATIC
34#else
35#define DBG(x...)
36#define STATIC static
37#endif
38
39/*** CAPABILITY REGISTER 0x00 ***/
40#define SPICTRL_CAP_SSSZ_BIT    24
41#define SPICTRL_CAP_AMODE_BIT   18
42#define SPICTRL_CAP_ASELA_BIT   17
43#define SPICTRL_CAP_SSEN_BIT    16
44#define SPICTRL_CAP_FDEPTH_BIT  8
45#define SPICTRL_CAP_REV_BIT     0
46
47#define SPICTRL_CAP_SSSZ        (0xff << SPICTRL_CAP_SSSZ_BIT)
48#define SPICTRL_CAP_AMODE       (1<<SPICTRL_CAP_AMODE_BIT)
49#define SPICTRL_CAP_ASELA       (1<<SPICTRL_CAP_ASELA_BIT)
50#define SPICTRL_CAP_SSEN        (1 << SPICTRL_CAP_SSEN_BIT)
51#define SPICTRL_CAP_FDEPTH      (0xff << SPICTRL_CAP_FDEPTH_BIT)
52#define SPICTRL_CAP_REV         (0xff << SPICTRL_CAP_REV_BIT)
53
54/*** MODE REGISTER 0x20 ***/
55#define SPICTRL_MODE_AMEN_BIT   31
56#define SPICTRL_MODE_LOOP_BIT   30
57#define SPICTRL_MODE_CPOL_BIT   29
58#define SPICTRL_MODE_CPHA_BIT   28
59#define SPICTRL_MODE_DIV16_BIT  27
60#define SPICTRL_MODE_REV_BIT    26
61#define SPICTRL_MODE_MS_BIT     25
62#define SPICTRL_MODE_EN_BIT     24
63#define SPICTRL_MODE_LEN_BIT    20
64#define SPICTRL_MODE_PM_BIT     16
65#define SPICTRL_MODE_ASEL_BIT   14
66#define SPICTRL_MODE_FACT_BIT   13
67#define SPICTRL_MODE_CG_BIT     7
68#define SPICTRL_MODE_TAC_BIT    4
69
70#define SPICTRL_MODE_AMEN       (1 << SPICTRL_MODE_AMEN_BIT)
71#define SPICTRL_MODE_LOOP       (1 << SPICTRL_MODE_LOOP_BIT)
72#define SPICTRL_MODE_CPOL       (1 << SPICTRL_MODE_CPOL_BIT)
73#define SPICTRL_MODE_CPHA       (1 << SPICTRL_MODE_CPHA_BIT)
74#define SPICTRL_MODE_DIV16      (1 << SPICTRL_MODE_DIV16_BIT)
75#define SPICTRL_MODE_REV        (1 << SPICTRL_MODE_REV_BIT)
76#define SPICTRL_MODE_MS         (1 << SPICTRL_MODE_MS_BIT)
77#define SPICTRL_MODE_EN         (1 << SPICTRL_MODE_EN_BIT)
78#define SPICTRL_MODE_LEN        (0xf << SPICTRL_MODE_LEN_BIT)
79#define SPICTRL_MODE_PM         (0xf << SPICTRL_MODE_PM_BIT)
80#define SPICTRL_MODE_ASEL       (1 << SPICTRL_MODE_ASEL_BIT)
81#define SPICTRL_MODE_FACT       (1 << SPICTRL_MODE_FACT_BIT)
82#define SPICTRL_MODE_CG         (0x1f << SPICTRL_MODE_CG_BIT)
83#define SPICTRL_MODE_TAC        (0x1 << SPICTRL_MODE_TAC_BIT)
84
85/*** EVENT REGISTER 0x24 ***/
86#define SPICTRL_EVENT_AT_BIT    15
87#define SPICTRL_EVENT_LT_BIT    14
88#define SPICTRL_EVENT_OV_BIT    12
89#define SPICTRL_EVENT_UN_BIT    11
90#define SPICTRL_EVENT_MME_BIT   10
91#define SPICTRL_EVENT_NE_BIT    9
92#define SPICTRL_EVENT_NF_BIT    8
93
94#define SPICTRL_EVENT_AT        (1 << SPICTRL_EVENT_AT_BIT)
95#define SPICTRL_EVENT_LT        (1 << SPICTRL_EVENT_LT_BIT)
96#define SPICTRL_EVENT_OV        (1 << SPICTRL_EVENT_OV_BIT)
97#define SPICTRL_EVENT_UN        (1 << SPICTRL_EVENT_UN_BIT)
98#define SPICTRL_EVENT_MME       (1 << SPICTRL_EVENT_MME_BIT)
99#define SPICTRL_EVENT_NE        (1 << SPICTRL_EVENT_NE_BIT)
100#define SPICTRL_EVENT_NF        (1 << SPICTRL_EVENT_NF_BIT)
101
102/*** MASK REGISTER 0x28 ***/
103#define SPICTRL_MASK_ATE_BIT    15
104#define SPICTRL_MASK_LTE_BIT    14
105#define SPICTRL_MASK_OVE_BIT    12
106#define SPICTRL_MASK_UNE_BIT    11
107#define SPICTRL_MASK_MMEE_BIT   10
108#define SPICTRL_MASK_NEE_BIT    9
109#define SPICTRL_MASK_NFE_BIT    8
110
111#define SPICTRL_MASK_ATE        (1 << SPICTRL_MASK_ATE_BIT)
112#define SPICTRL_MASK_LTE        (1 << SPICTRL_MASK_LTE_BIT)
113#define SPICTRL_MASK_OVE        (1 << SPICTRL_MASK_OVE_BIT)
114#define SPICTRL_MASK_UNE        (1 << SPICTRL_MASK_UNE_BIT)
115#define SPICTRL_MASK_MMEE       (1 << SPICTRL_MASK_MMEE_BIT)
116#define SPICTRL_MASK_NEE        (1 << SPICTRL_MASK_NEE_BIT)
117#define SPICTRL_MASK_NFE        (1 << SPICTRL_MASK_NFE_BIT)
118
119/*** COMMAND REGISTER 0x2c ***/
120#define SPICTRL_CMD_LST_BIT     22
121#define SPICTRL_CMD_LST         (1 << SPICTRL_CMD_LST_BIT)
122
123/*** TRANSMIT REGISTER 0x30 ***/
124#define SPICTRL_TX_TDATA_BIT    0
125#define SPICTRL_TX_TDATA        0xffffffff
126
127/*** RECEIVE REGISTER 0x34 ***/
128#define SPICTRL_RX_RDATA_BIT    0
129#define SPICTRL_RX_RDATA        0xffffffff
130
131/*** SLAVE SELECT REGISTER 0x38 - VARIABLE ***/
132
133/*** AM CONFIGURATION REGISTER 0x40 ***/
134#define SPICTRL_AMCFG_ERPT_BIT          6
135#define SPICTRL_AMCFG_SEQ_BIT           5
136#define SPICTRL_AMCFG_STRICT_BIT        4
137#define SPICTRL_AMCFG_OVTB_BIT          3
138#define SPICTRL_AMCFG_OVDB_BIT          2
139#define SPICTRL_AMCFG_ACT_BIT           1
140#define SPICTRL_AMCFG_EACT_BIT          0
141
142#define SPICTRL_AMCFG_ERPT      (1<<SPICTRL_AMCFG_ERPT_BIT)
143#define SPICTRL_AMCFG_SEQ       (1<<SPICTRL_AMCFG_SEQ_BIT)
144#define SPICTRL_AMCFG_STRICT    (1<<SPICTRL_AMCFG_STRICT_BIT)
145#define SPICTRL_AMCFG_OVTB      (1<<SPICTRL_AMCFG_OVTB_BIT)
146#define SPICTRL_AMCFG_OVDB      (1<<SPICTRL_AMCFG_OVDB_BIT)
147#define SPICTRL_AMCFG_ACT       (1<<SPICTRL_AMCFG_ACT_BIT)
148#define SPICTRL_AMCFG_EACT      (1<<SPICTRL_AMCFG_EACT_BIT)
149
150struct spictrl_priv {
151        rtems_libi2c_bus_t              i2clib_desc;
152        struct drvmgr_dev       *dev;
153        struct spictrl_regs             *regs;
154        int                             irq;
155        int                             minor;
156        unsigned int                    core_freq_hz;
157
158        /* Driver */
159        int                             fdepth;
160        int                             bits_per_char;
161        int                             lsb_first;
162        int                             txshift;
163        int                             rxshift;
164        unsigned int                    idle_char;
165        int                             (*slvSelFunc)(void *regs, uint32_t addr, int select);
166       
167        /* Automated Periodic transfers */
168        int                             periodic_started;
169        struct spictrl_ioctl_config     periodic_cfg;
170};
171
172/******************* Driver Manager Part ***********************/
173
174int spictrl_device_init(struct spictrl_priv *priv);
175
176int spictrl_init2(struct drvmgr_dev *dev);
177int spictrl_init3(struct drvmgr_dev *dev);
178
179struct drvmgr_drv_ops spictrl_ops =
180{
181        .init = {NULL, spictrl_init2, spictrl_init3, NULL},
182        .remove = NULL,
183        .info = NULL
184};
185
186struct amba_dev_id spictrl_ids[] =
187{
188        {VENDOR_GAISLER, GAISLER_SPICTRL},
189        {0, 0}          /* Mark end of table */
190};
191
192struct amba_drv_info spictrl_drv_info =
193{
194        {
195                DRVMGR_OBJ_DRV,                         /* Driver */
196                NULL,                                   /* Next driver */
197                NULL,                                   /* Device list */
198                DRIVER_AMBAPP_GAISLER_SPICTRL_ID,       /* Driver ID */
199                "SPICTRL_DRV",                          /* Driver Name */
200                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
201                &spictrl_ops,
202                NULL,                                   /* Funcs */
203                0,                                      /* No devices yet */
204                0,
205        },
206        &spictrl_ids[0]
207};
208
209void spictrl_register_drv (void)
210{
211        DBG("Registering SPICTRL driver\n");
212        drvmgr_drv_register(&spictrl_drv_info.general);
213}
214
215int spictrl_init2(struct drvmgr_dev *dev)
216{
217        struct spictrl_priv *priv;
218
219        DBG("SPICTRL[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
220
221        priv = dev->priv = grlib_calloc(1, sizeof(*priv));
222        if ( !priv )
223                return DRVMGR_NOMEM;
224        priv->dev = dev;
225
226        /* This core will not find other cores, so we wait for init2() */
227
228        return DRVMGR_OK;
229}
230
231int spictrl_init3(struct drvmgr_dev *dev)
232{
233        struct spictrl_priv *priv;
234        char prefix[32];
235        char devName[32];
236        int rc;
237
238        priv = (struct spictrl_priv *)dev->priv;
239
240        /* Do initialization */
241
242        /* Initialize i2c library */
243        rc = rtems_libi2c_initialize();
244        if (rc != 0) {
245                DBG("SPICTRL: rtems_libi2c_initialize failed, exiting...\n");
246                free(dev->priv);
247                dev->priv = NULL;
248                return DRVMGR_FAIL;
249        }
250
251        /* I/O system registered and initialized
252         * Now we take care of device initialization.
253         */
254
255        /* Get frequency */
256        if ( drvmgr_freq_get(dev, DEV_APB_SLV, &priv->core_freq_hz) ) {
257                return DRVMGR_FAIL;
258        }
259
260        if ( spictrl_device_init(priv) ) {
261                free(dev->priv);
262                dev->priv = NULL;
263                return DRVMGR_FAIL;
264        }
265
266        /* Get Filesystem name prefix */
267        prefix[0] = '\0';
268        if ( drvmgr_get_dev_prefix(dev, prefix) ) {
269                /* Failed to get prefix, make sure of a unique FS name
270                 * by using the driver minor.
271                 */
272                sprintf(devName, "/dev/spi%d", dev->minor_drv+1);
273        } else {
274                /* Got special prefix, this means we have a bus prefix
275                 * And we should use our "bus minor"
276                 */
277                sprintf(devName, "/dev/%sspi%d", prefix, dev->minor_bus+1);
278        }
279
280        /* Register Bus for this Device */
281        rc = rtems_libi2c_register_bus(devName, &priv->i2clib_desc);
282        if (rc < 0) {
283                DBG("SPICTRL: rtems_libi2c_register_bus(%s) failed\n", devName);
284                free(dev->priv);
285                dev->priv = NULL;
286                return DRVMGR_FAIL;
287        }
288        priv->minor = rc;
289
290        return DRVMGR_OK;
291}
292
293/******************* Driver Implementation ***********************/
294
295STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
296                                             uint32_t addr, int rw);
297
298/* Set as high frequency of SCK as possible but not higher than
299 * requested frequency (freq).
300 */
301static int spictrl_set_freq(struct spictrl_priv *priv, unsigned int freq)
302{
303        unsigned int core_freq_hz = priv->core_freq_hz;
304        unsigned int lowest_freq_possible;
305        unsigned int div, div16, pm, fact;
306
307        /* Lowest possible when DIV16 is set and PM is 0xf */
308        lowest_freq_possible = core_freq_hz / (16 * 4 * (0xf + 1));
309
310        if ( freq < lowest_freq_possible ) {
311                DBG("SPICTRL: TOO LOW FREQ %u, CORE FREQ %u, LOWEST FREQ %u\n",
312                        freq, core_freq_hz, lowest_freq_possible);
313                return -1;
314        }
315
316        div = ((core_freq_hz / 2) + (freq-1)) / freq;
317        DBG("SPICTRL: DIV=%d, FREQ=%d\n", div, freq);
318
319        /* Is DIV16 neccessary? */
320        if ( div > 16 ) {
321                div = (div + (16 - 1)) / 16;
322                div16 = 1;
323        } else {
324                div16 = 0;
325        }
326
327        if ( div > 0xf ) {
328                fact = 0; /* FACT adds an factor /2 */
329                div = (div + (2 - 1)) / 2;
330        } else {
331                fact = 1;
332        }
333
334        pm = div-1;
335
336        /* Update hardware */
337        priv->regs->mode =
338                (priv->regs->mode & ~(SPICTRL_MODE_PM|SPICTRL_MODE_DIV16|SPICTRL_MODE_FACT)) |
339                (pm << SPICTRL_MODE_PM_BIT) | (div16 << SPICTRL_MODE_DIV16_BIT) |
340                (fact << SPICTRL_MODE_FACT_BIT);
341
342        DBG("SPICTRL: Effective bit rate %u (requested %u), PM: %x, FACT: %d, div16: %x, core_freq: %u\n",
343                core_freq_hz / (2 * (fact ? 1 : 2) * (div) * (div16 ? 16 : 1)),
344                freq, pm, fact, div16, core_freq_hz);
345
346        return 0;
347}
348
349/* Start Automated Periodic transfers, after this call read can be done */
350static int spictrl_start_periodic(struct spictrl_priv *priv)
351{
352        struct spictrl_ioctl_config *cfg = &priv->periodic_cfg;
353        unsigned int am_cfg;
354
355        /* Clear the events */
356        priv->regs->event = 0xffffffff;
357
358        /* Enable core */
359        priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
360
361        /* Update hardware config from flags and period */
362        priv->regs->am_period = cfg->period;
363
364        /* Remove SPICTRL_PERIOD_FLAGS_ASEL and ACT bit and shift into posistion */
365        am_cfg = (cfg->period_flags & 0x1f8) >> 1;
366        priv->regs->am_cfg = am_cfg;
367
368        /* Start automated periodic transfers */
369        if ( cfg->period_flags & SPICTRL_PERIOD_FLAGS_EACT ) {
370                /* Enable external triggering */
371                priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_EACT;
372        } else {
373                /* Activate periodic transfers */
374                priv->regs->am_cfg = am_cfg | SPICTRL_AMCFG_ACT;
375        }
376
377        return 0;
378}
379
380/* Stop Automated Periodic transfers */
381static void spictrl_stop_periodic(struct spictrl_priv *priv)
382{
383        priv->regs->am_cfg = 0;
384}
385
386/* Return the status of the SPI controller (the event register),
387 * it may be needed in periodic mode to look at the Not Full bit (NF)
388 * in order not to hang in an infinte loop when read is called.
389 */
390static inline unsigned int spictrl_status(struct spictrl_priv *priv)
391{
392        return priv->regs->event;
393}
394
395static int spictrl_read_periodic(
396        struct spictrl_priv *priv,
397        struct spictrl_period_io *rarg)
398{
399        int i, rxi, rxshift, bits_per_char, reg;
400        unsigned int rx_word, mask;
401        void *rxbuf;
402
403        if ( rarg->options & 0x1 ) {
404                /* Read mask registers */
405                for (i=0; i<4; i++) {
406                        rarg->masks[i] = priv->regs->am_mask[i];
407                }
408        }
409
410        if ( rarg->options & 0x2 ) {
411                /* Read receive registers (after updating masks so that the caller can
412                 * read current buffer without knowning of actual register mask).
413                 */
414
415                /* If not started we could be hanging here forever. */
416                if ( !priv->periodic_started )
417                        return -1;
418
419                rxshift = priv->rxshift;
420                bits_per_char = priv->bits_per_char;
421                rx_word = 0;
422
423                rxbuf = rarg->data;
424                if ( !rxbuf ) {
425                        /* If no data pointer specified we cannot copy data... */
426                        return -1;
427                }
428
429                /* Wait until all data is available (if started) */
430                while ( (priv->regs->event & SPICTRL_EVENT_NE) == 0 ) {
431                        ;
432                }
433
434                rxi = 0;
435                for (i=0; i<4; i++) {
436                        mask = rarg->masks[i];
437                        reg = 0;
438                        while ( mask ) {
439                                if ( mask & 1 ) {
440                                        /* Update Register */
441                                        rx_word = priv->regs->am_rx[i*32 + reg] >> rxshift;
442
443                                        if ( bits_per_char <= 8 ) {
444                                                *((unsigned char *)rxbuf + rxi) = rx_word;
445                                        } else if ( bits_per_char <= 16 ) {
446                                                *((unsigned short *)rxbuf + rxi) = rx_word;
447                                        } else {
448                                                *((unsigned int *)rxbuf + rxi) = rx_word;
449                                        }
450                                        rxi++;
451                                }
452
453                                mask = mask>>1;
454                                reg++;
455                        }
456                }
457        }
458
459        return 0;
460}
461
462static int spictrl_write_periodic(
463        struct spictrl_priv *priv,
464        struct spictrl_period_io *warg)
465{
466        int i, txi, txshift, bits_per_char, reg;
467        unsigned int tx_word, mask;
468        void *txbuf;
469
470        if ( warg->options & 0x2 ) {
471
472                /* Make sure core is enabled, otherwise TX registers writes are lost */
473                priv->regs->mode |= SPICTRL_MODE_EN;
474
475                /* Update Transmit registers (before updating masks so that we do not
476                 * transmit invalid data)
477                 */
478
479                txshift = priv->txshift;
480                bits_per_char = priv->bits_per_char;
481                tx_word = 0;
482
483                txbuf = warg->data;
484                if ( !txbuf ) {
485                        /* If no data pointer specified we fill up with
486                         * idle chars.
487                         */
488                        tx_word = priv->idle_char << txshift;
489                }
490
491                txi = 0;
492                for (i=0; i<4; i++) {
493                        mask = warg->masks[i];
494                        reg = 0;
495                        while ( mask ) {
496                                if ( mask & 1 ) {
497                                        if ( txbuf ) {
498                                                if ( bits_per_char <= 8 ) {
499                                                        tx_word = *((unsigned char *)txbuf + txi);
500                                                } else if ( bits_per_char <= 16 ) {
501                                                        tx_word = *((unsigned short *)txbuf + txi);
502                                                } else {
503                                                        tx_word = *((unsigned int *)txbuf + txi);
504                                                }
505                                                tx_word = tx_word << txshift;
506                                                txi++;
507                                        }
508
509                                        /* Update Register */
510                                        DBG("WRITE 0x%08x to 0x%08x\n", tx_word, &priv->regs->am_tx[i*32 + reg]);
511                                        priv->regs->am_tx[i*32 + reg] = tx_word;
512                                }
513
514                                mask = mask>>1;
515                                reg++;
516                        }
517                }
518        }
519
520        if ( warg->options & 0x1 ) {
521                /* Update mask registers */
522                for (i=0; i<4; i++) {
523                        DBG("WRITE 0x%08x to 0x%08x (MSK%d)\n", warg->masks[i], &priv->regs->am_mask[i], i);
524                        priv->regs->am_mask[i] = warg->masks[i];
525                }
526        }
527
528        return 0;
529}
530
531static int spictrl_read_write(
532        struct spictrl_priv *priv,
533        void *rxbuf,
534        void *txbuf,
535        int len)
536{
537        unsigned int tx_word, rx_word, tmp;
538        int txshift = priv->txshift;
539        int rxshift = priv->rxshift;
540        int txi, rxi, bits_per_char;
541        int length;
542
543        /* Use IOCTL for periodic reads. The FIFO is not supported in automated
544         * periodic mode
545         */
546        if ( priv->periodic_cfg.periodic_mode ) {
547                return -1;
548        }
549
550        bits_per_char = priv->bits_per_char;
551        tx_word = 0;
552        if ( !txbuf ) {
553                tx_word = priv->idle_char << txshift;
554        }
555
556        /* Clear the events */
557        priv->regs->event = 0xffffffff;
558
559        /* Enable core */
560        priv->regs->mode |= SPICTRL_MODE_EN | SPICTRL_MODE_MS;
561
562        length = len;
563        if ( bits_per_char > 8 ) {
564                length = length / 2;
565                if ( bits_per_char > 16 )
566                        length = length / 2;
567        }
568        DBG("SPICTRL: LENGTH = %d, Bits/Char: %d, Shift: %d, %d\n", length, bits_per_char, txshift, rxshift);
569
570        txi=0;
571        rxi=0;
572        while ( (rxi < length) || (txi < length) ) {
573                /* Get transmit word */
574                if ( length > txi ) {
575                        if ( txbuf ) {
576                                if ( bits_per_char <= 8 ) {
577                                        tx_word = *((unsigned char *)txbuf + txi);
578                                } else if ( bits_per_char <= 16 ) {
579                                        tx_word = *((unsigned short *)txbuf + txi);
580                                } else {
581                                        tx_word = *((unsigned int *)txbuf + txi);
582                                }
583                                tx_word = tx_word << txshift;
584                        }
585
586                        /* Wait for SPICTRL to get ready for another TX char */
587                        while ( (priv->regs->event & SPICTRL_EVENT_NF) == 0 ) {
588                                /* Wait for all chars to transmit */
589/* Could implement waiting for SPICTRL IRQ here */
590                        }
591
592                        DBG("SPICTRL: Writing 0x%x\n", tx_word);
593
594                        /* Transmit word */
595                        priv->regs->tx = tx_word;
596                        txi++;
597                }
598
599                /* Read */
600                while ( priv->regs->event & SPICTRL_EVENT_NE ) {
601                        /* Read to avoid overrun */
602                        tmp = priv->regs->rx;
603                        DBG("SPICTRL: Read 0x%x\n", tmp);
604
605                        if ( rxbuf && (length > rxi) ) {
606                                /* Copy word to user buffer */
607                                rx_word = (tmp >> rxshift);
608
609                                DBG("SPICTRL: Receiving 0x%x (0x%x, %d)\n", rx_word, tmp, rxshift);
610
611                                if ( bits_per_char <= 8 ) {
612                                        *((unsigned char *)rxbuf + rxi) = rx_word;
613                                } else if ( bits_per_char <= 16 ) {
614                                        *((unsigned short *)rxbuf + rxi) = rx_word;
615                                } else {
616                                        *((unsigned int *)rxbuf + rxi) = rx_word;
617                                }
618
619                        }
620                        rxi++;
621                }
622        }
623
624        return len;
625}
626
627
628STATIC rtems_status_code spictrl_libi2c_init(rtems_libi2c_bus_t *bushdl)
629{
630        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
631
632        DBG("SPICTRL: spictrl_libi2c_init\n");
633
634        /* Disable SPICTTRL, Select Master mode */
635        priv->regs->mode = SPICTRL_MODE_MS;
636
637        /* Mask all Interrupts */
638        priv->regs->mask = 0;
639
640        /* Select no slave */
641        priv->regs->slvsel = 0xffffffff;
642
643        /* Clear all events */
644        priv->regs->event = 0xffffffff;
645
646        return 0;
647}
648
649/* Nothing to be done in start */
650STATIC rtems_status_code spictrl_libi2c_send_start(rtems_libi2c_bus_t *bushdl)
651{
652        DBG("SPICTRL: spictrl_libi2c_send_start\n");
653
654        return 0;
655}
656
657/* Inactivate all chip selects, indicates "End of command" */
658STATIC rtems_status_code spictrl_libi2c_send_stop(rtems_libi2c_bus_t *bushdl)
659{
660        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
661
662        priv->regs->slvsel = 0xffffffff;
663
664        if ( priv->slvSelFunc ) {
665                /* unslect all */
666                return priv->slvSelFunc(priv->regs, -1, 0);
667        }
668
669        DBG("SPICTRL: spictrl_libi2c_send_stop\n");
670        return 0;
671}
672
673/* Select Slave address by selecting apropriate chip select */
674STATIC rtems_status_code spictrl_libi2c_send_addr(rtems_libi2c_bus_t *bushdl,
675                                             uint32_t addr, int rw)
676{
677        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
678
679        DBG("SPICTRL: spictrl_libi2c_send_addr, %d\n", addr);
680
681        if ( priv->slvSelFunc ) {
682                /* Let user set spi select using for example GPIO */
683                return priv->slvSelFunc(priv->regs, addr, 1);
684        } else if ( priv->regs->capability & SPICTRL_CAP_SSEN ) {
685                int slaves;
686
687                /* Maximum number of slaves the core support */
688                slaves = (priv->regs->capability & SPICTRL_CAP_SSSZ) >> SPICTRL_CAP_SSSZ_BIT;
689
690                if ( addr > slaves )
691                        return -1;
692
693                if ( (priv->regs->capability & SPICTRL_CAP_ASELA) &&
694                     (priv->periodic_cfg.period_flags & SPICTRL_PERIOD_FLAGS_ASEL) ) {
695                        /* When automatic slave select is supported by hardware and
696                         * enabled by configuration the SPI address is determined by
697                         * the automatic slave select register and the "idle" slave
698                         * select register is set by configuration.
699                         */
700                        priv->regs->am_slvsel = ~(1<<(addr-1));
701                        priv->regs->slvsel = priv->periodic_cfg.period_slvsel;
702                        /* Enable automatic slave select */
703                        priv->regs->mode |= SPICTRL_MODE_ASEL;
704                } else {
705                        /* Normal mode */
706                        priv->regs->slvsel = ~(1<<(addr-1));
707                }
708        }
709
710        return 0;
711}
712
713/* Read a number of bytes */
714STATIC int spictrl_libi2c_read_bytes(rtems_libi2c_bus_t *bushdl,
715                                unsigned char *bytes, int nbytes)
716{
717        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
718        int ret;
719
720        DBG("SPICTRL: spictrl_libi2c_read_bytes %d\n", nbytes);
721        ret = spictrl_read_write(priv, bytes, NULL, nbytes);
722        if ( ret < 0 ) {
723                printk("SPICTRL: Error Reading\n");
724        }
725#ifdef DEBUG
726        else {
727                int i;
728                for(i=0; i<nbytes; i+=16) {
729                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
730                                bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
731                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
732                                bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
733                }
734        }
735#endif
736        return ret;
737}
738
739/* Write a number of bytes */
740STATIC int spictrl_libi2c_write_bytes(rtems_libi2c_bus_t *bushdl,
741                                unsigned char *bytes, int nbytes)
742{
743        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
744
745#ifdef DEBUG
746        int i;
747        DBG("SPICTRL: spictrl_libi2c_write_bytes: %d\n", nbytes);
748
749        for(i=0; i<nbytes; i+=16) {
750                DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
751                        bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
752                DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
753                        bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
754        }
755#endif
756
757        return spictrl_read_write(priv, NULL, bytes, nbytes);
758}
759
760/* Configure the interface and do simultaneous READ/WRITE operations */
761STATIC int spictrl_libi2c_ioctl(
762        rtems_libi2c_bus_t * bushdl,
763        int   cmd,
764        void *buffer)
765{
766        struct spictrl_priv *priv = (struct spictrl_priv *)bushdl;
767        int ret;
768
769        DBG("SPICTRL: spictrl_libi2c_ioctl(%d, 0x%x)\n", cmd, (unsigned int)buffer);
770
771        switch (cmd) {
772                case RTEMS_LIBI2C_IOCTL_SET_TFRMODE:
773                {
774                        rtems_libi2c_tfr_mode_t *trf_mode = buffer;
775                        unsigned int mode;
776
777                        /* Must disable core to write new values */
778                        priv->regs->mode &= ~SPICTRL_MODE_EN;
779
780                        /* Change bit frequency */
781                        if ( spictrl_set_freq(priv, trf_mode->baudrate) ) {
782                                /* Unable to set such a low frequency. */
783                                return -1;
784                        }
785
786                        /* Set Clock Polarity, Clock Phase, Reverse mode and Word Length */
787                        mode = (priv->regs->mode &
788                                ~(SPICTRL_MODE_CPOL|SPICTRL_MODE_CPHA|SPICTRL_MODE_REV|SPICTRL_MODE_LEN));
789                        if ( trf_mode->clock_inv )
790                                mode |= SPICTRL_MODE_CPOL;
791                        if ( trf_mode->clock_phs )
792                                mode |= SPICTRL_MODE_CPHA;
793                        if ( trf_mode->lsb_first == 0 )
794                                mode |= SPICTRL_MODE_REV; /* Set Reverse mode (MSB first) */
795
796                        if ( (trf_mode->bits_per_char < 4) ||
797                                ((trf_mode->bits_per_char > 16) && (trf_mode->bits_per_char != 32)) )
798                                return -1;
799                        if ( trf_mode->bits_per_char == 32 ) {
800                                priv->txshift = 0;
801                                priv->rxshift = 0;
802                        } else {
803                                mode |= (trf_mode->bits_per_char-1) << SPICTRL_MODE_LEN_BIT;
804                                if ( trf_mode->lsb_first == 0 ) {
805                                        /* REV bit 1 */
806                                        priv->txshift = 32 - trf_mode->bits_per_char;
807                                        priv->rxshift = 16;
808                                } else {
809                                        /* REV bit 0 */
810                                        priv->txshift = 0;
811                                        priv->rxshift = 16 - trf_mode->bits_per_char;
812                                }
813                        }
814
815                        priv->bits_per_char = trf_mode->bits_per_char;
816                        priv->lsb_first = trf_mode->lsb_first;
817                        priv->idle_char = trf_mode->idle_char;
818
819                        /* Update hardware */
820                        priv->regs->mode = mode;
821
822                        return 0;
823                }
824
825                case RTEMS_LIBI2C_IOCTL_READ_WRITE:
826                {
827                        rtems_libi2c_read_write_t *arg = buffer;
828
829                        DBG("SPICTRL: IOCTL READ/WRITE, RX: 0x%x, TX: 0x%x, len: %d\n", arg->rd_buf, arg->wr_buf, arg->byte_cnt);
830#ifdef DEBUG
831                        /* Printf out what is going to be transmitted */
832                        if ( arg->wr_buf ) {
833                                unsigned char *bytes = (unsigned char *)arg->wr_buf;
834                                int i;
835                                for(i=0; i<arg->byte_cnt; i+=16) {
836                                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
837                                                bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
838                                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
839                                                bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
840                                }
841                        }
842#endif
843
844                        ret = spictrl_read_write(priv, arg->rd_buf, (unsigned char *)arg->wr_buf,
845                                arg->byte_cnt);
846#ifdef DEBUG
847                        /* Printf out what was read */
848                        if ( arg->rd_buf ) {
849                                unsigned char *bytes = (unsigned char *)arg->rd_buf;
850                                int i;
851                                for(i=0; i<arg->byte_cnt; i+=16) {
852                                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ",
853                                                bytes[0+i], bytes[1+i], bytes[2+i], bytes[3+i], bytes[4+i], bytes[5+i], bytes[6+i], bytes[7+i]);
854                                        DBG("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
855                                                bytes[8+i], bytes[9+i], bytes[10+i], bytes[11+i], bytes[12+i], bytes[13+i], bytes[14+i], bytes[15+i]);
856                                }
857                        }
858#endif
859                        return ret;
860                }
861
862                /* Enable Periodic mode */
863                case SPICTRL_IOCTL_CONFIG:
864                {
865                        struct spictrl_ioctl_config *cfg;
866
867                        DBG("SPICTRL: Configuring Periodic mode\n");
868
869                        if ( priv->periodic_started ) {
870                                DBG("SPICTRL: Periodic mode already started, too late to configure\n");
871                                return -1;
872                        }
873
874                        cfg = buffer;
875                        if ( cfg == NULL ) {
876                                memset(&priv->periodic_cfg, 0, sizeof(priv->periodic_cfg));
877                        } else {
878                                priv->periodic_cfg = *cfg;
879                        }
880                        cfg = &priv->periodic_cfg;
881                        if ( cfg->periodic_mode ) {
882                                /* Enable Automated Periodic mode */
883                                priv->regs->mode |= SPICTRL_MODE_AMEN;
884
885                                /* Check that hardware has support for periodic mode */
886                                if ( (priv->regs->mode & SPICTRL_MODE_AMEN) == 0 ) {
887                                        priv->periodic_cfg.periodic_mode = 0;
888                                        DBG("SPICTRL: Periodic mode not supported by hardware\n");
889                                        return -1;
890                                }
891                        } else {
892                                /* Disable Periodic mode */
893                                priv->regs->mode &= ~SPICTRL_MODE_AMEN;
894                        }
895                        priv->periodic_started = 0;
896
897                        /* Set clockgap and TAC */
898                        priv->regs->mode = (priv->regs->mode & ~(SPICTRL_MODE_CG|SPICTRL_MODE_TAC)) |
899                                           (cfg->clock_gap << SPICTRL_MODE_CG_BIT) |
900                                           (cfg->flags & SPICTRL_MODE_TAC);
901                        return 0;
902                }
903                case SPICTRL_IOCTL_PERIOD_START:
904                {
905                        if ( !priv->periodic_cfg.periodic_mode || priv->periodic_started ) {
906                                return -1;
907                        }
908                        if ( spictrl_start_periodic(priv) == 0 ) {
909                                priv->periodic_started = 1;
910                                return 0;
911                        } else
912                                return -1;
913                }
914                case SPICTRL_IOCTL_PERIOD_STOP:
915                {
916                        if ( !priv->periodic_cfg.periodic_mode || !priv->periodic_started ) {
917                                return -1;
918                        }
919                        spictrl_stop_periodic(priv);
920                        priv->periodic_started = 0;
921                        return 0;
922                }
923                case SPICTRL_IOCTL_STATUS:
924                {
925                        if ( !buffer )
926                                return 0;
927                        *(unsigned int *)buffer = spictrl_status(priv);
928                        return 0;
929                }
930
931                case SPICTRL_IOCTL_PERIOD_WRITE:
932                {
933                        if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
934                                return -1;
935                        }
936                        if ( spictrl_write_periodic(priv, (struct spictrl_period_io *)
937                                                    buffer) == 0 ) {
938                                return 0;
939                        } else
940                                return -1;
941                }
942
943                case SPICTRL_IOCTL_PERIOD_READ:
944                {
945                        if ( !priv->periodic_cfg.periodic_mode || !buffer ) {
946                                return -1;
947                        }
948                        if ( spictrl_read_periodic(priv, (struct spictrl_period_io *)
949                                                    buffer) == 0 ) {
950                                return 0;
951                        } else
952                                return -1;
953                }
954
955                case SPICTRL_IOCTL_REGS:
956                {
957                        /* Copy Register Base Address to user space */
958                        if ( !buffer ) {
959                                return -1;
960                        }
961                        *(struct spictrl_regs **)buffer = priv->regs;
962                        return 0;
963                }
964
965                default:
966                        /* Unknown IOCTL */
967                        return -1;
968        }
969
970        return 0;
971}
972
973STATIC rtems_libi2c_bus_ops_t spictrl_libi2c_ops =
974{
975        .init           = spictrl_libi2c_init,
976        .send_start     = spictrl_libi2c_send_start,
977        .send_stop      = spictrl_libi2c_send_stop,
978        .send_addr      = spictrl_libi2c_send_addr,
979        .read_bytes     = spictrl_libi2c_read_bytes,
980        .write_bytes    = spictrl_libi2c_write_bytes,
981        .ioctl          = spictrl_libi2c_ioctl
982};
983
984int spictrl_device_init(struct spictrl_priv *priv)
985{
986        struct amba_dev_info *ambadev;
987        struct ambapp_core *pnpinfo;
988        union drvmgr_key_value *value;
989
990        /* Get device information from AMBA PnP information */
991        ambadev = (struct amba_dev_info *)priv->dev->businfo;
992        if ( ambadev == NULL ) {
993                return -1;
994        }
995        pnpinfo = &ambadev->info;
996        priv->irq = pnpinfo->irq;
997        priv->regs = (struct spictrl_regs *)pnpinfo->apb_slv->start;
998        priv->fdepth = (priv->regs->capability & SPICTRL_CAP_FDEPTH) >> SPICTRL_CAP_FDEPTH_BIT;
999
1000        DBG("SPCTRL: 0x%x irq %d, FIFO: %d\n", (unsigned int)priv->regs, priv->irq, priv->fdepth);
1001
1002        /* Mask all Interrupts */
1003        priv->regs->mask = 0;
1004
1005        /* Disable SPICTTRL */
1006        priv->regs->mode = 0;
1007
1008        /* Get custom */
1009        value = drvmgr_dev_key_get(priv->dev, "slvSelFunc", DRVMGR_KT_POINTER);
1010        if ( value ) {
1011                priv->slvSelFunc = value->ptr;
1012        }
1013
1014        /* Prepare I2C layer */
1015        priv->i2clib_desc.ops = &spictrl_libi2c_ops;
1016        priv->i2clib_desc.size = sizeof(spictrl_libi2c_ops);
1017        return 0;
1018}
Note: See TracBrowser for help on using the repository browser.