source: rtems/c/src/lib/libbsp/sparc/shared/gpio/grgpio.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: 10.7 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.org/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 <bsp/grgpio.h>
22#include <bsp/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 */
147static int 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
160static int 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
177static int 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
210static int 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
228static int 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        if ( options & GPIOLIB_IRQ_MASK ) {
266                /* Mask (disable) interrupt at interrupt controller */
267                if ( drvmgr_interrupt_mask(priv->dev, portnr) ) {
268                        return -1;
269                }
270        }
271        if ( options & GPIOLIB_IRQ_UNMASK ) {
272                /* Unmask (enable) interrupt at interrupt controller */
273                if ( drvmgr_interrupt_unmask(priv->dev, portnr) ) {
274                        return -1;
275                }
276        }
277
278        return 0;
279}
280
281static int grgpio_grpiolib_irq_register(void *handle, void *func, void *arg)
282{
283        struct grgpio_priv *priv;
284        int portnr;
285
286        portnr = grgpio_find_port(handle, &priv);
287        if ( portnr < 0 ) {
288                DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
289                return -1;
290        }
291        DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
292
293        /* Since the user doesn't provide the ISR and argument, we must... */
294        priv->isrs[portnr].isr = func;
295        priv->isrs[portnr].arg = arg;
296
297        return 0;
298}
299
300static int grgpio_grpiolib_set(void *handle, int dir, int outval)
301{
302        struct grgpio_priv *priv;
303        int portnr;
304        unsigned int mask;
305
306        portnr = grgpio_find_port(handle, &priv);
307        if ( portnr < 0 ) {
308                DBG("GRGPIO: FAILED OPENING HANDLE 0x%08x\n", handle);
309                return -1;
310        }
311        DBG("GRGPIO: OPENING %d at [0x%08x]\n", portnr, priv->regs);
312
313        /* Set Direction and Output */
314        mask = 1<<portnr;
315        priv->regs->dir = (priv->regs->dir & ~mask) | (dir ? mask : 0);
316        priv->regs->output = (priv->regs->output & ~mask) | (outval ? mask : 0);
317
318        return 0;
319}
320
321static int grgpio_gpiolib_show(void *handle)
322{
323        struct grgpio_priv *priv;
324        int portnr, i, regs[7];
325        volatile unsigned int *reg;
326
327        portnr = grgpio_find_port(handle, &priv);
328        if ( portnr < 0 ) {
329                DBG("GRGPIO: FAILED SHOWING HANDLE 0x%08x\n", handle);
330                return -1;
331        }
332        for (i=0, reg=&priv->regs->data; i<7; i++, reg++) {
333                regs[i] = ( *reg >> portnr) & 1;
334        }
335        printf("GRGPIO[%p] PORT[%d]: IN/OUT/DIR: [%d,%d,%d], MASK/POL/EDGE: [%d,%d,%d], BYPASS: %d\n",
336                priv->regs, portnr, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6]);
337        return 0;
338}
339
340static int grgpio_gpiolib_get_info(void *handle, struct gpiolib_info *pinfo)
341{
342        struct grgpio_priv *priv;
343        int portnr;
344        char prefix[48];
345        struct drvmgr_dev *dev;
346
347        if ( !pinfo )
348                return -1;
349
350        portnr = grgpio_find_port(handle, &priv);
351        if ( portnr < 0 ) {
352                DBG("GRGPIO: FAILED GET_INFO HANDLE 0x%08x\n", handle);
353                return -1;
354        }
355
356        /* Get Filesystem name prefix */
357        dev = priv->dev;
358        prefix[0] = '\0';
359        if ( drvmgr_get_dev_prefix(dev, prefix) ) {
360                /* Failed to get prefix, make sure of a unique FS name
361                 * by using the driver minor.
362                 */
363                snprintf(pinfo->devName, 64, "/dev/grgpio%d/%d", dev->minor_drv, portnr);
364        } else {
365                /* Got special prefix, this means we have a bus prefix
366                 * And we should use our "bus minor"
367                 */
368                snprintf(pinfo->devName, 64, "/dev/%sgrgpio%d/%d", prefix, dev->minor_bus, portnr);
369        }
370
371        return 0;
372}
373
374static struct gpiolib_drv_ops grgpio_gpiolib_ops = 
375{
376        .config         = grgpio_grpiolib_config,
377        .get            = grgpio_grpiolib_get,
378        .irq_opts       = grgpio_grpiolib_irq_opts,
379        .irq_register   = grgpio_grpiolib_irq_register,
380        .open           = grgpio_gpiolib_open,
381        .set            = grgpio_grpiolib_set,
382        .show           = grgpio_gpiolib_show,
383        .get_info       = grgpio_gpiolib_get_info,
384};
385
386int grgpio_device_init(struct grgpio_priv *priv)
387{
388        struct amba_dev_info *ambadev;
389        struct ambapp_core *pnpinfo;
390        union drvmgr_key_value *value;
391        unsigned int mask;
392        int port_cnt;
393
394        /* Get device information from AMBA PnP information */
395        ambadev = (struct amba_dev_info *)priv->dev->businfo;
396        if ( ambadev == NULL ) {
397                return -1;
398        }
399        pnpinfo = &ambadev->info;
400        priv->irq = pnpinfo->irq;
401        priv->regs = (struct grgpio_regs *)pnpinfo->apb_slv->start;
402
403        DBG("GRGPIO: 0x%08x irq %d\n", (unsigned int)priv->regs, priv->irq);
404
405        /* Mask all Interrupts */
406        priv->regs->imask = 0;
407
408        /* Make IRQ Rising edge triggered default */
409        priv->regs->ipol = 0xfffffffe;
410        priv->regs->iedge = 0xfffffffe;
411
412        /* Read what I/O lines have IRQ support */
413        priv->imask = priv->regs->ipol;
414
415        /* Let the user configure the port count, this might be needed
416         * when the GPIO lines must not be changed (assigned during bootup)
417         */
418        value = drvmgr_dev_key_get(priv->dev, "nBits", KEY_TYPE_INT);
419        if ( value ) {
420                priv->port_cnt = value->i;
421        } else {
422                /* Auto detect number of GPIO ports */
423                priv->regs->dir = 0;
424                priv->regs->output = 0xffffffff;
425                mask = priv->regs->output;
426                priv->regs->output = 0;
427
428                for(port_cnt=0; port_cnt<32; port_cnt++)
429                        if ( (mask & (1<<port_cnt)) == 0 )
430                                break;
431                priv->port_cnt = port_cnt;
432        }
433
434        /* Let the user configure the BYPASS register, this might be needed
435         * to select which cores can do I/O on a pin.
436         */
437        value = drvmgr_dev_key_get(priv->dev, "bypass", KEY_TYPE_INT);
438        if ( value ) {
439                priv->bypass = value->i;
440        } else {
441                priv->bypass = 0;
442        }
443        priv->regs->bypass = priv->bypass;
444
445        /* Prepare GPIOLIB layer */
446        priv->gpiolib_desc.ops = &grgpio_gpiolib_ops;
447
448        return 0;
449}
Note: See TracBrowser for help on using the repository browser.