From 0b6190c1c48c0c9f48753ce2390b9cd91bff3a15 Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Sun, 30 Apr 2017 11:11:17 +0200 Subject: [PATCH] drivers/analog: Add basic OPAMP driver --- drivers/analog/Kconfig | 6 + drivers/analog/Make.defs | 17 +++ drivers/analog/opamp.c | 243 +++++++++++++++++++++++++++++++++++ include/nuttx/analog/opamp.h | 109 ++++++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 drivers/analog/opamp.c create mode 100644 include/nuttx/analog/opamp.h diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig index 6727f67c47..64fa435f4d 100644 --- a/drivers/analog/Kconfig +++ b/drivers/analog/Kconfig @@ -141,3 +141,9 @@ config DAC_AD5410 select SPI endif # DAC + +config OPAMP + bool "Operational Amplifier" + default n + ---help--- + Select to enable support for Operational Amplifiers (OPAMPs). diff --git a/drivers/analog/Make.defs b/drivers/analog/Make.defs index 01d5a2fe8e..69d10a638d 100644 --- a/drivers/analog/Make.defs +++ b/drivers/analog/Make.defs @@ -60,6 +60,16 @@ CSRCS += comp.c endif +# Check for OPAMP devices + +ifeq ($(CONFIG_OPAMP),y) + +# Include the common OPAMP character driver + +CSRCS += opamp.c + +endif + # Check for ADC devices ifeq ($(CONFIG_ADC),y) @@ -105,6 +115,13 @@ ifeq ($(CONFIG_COMP),y) DEPPATH += --dep-path analog VPATH += :analog CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} +else +ifeq ($(CONFIG_OPAMP),y) + DEPPATH += --dep-path analog + VPATH += :analog + CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)analog} endif endif endif +endif + diff --git a/drivers/analog/opamp.c b/drivers/analog/opamp.c new file mode 100644 index 0000000000..666b19a8ce --- /dev/null +++ b/drivers/analog/opamp.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * drivers/analog/opamp.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int opamp_open(FAR struct file *filep); +static int opamp_close(FAR struct file *filep); +static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations opamp_fops = +{ + opamp_open, /* open */ + opamp_close, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* seek */ + opamp_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , NULL /* poll */ +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , NULL /* unlink */ +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +/**************************************************************************** + * Name: opamp_open + * + * Description: + * This function is called whenever the OPAMP device is opened. + * + ****************************************************************************/ + +static int opamp_open(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + uint8_t tmp; + int ret = OK; + + /* If the port is the middle of closing, wait until the close is finished */ + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Increment the count of references to the device. If this the first + * time that the driver has been opened for this device, then initialize + * the device. + */ + + tmp = dev->ad_ocount + 1; + if (tmp == 0) + { + /* More than 255 opens; uint8_t overflows to zero */ + + ret = -EMFILE; + } + else + { + /* Check if this is the first time that the driver has been opened. */ + + if (tmp == 1) + { + /* Yes.. perform one time hardware initialization. */ + + irqstate_t flags = enter_critical_section(); + ret = dev->ad_ops->ao_setup(dev); + if (ret == OK) + { + /* Save the new open count on success */ + + dev->ad_ocount = tmp; + } + + leave_critical_section(flags); + } + } + + sem_post(&dev->ad_closesem); + } + + return ret; +} + +/**************************************************************************** + * Name: opamp_close + * + * Description: + * This routine is called when the OPAMP device is closed. + * It waits for the last remaining data to be sent. + * + ****************************************************************************/ + +static int opamp_close(FAR struct file *filep) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + irqstate_t flags; + int ret = OK; + + if (sem_wait(&dev->ad_closesem) != OK) + { + ret = -errno; + } + else + { + /* Decrement the references to the driver. If the reference count will + * decrement to 0, then uninitialize the driver. + */ + + if (dev->ad_ocount > 1) + { + dev->ad_ocount--; + sem_post(&dev->ad_closesem); + } + else + { + /* There are no more references to the port */ + + dev->ad_ocount = 0; + + /* Free the IRQ and disable the OPAMP device */ + + flags = enter_critical_section(); /* Disable interrupts */ + dev->ad_ops->ao_shutdown(dev); /* Disable the OPAMP */ + leave_critical_section(flags); + + sem_post(&dev->ad_closesem); + } + } + + return ret; +} + +/**************************************************************************** + * Name: opamp_ioctl +****************************************************************************/ + +static int opamp_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct opamp_dev_s *dev = inode->i_private; + int ret; + + ret = dev->ad_ops->ao_ioctl(dev, cmd, arg); + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: opamp_register + ****************************************************************************/ + +int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev) +{ + int ret; + + /* Initialize the OPAMP device structure */ + + dev->ad_ocount = 0; + + /* Initialize semaphores */ + + sem_init(&dev->ad_closesem, 0, 1); + + /* Register the OPAMP character driver */ + + ret = register_driver(path, &opamp_fops, 0444, dev); + if (ret < 0) + { + sem_destroy(&dev->ad_closesem); + } + + return ret; +} diff --git a/include/nuttx/analog/opamp.h b/include/nuttx/analog/opamp.h new file mode 100644 index 0000000000..a0f3d55be0 --- /dev/null +++ b/include/nuttx/analog/opamp.h @@ -0,0 +1,109 @@ +/************************************************************************************ + * include/nuttx/analog/opamp.h + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ************************************************************************************/ + +#ifndef __INCLUDE_NUTTX_ANALOG_OPAMP_H +#define __INCLUDE_NUTTX_ANALOG_OPAMP_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +/************************************************************************************ + * Public Types + ************************************************************************************/ + +struct opamp_dev_s; +struct opamp_ops_s +{ + /* Configure the OPAMP. This method is called the first time that the OPAMP + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching OPAMP interrupts. Interrupts + * are all disabled upon return. + */ + + CODE int (*ao_setup)(FAR struct opamp_dev_s *dev); + + /* Disable the OPAMP. This method is called when the OPAMP device is closed. + * This method reverses the operation the setup method. + * Works only if OPAMP device is not locked. + */ + + CODE void (*ao_shutdown)(FAR struct opamp_dev_s *dev); + + /* All ioctl calls will be routed through this method */ + + CODE int (*ao_ioctl)(FAR struct opamp_dev_s *dev, int cmd, unsigned long arg); +}; + +struct opamp_dev_s +{ +#ifdef CONFIG_OPAMP + /* Fields managed by common upper half OPAMP logic */ + + uint8_t ad_ocount; /* The number of times the device has been opened */ + sem_t ad_closesem; /* Locks out new opens while close is in progress */ +#endif + + /* Fields provided by lower half OPAMP logic */ + + FAR const struct opamp_ops_s *ad_ops; /* Arch-specific operations */ + FAR void *ad_priv; /* Used by the arch-specific logic */ +}; + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +int opamp_register(FAR const char *path, FAR struct opamp_dev_s *dev); + +#if defined(__cplusplus) +} +#endif + +#endif /* __INCLUDE_NUTTX_ANALOG_OPAMP_H */