source: rtems/c/src/lib/libbsp/sparc/shared/spi/spictrl.c @ 4a7d1026

4.11
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 8:25:52 AM

sparc bsps: updated license to rtems.org

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