Commit 277c8e8b authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-5.1b' of...

Merge tag 'iio-for-5.1b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Second set of new device support, features and cleanup for IIO in the 5.1 cycle.

There are a few late breaking fixes in here that weren't worth trying to
rush into 5.0 as they have been with us for quite a while.

New device support
* ad7476
  - add support for TI ADS786X parts that are compatible with this Analog
    Devices driver. Good to see some simple devices are so similar.
* Ingenic jz47xx SoC ADCs
  - new driver and bindings
* Plantower PMS7003 partical sensor
  - new driver and bindings including vendor prefix.
* TI DAC7612
  - new driver and bindings for this dual DAC.

New features
* ad7768-1
  - Sampling frequency control
* bmi160
  - Data ready trigger support, including open-drain dt binding.

Cleanup / minor fixes.
* Analog Device DACs
  - Fix some inconsistent licenses.  These are only ones where there were
    two different license marked in the same file, and hence were previously
    unclear.
* ads124s08
  - Spelling fix.
* adxl345
  - Parameter alignement tidy up.
* bmi160
  - SPDX
  - correct a note on the types of supported interrupts which was too strict.
  - use iio_pollfunc_store_time to grab an earlier timestamp.
  - use if (ret) instead of if (ret < 0) to be consistent whilst simplifying
    some handling where ret was effectively getting written to 0 even though
    it was always already 0.
* exynos_adc
  - Fix a null pointer dereference on unbind.
  - Fix number of channels on Exynos4x12 devices to be 4 rather than 8.
* lpc32xx-adc
  - Move DT bindings doc out of staging. Oops, I missed this one when
    moving the driver.
  - SPDX.
* npcm-adc
  - drop documentation of reset node as going to be done differently.
    It's a new driver this cycle so no need to support the previous
    binding going forwards.
* sps30
  - Fix an issue with a loop timeout test that meant it would never identify
    a timeout.
  - Mark deliberate switch fall throughs.

* tag 'iio-for-5.1b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (26 commits)
  iio: adc: exynos-adc: Use proper number of channels for Exynos4x12
  dt-binding: iio: remove rst node from NPCM ADC document
  dt-bindings: iio: chemical: pms7003: add device tree support
  dt-bindings: add Plantower to the vendor prefixes
  iio: chemical: add support for Plantower PMS7003 sensor
  iio:chemical:sps30 Supress some switch fallthrough warnings.
  iio:adc:lpc32xx use SPDX-License-Identifier
  dt-bindings: iio: adc: move lpc32xx-adc out of staging
  iio: adc: ads124s08: fix spelling mistake "converions" -> "conversions"
  iio: adc: exynos-adc: Fix NULL pointer exception on unbind
  iio: chemical: sps30: fix a loop timeout test
  iio:accel:adxl345: Change alignment to match paranthesis
  iio:dac:dac7612: device tree bindings
  iio:dac:ti-dac7612: Add driver for Texas Instruments DAC7612
  iio: adc: ad7476: Add support for TI ADS786X ADCs
  iio: adc: ad7768-1: Add support for setting the sampling frequency
  drivers: iio: dac: Fix wrong license for ADI drivers
  IIO: add Ingenic JZ47xx ADC driver.
  dt-bindings: iio/adc: Add bindings for Ingenic JZ47xx SoCs ADC.
  dt-bindings: iio/adc: Add docs for Ingenic JZ47xx SoCs ADC.
  ...
