summaryrefslogtreecommitdiffstats
path: root/bsps/shared/grlib/analog
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-12-22 18:31:04 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-01-22 12:46:33 +0100
commit7eb606d393306da25fd6e6aa7f8595ffb2e924fc (patch)
tree085befd6fe5e29d229fec9683735516d48e9d41e /bsps/shared/grlib/analog
parentgrlib: Move header files (diff)
downloadrtems-7eb606d393306da25fd6e6aa7f8595ffb2e924fc.tar.bz2
grlib: Move source files
Update #3678.
Diffstat (limited to 'bsps/shared/grlib/analog')
-rw-r--r--bsps/shared/grlib/analog/gradcdac.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/bsps/shared/grlib/analog/gradcdac.c b/bsps/shared/grlib/analog/gradcdac.c
new file mode 100644
index 0000000000..02939e58f0
--- /dev/null
+++ b/bsps/shared/grlib/analog/gradcdac.c
@@ -0,0 +1,580 @@
+/* ADC / DAC (GRADCDAC) interface implementation
+ *
+ * COPYRIGHT (c) 2009.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <drvmgr/drvmgr.h>
+#include <grlib/ambapp_bus.h>
+#include <grlib/gradcdac.h>
+
+/****************** DEBUG Definitions ********************/
+#define DBG_IOCTRL 1
+#define DBG_TX 2
+#define DBG_RX 4
+
+#define DEBUG_FLAGS (DBG_IOCTRL | DBG_RX | DBG_TX )
+/* Uncomment for debug output */
+/*
+#define DEBUG
+#define DEBUGFUNCS
+*/
+#include <grlib/debug_defs.h>
+
+#include <grlib/grlib_impl.h>
+
+struct gradcdac_priv {
+ struct gradcdac_regs *regs; /* Must be first */
+ struct drvmgr_dev *dev;
+ char devName[48];
+
+ unsigned int freq;
+ int irqno;
+ int minor;
+
+ void (*isr_adc)(void *cookie, void *arg);
+ void (*isr_dac)(void *cookie, void *arg);
+ void *isr_adc_arg;
+ void *isr_dac_arg;
+
+ int open;
+};
+
+/* Global variables */
+
+/* Print Info routines */
+void gradcdac_print(void *cookie);
+
+int gradcdac_init2(struct drvmgr_dev *dev);
+int gradcdac_init3(struct drvmgr_dev *dev);
+int gradcadc_device_init(struct gradcdac_priv *pDev);
+void gradcdac_adc_interrupt(void *arg);
+void gradcdac_dac_interrupt(void *arg);
+
+struct drvmgr_drv_ops gradcdac_ops =
+{
+ .init = {NULL, gradcdac_init2, gradcdac_init3, NULL},
+ .remove = NULL,
+ .info = NULL
+};
+
+struct amba_dev_id gradcdac_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_GRADCDAC},
+ {0, 0} /* Mark end of table */
+};
+
+struct amba_drv_info gradcdac_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_GRADCDAC_ID, /* Driver ID */
+ "GRADCDAC_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &gradcdac_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ 0,
+ },
+ &gradcdac_ids[0]
+};
+
+void gradcdac_register_drv (void)
+{
+ DBG("Registering GRADCDAC driver\n");
+ drvmgr_drv_register(&gradcdac_drv_info.general);
+}
+
+int gradcdac_init2(struct drvmgr_dev *dev)
+{
+ struct gradcdac_priv *priv;
+
+ DBG("GRADCDAC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+
+ priv = dev->priv = grlib_calloc(1, sizeof(*priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* This core will not find other cores, so we wait for init2() */
+
+ return DRVMGR_OK;
+}
+
+
+int gradcdac_init3(struct drvmgr_dev *dev)
+{
+ struct gradcdac_priv *priv = dev->priv;
+ char prefix[32];
+
+ if ( !priv )
+ return DRVMGR_FAIL;
+
+ if ( gradcadc_device_init(priv) ) {
+ free(dev->priv);
+ dev->priv = NULL;
+ return DRVMGR_FAIL;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if ( drvmgr_get_dev_prefix(dev, prefix) ) {
+ /* Failed to get prefix, make sure of a unique FS name
+ * by using the driver minor.
+ */
+ sprintf(priv->devName, "/dev/gradcdac%d", dev->minor_drv);
+ } else {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sgradcdac%d", prefix, dev->minor_bus);
+ }
+
+ return DRVMGR_OK;
+}
+
+static void gradcdac_print_dev(struct gradcdac_priv *pDev)
+{
+ printf("======= GRADCDAC %p =======\n", pDev->regs);
+ printf(" Minor: %d\n", pDev->minor);
+ printf(" Dev Name: %s\n", pDev->devName);
+ printf(" RegBase: %p\n", pDev->regs);
+ printf(" IRQ: %d and %d\n", pDev->irqno, pDev->irqno+1);
+ printf(" Core Freq: %d kHz\n", pDev->freq / 1000);
+ printf(" Opened: %s\n", pDev->open ? "YES" : "NO");
+
+ printf(" CONFIG: 0x%x\n", pDev->regs->config);
+ printf(" STATUS: 0x%x\n", pDev->regs->status);
+}
+
+void gradcdac_print(void *cookie)
+{
+ struct drvmgr_dev *dev;
+ struct gradcdac_priv *pDev;
+
+ if ( cookie ) {
+ gradcdac_print_dev(cookie);
+ return;
+ }
+
+ /* Show all */
+ dev = gradcdac_drv_info.general.dev;
+ while (dev) {
+ pDev = (struct gradcdac_priv *)dev->priv;
+ gradcdac_print_dev(pDev);
+ dev = dev->next_in_drv;
+ }
+}
+
+static void gradcdac_hw_reset(struct gradcdac_regs *regs)
+{
+ /* Reset core */
+ regs->config = 0;
+ regs->adrdir = 0;
+ regs->adrout = 0;
+ regs->data_dir = 0;
+ regs->data_out = 0;
+}
+
+/* Device initialization called once on startup */
+int gradcadc_device_init(struct gradcdac_priv *pDev)
+{
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)pDev->dev->businfo;
+ if ( ambadev == NULL ) {
+ return -1;
+ }
+ pnpinfo = &ambadev->info;
+ pDev->irqno = pnpinfo->irq;
+ pDev->regs = (struct gradcdac_regs *)pnpinfo->apb_slv->start;
+ pDev->minor = pDev->dev->minor_drv;
+
+ /* Reset Hardware before attaching IRQ handler */
+ gradcdac_hw_reset(pDev->regs);
+
+ pDev->open = 0;
+
+ /* Get frequency in Hz */
+ if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->freq) ) {
+ return -1;
+ }
+
+ DBG("GRADCDAC frequency: %d Hz\n", pDev->freq);
+
+ return 0;
+}
+
+void gradcdac_dac_interrupt(void *arg)
+{
+ struct gradcdac_priv *pDev = arg;
+ if ( pDev->isr_dac )
+ pDev->isr_dac(pDev, pDev->isr_dac_arg);
+}
+
+void gradcdac_adc_interrupt(void *arg)
+{
+ struct gradcdac_priv *pDev = arg;
+ if ( pDev->isr_adc )
+ pDev->isr_adc(pDev, pDev->isr_adc_arg);
+}
+
+void *gradcdac_open(char *devname)
+{
+ struct gradcdac_priv *pDev;
+ struct drvmgr_dev *dev;
+
+ /* Find device by name */
+ dev = gradcdac_drv_info.general.dev;
+ while ( dev ) {
+ pDev = (struct gradcdac_priv *)dev->priv;
+ if ( pDev ) {
+ if ( strncmp(pDev->devName, devname, sizeof(pDev->devName)) == 0 ) {
+ /* Found matching device name */
+ break;
+ }
+ }
+ dev = dev->next_in_drv;
+ }
+
+ if ( !dev )
+ return NULL;
+
+ /* is device busy/taken? */
+ if ( pDev->open )
+ return NULL;
+
+ /* Mark device taken */
+ pDev->open = 1;
+
+ return pDev;
+}
+
+void gradcdac_set_config(void *cookie, struct gradcdac_config *cfg)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int config=0;
+
+ config = (cfg->dac_ws<<GRADCDAC_CFG_DACWS_BIT)&GRADCDAC_CFG_DACWS;
+
+ if ( cfg->wr_pol )
+ config |= GRADCDAC_CFG_WRPOL;
+
+ config |= (cfg->dac_dw<<GRADCDAC_CFG_DACDW_BIT)&GRADCDAC_CFG_DACDW;
+
+ config |= (cfg->adc_ws<<GRADCDAC_CFG_ADCWS_BIT)&GRADCDAC_CFG_ADCWS;
+
+ if ( cfg->rc_pol )
+ config |= GRADCDAC_CFG_RCPOL;
+
+ config |= (cfg->cs_mode<<GRADCDAC_CFG_CSMODE_BIT)&GRADCDAC_CFG_CSMODE;
+
+ if ( cfg->cs_pol )
+ config |= GRADCDAC_CFG_CSPOL;
+
+ if ( cfg->ready_mode )
+ config |= GRADCDAC_CFG_RDYMODE;
+
+ if ( cfg->ready_pol )
+ config |= GRADCDAC_CFG_RDYPOL;
+
+ if ( cfg->trigg_pol )
+ config |= GRADCDAC_CFG_TRIGPOL;
+
+ config |= (cfg->trigg_mode<<GRADCDAC_CFG_TRIGMODE_BIT)&GRADCDAC_CFG_TRIGMODE;
+
+ config |= (cfg->adc_dw<<GRADCDAC_CFG_ADCDW_BIT)&GRADCDAC_CFG_ADCDW;
+
+ /* Write config */
+ pDev->regs->config = config;
+}
+
+void gradcdac_get_config(void *cookie, struct gradcdac_config *cfg)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int config;
+
+ if ( !cfg )
+ return;
+
+ /* Get config */
+ config = pDev->regs->config;
+
+ cfg->dac_ws = (config&GRADCDAC_CFG_DACWS)>>GRADCDAC_CFG_DACWS_BIT;
+
+ cfg->wr_pol = (config&GRADCDAC_CFG_WRPOL)>>GRADCDAC_CFG_WRPOL_BIT;
+
+ cfg->dac_dw = (config&GRADCDAC_CFG_DACDW)>>GRADCDAC_CFG_DACDW_BIT;
+
+ cfg->adc_ws = (config&GRADCDAC_CFG_ADCWS)>>GRADCDAC_CFG_ADCWS_BIT;
+
+ cfg->rc_pol = (config&GRADCDAC_CFG_RCPOL)>>GRADCDAC_CFG_RCPOL_BIT;
+
+ cfg->cs_mode = (config&GRADCDAC_CFG_CSMODE)>>GRADCDAC_CFG_CSMODE_BIT;
+
+ cfg->cs_pol = (config&GRADCDAC_CFG_CSPOL)>>GRADCDAC_CFG_CSPOL_BIT;
+
+ cfg->ready_mode = (config&GRADCDAC_CFG_RDYMODE)>>GRADCDAC_CFG_RDYMODE_BIT;
+
+ cfg->ready_pol = (config&GRADCDAC_CFG_RDYPOL)>>GRADCDAC_CFG_RDYPOL_BIT;
+
+ cfg->trigg_pol = (config&GRADCDAC_CFG_TRIGPOL)>>GRADCDAC_CFG_TRIGPOL_BIT;
+
+ cfg->trigg_mode = (config&GRADCDAC_CFG_TRIGMODE)>>GRADCDAC_CFG_TRIGMODE_BIT;
+
+ cfg->adc_dw = (config&GRADCDAC_CFG_ADCDW)>>GRADCDAC_CFG_ADCDW_BIT;
+}
+
+void gradcdac_set_cfg(void *cookie, unsigned int config)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->config = config;
+}
+
+unsigned int gradcdac_get_cfg(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->config;
+}
+
+unsigned int gradcdac_get_status(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->status;
+}
+
+/* Install IRQ handler for ADC and/or DAC interrupt.
+ * The installed IRQ handler(ISR) must read the status
+ * register to clear the pending interrupt avoiding multiple
+ * entries to the ISR caused by the same IRQ.
+ *
+ * \param adc 1=ADC interrupt, 2=ADC interrupt, 3=ADC and DAC interrupt
+ * \param isr Interrupt service routine called when IRQ is fired
+ * \param arg custom argument passed to ISR when called.
+ */
+int gradcdac_install_irq_handler(void *cookie, int adc, void (*isr)(void *cookie, void *arg), void *arg)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ if ( (adc > 3) || !adc )
+ return -1;
+
+ if ( adc & GRADCDAC_ISR_ADC ){
+ pDev->isr_adc_arg = arg;
+ pDev->isr_adc = isr;
+ drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_ADC, "gradcdac_adc", gradcdac_adc_interrupt, pDev);
+ }
+
+ if ( adc & GRADCDAC_ISR_DAC ){
+ pDev->isr_dac_arg = arg;
+ pDev->isr_dac = isr;
+ drvmgr_interrupt_register(pDev->dev, GRADCDAC_IRQ_DAC, "gradcdac_dac", gradcdac_dac_interrupt, pDev);
+ }
+
+ return 0;
+}
+
+void gradcdac_uninstall_irq_handler(void *cookie, int adc)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ if ( (adc > 3) || !adc )
+ return;
+
+ if ( adc & GRADCDAC_ISR_ADC ){
+ drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_ADC, gradcdac_adc_interrupt, pDev);
+ pDev->isr_adc = NULL;
+ pDev->isr_adc_arg = NULL;
+ }
+
+ if ( adc & GRADCDAC_ISR_DAC ){
+ drvmgr_interrupt_unregister(pDev->dev, GRADCDAC_IRQ_DAC, gradcdac_dac_interrupt, pDev);
+ pDev->isr_dac = NULL;
+ pDev->isr_dac_arg = NULL;
+ }
+}
+
+/* Make the ADC circuitry initialize a analogue to digital
+ * conversion. The result can be read out by gradcdac_adc_convert_try
+ * or gradcdac_adc_convert.
+ */
+void gradcdac_adc_convert_start(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+
+ /* Write to ADC Data Input register to start a conversion */
+ pDev->regs->adc_din = 0;
+}
+
+/* Tries to read the conversion result. If the circuitry is busy
+ * converting the function return a non-zero value, if the conversion
+ * has successfully finished the function return zero.
+ *
+ * \param digital_value the resulting converted value is placed here
+ * \return zero = ADC conversion complete, digital_value contain current conversion result
+ * positive = ADC busy, digital_value contain previous conversion result
+ * negative = Conversion request failed.
+ */
+int gradcdac_adc_convert_try(void *cookie, unsigned short *digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ status = pDev->regs->status;
+
+ if ( digital_value ){
+ *digital_value = pDev->regs->adc_din;
+ }
+
+ if ( gradcdac_ADC_isOngoing(status) )
+ return 1;
+
+ if ( gradcdac_ADC_isCompleted(status) )
+ return 0;
+
+ /* Failure */
+ return -1;
+}
+
+/* Waits until the ADC circuity has finished a digital to analogue
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+int gradcdac_adc_convert(void *cookie, unsigned short *digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ do {
+ status=gradcdac_get_status(pDev);
+ }while ( gradcdac_ADC_isOngoing(status) );
+
+ if ( digital_value )
+ *digital_value = pDev->regs->adc_din;
+
+ if ( gradcdac_ADC_isCompleted(status) )
+ return 0;
+
+ return -1;
+}
+
+/* Try to make the DAC circuitry initialize a digital to analogue
+ * conversion. If the circuitry is busy by a previous conversion
+ * the function return a non-zero value, if the conversion is
+ * successfully initialized the function return zero.
+ */
+int gradcdac_dac_convert_try(void *cookie, unsigned short digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status = pDev->regs->status;
+
+ if ( gradcdac_DAC_isOngoing(status) )
+ return -1;
+
+ /* Force a new conversion */
+ pDev->regs->dac_dout = digital_value;
+
+ /* Return success */
+ return 0;
+}
+
+/* Initializes a digital to analogue conversion by waiting until
+ * previous conversions is finished before proceeding with the
+ * conversion. The Waiting is implemented as a busy loop utilizing
+ * 100% CPU load.
+ */
+void gradcdac_dac_convert(void *cookie, unsigned short digital_value)
+{
+ struct gradcdac_priv *pDev = cookie;
+ unsigned int status;
+
+ do {
+ status = gradcdac_get_status(pDev);
+ }while( gradcdac_DAC_isOngoing(status) );
+
+ pDev->regs->dac_dout = digital_value;
+}
+
+unsigned int gradcdac_get_adrinput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrin;
+}
+
+void gradcdac_set_adrinput(void *cookie, unsigned int input)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrin = input;
+}
+
+unsigned int gradcdac_get_adroutput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrout;
+}
+
+void gradcdac_set_adroutput(void *cookie, unsigned int output)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrout = output;
+}
+
+unsigned int gradcdac_get_adrdir(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->adrdir;
+}
+
+void gradcdac_set_adrdir(void *cookie, unsigned int dir)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->adrdir = dir;
+}
+
+unsigned int gradcdac_get_datainput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_in;
+}
+
+void gradcdac_set_datainput(void *cookie, unsigned int input)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_in = input;
+}
+
+unsigned int gradcdac_get_dataoutput(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_out;
+}
+
+void gradcdac_set_dataoutput(void *cookie, unsigned int output)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_out = output;
+}
+
+unsigned int gradcdac_get_datadir(void *cookie)
+{
+ struct gradcdac_priv *pDev = cookie;
+ return pDev->regs->data_dir;
+}
+
+void gradcdac_set_datadir(void *cookie, unsigned int dir)
+{
+ struct gradcdac_priv *pDev = cookie;
+ pDev->regs->data_dir = dir;
+}