source: rtems/c/src/lib/libbsp/sparc/shared/gpio/grgpio.c @ 3bb4122

4.115
Last change on this file since 3bb4122 was 3bb4122, checked in by Daniel Hellstrom <daniel@…>, on 02/23/15 at 12:02:39

LEON: added new drivers to the LEON2/LEON3 BSPs

Most drivers use the Driver Manager for device probing, they
work on AMBA-over-PCI systems if PCI is big-endian.

New APIs:

  • GPIO Library, interfaced to GRGPIO
  • GENIRQ, Generic interrupt service implementation helper

New GRLIB Drivers:

  • ACTEL 1553 RT, user interface is similar to 1553 BRM driver
  • GR1553 (1553 BC, RT and BM core)
  • AHBSTAT (AHB error status core)
  • GRADCDAC (Core interfacing to ADC/DAC hardware)
  • GRGPIO (GPIO port accessed from GPIO Library)
  • MCTRL (Memory controller settings configuration)
  • GRETH (10/100/1000 Ethernet driver using Driver manager)
  • GRPWM (Pulse Width Modulation core)
  • SPICTRL (SPI master interface)
  • GRSPW_ROUTER (SpaceWire? Router AMBA configuration interface)
  • GRCTM (SpaceCraft? on-board Time Management core)
  • SPWCUC (Time distribution over SpaceWire?)
  • GRTC (SpaceCraft? up-link Tele core)
  • GRTM (SpaceCraft? down-link Tele Metry core)

GR712RC ASIC specific interfaces:

  • GRASCS
  • CANMUX (select between OCCAN and SATCAN)
  • SATCAN
  • SLINK
  • Property mode set to 100644