parents 20931236 103cda6a
* Ingenic JZ47xx ADC controller IIO bindings
Required properties:
- compatible: Should be one of:
* ingenic,jz4725b-adc
* ingenic,jz4740-adc
- reg: ADC controller registers location and length.
- clocks: phandle to the SoC's ADC clock.
- clock-names: Must be set to "adc".
- #io-channel-cells: Must be set to <1> to indicate channels are selected
by index.
ADC clients must use the format described in iio-bindings.txt, giving
a phandle and IIO specifier pair ("io-channels") to the ADC controller.
Example:
#include <dt-bindings/iio/adc/ingenic,adc.h>
adc: adc@10070000 {
compatible = "ingenic,jz4740-adc";
#io-channel-cells = <1>;
reg = <0x10070000 0x30>;
clocks = <&cgu JZ4740_CLK_ADC>;
clock-names = "adc";
interrupt-parent = <&intc>;
interrupts = <18>;
};
adc-keys {
...
compatible = "adc-keys";
io-channels = <&adc INGENIC_ADC_AUX>;
io-channel-names = "buttons";
...
};
battery {
...
compatible = "ingenic,jz4740-battery";
io-channels = <&adc INGENIC_ADC_BATTERY>;
io-channel-names = "battery";
...
};
......@@ -14,11 +14,6 @@ Optional properties:
vref-supply is not added the ADC will use internal voltage
reference.
Required Node in the NPCM7xx BMC:
An additional register is present in the NPCM7xx SOC which is
assumed to be in the same device tree, with and marked as
compatible with "nuvoton,npcm750-rst".
Example:
adc: adc@f000c000 {
......@@ -27,9 +22,3 @@ adc: adc@f000c000 {
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk NPCM7XX_CLK_ADC>;
};
rst: rst@f0801000 {
compatible = "nuvoton,npcm750-rst", "syscon",
"simple-mfd";
reg = <0xf0801000 0x6C>;
};
......@@ -11,11 +11,13 @@ New driver handles the following
Required properties:
- compatible: Must be "samsung,exynos-adc-v1"
for exynos4412/5250 controllers.
for Exynos5250 controllers.
Must be "samsung,exynos-adc-v2" for
future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
Must be "samsung,exynos4212-adc" for
controllers compatible with ADC of Exynos4212 and Exynos4412.
Must be "samsung,exynos7-adc" for
the ADC in Exynos7 and compatibles
Must be "samsung,s3c2410-adc" for
......
* Plantower PMS7003 particulate matter sensor
Required properties:
- compatible: must be "plantower,pms7003"
- vcc-supply: phandle to the regulator that provides power to the sensor
Optional properties:
- plantower,set-gpios: phandle to the GPIO connected to the SET line
- reset-gpios: phandle to the GPIO connected to the RESET line
Refer to serial/slave-device.txt for generic serial attached device bindings.
Example:
&uart0 {
air-pollution-sensor {
compatible = "plantower,pms7003";
vcc-supply = <&reg_vcc5v0>;
};
};
* Texas Instruments Dual, 12-Bit Serial Input Digital-to-Analog Converter
The DAC7612 is a dual, 12-bit digital-to-analog converter (DAC) with guaranteed
12-bit monotonicity performance over the industrial temperature range.
Is is programmable through an SPI interface.
The internal DACs are loaded when the LOADDACS pin is pulled down.
http://www.ti.com/lit/ds/sbas106/sbas106.pdf
Required Properties:
- compatible: Should be one of:
"ti,dac7612"
"ti,dac7612u"
"ti,dac7612ub"
- reg: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
Optional Properties:
- ti,loaddacs-gpios: GPIO descriptor for the LOADDACS pin.
- spi-*: Definition as per Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
dac@1 {
compatible = "ti,dac7612";
reg = <0x1>;
ti,loaddacs-gpios = <&msmgpio 25 GPIO_ACTIVE_LOW>;
};
......@@ -9,9 +9,11 @@ Required properties:
- spi-max-frequency : set maximum clock frequency (only for SPI)
Optional properties:
- interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW
- interrupts : interrupt mapping for IRQ
- interrupt-names : set to "INT1" if INT1 pin should be used as interrupt
input, set to "INT2" if INT2 pin should be used instead
- drive-open-drain : set if the specified interrupt pin should be configured as
open drain. If not set, defaults to push-pull.
Examples:
......@@ -20,7 +22,7 @@ bmi160@68 {
reg = <0x68>;
interrupt-parent = <&gpio4>;
interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
interrupts = <12 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
......
......@@ -304,6 +304,7 @@ phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
pine64 Pine64
pixcir PIXCIR MICROELECTRONICS Co., Ltd
plantower Plantower Co., Ltd
plathome Plat'Home Co., Ltd.
plda PLDA
plx Broadcom Corporation (formerly PLX Technology)
......
......@@ -15105,6 +15105,13 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/ti/
Texas Instruments' DAC7612 DAC Driver
M: Ricardo Ribalda <ricardo@ribalda.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/dac/ti-dac7612.c
F: Documentation/devicetree/bindings/iio/dac/ti,dac7612.txt
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
......
......@@ -150,8 +150,8 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
}
static int adxl345_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct adxl345_data *data = iio_priv(indio_dev);
s64 n;
......
......@@ -57,14 +57,17 @@ config AD7298
module will be called ad7298.
config AD7476
tristate "Analog Devices AD7476 and similar 1-channel ADCs driver"
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD an TI"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Analog Devices AD7273, AD7274, AD7276,
AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468,
AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC).
Say yes here to build support for the following SPI analog to
digital converters (ADCs):
Analog Devices: AD7273, AD7274, AD7276, AD7277, AD7278, AD7475,
AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495, AD7910,
AD7920.
Texas Instruments: ADS7866, ADS7867, ADS7868.
To compile this driver as a module, choose M here: the
module will be called ad7476.
......@@ -407,6 +410,15 @@ config INA2XX_ADC
Say yes here to build support for TI INA2xx family of Power Monitors.
This driver is mutually exclusive with the HWMON version.
config INGENIC_ADC
tristate "Ingenic JZ47xx SoCs ADC driver"
depends on MIPS || COMPILE_TEST
help
Say yes here to build support for the Ingenic JZ47xx SoCs ADC unit.
This driver can also be built as a module. If so, the module will be
called ingenic_adc.
config IMX7D_ADC
tristate "Freescale IMX7D ADC driver"
depends on ARCH_MXC || COMPILE_TEST
......
......@@ -40,6 +40,7 @@ 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_INGENIC_ADC) += ingenic-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
......
......@@ -59,6 +59,9 @@ enum ad7476_supported_device_ids {
ID_ADC081S,
ID_ADC101S,
ID_ADC121S,
ID_ADS7866,
ID_ADS7867,
ID_ADS7868,
};
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
......@@ -157,6 +160,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0)
#define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \
BIT(IIO_CHAN_INFO_RAW))
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7091R] = {
......@@ -209,6 +214,18 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
.channel[0] = ADC081S_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7866] = {
.channel[0] = ADS786X_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7867] = {
.channel[0] = ADS786X_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_ADS7868] = {
.channel[0] = ADS786X_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
};
static const struct iio_info ad7476_info = {
......@@ -314,6 +331,9 @@ static const struct spi_device_id ad7476_id[] = {
{"adc081s", ID_ADC081S},
{"adc101s", ID_ADC101S},
{"adc121s", ID_ADC121S},
{"ads7866", ID_ADS7866},
{"ads7867", ID_ADS7867},
{"ads7868", ID_ADS7868},
{}
};
MODULE_DEVICE_TABLE(spi, ad7476_id);
......
......@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
......@@ -59,6 +60,18 @@
#define AD7768_REG_DIG_DIAG_STATUS 0x30
#define AD7768_REG_MCLK_COUNTER 0x31
/* AD7768_REG_POWER_CLOCK */
#define AD7768_PWR_MCLK_DIV_MSK GENMASK(5, 4)
#define AD7768_PWR_MCLK_DIV(x) FIELD_PREP(AD7768_PWR_MCLK_DIV_MSK, x)
#define AD7768_PWR_PWRMODE_MSK GENMASK(1, 0)
#define AD7768_PWR_PWRMODE(x) FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x)
/* AD7768_REG_DIGITAL_FILTER */
#define AD7768_DIG_FIL_FIL_MSK GENMASK(6, 4)
#define AD7768_DIG_FIL_FIL(x) FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x)
#define AD7768_DIG_FIL_DEC_MSK GENMASK(2, 0)
#define AD7768_DIG_FIL_DEC_RATE(x) FIELD_PREP(AD7768_DIG_FIL_DEC_MSK, x)
/* AD7768_REG_CONVERSION */
#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
......@@ -80,11 +93,51 @@ enum ad7768_pwrmode {
AD7768_FAST_MODE = 3
};
enum ad7768_mclk_div {
AD7768_MCLK_DIV_16,
AD7768_MCLK_DIV_8,
AD7768_MCLK_DIV_4,
AD7768_MCLK_DIV_2
};
enum ad7768_dec_rate {
AD7768_DEC_RATE_32 = 0,
AD7768_DEC_RATE_64 = 1,
AD7768_DEC_RATE_128 = 2,
AD7768_DEC_RATE_256 = 3,
AD7768_DEC_RATE_512 = 4,
AD7768_DEC_RATE_1024 = 5,
AD7768_DEC_RATE_8 = 9,
AD7768_DEC_RATE_16 = 10
};
struct ad7768_clk_configuration {
enum ad7768_mclk_div mclk_div;
enum ad7768_dec_rate dec_rate;
unsigned int clk_div;
enum ad7768_pwrmode pwrmode;
};
static const struct ad7768_clk_configuration ad7768_clk_config[] = {
{ AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE },
{ AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE },
{ AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE },
{ AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE },
{ AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE },
{ AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE },
{ AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE },
{ AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE },
{ AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE },
{ AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE },
{ AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE },
};
static const struct iio_chan_spec ad7768_channels[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.indexed = 1,
.channel = 0,
.scan_index = 0,
......@@ -102,8 +155,12 @@ struct ad7768_state {
struct spi_device *spi;
struct regulator *vref;
struct mutex lock;
struct clk *mclk;
unsigned int mclk_freq;
unsigned int samp_freq;
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
......@@ -210,6 +267,90 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
return ret;
}
static int ad7768_set_dig_fil(struct ad7768_state *st,
enum ad7768_dec_rate dec_rate)
{
unsigned int mode;
int ret;
if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16)
mode = AD7768_DIG_FIL_FIL(dec_rate);
else
mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
ret = ad7768_spi_reg_write(st, AD7768_REG_DIGITAL_FILTER, mode);
if (ret < 0)
return ret;
/* A sync-in pulse is required every time the filter dec rate changes */
gpiod_set_value(st->gpio_sync_in, 1);
gpiod_set_value(st->gpio_sync_in, 0);
return 0;
}
static int ad7768_set_freq(struct ad7768_state *st,
unsigned int freq)
{
unsigned int diff_new, diff_old, pwr_mode, i, idx;
int res, ret;
diff_old = U32_MAX;
idx = 0;
res = DIV_ROUND_CLOSEST(st->mclk_freq, freq);
/* Find the closest match for the desired sampling frequency */
for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
diff_new = abs(res - ad7768_clk_config[i].clk_div);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
}
}
/*
* Set both the mclk_div and pwrmode with a single write to the
* POWER_CLOCK register
*/
pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
ret = ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK, pwr_mode);
if (ret < 0)
return ret;
ret = ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate);
if (ret < 0)
return ret;
st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
ad7768_clk_config[idx].clk_div);
return 0;
}
static ssize_t ad7768_sampling_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7768_state *st = iio_priv(indio_dev);
unsigned int freq;
int i, len = 0;
for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
freq = DIV_ROUND_CLOSEST(st->mclk_freq,
ad7768_clk_config[i].clk_div);
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", freq);
}
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ad7768_sampling_freq_avail);
static int ad7768_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
......@@ -242,13 +383,43 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
*val2 = chan->scan_type.realbits;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->samp_freq;
return IIO_VAL_INT;
}
return -EINVAL;
}
static int ad7768_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
{
struct ad7768_state *st = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
return ad7768_set_freq(st, val);
default:
return -EINVAL;
}
}
static struct attribute *ad7768_attributes[] = {
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group ad7768_group = {
.attrs = ad7768_attributes,
};
static const struct iio_info ad7768_info = {
.attrs = &ad7768_group,
.read_raw = &ad7768_read_raw,
.write_raw = &ad7768_write_raw,
.debugfs_reg_access = &ad7768_reg_access,
};
......@@ -270,9 +441,13 @@ static int ad7768_setup(struct ad7768_state *st)
if (ret)
return ret;
/* Set power mode to fast */
return ad7768_spi_reg_write(st, AD7768_REG_POWER_CLOCK,
AD7768_FAST_MODE);
st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in",
GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_sync_in))
return PTR_ERR(st->gpio_sync_in);
/* Set the default sampling frequency to 32000 kSPS */
return ad7768_set_freq(st, 32000);
}
static irqreturn_t ad7768_trigger_handler(int irq, void *p)
......@@ -356,6 +531,13 @@ static void ad7768_regulator_disable(void *data)
regulator_disable(st->vref);
}
static void ad7768_clk_disable(void *data)
{
struct ad7768_state *st = data;
clk_disable_unprepare(st->mclk);
}
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
......@@ -383,6 +565,20 @@ static int ad7768_probe(struct spi_device *spi)
if (ret)
return ret;
st->mclk = devm_clk_get(&spi->dev, "mclk");
if (IS_ERR(st->mclk))
return PTR_ERR(st->mclk);
ret = clk_prepare_enable(st->mclk);
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(&spi->dev, ad7768_clk_disable, st);
if (ret)
return ret;
st->mclk_freq = clk_get_rate(st->mclk);
spi_set_drvdata(spi, indio_dev);
mutex_init(&st->lock);
......
......@@ -115,6 +115,7 @@
#define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
#define MAX_EXYNOS4212_ADC_CHANNELS 4
#define MAX_S5PV210_ADC_CHANNELS 10
/* Bit definitions common for ADC_V1 and ADC_V2 */
......@@ -271,6 +272,19 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
/* Exynos4212 and 4412 is like ADCv1 but with four channels only */
static const struct exynos_adc_data exynos4212_adc_data = {
.num_channels = MAX_EXYNOS4212_ADC_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
.needs_adc_phy = true,
.phy_offset = EXYNOS_ADCV1_PHY_OFFSET,
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
};
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
......@@ -492,6 +506,9 @@ static const struct of_device_id exynos_adc_match[] = {
}, {
.compatible = "samsung,s5pv210-adc",
.data = &exynos_adc_s5pv210_data,
}, {
.compatible = "samsung,exynos4212-adc",
.data = &exynos4212_adc_data,
}, {
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
......@@ -929,7 +946,7 @@ static int exynos_adc_remove(struct platform_device *pdev)
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct exynos_adc *info = iio_priv(indio_dev);
if (IS_REACHABLE(CONFIG_INPUT)) {
if (IS_REACHABLE(CONFIG_INPUT) && info->input) {
free_irq(info->tsirq, info);
input_unregister_device(info->input);
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* ADC driver for the Ingenic JZ47xx SoCs
* Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu>
*
* based on drivers/mfd/jz4740-adc.c
*/
#include <dt-bindings/iio/adc/ingenic,adc.h>
#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#define JZ_ADC_REG_ENABLE 0x00
#define JZ_ADC_REG_CFG 0x04
#define JZ_ADC_REG_CTRL 0x08
#define JZ_ADC_REG_STATUS 0x0c
#define JZ_ADC_REG_ADTCH 0x18
#define JZ_ADC_REG_ADBDAT 0x1c
#define JZ_ADC_REG_ADSDAT 0x20
#define JZ_ADC_REG_CFG_BAT_MD BIT(4)
#define JZ_ADC_AUX_VREF 3300
#define JZ_ADC_AUX_VREF_BITS 12
#define JZ_ADC_BATTERY_LOW_VREF 2500
#define JZ_ADC_BATTERY_LOW_VREF_BITS 12
#define JZ4725B_ADC_BATTERY_HIGH_VREF 7500
#define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10
#define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986)
#define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12
struct ingenic_adc_soc_data {
unsigned int battery_high_vref;
unsigned int battery_high_vref_bits;
const int *battery_raw_avail;
size_t battery_raw_avail_size;
const int *battery_scale_avail;
size_t battery_scale_avail_size;
};
struct ingenic_adc {
void __iomem *base;
struct clk *clk;
struct mutex lock;
const struct ingenic_adc_soc_data *soc_data;
bool low_vref_mode;
};
static void ingenic_adc_set_config(struct ingenic_adc *adc,
uint32_t mask,
uint32_t val)
{
uint32_t cfg;
clk_enable(adc->clk);
mutex_lock(&adc->lock);
cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
cfg |= val;
writel(cfg, adc->base + JZ_ADC_REG_CFG);
mutex_unlock(&adc->lock);
clk_disable(adc->clk);
}
static void ingenic_adc_enable(struct ingenic_adc *adc,
int engine,
bool enabled)
{
u8 val;
mutex_lock(&adc->lock);
val = readb(adc->base + JZ_ADC_REG_ENABLE);
if (enabled)
val |= BIT(engine);
else
val &= ~BIT(engine);
writeb(val, adc->base + JZ_ADC_REG_ENABLE);
mutex_unlock(&adc->lock);
}
static int ingenic_adc_capture(struct ingenic_adc *adc,
int engine)
{
u8 val;
int ret;
ingenic_adc_enable(adc, engine, true);
ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
!(val & BIT(engine)), 250, 1000);
if (ret)
ingenic_adc_enable(adc, engine, false);
return ret;
}
static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int val,
int val2,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_BATTERY:
if (val > JZ_ADC_BATTERY_LOW_VREF) {
ingenic_adc_set_config(adc,
JZ_ADC_REG_CFG_BAT_MD,
0);
adc->low_vref_mode = false;
} else {
ingenic_adc_set_config(adc,
JZ_ADC_REG_CFG_BAT_MD,
JZ_ADC_REG_CFG_BAT_MD);
adc->low_vref_mode = true;
}
return 0;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const int jz4725b_adc_battery_raw_avail[] = {
0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
};
static const int jz4725b_adc_battery_scale_avail[] = {
JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
static const int jz4740_adc_battery_raw_avail[] = {
0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
};
static const int jz4740_adc_battery_scale_avail[] = {
JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
};
static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
.battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
.battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
.battery_raw_avail = jz4725b_adc_battery_raw_avail,
.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
.battery_scale_avail = jz4725b_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
};
static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
.battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
.battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
.battery_raw_avail = jz4740_adc_battery_raw_avail,
.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
.battery_scale_avail = jz4740_adc_battery_scale_avail,
.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
};
static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
const int **vals,
int *type,
int *length,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
switch (m) {
case IIO_CHAN_INFO_RAW:
*type = IIO_VAL_INT;
*length = adc->soc_data->battery_raw_avail_size;
*vals = adc->soc_data->battery_raw_avail;
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_FRACTIONAL_LOG2;
*length = adc->soc_data->battery_scale_avail_size;
*vals = adc->soc_data->battery_scale_avail;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
};
}
static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct ingenic_adc *adc = iio_priv(iio_dev);
int ret;
switch (m) {
case IIO_CHAN_INFO_RAW:
clk_enable(adc->clk);
ret = ingenic_adc_capture(adc, chan->channel);
if (ret) {
clk_disable(adc->clk);
return ret;
}
switch (chan->channel) {
case INGENIC_ADC_AUX:
*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
break;
case INGENIC_ADC_BATTERY:
*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
break;
}
clk_disable(adc->clk);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case INGENIC_ADC_AUX:
*val = JZ_ADC_AUX_VREF;
*val2 = JZ_ADC_AUX_VREF_BITS;
break;
case INGENIC_ADC_BATTERY:
if (adc->low_vref_mode) {
*val = JZ_ADC_BATTERY_LOW_VREF;
*val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
} else {
*val = adc->soc_data->battery_high_vref;
*val2 = adc->soc_data->battery_high_vref_bits;
}
break;
}
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
static void ingenic_adc_clk_cleanup(void *data)
{
clk_unprepare(data);
}
static const struct iio_info ingenic_adc_info = {
.write_raw = ingenic_adc_write_raw,
.read_raw = ingenic_adc_read_raw,
.read_avail = ingenic_adc_read_avail,
};
static const struct iio_chan_spec ingenic_channels[] = {
{
.extend_name = "aux",
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = INGENIC_ADC_AUX,
},
{
.extend_name = "battery",
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.indexed = 1,
.channel = INGENIC_ADC_BATTERY,
},
};
static int ingenic_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct iio_dev *iio_dev;
struct ingenic_adc *adc;
struct resource *mem_base;
const struct ingenic_adc_soc_data *soc_data;
int ret;
soc_data = device_get_match_data(dev);
if (!soc_data)
return -EINVAL;
iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
if (!iio_dev)
return -ENOMEM;
adc = iio_priv(iio_dev);
mutex_init(&adc->lock);
adc->soc_data = soc_data;
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc->base = devm_ioremap_resource(dev, mem_base);
if (IS_ERR(adc->base)) {
dev_err(dev, "Unable to ioremap mmio resource\n");
return PTR_ERR(adc->base);
}
adc->clk = devm_clk_get(dev, "adc");
if (IS_ERR(adc->clk)) {
dev_err(dev, "Unable to get clock\n");
return PTR_ERR(adc->clk);
}
ret = clk_prepare_enable(adc->clk);
if (ret) {
dev_err(dev, "Failed to enable clock\n");
return ret;
}
/* Put hardware in a known passive state. */
writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
clk_disable(adc->clk);
ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
if (ret) {
dev_err(dev, "Unable to add action\n");
return ret;
}
iio_dev->dev.parent = dev;
iio_dev->name = "jz-adc";
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = ingenic_channels;
iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
iio_dev->info = &ingenic_adc_info;
ret = devm_iio_device_register(dev, iio_dev);
if (ret)
dev_err(dev, "Unable to register IIO device\n");
return ret;
}
#ifdef CONFIG_OF
static const struct of_device_id ingenic_adc_of_match[] = {
{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
{ },
};
MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
#endif
static struct platform_driver ingenic_adc_driver = {
.driver = {
.name = "ingenic-adc",
.of_match_table = of_match_ptr(ingenic_adc_of_match),
},
.probe = ingenic_adc_probe,
};
module_platform_driver(ingenic_adc_driver);
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0+
/*
* lpc32xx_adc.c - Support for ADC in LPC32XX
*
* 3-channel, 10-bit ADC
*
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
......
......@@ -232,7 +232,7 @@ static int ads124s_read_raw(struct iio_dev *indio_dev,
ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
if (ret) {
dev_err(&priv->spi->dev, "Start converions failed\n");
dev_err(&priv->spi->dev, "Start conversions failed\n");
goto out;
}
......@@ -246,7 +246,7 @@ static int ads124s_read_raw(struct iio_dev *indio_dev,
ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
if (ret) {
dev_err(&priv->spi->dev, "Stop converions failed\n");
dev_err(&priv->spi->dev, "Stop conversions failed\n");
goto out;
}
......@@ -283,12 +283,12 @@ static irqreturn_t ads124s_trigger_handler(int irq, void *p)
ret = ads124s_write_cmd(indio_dev, ADS124S08_START_CONV);
if (ret)
dev_err(&priv->spi->dev, "Start ADC converions failed\n");
dev_err(&priv->spi->dev, "Start ADC conversions failed\n");
buffer[j] = ads124s_read(indio_dev, scan_index);
ret = ads124s_write_cmd(indio_dev, ADS124S08_STOP_CONV);
if (ret)
dev_err(&priv->spi->dev, "Stop ADC converions failed\n");
dev_err(&priv->spi->dev, "Stop ADC conversions failed\n");
j++;
}
......
......@@ -61,6 +61,16 @@ config IAQCORE
iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds)
sensors
config PMS7003
tristate "Plantower PMS7003 particulate matter sensor"
depends on SERIAL_DEV_BUS
help
Say Y here to build support for the Plantower PMS7003 particulate
matter sensor.
To compile this driver as a module, choose M here: the module will
be called pms7003.
config SPS30
tristate "SPS30 particulate matter sensor"
depends on I2C
......
......@@ -9,6 +9,7 @@ obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_PMS7003) += pms7003.o
obj-$(CONFIG_SENSIRION_SGP30) += sgp30.o
obj-$(CONFIG_SPS30) += sps30.o
obj-$(CONFIG_VZ89X) += vz89x.o
// SPDX-License-Identifier: GPL-2.0
/*
* Plantower PMS7003 particulate matter sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
*/
#include <asm/unaligned.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/serdev.h>
#define PMS7003_DRIVER_NAME "pms7003"
#define PMS7003_MAGIC 0x424d
/* last 2 data bytes hold frame checksum */
#define PMS7003_MAX_DATA_LENGTH 28
#define PMS7003_CHECKSUM_LENGTH 2
#define PMS7003_PM10_OFFSET 10
#define PMS7003_PM2P5_OFFSET 8
#define PMS7003_PM1_OFFSET 6
#define PMS7003_TIMEOUT msecs_to_jiffies(6000)
#define PMS7003_CMD_LENGTH 7
#define PMS7003_PM_MAX 1000
#define PMS7003_PM_MIN 0
enum {
PM1,
PM2P5,
PM10,
};
enum pms7003_cmd {
CMD_WAKEUP,
CMD_ENTER_PASSIVE_MODE,
CMD_READ_PASSIVE,
CMD_SLEEP,
};
/*
* commands have following format:
*
* +------+------+-----+------+-----+-----------+-----------+
* | 0x42 | 0x4d | cmd | 0x00 | arg | cksum msb | cksum lsb |
* +------+------+-----+------+-----+-----------+-----------+
*/
static const u8 pms7003_cmd_tbl[][PMS7003_CMD_LENGTH] = {
[CMD_WAKEUP] = { 0x42, 0x4d, 0xe4, 0x00, 0x01, 0x01, 0x74 },
[CMD_ENTER_PASSIVE_MODE] = { 0x42, 0x4d, 0xe1, 0x00, 0x00, 0x01, 0x70 },
[CMD_READ_PASSIVE] = { 0x42, 0x4d, 0xe2, 0x00, 0x00, 0x01, 0x71 },
[CMD_SLEEP] = { 0x42, 0x4d, 0xe4, 0x00, 0x00, 0x01, 0x73 },
};
struct pms7003_frame {
u8 data[PMS7003_MAX_DATA_LENGTH];
u16 expected_length;
u16 length;
};
struct pms7003_state {
struct serdev_device *serdev;
struct pms7003_frame frame;
struct completion frame_ready;
struct mutex lock; /* must be held whenever state gets touched */
};
static int pms7003_do_cmd(struct pms7003_state *state, enum pms7003_cmd cmd)
{
int ret;
ret = serdev_device_write(state->serdev, pms7003_cmd_tbl[cmd],
PMS7003_CMD_LENGTH, PMS7003_TIMEOUT);
if (ret < PMS7003_CMD_LENGTH)
return ret < 0 ? ret : -EIO;
ret = wait_for_completion_interruptible_timeout(&state->frame_ready,
PMS7003_TIMEOUT);
if (!ret)
ret = -ETIMEDOUT;
return ret < 0 ? ret : 0;
}
static u16 pms7003_get_pm(const u8 *data)
{
return clamp_val(get_unaligned_be16(data),
PMS7003_PM_MIN, PMS7003_PM_MAX);
}
static irqreturn_t pms7003_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
u16 data[3 + 1 + 4]; /* PM1, PM2P5, PM10, padding, timestamp */
int ret;
mutex_lock(&state->lock);
ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
if (ret) {
mutex_unlock(&state->lock);
goto err;
}
data[PM1] = pms7003_get_pm(frame->data + PMS7003_PM1_OFFSET);
data[PM2P5] = pms7003_get_pm(frame->data + PMS7003_PM2P5_OFFSET);
data[PM10] = pms7003_get_pm(frame->data + PMS7003_PM10_OFFSET);
mutex_unlock(&state->lock);
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_get_time_ns(indio_dev));
err:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int pms7003_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_MASSCONCENTRATION:
mutex_lock(&state->lock);
ret = pms7003_do_cmd(state, CMD_READ_PASSIVE);
if (ret) {
mutex_unlock(&state->lock);
return ret;
}
*val = pms7003_get_pm(frame->data + chan->address);
mutex_unlock(&state->lock);
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static const struct iio_info pms7003_info = {
.read_raw = pms7003_read_raw,
};
#define PMS7003_CHAN(_index, _mod, _addr) { \
.type = IIO_MASSCONCENTRATION, \
.modified = 1, \
.channel2 = IIO_MOD_ ## _mod, \
.address = _addr, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = _index, \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
}
static const struct iio_chan_spec pms7003_channels[] = {
PMS7003_CHAN(0, PM1, PMS7003_PM1_OFFSET),
PMS7003_CHAN(1, PM2P5, PMS7003_PM2P5_OFFSET),
PMS7003_CHAN(2, PM10, PMS7003_PM10_OFFSET),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static u16 pms7003_calc_checksum(struct pms7003_frame *frame)
{
u16 checksum = (PMS7003_MAGIC >> 8) + (u8)(PMS7003_MAGIC & 0xff) +
(frame->length >> 8) + (u8)frame->length;
int i;
for (i = 0; i < frame->length - PMS7003_CHECKSUM_LENGTH; i++)
checksum += frame->data[i];
return checksum;
}
static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
{
int offset = frame->length - PMS7003_CHECKSUM_LENGTH;
u16 checksum = get_unaligned_be16(frame->data + offset);
return checksum == pms7003_calc_checksum(frame);
}
static int pms7003_receive_buf(struct serdev_device *serdev,
const unsigned char *buf, size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
int num;
if (!frame->expected_length) {
u16 magic;
/* wait for SOF and data length */
if (size < 4)
return 0;
magic = get_unaligned_be16(buf);
if (magic != PMS7003_MAGIC)
return 2;
num = get_unaligned_be16(buf + 2);
if (num <= PMS7003_MAX_DATA_LENGTH) {
frame->expected_length = num;
frame->length = 0;
}
return 4;
}
num = min(size, (size_t)(frame->expected_length - frame->length));
memcpy(frame->data + frame->length, buf, num);
frame->length += num;
if (frame->length == frame->expected_length) {
if (pms7003_frame_is_okay(frame))
complete(&state->frame_ready);
frame->expected_length = 0;
}
return num;
}
static const struct serdev_device_ops pms7003_serdev_ops = {
.receive_buf = pms7003_receive_buf,
.write_wakeup = serdev_device_write_wakeup,
};
static void pms7003_stop(void *data)
{
struct pms7003_state *state = data;
pms7003_do_cmd(state, CMD_SLEEP);
}
static const unsigned long pms7003_scan_masks[] = { 0x07, 0x00 };
static int pms7003_probe(struct serdev_device *serdev)
{
struct pms7003_state *state;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&serdev->dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
state = iio_priv(indio_dev);
serdev_device_set_drvdata(serdev, indio_dev);
state->serdev = serdev;
indio_dev->dev.parent = &serdev->dev;
indio_dev->info = &pms7003_info;
indio_dev->name = PMS7003_DRIVER_NAME;
indio_dev->channels = pms7003_channels,
indio_dev->num_channels = ARRAY_SIZE(pms7003_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = pms7003_scan_masks;
mutex_init(&state->lock);
init_completion(&state->frame_ready);
serdev_device_set_client_ops(serdev, &pms7003_serdev_ops);
ret = devm_serdev_device_open(&serdev->dev, serdev);
if (ret)
return ret;
serdev_device_set_baudrate(serdev, 9600);
serdev_device_set_flow_control(serdev, false);
ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
if (ret)
return ret;
ret = pms7003_do_cmd(state, CMD_WAKEUP);
if (ret) {
dev_err(&serdev->dev, "failed to wakeup sensor\n");
return ret;
}
ret = pms7003_do_cmd(state, CMD_ENTER_PASSIVE_MODE);
if (ret) {
dev_err(&serdev->dev, "failed to enter passive mode\n");
return ret;
}
ret = devm_add_action_or_reset(&serdev->dev, pms7003_stop, state);
if (ret)
return ret;
ret = devm_iio_triggered_buffer_setup(&serdev->dev, indio_dev, NULL,
pms7003_trigger_handler, NULL);
if (ret)
return ret;
return devm_iio_device_register(&serdev->dev, indio_dev);
}
static const struct of_device_id pms7003_of_match[] = {
{ .compatible = "plantower,pms7003" },
{ }
};
MODULE_DEVICE_TABLE(of, pms7003_of_match);
static struct serdev_device_driver pms7003_driver = {
.driver = {
.name = PMS7003_DRIVER_NAME,
.of_match_table = pms7003_of_match,
},
.probe = pms7003_probe,
};
module_serdev_device_driver(pms7003_driver);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("Plantower PMS7003 particulate matter sensor driver");
MODULE_LICENSE("GPL v2");
......@@ -118,6 +118,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
case SPS30_READ_AUTO_CLEANING_PERIOD:
buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD;
/* fall through */
case SPS30_READ_DATA_READY_FLAG:
case SPS30_READ_DATA:
case SPS30_READ_SERIAL:
......@@ -210,7 +211,7 @@ static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
msleep_interruptible(300);
}
if (!tries)
if (tries == -1)
return -ETIMEDOUT;
ret = sps30_do_cmd(state, SPS30_READ_DATA, tmp, sizeof(int) * size);
......@@ -295,6 +296,8 @@ static int sps30_read_raw(struct iio_dev *indio_dev,
*val2 = 10000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
......
......@@ -375,6 +375,16 @@ config TI_DAC7311
If compiled as a module, it will be called ti-dac7311.
config TI_DAC7612
tristate "Texas Instruments 12-bit 2-channel DAC driver"
depends on SPI_MASTER && GPIOLIB
help
Driver for the Texas Instruments DAC7612, DAC7612U, DAC7612UB
The driver hand drive the load pin automatically, otherwise
it needs to be toggled manually.
If compiled as a module, it will be called ti-dac7612.
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
......
......@@ -41,4 +41,5 @@ obj-$(CONFIG_STM32_DAC) += stm32-dac.o
obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
obj-$(CONFIG_TI_DAC7612) += ti-dac7612.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5672R, AD5674R, AD5676, AD5676R, AD5679R,
* AD5681R, AD5682R, AD5683, AD5683R, AD5684,
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5686R, AD5685R, AD5684R Digital to analog converters driver
*
......
/* SPDX-License-Identifier: GPL-2.0+ */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This file is part of AD5686 DAC driver
*
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R,
* AD5694, AD5694R, AD5695R, AD5696, AD5696R
......
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: GPL-2.0
/*
* AD5758 Digital to analog converters driver
*
......
// SPDX-License-Identifier: GPL-2.0
/*
* DAC7612 Dual, 12-Bit Serial input Digital-to-Analog Converter
*
* Copyright 2019 Qtechnology A/S
* 2019 Ricardo Ribalda <ricardo@ribalda.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#define DAC7612_RESOLUTION 12
#define DAC7612_ADDRESS 4
#define DAC7612_START 5
struct dac7612 {
struct spi_device *spi;
struct gpio_desc *loaddacs;
uint16_t cache[2];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
uint8_t data[2] ____cacheline_aligned;
};
static int dac7612_cmd_single(struct dac7612 *priv, int channel, u16 val)
{
int ret;
priv->data[0] = BIT(DAC7612_START) | (channel << DAC7612_ADDRESS);
priv->data[0] |= val >> 8;
priv->data[1] = val & 0xff;
priv->cache[channel] = val;
ret = spi_write(priv->spi, priv->data, sizeof(priv->data));
if (ret)
return ret;
gpiod_set_value(priv->loaddacs, 1);
gpiod_set_value(priv->loaddacs, 0);
return 0;
}
#define dac7612_CHANNEL(chan, name) { \
.type = IIO_VOLTAGE, \
.channel = (chan), \
.indexed = 1, \
.output = 1, \
.datasheet_name = name, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec dac7612_channels[] = {
dac7612_CHANNEL(0, "OUTA"),
dac7612_CHANNEL(1, "OUTB"),
};
static int dac7612_read_raw(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct dac7612 *priv;
switch (mask) {
case IIO_CHAN_INFO_RAW:
priv = iio_priv(iio_dev);
*val = priv->cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 1;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int dac7612_write_raw(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int val, int val2, long mask)
{
struct dac7612 *priv = iio_priv(iio_dev);
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
if ((val >= BIT(DAC7612_RESOLUTION)) || val < 0 || val2)
return -EINVAL;
if (val == priv->cache[chan->channel])
return 0;
mutex_lock(&iio_dev->mlock);
ret = dac7612_cmd_single(priv, chan->channel, val);
mutex_unlock(&iio_dev->mlock);
return ret;
}
static const struct iio_info dac7612_info = {
.read_raw = dac7612_read_raw,
.write_raw = dac7612_write_raw,
};
static int dac7612_probe(struct spi_device *spi)
{
struct iio_dev *iio_dev;
struct dac7612 *priv;
int i;
int ret;
iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
if (!iio_dev)
return -ENOMEM;
priv = iio_priv(iio_dev);
/*
* LOADDACS pin can be controlled by the driver or externally.
* When controlled by the driver, the DAC value is updated after
* every write.
* When the driver does not control the PIN, the user or an external
* event can change the value of all DACs by pulsing down the LOADDACs
* pin.
*/
priv->loaddacs = devm_gpiod_get_optional(&spi->dev, "ti,loaddacs",
GPIOD_OUT_LOW);
if (IS_ERR(priv->loaddacs))
return PTR_ERR(priv->loaddacs);
priv->spi = spi;
spi_set_drvdata(spi, iio_dev);
iio_dev->dev.parent = &spi->dev;
iio_dev->info = &dac7612_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = dac7612_channels;
iio_dev->num_channels = ARRAY_SIZE(priv->cache);
iio_dev->name = spi_get_device_id(spi)->name;
for (i = 0; i < ARRAY_SIZE(priv->cache); i++) {
ret = dac7612_cmd_single(priv, i, 0);
if (ret)
return ret;
}
return devm_iio_device_register(&spi->dev, iio_dev);
}
static const struct spi_device_id dac7612_id[] = {
{"ti-dac7612"},
{}
};
MODULE_DEVICE_TABLE(spi, dac7612_id);
static const struct of_device_id dac7612_of_match[] = {
{ .compatible = "ti,dac7612" },
{ .compatible = "ti,dac7612u" },
{ .compatible = "ti,dac7612ub" },
{ },
};
MODULE_DEVICE_TABLE(of, dac7612_of_match);
static struct spi_driver dac7612_driver = {
.driver = {
.name = "ti-dac7612",
.of_match_table = dac7612_of_match,
},
.probe = dac7612_probe,
.id_table = dac7612_id,
};
module_spi_driver(dac7612_driver);
MODULE_AUTHOR("Ricardo Ribalda <ricardo@ribalda.com>");
MODULE_DESCRIPTION("Texas Instruments DAC7612 DAC driver");
MODULE_LICENSE("GPL v2");
......@@ -2,9 +2,20 @@
#ifndef BMI160_H_
#define BMI160_H_
#include <linux/iio/iio.h>
struct bmi160_data {
struct regmap *regmap;
struct iio_trigger *trig;
};
extern const struct regmap_config bmi160_regmap_config;
int bmi160_core_probe(struct device *dev, struct regmap *regmap,
const char *name, bool use_spi);
int bmi160_enable_irq(struct regmap *regmap, bool enable);
int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type);
#endif /* BMI160_H_ */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, I2C bits
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address is:
* - 0x68 if SDO is pulled to GND
* - 0x69 if SDO is pulled to VDDIO
......
// SPDX-License-Identifier: GPL-2.0
/*
* BMI160 - Bosch IMU, SPI bits
*
* Copyright (c) 2016, Intel Corporation.
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*/
#include <linux/acpi.h>
#include <linux/module.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _DT_BINDINGS_IIO_ADC_INGENIC_ADC_H
#define _DT_BINDINGS_IIO_ADC_INGENIC_ADC_H
/* ADC channel idx. */
#define INGENIC_ADC_AUX 0
#define INGENIC_ADC_BATTERY 1
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment