diff options
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r-- | drivers/iio/adc/Kconfig | 83 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 6 | ||||
-rw-r--r-- | drivers/iio/adc/axp288_adc.c | 32 | ||||
-rw-r--r-- | drivers/iio/adc/exynos_adc.c | 2 | ||||
-rw-r--r-- | drivers/iio/adc/fsl-imx25-gcq.c | 1 | ||||
-rw-r--r-- | drivers/iio/adc/hx711.c | 532 | ||||
-rw-r--r-- | drivers/iio/adc/ina2xx-adc.c | 2 | ||||
-rw-r--r-- | drivers/iio/adc/max11100.c | 181 | ||||
-rw-r--r-- | drivers/iio/adc/max1363.c | 1 | ||||
-rw-r--r-- | drivers/iio/adc/meson_saradc.c | 922 | ||||
-rw-r--r-- | drivers/iio/adc/qcom-spmi-vadc.c | 481 | ||||
-rw-r--r-- | drivers/iio/adc/rcar-gyroadc.c | 631 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.c | 1 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc-core.h | 2 | ||||
-rw-r--r-- | drivers/iio/adc/stm32-adc.c | 633 | ||||
-rw-r--r-- | drivers/iio/adc/stx104.c | 72 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads1015.c | 4 | ||||
-rw-r--r-- | drivers/iio/adc/ti-ads7950.c | 490 | ||||
-rw-r--r-- | drivers/iio/adc/ti-tlc4541.c | 271 |
19 files changed, 4121 insertions, 226 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9c8b558ba19e..dedae7adbce9 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -247,6 +247,25 @@ config HI8435 This driver can also be built as a module. If so, the module will be called hi8435. +config HX711 + tristate "AVIA HX711 ADC for weight cells" + depends on GPIOLIB + help + If you say yes here you get support for AVIA HX711 ADC which is used + for weigh cells + + This driver uses two GPIOs, one acts as the clock and controls the + channel selection and gain, the other one is used for the measurement + data + + Currently the raw value is read from the chip and delivered. + To get an actual weight one needs to subtract the + zero offset and multiply by a scale factor. + This should be done in userspace. + + This driver can also be built as a module. If so, the module will be + called hx711. + config INA2XX_ADC tristate "Texas Instruments INA2xx Power Monitors IIO driver" depends on I2C && !SENSORS_INA2XX @@ -307,6 +326,15 @@ config MAX1027 To compile this driver as a module, choose M here: the module will be called max1027. +config MAX11100 + tristate "Maxim max11100 ADC driver" + depends on SPI_MASTER + help + Say yes here to build support for Maxim max11100 SPI ADC + + To compile this driver as a module, choose M here: the module will be + called max11100. + config MAX1363 tristate "Maxim max1363 ADC driver" depends on I2C @@ -371,6 +399,18 @@ config MEN_Z188_ADC This driver can also be built as a module. If so, the module will be called men_z188_adc. +config MESON_SARADC + tristate "Amlogic Meson SAR ADC driver" + default ARCH_MESON + depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST) + select REGMAP_MMIO + help + Say yes here to build support for the SAR ADC found in Amlogic Meson + SoCs. + + To compile this driver as a module, choose M here: the + module will be called meson_saradc. + config MXS_LRADC tristate "Freescale i.MX23/i.MX28 LRADC" depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM @@ -430,6 +470,19 @@ config QCOM_SPMI_VADC To compile this driver as a module, choose M here: the module will be called qcom-spmi-vadc. +config RCAR_GYRO_ADC + tristate "Renesas R-Car GyroADC driver" + depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST) + help + Say yes here to build support for the GyroADC found in Renesas + R-Car Gen2 SoCs. This block is a simple SPI offload engine for + reading data out of attached compatible ADCs in a round-robin + fashion. Up to 4 or 8 ADC channels are supported by this block, + depending on which ADCs are attached. + + To compile this driver as a module, choose M here: the + module will be called rcar-gyroadc. + config ROCKCHIP_SARADC tristate "Rockchip SARADC driver" depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) @@ -444,8 +497,13 @@ config ROCKCHIP_SARADC config STM32_ADC_CORE tristate "STMicroelectronics STM32 adc core" depends on ARCH_STM32 || COMPILE_TEST + depends on HAS_DMA depends on OF depends on REGULATOR + select IIO_BUFFER + select MFD_STM32_TIMERS + select IIO_STM32_TIMER_TRIGGER + select IIO_TRIGGERED_BUFFER help Select this option to enable the core driver for STMicroelectronics STM32 analog-to-digital converter (ADC). @@ -549,6 +607,19 @@ config TI_ADS1015 This driver can also be built as a module. If so, the module will be called ti-ads1015. +config TI_ADS7950 + tristate "Texas Instruments ADS7950 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Texas Instruments ADS7950, ADS7951, + ADS7952, ADS7953, ADS7954, ADS7955, ADS7956, ADS7957, ADS7958, ADS7959. + ADS7960, ADS7961. + + To compile this driver as a module, choose M here: the + module will be called ti-ads7950. + config TI_ADS8688 tristate "Texas Instruments ADS8688" depends on SPI && OF @@ -571,6 +642,18 @@ config TI_AM335X_ADC To compile this driver as a module, choose M here: the module will be called ti_am335x_adc. +config TI_TLC4541 + tristate "Texas Instruments TLC4541 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Texas Instruments TLC4541 / TLC3541 + ADC chips. + + This driver can also be built as a module. If so, the module will be + called ti-tlc4541. + config TWL4030_MADC tristate "TWL4030 MADC (Monitoring A/D Converter)" depends on TWL4030_CORE diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index d36c4be8d1fc..d0012620cd1c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -25,22 +25,26 @@ obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o obj-$(CONFIG_HI8435) += hi8435.o +obj-$(CONFIG_HX711) += hx711.o obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_MAX1027) += max1027.o +obj-$(CONFIG_MAX11100) += max11100.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o +obj-$(CONFIG_MESON_SARADC) += meson_saradc.o obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o +obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o @@ -51,8 +55,10 @@ obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o +obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o +obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o obj-$(CONFIG_VF610_ADC) += vf610_adc.o diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index 7fd24949c0c1..64799ad7ebad 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -28,8 +28,6 @@ #include <linux/iio/driver.h> #define AXP288_ADC_EN_MASK 0xF1 -#define AXP288_ADC_TS_PIN_GPADC 0xF2 -#define AXP288_ADC_TS_PIN_ON 0xF3 enum axp288_adc_id { AXP288_ADC_TS, @@ -123,16 +121,6 @@ static int axp288_adc_read_channel(int *val, unsigned long address, return IIO_VAL_INT; } -static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode, - unsigned long address) -{ - /* channels other than GPADC do not need to switch TS pin */ - if (address != AXP288_GP_ADC_H) - return 0; - - return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode); -} - static int axp288_adc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -143,16 +131,7 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev, mutex_lock(&indio_dev->mlock); switch (mask) { case IIO_CHAN_INFO_RAW: - if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC, - chan->address)) { - dev_err(&indio_dev->dev, "GPADC mode\n"); - ret = -EINVAL; - break; - } ret = axp288_adc_read_channel(val, chan->address, info->regmap); - if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON, - chan->address)) - dev_err(&indio_dev->dev, "TS pin restore\n"); break; default: ret = -EINVAL; @@ -162,15 +141,6 @@ static int axp288_adc_read_raw(struct iio_dev *indio_dev, return ret; } -static int axp288_adc_set_state(struct regmap *regmap) -{ - /* ADC should be always enabled for internal FG to function */ - if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON)) - return -EIO; - - return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK); -} - static const struct iio_info axp288_adc_iio_info = { .read_raw = &axp288_adc_read_raw, .driver_module = THIS_MODULE, @@ -199,7 +169,7 @@ static int axp288_adc_probe(struct platform_device *pdev) * Set ADC to enabled state at all time, including system suspend. * otherwise internal fuel gauge functionality may be affected. */ - ret = axp288_adc_set_state(axp20x->regmap); + ret = regmap_write(info->regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK); if (ret) { dev_err(&pdev->dev, "unable to enable ADC device\n"); return ret; diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index c15756d7bf7f..ad1775b5f83c 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -632,7 +632,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id) input_report_key(info->input, BTN_TOUCH, 1); input_sync(info->input); - msleep(1); + usleep_range(1000, 1100); }; writel(0, ADC_V1_CLRINTPNDNUP(info->regs)); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index 72b32c1ab257..ea264fa9e567 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -401,6 +401,7 @@ static const struct of_device_id mx25_gcq_ids[] = { { .compatible = "fsl,imx25-gcq", }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, mx25_gcq_ids); static struct platform_driver mx25_gcq_driver = { .driver = { diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c new file mode 100644 index 000000000000..139639f73769 --- /dev/null +++ b/drivers/iio/adc/hx711.c @@ -0,0 +1,532 @@ +/* + * HX711: analog to digital converter for weight sensor module + * + * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> + +/* gain to pulse and scale conversion */ +#define HX711_GAIN_MAX 3 + +struct hx711_gain_to_scale { + int gain; + int gain_pulse; + int scale; + int channel; +}; + +/* + * .scale depends on AVDD which in turn is known as soon as the regulator + * is available + * therefore we set .scale in hx711_probe() + * + * channel A in documentation is channel 0 in source code + * channel B in documentation is channel 1 in source code + */ +static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = { + { 128, 1, 0, 0 }, + { 32, 2, 0, 1 }, + { 64, 3, 0, 0 } +}; + +static int hx711_get_gain_to_pulse(int gain) +{ + int i; + + for (i = 0; i < HX711_GAIN_MAX; i++) + if (hx711_gain_to_scale[i].gain == gain) + return hx711_gain_to_scale[i].gain_pulse; + return 1; +} + +static int hx711_get_gain_to_scale(int gain) +{ + int i; + + for (i = 0; i < HX711_GAIN_MAX; i++) + if (hx711_gain_to_scale[i].gain == gain) + return hx711_gain_to_scale[i].scale; + return 0; +} + +static int hx711_get_scale_to_gain(int scale) +{ + int i; + + for (i = 0; i < HX711_GAIN_MAX; i++) + if (hx711_gain_to_scale[i].scale == scale) + return hx711_gain_to_scale[i].gain; + return -EINVAL; +} + +struct hx711_data { + struct device *dev; + struct gpio_desc *gpiod_pd_sck; + struct gpio_desc *gpiod_dout; + struct regulator *reg_avdd; + int gain_set; /* gain set on device */ + int gain_chan_a; /* gain for channel A */ + struct mutex lock; +}; + +static int hx711_cycle(struct hx711_data *hx711_data) +{ + int val; + + /* + * if preempted for more then 60us while PD_SCK is high: + * hx711 is going in reset + * ==> measuring is false + */ + preempt_disable(); + gpiod_set_value(hx711_data->gpiod_pd_sck, 1); + val = gpiod_get_value(hx711_data->gpiod_dout); + /* + * here we are not waiting for 0.2 us as suggested by the datasheet, + * because the oscilloscope showed in a test scenario + * at least 1.15 us for PD_SCK high (T3 in datasheet) + * and 0.56 us for PD_SCK low on TI Sitara with 800 MHz + */ + gpiod_set_value(hx711_data->gpiod_pd_sck, 0); + preempt_enable(); + + return val; +} + +static int hx711_read(struct hx711_data *hx711_data) +{ + int i, ret; + int value = 0; + int val = gpiod_get_value(hx711_data->gpiod_dout); + + /* we double check if it's really down */ + if (val) + return -EIO; + + for (i = 0; i < 24; i++) { + value <<= 1; + ret = hx711_cycle(hx711_data); + if (ret) + value++; + } + + value ^= 0x800000; + + for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++) + hx711_cycle(hx711_data); + + return value; +} + +static int hx711_wait_for_ready(struct hx711_data *hx711_data) +{ + int i, val; + + /* + * a maximum reset cycle time of 56 ms was measured. + * we round it up to 100 ms + */ + for (i = 0; i < 100; i++) { + val = gpiod_get_value(hx711_data->gpiod_dout); + if (!val) + break; + /* sleep at least 1 ms */ + msleep(1); + } + if (val) + return -EIO; + + return 0; +} + +static int hx711_reset(struct hx711_data *hx711_data) +{ + int ret; + int val = gpiod_get_value(hx711_data->gpiod_dout); + + if (val) { + /* + * an examination with the oszilloscope indicated + * that the first value read after the reset is not stable + * if we reset too short; + * the shorter the reset cycle + * the less reliable the first value after reset is; + * there were no problems encountered with a value + * of 10 ms or higher + */ + gpiod_set_value(hx711_data->gpiod_pd_sck, 1); + msleep(10); + gpiod_set_value(hx711_data->gpiod_pd_sck, 0); + + ret = hx711_wait_for_ready(hx711_data); + if (ret) + return ret; + /* + * after a reset the gain is 128 so we do a dummy read + * to set the gain for the next read + */ + ret = hx711_read(hx711_data); + if (ret < 0) + return ret; + + /* + * after a dummy read we need to wait vor readiness + * for not mixing gain pulses with the clock + */ + ret = hx711_wait_for_ready(hx711_data); + if (ret) + return ret; + } + + return val; +} + +static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan) +{ + int ret; + + if (chan == 0) { + if (hx711_data->gain_set == 32) { + hx711_data->gain_set = hx711_data->gain_chan_a; + + ret = hx711_read(hx711_data); + if (ret < 0) + return ret; + + ret = hx711_wait_for_ready(hx711_data); + if (ret) + return ret; + } + } else { + if (hx711_data->gain_set != 32) { + hx711_data->gain_set = 32; + + ret = hx711_read(hx711_data); + if (ret < 0) + return ret; + + ret = hx711_wait_for_ready(hx711_data); + if (ret) + return ret; + } + } + + return 0; +} + +static int hx711_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct hx711_data *hx711_data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&hx711_data->lock); + + /* + * hx711_reset() must be called from here + * because it could be calling hx711_read() by itself + */ + if (hx711_reset(hx711_data)) { + mutex_unlock(&hx711_data->lock); + dev_err(hx711_data->dev, "reset failed!"); + return -EIO; + } + + ret = hx711_set_gain_for_channel(hx711_data, chan->channel); + if (ret < 0) { + mutex_unlock(&hx711_data->lock); + return ret; + } + + *val = hx711_read(hx711_data); + + mutex_unlock(&hx711_data->lock); + + if (*val < 0) + return *val; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + mutex_lock(&hx711_data->lock); + + *val2 = hx711_get_gain_to_scale(hx711_data->gain_set); + + mutex_unlock(&hx711_data->lock); + + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int hx711_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct hx711_data *hx711_data = iio_priv(indio_dev); + int ret; + int gain; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + /* + * a scale greater than 1 mV per LSB is not possible + * with the HX711, therefore val must be 0 + */ + if (val != 0) + return -EINVAL; + + mutex_lock(&hx711_data->lock); + + gain = hx711_get_scale_to_gain(val2); + if (gain < 0) { + mutex_unlock(&hx711_data->lock); + return gain; + } + + if (gain != hx711_data->gain_set) { + hx711_data->gain_set = gain; + if (gain != 32) + hx711_data->gain_chan_a = gain; + + ret = hx711_read(hx711_data); + if (ret < 0) { + mutex_unlock(&hx711_data->lock); + return ret; + } + } + + mutex_unlock(&hx711_data->lock); + return 0; + default: + return -EINVAL; + } + + return 0; +} + +static int hx711_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_NANO; +} + +static ssize_t hx711_scale_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr); + int channel = iio_attr->address; + int i, len = 0; + + for (i = 0; i < HX711_GAIN_MAX; i++) + if (hx711_gain_to_scale[i].channel == channel) + len += sprintf(buf + len, "0.%09d ", + hx711_gain_to_scale[i].scale); + + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEVICE_ATTR(in_voltage0_scale_available, S_IRUGO, + hx711_scale_available_show, NULL, 0); + +static IIO_DEVICE_ATTR(in_voltage1_scale_available, S_IRUGO, + hx711_scale_available_show, NULL, 1); + +static struct attribute *hx711_attributes[] = { + &iio_dev_attr_in_voltage0_scale_available.dev_attr.attr, + &iio_dev_attr_in_voltage1_scale_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group hx711_attribute_group = { + .attrs = hx711_attributes, +}; + +static const struct iio_info hx711_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = hx711_read_raw, + .write_raw = hx711_write_raw, + .write_raw_get_fmt = hx711_write_raw_get_fmt, + .attrs = &hx711_attribute_group, +}; + +static const struct iio_chan_spec hx711_chan_spec[] = { + { + .type = IIO_VOLTAGE, + .channel = 0, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_VOLTAGE, + .channel = 1, + .indexed = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int hx711_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct hx711_data *hx711_data; + struct iio_dev *indio_dev; + int ret; + int i; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data)); + if (!indio_dev) { + dev_err(dev, "failed to allocate IIO device\n"); + return -ENOMEM; + } + + hx711_data = iio_priv(indio_dev); + hx711_data->dev = dev; + + mutex_init(&hx711_data->lock); + + /* + * PD_SCK stands for power down and serial clock input of HX711 + * in the driver it is an output + */ + hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW); + if (IS_ERR(hx711_data->gpiod_pd_sck)) { + dev_err(dev, "failed to get sck-gpiod: err=%ld\n", + PTR_ERR(hx711_data->gpiod_pd_sck)); + return PTR_ERR(hx711_data->gpiod_pd_sck); + } + + /* + * DOUT stands for serial data output of HX711 + * for the driver it is an input + */ + hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN); + if (IS_ERR(hx711_data->gpiod_dout)) { + dev_err(dev, "failed to get dout-gpiod: err=%ld\n", + PTR_ERR(hx711_data->gpiod_dout)); + return PTR_ERR(hx711_data->gpiod_dout); + } + + hx711_data->reg_avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(hx711_data->reg_avdd)) + return PTR_ERR(hx711_data->reg_avdd); + + ret = regulator_enable(hx711_data->reg_avdd); + if (ret < 0) + return ret; + + /* + * with + * full scale differential input range: AVDD / GAIN + * full scale output data: 2^24 + * we can say: + * AVDD / GAIN = 2^24 + * therefore: + * 1 LSB = AVDD / GAIN / 2^24 + * AVDD is in uV, but we need 10^-9 mV + * approximately to fit into a 32 bit number: + * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV] + */ + ret = regulator_get_voltage(hx711_data->reg_avdd); + if (ret < 0) { + regulator_disable(hx711_data->reg_avdd); + return ret; + } + /* we need 10^-9 mV */ + ret *= 100; + + for (i = 0; i < HX711_GAIN_MAX; i++) + hx711_gain_to_scale[i].scale = + ret / hx711_gain_to_scale[i].gain / 1678; + + hx711_data->gain_set = 128; + hx711_data->gain_chan_a = 128; + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = "hx711"; + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &hx711_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = hx711_chan_spec; + indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec); + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(dev, "Couldn't register the device\n"); + regulator_disable(hx711_data->reg_avdd); + } + + return ret; +} + +static int hx711_remove(struct platform_device *pdev) +{ + struct hx711_data *hx711_data; + struct iio_dev *indio_dev; + + indio_dev = platform_get_drvdata(pdev); + hx711_data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + regulator_disable(hx711_data->reg_avdd); + + return 0; +} + +static const struct of_device_id of_hx711_match[] = { + { .compatible = "avia,hx711", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_hx711_match); + +static struct platform_driver hx711_driver = { + .probe = hx711_probe, + .remove = hx711_remove, + .driver = { + .name = "hx711-gpio", + .of_match_table = of_hx711_match, + }, +}; + +module_platform_driver(hx711_driver); + +MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>"); +MODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:hx711-gpio"); + diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 59b7d76e1ad2..3263231276ca 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -22,6 +22,8 @@ #include <linux/delay.h> #include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/sysfs.h> #include <linux/kthread.h> diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c new file mode 100644 index 000000000000..a088cf99bfe1 --- /dev/null +++ b/drivers/iio/adc/max11100.c @@ -0,0 +1,181 @@ +/* + * iio/adc/max11100.c + * Maxim max11100 ADC Driver with IIO interface + * + * Copyright (C) 2016-17 Renesas Electronics Corporation + * Copyright (C) 2016-17 Jacopo Mondi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#include <linux/iio/iio.h> +#include <linux/iio/driver.h> + +/* + * LSB is the ADC single digital step + * 1 LSB = (vref_mv / 2 ^ 16) + * + * LSB is used to calculate analog voltage value + * from the number of ADC steps count + * + * Ain = (count * LSB) + */ +#define MAX11100_LSB_DIV (1 << 16) + +struct max11100_state { + struct regulator *vref_reg; + struct spi_device *spi; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 buffer[3] ____cacheline_aligned; +}; + +static struct iio_chan_spec max11100_channels[] = { + { /* [0] */ + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int max11100_read_single(struct iio_dev *indio_dev, int *val) +{ + int ret; + struct max11100_state *state = iio_priv(indio_dev); + + ret = spi_read(state->spi, state->buffer, sizeof(state->buffer)); + if (ret) { + dev_err(&indio_dev->dev, "SPI transfer failed\n"); + return ret; + } + + /* the first 8 bits sent out from ADC must be 0s */ + if (state->buffer[0]) { + dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n"); + return -EINVAL; + } + + *val = (state->buffer[1] << 8) | state->buffer[2]; + + return 0; +} + +static int max11100_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long info) +{ + int ret, vref_uv; + struct max11100_state *state = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + ret = max11100_read_single(indio_dev, val); + if (ret) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + vref_uv = regulator_get_voltage(state->vref_reg); + if (vref_uv < 0) + /* dummy regulator "get_voltage" returns -EINVAL */ + return -EINVAL; + + *val = vref_uv / 1000; + *val2 = MAX11100_LSB_DIV; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static const struct iio_info max11100_info = { + .driver_module = THIS_MODULE, + .read_raw = max11100_read_raw, +}; + +static int max11100_probe(struct spi_device *spi) +{ + int ret; + struct iio_dev *indio_dev; + struct max11100_state *state; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + spi_set_drvdata(spi, indio_dev); + + state = iio_priv(indio_dev); + state->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; + indio_dev->name = "max11100"; + indio_dev->info = &max11100_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = max11100_channels, + indio_dev->num_channels = ARRAY_SIZE(max11100_channels), + + state->vref_reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(state->vref_reg)) + return PTR_ERR(state->vref_reg); + + ret = regulator_enable(state->vref_reg); + if (ret) + return ret; + + ret = iio_device_register(indio_dev); + if (ret) + goto disable_regulator; + + return 0; + +disable_regulator: + regulator_disable(state->vref_reg); + + return ret; +} + +static int max11100_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct max11100_state *state = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(state->vref_reg); + + return 0; +} + +static const struct of_device_id max11100_ids[] = { + {.compatible = "maxim,max11100"}, + { }, +}; +MODULE_DEVICE_TABLE(of, max11100_ids); + +static struct spi_driver max11100_driver = { + .driver = { + .name = "max11100", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max11100_ids), + }, + .probe = max11100_probe, + .remove = max11100_remove, +}; + +module_spi_driver(max11100_driver); + +MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>"); +MODULE_DESCRIPTION("Maxim max11100 ADC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 841a13c9b6ea..c6c12feb4a08 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1567,6 +1567,7 @@ static const struct of_device_id max1363_of_match[] = { MAX1363_COMPATIBLE("maxim,max11647", max11647), { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, max1363_of_match); #endif static int max1363_probe(struct i2c_client *client, diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c new file mode 100644 index 000000000000..89def6034f40 --- /dev/null +++ b/drivers/iio/adc/meson_saradc.c @@ -0,0 +1,922 @@ +/* + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter + * + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define MESON_SAR_ADC_REG0 0x00 + #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31) + #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28) + #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30) + #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29) + #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28) + #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27) + #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26) + #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21) + #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19) + #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16) + #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15) + #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14) + #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9) + #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4) + #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3) + #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2) + #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1) + #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0) + +#define MESON_SAR_ADC_CHAN_LIST 0x04 + #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24) + #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \ + (GENMASK(2, 0) << ((_chan) * 3)) + +#define MESON_SAR_ADC_AVG_CNTL 0x08 + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \ + (16 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \ + (GENMASK(17, 16) << ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \ + (0 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \ + (GENMASK(1, 0) << ((_chan) * 2)) + +#define MESON_SAR_ADC_REG3 0x0c + #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31) + #define MESON_SAR_ADC_REG3_CLK_EN BIT(30) + #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28) + #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27) + #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26) + #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22) + #define MESON_SAR_ADC_REG3_ADC_EN BIT(21) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16) + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10 + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5 + #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_DELAY 0x10 + #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24) + #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15) + #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14) + #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_LAST_RD 0x14 + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0) + +#define MESON_SAR_ADC_FIFO_RD 0x18 + #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12) + #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0) + +#define MESON_SAR_ADC_AUX_SW 0x1c + #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan) \ + (GENMASK(10, 8) << (((_chan) - 2) * 2)) + #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4) + #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_CHAN_10_SW 0x20 + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DETECT_IDLE_SW 0x24 + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DELTA_10 0x28 + #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27) + #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26) + #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16) + #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15) + #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11 + #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11) + #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10) + #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0) + +/* + * NOTE: registers from here are undocumented (the vendor Linux kernel driver + * and u-boot source served as reference). These only seem to be relevant on + * GXBB and newer. + */ +#define MESON_SAR_ADC_REG11 0x2c + #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) + +#define MESON_SAR_ADC_REG13 0x34 + #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) + +#define MESON_SAR_ADC_MAX_FIFO_SIZE 32 + +#define MESON_SAR_ADC_CHAN(_chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = "SAR_ADC_CH"#_chan, \ +} + +/* + * TODO: the hardware supports IIO_TEMP for channel 6 as well which is + * currently not supported by this driver. + */ +static const struct iio_chan_spec meson_sar_adc_iio_channels[] = { + MESON_SAR_ADC_CHAN(0), + MESON_SAR_ADC_CHAN(1), + MESON_SAR_ADC_CHAN(2), + MESON_SAR_ADC_CHAN(3), + MESON_SAR_ADC_CHAN(4), + MESON_SAR_ADC_CHAN(5), + MESON_SAR_ADC_CHAN(6), + MESON_SAR_ADC_CHAN(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +enum meson_sar_adc_avg_mode { + NO_AVERAGING = 0x0, + MEAN_AVERAGING = 0x1, + MEDIAN_AVERAGING = 0x2, +}; + +enum meson_sar_adc_num_samples { + ONE_SAMPLE = 0x0, + TWO_SAMPLES = 0x1, + FOUR_SAMPLES = 0x2, + EIGHT_SAMPLES = 0x3, +}; + +enum meson_sar_adc_chan7_mux_sel { + CHAN7_MUX_VSS = 0x0, + CHAN7_MUX_VDD_DIV4 = 0x1, + CHAN7_MUX_VDD_DIV2 = 0x2, + CHAN7_MUX_VDD_MUL3_DIV4 = 0x3, + CHAN7_MUX_VDD = 0x4, + CHAN7_MUX_CH7_INPUT = 0x7, +}; + +struct meson_sar_adc_data { + unsigned int resolution; + const char *name; +}; + +struct meson_sar_adc_priv { + struct regmap *regmap; + struct regulator *vref; + const struct meson_sar_adc_data *data; + struct clk *clkin; + struct clk *core_clk; + struct clk *sana_clk; + struct clk *adc_sel_clk; + struct clk *adc_clk; + struct clk_gate clk_gate; + struct clk *adc_div_clk; + struct clk_divider clk_div; +}; + +static const struct regmap_config meson_sar_adc_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = MESON_SAR_ADC_REG13, +}; + +static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + + return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); +} + +static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int regval, timeout = 10000; + + /* + * NOTE: we need a small delay before reading the status, otherwise + * the sample engine may not have started internally (which would + * seem to us that sampling is already finished). + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + + return 0; +} + +static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0; + + ret = meson_sar_adc_wait_busy_clear(indio_dev); + if (ret) + return ret; + + while (meson_sar_adc_get_fifo_count(indio_dev) > 0 && + count < MESON_SAR_ADC_MAX_FIFO_SIZE) { + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); + + fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, + regval); + if (fifo_chan != chan->channel) + continue; + + fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, + regval); + fifo_val &= (BIT(priv->data->resolution) - 1); + + sum += fifo_val; + count++; + } + + if (!count) + return -ENOENT; + + *val = sum / count; + + return 0; +} + +static void meson_sar_adc_set_averaging(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum meson_sar_adc_avg_mode mode, + enum meson_sar_adc_num_samples samples) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int val, channel = chan->channel; + + val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel), + val); + + val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val); +} + +static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + /* + * the SAR ADC engine allows sampling multiple channels at the same + * time. to keep it simple we're only working with one *internal* + * channel, which starts counting at index 0 (which means: count = 1). + */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval); + + /* map channel index 0 to the channel which we want to read */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + regval); + + if (chan->channel == 6) + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0); +} + +static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev, + enum meson_sar_adc_chan7_mux_sel sel) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval); + + usleep_range(10, 20); +} + +static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_START, + MESON_SAR_ADC_REG0_SAMPLING_START); +} + +static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_STOP, + MESON_SAR_ADC_REG0_SAMPLING_STOP); + + /* wait until all modules are stopped */ + meson_sar_adc_wait_busy_clear(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); +} + +static int meson_sar_adc_lock(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int val, timeout = 10000; + + mutex_lock(&indio_dev->mlock); + + /* prevent BL30 from using the SAR ADC while we are using it */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); + + /* wait until BL30 releases it's lock (so we can use the SAR ADC) */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + + return 0; +} + +static void meson_sar_adc_unlock(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + /* allow BL30 to use the SAR ADC again */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + + mutex_unlock(&indio_dev->mlock); +} + +static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int count; + + for (count = 0; count < MESON_SAR_ADC_MAX_FIFO_SIZE; count++) { + if (!meson_sar_adc_get_fifo_count(indio_dev)) + break; + + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, 0); + } +} + +static int meson_sar_adc_get_sample(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum meson_sar_adc_avg_mode avg_mode, + enum meson_sar_adc_num_samples avg_samples, + int *val) +{ + int ret; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + return ret; + + /* clear the FIFO to make sure we're not reading old values */ + meson_sar_adc_clear_fifo(indio_dev); + + meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples); + + meson_sar_adc_enable_channel(indio_dev, chan); + + meson_sar_adc_start_sample_engine(indio_dev); + ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val); + meson_sar_adc_stop_sample_engine(indio_dev); + + meson_sar_adc_unlock(indio_dev); + + if (ret) { + dev_warn(indio_dev->dev.parent, + "failed to read sample for channel %d: %d\n", + chan->channel, ret); + return ret; + } + + return IIO_VAL_INT; +} + +static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING, + ONE_SAMPLE, val); + break; + + case IIO_CHAN_INFO_AVERAGE_RAW: + return meson_sar_adc_get_sample(indio_dev, chan, + MEAN_AVERAGING, EIGHT_SAMPLES, + val); + break; + + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(priv->vref); + if (ret < 0) { + dev_err(indio_dev->dev.parent, + "failed to get vref voltage: %d\n", ret); + return ret; + } + + *val = ret / 1000; + *val2 = priv->data->resolution; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, + void __iomem *base) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + struct clk_init_data init; + const char *clk_parents[1]; + + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div", + of_node_full_name(indio_dev->dev.of_node)); + init.flags = 0; + init.ops = &clk_divider_ops; + clk_parents[0] = __clk_get_name(priv->clkin); + init.parent_names = clk_parents; + init.num_parents = 1; + + priv->clk_div.reg = base + MESON_SAR_ADC_REG3; + priv->clk_div.shift = MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT; + priv->clk_div.width = MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH; + priv->clk_div.hw.init = &init; + priv->clk_div.flags = 0; + + priv->adc_div_clk = devm_clk_register(&indio_dev->dev, + &priv->clk_div.hw); + if (WARN_ON(IS_ERR(priv->adc_div_clk))) + return PTR_ERR(priv->adc_div_clk); + + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en", + of_node_full_name(indio_dev->dev.of_node)); + init.flags = CLK_SET_RATE_PARENT; + init.ops = &clk_gate_ops; + clk_parents[0] = __clk_get_name(priv->adc_div_clk); + init.parent_names = clk_parents; + init.num_parents = 1; + + priv->clk_gate.reg = base + MESON_SAR_ADC_REG3; + priv->clk_gate.bit_idx = fls(MESON_SAR_ADC_REG3_CLK_EN); + priv->clk_gate.hw.init = &init; + + priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw); + if (WARN_ON(IS_ERR(priv->adc_clk))) + return PTR_ERR(priv->adc_clk); + + return 0; +} + +static int meson_sar_adc_init(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int regval, ret; + + /* + * make sure we start at CH7 input since the other muxes are only used + * for internal calibration. + */ + meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); + + /* + * leave sampling delay and the input clocks as configured by BL30 to + * make sure BL30 gets the values it expects when reading the + * temperature sensor. + */ + regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); + if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) + return 0; + + meson_sar_adc_stop_sample_engine(indio_dev); + + /* update the channel 6 MUX to select the temperature sensor */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); + + /* disable all channels by default */ + regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + 0)); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + 1)); + + ret = clk_set_parent(priv->adc_sel_clk, priv->clkin); + if (ret) { + dev_err(indio_dev->dev.parent, + "failed to set adc parent to clkin\n"); + return ret; + } + + ret = clk_set_rate(priv->adc_clk, 1200000); + if (ret) { + dev_err(indio_dev->dev.parent, + "failed to set adc clock rate\n"); + return ret; + } + + return 0; +} + +static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + goto err_lock; + + ret = regulator_enable(priv->vref); + if (ret < 0) { + dev_err(indio_dev->dev.parent, + "failed to enable vref regulator\n"); + goto err_vref; + } + + ret = clk_prepare_enable(priv->core_clk); + if (ret) { + dev_err(indio_dev->dev.parent, "failed to enable core clk\n"); + goto err_core_clk; + } + + ret = clk_prepare_enable(priv->sana_clk); + if (ret) { + dev_err(indio_dev->dev.parent, "failed to enable sana clk\n"); + goto err_sana_clk; + } + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, + MESON_SAR_ADC_REG11_BANDGAP_EN); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, + MESON_SAR_ADC_REG3_ADC_EN); + + udelay(5); + + ret = clk_prepare_enable(priv->adc_clk); + if (ret) { + dev_err(indio_dev->dev.parent, "failed to enable adc clk\n"); + goto err_adc_clk; + } + + meson_sar_adc_unlock(indio_dev); + + return 0; + +err_adc_clk: + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + clk_disable_unprepare(priv->sana_clk); +err_sana_clk: + clk_disable_unprepare(priv->core_clk); +err_core_clk: + regulator_disable(priv->vref); +err_vref: + meson_sar_adc_unlock(indio_dev); +err_lock: + return ret; +} + +static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + return ret; + + clk_disable_unprepare(priv->adc_clk); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + + clk_disable_unprepare(priv->sana_clk); + clk_disable_unprepare(priv->core_clk); + + regulator_disable(priv->vref); + + meson_sar_adc_unlock(indio_dev); + + return 0; +} + +static const struct iio_info meson_sar_adc_iio_info = { + .read_raw = meson_sar_adc_iio_info_read_raw, + .driver_module = THIS_MODULE, +}; + +struct meson_sar_adc_data meson_sar_adc_gxbb_data = { + .resolution = 10, + .name = "meson-gxbb-saradc", +}; + +struct meson_sar_adc_data meson_sar_adc_gxl_data = { + .resolution = 12, + .name = "meson-gxl-saradc", +}; + +struct meson_sar_adc_data meson_sar_adc_gxm_data = { + .resolution = 12, + .name = "meson-gxm-saradc", +}; + +static const struct of_device_id meson_sar_adc_of_match[] = { + { + .compatible = "amlogic,meson-gxbb-saradc", + .data = &meson_sar_adc_gxbb_data, + }, { + .compatible = "amlogic,meson-gxl-saradc", + .data = &meson_sar_adc_gxl_data, + }, { + .compatible = "amlogic,meson-gxm-saradc", + .data = &meson_sar_adc_gxm_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match); + +static int meson_sar_adc_probe(struct platform_device *pdev) +{ + struct meson_sar_adc_priv *priv; + struct iio_dev *indio_dev; + struct resource *res; + void __iomem *base; + const struct of_device_id *match; + int ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + + priv = iio_priv(indio_dev); + + match = of_match_device(meson_sar_adc_of_match, &pdev->dev); + priv->data = match->data; + + indio_dev->name = priv->data->name; + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &meson_sar_adc_iio_info; + + indio_dev->channels = meson_sar_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(meson_sar_adc_iio_channels); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &meson_sar_adc_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->clkin = devm_clk_get(&pdev->dev, "clkin"); + if (IS_ERR(priv->clkin)) { + dev_err(&pdev->dev, "failed to get clkin\n"); + return PTR_ERR(priv->clkin); + } + + priv->core_clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(priv->core_clk)) { + dev_err(&pdev->dev, "failed to get core clk\n"); + return PTR_ERR(priv->core_clk); + } + + priv->sana_clk = devm_clk_get(&pdev->dev, "sana"); + if (IS_ERR(priv->sana_clk)) { + if (PTR_ERR(priv->sana_clk) == -ENOENT) { + priv->sana_clk = NULL; + } else { + dev_err(&pdev->dev, "failed to get sana clk\n"); + return PTR_ERR(priv->sana_clk); + } + } + + priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk"); + if (IS_ERR(priv->adc_clk)) { + if (PTR_ERR(priv->adc_clk) == -ENOENT) { + priv->adc_clk = NULL; + } else { + dev_err(&pdev->dev, "failed to get adc clk\n"); + return PTR_ERR(priv->adc_clk); + } + } + + priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel"); + if (IS_ERR(priv->adc_sel_clk)) { + if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) { + priv->adc_sel_clk = NULL; + } else { + dev_err(&pdev->dev, "failed to get adc_sel clk\n"); + return PTR_ERR(priv->adc_sel_clk); + } + } + + /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */ + if (!priv->adc_clk) { + ret = meson_sar_adc_clk_init(indio_dev, base); + if (ret) + return ret; + } + + priv->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(priv->vref)) { + dev_err(&pdev->dev, "failed to get vref regulator\n"); + return PTR_ERR(priv->vref); + } + + ret = meson_sar_adc_init(indio_dev); + if (ret) + goto err; + + ret = meson_sar_adc_hw_enable(indio_dev); + if (ret) + goto err; + + platform_set_drvdata(pdev, indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_hw; + + return 0; + +err_hw: + meson_sar_adc_hw_disable(indio_dev); +err: + return ret; +} + +static int meson_sar_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + iio_device_unregister(indio_dev); + + return meson_sar_adc_hw_disable(indio_dev); +} + +static int __maybe_unused meson_sar_adc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return meson_sar_adc_hw_disable(indio_dev); +} + +static int __maybe_unused meson_sar_adc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return meson_sar_adc_hw_enable(indio_dev); +} + +static SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, + meson_sar_adc_suspend, meson_sar_adc_resume); + +static struct platform_driver meson_sar_adc_driver = { + .probe = meson_sar_adc_probe, + .remove = meson_sar_adc_remove, + .driver = { + .name = "meson-saradc", + .of_match_table = meson_sar_adc_of_match, + .pm = &meson_sar_adc_pm_ops, + }, +}; + +module_platform_driver(meson_sar_adc_driver); + +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index c2babe50a0d8..0a19761d656c 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -84,7 +84,7 @@ #define VADC_MAX_ADC_CODE 0xa800 #define VADC_ABSOLUTE_RANGE_UV 625000 -#define VADC_RATIOMETRIC_RANGE_UV 1800000 +#define VADC_RATIOMETRIC_RANGE 1800 #define VADC_DEF_PRESCALING 0 /* 1:1 */ #define VADC_DEF_DECIMATION 0 /* 512 */ @@ -100,9 +100,23 @@ #define KELVINMIL_CELSIUSMIL 273150 +#define PMI_CHG_SCALE_1 -138890 +#define PMI_CHG_SCALE_2 391750000000LL + #define VADC_CHAN_MIN VADC_USBIN #define VADC_CHAN_MAX VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM +/** + * struct vadc_map_pt - Map the graph representation for ADC channel + * @x: Represent the ADC digitized code. + * @y: Represent the physical data which can be temperature, voltage, + * resistance. + */ +struct vadc_map_pt { + s32 x; + s32 y; +}; + /* * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels. * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for @@ -148,6 +162,9 @@ struct vadc_prescale_ratio { * start of conversion. * @avg_samples: ability to provide single result from the ADC * that is an average of multiple measurements. + * @scale_fn: Represents the scaling function to convert voltage + * physical units desired by the client for the channel. + * Referenced from enum vadc_scale_fn_type. */ struct vadc_channel_prop { unsigned int channel; @@ -156,6 +173,7 @@ struct vadc_channel_prop { unsigned int prescale; unsigned int hw_settle_time; unsigned int avg_samples; + unsigned int scale_fn; }; /** @@ -186,6 +204,35 @@ struct vadc_priv { struct mutex lock; }; +/** + * struct vadc_scale_fn - Scaling function prototype + * @scale: Function pointer to one of the scaling functions + * which takes the adc properties, channel properties, + * and returns the physical result. + */ +struct vadc_scale_fn { + int (*scale)(struct vadc_priv *, const struct vadc_channel_prop *, + u16, int *); +}; + +/** + * enum vadc_scale_fn_type - Scaling function to convert ADC code to + * physical scaled units for the channel. + * SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV). + * SCALE_THERM_100K_PULLUP: Returns temperature in millidegC. + * Uses a mapping table with 100K pullup. + * SCALE_PMIC_THERM: Returns result in milli degree's Centigrade. + * SCALE_XOTHERM: Returns XO thermistor voltage in millidegC. + * SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp + */ +enum vadc_scale_fn_type { + SCALE_DEFAULT = 0, + SCALE_THERM_100K_PULLUP, + SCALE_PMIC_THERM, + SCALE_XOTHERM, + SCALE_PMI_CHG_TEMP, +}; + static const struct vadc_prescale_ratio vadc_prescale_ratios[] = { {.num = 1, .den = 1}, {.num = 1, .den = 3}, @@ -197,6 +244,44 @@ static const struct vadc_prescale_ratio vadc_prescale_ratios[] = { {.num = 1, .den = 10} }; +/* Voltage to temperature */ +static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = { + {1758, -40}, + {1742, -35}, + {1719, -30}, + {1691, -25}, + {1654, -20}, + {1608, -15}, + {1551, -10}, + {1483, -5}, + {1404, 0}, + {1315, 5}, + {1218, 10}, + {1114, 15}, + {1007, 20}, + {900, 25}, + {795, 30}, + {696, 35}, + {605, 40}, + {522, 45}, + {448, 50}, + {383, 55}, + {327, 60}, + {278, 65}, + {237, 70}, + {202, 75}, + {172, 80}, + {146, 85}, + {125, 90}, + {107, 95}, + {92, 100}, + {79, 105}, + {68, 110}, + {59, 115}, + {51, 120}, + {44, 125} +}; + static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data) { return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1); @@ -418,7 +503,7 @@ static int vadc_measure_ref_points(struct vadc_priv *vadc) u16 read_1, read_2; int ret; - vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE_UV; + vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE; vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV; prop = vadc_get_channel(vadc, VADC_REF_1250MV); @@ -468,27 +553,148 @@ err: return ret; } -static s32 vadc_calibrate(struct vadc_priv *vadc, - const struct vadc_channel_prop *prop, u16 adc_code) +static int vadc_map_voltage_temp(const struct vadc_map_pt *pts, + u32 tablesize, s32 input, s64 *output) +{ + bool descending = 1; + u32 i = 0; + + if (!pts) + return -EINVAL; + + /* Check if table is descending or ascending */ + if (tablesize > 1) { + if (pts[0].x < pts[1].x) + descending = 0; + } + + while (i < tablesize) { + if ((descending) && (pts[i].x < input)) { + /* table entry is less than measured*/ + /* value and table is descending, stop */ + break; + } else if ((!descending) && + (pts[i].x > input)) { + /* table entry is greater than measured*/ + /*value and table is ascending, stop */ + break; + } + i++; + } + + if (i == 0) { + *output = pts[0].y; + } else if (i == tablesize) { + *output = pts[tablesize - 1].y; + } else { + /* result is between search_index and search_index-1 */ + /* interpolate linearly */ + *output = (((s32)((pts[i].y - pts[i - 1].y) * + (input - pts[i - 1].x)) / + (pts[i].x - pts[i - 1].x)) + + pts[i - 1].y); + } + + return 0; +} + +static void vadc_scale_calib(struct vadc_priv *vadc, u16 adc_code, + const struct vadc_channel_prop *prop, + s64 *scale_voltage) +{ + *scale_voltage = (adc_code - + vadc->graph[prop->calibration].gnd); + *scale_voltage *= vadc->graph[prop->calibration].dx; + *scale_voltage = div64_s64(*scale_voltage, + vadc->graph[prop->calibration].dy); + if (prop->calibration == VADC_CALIB_ABSOLUTE) + *scale_voltage += + vadc->graph[prop->calibration].dx; + + if (*scale_voltage < 0) + *scale_voltage = 0; +} + +static int vadc_scale_volt(struct vadc_priv *vadc, + const struct vadc_channel_prop *prop, u16 adc_code, + int *result_uv) { const struct vadc_prescale_ratio *prescale; - s64 voltage; + s64 voltage = 0, result = 0; - voltage = adc_code - vadc->graph[prop->calibration].gnd; - voltage *= vadc->graph[prop->calibration].dx; - voltage = div64_s64(voltage, vadc->graph[prop->calibration].dy); + vadc_scale_calib(vadc, adc_code, prop, &voltage); + + prescale = &vadc_prescale_ratios[prop->prescale]; + voltage = voltage * prescale->den; + result = div64_s64(voltage, prescale->num); + *result_uv = result; + + return 0; +} + +static int vadc_scale_therm(struct vadc_priv *vadc, + const struct vadc_channel_prop *prop, u16 adc_code, + int *result_mdec) +{ + s64 voltage = 0, result = 0; + + vadc_scale_calib(vadc, adc_code, prop, &voltage); if (prop->calibration == VADC_CALIB_ABSOLUTE) - voltage += vadc->graph[prop->calibration].dx; + voltage = div64_s64(voltage, 1000); + + vadc_map_voltage_temp(adcmap_100k_104ef_104fb, + ARRAY_SIZE(adcmap_100k_104ef_104fb), + voltage, &result); + result *= 1000; + *result_mdec = result; - if (voltage < 0) + return 0; +} + +static int vadc_scale_die_temp(struct vadc_priv *vadc, + const struct vadc_channel_prop *prop, + u16 adc_code, int *result_mdec) +{ + const struct vadc_prescale_ratio *prescale; + s64 voltage = 0; + u64 temp; /* Temporary variable for do_div */ + + vadc_scale_calib(vadc, adc_code, prop, &voltage); + + if (voltage > 0) { + prescale = &vadc_prescale_ratios[prop->prescale]; + temp = voltage * prescale->den; + do_div(temp, prescale->num * 2); + voltage = temp; + } else { voltage = 0; + } - prescale = &vadc_prescale_ratios[prop->prescale]; + voltage -= KELVINMIL_CELSIUSMIL; + *result_mdec = voltage; + + return 0; +} + +static int vadc_scale_chg_temp(struct vadc_priv *vadc, + const struct vadc_channel_prop *prop, + u16 adc_code, int *result_mdec) +{ + const struct vadc_prescale_ratio *prescale; + s64 voltage = 0, result = 0; + vadc_scale_calib(vadc, adc_code, prop, &voltage); + + prescale = &vadc_prescale_ratios[prop->prescale]; voltage = voltage * prescale->den; + voltage = div64_s64(voltage, prescale->num); + voltage = ((PMI_CHG_SCALE_1) * (voltage * 2)); + voltage = (voltage + PMI_CHG_SCALE_2); + result = div64_s64(voltage, 1000000); + *result_mdec = result; - return div64_s64(voltage, prescale->num); + return 0; } static int vadc_decimation_from_dt(u32 value) @@ -536,6 +742,14 @@ static int vadc_avg_samples_from_dt(u32 value) return __ffs64(value); } +static struct vadc_scale_fn scale_fn[] = { + [SCALE_DEFAULT] = {vadc_scale_volt}, + [SCALE_THERM_100K_PULLUP] = {vadc_scale_therm}, + [SCALE_PMIC_THERM] = {vadc_scale_die_temp}, + [SCALE_XOTHERM] = {vadc_scale_therm}, + [SCALE_PMI_CHG_TEMP] = {vadc_scale_chg_temp}, +}; + static int vadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -552,11 +766,8 @@ static int vadc_read_raw(struct iio_dev *indio_dev, if (ret) break; - *val = vadc_calibrate(vadc, prop, adc_code); + scale_fn[prop->scale_fn].scale(vadc, prop, adc_code, val); - /* 2mV/K, return milli Celsius */ - *val /= 2; - *val -= KELVINMIL_CELSIUSMIL; return IIO_VAL_INT; case IIO_CHAN_INFO_RAW: prop = &vadc->chan_props[chan->address]; @@ -564,12 +775,8 @@ static int vadc_read_raw(struct iio_dev *indio_dev, if (ret) break; - *val = vadc_calibrate(vadc, prop, adc_code); + *val = (int)adc_code; return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = 1000; - return IIO_VAL_INT_PLUS_MICRO; default: ret = -EINVAL; break; @@ -602,22 +809,39 @@ struct vadc_channels { unsigned int prescale_index; enum iio_chan_type type; long info_mask; + unsigned int scale_fn; }; -#define VADC_CHAN(_dname, _type, _mask, _pre) \ +#define VADC_CHAN(_dname, _type, _mask, _pre, _scale) \ [VADC_##_dname] = { \ .datasheet_name = __stringify(_dname), \ .prescale_index = _pre, \ .type = _type, \ - .info_mask = _mask \ + .info_mask = _mask, \ + .scale_fn = _scale \ }, \ -#define VADC_CHAN_TEMP(_dname, _pre) \ - VADC_CHAN(_dname, IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre) \ +#define VADC_NO_CHAN(_dname, _type, _mask, _pre) \ + [VADC_##_dname] = { \ + .datasheet_name = __stringify(_dname), \ + .prescale_index = _pre, \ + .type = _type, \ + .info_mask = _mask \ + }, -#define VADC_CHAN_VOLT(_dname, _pre) \ +#define VADC_CHAN_TEMP(_dname, _pre, _scale) \ + VADC_CHAN(_dname, IIO_TEMP, \ + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), \ + _pre, _scale) \ + +#define VADC_CHAN_VOLT(_dname, _pre, _scale) \ VADC_CHAN(_dname, IIO_VOLTAGE, \ - BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\ + _pre, _scale) \ + +#define VADC_CHAN_NO_SCALE(_dname, _pre) \ + VADC_NO_CHAN(_dname, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_RAW), \ _pre) \ /* @@ -626,106 +850,106 @@ struct vadc_channels { * gaps in the array should be treated as reserved channels. */ static const struct vadc_channels vadc_chans[] = { - VADC_CHAN_VOLT(USBIN, 4) - VADC_CHAN_VOLT(DCIN, 4) - VADC_CHAN_VOLT(VCHG_SNS, 3) - VADC_CHAN_VOLT(SPARE1_03, 1) - VADC_CHAN_VOLT(USB_ID_MV, 1) - VADC_CHAN_VOLT(VCOIN, 1) - VADC_CHAN_VOLT(VBAT_SNS, 1) - VADC_CHAN_VOLT(VSYS, 1) - VADC_CHAN_TEMP(DIE_TEMP, 0) - VADC_CHAN_VOLT(REF_625MV, 0) - VADC_CHAN_VOLT(REF_1250MV, 0) - VADC_CHAN_VOLT(CHG_TEMP, 0) - VADC_CHAN_VOLT(SPARE1, 0) - VADC_CHAN_VOLT(SPARE2, 0) - VADC_CHAN_VOLT(GND_REF, 0) - VADC_CHAN_VOLT(VDD_VADC, 0) - - VADC_CHAN_VOLT(P_MUX1_1_1, 0) - VADC_CHAN_VOLT(P_MUX2_1_1, 0) - VADC_CHAN_VOLT(P_MUX3_1_1, 0) - VADC_CHAN_VOLT(P_MUX4_1_1, 0) - VADC_CHAN_VOLT(P_MUX5_1_1, 0) - VADC_CHAN_VOLT(P_MUX6_1_1, 0) - VADC_CHAN_VOLT(P_MUX7_1_1, 0) - VADC_CHAN_VOLT(P_MUX8_1_1, 0) - VADC_CHAN_VOLT(P_MUX9_1_1, 0) - VADC_CHAN_VOLT(P_MUX10_1_1, 0) - VADC_CHAN_VOLT(P_MUX11_1_1, 0) - VADC_CHAN_VOLT(P_MUX12_1_1, 0) - VADC_CHAN_VOLT(P_MUX13_1_1, 0) - VADC_CHAN_VOLT(P_MUX14_1_1, 0) - VADC_CHAN_VOLT(P_MUX15_1_1, 0) - VADC_CHAN_VOLT(P_MUX16_1_1, 0) - - VADC_CHAN_VOLT(P_MUX1_1_3, 1) - VADC_CHAN_VOLT(P_MUX2_1_3, 1) - VADC_CHAN_VOLT(P_MUX3_1_3, 1) - VADC_CHAN_VOLT(P_MUX4_1_3, 1) - VADC_CHAN_VOLT(P_MUX5_1_3, 1) - VADC_CHAN_VOLT(P_MUX6_1_3, 1) - VADC_CHAN_VOLT(P_MUX7_1_3, 1) - VADC_CHAN_VOLT(P_MUX8_1_3, 1) - VADC_CHAN_VOLT(P_MUX9_1_3, 1) - VADC_CHAN_VOLT(P_MUX10_1_3, 1) - VADC_CHAN_VOLT(P_MUX11_1_3, 1) - VADC_CHAN_VOLT(P_MUX12_1_3, 1) - VADC_CHAN_VOLT(P_MUX13_1_3, 1) - VADC_CHAN_VOLT(P_MUX14_1_3, 1) - VADC_CHAN_VOLT(P_MUX15_1_3, 1) - VADC_CHAN_VOLT(P_MUX16_1_3, 1) - - VADC_CHAN_VOLT(LR_MUX1_BAT_THERM, 0) - VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_XO_THERM, 0) - VADC_CHAN_VOLT(LR_MUX4_AMUX_THM1, 0) - VADC_CHAN_VOLT(LR_MUX5_AMUX_THM2, 0) - VADC_CHAN_VOLT(LR_MUX6_AMUX_THM3, 0) - VADC_CHAN_VOLT(LR_MUX7_HW_ID, 0) - VADC_CHAN_VOLT(LR_MUX8_AMUX_THM4, 0) - VADC_CHAN_VOLT(LR_MUX9_AMUX_THM5, 0) - VADC_CHAN_VOLT(LR_MUX10_USB_ID, 0) - VADC_CHAN_VOLT(AMUX_PU1, 0) - VADC_CHAN_VOLT(AMUX_PU2, 0) - VADC_CHAN_VOLT(LR_MUX3_BUF_XO_THERM, 0) - - VADC_CHAN_VOLT(LR_MUX1_PU1_BAT_THERM, 0) - VADC_CHAN_VOLT(LR_MUX2_PU1_BAT_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_PU1_XO_THERM, 0) - VADC_CHAN_VOLT(LR_MUX4_PU1_AMUX_THM1, 0) - VADC_CHAN_VOLT(LR_MUX5_PU1_AMUX_THM2, 0) - VADC_CHAN_VOLT(LR_MUX6_PU1_AMUX_THM3, 0) - VADC_CHAN_VOLT(LR_MUX7_PU1_AMUX_HW_ID, 0) - VADC_CHAN_VOLT(LR_MUX8_PU1_AMUX_THM4, 0) - VADC_CHAN_VOLT(LR_MUX9_PU1_AMUX_THM5, 0) - VADC_CHAN_VOLT(LR_MUX10_PU1_AMUX_USB_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_XO_THERM, 0) - - VADC_CHAN_VOLT(LR_MUX1_PU2_BAT_THERM, 0) - VADC_CHAN_VOLT(LR_MUX2_PU2_BAT_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_PU2_XO_THERM, 0) - VADC_CHAN_VOLT(LR_MUX4_PU2_AMUX_THM1, 0) - VADC_CHAN_VOLT(LR_MUX5_PU2_AMUX_THM2, 0) - VADC_CHAN_VOLT(LR_MUX6_PU2_AMUX_THM3, 0) - VADC_CHAN_VOLT(LR_MUX7_PU2_AMUX_HW_ID, 0) - VADC_CHAN_VOLT(LR_MUX8_PU2_AMUX_THM4, 0) - VADC_CHAN_VOLT(LR_MUX9_PU2_AMUX_THM5, 0) - VADC_CHAN_VOLT(LR_MUX10_PU2_AMUX_USB_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_BUF_PU2_XO_THERM, 0) - - VADC_CHAN_VOLT(LR_MUX1_PU1_PU2_BAT_THERM, 0) - VADC_CHAN_VOLT(LR_MUX2_PU1_PU2_BAT_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_PU1_PU2_XO_THERM, 0) - VADC_CHAN_VOLT(LR_MUX4_PU1_PU2_AMUX_THM1, 0) - VADC_CHAN_VOLT(LR_MUX5_PU1_PU2_AMUX_THM2, 0) - VADC_CHAN_VOLT(LR_MUX6_PU1_PU2_AMUX_THM3, 0) - VADC_CHAN_VOLT(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0) - VADC_CHAN_VOLT(LR_MUX8_PU1_PU2_AMUX_THM4, 0) - VADC_CHAN_VOLT(LR_MUX9_PU1_PU2_AMUX_THM5, 0) - VADC_CHAN_VOLT(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0) - VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0) + VADC_CHAN_VOLT(USBIN, 4, SCALE_DEFAULT) + VADC_CHAN_VOLT(DCIN, 4, SCALE_DEFAULT) + VADC_CHAN_NO_SCALE(VCHG_SNS, 3) + VADC_CHAN_NO_SCALE(SPARE1_03, 1) + VADC_CHAN_NO_SCALE(USB_ID_MV, 1) + VADC_CHAN_VOLT(VCOIN, 1, SCALE_DEFAULT) + VADC_CHAN_NO_SCALE(VBAT_SNS, 1) + VADC_CHAN_VOLT(VSYS, 1, SCALE_DEFAULT) + VADC_CHAN_TEMP(DIE_TEMP, 0, SCALE_PMIC_THERM) + VADC_CHAN_VOLT(REF_625MV, 0, SCALE_DEFAULT) + VADC_CHAN_VOLT(REF_1250MV, 0, SCALE_DEFAULT) + VADC_CHAN_NO_SCALE(CHG_TEMP, 0) + VADC_CHAN_NO_SCALE(SPARE1, 0) + VADC_CHAN_TEMP(SPARE2, 0, SCALE_PMI_CHG_TEMP) + VADC_CHAN_VOLT(GND_REF, 0, SCALE_DEFAULT) + VADC_CHAN_VOLT(VDD_VADC, 0, SCALE_DEFAULT) + + VADC_CHAN_NO_SCALE(P_MUX1_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX2_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX3_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX4_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX5_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX6_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX7_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX8_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX9_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX10_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX11_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX12_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX13_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX14_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX15_1_1, 0) + VADC_CHAN_NO_SCALE(P_MUX16_1_1, 0) + + VADC_CHAN_NO_SCALE(P_MUX1_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX2_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX3_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX4_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX5_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX6_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX7_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX8_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX9_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX10_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX11_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX12_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX13_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX14_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX15_1_3, 1) + VADC_CHAN_NO_SCALE(P_MUX16_1_3, 1) + + VADC_CHAN_NO_SCALE(LR_MUX1_BAT_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX2_BAT_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_XO_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX4_AMUX_THM1, 0) + VADC_CHAN_NO_SCALE(LR_MUX5_AMUX_THM2, 0) + VADC_CHAN_NO_SCALE(LR_MUX6_AMUX_THM3, 0) + VADC_CHAN_NO_SCALE(LR_MUX7_HW_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX8_AMUX_THM4, 0) + VADC_CHAN_NO_SCALE(LR_MUX9_AMUX_THM5, 0) + VADC_CHAN_NO_SCALE(LR_MUX10_USB_ID, 0) + VADC_CHAN_NO_SCALE(AMUX_PU1, 0) + VADC_CHAN_NO_SCALE(AMUX_PU2, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_BUF_XO_THERM, 0) + + VADC_CHAN_NO_SCALE(LR_MUX1_PU1_BAT_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX2_PU1_BAT_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_PU1_XO_THERM, 0) + VADC_CHAN_TEMP(LR_MUX4_PU1_AMUX_THM1, 0, SCALE_THERM_100K_PULLUP) + VADC_CHAN_TEMP(LR_MUX5_PU1_AMUX_THM2, 0, SCALE_THERM_100K_PULLUP) + VADC_CHAN_TEMP(LR_MUX6_PU1_AMUX_THM3, 0, SCALE_THERM_100K_PULLUP) + VADC_CHAN_NO_SCALE(LR_MUX7_PU1_AMUX_HW_ID, 0) + VADC_CHAN_TEMP(LR_MUX8_PU1_AMUX_THM4, 0, SCALE_THERM_100K_PULLUP) + VADC_CHAN_TEMP(LR_MUX9_PU1_AMUX_THM5, 0, SCALE_THERM_100K_PULLUP) + VADC_CHAN_NO_SCALE(LR_MUX10_PU1_AMUX_USB_ID, 0) + VADC_CHAN_TEMP(LR_MUX3_BUF_PU1_XO_THERM, 0, SCALE_XOTHERM) + + VADC_CHAN_NO_SCALE(LR_MUX1_PU2_BAT_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX2_PU2_BAT_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_PU2_XO_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX4_PU2_AMUX_THM1, 0) + VADC_CHAN_NO_SCALE(LR_MUX5_PU2_AMUX_THM2, 0) + VADC_CHAN_NO_SCALE(LR_MUX6_PU2_AMUX_THM3, 0) + VADC_CHAN_NO_SCALE(LR_MUX7_PU2_AMUX_HW_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX8_PU2_AMUX_THM4, 0) + VADC_CHAN_NO_SCALE(LR_MUX9_PU2_AMUX_THM5, 0) + VADC_CHAN_NO_SCALE(LR_MUX10_PU2_AMUX_USB_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_BUF_PU2_XO_THERM, 0) + + VADC_CHAN_NO_SCALE(LR_MUX1_PU1_PU2_BAT_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX2_PU1_PU2_BAT_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_PU1_PU2_XO_THERM, 0) + VADC_CHAN_NO_SCALE(LR_MUX4_PU1_PU2_AMUX_THM1, 0) + VADC_CHAN_NO_SCALE(LR_MUX5_PU1_PU2_AMUX_THM2, 0) + VADC_CHAN_NO_SCALE(LR_MUX6_PU1_PU2_AMUX_THM3, 0) + VADC_CHAN_NO_SCALE(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX8_PU1_PU2_AMUX_THM4, 0) + VADC_CHAN_NO_SCALE(LR_MUX9_PU1_PU2_AMUX_THM5, 0) + VADC_CHAN_NO_SCALE(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0) + VADC_CHAN_NO_SCALE(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0) }; static int vadc_get_dt_channel_data(struct device *dev, @@ -844,6 +1068,7 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node) return ret; } + prop.scale_fn = vadc_chans[prop.channel].scale_fn; vadc->chan_props[index] = prop; vadc_chan = &vadc_chans[prop.channel]; diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c new file mode 100644 index 000000000000..0c44f72c32a8 --- /dev/null +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -0,0 +1,631 @@ +/* + * Renesas R-Car GyroADC driver + * + * Copyright 2016 Marek Vasut <marek.vasut@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/err.h> +#include <linux/pm_runtime.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> + +#define DRIVER_NAME "rcar-gyroadc" + +/* GyroADC registers. */ +#define RCAR_GYROADC_MODE_SELECT 0x00 +#define RCAR_GYROADC_MODE_SELECT_1_MB88101A 0x0 +#define RCAR_GYROADC_MODE_SELECT_2_ADCS7476 0x1 +#define RCAR_GYROADC_MODE_SELECT_3_MAX1162 0x3 + +#define RCAR_GYROADC_START_STOP 0x04 +#define RCAR_GYROADC_START_STOP_START BIT(0) + +#define RCAR_GYROADC_CLOCK_LENGTH 0x08 +#define RCAR_GYROADC_1_25MS_LENGTH 0x0c + +#define RCAR_GYROADC_REALTIME_DATA(ch) (0x10 + ((ch) * 4)) +#define RCAR_GYROADC_100MS_ADDED_DATA(ch) (0x30 + ((ch) * 4)) +#define RCAR_GYROADC_10MS_AVG_DATA(ch) (0x50 + ((ch) * 4)) + +#define RCAR_GYROADC_FIFO_STATUS 0x70 +#define RCAR_GYROADC_FIFO_STATUS_EMPTY(ch) BIT(0 + (4 * (ch))) +#define RCAR_GYROADC_FIFO_STATUS_FULL(ch) BIT(1 + (4 * (ch))) +#define RCAR_GYROADC_FIFO_STATUS_ERROR(ch) BIT(2 + (4 * (ch))) + +#define RCAR_GYROADC_INTR 0x74 +#define RCAR_GYROADC_INTR_INT BIT(0) + +#define RCAR_GYROADC_INTENR 0x78 +#define RCAR_GYROADC_INTENR_INTEN BIT(0) + +#define RCAR_GYROADC_SAMPLE_RATE 800 /* Hz */ + +#define RCAR_GYROADC_RUNTIME_PM_DELAY_MS 2000 + +enum rcar_gyroadc_model { + RCAR_GYROADC_MODEL_DEFAULT, + RCAR_GYROADC_MODEL_R8A7792, +}; + +struct rcar_gyroadc { + struct device *dev; + void __iomem *regs; + struct clk *iclk; + struct regulator *vref[8]; + unsigned int num_channels; + enum rcar_gyroadc_model model; + unsigned int mode; + unsigned int sample_width; +}; + +static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv) +{ + const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000; + const unsigned long clk_mul = + (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5; + unsigned long clk_len = clk_mhz * clk_mul; + + /* + * According to the R-Car Gen2 datasheet Rev. 1.01, Sept 08 2014, + * page 77-7, clock length must be even number. If it's odd number, + * add one. + */ + if (clk_len & 1) + clk_len++; + + /* Stop the GyroADC. */ + writel(0, priv->regs + RCAR_GYROADC_START_STOP); + + /* Disable IRQ on V2H. */ + if (priv->model == RCAR_GYROADC_MODEL_R8A7792) + writel(0, priv->regs + RCAR_GYROADC_INTENR); + + /* Set mode and timing. */ + writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT); + writel(clk_len, priv->regs + RCAR_GYROADC_CLOCK_LENGTH); + writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH); +} + +static void rcar_gyroadc_hw_start(struct rcar_gyroadc *priv) +{ + /* Start sampling. */ + writel(RCAR_GYROADC_START_STOP_START, + priv->regs + RCAR_GYROADC_START_STOP); + + /* + * Wait for the first conversion to complete. This is longer than + * the 1.25 mS in the datasheet because 1.25 mS is not enough for + * the hardware to deliver the first sample and the hardware does + * then return zeroes instead of valid data. + */ + mdelay(3); +} + +static void rcar_gyroadc_hw_stop(struct rcar_gyroadc *priv) +{ + /* Stop the GyroADC. */ + writel(0, priv->regs + RCAR_GYROADC_START_STOP); +} + +#define RCAR_GYROADC_CHAN(_idx) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +} + +static const struct iio_chan_spec rcar_gyroadc_iio_channels_1[] = { + RCAR_GYROADC_CHAN(0), + RCAR_GYROADC_CHAN(1), + RCAR_GYROADC_CHAN(2), + RCAR_GYROADC_CHAN(3), +}; + +static const struct iio_chan_spec rcar_gyroadc_iio_channels_2[] = { + RCAR_GYROADC_CHAN(0), + RCAR_GYROADC_CHAN(1), + RCAR_GYROADC_CHAN(2), + RCAR_GYROADC_CHAN(3), + RCAR_GYROADC_CHAN(4), + RCAR_GYROADC_CHAN(5), + RCAR_GYROADC_CHAN(6), + RCAR_GYROADC_CHAN(7), +}; + +static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = { + RCAR_GYROADC_CHAN(0), + RCAR_GYROADC_CHAN(1), + RCAR_GYROADC_CHAN(2), + RCAR_GYROADC_CHAN(3), + RCAR_GYROADC_CHAN(4), + RCAR_GYROADC_CHAN(5), + RCAR_GYROADC_CHAN(6), + RCAR_GYROADC_CHAN(7), +}; + +static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) +{ + struct device *dev = priv->dev; + int ret; + + if (on) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) + pm_runtime_put_noidle(dev); + } else { + pm_runtime_mark_last_busy(dev); + ret = pm_runtime_put_autosuspend(dev); + } + + return ret; +} + +static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rcar_gyroadc *priv = iio_priv(indio_dev); + struct regulator *consumer; + unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel); + unsigned int vref; + int ret; + + /* + * MB88101 is special in that it has only single regulator for + * all four channels. + */ + if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) + consumer = priv->vref[0]; + else + consumer = priv->vref[chan->channel]; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type != IIO_VOLTAGE) + return -EINVAL; + + /* Channel not connected. */ + if (!consumer) + return -EINVAL; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = rcar_gyroadc_set_power(priv, true); + if (ret < 0) { + iio_device_release_direct_mode(indio_dev); + return ret; + } + + *val = readl(priv->regs + datareg); + *val &= BIT(priv->sample_width) - 1; + + ret = rcar_gyroadc_set_power(priv, false); + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* Channel not connected. */ + if (!consumer) + return -EINVAL; + + vref = regulator_get_voltage(consumer); + *val = vref / 1000; + *val2 = 1 << priv->sample_width; + + return IIO_VAL_FRACTIONAL; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = RCAR_GYROADC_SAMPLE_RATE; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int rcar_gyroadc_reg_access(struct iio_dev *indio_dev, + unsigned int reg, unsigned int writeval, + unsigned int *readval) +{ + struct rcar_gyroadc *priv = iio_priv(indio_dev); + unsigned int maxreg = RCAR_GYROADC_FIFO_STATUS; + + if (readval == NULL) + return -EINVAL; + + if (reg % 4) + return -EINVAL; + + /* Handle the V2H case with extra interrupt block. */ + if (priv->model == RCAR_GYROADC_MODEL_R8A7792) + maxreg = RCAR_GYROADC_INTENR; + + if (reg > maxreg) + return -EINVAL; + + *readval = readl(priv->regs + reg); + + return 0; +} + +static const struct iio_info rcar_gyroadc_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = rcar_gyroadc_read_raw, + .debugfs_reg_access = rcar_gyroadc_reg_access, +}; + +static const struct of_device_id rcar_gyroadc_match[] = { + { + /* R-Car compatible GyroADC */ + .compatible = "renesas,rcar-gyroadc", + .data = (void *)RCAR_GYROADC_MODEL_DEFAULT, + }, { + /* R-Car V2H specialty with interrupt registers. */ + .compatible = "renesas,r8a7792-gyroadc", + .data = (void *)RCAR_GYROADC_MODEL_R8A7792, + }, { + /* sentinel */ + } +}; + +MODULE_DEVICE_TABLE(of, rcar_gyroadc_match); + +static const struct of_device_id rcar_gyroadc_child_match[] = { + /* Mode 1 ADCs */ + { + .compatible = "fujitsu,mb88101a", + .data = (void *)RCAR_GYROADC_MODE_SELECT_1_MB88101A, + }, + /* Mode 2 ADCs */ + { + .compatible = "ti,adcs7476", + .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, + }, { + .compatible = "ti,adc121", + .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, + }, { + .compatible = "adi,ad7476", + .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, + }, + /* Mode 3 ADCs */ + { + .compatible = "maxim,max1162", + .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, + }, { + .compatible = "maxim,max11100", + .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, + }, + { /* sentinel */ } +}; + +static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) +{ + const struct of_device_id *of_id; + const struct iio_chan_spec *channels; + struct rcar_gyroadc *priv = iio_priv(indio_dev); + struct device *dev = priv->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + struct regulator *vref; + unsigned int reg; + unsigned int adcmode, childmode; + unsigned int sample_width; + unsigned int num_channels; + int ret, first = 1; + + for_each_child_of_node(np, child) { + of_id = of_match_node(rcar_gyroadc_child_match, child); + if (!of_id) { + dev_err(dev, "Ignoring unsupported ADC \"%s\".", + child->name); + continue; + } + + childmode = (unsigned int)of_id->data; + switch (childmode) { + case RCAR_GYROADC_MODE_SELECT_1_MB88101A: + sample_width = 12; + channels = rcar_gyroadc_iio_channels_1; + num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_1); + break; + case RCAR_GYROADC_MODE_SELECT_2_ADCS7476: + sample_width = 15; + channels = rcar_gyroadc_iio_channels_2; + num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_2); + break; + case RCAR_GYROADC_MODE_SELECT_3_MAX1162: + sample_width = 16; + channels = rcar_gyroadc_iio_channels_3; + num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3); + break; + } + + /* + * MB88101 is special in that it's only a single chip taking + * up all the CHS lines. Thus, the DT binding is also special + * and has no reg property. If we run into such ADC, handle + * it here. + */ + if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) { + reg = 0; + } else { + ret = of_property_read_u32(child, "reg", ®); + if (ret) { + dev_err(dev, + "Failed to get child reg property of ADC \"%s\".\n", + child->name); + return ret; + } + + /* Channel number is too high. */ + if (reg >= num_channels) { + dev_err(dev, + "Only %i channels supported with %s, but reg = <%i>.\n", + num_channels, child->name, reg); + return ret; + } + } + + /* Child node selected different mode than the rest. */ + if (!first && (adcmode != childmode)) { + dev_err(dev, + "Channel %i uses different ADC mode than the rest.\n", + reg); + return ret; + } + + /* Channel is valid, grab the regulator. */ + dev->of_node = child; + vref = devm_regulator_get(dev, "vref"); + dev->of_node = np; + if (IS_ERR(vref)) { + dev_dbg(dev, "Channel %i 'vref' supply not connected.\n", + reg); + return PTR_ERR(vref); + } + + priv->vref[reg] = vref; + + if (!first) + continue; + + /* First child node which passed sanity tests. */ + adcmode = childmode; + first = 0; + + priv->num_channels = num_channels; + priv->mode = childmode; + priv->sample_width = sample_width; + + indio_dev->channels = channels; + indio_dev->num_channels = num_channels; + + /* + * MB88101 is special and we only have one such device + * attached to the GyroADC at a time, so if we found it, + * we can stop parsing here. + */ + if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) + break; + } + + if (first) { + dev_err(dev, "No valid ADC channels found, aborting.\n"); + return -EINVAL; + } + + return 0; +} + +static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev) +{ + struct rcar_gyroadc *priv = iio_priv(indio_dev); + unsigned int i; + + for (i = 0; i < priv->num_channels; i++) { + if (!priv->vref[i]) + continue; + + regulator_disable(priv->vref[i]); + } +} + +static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev) +{ + struct rcar_gyroadc *priv = iio_priv(indio_dev); + struct device *dev = priv->dev; + unsigned int i; + int ret; + + for (i = 0; i < priv->num_channels; i++) { + if (!priv->vref[i]) + continue; + + ret = regulator_enable(priv->vref[i]); + if (ret) { + dev_err(dev, "Failed to enable regulator %i (ret=%i)\n", + i, ret); + goto err; + } + } + + return 0; + +err: + rcar_gyroadc_deinit_supplies(indio_dev); + return ret; +} + +static int rcar_gyroadc_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(rcar_gyroadc_match, &pdev->dev); + struct device *dev = &pdev->dev; + struct rcar_gyroadc *priv; + struct iio_dev *indio_dev; + struct resource *mem; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) { + dev_err(dev, "Failed to allocate IIO device.\n"); + return -ENOMEM; + } + + priv = iio_priv(indio_dev); + priv->dev = dev; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + priv->iclk = devm_clk_get(dev, "if"); + if (IS_ERR(priv->iclk)) { + ret = PTR_ERR(priv->iclk); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret); + return ret; + } + + ret = rcar_gyroadc_parse_subdevs(indio_dev); + if (ret) + return ret; + + ret = rcar_gyroadc_init_supplies(indio_dev); + if (ret) + return ret; + + priv->model = (enum rcar_gyroadc_model)of_id->data; + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = DRIVER_NAME; + indio_dev->dev.parent = dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &rcar_gyroadc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = clk_prepare_enable(priv->iclk); + if (ret) { + dev_err(dev, "Could not prepare or enable the IF clock.\n"); + goto err_clk_if_enable; + } + + pm_runtime_set_autosuspend_delay(dev, RCAR_GYROADC_RUNTIME_PM_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + pm_runtime_get_sync(dev); + rcar_gyroadc_hw_init(priv); + rcar_gyroadc_hw_start(priv); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(dev, "Couldn't register IIO device.\n"); + goto err_iio_device_register; + } + + pm_runtime_put_sync(dev); + + return 0; + +err_iio_device_register: + rcar_gyroadc_hw_stop(priv); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + clk_disable_unprepare(priv->iclk); +err_clk_if_enable: + rcar_gyroadc_deinit_supplies(indio_dev); + + return ret; +} + +static int rcar_gyroadc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct rcar_gyroadc *priv = iio_priv(indio_dev); + struct device *dev = priv->dev; + + iio_device_unregister(indio_dev); + pm_runtime_get_sync(dev); + rcar_gyroadc_hw_stop(priv); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + clk_disable_unprepare(priv->iclk); + rcar_gyroadc_deinit_supplies(indio_dev); + + return 0; +} + +#if defined(CONFIG_PM) +static int rcar_gyroadc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rcar_gyroadc *priv = iio_priv(indio_dev); + + rcar_gyroadc_hw_stop(priv); + + return 0; +} + +static int rcar_gyroadc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rcar_gyroadc *priv = iio_priv(indio_dev); + + rcar_gyroadc_hw_start(priv); + + return 0; +} +#endif + +static const struct dev_pm_ops rcar_gyroadc_pm_ops = { + SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL) +}; + +static struct platform_driver rcar_gyroadc_driver = { + .probe = rcar_gyroadc_probe, + .remove = rcar_gyroadc_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = rcar_gyroadc_match, + .pm = &rcar_gyroadc_pm_ops, + }, +}; + +module_platform_driver(rcar_gyroadc_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); +MODULE_DESCRIPTION("Renesas R-Car GyroADC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 4214b0cd6b1b..22b7c9321e78 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -201,6 +201,7 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->common.base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(priv->common.base)) return PTR_ERR(priv->common.base); + priv->common.phys_base = res->start; priv->vref = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(priv->vref)) { diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h index 081fa5f55015..2ec7abbfbcaa 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -42,10 +42,12 @@ /** * struct stm32_adc_common - stm32 ADC driver common data (for all instances) * @base: control registers base cpu addr + * @phys_base: control registers base physical addr * @vref_mv: vref voltage (mv) */ struct stm32_adc_common { void __iomem *base; + phys_addr_t phys_base; int vref_mv; }; diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 5715e79f4935..9b49a6addc2a 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -21,7 +21,14 @@ #include <linux/clk.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/timer/stm32-timer-trigger.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -58,21 +65,71 @@ /* STM32F4_ADC_CR2 - bit fields */ #define STM32F4_SWSTART BIT(30) +#define STM32F4_EXTEN_SHIFT 28 #define STM32F4_EXTEN_MASK GENMASK(29, 28) +#define STM32F4_EXTSEL_SHIFT 24 +#define STM32F4_EXTSEL_MASK GENMASK(27, 24) #define STM32F4_EOCS BIT(10) +#define STM32F4_DDS BIT(9) +#define STM32F4_DMA BIT(8) #define STM32F4_ADON BIT(0) -/* STM32F4_ADC_SQR1 - bit fields */ -#define STM32F4_L_SHIFT 20 -#define STM32F4_L_MASK GENMASK(23, 20) - -/* STM32F4_ADC_SQR3 - bit fields */ -#define STM32F4_SQ1_SHIFT 0 -#define STM32F4_SQ1_MASK GENMASK(4, 0) - +#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ #define STM32_ADC_TIMEOUT_US 100000 #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) +#define STM32_DMA_BUFFER_SIZE PAGE_SIZE + +/* External trigger enable */ +enum stm32_adc_exten { + STM32_EXTEN_SWTRIG, + STM32_EXTEN_HWTRIG_RISING_EDGE, + STM32_EXTEN_HWTRIG_FALLING_EDGE, + STM32_EXTEN_HWTRIG_BOTH_EDGES, +}; + +/* extsel - trigger mux selection value */ +enum stm32_adc_extsel { + STM32_EXT0, + STM32_EXT1, + STM32_EXT2, + STM32_EXT3, + STM32_EXT4, + STM32_EXT5, + STM32_EXT6, + STM32_EXT7, + STM32_EXT8, + STM32_EXT9, + STM32_EXT10, + STM32_EXT11, + STM32_EXT12, + STM32_EXT13, + STM32_EXT14, + STM32_EXT15, +}; + +/** + * struct stm32_adc_trig_info - ADC trigger info + * @name: name of the trigger, corresponding to its source + * @extsel: trigger selection + */ +struct stm32_adc_trig_info { + const char *name; + enum stm32_adc_extsel extsel; +}; + +/** + * stm32_adc_regs - stm32 ADC misc registers & bitfield desc + * @reg: register offset + * @mask: bitfield mask + * @shift: left shift + */ +struct stm32_adc_regs { + int reg; + int mask; + int shift; +}; + /** * struct stm32_adc - private data of each ADC IIO instance * @common: reference to ADC block common data @@ -82,15 +139,29 @@ * @clk: clock for this adc instance * @irq: interrupt for this adc instance * @lock: spinlock + * @bufi: data buffer index + * @num_conv: expected number of scan conversions + * @trigger_polarity: external trigger polarity (e.g. exten) + * @dma_chan: dma channel + * @rx_buf: dma rx buffer cpu address + * @rx_dma_buf: dma rx buffer bus address + * @rx_buf_sz: dma rx buffer size */ struct stm32_adc { struct stm32_adc_common *common; u32 offset; struct completion completion; - u16 *buffer; + u16 buffer[STM32_ADC_MAX_SQ]; struct clk *clk; int irq; spinlock_t lock; /* interrupt lock */ + unsigned int bufi; + unsigned int num_conv; + u32 trigger_polarity; + struct dma_chan *dma_chan; + u8 *rx_buf; + dma_addr_t rx_dma_buf; + unsigned int rx_buf_sz; }; /** @@ -126,6 +197,53 @@ static const struct stm32_adc_chan_spec stm32f4_adc123_channels[] = { }; /** + * stm32f4_sq - describe regular sequence registers + * - L: sequence len (register & bit field) + * - SQ1..SQ16: sequence entries (register & bit field) + */ +static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = { + /* L: len bit field description to be kept as first element */ + { STM32F4_ADC_SQR1, GENMASK(23, 20), 20 }, + /* SQ1..SQ16 registers & bit fields (reg, mask, shift) */ + { STM32F4_ADC_SQR3, GENMASK(4, 0), 0 }, + { STM32F4_ADC_SQR3, GENMASK(9, 5), 5 }, + { STM32F4_ADC_SQR3, GENMASK(14, 10), 10 }, + { STM32F4_ADC_SQR3, GENMASK(19, 15), 15 }, + { STM32F4_ADC_SQR3, GENMASK(24, 20), 20 }, + { STM32F4_ADC_SQR3, GENMASK(29, 25), 25 }, + { STM32F4_ADC_SQR2, GENMASK(4, 0), 0 }, + { STM32F4_ADC_SQR2, GENMASK(9, 5), 5 }, + { STM32F4_ADC_SQR2, GENMASK(14, 10), 10 }, + { STM32F4_ADC_SQR2, GENMASK(19, 15), 15 }, + { STM32F4_ADC_SQR2, GENMASK(24, 20), 20 }, + { STM32F4_ADC_SQR2, GENMASK(29, 25), 25 }, + { STM32F4_ADC_SQR1, GENMASK(4, 0), 0 }, + { STM32F4_ADC_SQR1, GENMASK(9, 5), 5 }, + { STM32F4_ADC_SQR1, GENMASK(14, 10), 10 }, + { STM32F4_ADC_SQR1, GENMASK(19, 15), 15 }, +}; + +/* STM32F4 external trigger sources for all instances */ +static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { + { TIM1_CH1, STM32_EXT0 }, + { TIM1_CH2, STM32_EXT1 }, + { TIM1_CH3, STM32_EXT2 }, + { TIM2_CH2, STM32_EXT3 }, + { TIM2_CH3, STM32_EXT4 }, + { TIM2_CH4, STM32_EXT5 }, + { TIM2_TRGO, STM32_EXT6 }, + { TIM3_CH1, STM32_EXT7 }, + { TIM3_TRGO, STM32_EXT8 }, + { TIM4_CH4, STM32_EXT9 }, + { TIM5_CH1, STM32_EXT10 }, + { TIM5_CH2, STM32_EXT11 }, + { TIM5_CH3, STM32_EXT12 }, + { TIM8_CH1, STM32_EXT13 }, + { TIM8_TRGO, STM32_EXT14 }, + {}, /* sentinel */ +}; + +/** * STM32 ADC registers access routines * @adc: stm32 adc instance * @reg: reg offset in adc instance @@ -187,10 +305,21 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) /** * stm32_adc_start_conv() - Start conversions for regular channels. * @adc: stm32 adc instance + * @dma: use dma to transfer conversion result + * + * Start conversions for regular channels. + * Also take care of normal or DMA mode. Circular DMA may be used for regular + * conversions, in IIO buffer modes. Otherwise, use ADC interrupt with direct + * DR read instead (e.g. read_raw, or triggered buffer mode without DMA). */ -static void stm32_adc_start_conv(struct stm32_adc *adc) +static void stm32_adc_start_conv(struct stm32_adc *adc, bool dma) { stm32_adc_set_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); + + if (dma) + stm32_adc_set_bits(adc, STM32F4_ADC_CR2, + STM32F4_DMA | STM32F4_DDS); + stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_EOCS | STM32F4_ADON); /* Wait for Power-up time (tSTAB from datasheet) */ @@ -207,10 +336,153 @@ static void stm32_adc_stop_conv(struct stm32_adc *adc) stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_STRT); stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN); - stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_ADON); + stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, + STM32F4_ADON | STM32F4_DMA | STM32F4_DDS); +} + +/** + * stm32_adc_conf_scan_seq() - Build regular channels scan sequence + * @indio_dev: IIO device + * @scan_mask: channels to be converted + * + * Conversion sequence : + * Configure ADC scan sequence based on selected channels in scan_mask. + * Add channels to SQR registers, from scan_mask LSB to MSB, then + * program sequence len. + */ +static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + const struct iio_chan_spec *chan; + u32 val, bit; + int i = 0; + + for_each_set_bit(bit, scan_mask, indio_dev->masklength) { + chan = indio_dev->channels + bit; + /* + * Assign one channel per SQ entry in regular + * sequence, starting with SQ1. + */ + i++; + if (i > STM32_ADC_MAX_SQ) + return -EINVAL; + + dev_dbg(&indio_dev->dev, "%s chan %d to SQ%d\n", + __func__, chan->channel, i); + + val = stm32_adc_readl(adc, stm32f4_sq[i].reg); + val &= ~stm32f4_sq[i].mask; + val |= chan->channel << stm32f4_sq[i].shift; + stm32_adc_writel(adc, stm32f4_sq[i].reg, val); + } + + if (!i) + return -EINVAL; + + /* Sequence len */ + val = stm32_adc_readl(adc, stm32f4_sq[0].reg); + val &= ~stm32f4_sq[0].mask; + val |= ((i - 1) << stm32f4_sq[0].shift); + stm32_adc_writel(adc, stm32f4_sq[0].reg, val); + + return 0; +} + +/** + * stm32_adc_get_trig_extsel() - Get external trigger selection + * @trig: trigger + * + * Returns trigger extsel value, if trig matches, -EINVAL otherwise. + */ +static int stm32_adc_get_trig_extsel(struct iio_trigger *trig) +{ + int i; + + /* lookup triggers registered by stm32 timer trigger driver */ + for (i = 0; stm32f4_adc_trigs[i].name; i++) { + /** + * Checking both stm32 timer trigger type and trig name + * should be safe against arbitrary trigger names. + */ + if (is_stm32_timer_trigger(trig) && + !strcmp(stm32f4_adc_trigs[i].name, trig->name)) { + return stm32f4_adc_trigs[i].extsel; + } + } + + return -EINVAL; } /** + * stm32_adc_set_trig() - Set a regular trigger + * @indio_dev: IIO device + * @trig: IIO trigger + * + * Set trigger source/polarity (e.g. SW, or HW with polarity) : + * - if HW trigger disabled (e.g. trig == NULL, conversion launched by sw) + * - if HW trigger enabled, set source & polarity + */ +static int stm32_adc_set_trig(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u32 val, extsel = 0, exten = STM32_EXTEN_SWTRIG; + unsigned long flags; + int ret; + + if (trig) { + ret = stm32_adc_get_trig_extsel(trig); + if (ret < 0) + return ret; + + /* set trigger source and polarity (default to rising edge) */ + extsel = ret; + exten = adc->trigger_polarity + STM32_EXTEN_HWTRIG_RISING_EDGE; + } + + spin_lock_irqsave(&adc->lock, flags); + val = stm32_adc_readl(adc, STM32F4_ADC_CR2); + val &= ~(STM32F4_EXTEN_MASK | STM32F4_EXTSEL_MASK); + val |= exten << STM32F4_EXTEN_SHIFT; + val |= extsel << STM32F4_EXTSEL_SHIFT; + stm32_adc_writel(adc, STM32F4_ADC_CR2, val); + spin_unlock_irqrestore(&adc->lock, flags); + + return 0; +} + +static int stm32_adc_set_trig_pol(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int type) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + adc->trigger_polarity = type; + + return 0; +} + +static int stm32_adc_get_trig_pol(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + + return adc->trigger_polarity; +} + +static const char * const stm32_trig_pol_items[] = { + "rising-edge", "falling-edge", "both-edges", +}; + +static const struct iio_enum stm32_adc_trig_pol = { + .items = stm32_trig_pol_items, + .num_items = ARRAY_SIZE(stm32_trig_pol_items), + .get = stm32_adc_get_trig_pol, + .set = stm32_adc_set_trig_pol, +}; + +/** * stm32_adc_single_conv() - Performs a single conversion * @indio_dev: IIO device * @chan: IIO channel @@ -228,28 +500,27 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, struct stm32_adc *adc = iio_priv(indio_dev); long timeout; u32 val; - u16 result; int ret; reinit_completion(&adc->completion); - adc->buffer = &result; + adc->bufi = 0; - /* Program chan number in regular sequence */ - val = stm32_adc_readl(adc, STM32F4_ADC_SQR3); - val &= ~STM32F4_SQ1_MASK; - val |= chan->channel << STM32F4_SQ1_SHIFT; - stm32_adc_writel(adc, STM32F4_ADC_SQR3, val); + /* Program chan number in regular sequence (SQ1) */ + val = stm32_adc_readl(adc, stm32f4_sq[1].reg); + val &= ~stm32f4_sq[1].mask; + val |= chan->channel << stm32f4_sq[1].shift; + stm32_adc_writel(adc, stm32f4_sq[1].reg, val); /* Set regular sequence len (0 for 1 conversion) */ - stm32_adc_clr_bits(adc, STM32F4_ADC_SQR1, STM32F4_L_MASK); + stm32_adc_clr_bits(adc, stm32f4_sq[0].reg, stm32f4_sq[0].mask); /* Trigger detection disabled (conversion can be launched in SW) */ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK); stm32_adc_conv_irq_enable(adc); - stm32_adc_start_conv(adc); + stm32_adc_start_conv(adc, false); timeout = wait_for_completion_interruptible_timeout( &adc->completion, STM32_ADC_TIMEOUT); @@ -258,7 +529,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, } else if (timeout < 0) { ret = timeout; } else { - *res = result; + *res = adc->buffer[0]; ret = IIO_VAL_INT; } @@ -301,17 +572,73 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, static irqreturn_t stm32_adc_isr(int irq, void *data) { struct stm32_adc *adc = data; + struct iio_dev *indio_dev = iio_priv_to_dev(adc); u32 status = stm32_adc_readl(adc, STM32F4_ADC_SR); if (status & STM32F4_EOC) { - *adc->buffer = stm32_adc_readw(adc, STM32F4_ADC_DR); - complete(&adc->completion); + /* Reading DR also clears EOC status flag */ + adc->buffer[adc->bufi] = stm32_adc_readw(adc, STM32F4_ADC_DR); + if (iio_buffer_enabled(indio_dev)) { + adc->bufi++; + if (adc->bufi >= adc->num_conv) { + stm32_adc_conv_irq_disable(adc); + iio_trigger_poll(indio_dev->trig); + } + } else { + complete(&adc->completion); + } return IRQ_HANDLED; } return IRQ_NONE; } +/** + * stm32_adc_validate_trigger() - validate trigger for stm32 adc + * @indio_dev: IIO device + * @trig: new trigger + * + * Returns: 0 if trig matches one of the triggers registered by stm32 adc + * driver, -EINVAL otherwise. + */ +static int stm32_adc_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + return stm32_adc_get_trig_extsel(trig) < 0 ? -EINVAL : 0; +} + +static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + unsigned int watermark = STM32_DMA_BUFFER_SIZE / 2; + + /* + * dma cyclic transfers are used, buffer is split into two periods. + * There should be : + * - always one buffer (period) dma is working on + * - one buffer (period) driver can push with iio_trigger_poll(). + */ + watermark = min(watermark, val * (unsigned)(sizeof(u16))); + adc->rx_buf_sz = watermark * 2; + + return 0; +} + +static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + int ret; + + adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); + + ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); + if (ret) + return ret; + + return 0; +} + static int stm32_adc_of_xlate(struct iio_dev *indio_dev, const struct of_phandle_args *iiospec) { @@ -350,11 +677,199 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, static const struct iio_info stm32_adc_iio_info = { .read_raw = stm32_adc_read_raw, + .validate_trigger = stm32_adc_validate_trigger, + .hwfifo_set_watermark = stm32_adc_set_watermark, + .update_scan_mode = stm32_adc_update_scan_mode, .debugfs_reg_access = stm32_adc_debugfs_reg_access, .of_xlate = stm32_adc_of_xlate, .driver_module = THIS_MODULE, }; +static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) +{ + struct dma_tx_state state; + enum dma_status status; + + status = dmaengine_tx_status(adc->dma_chan, + adc->dma_chan->cookie, + &state); + if (status == DMA_IN_PROGRESS) { + /* Residue is size in bytes from end of buffer */ + unsigned int i = adc->rx_buf_sz - state.residue; + unsigned int size; + + /* Return available bytes */ + if (i >= adc->bufi) + size = i - adc->bufi; + else + size = adc->rx_buf_sz + i - adc->bufi; + + return size; + } + + return 0; +} + +static void stm32_adc_dma_buffer_done(void *data) +{ + struct iio_dev *indio_dev = data; + + iio_trigger_poll_chained(indio_dev->trig); +} + +static int stm32_adc_dma_start(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct dma_async_tx_descriptor *desc; + dma_cookie_t cookie; + int ret; + + if (!adc->dma_chan) + return 0; + + dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, + adc->rx_buf_sz, adc->rx_buf_sz / 2); + + /* Prepare a DMA cyclic transaction */ + desc = dmaengine_prep_dma_cyclic(adc->dma_chan, + adc->rx_dma_buf, + adc->rx_buf_sz, adc->rx_buf_sz / 2, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) + return -EBUSY; + + desc->callback = stm32_adc_dma_buffer_done; + desc->callback_param = indio_dev; + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { + dmaengine_terminate_all(adc->dma_chan); + return ret; + } + + /* Issue pending DMA requests */ + dma_async_issue_pending(adc->dma_chan); + + return 0; +} + +static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + int ret; + + ret = stm32_adc_set_trig(indio_dev, indio_dev->trig); + if (ret) { + dev_err(&indio_dev->dev, "Can't set trigger\n"); + return ret; + } + + ret = stm32_adc_dma_start(indio_dev); + if (ret) { + dev_err(&indio_dev->dev, "Can't start dma\n"); + goto err_clr_trig; + } + + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret < 0) + goto err_stop_dma; + + /* Reset adc buffer index */ + adc->bufi = 0; + + if (!adc->dma_chan) + stm32_adc_conv_irq_enable(adc); + + stm32_adc_start_conv(adc, !!adc->dma_chan); + + return 0; + +err_stop_dma: + if (adc->dma_chan) + dmaengine_terminate_all(adc->dma_chan); +err_clr_trig: + stm32_adc_set_trig(indio_dev, NULL); + + return ret; +} + +static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + int ret; + + stm32_adc_stop_conv(adc); + if (!adc->dma_chan) + stm32_adc_conv_irq_disable(adc); + + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret < 0) + dev_err(&indio_dev->dev, "predisable failed\n"); + + if (adc->dma_chan) + dmaengine_terminate_all(adc->dma_chan); + + if (stm32_adc_set_trig(indio_dev, NULL)) + dev_err(&indio_dev->dev, "Can't clear trigger\n"); + + return ret; +} + +static const struct iio_buffer_setup_ops stm32_adc_buffer_setup_ops = { + .postenable = &stm32_adc_buffer_postenable, + .predisable = &stm32_adc_buffer_predisable, +}; + +static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct stm32_adc *adc = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); + + if (!adc->dma_chan) { + /* reset buffer index */ + adc->bufi = 0; + iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, + pf->timestamp); + } else { + int residue = stm32_adc_dma_residue(adc); + + while (residue >= indio_dev->scan_bytes) { + u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); + residue -= indio_dev->scan_bytes; + adc->bufi += indio_dev->scan_bytes; + if (adc->bufi >= adc->rx_buf_sz) + adc->bufi = 0; + } + } + + iio_trigger_notify_done(indio_dev->trig); + + /* re-enable eoc irq */ + if (!adc->dma_chan) + stm32_adc_conv_irq_enable(adc); + + return IRQ_HANDLED; +} + +static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = { + IIO_ENUM("trigger_polarity", IIO_SHARED_BY_ALL, &stm32_adc_trig_pol), + { + .name = "trigger_polarity_available", + .shared = IIO_SHARED_BY_ALL, + .read = iio_enum_available_read, + .private = (uintptr_t)&stm32_adc_trig_pol, + }, + {}, +}; + static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, struct iio_chan_spec *chan, const struct stm32_adc_chan_spec *channel, @@ -370,6 +885,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, chan->scan_type.sign = 'u'; chan->scan_type.realbits = 12; chan->scan_type.storagebits = 16; + chan->ext_info = stm32_adc_ext_info; } static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) @@ -410,6 +926,45 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) return 0; } +static int stm32_adc_dma_request(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct dma_slave_config config; + int ret; + + adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); + if (!adc->dma_chan) + return 0; + + adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, + STM32_DMA_BUFFER_SIZE, + &adc->rx_dma_buf, GFP_KERNEL); + if (!adc->rx_buf) { + ret = -ENOMEM; + goto err_release; + } + + /* Configure DMA channel to read data register */ + memset(&config, 0, sizeof(config)); + config.src_addr = (dma_addr_t)adc->common->phys_base; + config.src_addr += adc->offset + STM32F4_ADC_DR; + config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + + ret = dmaengine_slave_config(adc->dma_chan, &config); + if (ret) + goto err_free; + + return 0; + +err_free: + dma_free_coherent(adc->dma_chan->device->dev, STM32_DMA_BUFFER_SIZE, + adc->rx_buf, adc->rx_dma_buf); +err_release: + dma_release_channel(adc->dma_chan); + + return ret; +} + static int stm32_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -471,14 +1026,37 @@ static int stm32_adc_probe(struct platform_device *pdev) if (ret < 0) goto err_clk_disable; + ret = stm32_adc_dma_request(indio_dev); + if (ret < 0) + goto err_clk_disable; + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + &stm32_adc_trigger_handler, + &stm32_adc_buffer_setup_ops); + if (ret) { + dev_err(&pdev->dev, "buffer setup failed\n"); + goto err_dma_disable; + } + ret = iio_device_register(indio_dev); if (ret) { dev_err(&pdev->dev, "iio dev register failed\n"); - goto err_clk_disable; + goto err_buffer_cleanup; } return 0; +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + +err_dma_disable: + if (adc->dma_chan) { + dma_free_coherent(adc->dma_chan->device->dev, + STM32_DMA_BUFFER_SIZE, + adc->rx_buf, adc->rx_dma_buf); + dma_release_channel(adc->dma_chan); + } err_clk_disable: clk_disable_unprepare(adc->clk); @@ -491,6 +1069,13 @@ static int stm32_adc_remove(struct platform_device *pdev) struct iio_dev *indio_dev = iio_priv_to_dev(adc); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + if (adc->dma_chan) { + dma_free_coherent(adc->dma_chan->device->dev, + STM32_DMA_BUFFER_SIZE, + adc->rx_buf, adc->rx_dma_buf); + dma_release_channel(adc->dma_chan); + } clk_disable_unprepare(adc->clk); return 0; diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c index 7e3645749eaf..be2de48844bc 100644 --- a/drivers/iio/adc/stx104.c +++ b/drivers/iio/adc/stx104.c @@ -76,16 +76,6 @@ struct stx104_gpio { unsigned int out_state; }; -/** - * struct stx104_dev - STX104 device private data structure - * @indio_dev: IIO device - * @chip: instance of the gpio_chip - */ -struct stx104_dev { - struct iio_dev *indio_dev; - struct gpio_chip *chip; -}; - static int stx104_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { @@ -266,12 +256,38 @@ static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, spin_unlock_irqrestore(&stx104gpio->lock, flags); } +#define STX104_NGPIO 8 +static const char *stx104_names[STX104_NGPIO] = { + "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3" +}; + +static void stx104_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + unsigned long flags; + + /* verify masked GPIO are output */ + if (!(*mask & 0xF0)) + return; + + *mask >>= 4; + *bits >>= 4; + + spin_lock_irqsave(&stx104gpio->lock, flags); + + stx104gpio->out_state &= ~*mask; + stx104gpio->out_state |= *mask & *bits; + outb(stx104gpio->out_state, stx104gpio->base); + + spin_unlock_irqrestore(&stx104gpio->lock, flags); +} + static int stx104_probe(struct device *dev, unsigned int id) { struct iio_dev *indio_dev; struct stx104_iio *priv; struct stx104_gpio *stx104gpio; - struct stx104_dev *stx104dev; int err; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); @@ -282,10 +298,6 @@ static int stx104_probe(struct device *dev, unsigned int id) if (!stx104gpio) return -ENOMEM; - stx104dev = devm_kzalloc(dev, sizeof(*stx104dev), GFP_KERNEL); - if (!stx104dev) - return -ENOMEM; - if (!devm_request_region(dev, base[id], STX104_EXTENT, dev_name(dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", @@ -324,45 +336,26 @@ static int stx104_probe(struct device *dev, unsigned int id) stx104gpio->chip.parent = dev; stx104gpio->chip.owner = THIS_MODULE; stx104gpio->chip.base = -1; - stx104gpio->chip.ngpio = 8; + stx104gpio->chip.ngpio = STX104_NGPIO; + stx104gpio->chip.names = stx104_names; stx104gpio->chip.get_direction = stx104_gpio_get_direction; stx104gpio->chip.direction_input = stx104_gpio_direction_input; stx104gpio->chip.direction_output = stx104_gpio_direction_output; stx104gpio->chip.get = stx104_gpio_get; stx104gpio->chip.set = stx104_gpio_set; + stx104gpio->chip.set_multiple = stx104_gpio_set_multiple; stx104gpio->base = base[id] + 3; stx104gpio->out_state = 0x0; spin_lock_init(&stx104gpio->lock); - stx104dev->indio_dev = indio_dev; - stx104dev->chip = &stx104gpio->chip; - dev_set_drvdata(dev, stx104dev); - - err = gpiochip_add_data(&stx104gpio->chip, stx104gpio); + err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio); if (err) { dev_err(dev, "GPIO registering failed (%d)\n", err); return err; } - err = iio_device_register(indio_dev); - if (err) { - dev_err(dev, "IIO device registering failed (%d)\n", err); - gpiochip_remove(&stx104gpio->chip); - return err; - } - - return 0; -} - -static int stx104_remove(struct device *dev, unsigned int id) -{ - struct stx104_dev *const stx104dev = dev_get_drvdata(dev); - - iio_device_unregister(stx104dev->indio_dev); - gpiochip_remove(stx104dev->chip); - - return 0; + return devm_iio_device_register(dev, indio_dev); } static struct isa_driver stx104_driver = { @@ -370,7 +363,6 @@ static struct isa_driver stx104_driver = { .driver = { .name = "stx104" }, - .remove = stx104_remove }; module_isa_driver(stx104_driver, num_stx104); diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index cde6f130a99a..422b314f5a3f 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -472,14 +472,14 @@ static const struct attribute_group ads1115_attribute_group = { .attrs = ads1115_attributes, }; -static struct iio_info ads1015_info = { +static const struct iio_info ads1015_info = { .driver_module = THIS_MODULE, .read_raw = ads1015_read_raw, .write_raw = ads1015_write_raw, .attrs = &ads1015_attribute_group, }; -static struct iio_info ads1115_info = { +static const struct iio_info ads1115_info = { .driver_module = THIS_MODULE, .read_raw = ads1015_read_raw, .write_raw = ads1015_write_raw, diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c new file mode 100644 index 000000000000..16a06633332c --- /dev/null +++ b/drivers/iio/adc/ti-ads7950.c @@ -0,0 +1,490 @@ +/* + * Texas Instruments ADS7950 SPI ADC driver + * + * Copyright 2016 David Lechner <david@lechnology.com> + * + * Based on iio/ad7923.c: + * Copyright 2011 Analog Devices Inc + * Copyright 2012 CS Systemes d'Information + * + * And also on hwmon/ads79xx.c + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define TI_ADS7950_CR_MANUAL BIT(12) +#define TI_ADS7950_CR_WRITE BIT(11) +#define TI_ADS7950_CR_CHAN(ch) ((ch) << 7) +#define TI_ADS7950_CR_RANGE_5V BIT(6) + +#define TI_ADS7950_MAX_CHAN 16 + +#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16)) + +/* val = value, dec = left shift, bits = number of bits of the mask */ +#define TI_ADS7950_EXTRACT(val, dec, bits) \ + (((val) >> (dec)) & ((1 << (bits)) - 1)) + +struct ti_ads7950_state { + struct spi_device *spi; + struct spi_transfer ring_xfer[TI_ADS7950_MAX_CHAN + 2]; + struct spi_transfer scan_single_xfer[3]; + struct spi_message ring_msg; + struct spi_message scan_single_msg; + + struct regulator *reg; + + unsigned int settings; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE] + ____cacheline_aligned; + __be16 tx_buf[TI_ADS7950_MAX_CHAN]; +}; + +struct ti_ads7950_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +enum ti_ads7950_id { + TI_ADS7950, + TI_ADS7951, + TI_ADS7952, + TI_ADS7953, + TI_ADS7954, + TI_ADS7955, + TI_ADS7956, + TI_ADS7957, + TI_ADS7958, + TI_ADS7959, + TI_ADS7960, + TI_ADS7961, +}; + +#define TI_ADS7950_V_CHAN(index, bits) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + .datasheet_name = "CH##index", \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = bits, \ + .storagebits = 16, \ + .shift = 12 - (bits), \ + .endianness = IIO_BE, \ + }, \ +} + +#define DECLARE_TI_ADS7950_4_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ + TI_ADS7950_V_CHAN(0, bits), \ + TI_ADS7950_V_CHAN(1, bits), \ + TI_ADS7950_V_CHAN(2, bits), \ + TI_ADS7950_V_CHAN(3, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DECLARE_TI_ADS7950_8_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ + TI_ADS7950_V_CHAN(0, bits), \ + TI_ADS7950_V_CHAN(1, bits), \ + TI_ADS7950_V_CHAN(2, bits), \ + TI_ADS7950_V_CHAN(3, bits), \ + TI_ADS7950_V_CHAN(4, bits), \ + TI_ADS7950_V_CHAN(5, bits), \ + TI_ADS7950_V_CHAN(6, bits), \ + TI_ADS7950_V_CHAN(7, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(8), \ +} + +#define DECLARE_TI_ADS7950_12_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ + TI_ADS7950_V_CHAN(0, bits), \ + TI_ADS7950_V_CHAN(1, bits), \ + TI_ADS7950_V_CHAN(2, bits), \ + TI_ADS7950_V_CHAN(3, bits), \ + TI_ADS7950_V_CHAN(4, bits), \ + TI_ADS7950_V_CHAN(5, bits), \ + TI_ADS7950_V_CHAN(6, bits), \ + TI_ADS7950_V_CHAN(7, bits), \ + TI_ADS7950_V_CHAN(8, bits), \ + TI_ADS7950_V_CHAN(9, bits), \ + TI_ADS7950_V_CHAN(10, bits), \ + TI_ADS7950_V_CHAN(11, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(12), \ +} + +#define DECLARE_TI_ADS7950_16_CHANNELS(name, bits) \ +const struct iio_chan_spec name ## _channels[] = { \ + TI_ADS7950_V_CHAN(0, bits), \ + TI_ADS7950_V_CHAN(1, bits), \ + TI_ADS7950_V_CHAN(2, bits), \ + TI_ADS7950_V_CHAN(3, bits), \ + TI_ADS7950_V_CHAN(4, bits), \ + TI_ADS7950_V_CHAN(5, bits), \ + TI_ADS7950_V_CHAN(6, bits), \ + TI_ADS7950_V_CHAN(7, bits), \ + TI_ADS7950_V_CHAN(8, bits), \ + TI_ADS7950_V_CHAN(9, bits), \ + TI_ADS7950_V_CHAN(10, bits), \ + TI_ADS7950_V_CHAN(11, bits), \ + TI_ADS7950_V_CHAN(12, bits), \ + TI_ADS7950_V_CHAN(13, bits), \ + TI_ADS7950_V_CHAN(14, bits), \ + TI_ADS7950_V_CHAN(15, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(16), \ +} + +static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7950, 12); +static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7951, 12); +static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7952, 12); +static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7953, 12); +static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7954, 10); +static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7955, 10); +static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7956, 10); +static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7957, 10); +static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7958, 8); +static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7959, 8); +static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7960, 8); +static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7961, 8); + +static const struct ti_ads7950_chip_info ti_ads7950_chip_info[] = { + [TI_ADS7950] = { + .channels = ti_ads7950_channels, + .num_channels = ARRAY_SIZE(ti_ads7950_channels), + }, + [TI_ADS7951] = { + .channels = ti_ads7951_channels, + .num_channels = ARRAY_SIZE(ti_ads7951_channels), + }, + [TI_ADS7952] = { + .channels = ti_ads7952_channels, + .num_channels = ARRAY_SIZE(ti_ads7952_channels), + }, + [TI_ADS7953] = { + .channels = ti_ads7953_channels, + .num_channels = ARRAY_SIZE(ti_ads7953_channels), + }, + [TI_ADS7954] = { + .channels = ti_ads7954_channels, + .num_channels = ARRAY_SIZE(ti_ads7954_channels), + }, + [TI_ADS7955] = { + .channels = ti_ads7955_channels, + .num_channels = ARRAY_SIZE(ti_ads7955_channels), + }, + [TI_ADS7956] = { + .channels = ti_ads7956_channels, + .num_channels = ARRAY_SIZE(ti_ads7956_channels), + }, + [TI_ADS7957] = { + .channels = ti_ads7957_channels, + .num_channels = ARRAY_SIZE(ti_ads7957_channels), + }, + [TI_ADS7958] = { + .channels = ti_ads7958_channels, + .num_channels = ARRAY_SIZE(ti_ads7958_channels), + }, + [TI_ADS7959] = { + .channels = ti_ads7959_channels, + .num_channels = ARRAY_SIZE(ti_ads7959_channels), + }, + [TI_ADS7960] = { + .channels = ti_ads7960_channels, + .num_channels = ARRAY_SIZE(ti_ads7960_channels), + }, + [TI_ADS7961] = { + .channels = ti_ads7961_channels, + .num_channels = ARRAY_SIZE(ti_ads7961_channels), + }, +}; + +/* + * ti_ads7950_update_scan_mode() setup the spi transfer buffer for the new + * scan mask + */ +static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + int i, cmd, len; + + len = 0; + for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) { + cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings; + st->tx_buf[len++] = cpu_to_be16(cmd); + } + + /* Data for the 1st channel is not returned until the 3rd transfer */ + len += 2; + for (i = 0; i < len; i++) { + if ((i + 2) < len) + st->ring_xfer[i].tx_buf = &st->tx_buf[i]; + if (i >= 2) + st->ring_xfer[i].rx_buf = &st->rx_buf[i - 2]; + st->ring_xfer[i].len = 2; + st->ring_xfer[i].cs_change = 1; + } + /* make sure last transfer's cs_change is not set */ + st->ring_xfer[len - 1].cs_change = 0; + + spi_message_init_with_transfers(&st->ring_msg, st->ring_xfer, len); + + return 0; +} + +static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ti_ads7950_state *st = iio_priv(indio_dev); + int ret; + + ret = spi_sync(st->spi, &st->ring_msg); + if (ret < 0) + goto out; + + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns(indio_dev)); + +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch) +{ + int ret, cmd; + + cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings; + st->tx_buf[0] = cpu_to_be16(cmd); + + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + return ret; + + return be16_to_cpu(st->rx_buf[0]); +} + +static int ti_ads7950_get_range(struct ti_ads7950_state *st) +{ + int vref; + + vref = regulator_get_voltage(st->reg); + if (vref < 0) + return vref; + + vref /= 1000; + + if (st->settings & TI_ADS7950_CR_RANGE_5V) + vref *= 2; + + return vref; +} + +static int ti_ads7950_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct ti_ads7950_state *st = iio_priv(indio_dev); + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret < 0) + return ret; + + ret = ti_ads7950_scan_direct(st, chan->address); + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; + + if (chan->address != TI_ADS7950_EXTRACT(ret, 12, 4)) + return -EIO; + + *val = TI_ADS7950_EXTRACT(ret, chan->scan_type.shift, + chan->scan_type.realbits); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = ti_ads7950_get_range(st); + if (ret < 0) + return ret; + + *val = ret; + *val2 = (1 << chan->scan_type.realbits) - 1; + + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static const struct iio_info ti_ads7950_info = { + .read_raw = &ti_ads7950_read_raw, + .update_scan_mode = ti_ads7950_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static int ti_ads7950_probe(struct spi_device *spi) +{ + struct ti_ads7950_state *st; + struct iio_dev *indio_dev; + const struct ti_ads7950_chip_info *info; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V; + + info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data]; + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = info->channels; + indio_dev->num_channels = info->num_channels; + indio_dev->info = &ti_ads7950_info; + + /* + * Setup default message. The sample is read at the end of the first + * transfer, then it takes one full cycle to convert the sample and one + * more cycle to send the value. The conversion process is driven by + * the SPI clock, which is why we have 3 transfers. The middle one is + * just dummy data sent while the chip is converting the sample that + * was read at the end of the first transfer. + */ + + st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; + st->scan_single_xfer[0].len = 2; + st->scan_single_xfer[0].cs_change = 1; + st->scan_single_xfer[1].tx_buf = &st->tx_buf[0]; + st->scan_single_xfer[1].len = 2; + st->scan_single_xfer[1].cs_change = 1; + st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; + st->scan_single_xfer[2].len = 2; + + spi_message_init_with_transfers(&st->scan_single_msg, + st->scan_single_xfer, 3); + + st->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(st->reg)) { + dev_err(&spi->dev, "Failed get get regulator \"vref\"\n"); + return PTR_ERR(st->reg); + } + + ret = regulator_enable(st->reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n"); + return ret; + } + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ti_ads7950_trigger_handler, NULL); + if (ret) { + dev_err(&spi->dev, "Failed to setup triggered buffer\n"); + goto error_disable_reg; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device\n"); + goto error_cleanup_ring; + } + + return 0; + +error_cleanup_ring: + iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: + regulator_disable(st->reg); + + return ret; +} + +static int ti_ads7950_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ti_ads7950_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(st->reg); + + return 0; +} + +static const struct spi_device_id ti_ads7950_id[] = { + { "ads7950", TI_ADS7950 }, + { "ads7951", TI_ADS7951 }, + { "ads7952", TI_ADS7952 }, + { "ads7953", TI_ADS7953 }, + { "ads7954", TI_ADS7954 }, + { "ads7955", TI_ADS7955 }, + { "ads7956", TI_ADS7956 }, + { "ads7957", TI_ADS7957 }, + { "ads7958", TI_ADS7958 }, + { "ads7959", TI_ADS7959 }, + { "ads7960", TI_ADS7960 }, + { "ads7961", TI_ADS7961 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ti_ads7950_id); + +static struct spi_driver ti_ads7950_driver = { + .driver = { + .name = "ads7950", + }, + .probe = ti_ads7950_probe, + .remove = ti_ads7950_remove, + .id_table = ti_ads7950_id, +}; +module_spi_driver(ti_ads7950_driver); + +MODULE_AUTHOR("David Lechner <david@lechnology.com>"); +MODULE_DESCRIPTION("TI TI_ADS7950 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c new file mode 100644 index 000000000000..78d91a069ea4 --- /dev/null +++ b/drivers/iio/adc/ti-tlc4541.c @@ -0,0 +1,271 @@ +/* + * TI tlc4541 ADC Driver + * + * Copyright (C) 2017 Phil Reid + * + * Datasheets can be found here: + * http://www.ti.com/lit/gpn/tlc3541 + * http://www.ti.com/lit/gpn/tlc4541 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * The tlc4541 requires 24 clock cycles to start a transfer. + * Conversion then takes 2.94us to complete before data is ready + * Data is returned MSB first. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> + +struct tlc4541_state { + struct spi_device *spi; + struct regulator *reg; + struct spi_transfer scan_single_xfer[3]; + struct spi_message scan_single_msg; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * 2 bytes data + 6 bytes padding + 8 bytes timestamp when + * call iio_push_to_buffers_with_timestamp. + */ + __be16 rx_buf[8] ____cacheline_aligned; +}; + +struct tlc4541_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +enum tlc4541_id { + TLC3541, + TLC4541, +}; + +#define TLC4541_V_CHAN(bits, bitshift) { \ + .type = IIO_VOLTAGE, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = (bitshift), \ + .endianness = IIO_BE, \ + }, \ + } + +#define DECLARE_TLC4541_CHANNELS(name, bits, bitshift) \ +const struct iio_chan_spec name ## _channels[] = { \ + TLC4541_V_CHAN(bits, bitshift), \ + IIO_CHAN_SOFT_TIMESTAMP(1), \ +} + +static DECLARE_TLC4541_CHANNELS(tlc3541, 14, 2); +static DECLARE_TLC4541_CHANNELS(tlc4541, 16, 0); + +static const struct tlc4541_chip_info tlc4541_chip_info[] = { + [TLC3541] = { + .channels = tlc3541_channels, + .num_channels = ARRAY_SIZE(tlc3541_channels), + }, + [TLC4541] = { + .channels = tlc4541_channels, + .num_channels = ARRAY_SIZE(tlc4541_channels), + }, +}; + +static irqreturn_t tlc4541_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct tlc4541_state *st = iio_priv(indio_dev); + int ret; + + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret < 0) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf, + iio_get_time_ns(indio_dev)); + +done: + iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; +} + +static int tlc4541_get_range(struct tlc4541_state *st) +{ + int vref; + + vref = regulator_get_voltage(st->reg); + if (vref < 0) + return vref; + + vref /= 1000; + + return vref; +} + +static int tlc4541_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret = 0; + struct tlc4541_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + ret = spi_sync(st->spi, &st->scan_single_msg); + iio_device_release_direct_mode(indio_dev); + if (ret < 0) + return ret; + *val = be16_to_cpu(st->rx_buf[0]); + *val = *val >> chan->scan_type.shift; + *val &= GENMASK(chan->scan_type.realbits - 1, 0); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = tlc4541_get_range(st); + if (ret < 0) + return ret; + *val = ret; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + } + return -EINVAL; +} + +static const struct iio_info tlc4541_info = { + .read_raw = &tlc4541_read_raw, + .driver_module = THIS_MODULE, +}; + +static int tlc4541_probe(struct spi_device *spi) +{ + struct tlc4541_state *st; + struct iio_dev *indio_dev; + const struct tlc4541_chip_info *info; + int ret; + int8_t device_init = 0; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + + info = &tlc4541_chip_info[spi_get_device_id(spi)->driver_data]; + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = info->channels; + indio_dev->num_channels = info->num_channels; + indio_dev->info = &tlc4541_info; + + /* perform reset */ + spi_write(spi, &device_init, 1); + + /* Setup default message */ + st->scan_single_xfer[0].rx_buf = &st->rx_buf[0]; + st->scan_single_xfer[0].len = 3; + st->scan_single_xfer[1].delay_usecs = 3; + st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; + st->scan_single_xfer[2].len = 2; + + spi_message_init_with_transfers(&st->scan_single_msg, + st->scan_single_xfer, 3); + + st->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + + ret = regulator_enable(st->reg); + if (ret) + return ret; + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &tlc4541_trigger_handler, NULL); + if (ret) + goto error_disable_reg; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_buffer; + + return 0; + +error_cleanup_buffer: + iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: + regulator_disable(st->reg); + + return ret; +} + +static int tlc4541_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct tlc4541_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(st->reg); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id tlc4541_dt_ids[] = { + { .compatible = "ti,tlc3541", }, + { .compatible = "ti,tlc4541", }, + {} +}; +MODULE_DEVICE_TABLE(of, tlc4541_dt_ids); +#endif + +static const struct spi_device_id tlc4541_id[] = { + {"tlc3541", TLC3541}, + {"tlc4541", TLC4541}, + {} +}; +MODULE_DEVICE_TABLE(spi, tlc4541_id); + +static struct spi_driver tlc4541_driver = { + .driver = { + .name = "tlc4541", + .of_match_table = of_match_ptr(tlc4541_dt_ids), + }, + .probe = tlc4541_probe, + .remove = tlc4541_remove, + .id_table = tlc4541_id, +}; +module_spi_driver(tlc4541_driver); + +MODULE_AUTHOR("Phil Reid <preid@electromag.com.au>"); +MODULE_DESCRIPTION("Texas Instruments TLC4541 ADC"); +MODULE_LICENSE("GPL v2"); |