File size: 10.2 KB
Line 
1/*  GRGPIO GPIO Driver interface.
2 *
3 *  COPYRIGHT (c) 2009.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.com/license/LICENSE.
9 */
10
11#include <bsp.h>
12#include <rtems/libio.h>
13#include <stdlib.h>
14#include <assert.h>
15#include <rtems/bspIo.h>
16#include <string.h>
17#include <stdio.h>
18
19#include <drvmgr/drvmgr.h>
20#include <drvmgr/ambapp_bus.h>
21#include <grgpio.h>
22#include <gpiolib.h>
23#include <ambapp.h>
24#include <grlib.h>
25
26/*#define DEBUG 1*/
27
28#ifdef DEBUG
29#define DBG(x...) printk(x)
30#define STATIC
31#else
32#define DBG(x...)
33#define STATIC static
34#endif
35
36struct grgpio_isr {
37        drvmgr_isr isr;
38        void *arg;
39};
40
41struct grgpio_priv {
42        struct drvmgr_dev       *dev;
43        struct grgpio_regs              *regs;
44        int                             irq;
45        int                             minor;
46
47        /* Driver implementation */
48        int                             port_cnt;
49        unsigned char                   port_handles[32];
50        struct grgpio_isr               isrs[32];
51        struct gpiolib_drv              gpiolib_desc;
52        unsigned int                    bypass;
53        unsigned int                    imask;
54};
55
56/******************* Driver Manager Part ***********************/
57
58int grgpio_device_init(struct grgpio_priv *priv);
59
60int grgpio_init1(struct drvmgr_dev *dev);
61int grgpio_init2(struct drvmgr_dev *dev);
62
63struct drvmgr_drv_ops grgpio_ops =
64{
65        .init = {grgpio_init1, NULL, NULL, NULL},
66        .remove = NULL,
67        .info = NULL
68};
69
70struct amba_dev_id grgpio_ids[] =
71{
72        {VENDOR_GAISLER, GAISLER_GPIO},
73        {0, 0}          /* Mark end of table */
74};
75
76struct amba_drv_info grgpio_drv_info =
77{
78        {
79                DRVMGR_OBJ_DRV,                         /* Driver */
80                NULL,                                   /* Next driver */
81                NULL,                                   /* Device list */
82                DRIVER_AMBAPP_GAISLER_GRGPIO_ID,        /* Driver ID */
83                "GRGPIO_DRV",                           /* Driver Name */
84                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
85                &grgpio_ops,
86                NULL,                                   /* Funcs */
87                0,                                      /* No devices yet */
88                0,
89        },
90        &grgpio_ids[0]
91};
92
93void grgpio_register_drv (void)
94{
95        DBG("Registering GRGPIO driver\n");
96        drvmgr_drv_register(&grgpio_drv_info.general);
97}
98
99/* Register GRGPIO pins as quick as possible to the GPIO library,
100 * other drivers may depend upon them in INIT LEVEL 2.
101 * Note that since IRQ may not be available in init1, it is assumed
102 * that the GPIOLibrary does not request IRQ routines until LEVEL 2.
103 */
104int grgpio_init1(struct drvmgr_dev *dev)
105{
106        struct grgpio_priv *priv;
107        int status, port;
108
109        DBG("GRGPIO[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
110
111        /* This core will not find other cores, but other driver may depend upon
112         * the GPIO library to function. So, we set up GPIO right away.
113         */
114
115        /* Initialize library if not already done */
116        status = gpiolib_initialize();
117        if ( status < 0 )
118                return DRVMGR_FAIL;
119
120        priv = dev->priv = malloc(sizeof(struct grgpio_priv));
121        if ( !priv )
122                return DRVMGR_NOMEM;
123        memset(priv, 0, sizeof(*priv));
124        priv->dev = dev;
125
126        if ( grgpio_device_init(priv) ) {
127                free(dev->priv);
128                dev->priv = NULL;
129                return DRVMGR_FAIL;
130        }
131
132        /* Register all ports available on this core as GPIO port to
133         * upper layer
134         */
135        for(port=0; port<priv->port_cnt; port++) {
136                priv->port_handles[port] = port;
137                gpiolib_drv_register(&priv->gpiolib_desc,
138                                        &priv->port_handles[port]);
139        }
140
141        return DRVMGR_OK;
142}
143
144/******************* Driver Implementation ***********************/
145
146/* Find port from handle, returns -1 if not found */
147int grgpio_find_port(void *handle, struct grgpio_priv **priv)
148{
149        unsigned char portnr;
150       
151        portnr = *(unsigned char *)handle;
152        if ( portnr > 31 )
153                return -1;
154        *priv = (struct grgpio_priv *)
155                (((unsigned int)handle - portnr*sizeof(unsigned char)) -
156                offsetof(struct grgpio_priv, port_handles));
157        return portnr;
158}
159
160int grgpio_gpiolib_open(void *handle)
161{
162        struct grgpio_priv *priv;
163        int portnr;
164
165        portnr = grgpio_find_port(handle, &priv);
166        if ( portnr < 0 ) {
167                DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
168                return -1;
169        }
170        DBG("GRGPIO[0x%08x][%d]: OPENING\n", priv->regs, portnr);
171
172        /* Open the device, nothing to be done... */
173
174        return 0;
175}
176
177int grgpio_grpiolib_config(void *handle, struct gpiolib_config *cfg)
178{
179        struct grgpio_priv *priv;
180        int portnr;
181        unsigned int mask;
182
183        portnr = grgpio_find_port(handle, &priv);
184        if ( portnr < 0 ) {
185                return -1;
186        }
187        DBG("GRGPIO[0x%08x][%d]: CONFIG\n", priv->regs, portnr);
188
189        /* Configure the device. And check that operation is supported,
190         * not all I/O Pins have IRQ support.
191         */
192        mask = (1<<portnr);
193
194        /* Return error when IRQ not supported by this I/O Line and it
195         * is beeing enabled by user.
196         */
197        if ( ((mask & priv->imask) == 0) && cfg->mask )
198                return -1;
199
200        priv->regs->imask &= ~mask; /* Disable interrupt temporarily */
201
202        /* Configure settings before enabling interrupt */
203        priv->regs->ipol = (priv->regs->ipol & ~mask) | (cfg->irq_polarity ? mask : 0);
204        priv->regs->iedge = (priv->regs->iedge & ~mask) | (cfg->irq_level ? 0 : mask);
205        priv->regs->imask |= cfg->mask ? mask : 0;
206
207        return 0;
208}
209
210int grgpio_grpiolib_get(void *handle, int *inval)
211{
212        struct grgpio_priv *priv;
213        int portnr;
214
215        portnr = grgpio_find_port(handle, &priv);
216        if ( portnr < 0 ) {
217                return -1;
218        }
219        DBG("GRGPIO[0x%08x][%d]: GET\n", priv->regs, portnr);
220
221        /* Get current status of the port */
222        if ( inval )
223                *inval = (priv->regs->data >> portnr) & 0x1;
224
225        return 0;
226}
227
228int grgpio_grpiolib_irq_opts(void *handle, unsigned int options)
229{
230        struct grgpio_priv *priv;
231        int portnr;
232        drvmgr_isr isr;
233        void *arg;
234
235        portnr = grgpio_find_port(handle, &priv);
236        if ( portnr < 0 ) {
237                return -1;
238        }
239        DBG("GRGPIO[0x%08x][%d]: IRQ OPTS 0x%x\n", priv->regs, portnr, options);
240
241        if ( options & GPIOLIB_IRQ_FORCE )
242                return -1;
243
244        isr = priv->isrs[portnr].isr;
245        arg = priv->isrs[portnr].arg;
246
247        if ( options & GPIOLIB_IRQ_DISABLE ) {
248                /* Disable interrupt at interrupt controller */
249                if ( drvmgr_interrupt_unregister(priv->dev, portnr, isr, arg) ) {
250                        return -1;
251                }
252        }
253        if ( options & GPIOLIB_IRQ_CLEAR ) {
254                /* Clear interrupt at interrupt controller */
255                if ( drvmgr_interrupt_clear(priv->dev, portnr) ) {
256                        return -1;
257                }
258        }
259        if ( options & GPIOLIB_IRQ_ENABLE ) {
260                /* Enable interrupt at interrupt controller */
261                if ( drvmgr_interrupt_register(priv->dev, portnr, "grgpio", isr, arg) ) {
262                        return -1;
263                }
264        }
265
266        return 0;
267}
268
269int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
270{
271        struct grgpio_priv *priv;
272        int portnr;
273
274        portnr = grgpio_find_port(handle, &priv);
275        if ( portnr < 0 ) {
276                DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
277                return -1;
278        }
279        DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
280
281        /* Since the user doesn't provide the ISR and argument, we must... */
282        priv->isrs[portnr].isr = func;
283        priv->isrs[portnr].arg = arg;
284
285        return 0;
286}
287
288int grgpio_grpiolib_set(void *handle, int dir, int outval)
289{
290        struct grgpio_priv *priv;
291        int portnr;
292        unsigned int mask;
293
294        portnr = grgpio_find_port(handle, &priv);
295        if ( portnr < 0 ) {
296                DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
297                return -1;
298        }
299        DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
300
301        /* Set Direction and Output */
302        mask = 1<<portnr;
303        priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
304        priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
305
306        return 0;
307}
308
309int grgpio_gpiolib_show(void *handle)
310{
311        struct grgpio_priv *priv;
312        int portnr, i, regs[7];
313        volatile unsigned int *reg;
314
315        portnr = grgpio_find_port(handle, &priv);
316        if ( portnr < 0 ) {
317                DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
318                return -1;
319        }
320        for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
321                regs[i] = ( *reg >> portnr) & 1;
322        }
323        printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
324                priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
325        return 0;
326}
327
328int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
329{
330        struct grgpio_priv *priv;
331        int portnr;
332        char prefix[48];
333        struct drvmgr_dev *dev;
334
335        if ( !pinfo )
336                return -1;
337
338        portnr = grgpio_find_port(handle, &priv);
339        if ( portnr < 0 ) {
340                DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
341                return -1;
342        }
343
344        /* Get Filesystem name prefix */
345        dev = priv->dev;
346        prefix[0] = '\0';
347        if ( drvmgr_get_dev_prefix(dev, prefix) ) {
348                /* Failed to get prefix, make sure of a unique FS name
349                 * by using the driver minor.
350                 */
351                snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
352        } else {
353                /* Got special prefix, this means we have a bus prefix
354                 * And we should use our "bus minor"
355                 */
356                snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
357        }
358
359        return 0;
360}
361
362static struct gpiolib_drv_ops grgpio_gpiolib_ops =
363{
364        .config         = grgpio_grpiolib_config,
365        .get            = grgpio_grpiolib_get,
366        .irq_opts       = grgpio_grpiolib_irq_opts,
367        .irq_register   = grgpio_grpiolib_irq_register,
368        .open           = grgpio_gpiolib_open,
369        .set            = grgpio_grpiolib_set,
370        .show           = grgpio_gpiolib_show,
371        .get_info       = grgpio_gpiolib_get_info,
372};
373
374int grgpio_device_init(struct grgpio_priv *priv)
375{
376        struct amba_dev_info *ambadev;
377        struct ambapp_core *pnpinfo;
378        union drvmgr_key_value *value;
379        unsigned int mask;
380        int port_cnt;
381
382        /* Get device information from AMBA PnP information */
383        ambadev = (struct amba_dev_info *)priv->dev->businfo;
384        if ( ambadev == NULL ) {
385                return -1;
386        }
387        pnpinfo = &ambadev->info;
388        priv->irq = pnpinfo->irq;
389        priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
390
391        DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
392
393        /* Mask all Interrupts */
394        priv->regs->imask = 0;
395
396        /* Make IRQ Rising edge triggered default */
397        priv->regs->ipol = 0xfffffffe;
398        priv->regs->iedge = 0xfffffffe;
399
400        /* Read what I/O lines have IRQ support */
401        priv->imask = priv->regs->ipol;
402
403        /* Let the user configure the port count, this might be needed
404         * when the GPIO lines must not be changed (assigned during bootup)
405         */
406        value = drvmgr_dev_key_get(priv->dev, "nBits", KEY_TYPE_INT);
407        if ( value ) {
408                priv->port_cnt = value->i;
409        } else {
410                /* Auto detect number of GPIO ports */
411                priv->regs->dir = 0;
412                priv->regs->output = 0xffffffff;
413                mask = priv->regs->output;
414                priv->regs->output = 0;
415
416                for(port_cnt=0; port_cnt<32; port_cnt++)
417                        if ( (mask & (1<<port_cnt)) == 0 )
418                                break;
419                priv->port_cnt = port_cnt;
420        }
421
422        /* Let the user configure the BYPASS register, this might be needed
423         * to select which cores can do I/O on a pin.
424         */
425        value = drvmgr_dev_key_get(priv->dev, "bypass", KEY_TYPE_INT);
426        if ( value ) {
427                priv->bypass = value->i;
428        } else {
429                priv->bypass = 0;
430        }
431        priv->regs->bypass = priv->bypass;
432
433        /* Prepare GPIOLIB layer */
434        priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
435
436        return 0;
437}
Note: See TracBrowser for help on using the repository browser.