Merge tag 'iio-for-v4.2b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes: Second set of new driver, functionality and cleanups for IIO in the 4.2 cycle. Core functionality * i and q modifiers from quadrature channels. * IIO_CHAN_INFO_OVERSAMPLING_RATIO added. * High pass filter attributes added to mirror the existing low pass filter ones. Core cleanups * Make IIO tools building more cross compiler friendly. * Substantial rework of the function __iio_update_buffers to greatly simplify a hideously evolved function. New drivers and support * ACPI0008 ambient light sensor driver. This one has been around a long time to will be good to finally get it into mainline. * Berlin SOC ADC support. * BMC150 magnetometer. The accelerometer in the same package has been supported for quite some time, so good to have this half as well. * m62332 DAC driver * MEMSIC MMC35420 magnetometer. * ROHM BH1710 and similar ambient light sensors. * Sensortek STK3310 light sensor. * Sensortek STK8312 accelerometer. * Sensortek STK8BA50 accelerometer. * ti-adc128s052 gains support form the adc122s021 2 channel ADC. Driver cleanups and functionality. * Allow various drivers to compile with !GPIOLIB if COMPILE_TEST enabled. * bmc150 - decouple trigger from buffer to allow other triggers to be used. * bmg160 - decouple trigger from buffer to allow other triggers to be used. Fix a trivial unused field. * Constify a load of platform_device_id structures. * inv_mpu6050 - device tree bindings. * hid-sensors - fix a memory leak during probe if certain errors occur. * ltr501 - illuminance channel derived (in an non obvious fashion) from the intensity channels. * ltr501 - fix a boundary check on the proximity threshold. * mlx90614 - drop a pointless return. * mma8452 - Debugfs register access and fix a bug that had no effect (by coincidence) * ti_am335x_adc - add device tree bindings for sample-delay, open-delay and averaging. The ideal settings for these tend to be board design specific.
This commit is contained in:
@@ -135,6 +135,13 @@ config AXP288_ADC
|
||||
device. Depending on platform configuration, this general purpose ADC can
|
||||
be used for sampling sensors such as thermal resistors.
|
||||
|
||||
config BERLIN2_ADC
|
||||
tristate "Marvell Berlin2 ADC driver"
|
||||
depends on ARCH_BERLIN
|
||||
help
|
||||
Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
|
||||
temperature measurement.
|
||||
|
||||
config DA9150_GPADC
|
||||
tristate "Dialog DA9150 GPADC driver support"
|
||||
depends on MFD_DA9150
|
||||
@@ -285,11 +292,11 @@ config TI_ADC081C
|
||||
called ti-adc081c.
|
||||
|
||||
config TI_ADC128S052
|
||||
tristate "Texas Instruments ADC128S052"
|
||||
tristate "Texas Instruments ADC128S052/ADC122S021"
|
||||
depends on SPI
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments ADC128S052
|
||||
chip.
|
||||
and ADC122S021 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-adc128s052.
|
||||
|
@@ -15,6 +15,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
|
||||
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
|
||||
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
|
||||
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
|
@@ -238,7 +238,7 @@ static int axp288_adc_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id axp288_adc_id_table[] = {
|
||||
static const struct platform_device_id axp288_adc_id_table[] = {
|
||||
{ .name = "axp288_adc" },
|
||||
{},
|
||||
};
|
||||
|
378
drivers/iio/adc/berlin2-adc.c
Normal file
378
drivers/iio/adc/berlin2-adc.c
Normal file
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Marvell Berlin2 ADC driver
|
||||
*
|
||||
* Copyright (C) 2015 Marvell Technology Group Ltd.
|
||||
*
|
||||
* Antoine Tenart <antoine.tenart@free-electrons.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/iio/machine.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#define BERLIN2_SM_CTRL 0x14
|
||||
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
|
||||
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
|
||||
#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */
|
||||
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
|
||||
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10)
|
||||
#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK (0x3 << 10)
|
||||
#define BERLIN2_SM_CTRL_ADC_START BIT(12)
|
||||
#define BERLIN2_SM_CTRL_ADC_RESET BIT(13)
|
||||
#define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14)
|
||||
#define BERLIN2_SM_CTRL_ADC_CONT_SINGLE (0x0 << 15)
|
||||
#define BERLIN2_SM_CTRL_ADC_CONT_CONTINUOUS (0x1 << 15)
|
||||
#define BERLIN2_SM_CTRL_ADC_BUFFER_EN BIT(16)
|
||||
#define BERLIN2_SM_CTRL_ADC_VREF_EXT (0x0 << 17)
|
||||
#define BERLIN2_SM_CTRL_ADC_VREF_INT (0x1 << 17)
|
||||
#define BERLIN2_SM_CTRL_ADC_ROTATE BIT(19)
|
||||
#define BERLIN2_SM_CTRL_TSEN_EN BIT(20)
|
||||
#define BERLIN2_SM_CTRL_TSEN_CLK_SEL_125 (0x0 << 21) /* 1.25 MHz */
|
||||
#define BERLIN2_SM_CTRL_TSEN_CLK_SEL_250 (0x1 << 21) /* 2.5 MHz */
|
||||
#define BERLIN2_SM_CTRL_TSEN_MODE_0_125 (0x0 << 22) /* 0-125 C */
|
||||
#define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */
|
||||
#define BERLIN2_SM_CTRL_TSEN_RESET BIT(29)
|
||||
#define BERLIN2_SM_ADC_DATA 0x20
|
||||
#define BERLIN2_SM_ADC_MASK 0x3ff
|
||||
#define BERLIN2_SM_ADC_STATUS 0x1c
|
||||
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
|
||||
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf
|
||||
#define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
|
||||
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16)
|
||||
#define BERLIN2_SM_TSEN_STATUS 0x24
|
||||
#define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
|
||||
#define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
|
||||
#define BERLIN2_SM_TSEN_DATA 0x28
|
||||
#define BERLIN2_SM_TSEN_MASK 0xfff
|
||||
#define BERLIN2_SM_TSEN_CTRL 0x74
|
||||
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
|
||||
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
|
||||
#define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */
|
||||
#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK (0x1 << 21)
|
||||
#define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22)
|
||||
#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK (0xf << 22)
|
||||
|
||||
struct berlin2_adc_priv {
|
||||
struct regmap *regmap;
|
||||
struct mutex lock;
|
||||
wait_queue_head_t wq;
|
||||
bool data_available;
|
||||
int data;
|
||||
};
|
||||
|
||||
#define BERLIN2_ADC_CHANNEL(n, t) \
|
||||
{ \
|
||||
.channel = n, \
|
||||
.datasheet_name = "channel"#n, \
|
||||
.type = t, \
|
||||
.indexed = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
}
|
||||
|
||||
static struct iio_chan_spec berlin2_adc_channels[] = {
|
||||
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(3, IIO_VOLTAGE), /* external input */
|
||||
BERLIN2_ADC_CHANNEL(4, IIO_VOLTAGE), /* reserved */
|
||||
BERLIN2_ADC_CHANNEL(5, IIO_VOLTAGE), /* reserved */
|
||||
{ /* temperature sensor */
|
||||
.channel = 6,
|
||||
.datasheet_name = "channel6",
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */
|
||||
};
|
||||
#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels)
|
||||
|
||||
static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
|
||||
{
|
||||
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
|
||||
int data, ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* Configure the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK
|
||||
| BERLIN2_SM_CTRL_ADC_START,
|
||||
BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
/* Disable the interrupts */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
|
||||
BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
|
||||
|
||||
if (ret == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_ADC_START, 0);
|
||||
|
||||
data = priv->data;
|
||||
priv->data_available = false;
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
|
||||
int data, ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
/* Configure the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
|
||||
BERLIN2_SM_CTRL_ADC_ROTATE);
|
||||
|
||||
/* Configure the temperature sensor */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
|
||||
BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK
|
||||
| BERLIN2_SM_TSEN_CTRL_START,
|
||||
BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12
|
||||
| BERLIN2_SM_TSEN_CTRL_START);
|
||||
|
||||
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
/* Disable interrupts */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
|
||||
BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
|
||||
|
||||
if (ret == 0)
|
||||
ret = -ETIMEDOUT;
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
|
||||
BERLIN2_SM_TSEN_CTRL_START, 0);
|
||||
|
||||
data = priv->data;
|
||||
priv->data_available = false;
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
|
||||
int temp;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_VOLTAGE)
|
||||
return -EINVAL;
|
||||
|
||||
/* Enable the interrupts */
|
||||
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
|
||||
BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel));
|
||||
|
||||
*val = berlin2_adc_read(indio_dev, chan->channel);
|
||||
if (*val < 0)
|
||||
return *val;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
if (chan->type != IIO_TEMP)
|
||||
return -EINVAL;
|
||||
|
||||
/* Enable interrupts */
|
||||
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
|
||||
BERLIN2_SM_TSEN_STATUS_INT_EN);
|
||||
|
||||
temp = berlin2_adc_tsen_read(indio_dev);
|
||||
if (temp < 0)
|
||||
return temp;
|
||||
|
||||
if (temp > 2047)
|
||||
temp = -(4096 - temp);
|
||||
|
||||
/* Convert to milli Celsius */
|
||||
*val = ((temp * 100000) / 264 - 270000);
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static irqreturn_t berlin2_adc_irq(int irq, void *private)
|
||||
{
|
||||
struct berlin2_adc_priv *priv = iio_priv(private);
|
||||
unsigned val;
|
||||
|
||||
regmap_read(priv->regmap, BERLIN2_SM_ADC_STATUS, &val);
|
||||
if (val & BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK) {
|
||||
regmap_read(priv->regmap, BERLIN2_SM_ADC_DATA, &priv->data);
|
||||
priv->data &= BERLIN2_SM_ADC_MASK;
|
||||
|
||||
val &= ~BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK;
|
||||
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, val);
|
||||
|
||||
priv->data_available = true;
|
||||
wake_up_interruptible(&priv->wq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t berlin2_adc_tsen_irq(int irq, void *private)
|
||||
{
|
||||
struct berlin2_adc_priv *priv = iio_priv(private);
|
||||
unsigned val;
|
||||
|
||||
regmap_read(priv->regmap, BERLIN2_SM_TSEN_STATUS, &val);
|
||||
if (val & BERLIN2_SM_TSEN_STATUS_DATA_RDY) {
|
||||
regmap_read(priv->regmap, BERLIN2_SM_TSEN_DATA, &priv->data);
|
||||
priv->data &= BERLIN2_SM_TSEN_MASK;
|
||||
|
||||
val &= ~BERLIN2_SM_TSEN_STATUS_DATA_RDY;
|
||||
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, val);
|
||||
|
||||
priv->data_available = true;
|
||||
wake_up_interruptible(&priv->wq);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info berlin2_adc_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = berlin2_adc_read_raw,
|
||||
};
|
||||
|
||||
static int berlin2_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct berlin2_adc_priv *priv;
|
||||
struct device_node *parent_np = of_get_parent(pdev->dev.of_node);
|
||||
int irq, tsen_irq;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev,
|
||||
sizeof(struct berlin2_adc_priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = iio_priv(indio_dev);
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
priv->regmap = syscon_node_to_regmap(parent_np);
|
||||
of_node_put(parent_np);
|
||||
if (IS_ERR(priv->regmap))
|
||||
return PTR_ERR(priv->regmap);
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "adc");
|
||||
if (irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
tsen_irq = platform_get_irq_byname(pdev, "tsen");
|
||||
if (tsen_irq < 0)
|
||||
return -ENODEV;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
|
||||
pdev->dev.driver->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
|
||||
0, pdev->dev.driver->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init_waitqueue_head(&priv->wq);
|
||||
mutex_init(&priv->lock);
|
||||
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &berlin2_adc_info;
|
||||
|
||||
indio_dev->num_channels = BERLIN2_N_CHANNELS;
|
||||
indio_dev->channels = berlin2_adc_channels;
|
||||
|
||||
/* Power up the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
/* Power down the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_ADC_POWER, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int berlin2_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
/* Power down the ADC */
|
||||
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
|
||||
BERLIN2_SM_CTRL_ADC_POWER, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id berlin2_adc_match[] = {
|
||||
{ .compatible = "marvell,berlin2-adc", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, berlin2_adc_match);
|
||||
|
||||
static struct platform_driver berlin2_adc_driver = {
|
||||
.driver = {
|
||||
.name = "berlin2-adc",
|
||||
.of_match_table = berlin2_adc_match,
|
||||
},
|
||||
.probe = berlin2_adc_probe,
|
||||
.remove = berlin2_adc_remove,
|
||||
};
|
||||
module_platform_driver(berlin2_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Marvell Berlin2 ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
|
||||
*
|
||||
* Driver for Texas Instruments' ADC128S052 ADC chip.
|
||||
* Datasheet can be found here:
|
||||
* Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
|
||||
* Datasheets can be found here:
|
||||
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
|
||||
* http://www.ti.com/lit/ds/symlink/adc122s021.pdf
|
||||
*
|
||||
* 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
|
||||
@@ -16,6 +17,11 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
struct adc128_configuration {
|
||||
const struct iio_chan_spec *channels;
|
||||
u8 num_channels;
|
||||
};
|
||||
|
||||
struct adc128 {
|
||||
struct spi_device *spi;
|
||||
|
||||
@@ -92,7 +98,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev,
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adc128_channels[] = {
|
||||
static const struct iio_chan_spec adc128s052_channels[] = {
|
||||
ADC128_VOLTAGE_CHANNEL(0),
|
||||
ADC128_VOLTAGE_CHANNEL(1),
|
||||
ADC128_VOLTAGE_CHANNEL(2),
|
||||
@@ -103,6 +109,16 @@ static const struct iio_chan_spec adc128_channels[] = {
|
||||
ADC128_VOLTAGE_CHANNEL(7),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adc122s021_channels[] = {
|
||||
ADC128_VOLTAGE_CHANNEL(0),
|
||||
ADC128_VOLTAGE_CHANNEL(1),
|
||||
};
|
||||
|
||||
static const struct adc128_configuration adc128_config[] = {
|
||||
{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
|
||||
{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
|
||||
};
|
||||
|
||||
static const struct iio_info adc128_info = {
|
||||
.read_raw = adc128_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
@@ -112,6 +128,7 @@ static int adc128_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct adc128 *adc;
|
||||
int config = spi_get_device_id(spi)->driver_data;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
|
||||
@@ -128,8 +145,8 @@ static int adc128_probe(struct spi_device *spi)
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &adc128_info;
|
||||
|
||||
indio_dev->channels = adc128_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adc128_channels);
|
||||
indio_dev->channels = adc128_config[config].channels;
|
||||
indio_dev->num_channels = adc128_config[config].num_channels;
|
||||
|
||||
adc->reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(adc->reg))
|
||||
@@ -158,7 +175,8 @@ static int adc128_remove(struct spi_device *spi)
|
||||
}
|
||||
|
||||
static const struct spi_device_id adc128_id[] = {
|
||||
{ "adc128s052", 0},
|
||||
{ "adc128s052", 0}, /* index into adc128_config */
|
||||
{ "adc122s021", 1},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc128_id);
|
||||
|
@@ -37,6 +37,7 @@ struct tiadc_device {
|
||||
u8 channel_step[8];
|
||||
int buffer_en_ch_steps;
|
||||
u16 data[8];
|
||||
u32 open_delay[8], sample_delay[8], step_avg[8];
|
||||
};
|
||||
|
||||
static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
|
||||
@@ -85,6 +86,7 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
|
||||
static void tiadc_step_config(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct tiadc_device *adc_dev = iio_priv(indio_dev);
|
||||
struct device *dev = adc_dev->mfd_tscadc->dev;
|
||||
unsigned int stepconfig;
|
||||
int i, steps = 0;
|
||||
|
||||
@@ -98,20 +100,47 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
|
||||
* needs to be given to ADC to digitalize data.
|
||||
*/
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
|
||||
| STEPCONFIG_MODE_SWCNT;
|
||||
else
|
||||
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
|
||||
|
||||
for (i = 0; i < adc_dev->channels; i++) {
|
||||
int chan;
|
||||
|
||||
chan = adc_dev->channel_line[i];
|
||||
|
||||
if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) {
|
||||
dev_warn(dev, "chan %d step_avg truncating to %d\n",
|
||||
chan, STEPCONFIG_AVG_16);
|
||||
adc_dev->step_avg[i] = STEPCONFIG_AVG_16;
|
||||
}
|
||||
|
||||
if (adc_dev->step_avg[i])
|
||||
stepconfig =
|
||||
STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) |
|
||||
STEPCONFIG_FIFO1;
|
||||
else
|
||||
stepconfig = STEPCONFIG_FIFO1;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev))
|
||||
stepconfig |= STEPCONFIG_MODE_SWCNT;
|
||||
|
||||
tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
|
||||
stepconfig | STEPCONFIG_INP(chan));
|
||||
|
||||
if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) {
|
||||
dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n",
|
||||
chan);
|
||||
adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK;
|
||||
}
|
||||
|
||||
if (adc_dev->sample_delay[i] > 0xFF) {
|
||||
dev_warn(dev, "chan %d sample delay truncating to 0xFF\n",
|
||||
chan);
|
||||
adc_dev->sample_delay[i] = 0xFF;
|
||||
}
|
||||
|
||||
tiadc_writel(adc_dev, REG_STEPDELAY(steps),
|
||||
STEPCONFIG_OPENDLY);
|
||||
STEPDELAY_OPEN(adc_dev->open_delay[i]) |
|
||||
STEPDELAY_SAMPLE(adc_dev->sample_delay[i]));
|
||||
|
||||
adc_dev->channel_step[i] = steps;
|
||||
steps++;
|
||||
}
|
||||
@@ -406,9 +435,22 @@ static int tiadc_parse_dt(struct platform_device *pdev,
|
||||
|
||||
of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
|
||||
adc_dev->channel_line[channels] = val;
|
||||
|
||||
/* Set Default values for optional DT parameters */
|
||||
adc_dev->open_delay[channels] = STEPCONFIG_OPENDLY;
|
||||
adc_dev->sample_delay[channels] = STEPCONFIG_SAMPLEDLY;
|
||||
adc_dev->step_avg[channels] = 16;
|
||||
|
||||
channels++;
|
||||
}
|
||||
|
||||
of_property_read_u32_array(node, "ti,chan-step-avg",
|
||||
adc_dev->step_avg, channels);
|
||||
of_property_read_u32_array(node, "ti,chan-step-opendelay",
|
||||
adc_dev->open_delay, channels);
|
||||
of_property_read_u32_array(node, "ti,chan-step-sampledelay",
|
||||
adc_dev->sample_delay, channels);
|
||||
|
||||
adc_dev->channels = channels;
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user