source: rtems/bsps/sparc/shared/analog/gradcdac.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: 13.6 KB
Line 
1/*  ADC / DAC (GRADCDAC) interface implementation
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 <rtems.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <drvmgr/drvmgr.h>
16#include <drvmgr/ambapp_bus.h>
17#include <bsp/gradcdac.h>
18
19/****************** DEBUG Definitions ********************/
20#define DBG_IOCTRL 1
21#define DBG_TX 2
22#define DBG_RX 4
23
24#define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
25/* Uncomment for debug output */
26/*
27#define DEBUG
28#define DEBUGFUNCS
29*/
30#include <bsp/debug_defs.h>
31
32#include <grlib_impl.h>
33
34struct gradcdac_priv {
35        struct gradcdac_regs *regs;     /* Must be first */
36        struct drvmgr_dev *dev;
37        char devName[48];
38
39        unsigned int freq;
40        int irqno;
41        int minor;
42
43        void (*isr_adc)(void *cookie, void *arg);
44        void (*isr_dac)(void *cookie, void *arg);
45        void *isr_adc_arg;
46        void *isr_dac_arg;
47
48        int open;
49};
50
51/* Global variables */
52
53/* Print Info routines */
54void gradcdac_print(void *cookie);
55
56int gradcdac_init2(struct drvmgr_dev *dev);
57int gradcdac_init3(struct drvmgr_dev *dev);
58int gradcadc_device_init(struct gradcdac_priv *pDev);
59void gradcdac_adc_interrupt(void *arg);
60void gradcdac_dac_interrupt(void *arg);
61
62struct drvmgr_drv_ops gradcdac_ops =
63{
64        .init = {NULL, gradcdac_init2, gradcdac_init3, NULL},
65        .remove = NULL,
66        .info = NULL
67};
68
69struct amba_dev_id gradcdac_ids[] =
70{
71        {VENDOR_GAISLER, GAISLER_GRADCDAC},
72        {0, 0}          /* Mark end of table */
73};
74
75struct amba_drv_info gradcdac_drv_info =
76{
77        {
78                DRVMGR_OBJ_DRV,                         /* Driver */
79                NULL,                                   /* Next driver */
80                NULL,                                   /* Device list */
81                DRIVER_AMBAPP_GAISLER_GRADCDAC_ID,      /* Driver ID */
82                "GRADCDAC_DRV",                         /* Driver Name */
83                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
84                &gradcdac_ops,
85                NULL,                                   /* Funcs */
86                0,                                      /* No devices yet */
87                0,
88        },
89        &gradcdac_ids[0]
90};
91
92void gradcdac_register_drv (void)
93{
94        DBG("Registering GRADCDAC driver\n");
95        drvmgr_drv_register(&gradcdac_drv_info.general);
96}
97
98int gradcdac_init2(struct drvmgr_dev *dev)
99{
100        struct gradcdac_priv *priv;
101
102        DBG("GRADCDAC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
103
104        priv = dev->priv = grlib_calloc(1, sizeof(*priv));
105        if ( !priv )
106                return DRVMGR_NOMEM;
107        priv->dev = dev;
108
109        /* This core will not find other cores, so we wait for init2() */
110
111        return DRVMGR_OK;
112}
113
114
115int gradcdac_init3(struct drvmgr_dev *dev)
116{
117        struct gradcdac_priv *priv = dev->priv;
118        char prefix[32];
119
120        if ( !priv )
121                return DRVMGR_FAIL;
122
123        if ( gradcadc_device_init(priv) ) {
124                free(dev->priv);
125                dev->priv = NULL;
126                return DRVMGR_FAIL;
127        }
128
129        /* Get Filesystem name prefix */
130        prefix[0] = '\0';
131        if ( drvmgr_get_dev_prefix(dev, prefix) ) {
132                /* Failed to get prefix, make sure of a unique FS name
133                 * by using the driver minor.
134                 */
135                sprintf(priv->devName, "/dev/gradcdac%d", dev->minor_drv);
136        } else {
137                /* Got special prefix, this means we have a bus prefix
138                 * And we should use our "bus minor"
139                 */
140                sprintf(priv->devName, "/dev/%sgradcdac%d", prefix, dev->minor_bus);
141        }
142
143        return DRVMGR_OK;
144}
145
146static void gradcdac_print_dev(struct gradcdac_priv *pDev)
147{
148        printf("======= GRADCDAC %p =======\n", pDev->regs);
149        printf(" Minor:          %d\n", pDev->minor);
150        printf(" Dev Name:       %s\n", pDev->devName);
151        printf(" RegBase:        %p\n", pDev->regs);
152        printf(" IRQ:            %d and %d\n", pDev->irqno, pDev->irqno+1);
153        printf(" Core Freq:      %d kHz\n", pDev->freq / 1000);
154        printf(" Opened:         %s\n", pDev->open ? "YES" : "NO");
155
156        printf(" CONFIG:         0x%x\n", pDev->regs->config);
157        printf(" STATUS:         0x%x\n", pDev->regs->status);
158}
159
160void gradcdac_print(void *cookie)
161{
162        struct drvmgr_dev *dev;
163        struct gradcdac_priv *pDev;
164
165        if ( cookie ) {
166                gradcdac_print_dev(cookie);
167                return;
168        }
169
170        /* Show all */
171        dev = gradcdac_drv_info.general.dev;
172        while (dev) {
173                pDev = (struct gradcdac_priv *)dev->priv;
174                gradcdac_print_dev(pDev);
175                dev = dev->next_in_drv;
176        }
177}
178
179static void gradcdac_hw_reset(struct gradcdac_regs *regs)
180{
181        /* Reset core */
182        regs->config = 0;
183        regs->adrdir = 0;
184        regs->adrout = 0;
185        regs->data_dir = 0;
186        regs->data_out = 0;
187}
188       
189/* Device initialization called once on startup */
190int gradcadc_device_init(struct gradcdac_priv *pDev)
191{
192        struct amba_dev_info *ambadev;
193        struct ambapp_core *pnpinfo;
194
195        /* Get device information from AMBA PnP information */
196        ambadev = (struct amba_dev_info *)pDev->dev->businfo;
197        if ( ambadev == NULL ) {
198                return -1;
199        }
200        pnpinfo = &ambadev->info;
201        pDev->irqno = pnpinfo->irq;
202        pDev->regs = (struct gradcdac_regs *)pnpinfo->apb_slv->start;
203        pDev->minor = pDev->dev->minor_drv;
204
205        /* Reset Hardware before attaching IRQ handler */
206        gradcdac_hw_reset(pDev->regs);
207
208        pDev->open = 0;
209       
210        /* Get frequency in Hz */
211        if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->freq) ) {
212                return -1;
213        }
214
215        DBG("GRADCDAC frequency: %d Hz\n", pDev->freq);
216
217        return 0;
218}
219
220void gradcdac_dac_interrupt(void *arg)
221{
222        struct gradcdac_priv *pDev = arg;
223        if ( pDev->isr_dac )
224                pDev->isr_dac(pDev, pDev->isr_dac_arg);
225}
226
227void gradcdac_adc_interrupt(void *arg)
228{
229        struct gradcdac_priv *pDev = arg;
230        if ( pDev->isr_adc )
231                pDev->isr_adc(pDev, pDev->isr_adc_arg);
232}
233
234void *gradcdac_open(char *devname)
235{
236        struct gradcdac_priv *pDev;
237        struct drvmgr_dev *dev;
238
239        /* Find device by name */
240        dev = gradcdac_drv_info.general.dev;
241        while ( dev ) {
242                pDev = (struct gradcdac_priv *)dev->priv;
243                if ( pDev ) {
244                        if ( strncmp(pDev->devName, devname, sizeof(pDev->devName)) == 0 ) {
245                                /* Found matching device name */
246                                break;
247                        }
248                }
249                dev = dev->next_in_drv;
250        }
251
252        if ( !dev )
253                return NULL;
254
255        /* is device busy/taken? */
256        if  ( pDev->open )
257                return NULL;
258
259        /* Mark device taken */
260        pDev->open = 1;
261
262        return pDev;
263}
264
265void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg)
266{
267        struct gradcdac_priv *pDev = cookie;
268        unsigned int config=0;
269
270        config = (cfg->dac_ws<<GRADCDAC_CFG_DACWS_BIT)&GRADCDAC_CFG_DACWS;
271
272        if ( cfg->wr_pol )
273                config |= GRADCDAC_CFG_WRPOL;
274
275        config |= (cfg->dac_dw<<GRADCDAC_CFG_DACDW_BIT)&GRADCDAC_CFG_DACDW;
276
277        config |= (cfg->adc_ws<<GRADCDAC_CFG_ADCWS_BIT)&GRADCDAC_CFG_ADCWS;
278
279        if ( cfg->rc_pol )
280                config |= GRADCDAC_CFG_RCPOL;
281
282        config |= (cfg->cs_mode<<GRADCDAC_CFG_CSMODE_BIT)&GRADCDAC_CFG_CSMODE;
283
284        if ( cfg->cs_pol )
285                config |= GRADCDAC_CFG_CSPOL;
286
287        if ( cfg->ready_mode )
288                config |= GRADCDAC_CFG_RDYMODE;
289
290        if ( cfg->ready_pol )
291                config |= GRADCDAC_CFG_RDYPOL;
292
293        if ( cfg->trigg_pol )
294                config |= GRADCDAC_CFG_TRIGPOL;
295
296        config |= (cfg->trigg_mode<<GRADCDAC_CFG_TRIGMODE_BIT)&GRADCDAC_CFG_TRIGMODE;
297
298        config |= (cfg->adc_dw<<GRADCDAC_CFG_ADCDW_BIT)&GRADCDAC_CFG_ADCDW;
299
300        /* Write config */
301        pDev->regs->config = config;
302}
303
304void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg)
305{
306        struct gradcdac_priv *pDev = cookie;
307        unsigned int config;
308
309        if ( !cfg )
310                return;
311
312        /* Get config */
313        config = pDev->regs->config;
314       
315        cfg->dac_ws =  (config&GRADCDAC_CFG_DACWS)>>GRADCDAC_CFG_DACWS_BIT;
316
317        cfg->wr_pol = (config&GRADCDAC_CFG_WRPOL)>>GRADCDAC_CFG_WRPOL_BIT;
318
319        cfg->dac_dw = (config&GRADCDAC_CFG_DACDW)>>GRADCDAC_CFG_DACDW_BIT;
320
321        cfg->adc_ws = (config&GRADCDAC_CFG_ADCWS)>>GRADCDAC_CFG_ADCWS_BIT;
322
323        cfg->rc_pol = (config&GRADCDAC_CFG_RCPOL)>>GRADCDAC_CFG_RCPOL_BIT;
324               
325        cfg->cs_mode = (config&GRADCDAC_CFG_CSMODE)>>GRADCDAC_CFG_CSMODE_BIT;
326
327        cfg->cs_pol = (config&GRADCDAC_CFG_CSPOL)>>GRADCDAC_CFG_CSPOL_BIT;
328               
329        cfg->ready_mode = (config&GRADCDAC_CFG_RDYMODE)>>GRADCDAC_CFG_RDYMODE_BIT;
330       
331        cfg->ready_pol = (config&GRADCDAC_CFG_RDYPOL)>>GRADCDAC_CFG_RDYPOL_BIT;
332       
333        cfg->trigg_pol = (config&GRADCDAC_CFG_TRIGPOL)>>GRADCDAC_CFG_TRIGPOL_BIT;
334
335        cfg->trigg_mode = (config&GRADCDAC_CFG_TRIGMODE)>>GRADCDAC_CFG_TRIGMODE_BIT;
336       
337        cfg->adc_dw = (config&GRADCDAC_CFG_ADCDW)>>GRADCDAC_CFG_ADCDW_BIT;
338}
339
340void gradcdac_set_cfg(void *cookie, unsigned int config)
341{
342        struct gradcdac_priv *pDev = cookie;
343        pDev->regs->config = config;
344}
345
346unsigned int gradcdac_get_cfg(void *cookie)
347{
348        struct gradcdac_priv *pDev = cookie;
349        return pDev->regs->config;
350}
351
352unsigned int gradcdac_get_status(void *cookie)
353{
354        struct gradcdac_priv *pDev = cookie;
355        return pDev->regs->status;
356}
357
358/* Install IRQ handler for ADC and/or DAC interrupt.
359 * The installed IRQ handler(ISR) must read the status
360 * register to clear the pending interrupt avoiding multiple
361 * entries to the ISR caused by the same IRQ.
362 *
363 * \param adc  1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
364 * \param isr  Interrupt service routine called when IRQ is fired
365 * \param arg  custom argument passed to ISR when called.
366 */
367int gradcdac_install_irq_handler(void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg)
368{
369        struct gradcdac_priv *pDev = cookie;
370
371        if ( (adc > 3) || !adc )
372                return -1;
373
374        if ( adc & GRADCDAC_ISR_ADC ){
375                pDev->isr_adc_arg = arg;
376                pDev->isr_adc = isr;
377                drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_ADC, "gradcdac_adc", gradcdac_adc_interrupt, pDev);
378        }
379
380        if ( adc & GRADCDAC_ISR_DAC ){
381                pDev->isr_dac_arg = arg;
382                pDev->isr_dac = isr;
383                drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_DAC, "gradcdac_dac", gradcdac_dac_interrupt, pDev);
384        }
385
386        return 0;
387}
388
389void gradcdac_uninstall_irq_handler(void *cookie, int adc)
390{
391        struct gradcdac_priv *pDev = cookie;
392
393        if ( (adc > 3) || !adc )
394                return;
395
396        if ( adc & GRADCDAC_ISR_ADC ){
397                drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_ADC, gradcdac_adc_interrupt, pDev);
398                pDev->isr_adc = NULL;
399                pDev->isr_adc_arg = NULL;
400        }
401
402        if ( adc & GRADCDAC_ISR_DAC ){
403                drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_DAC, gradcdac_dac_interrupt, pDev);
404                pDev->isr_dac = NULL;
405                pDev->isr_dac_arg = NULL;
406        }
407}
408
409/* Make the ADC circuitry initialize a analogue to digital
410 * conversion. The result can be read out by gradcdac_adc_convert_try
411 * or gradcdac_adc_convert.
412 */
413void gradcdac_adc_convert_start(void *cookie)
414{
415        struct gradcdac_priv *pDev = cookie;
416
417        /* Write to ADC Data Input register to start a conversion */
418        pDev->regs->adc_din = 0;
419}
420
421/* Tries to read the conversion result. If the circuitry is busy
422 * converting the function return a non-zero value, if the conversion
423 * has successfully finished the function return zero.
424 *
425 * \param digital_value the resulting converted value is placed here
426 * \return zero     = ADC conversion complete, digital_value contain current conversion result
427 *         positive = ADC busy, digital_value contain previous conversion result
428 *         negative = Conversion request failed.
429 */
430int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value)
431{
432        struct gradcdac_priv *pDev = cookie;
433        unsigned int status;
434
435        status = pDev->regs->status;
436
437        if ( digital_value ){
438                *digital_value = pDev->regs->adc_din;
439        }
440
441        if ( gradcdac_ADC_isOngoing(status) )
442                return 1;
443
444        if ( gradcdac_ADC_isCompleted(status) )
445                return 0;
446
447        /* Failure */
448        return -1;
449}
450
451/* Waits until the ADC circuity has finished a digital to analogue
452 * conversion. The Waiting is implemented as a busy loop utilizing
453 * 100% CPU load.
454 */
455int gradcdac_adc_convert(void *cookie, unsigned short *digital_value)
456{
457        struct gradcdac_priv *pDev = cookie;
458        unsigned int status;
459
460        do {
461                status=gradcdac_get_status(pDev);
462        }while ( gradcdac_ADC_isOngoing(status) );
463
464        if ( digital_value )
465                *digital_value = pDev->regs->adc_din;
466
467        if ( gradcdac_ADC_isCompleted(status) )
468                return 0;
469
470        return -1;
471}
472
473/* Try to make the DAC circuitry initialize a digital to analogue
474 * conversion. If the circuitry is busy by a previous conversion
475 * the function return a non-zero value, if the conversion is
476 * successfully initialized the function return zero.
477 */
478int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value)
479{
480        struct gradcdac_priv *pDev = cookie;
481        unsigned int status = pDev->regs->status;
482
483        if ( gradcdac_DAC_isOngoing(status) )
484                return -1;
485
486        /* Force a new conversion */
487        pDev->regs->dac_dout = digital_value;
488
489        /* Return success */
490        return 0;
491}
492
493/* Initializes a digital to analogue conversion by waiting until
494 * previous conversions is finished before proceeding with the
495 * conversion. The Waiting is implemented as a busy loop utilizing
496 * 100% CPU load.
497 */
498void gradcdac_dac_convert(void *cookie, unsigned short digital_value)
499{
500        struct gradcdac_priv *pDev = cookie;
501        unsigned int status;
502       
503        do {
504                status = gradcdac_get_status(pDev);
505        }while( gradcdac_DAC_isOngoing(status) );
506       
507        pDev->regs->dac_dout = digital_value;
508}
509
510unsigned int gradcdac_get_adrinput(void *cookie)
511{
512        struct gradcdac_priv *pDev = cookie;
513        return pDev->regs->adrin;
514}
515
516void gradcdac_set_adrinput(void *cookie, unsigned int input)
517{
518        struct gradcdac_priv *pDev = cookie;
519        pDev->regs->adrin = input;
520}
521
522unsigned int gradcdac_get_adroutput(void *cookie)
523{
524        struct gradcdac_priv *pDev = cookie;
525        return pDev->regs->adrout;
526}
527
528void gradcdac_set_adroutput(void *cookie, unsigned int output)
529{
530        struct gradcdac_priv *pDev = cookie;
531        pDev->regs->adrout = output;
532}
533
534unsigned int gradcdac_get_adrdir(void *cookie)
535{
536        struct gradcdac_priv *pDev = cookie;
537        return pDev->regs->adrdir;
538}
539
540void gradcdac_set_adrdir(void *cookie, unsigned int dir)
541{
542        struct gradcdac_priv *pDev = cookie;
543        pDev->regs->adrdir = dir;
544}
545
546unsigned int gradcdac_get_datainput(void *cookie)
547{
548        struct gradcdac_priv *pDev = cookie;
549        return pDev->regs->data_in;
550}
551
552void gradcdac_set_datainput(void *cookie, unsigned int input)
553{
554        struct gradcdac_priv *pDev = cookie;
555        pDev->regs->data_in = input;
556}
557
558unsigned int gradcdac_get_dataoutput(void *cookie)
559{
560        struct gradcdac_priv *pDev = cookie;
561        return pDev->regs->data_out;
562}
563
564void gradcdac_set_dataoutput(void *cookie, unsigned int output)
565{
566        struct gradcdac_priv *pDev = cookie;
567        pDev->regs->data_out = output;
568}
569
570unsigned int gradcdac_get_datadir(void *cookie)
571{
572        struct gradcdac_priv *pDev = cookie;
573        return pDev->regs->data_dir;
574}
575
576void gradcdac_set_datadir(void *cookie, unsigned int dir)
577{
578        struct gradcdac_priv *pDev = cookie;
579        pDev->regs->data_dir = dir;
580}
Note: See TracBrowser for help on using the repository browser.