source: rtems/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c @ 5823bae8

4.115
Last change on this file since 5823bae8 was 5823bae8, checked in by Daniel Hellstrom <daniel@…>, on 02/27/15 at 13:03:15

LEON: move driver headers to bsp/ directory

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