diff --git a/drivers/analog/Kconfig b/drivers/analog/Kconfig index a535c22d75..87a434c4a1 100644 --- a/drivers/analog/Kconfig +++ b/drivers/analog/Kconfig @@ -126,6 +126,7 @@ config PGA11X_MULTIPLE devid=SPIDEV_MUX(n). endif # if ADC_PGA11X + endif # ADC config COMP @@ -162,7 +163,19 @@ config DAC7571_I2C_FREQUENCY endif # DAC config OPAMP - bool "Operational Amplifier" - default n - ---help--- + bool "Operational Amplifier" + default n + ---help--- Select to enable support for Operational Amplifiers (OPAMPs). + +config LMP92001 + bool "LMP92001 support" + default n + select I2C + ---help--- + Enable driver support for the Texas Instruments LMP92001. + +config LMP92001_I2C_FREQUENCY + int "LMP92001 I2C frequency" + default 400000 + depends on LMP92001 diff --git a/drivers/analog/Make.defs b/drivers/analog/Make.defs index 8450fe0faf..09fb9f64b8 100644 --- a/drivers/analog/Make.defs +++ b/drivers/analog/Make.defs @@ -52,6 +52,7 @@ endif ifeq ($(CONFIG_DAC7571),y) CSRCS += dac7571.c endif + endif # Check for COMP devices @@ -103,6 +104,10 @@ ifeq ($(CONFIG_ADC_LTC1867L),y) endif endif +ifeq ($(CONFIG_LMP92001),y) + CSRCS += lmp92001.c +endif + # Add analog driver build support (the nested if-then-else implements an OR) ifeq ($(CONFIG_DAC),y) diff --git a/drivers/analog/dac.c b/drivers/analog/dac.c index bfc2468463..495095c73c 100644 --- a/drivers/analog/dac.c +++ b/drivers/analog/dac.c @@ -283,7 +283,7 @@ static ssize_t dac_write(FAR struct file *filep, FAR const char *buffer, size_t int msglen; int ret = 0; - /* Interrupts must disabled throughout the following */ + /* Interrupts must be disabled throughout the following */ flags = enter_critical_section(); @@ -381,7 +381,7 @@ static ssize_t dac_write(FAR struct file *filep, FAR const char *buffer, size_t } /* We get here if there is space at the end of the FIFO. Add the new - * CAN message at the tail of the FIFO. + * DAC message at the tail of the FIFO. */ if (msglen == 5) diff --git a/drivers/analog/lmp92001.c b/drivers/analog/lmp92001.c new file mode 100644 index 0000000000..a96bbc1e20 --- /dev/null +++ b/drivers/analog/lmp92001.c @@ -0,0 +1,1562 @@ +/**************************************************************************** + * drivers/analog/lmp92001.c + * + * Copyright (C) 2018 Abdelatif Guettouche. All rights reserved. + * Author: Abdelatif Guettouche + * + * This file is a part of NuttX: + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * + * 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 + +#include + +/**************************************************************************** + * Preprocessor definitions + ****************************************************************************/ + +#if !defined(CONFIG_I2C) +# error I2C Support Required. +#endif + +#if defined(CONFIG_LMP92001) + +#define LMP92001_REG_TEST 0x01U + +#define LMP92001_REG_ID 0x0EU +#define LMP92001_REG_VER 0x0FU + +#define LMP92001_REG_SGEN 0x10U +#define LMP92001_REG_SGPI 0x11U +#define LMP92001_REG_SHIL 0x12U +#define LMP92001_REG_SLOL 0x13U + +#define LMP92001_REG_CGEN 0x14U +#define LMP92001_REG_CDAC 0x15U +#define LMP92001_REG_CGPO 0x16U +#define LMP92001_REG_CINH 0x17U +#define LMP92001_REG_CINL 0x18U +#define LMP92001_REG_CAD1 0x19U +#define LMP92001_REG_CAD2 0x1AU +#define LMP92001_REG_CAD3 0x1BU +#define LMP92001_REG_CTRIG 0x1CU + +#define LMP92001_REG_ADC1 0x20U +#define LMP92001_REG_ADC2 0x21U +#define LMP92001_REG_ADC3 0x22U +#define LMP92001_REG_ADC4 0x23U +#define LMP92001_REG_ADC5 0x24U +#define LMP92001_REG_ADC6 0x25U +#define LMP92001_REG_ADC7 0x26U +#define LMP92001_REG_ADC8 0x27U +#define LMP92001_REG_ADC9 0x28U +#define LMP92001_REG_ADC10 0x29U +#define LMP92001_REG_ADC11 0x2AU +#define LMP92001_REG_ADC12 0x2BU +#define LMP92001_REG_ADC13 0x2CU +#define LMP92001_REG_ADC14 0x2DU +#define LMP92001_REG_ADC15 0x2EU +#define LMP92001_REG_ADC16 0x2FU +#define LMP92001_REG_ADC17 0x30U + +#define LMP92001_REG_LIH1 0x40U +#define LMP92001_REG_LIH2 0x41U +#define LMP92001_REG_LIH3 0x42U +#define LMP92001_REG_LIH9 0x43U +#define LMP92001_REG_LIH10 0x44U +#define LMP92001_REG_LIH11 0x45U +#define LMP92001_REG_LIL1 0x46U +#define LMP92001_REG_LIL2 0x47U +#define LMP92001_REG_LIL3 0x48U +#define LMP92001_REG_LIL9 0x49U +#define LMP92001_REG_LIL10 0x4AU +#define LMP92001_REG_LIL11 0x4BU + +#define LMP92001_REG_CREF 0x66U + +#define LMP92001_REG_DAC1 0x80U +#define LMP92001_REG_DAC2 0x81U +#define LMP92001_REG_DAC3 0x82U +#define LMP92001_REG_DAC4 0x83U +#define LMP92001_REG_DAC5 0x84U +#define LMP92001_REG_DAC6 0x85U +#define LMP92001_REG_DAC7 0x86U +#define LMP92001_REG_DAC8 0x87U +#define LMP92001_REG_DAC9 0x88U +#define LMP92001_REG_DAC10 0x89U +#define LMP92001_REG_DAC11 0x8AU +#define LMP92001_REG_DAC12 0x8BU + +#define LMP92001_REG_DALL 0x90U + +#define LMP92001_REG_BLK0 0xF0U +#define LMP92001_REG_BLK1 0xF1U +#define LMP92001_REG_BLK2 0xF2U +#define LMP92001_REG_BLK3 0xF3U +#define LMP92001_REG_BLK4 0xF4U +#define LMP92001_REG_BLK5 0xF5U + +#define LMP92001_SGEN_BUSY (1 << 7U) +#define LMP92001_SGEN_RDYN (1 << 6U) +#define LMP92001_SGEN_HV (1 << 2U) +#define LMP92001_SGEN_LV (1 << 1U) +#define LMP92001_SGEN_GPI (1 << 0U) + +#define LMP92001_SGPI_GPI7 (1 << 7U) +#define LMP92001_SGPI_GPI6 (1 << 6U) +#define LMP92001_SGPI_GPI5 (1 << 5U) +#define LMP92001_SGPI_GPI4 (1 << 4U) +#define LMP92001_SGPI_GPI3 (1 << 3U) +#define LMP92001_SGPI_GPI2 (1 << 2U) +#define LMP92001_SGPI_GPI1 (1 << 1U) +#define LMP92001_SGPI_GPI0 (1 << 0U) + +#define LMP92001_CGEN_RST (1 << 7U) +#define LMP92001_CGEN_TOD (1 << 2U) +#define LMP92001_CGEN_LCK (1 << 1U) +#define LMP92001_CGEN_STRT (1 << 0U) + +#define LMP92001_CDAC_GANG (1 << 2U) +#define LMP92001_CDAC_OLVL (1 << 1U) +#define LMP92001_CDAC_OFF (1 << 0U) +#define LMP92001_CDAC_ON (0U) + +#define LMP92001_CGPO_GPO7 (1 << 7U) +#define LMP92001_CGPO_GPO6 (1 << 6U) +#define LMP92001_CGPO_GPO5 (1 << 5U) +#define LMP92001_CGPO_GPO4 (1 << 4U) +#define LMP92001_CGPO_GPO3 (1 << 3U) +#define LMP92001_CGPO_GPO2 (1 << 2U) +#define LMP92001_CGPO_GPO1 (1 << 1U) +#define LMP92001_CGPO_GPO0 (1 << 0U) + +#define LMP92001_CTRIG_SNGL (1 << 0U) + +#define LMP92001_CREF_AEXT (1 << 2U) +#define LMP92001_CREF_DEXT (1 << 1U) + +#define LMP92001_ADC_MAX_CHANNELS 17U +#define LMP92001_DAC_MAX_CHANNELS 12U +#define LMP92001_GPIO_MAX_PINS 8U + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct lmp92001_dev_s +{ + FAR struct i2c_master_s *i2c; /* I2C interface */ + uint8_t addr; /* I2C address */ + +#ifdef CONFIG_ADC + FAR const struct adc_callback_s *cb; + uint8_t adc_channels_enabled; + uint8_t adc_channels[LMP92001_ADC_MAX_CHANNELS]; +#endif + +#ifdef CONFIG_IOEXPANDER + struct ioexpander_dev_s gpio_dev; +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* LMP92001 Helpers. */ + +static int lmp92001_i2c_write(FAR struct lmp92001_dev_s *priv, + FAR const uint8_t *buffer, int buflen); +static int lmp92001_i2c_read(FAR struct lmp92001_dev_s *priv, + uint8_t reg, FAR uint8_t *buffer, int buflen); + +static int lmp92001_dac_setref(FAR struct lmp92001_dev_s *priv, + enum lmp92001_ref_e ref); +static int lmp92001_dac_updateall(FAR struct lmp92001_dev_s *priv, + uint16_t value); + +static int lmp92001_adc_setref(FAR struct lmp92001_dev_s *priv, + enum lmp92001_ref_e ref); +static void lmp92001_adc_extractchannel(FAR struct lmp92001_dev_s *priv, + enum lmp92001_adc_enable_e channels); +static int lmp92001_adc_enablechannel(FAR struct lmp92001_dev_s *priv, + enum lmp92001_adc_enable_e channels); +static int lmp92001_adc_singleshot(FAR struct lmp92001_dev_s *priv); +static int lmp92001_adc_continuousconv(FAR struct lmp92001_dev_s *priv); +static int lmp92001_adc_readchannel(FAR struct lmp92001_dev_s *priv, + FAR struct adc_msg_s *msg); + +/* DAC Interface. */ + +#ifdef CONFIG_DAC +static void lmp92001_dac_reset(FAR struct dac_dev_s *dev); +static int lmp92001_dac_setup(FAR struct dac_dev_s *dev); +static void lmp92001_dac_shutdown(FAR struct dac_dev_s *dev); +static void lmp92001_dac_txint(FAR struct dac_dev_s *dev, bool enable); +static int lmp92001_dac_send(FAR struct dac_dev_s *dev, + FAR struct dac_msg_s *msg); +static int lmp92001_dac_ioctl(FAR struct dac_dev_s *dev, int cmd, + unsigned long arg); +#endif + +/* ADC Interface. */ + +#ifdef CONFIG_ADC +static int lmp92001_adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback); +static void lmp92001_adc_reset(FAR struct adc_dev_s *dev); +static int lmp92001_adc_setup(FAR struct adc_dev_s *dev); +static void lmp92001_adc_shutdown(FAR struct adc_dev_s *dev); +static void lmp92001_adc_rxint(FAR struct adc_dev_s *dev, bool enable); +static int lmp92001_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, + unsigned long arg); +#endif + +/* I/O Expander Interface. */ + +#ifdef CONFIG_IOEXPANDER +static int lmp92001_gpio_direction(FAR struct ioexpander_dev_s *dev, + uint8_t pin, int dir); +static int lmp92001_gpio_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int opt, void *regval); +static int lmp92001_gpio_writepin(FAR struct ioexpander_dev_s *dev, + uint8_t pin, bool value); +static int lmp92001_gpio_readpin(FAR struct ioexpander_dev_s *dev, + uint8_t pin, FAR bool *value); +#ifdef CONFIG_IOEXPANDER_MULTIPIN +static int lmp92001_gpio_multiwritepin(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count); +static int lmp92001_gpio_multireadpin(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count); +#endif +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +static FAR void *lmp92001_gpio_attach(FAR struct ioexpander_dev_s *dev, + ioe_pinset_t pinset, + ioe_callback_t callback, FAR void *arg); +static int lmp92001_gpio_detach(FAR struct ioexpander_dev_s *dev, + FAR void *handle); +#endif +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct lmp92001_dev_s g_devpriv; + +#ifdef CONFIG_DAC +static const struct dac_ops_s g_dacops = +{ + .ao_reset = lmp92001_dac_reset, + .ao_setup = lmp92001_dac_setup, + .ao_shutdown = lmp92001_dac_shutdown, + .ao_txint = lmp92001_dac_txint, + .ao_send = lmp92001_dac_send, + .ao_ioctl = lmp92001_dac_ioctl, +}; + +static struct dac_dev_s g_dacdev = +{ + .ad_ops = &g_dacops, + .ad_priv = &g_devpriv, +}; +#endif + +#ifdef CONFIG_ADC +static const struct adc_ops_s g_adcops = +{ + .ao_bind = lmp92001_adc_bind, + .ao_reset = lmp92001_adc_reset, + .ao_setup = lmp92001_adc_setup, + .ao_shutdown = lmp92001_adc_shutdown, + .ao_rxint = lmp92001_adc_rxint, + .ao_ioctl = lmp92001_adc_ioctl +}; + +static struct adc_dev_s g_adcdev = +{ + .ad_ops = &g_adcops, + .ad_priv = &g_devpriv, +}; +#endif + +#ifdef CONFIG_IOEXPANDER +static const struct ioexpander_ops_s g_gpio_ops = +{ + lmp92001_gpio_direction, + lmp92001_gpio_option, + lmp92001_gpio_writepin, + lmp92001_gpio_readpin, + lmp92001_gpio_readpin +#ifdef CONFIG_IOEXPANDER_MULTIPIN + , lmp92001_gpio_multiwritepin + , lmp92001_gpio_multireadpin + , lmp92001_gpio_multireadpin +#endif +#ifdef CONFIG_IOEXPANDER_INT_ENABLE + , lmp92001_gpio_attach + , lmp92001_gpio_detach +#endif +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lmp92001_i2c_write + * + * Description: + * Transmits a buffer. + * + ****************************************************************************/ + +static int lmp92001_i2c_write(FAR struct lmp92001_dev_s *priv, + FAR const uint8_t *buffer, int buflen) +{ + struct i2c_msg_s msg; + int ret; + + /* Setup for the transfer */ + + msg.frequency = CONFIG_LMP92001_I2C_FREQUENCY, + msg.addr = priv->addr; + msg.flags = 0; + msg.buffer = (FAR uint8_t *)buffer; /* Override const */ + msg.length = buflen; + + /* Then perform the transfer. */ + + ret = I2C_TRANSFER(priv->i2c, &msg, 1); + if (ret < 0) + { + aerr("LMP92001 I2C transfer failed: %d", ret); + return ret; + } + + return (ret >= 0) ? OK : ret; +} + +/**************************************************************************** + * Name: lmp92001_i2c_read + * + * Description: + * Reads a buffer. + * + ****************************************************************************/ + +static int lmp92001_i2c_read(FAR struct lmp92001_dev_s *priv, + uint8_t reg, FAR uint8_t *buffer, int buflen) +{ + struct i2c_msg_s msg[2]; + int ret; + + /* Setup for the transfer */ + + msg[0].frequency = CONFIG_LMP92001_I2C_FREQUENCY, + msg[0].addr = priv->addr, + msg[0].flags = I2C_M_NOSTOP; + msg[0].buffer = ® + msg[0].length = 1; + + msg[1].frequency = CONFIG_LMP92001_I2C_FREQUENCY, + msg[1].addr = priv->addr, + msg[1].flags = I2C_M_READ; + msg[1].buffer = buffer; + msg[1].length = buflen; + + /* Then perform the transfer. */ + + ret = I2C_TRANSFER(priv->i2c, msg, 2); + if (ret < 0) + { + aerr("LMP92001 I2C transfer failed: %d", ret); + return ret; + } + + return (ret >= 0) ? OK : ret; +} + +/**************************************************************************** + * Name: lmp92001_dac_setref + * + * Description: + * Sets the DACs reference (internal or external). + * + ****************************************************************************/ + +static int lmp92001_dac_setref(FAR struct lmp92001_dev_s *priv, + enum lmp92001_ref_e ref) +{ + uint8_t value = 0; + + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret = OK; + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CREF, &value, 1); + if (ret < 0) + { + aerr("LMP92001 DAC set reference failed: %d", ret); + return ret; + } + + if (ref == LMP92001_REF_EXTERNAL) + { + value |= LMP92001_CREF_DEXT; + } + else + { + value &= ~LMP92001_CREF_DEXT; + } + + buffer[0] = LMP92001_REG_CREF; + buffer[1] = value; + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 DAC set reference failed: %d", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_dac_updateall + * + * Description: + * Write to all DACx registers simultaneously. + * + ****************************************************************************/ + +static int lmp92001_dac_updateall(FAR struct lmp92001_dev_s *priv, + uint16_t value) +{ + uint8_t const BUFFER_SIZE = 3U; + uint8_t buffer[BUFFER_SIZE]; + + int ret = OK; + + buffer[0] = LMP92001_REG_DALL; + buffer[1] = (uint8_t)(value >> 8U); + buffer[2] = (uint8_t)(value & 0xFFU); + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 DAC update all failed: %d", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_dac_reset + * + * Description: + * Reset the DAC device. Called early to initialize the hardware. This + * is called, before ao_setup() and on error conditions. + * + ****************************************************************************/ + +#ifdef CONFIG_DAC +static void lmp92001_dac_reset(FAR struct dac_dev_s *dev) +{ +} + +/**************************************************************************** + * Name: lmp92001_dac_setup + * + * Description: + * Configure the DAC. This method is called the first time that the DAC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching DAC interrupts. Interrupts + * are all disabled upon return. + * + ****************************************************************************/ + +static int lmp92001_dac_setup(FAR struct dac_dev_s *dev) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev->ad_priv; + + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret = OK; + + /* Enable DAC channels. */ + + buffer[0] = LMP92001_REG_CDAC; + buffer[1] = LMP92001_CDAC_ON; + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 DAC setup failed: %d", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_dac_shutdown + * + * Description: + * Disable the DAC. This method is called when the DAC device is closed. + * This method reverses the operation the setup method. + * + ****************************************************************************/ + +static void lmp92001_dac_shutdown(FAR struct dac_dev_s *dev) +{ +} + +/**************************************************************************** + * Name: lmp92001_dac_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void lmp92001_dac_txint(FAR struct dac_dev_s *dev, bool enable) +{ +} + +/**************************************************************************** + * Name: lmp92001_dac_send + * + * Description: + * This method will send one message on the DAC. + * + ****************************************************************************/ + +static int lmp92001_dac_send(FAR struct dac_dev_s *dev, + FAR struct dac_msg_s *msg) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev->ad_priv; + + uint8_t const BUFFER_SIZE = 3U; + uint8_t buffer[BUFFER_SIZE]; + + int ret; + + /* Sanity check */ + + DEBUGASSERT(priv->i2c != NULL); + + ainfo("Channel: %d - Value: %08x\n", msg->am_channel, msg->am_data); + + /* Set up the message to send. + * We follow the same conventions as the datasheet. + * ie. channels number start from 1 not from zero. + */ + + buffer[0] = (msg->am_channel - 1) + LMP92001_REG_DAC1; + buffer[1] = (uint8_t)(msg->am_data >> 8U); + buffer[2] = (uint8_t)(msg->am_data & 0xFFU); + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 DAC send failed: %d", ret); + return ret; + } + + dac_txdone(&g_dacdev); + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_dac_ioctl + * + * Description: + * All ioctl calls will be routed through this method. + * + ****************************************************************************/ + +static int lmp92001_dac_ioctl(FAR struct dac_dev_s *dev, int cmd, + unsigned long arg) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev->ad_priv; + int ret = OK; + + switch (cmd) + { + case ANIOC_LMP92001_DAC_SET_REF: + { + ret = lmp92001_dac_setref(priv, (enum lmp92001_ref_e)(arg)); + } + break; + + case ANIOC_LMP92001_DAC_UPDATEALL: + { + ret = lmp92001_dac_updateall(priv, (uint16_t)(arg)); + } + break; + + /* Command was not recognized */ + + default: + aerr("LMP92001 ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_DAC */ + +/**************************************************************************** + * Name: lmp92001_adc_setref + * + * Description: + * Sets the ADCs reference (internal or external). + * + ****************************************************************************/ + +static int lmp92001_adc_setref(FAR struct lmp92001_dev_s *priv, + enum lmp92001_ref_e ref) +{ + uint8_t value = 0; + + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret = OK; + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CREF, &value, 1); + if (ret < 0) + { + aerr("LMP92001 ADC set reference failed: %d", ret); + return ret; + } + + if (ref == LMP92001_REF_EXTERNAL) + { + value |= LMP92001_CREF_AEXT; + } + else + { + value &= ~LMP92001_CREF_AEXT; + } + + buffer[0] = LMP92001_REG_CREF; + buffer[1] = value; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC set reference failed: %d", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_adc_extractchannel + * + * Description: + * Extract channels from the enum. + * + ****************************************************************************/ + +static void lmp92001_adc_extractchannel(FAR struct lmp92001_dev_s *priv, + enum lmp92001_adc_enable_e channels) +{ + uint8_t i; + uint8_t j; + uint16_t tmp; + + i = 0U; + j = priv->adc_channels_enabled; + tmp = channels; + + /* Channels to be enabled are the bits set in the argument channels. */ + + while (tmp != 0U) + { + if (tmp & 1U) + { + priv->adc_channels_enabled++; + priv->adc_channels[j] = i + 1; + + ainfo("Channel %d to be enabled\n", priv->adc_channels[j]); + + j++; + } + + tmp >>= 1U; + i++; + } + + ainfo("Number of channels to be enabled: %d\n", + priv->adc_channels_enabled); +} + +/**************************************************************************** + * Name: lmp92001_adc_enablechannel + * + * Description: + * Enables the given ADC channels. + * + ****************************************************************************/ + +static int lmp92001_adc_enablechannel(FAR struct lmp92001_dev_s *priv, + enum lmp92001_adc_enable_e channels) +{ + uint8_t cad1 = 0U; + uint8_t cad2 = 0U; + uint8_t cad3 = 0U; + + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret = OK; + + if (priv->adc_channels_enabled < LMP92001_ADC_MAX_CHANNELS && channels != 0) + { + lmp92001_adc_extractchannel(priv, channels); + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CAD1, &cad1, 1); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CAD2, &cad2, 1); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CAD3, &cad3, 1); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + + cad1 |= channels & 0x000FFU; + cad2 |= (channels >> 8U) & 0x000FFU; + cad3 |= (channels >> 16U) & 0x1U; + + if (cad1 > 0) + { + buffer[0] = LMP92001_REG_CAD1; + buffer[1] = cad1; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + } + + if (cad2 > 0) + { + buffer[0] = LMP92001_REG_CAD2; + buffer[1] = cad2; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + } + + if (cad3 > 0) + { + buffer[0] = LMP92001_REG_CAD3; + buffer[1] = cad3; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC enable channel failed %d\n", ret); + return ret; + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_adc_singleshot + * + * Description: + * Starts a single shot conversion. + * + ****************************************************************************/ + +static int lmp92001_adc_singleshot(FAR struct lmp92001_dev_s *priv) +{ + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + uint8_t sgen_value = 0; + + int ret = OK; + + /* Lock registers, this will also force CGEN.STRT to 0. */ + + buffer[0] = LMP92001_REG_CGEN; + buffer[1] = LMP92001_CGEN_LCK; + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC Single shot failed %d\n", ret); + return ret; + } + + /* Trigger a single shot conversion. */ + + buffer[0] = LMP92001_REG_CTRIG; + buffer[1] = LMP92001_CTRIG_SNGL; + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC Single shot failed %d\n", ret); + return ret; + } + + /* Wait for the BUSY flag. */ + + do + { + lmp92001_i2c_read(priv, LMP92001_REG_SGEN, &sgen_value, 1); + } + while ((sgen_value & LMP92001_SGEN_BUSY) != 0); + + /* Unlock registers. + * It's not needed to read the registers first and verify if some + * bits were set. All the other bits should already be cleared. + */ + + buffer[0] = LMP92001_REG_CGEN; + buffer[1] = 0; + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC Single shot failed %d\n", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_adc_continuousconv + * + * Description: + * Starts the continuous conversion. + * + ****************************************************************************/ + +static int lmp92001_adc_continuousconv(FAR struct lmp92001_dev_s *priv) +{ + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + uint8_t sgen_value = 0U; + + int ret = OK; + + /* Set CGEN.STRT bit and lock registers */ + + buffer[0] = LMP92001_REG_CGEN; + buffer[1] = LMP92001_CGEN_STRT | LMP92001_CGEN_LCK; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC Continuous conversion failed %d\n", ret); + return ret; + } + + /* Wait for the BUSY flag. */ + + do + { + lmp92001_i2c_read(priv, LMP92001_REG_SGEN, &sgen_value, 1); + } + while ((sgen_value & LMP92001_SGEN_BUSY) != 0); + + /* Unlock the registers and keep STRT set. */ + + buffer[0] = LMP92001_REG_CGEN; + buffer[1] = LMP92001_CGEN_STRT; + buffer[1] &= ~LMP92001_CGEN_LCK; + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + aerr("LMP92001 ADC Continuous conversion failed %d\n", ret); + return ret; + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_adc_readchannel + * + * Description: + * Read from an ADC channel. + * + ****************************************************************************/ + +static int lmp92001_adc_readchannel(FAR struct lmp92001_dev_s *priv, + FAR struct adc_msg_s *msg) +{ + uint8_t buffer[2]; + uint8_t channel; + + int ret = OK; + + /* Adding LMP92001_REG_ADC1 to a channel gives the channel's register. + * Reminder: Channels numbering is the same as the datasheet. + * First channel is called Channel1. + * Note: ADC registers are 16-bit wide. + */ + + channel = LMP92001_REG_ADC1 + msg->am_channel - 1; + + ret = lmp92001_i2c_read(priv, channel, buffer, 2); + if (ret < 0) + { + aerr("LMP92001 ADC read failed: %d\n", ret); + return ret; + } + + msg->am_data = (buffer[0] << 8U) | buffer[1]; + + return ret; +} + +#ifdef CONFIG_ADC +/**************************************************************************** + * Name: lmp92001_adc_bind + * + * Description: + * Bind the upper-half driver callbacks to the lower-half implementation. + * This must be called early in order to receive ADC event notifications. + * + ****************************************************************************/ + +static int lmp92001_adc_bind(FAR struct adc_dev_s *dev, + FAR const struct adc_callback_s *callback) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev->ad_priv; + + DEBUGASSERT(priv != NULL); + + priv->cb = callback; + + return OK; +} + +/**************************************************************************** + * Name: lmp92001_adc_reset + * + * Description: + * Reset the ADC device. Called early to initialize the hardware. This + * is called, before ao_setup() and on error conditions. + * + ****************************************************************************/ + +static void lmp92001_adc_reset(FAR struct adc_dev_s *dev) +{ + FAR struct lmp92001_dev_s *priv = + (FAR struct lmp92001_dev_s *)dev->ad_priv; + + priv->adc_channels_enabled = 0; +} + +/**************************************************************************** + * Name: lmp92001_adc_setup + * + * Description: + * Configure the ADC. This method is called the first time that the ADC + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching ADC interrupts. + * Interrupts are all disabled upon return. + * + ****************************************************************************/ + +static int lmp92001_adc_setup(FAR struct adc_dev_s *dev) +{ + return OK; +} + +/**************************************************************************** + * Name: lmp92001_adc_shutdown + * + * Description: + * Disable the ADC. This method is called when the ADC device is closed. + * This method reverses the operation the setup method. + * + ****************************************************************************/ + +static void lmp92001_adc_shutdown(FAR struct adc_dev_s *dev) +{ +} + +/**************************************************************************** + * Name: lmp92001_adc_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void lmp92001_adc_rxint(FAR struct adc_dev_s *dev, bool enable) +{ +} + +/**************************************************************************** + * Name: lmp92001_adc_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int lmp92001_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, + unsigned long arg) +{ + FAR struct lmp92001_dev_s *priv = + (FAR struct lmp92001_dev_s *)dev->ad_priv; + int ret = OK; + + switch (cmd) + { + case ANIOC_LMP92001_ADC_ENABLE: + { + ret = lmp92001_adc_enablechannel(priv, + (enum lmp92001_adc_enable_e)arg); + } + break; + + case ANIOC_LMP92001_ADC_SET_REF: + { + ret = lmp92001_adc_setref(priv, (enum lmp92001_ref_e)(arg)); + } + break; + + case ANIOC_TRIGGER: + case ANIOC_LMP92001_ADC_SINGLESHOT_CONV: + { + struct adc_msg_s msg; + + int i; + + ret = lmp92001_adc_singleshot(priv); + if (ret < 0) + { + break; + } + + for (i = 0; i < priv->adc_channels_enabled; i++) + { + msg.am_channel = priv->adc_channels[i]; + + ret = lmp92001_adc_readchannel(priv, &msg); + + priv->cb->au_receive(&g_adcdev, priv->adc_channels[i], + msg.am_data); + } + } + break; + + case ANIOC_LMP92001_ADC_READ_CHANNEL: + { + FAR struct adc_msg_s *msg = + (FAR struct adc_msg_s *)((uintptr_t)arg); + + ret = lmp92001_adc_singleshot(priv); + if (ret < 0) + { + break; + } + + ret = lmp92001_adc_readchannel(priv, msg); + } + break; + + case ANIOC_LMP92001_ADC_CONTINUOUS_CONV: + { + struct adc_msg_s msg; + + int i; + + ret = lmp92001_adc_continuousconv(priv); + if (ret < 0) + { + break; + } + + for (i = 0; i < priv->adc_channels_enabled; i++) + { + msg.am_channel = priv->adc_channels[i]; + + ret = lmp92001_adc_readchannel(priv, &msg); + + priv->cb->au_receive(&g_adcdev, priv->adc_channels[i], + msg.am_data); + } + } + break; + + /* Command was not recognized */ + + default: + aerr("LMP92001 ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_ADC */ + +/**************************************************************************** + * Name: lmp92001_gpio_direction + * + * Description: + * Set the direction of an ioexpander pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * dir - One of the IOEXPANDER_DIRECTION_ macros + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#ifdef CONFIG_IOEXPANDER +static int lmp92001_gpio_direction(FAR struct ioexpander_dev_s *dev, + uint8_t pin, int direction) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev; + + uint8_t regval; + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret; + + DEBUGASSERT(priv != NULL && pin < LMP92001_GPIO_MAX_PINS && + (direction == IOEXPANDER_DIRECTION_IN || + direction == IOEXPANDER_DIRECTION_OUT)); + + gpioinfo("I2C addr=%02x pin=%u direction=%s\n", + priv->addr, pin, + (direction == IOEXPANDER_DIRECTION_IN) ? "IN" : "OUT"); + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CGPO, ®val, 1); + if (ret < 0) + { + gpioerr("LMP92001 GPIO set direction failed: %d\n", ret); + return ret; + } + + buffer[0] = LMP92001_REG_CGPO; + if (direction == IOEXPANDER_DIRECTION_IN) + { + buffer[1] = regval | (1 << pin); + } + else + { + buffer[1] = regval & ~(1 << pin); + } + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + gpioerr("LMP92001 GPIO set direction failed: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_gpio_option + * + * Description: + * Set pin options. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * opt - One of the IOEXPANDER_OPTION_ macros + * val - The option's value + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int lmp92001_gpio_option(FAR struct ioexpander_dev_s *dev, uint8_t pin, + int opt, void *regval) +{ + return OK; +} + +/**************************************************************************** + * Name: lmp92001_gpio_writepin + * + * Description: + * Set the pin level. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin to alter in this call + * val - The pin level. Usually TRUE will set the pin high, + * except if OPTION_INVERT has been set on this pin. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int lmp92001_gpio_writepin(FAR struct ioexpander_dev_s *dev, + uint8_t pin, bool value) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev; + + uint8_t regval; + uint8_t const BUFFER_SIZE = 2U; + uint8_t buffer[BUFFER_SIZE]; + + int ret; + + ret = lmp92001_i2c_read(priv, LMP92001_REG_CGPO, ®val, 1); + if (ret < 0) + { + gpioerr("LMP92001 GPIO write pin failed: %d\n", ret); + return ret; + } + + buffer[0] = LMP92001_REG_CGPO; + + if (value) + { + buffer[1] = regval | (1 << pin); + } + else + { + buffer[1] = regval & ~(value << pin); + } + + ret = lmp92001_i2c_write(priv, buffer, BUFFER_SIZE); + if (ret < 0) + { + gpioerr("LMP92001 GPIO write pin failed: %d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: lmp92001_gpio_readpin + * + * Description: + * Read the actual PIN level. This can be different from the last value + * written to this pin. Required. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The index of the pin + * value - Pointer to a buffer where the pin level is stored. Usually TRUE + * if the pin is high. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int lmp92001_gpio_readpin(FAR struct ioexpander_dev_s *dev, + uint8_t pin, FAR bool *value) +{ + FAR struct lmp92001_dev_s *priv = (FAR struct lmp92001_dev_s *)dev; + + uint8_t regval; + + int ret; + + DEBUGASSERT(priv != NULL && pin < LMP92001_GPIO_MAX_PINS && + value != NULL); + + gpioinfo("I2C addr=%02x, pin=%u\n", priv->addr, pin); + + ret = lmp92001_i2c_read(priv, LMP92001_REG_SGPI, ®val, 1); + if (ret < 0) + { + gpioerr("LMP92001 GPIO read pin failed: %d\n", ret); + return ret; + } + + *value = (bool)(regval >> pin) & 1U; + + return ret; + +} + +/**************************************************************************** + * Name: lmp92001_gpio_multiwritepin + * + * Description: + * Set the pin level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pins - The list of pin indexes to alter in this call + * val - The list of pin levels. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +#ifdef CONFIG_IOEXPANDER_MULTIPIN +static int lmp92001_gpio_multiwritepin(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count) +{ +} + +/**************************************************************************** + * Name: lmp92001_gpio_multireadpin + * + * Description: + * Read the actual level for multiple pins. This routine may be faster than + * individual pin accesses. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * pin - The list of pin indexes to read + * values - Pointer to a buffer where the pin levels are stored. + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int lmp92001_gpio_multireadpin(FAR struct ioexpander_dev_s *dev, + FAR uint8_t *pins, FAR bool *values, + int count) +{ +} +#endif + +/**************************************************************************** + * Name: lmp92001_gpio_attach + * + * Description: + * Attach and enable a pin interrupt callback function. + * + * Input Parameters: + * dev - Device-specific state data + * pinset - The set of pin events that will generate the callback + * callback - The pointer to callback function. NULL will detach the + * callback. + * arg - User-provided callback argument + * + * Returned Value: + * A non-NULL handle value is returned on success. This handle may be + * used later to detach and disable the pin interrupt. + * + ****************************************************************************/ + +#ifdef CONFIG_IOEXPANDER_INT_ENABLE +static FAR void *lmp92001_gpio_attach(FAR struct ioexpander_dev_s *dev, + ioe_pinset_t pinset, + ioe_callback_t callback, FAR void *arg) +{ +} + +/**************************************************************************** + * Name: lmp92001_gpio_detach + * + * Description: + * Detach and disable a pin interrupt callback function. + * + * Input Parameters: + * dev - Device-specific state data + * handle - The non-NULL opaque value return by lmp92001_gpio_attach() + * + * Returned Value: + * 0 on success, else a negative error code + * + ****************************************************************************/ + +static int lmp92001_gpio_detach(FAR struct ioexpander_dev_s *dev, + FAR void *handle) +{ +} +#endif +#endif /* CONFIG_IOEXPANDER */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lmp92001_dac_initialize + * + * Description: + * Initialize DAC + * + * Input Parameters: + * I2C Port number + * Device address + * + * Returned Value: + * Valid LMP92001 device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#ifdef CONFIG_DAC +FAR struct dac_dev_s *lmp92001_dac_initialize(FAR struct i2c_master_s *i2c, + uint8_t addr) +{ + FAR struct lmp92001_dev_s *priv; + + /* Sanity check */ + + DEBUGASSERT(i2c != NULL); + + /* Initialize the LMP92001 device structure */ + + priv = (FAR struct lmp92001_dev_s *)g_dacdev.ad_priv; + priv->i2c = i2c; + priv->addr = addr; + + return &g_dacdev; +} +#endif + +/**************************************************************************** + * Name: lmp92001_adc_initialize + * + * Description: + * Initialize ADC + * + * Input Parameters: + * I2C Port number + * Device address + * + * Returned Value: + * Valid LMP92001 device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +#ifdef CONFIG_ADC +FAR struct adc_dev_s *lmp92001_adc_initialize(FAR struct i2c_master_s *i2c, + uint8_t addr) +{ + FAR struct lmp92001_dev_s *priv; + + /* Sanity check */ + + DEBUGASSERT(i2c != NULL); + + /* Initialize the LMP92001 device structure */ + + priv = (FAR struct lmp92001_dev_s *)g_adcdev.ad_priv; + priv->cb = NULL; + priv->i2c = i2c; + priv->addr = addr; + + return &g_adcdev; +} +#endif + +#ifdef CONFIG_IOEXPANDER +FAR struct ioexpander_dev_s * +lmp92001_gpio_initialize(FAR struct i2c_master_s *i2c, uint8_t addr) +{ + FAR struct lmp92001_dev_s *priv; + + /* Sanity check */ + + DEBUGASSERT(i2c != NULL); + + /* Initialize the LMP92001 device structure */ + + priv = &g_devpriv; + + priv->gpio_dev.ops = &g_gpio_ops; + priv->i2c = i2c; + priv->addr = addr; + + return &priv->gpio_dev; +} +#endif + +#endif /* CONFIG_LMP92001 */ diff --git a/include/nuttx/analog/adc.h b/include/nuttx/analog/adc.h index 7ce2577fe4..c54bbc4e8f 100644 --- a/include/nuttx/analog/adc.h +++ b/include/nuttx/analog/adc.h @@ -8,7 +8,7 @@ * * Derived from include/nuttx/can/can.h * - * Copyright (C) 2008, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2008, 2009, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ #include #include #include +#include /************************************************************************************ * Pre-processor Definitions @@ -258,6 +259,24 @@ int adc_register(FAR const char *path, FAR struct adc_dev_s *dev); FAR struct adc_dev_s *up_ads1255initialize(FAR struct spi_dev_s *spi, unsigned int devno); +/**************************************************************************** + * Name: lmp92001_adc_initialize + * + * Description: + * Initialize ADC + * + * Input Parameters: + * I2C Port number + * Device address + * + * Returned Value: + * Valid LM92001 device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct adc_dev_s *lmp92001_adc_initialize(FAR struct i2c_master_s *i2c, + uint8_t addr); + #if defined(__cplusplus) } #endif diff --git a/include/nuttx/analog/dac.h b/include/nuttx/analog/dac.h index 50dfbbd381..192cd68bc6 100644 --- a/include/nuttx/analog/dac.h +++ b/include/nuttx/analog/dac.h @@ -8,7 +8,7 @@ * * Derived from include/nuttx/can/can.h * - * Copyright (C) 2008, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2008, 2009, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -88,7 +88,7 @@ struct dac_fifo_s sem_t af_sem; /* Counting semaphore */ uint8_t af_head; /* Index to the head [IN] index in the circular buffer */ uint8_t af_tail; /* Index to the tail [OUT] index in the circular buffer */ - /* Circular buffer of CAN messages */ + /* Circular buffer of DAC messages */ struct dac_msg_s af_buffer[CONFIG_DAC_FIFOSIZE]; }; @@ -212,6 +212,24 @@ FAR struct dac_dev_s *up_ad5410initialize(FAR struct spi_dev_s *spi, unsigned in FAR struct dac_dev_s *dac7571_initialize(FAR struct i2c_master_s *i2c, uint8_t addr); +/**************************************************************************** + * Name: lmp92001_dac_initialize + * + * Description: + * Initialize DAC + * + * Input Parameters: + * I2C Port number + * Device address + * + * Returned Value: + * Valid LM92001 device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +FAR struct dac_dev_s *lmp92001_dac_initialize(FAR struct i2c_master_s *i2c, + uint8_t addr); + #if defined(__cplusplus) } #endif diff --git a/include/nuttx/analog/ioctl.h b/include/nuttx/analog/ioctl.h index 5c0cd21ee9..1816887770 100644 --- a/include/nuttx/analog/ioctl.h +++ b/include/nuttx/analog/ioctl.h @@ -65,8 +65,8 @@ * IN: Threshold value * OUT: None */ -#define AN_FIRST 0x0001 /* First common command */ -#define AN_NCMDS 3 /* Number of common commands */ +#define AN_FIRST 0x0001 /* First common command */ +#define AN_NCMDS 3 /* Number of common commands */ /* User defined ioctl commands are also supported. These will be forwarded * by the upper-half QE driver to the lower-half QE driver via the ioctl() @@ -77,8 +77,13 @@ /* See include/nuttx/analog/ads1242.h */ -#define AN_ADS2142_FIRST (AN_FIRST + AN_NCMDS) -#define AN_ADS2142_NCMDS 6 +#define AN_ADS2142_FIRST (AN_FIRST + AN_NCMDS) +#define AN_ADS2142_NCMDS 6 + +/* See include/nuttx/analog/lm92001.h */ + +#define AN_LMP92001_FIRST (AN_FIRST + AN_NCMDS + AN_ADS2142_NCMDS) +#define AN_LMP92001_NCMDS 7 /**************************************************************************** * Public Function Prototypes diff --git a/include/nuttx/analog/lmp92001.h b/include/nuttx/analog/lmp92001.h new file mode 100644 index 0000000000..d1040055f6 --- /dev/null +++ b/include/nuttx/analog/lmp92001.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * include/nuttx/analog/lmp92001.h + * + * Copyright (C) 2018 Abdelatif Guettouche. All rights reserved. + * Author: Abdelatif Guettouche + * + * This file is a part of NuttX: + * + * Copyright (C) 2010 Gregory Nutt. All rights reserved. + * + * 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_LMP92001_H +#define __INCLUDE_NUTTX_ANALOG_LMP92001_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* IOCTL Commands ***********************************************************/ +/* Cmd: ANIOC_LMP92001_DAC_SET_REF Arg: bool value + * Cmd: ANIOC_LMP92001_DAC_UPDATEALL Arg: uint16_t value + * Cmd: ANIOC_LMP92001_ADC_SET_REF Arg: bool value + * Cmd: ANIOC_LMP92001_ADC_ENABLE Arg: lmp92001_adc_enable_e channel + * Cmd: ANIOC_LMP92001_ADC_SINGLESHOT_CONV Arg: none + * Cmd: ANIOC_LMP92001_ADC_CONTINUOUS_CONV Arg: none + * Cmd: ANIOC_LMP92001_ADC_READ_CHANNEL Arg: struct adc_msg_s *channel + */ + +#define ANIOC_LMP92001_DAC_SET_REF _ANIOC(AN_LMP92001_FIRST + 0) +#define ANIOC_LMP92001_DAC_UPDATEALL _ANIOC(AN_LMP92001_FIRST + 1) +#define ANIOC_LMP92001_ADC_SET_REF _ANIOC(AN_LMP92001_FIRST + 2) +#define ANIOC_LMP92001_ADC_ENABLE _ANIOC(AN_LMP92001_FIRST + 3) +#define ANIOC_LMP92001_ADC_SINGLESHOT_CONV _ANIOC(AN_LMP92001_FIRST + 4) +#define ANIOC_LMP92001_ADC_CONTINUOUS_CONV _ANIOC(AN_LMP92001_FIRST + 5) +#define ANIOC_LMP92001_ADC_READ_CHANNEL _ANIOC(AN_LMP92001_FIRST + 6) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum lmp92001_ref_e +{ + LMP92001_REF_INTERNAL = 0U, + LMP92001_REF_EXTERNAL +}; + +enum lmp92001_adc_enable_e +{ + LMP92001_ADC_EN_CH1 = 1 << 0U, + LMP92001_ADC_EN_CH2 = 1 << 1U, + LMP92001_ADC_EN_CH3 = 1 << 2U, + LMP92001_ADC_EN_CH4 = 1 << 3U, + LMP92001_ADC_EN_CH5 = 1 << 4U, + LMP92001_ADC_EN_CH6 = 1 << 5U, + LMP92001_ADC_EN_CH7 = 1 << 6U, + LMP92001_ADC_EN_CH8 = 1 << 7U, + LMP92001_ADC_EN_CH9 = 1 << 8U, + LMP92001_ADC_EN_CH10 = 1 << 9U, + LMP92001_ADC_EN_CH11 = 1 << 10U, + LMP92001_ADC_EN_CH12 = 1 << 11U, + LMP92001_ADC_EN_CH13 = 1 << 12U, + LMP92001_ADC_EN_CH14 = 1 << 13U, + LMP92001_ADC_EN_CH15 = 1 << 14U, + LMP92001_ADC_EN_CH16 = 1 << 15U, + LMP92001_ADC_EN_CH17 = 1 << 16U, + LMP92001_ADC_EN_ALL = 0x1FFFFU +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: lmp92001_gpio_initialize + * + * Description: + * Instantiate and configure the LMP92001 device driver to use the provided + * I2C device instance. + * + * Input Parameters: + * i2c - An I2C driver instance + * minor - The device i2c address + * + * Returned Value: + * An ioexpander_dev_s instance on success, NULL on failure. + * + ****************************************************************************/ + +struct i2c_master_s; /* Forward reference */ +struct ioexpander_dev_s; /* Forward reference */ + +FAR struct ioexpander_dev_s * +lmp92001_gpio_initialize(FAR struct i2c_master_s *i2c, uint8_t addr); + +#endif /* __INCLUDE_NUTTX_ANALOG_LMP92001_H */