summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/shared/analog
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2015-02-23 13:02:39 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:17 +0200
commit3bb41226e0941b86d58ecb97f7d292677de573c8 (patch)
tree907aa270343f7c6d1bc08bf73288fb9b10da6197 /c/src/lib/libbsp/sparc/shared/analog
parentLEON: added network device configuration helper function (diff)
downloadrtems-3bb41226e0941b86d58ecb97f7d292677de573c8.tar.bz2
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
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/analog')
-rw-r--r--c/src/lib/libbsp/sparc/shared/analog/gradcdac.c578
1 files changed, 578 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
new file mode 100644
index 0000000000..4b8e636666
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/analog/gradcdac.c
@@ -0,0 +1,578 @@
+/* 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.com/license/LICENSE.
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <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 <debug_defs.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 = malloc(sizeof(struct gradcdac_priv));
+ if ( !priv )
+ return DRVMGR_NOMEM;
+ memset(priv, 0, sizeof(*priv));
+ 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;
+}
+
+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;
+ }
+}
+
+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;
+}