Second set of iio new device support, features and cleanups for the 4.9 cycle.
New device support * ad8801 dac - new driver supporting ad8801 and ad8803 DACs. * adc12138 - new driver supporting TI adc12130/adc12132 and adc12138 ADCs. * ltc2485 adc - new driver * mxc6255 - add support for the mxc6225 part name and fixup the ID check so it works. * vz89x VOC sensor - add support for the vz89te part which drops the voc_short channel and adds CRCs compared to other supported parts. New features * core - immutable triggers. These effectively grant exclusive control over a trigger. The typical usecase is a device representing an analog part (perhaps a MUX) that needs to control the sampling of a downstream ADC. - resource managed trigger registration and triggered_buffer_init. - iio_push_event now protected against case of the event interface registration not having yet occured. Only matters if an interrupt can occur during this window - might happen on shared interrupt lines. - helper to let a driver query if the trigger it is using is provided by itself (using the convention of both device and trigger having the same parent). * tools - iio-utils. Used channel modifier scaling in preference to generic scaling when both exist. * at91-adc - Add support for touchscreen switches closure time needed by some newer parts. * stx104 - support the ADC channels on this ADC/DAC board. As these are the primary feature of the board also move the driver to the iio/adc directory. * sx9500 - device tree bindings. Cleanups / Fixes * ad5755 - fix an off-by-one on devnr limit check (introduced earlier this cycle) * ad7266 - drop NULL check on devm_regulator_get_optional as it can't return NULL. * ak8974 - avoid an unused functional warning due to rework in PM core code. - remove .owner field setting as done by i2c_core. * ina2xx - clear out a left over debug field from chip global data. * hid-sensors - avoid an unused functional warning due to rework in PM core code. * maxim-thermocouple - fix non static symbol warnings. * ms5611 - fetch and enable regulators unconditionally when they aren't optional. * sca3000 - whitespace cleanup. * st_sensors - fetch and enable regulators unconditionally rather than having them supported as optional regulators (missunderstanding on my part amongst others a while back) - followup to previous patch fixes error checking on the regulators. - mark symbols static where possible. - use the 'is it my trigger' help function. This prevents the odd case of another device triggering from the st-sensors trigger whilst the st-sensors trigger is itself not using it but rather using say an hrtimer. * ti-ads1015 - add missing of_node_put. * vz89x - rework to all support of new devices. - prevent reading of a corrupted buffer. - fixup a return value of 0/1 in a bool returning function. Address updates - Vlad Dogaru email address change. -----BEGIN PGP SIGNATURE----- iQIuBAABCAAYBQJX1wW9ERxqaWMyM0BrZXJuZWwub3JnAAoJEFSFNJnE9BaII9UP /jXkXtaL62pvipMuEujmpR7j/A+GhmSWHhnbJ9XXeGZStGMUummTyaM+6WZoCKUH bMtZh/ETsn+FI7mD7P/FtwHauoxSmndcaAfB6cDKQMVakbXbz4VHrim256cY3gvq dzF5nYX+wDue6D7k55VPrtV1isBfipeCXKBtzBlAXaVE2FK2qKP+PIlAln8Ql5/l b5B3pvqu0YVED4t2MzyVWcVidPOEh9GgwHu7Ba+kjVi6zuB4w+r5ZreIObb5IR54 FDcEwL6vV9AlmX15Pc18NO+50bZ8TvgT4y7ISqaOwszaIEoDAc0hXT7TdUOscmtt LIbhzHVMVkPSjxvtpz2ui8GfqzhxLi3ZzfNHRegOqH4b2Cpoh4zdwn7nCyJEHZV5 simAL00FGjzp6B4Zp+Ly6ygKzpF3iXZce0Qjlr/ge+ioNIrfuK10sdLw8NZA5GUB JcFYijcFLUb0Cu/KjZ7njlfdAN9Tt94xzpnllM8+j4M50Nhbw05YNhIxB7RxmeSH Y44/oBLG51SgtlIg5Z4rULRAcOC5dty73Inb0n4lbN/pjgIcnh+EYtPeI2fA8vyB XYqr4xx+A3ZX1yKpYLYO+JYtVsVq9RGYdb501uBhEE3/GWEpxZvbyqHnPwwfM+Pf ZNuBceBxM3yyi4Z/lKkZnQbaF/1fFoG7FO1n6iRpb8Ci =V1xL -----END PGP SIGNATURE----- Merge tag 'iio-for-4.9b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Second set of iio new device support, features and cleanups for the 4.9 cycle. New device support * ad8801 dac - new driver supporting ad8801 and ad8803 DACs. * adc12138 - new driver supporting TI adc12130/adc12132 and adc12138 ADCs. * ltc2485 adc - new driver * mxc6255 - add support for the mxc6225 part name and fixup the ID check so it works. * vz89x VOC sensor - add support for the vz89te part which drops the voc_short channel and adds CRCs compared to other supported parts. New features * core - immutable triggers. These effectively grant exclusive control over a trigger. The typical usecase is a device representing an analog part (perhaps a MUX) that needs to control the sampling of a downstream ADC. - resource managed trigger registration and triggered_buffer_init. - iio_push_event now protected against case of the event interface registration not having yet occured. Only matters if an interrupt can occur during this window - might happen on shared interrupt lines. - helper to let a driver query if the trigger it is using is provided by itself (using the convention of both device and trigger having the same parent). * tools - iio-utils. Used channel modifier scaling in preference to generic scaling when both exist. * at91-adc - Add support for touchscreen switches closure time needed by some newer parts. * stx104 - support the ADC channels on this ADC/DAC board. As these are the primary feature of the board also move the driver to the iio/adc directory. * sx9500 - device tree bindings. Cleanups / Fixes * ad5755 - fix an off-by-one on devnr limit check (introduced earlier this cycle) * ad7266 - drop NULL check on devm_regulator_get_optional as it can't return NULL. * ak8974 - avoid an unused functional warning due to rework in PM core code. - remove .owner field setting as done by i2c_core. * ina2xx - clear out a left over debug field from chip global data. * hid-sensors - avoid an unused functional warning due to rework in PM core code. * maxim-thermocouple - fix non static symbol warnings. * ms5611 - fetch and enable regulators unconditionally when they aren't optional. * sca3000 - whitespace cleanup. * st_sensors - fetch and enable regulators unconditionally rather than having them supported as optional regulators (missunderstanding on my part amongst others a while back) - followup to previous patch fixes error checking on the regulators. - mark symbols static where possible. - use the 'is it my trigger' help function. This prevents the odd case of another device triggering from the st-sensors trigger whilst the st-sensors trigger is itself not using it but rather using say an hrtimer. * ti-ads1015 - add missing of_node_put. * vz89x - rework to all support of new devices. - prevent reading of a corrupted buffer. - fixup a return value of 0/1 in a bool returning function. Address updates - Vlad Dogaru email address change.
This commit is contained in:
commit
552edf8d79
1
.mailmap
1
.mailmap
|
@ -159,6 +159,7 @@ Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
|
|||
Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
|
||||
Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
|
||||
Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
|
||||
Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
|
||||
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
|
||||
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
|
||||
Takashi YOSHII <takashi.yoshii.zj@renesas.com>
|
||||
|
|
37
Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt
Normal file
37
Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
* Texas Instruments' ADC12130/ADC12132/ADC12138
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of
|
||||
* "ti,adc12130"
|
||||
* "ti,adc12132"
|
||||
* "ti,adc12138"
|
||||
- reg: SPI chip select number for the device
|
||||
- interrupts: Should contain interrupt for EOC (end of conversion)
|
||||
- clocks: phandle to conversion clock input
|
||||
- spi-max-frequency: Definision as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
- vref-p-supply: The regulator supply for positive analog voltage reference
|
||||
|
||||
Optional properties:
|
||||
- vref-n-supply: The regulator supply for negative analog voltage reference
|
||||
(Note that this must not go below GND or exceed vref-p)
|
||||
If not specified, this is assumed to be analog ground.
|
||||
- ti,acquisition-time: The number of conversion clock periods for the S/H's
|
||||
acquisition time. Should be one of 6, 10, 18, 34. If not specified,
|
||||
default value of 10 is used.
|
||||
For high source impedances, this value can be increased to 18 or 34.
|
||||
For less ADC accuracy and/or slower CCLK frequencies this value may be
|
||||
decreased to 6. See section 6.0 INPUT SOURCE RESISTANCE in the
|
||||
datasheet for details.
|
||||
|
||||
Example:
|
||||
adc@0 {
|
||||
compatible = "ti,adc12138";
|
||||
reg = <0>;
|
||||
interrupts = <28 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
clocks = <&cclk>;
|
||||
vref-p-supply = <&ldo4_reg>;
|
||||
spi-max-frequency = <5000000>;
|
||||
ti,acquisition-time = <6>;
|
||||
};
|
24
Documentation/devicetree/bindings/iio/proximity/sx9500.txt
Normal file
24
Documentation/devicetree/bindings/iio/proximity/sx9500.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
Semtech's SX9500 capacitive proximity button device driver
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "semtech,sx9500"
|
||||
- reg: i2c address where to find the device
|
||||
- interrupt-parent : should be the phandle for the interrupt controller
|
||||
- interrupts : the sole interrupt generated by the device
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: Reference to the GPIO connected to the device's active
|
||||
low reset pin.
|
||||
|
||||
Example:
|
||||
|
||||
sx9500@28 {
|
||||
compatible = "semtech,sx9500";
|
||||
reg = <0x28>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
|
||||
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
|
||||
};
|
|
@ -266,8 +266,12 @@ IIO
|
|||
devm_iio_device_unregister()
|
||||
devm_iio_kfifo_allocate()
|
||||
devm_iio_kfifo_free()
|
||||
devm_iio_triggered_buffer_setup()
|
||||
devm_iio_triggered_buffer_cleanup()
|
||||
devm_iio_trigger_alloc()
|
||||
devm_iio_trigger_free()
|
||||
devm_iio_trigger_register()
|
||||
devm_iio_trigger_unregister()
|
||||
devm_iio_channel_get()
|
||||
devm_iio_channel_release()
|
||||
devm_iio_channel_get_all()
|
||||
|
|
|
@ -810,11 +810,11 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
|||
S: Maintained
|
||||
F: sound/aoa/
|
||||
|
||||
APEX EMBEDDED SYSTEMS STX104 DAC DRIVER
|
||||
APEX EMBEDDED SYSTEMS STX104 IIO DRIVER
|
||||
M: William Breathitt Gray <vilhelm.gray@gmail.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/iio/dac/stx104.c
|
||||
F: drivers/iio/adc/stx104.c
|
||||
|
||||
APM DRIVER
|
||||
M: Jiri Kosina <jikos@kernel.org>
|
||||
|
|
|
@ -154,7 +154,7 @@ static int mxc6255_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (chip_id != MXC6255_CHIP_ID) {
|
||||
if ((chip_id & 0x1f) != MXC6255_CHIP_ID) {
|
||||
dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -171,12 +171,14 @@ static int mxc6255_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
static const struct acpi_device_id mxc6255_acpi_match[] = {
|
||||
{"MXC6225", 0},
|
||||
{"MXC6255", 0},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
|
||||
|
||||
static const struct i2c_device_id mxc6255_id[] = {
|
||||
{"mxc6225", 0},
|
||||
{"mxc6255", 0},
|
||||
{ }
|
||||
};
|
||||
|
|
|
@ -264,6 +264,15 @@ config LPC18XX_ADC
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called lpc18xx_adc.
|
||||
|
||||
config LTC2485
|
||||
tristate "Linear Technology LTC2485 ADC driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Linear Technology LTC2485 ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ltc2485.
|
||||
|
||||
config MAX1027
|
||||
tristate "Maxim max1027 ADC driver"
|
||||
depends on SPI
|
||||
|
@ -410,6 +419,21 @@ config ROCKCHIP_SARADC
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called rockchip_saradc.
|
||||
|
||||
config STX104
|
||||
tristate "Apex Embedded Systems STX104 driver"
|
||||
depends on X86 && ISA_BUS_API
|
||||
select GPIOLIB
|
||||
help
|
||||
Say yes here to build support for the Apex Embedded Systems STX104
|
||||
integrated analog PC/104 card.
|
||||
|
||||
This driver supports the 16 channels of single-ended (8 channels of
|
||||
differential) analog inputs, 2 channels of analog output, 4 digital
|
||||
inputs, and 4 digital outputs provided by the STX104.
|
||||
|
||||
The base port addresses for the devices may be configured via the base
|
||||
array module parameter.
|
||||
|
||||
config TI_ADC081C
|
||||
tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
|
||||
depends on I2C
|
||||
|
@ -430,6 +454,18 @@ config TI_ADC0832
|
|||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-adc0832.
|
||||
|
||||
config TI_ADC12138
|
||||
tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments ADC12130,
|
||||
ADC12132 and ADC12138 chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called ti-adc12138.
|
||||
|
||||
config TI_ADC128S052
|
||||
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
|
||||
depends on SPI
|
||||
|
|
|
@ -27,6 +27,7 @@ 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_MAX1363) += max1363.o
|
||||
obj-$(CONFIG_MCP320X) += mcp320x.o
|
||||
|
@ -39,8 +40,10 @@ 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_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
|
||||
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
|
||||
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
|
||||
|
|
|
@ -481,7 +481,7 @@ error_free_gpios:
|
|||
if (!st->fixed_addr)
|
||||
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
|
||||
error_disable_reg:
|
||||
if (!IS_ERR_OR_NULL(st->reg))
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
|
@ -496,7 +496,7 @@ static int ad7266_remove(struct spi_device *spi)
|
|||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (!st->fixed_addr)
|
||||
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
|
||||
if (!IS_ERR_OR_NULL(st->reg))
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */
|
||||
#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4)
|
||||
#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */
|
||||
#define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16)
|
||||
#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */
|
||||
#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28)
|
||||
#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */
|
||||
|
@ -150,6 +151,7 @@
|
|||
#define MAX_RLPOS_BITS 10
|
||||
#define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */
|
||||
#define TOUCH_SHTIM 0xa
|
||||
#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */
|
||||
|
||||
/**
|
||||
* struct at91_adc_reg_desc - Various informations relative to registers
|
||||
|
@ -1001,7 +1003,9 @@ static void atmel_ts_close(struct input_dev *dev)
|
|||
|
||||
static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
|
||||
{
|
||||
struct iio_dev *idev = iio_priv_to_dev(st);
|
||||
u32 reg = 0;
|
||||
u32 tssctim = 0;
|
||||
int i = 0;
|
||||
|
||||
/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
|
||||
|
@ -1034,11 +1038,20 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Touchscreen Switches Closure time needed for allowing the value to
|
||||
* stabilize.
|
||||
* Switch Closure Time = (TSSCTIM * 4) ADCClock periods
|
||||
*/
|
||||
tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4);
|
||||
dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n",
|
||||
adc_clk_khz, tssctim);
|
||||
|
||||
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
|
||||
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
|
||||
else
|
||||
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
|
||||
|
||||
reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM;
|
||||
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
|
||||
& AT91_ADC_TSMR_TSAV;
|
||||
reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC;
|
||||
|
|
|
@ -114,7 +114,6 @@ struct ina2xx_chip_info {
|
|||
struct mutex state_lock;
|
||||
unsigned int shunt_resistor;
|
||||
int avg;
|
||||
s64 prev_ns; /* track buffer capture time, check for underruns */
|
||||
int int_time_vbus; /* Bus voltage integration time uS */
|
||||
int int_time_vshunt; /* Shunt voltage integration time uS */
|
||||
bool allow_async_readout;
|
||||
|
@ -509,8 +508,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
|
|||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
(unsigned int *)data, time_a);
|
||||
|
||||
chip->prev_ns = time_a;
|
||||
|
||||
return (unsigned long)(time_b - time_a) / 1000;
|
||||
};
|
||||
|
||||
|
@ -554,8 +551,6 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
|
|||
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
|
||||
chip->allow_async_readout);
|
||||
|
||||
chip->prev_ns = iio_get_time_ns(indio_dev);
|
||||
|
||||
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
|
||||
"%s:%d-%uus", indio_dev->name, indio_dev->id,
|
||||
sampling_us);
|
||||
|
|
148
drivers/iio/adc/ltc2485.c
Normal file
148
drivers/iio/adc/ltc2485.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* ltc2485.c - Driver for Linear Technology LTC2485 ADC
|
||||
*
|
||||
* Copyright (C) 2016 Alison Schofield <amsfield22@gmail.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.
|
||||
*
|
||||
* Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/* Power-on configuration: rejects both 50/60Hz, operates at 1x speed */
|
||||
#define LTC2485_CONFIG_DEFAULT 0
|
||||
|
||||
struct ltc2485_data {
|
||||
struct i2c_client *client;
|
||||
ktime_t time_prev; /* last conversion */
|
||||
};
|
||||
|
||||
static void ltc2485_wait_conv(struct ltc2485_data *data)
|
||||
{
|
||||
const unsigned int conv_time = 147; /* conversion time ms */
|
||||
unsigned int time_elapsed;
|
||||
|
||||
/* delay if conversion time not passed since last read or write */
|
||||
time_elapsed = ktime_ms_delta(ktime_get(), data->time_prev);
|
||||
|
||||
if (time_elapsed < conv_time)
|
||||
msleep(conv_time - time_elapsed);
|
||||
}
|
||||
|
||||
static int ltc2485_read(struct ltc2485_data *data, int *val)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
__be32 buf = 0;
|
||||
int ret;
|
||||
|
||||
ltc2485_wait_conv(data);
|
||||
|
||||
ret = i2c_master_recv(client, (char *)&buf, 4);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "i2c_master_recv failed\n");
|
||||
return ret;
|
||||
}
|
||||
data->time_prev = ktime_get();
|
||||
*val = sign_extend32(be32_to_cpu(buf) >> 6, 24);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2485_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ltc2485_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (mask == IIO_CHAN_INFO_RAW) {
|
||||
ret = ltc2485_read(data, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
} else if (mask == IIO_CHAN_INFO_SCALE) {
|
||||
*val = 5000; /* on board vref millivolts */
|
||||
*val2 = 25; /* 25 (24 + sign) data bits */
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ltc2485_channel[] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_info ltc2485_info = {
|
||||
.read_raw = ltc2485_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ltc2485_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ltc2485_data *data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->info = <c2485_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ltc2485_channel;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ltc2485_channel);
|
||||
|
||||
ret = i2c_smbus_write_byte(data->client, LTC2485_CONFIG_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->time_prev = ktime_get();
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc2485_id[] = {
|
||||
{ "ltc2485", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2485_id);
|
||||
|
||||
static struct i2c_driver ltc2485_driver = {
|
||||
.driver = {
|
||||
.name = "ltc2485",
|
||||
},
|
||||
.probe = ltc2485_probe,
|
||||
.id_table = ltc2485_id,
|
||||
};
|
||||
module_i2c_driver(ltc2485_driver);
|
||||
|
||||
MODULE_AUTHOR("Alison Schofield <amsfield22@gmail.com>");
|
||||
MODULE_DESCRIPTION("Linear Technology LTC2485 ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* DAC driver for the Apex Embedded Systems STX104
|
||||
* IIO driver for the Apex Embedded Systems STX104
|
||||
* Copyright (C) 2016 William Breathitt Gray
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -20,19 +20,30 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define STX104_NUM_CHAN 2
|
||||
|
||||
#define STX104_CHAN(chan) { \
|
||||
#define STX104_OUT_CHAN(chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.output = 1 \
|
||||
}
|
||||
#define STX104_IN_CHAN(chan, diff) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = chan, \
|
||||
.channel2 = chan, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.differential = diff \
|
||||
}
|
||||
|
||||
#define STX104_NUM_OUT_CHAN 2
|
||||
|
||||
#define STX104_EXTENT 16
|
||||
|
||||
|
@ -47,8 +58,8 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
|
|||
* @base: base port address of the IIO device
|
||||
*/
|
||||
struct stx104_iio {
|
||||
unsigned chan_out_states[STX104_NUM_CHAN];
|
||||
unsigned base;
|
||||
unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -79,28 +90,95 @@ static int stx104_read_raw(struct iio_dev *indio_dev,
|
|||
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
|
||||
{
|
||||
struct stx104_iio *const priv = iio_priv(indio_dev);
|
||||
unsigned int adc_config;
|
||||
int adbu;
|
||||
int gain;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
return -EINVAL;
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
/* get gain configuration */
|
||||
adc_config = inb(priv->base + 11);
|
||||
gain = adc_config & 0x3;
|
||||
|
||||
*val = priv->chan_out_states[chan->channel];
|
||||
*val = 1 << gain;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->output) {
|
||||
*val = priv->chan_out_states[chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT;
|
||||
/* select ADC channel */
|
||||
outb(chan->channel | (chan->channel << 4), priv->base + 2);
|
||||
|
||||
/* trigger ADC sample capture and wait for completion */
|
||||
outb(0, priv->base);
|
||||
while (inb(priv->base + 8) & BIT(7));
|
||||
|
||||
*val = inw(priv->base);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/* get ADC bipolar/unipolar configuration */
|
||||
adc_config = inb(priv->base + 11);
|
||||
adbu = !(adc_config & BIT(2));
|
||||
|
||||
*val = -32768 * adbu;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/* get ADC bipolar/unipolar and gain configuration */
|
||||
adc_config = inb(priv->base + 11);
|
||||
adbu = !(adc_config & BIT(2));
|
||||
gain = adc_config & 0x3;
|
||||
|
||||
*val = 5;
|
||||
*val2 = 15 - adbu + gain;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stx104_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val, int val2, long mask)
|
||||
{
|
||||
struct stx104_iio *const priv = iio_priv(indio_dev);
|
||||
const unsigned chan_addr_offset = 2 * chan->channel;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_RAW)
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
/* Only four gain states (x1, x2, x4, x8) */
|
||||
switch (val) {
|
||||
case 1:
|
||||
outb(0, priv->base + 11);
|
||||
break;
|
||||
case 2:
|
||||
outb(1, priv->base + 11);
|
||||
break;
|
||||
case 4:
|
||||
outb(2, priv->base + 11);
|
||||
break;
|
||||
case 8:
|
||||
outb(3, priv->base + 11);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->output) {
|
||||
/* DAC can only accept up to a 16-bit value */
|
||||
if ((unsigned int)val > 65535)
|
||||
return -EINVAL;
|
||||
|
||||
priv->chan_out_states[chan->channel] = val;
|
||||
outw(val, priv->base + 4 + 2 * chan->channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->chan_out_states[chan->channel] = val;
|
||||
outw(val, priv->base + 4 + chan_addr_offset);
|
||||
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info stx104_info = {
|
||||
|
@ -109,9 +187,22 @@ static const struct iio_info stx104_info = {
|
|||
.write_raw = stx104_write_raw
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
|
||||
STX104_CHAN(0),
|
||||
STX104_CHAN(1)
|
||||
/* single-ended input channels configuration */
|
||||
static const struct iio_chan_spec stx104_channels_sing[] = {
|
||||
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
|
||||
STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
|
||||
STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
|
||||
STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
|
||||
STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
|
||||
STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
|
||||
STX104_IN_CHAN(15, 0)
|
||||
};
|
||||
/* differential input channels configuration */
|
||||
static const struct iio_chan_spec stx104_channels_diff[] = {
|
||||
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
|
||||
STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
|
||||
STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
|
||||
STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
|
||||
};
|
||||
|
||||
static int stx104_gpio_get_direction(struct gpio_chip *chip,
|
||||
|
@ -204,13 +295,27 @@ static int stx104_probe(struct device *dev, unsigned int id)
|
|||
|
||||
indio_dev->info = &stx104_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = stx104_channels;
|
||||
indio_dev->num_channels = STX104_NUM_CHAN;
|
||||
|
||||
/* determine if differential inputs */
|
||||
if (inb(base[id] + 8) & BIT(5)) {
|
||||
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
|
||||
indio_dev->channels = stx104_channels_diff;
|
||||
} else {
|
||||
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
|
||||
indio_dev->channels = stx104_channels_sing;
|
||||
}
|
||||
|
||||
indio_dev->name = dev_name(dev);
|
||||
|
||||
priv = iio_priv(indio_dev);
|
||||
priv->base = base[id];
|
||||
|
||||
/* configure device for software trigger operation */
|
||||
outb(0, base[id] + 9);
|
||||
|
||||
/* initialize gain setting to x1 */
|
||||
outb(0, base[id] + 11);
|
||||
|
||||
/* initialize DAC output to 0V */
|
||||
outw(0, base[id] + 4);
|
||||
outw(0, base[id] + 6);
|
||||
|
@ -271,5 +376,5 @@ static struct isa_driver stx104_driver = {
|
|||
module_isa_driver(stx104_driver, num_stx104);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver");
|
||||
MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
552
drivers/iio/adc/ti-adc12138.c
Normal file
552
drivers/iio/adc/ti-adc12138.c
Normal file
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* ADC12130/ADC12132/ADC12138 12-bit plus sign ADC driver
|
||||
*
|
||||
* Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Datasheet: http://www.ti.com/lit/ds/symlink/adc12138.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define ADC12138_MODE_AUTO_CAL 0x08
|
||||
#define ADC12138_MODE_READ_STATUS 0x0c
|
||||
#define ADC12138_MODE_ACQUISITION_TIME_6 0x0e
|
||||
#define ADC12138_MODE_ACQUISITION_TIME_10 0x4e
|
||||
#define ADC12138_MODE_ACQUISITION_TIME_18 0x8e
|
||||
#define ADC12138_MODE_ACQUISITION_TIME_34 0xce
|
||||
|
||||
#define ADC12138_STATUS_CAL BIT(6)
|
||||
|
||||
enum {
|
||||
adc12130,
|
||||
adc12132,
|
||||
adc12138,
|
||||
};
|
||||
|
||||
struct adc12138 {
|
||||
struct spi_device *spi;
|
||||
unsigned int id;
|
||||
/* conversion clock */
|
||||
struct clk *cclk;
|
||||
/* positive analog voltage reference */
|
||||
struct regulator *vref_p;
|
||||
/* negative analog voltage reference */
|
||||
struct regulator *vref_n;
|
||||
struct mutex lock;
|
||||
struct completion complete;
|
||||
/* The number of cclk periods for the S/H's acquisition time */
|
||||
unsigned int acquisition_time;
|
||||
|
||||
u8 tx_buf[2] ____cacheline_aligned;
|
||||
u8 rx_buf[2];
|
||||
};
|
||||
|
||||
#define ADC12138_VOLTAGE_CHANNEL(chan) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
| BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.scan_index = chan, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 13, \
|
||||
.storagebits = 16, \
|
||||
.shift = 3, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define ADC12138_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (chan1), \
|
||||
.channel2 = (chan2), \
|
||||
.differential = 1, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
|
||||
| BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
.scan_index = si, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 13, \
|
||||
.storagebits = 16, \
|
||||
.shift = 3, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adc12132_channels[] = {
|
||||
ADC12138_VOLTAGE_CHANNEL(0),
|
||||
ADC12138_VOLTAGE_CHANNEL(1),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 2),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 3),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec adc12138_channels[] = {
|
||||
ADC12138_VOLTAGE_CHANNEL(0),
|
||||
ADC12138_VOLTAGE_CHANNEL(1),
|
||||
ADC12138_VOLTAGE_CHANNEL(2),
|
||||
ADC12138_VOLTAGE_CHANNEL(3),
|
||||
ADC12138_VOLTAGE_CHANNEL(4),
|
||||
ADC12138_VOLTAGE_CHANNEL(5),
|
||||
ADC12138_VOLTAGE_CHANNEL(6),
|
||||
ADC12138_VOLTAGE_CHANNEL(7),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 9),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(2, 3, 10),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(3, 2, 11),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(4, 5, 12),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(5, 4, 13),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(6, 7, 14),
|
||||
ADC12138_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(16),
|
||||
};
|
||||
|
||||
static int adc12138_mode_programming(struct adc12138 *adc, u8 mode,
|
||||
void *rx_buf, int len)
|
||||
{
|
||||
struct spi_transfer xfer = {
|
||||
.tx_buf = adc->tx_buf,
|
||||
.rx_buf = adc->rx_buf,
|
||||
.len = len,
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* Skip unused bits for ADC12130 and ADC12132 */
|
||||
if (adc->id != adc12138)
|
||||
mode = (mode & 0xc0) | ((mode & 0x0f) << 2);
|
||||
|
||||
adc->tx_buf[0] = mode;
|
||||
|
||||
ret = spi_sync_transfer(adc->spi, &xfer, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(rx_buf, adc->rx_buf, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc12138_read_status(struct adc12138 *adc)
|
||||
{
|
||||
u8 rx_buf[2];
|
||||
int ret;
|
||||
|
||||
ret = adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
|
||||
rx_buf, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (rx_buf[0] << 1) | (rx_buf[1] >> 7);
|
||||
}
|
||||
|
||||
static int __adc12138_start_conv(struct adc12138 *adc,
|
||||
struct iio_chan_spec const *channel,
|
||||
void *data, int len)
|
||||
|
||||
{
|
||||
const u8 ch_to_mux[] = { 0, 4, 1, 5, 2, 6, 3, 7 };
|
||||
u8 mode = (ch_to_mux[channel->channel] << 4) |
|
||||
(channel->differential ? 0 : 0x80);
|
||||
|
||||
return adc12138_mode_programming(adc, mode, data, len);
|
||||
}
|
||||
|
||||
static int adc12138_start_conv(struct adc12138 *adc,
|
||||
struct iio_chan_spec const *channel)
|
||||
{
|
||||
u8 trash;
|
||||
|
||||
return __adc12138_start_conv(adc, channel, &trash, 1);
|
||||
}
|
||||
|
||||
static int adc12138_start_and_read_conv(struct adc12138 *adc,
|
||||
struct iio_chan_spec const *channel,
|
||||
__be16 *data)
|
||||
{
|
||||
return __adc12138_start_conv(adc, channel, data, 2);
|
||||
}
|
||||
|
||||
static int adc12138_read_conv_data(struct adc12138 *adc, __be16 *value)
|
||||
{
|
||||
/* Issue a read status instruction and read previous conversion data */
|
||||
return adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
|
||||
value, sizeof(*value));
|
||||
}
|
||||
|
||||
static int adc12138_wait_eoc(struct adc12138 *adc, unsigned long timeout)
|
||||
{
|
||||
if (!wait_for_completion_timeout(&adc->complete, timeout))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adc12138_adc_conversion(struct adc12138 *adc,
|
||||
struct iio_chan_spec const *channel,
|
||||
__be16 *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
reinit_completion(&adc->complete);
|
||||
|
||||
ret = adc12138_start_conv(adc, channel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return adc12138_read_conv_data(adc, value);
|
||||
}
|
||||
|
||||
static int adc12138_read_raw(struct iio_dev *iio,
|
||||
struct iio_chan_spec const *channel, int *value,
|
||||
int *shift, long mask)
|
||||
{
|
||||
struct adc12138 *adc = iio_priv(iio);
|
||||
int ret;
|
||||
__be16 data;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&adc->lock);
|
||||
ret = adc12138_adc_conversion(adc, channel, &data);
|
||||
mutex_unlock(&adc->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*value = sign_extend32(be16_to_cpu(data) >> 3, 12);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regulator_get_voltage(adc->vref_p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*value = ret;
|
||||
|
||||
if (!IS_ERR(adc->vref_n)) {
|
||||
ret = regulator_get_voltage(adc->vref_n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*value -= ret;
|
||||
}
|
||||
|
||||
/* convert regulator output voltage to mV */
|
||||
*value /= 1000;
|
||||
*shift = channel->scan_type.realbits - 1;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
if (!IS_ERR(adc->vref_n)) {
|
||||
*value = regulator_get_voltage(adc->vref_n);
|
||||
if (*value < 0)
|
||||
return *value;
|
||||
} else {
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
/* convert regulator output voltage to mV */
|
||||
*value /= 1000;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info adc12138_info = {
|
||||
.read_raw = adc12138_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int adc12138_init(struct adc12138 *adc)
|
||||
{
|
||||
int ret;
|
||||
int status;
|
||||
u8 mode;
|
||||
u8 trash;
|
||||
|
||||
reinit_completion(&adc->complete);
|
||||
|
||||
ret = adc12138_mode_programming(adc, ADC12138_MODE_AUTO_CAL, &trash, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* data output at this time has no significance */
|
||||
status = adc12138_read_status(adc);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
adc12138_wait_eoc(adc, msecs_to_jiffies(100));
|
||||
|
||||
status = adc12138_read_status(adc);
|
||||
if (status & ADC12138_STATUS_CAL) {
|
||||
dev_warn(&adc->spi->dev,
|
||||
"Auto Cal sequence is still in progress: %#x\n",
|
||||
status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
switch (adc->acquisition_time) {
|
||||
case 6:
|
||||
mode = ADC12138_MODE_ACQUISITION_TIME_6;
|
||||
break;
|
||||
case 10:
|
||||
mode = ADC12138_MODE_ACQUISITION_TIME_10;
|
||||
break;
|
||||
case 18:
|
||||
mode = ADC12138_MODE_ACQUISITION_TIME_18;
|
||||
break;
|
||||
case 34:
|
||||
mode = ADC12138_MODE_ACQUISITION_TIME_34;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return adc12138_mode_programming(adc, mode, &trash, 1);
|
||||
}
|
||||
|
||||
static irqreturn_t adc12138_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct adc12138 *adc = iio_priv(indio_dev);
|
||||
__be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */
|
||||
__be16 trash;
|
||||
int ret;
|
||||
int scan_index;
|
||||
int i = 0;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
const struct iio_chan_spec *scan_chan =
|
||||
&indio_dev->channels[scan_index];
|
||||
|
||||
reinit_completion(&adc->complete);
|
||||
|
||||
ret = adc12138_start_and_read_conv(adc, scan_chan,
|
||||
i ? &data[i - 1] : &trash);
|
||||
if (ret) {
|
||||
dev_warn(&adc->spi->dev,
|
||||
"failed to start conversion\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
|
||||
if (ret) {
|
||||
dev_warn(&adc->spi->dev, "wait eoc timeout\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i) {
|
||||
ret = adc12138_read_conv_data(adc, &data[i - 1]);
|
||||
if (ret) {
|
||||
dev_warn(&adc->spi->dev,
|
||||
"failed to get conversion data\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
mutex_unlock(&adc->lock);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t adc12138_eoc_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_dev *indio_dev = p;
|
||||
struct adc12138 *adc = iio_priv(indio_dev);
|
||||
|
||||
complete(&adc->complete);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adc12138_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct adc12138 *adc;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->spi = spi;
|
||||
adc->id = spi_get_device_id(spi)->driver_data;
|
||||
mutex_init(&adc->lock);
|
||||
init_completion(&adc->complete);
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &adc12138_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
switch (adc->id) {
|
||||
case adc12130:
|
||||
case adc12132:
|
||||
indio_dev->channels = adc12132_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adc12132_channels);
|
||||
break;
|
||||
case adc12138:
|
||||
indio_dev->channels = adc12138_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adc12138_channels);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(spi->dev.of_node, "ti,acquisition-time",
|
||||
&adc->acquisition_time);
|
||||
if (ret)
|
||||
adc->acquisition_time = 10;
|
||||
|
||||
adc->cclk = devm_clk_get(&spi->dev, NULL);
|
||||
if (IS_ERR(adc->cclk))
|
||||
return PTR_ERR(adc->cclk);
|
||||
|
||||
adc->vref_p = devm_regulator_get(&spi->dev, "vref-p");
|
||||
if (IS_ERR(adc->vref_p))
|
||||
return PTR_ERR(adc->vref_p);
|
||||
|
||||
adc->vref_n = devm_regulator_get_optional(&spi->dev, "vref-n");
|
||||
if (IS_ERR(adc->vref_n)) {
|
||||
/*
|
||||
* Assume vref_n is 0V if an optional regulator is not
|
||||
* specified, otherwise return the error code.
|
||||
*/
|
||||
ret = PTR_ERR(adc->vref_n);
|
||||
if (ret != -ENODEV)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler,
|
||||
IRQF_TRIGGER_RISING, indio_dev->name, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->cclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(adc->vref_p);
|
||||
if (ret)
|
||||
goto err_clk_disable;
|
||||
|
||||
if (!IS_ERR(adc->vref_n)) {
|
||||
ret = regulator_enable(adc->vref_n);
|
||||
if (ret)
|
||||
goto err_vref_p_disable;
|
||||
}
|
||||
|
||||
ret = adc12138_init(adc);
|
||||
if (ret)
|
||||
goto err_vref_n_disable;
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
adc12138_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto err_vref_n_disable;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto err_buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
err_vref_n_disable:
|
||||
if (!IS_ERR(adc->vref_n))
|
||||
regulator_disable(adc->vref_n);
|
||||
err_vref_p_disable:
|
||||
regulator_disable(adc->vref_p);
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(adc->cclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adc12138_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct adc12138 *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
if (!IS_ERR(adc->vref_n))
|
||||
regulator_disable(adc->vref_n);
|
||||
regulator_disable(adc->vref_p);
|
||||
clk_disable_unprepare(adc->cclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
static const struct of_device_id adc12138_dt_ids[] = {
|
||||
{ .compatible = "ti,adc12130", },
|
||||
{ .compatible = "ti,adc12132", },
|
||||
{ .compatible = "ti,adc12138", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc12138_dt_ids);
|
||||
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id adc12138_id[] = {
|
||||
{ "adc12130", adc12130 },
|
||||
{ "adc12132", adc12132 },
|
||||
{ "adc12138", adc12138 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, adc12138_id);
|
||||
|
||||
static struct spi_driver adc12138_driver = {
|
||||
.driver = {
|
||||
.name = "adc12138",
|
||||
.of_match_table = of_match_ptr(adc12138_dt_ids),
|
||||
},
|
||||
.probe = adc12138_probe,
|
||||
.remove = adc12138_remove,
|
||||
.id_table = adc12138_id,
|
||||
};
|
||||
module_spi_driver(adc12138_driver);
|
||||
|
||||
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
|
||||
MODULE_DESCRIPTION("ADC12130/ADC12132/ADC12138 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -522,6 +522,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
|
|||
if (pga > 6) {
|
||||
dev_err(&client->dev, "invalid gain on %s\n",
|
||||
node->full_name);
|
||||
of_node_put(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -532,6 +533,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
|
|||
dev_err(&client->dev,
|
||||
"invalid data_rate on %s\n",
|
||||
node->full_name);
|
||||
of_node_put(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -438,7 +438,7 @@ static int ads8688_probe(struct spi_device *spi)
|
|||
return 0;
|
||||
|
||||
error_out:
|
||||
if (!IS_ERR_OR_NULL(st->reg))
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return ret;
|
||||
|
@ -451,7 +451,7 @@ static int ads8688_remove(struct spi_device *spi)
|
|||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(st->reg))
|
||||
if (!IS_ERR(st->reg))
|
||||
regulator_disable(st->reg);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -98,6 +98,48 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
|
|||
}
|
||||
EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
|
||||
|
||||
static void devm_iio_triggered_buffer_clean(struct device *dev, void *res)
|
||||
{
|
||||
iio_triggered_buffer_cleanup(*(struct iio_dev **)res);
|
||||
}
|
||||
|
||||
int devm_iio_triggered_buffer_setup(struct device *dev,
|
||||
struct iio_dev *indio_dev,
|
||||
irqreturn_t (*h)(int irq, void *p),
|
||||
irqreturn_t (*thread)(int irq, void *p),
|
||||
const struct iio_buffer_setup_ops *ops)
|
||||
{
|
||||
struct iio_dev **ptr;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
*ptr = indio_dev;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops);
|
||||
if (!ret)
|
||||
devres_add(dev, ptr);
|
||||
else
|
||||
devres_free(ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup);
|
||||
|
||||
void devm_iio_triggered_buffer_cleanup(struct device *dev,
|
||||
struct iio_dev *indio_dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = devres_release(dev, devm_iio_triggered_buffer_clean,
|
||||
devm_iio_device_match, indio_dev);
|
||||
WARN_ON(rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -19,25 +19,55 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define VZ89X_REG_MEASUREMENT 0x09
|
||||
#define VZ89X_REG_MEASUREMENT_SIZE 6
|
||||
#define VZ89X_REG_MEASUREMENT_RD_SIZE 6
|
||||
#define VZ89X_REG_MEASUREMENT_WR_SIZE 3
|
||||
|
||||
#define VZ89X_VOC_CO2_IDX 0
|
||||
#define VZ89X_VOC_SHORT_IDX 1
|
||||
#define VZ89X_VOC_TVOC_IDX 2
|
||||
#define VZ89X_VOC_RESISTANCE_IDX 3
|
||||
|
||||
#define VZ89TE_REG_MEASUREMENT 0x0c
|
||||
#define VZ89TE_REG_MEASUREMENT_RD_SIZE 7
|
||||
#define VZ89TE_REG_MEASUREMENT_WR_SIZE 6
|
||||
|
||||
#define VZ89TE_VOC_TVOC_IDX 0
|
||||
#define VZ89TE_VOC_CO2_IDX 1
|
||||
#define VZ89TE_VOC_RESISTANCE_IDX 2
|
||||
|
||||
enum {
|
||||
VZ89X,
|
||||
VZ89TE,
|
||||
};
|
||||
|
||||
struct vz89x_chip_data;
|
||||
|
||||
struct vz89x_data {
|
||||
struct i2c_client *client;
|
||||
const struct vz89x_chip_data *chip;
|
||||
struct mutex lock;
|
||||
int (*xfer)(struct vz89x_data *data, u8 cmd);
|
||||
|
||||
bool is_valid;
|
||||
unsigned long last_update;
|
||||
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
|
||||
u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE];
|
||||
};
|
||||
|
||||
struct vz89x_chip_data {
|
||||
bool (*valid)(struct vz89x_data *data);
|
||||
const struct iio_chan_spec *channels;
|
||||
u8 num_channels;
|
||||
|
||||
u8 cmd;
|
||||
u8 read_size;
|
||||
u8 write_size;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec vz89x_channels[] = {
|
||||
|
@ -70,6 +100,40 @@ static const struct iio_chan_spec vz89x_channels[] = {
|
|||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = VZ89X_VOC_RESISTANCE_IDX,
|
||||
.scan_index = -1,
|
||||
.scan_type = {
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec vz89te_channels[] = {
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_VOC,
|
||||
.modified = 1,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
|
||||
.address = VZ89TE_VOC_TVOC_IDX,
|
||||
},
|
||||
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
.channel2 = IIO_MOD_CO2,
|
||||
.modified = 1,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
|
||||
.address = VZ89TE_VOC_CO2_IDX,
|
||||
},
|
||||
{
|
||||
.type = IIO_RESISTANCE,
|
||||
.info_mask_separate =
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = VZ89TE_VOC_RESISTANCE_IDX,
|
||||
.scan_index = -1,
|
||||
.scan_type = {
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -93,29 +157,45 @@ static const struct attribute_group vz89x_attrs_group = {
|
|||
* always zero, and by also confirming the VOC_short isn't zero.
|
||||
*/
|
||||
|
||||
static int vz89x_measurement_is_valid(struct vz89x_data *data)
|
||||
static bool vz89x_measurement_is_valid(struct vz89x_data *data)
|
||||
{
|
||||
if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
|
||||
return 1;
|
||||
return true;
|
||||
|
||||
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
|
||||
return !!(data->buffer[data->chip->read_size - 1] > 0);
|
||||
}
|
||||
|
||||
/* VZ89TE device has a modified CRC-8 two complement check */
|
||||
static bool vz89te_measurement_is_valid(struct vz89x_data *data)
|
||||
{
|
||||
u8 crc = 0;
|
||||
int i, sum = 0;
|
||||
|
||||
for (i = 0; i < (data->chip->read_size - 1); i++) {
|
||||
sum = crc + data->buffer[i];
|
||||
crc = sum;
|
||||
crc += sum / 256;
|
||||
}
|
||||
|
||||
return !((0xff - crc) == data->buffer[data->chip->read_size - 1]);
|
||||
}
|
||||
|
||||
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
|
||||
{
|
||||
const struct vz89x_chip_data *chip = data->chip;
|
||||
struct i2c_client *client = data->client;
|
||||
struct i2c_msg msg[2];
|
||||
int ret;
|
||||
u8 buf[3] = { cmd, 0, 0};
|
||||
u8 buf[6] = { cmd, 0, 0, 0, 0, 0xf3 };
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = client->flags;
|
||||
msg[0].len = 3;
|
||||
msg[0].len = chip->write_size;
|
||||
msg[0].buf = (char *) &buf;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = client->flags | I2C_M_RD;
|
||||
msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
|
||||
msg[1].len = chip->read_size;
|
||||
msg[1].buf = (char *) &data->buffer;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
|
@ -133,7 +213,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
|
||||
for (i = 0; i < data->chip->read_size; i++) {
|
||||
ret = i2c_smbus_read_byte(client);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -145,30 +225,47 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
|
|||
|
||||
static int vz89x_get_measurement(struct vz89x_data *data)
|
||||
{
|
||||
const struct vz89x_chip_data *chip = data->chip;
|
||||
int ret;
|
||||
|
||||
/* sensor can only be polled once a second max per datasheet */
|
||||
if (!time_after(jiffies, data->last_update + HZ))
|
||||
return 0;
|
||||
return data->is_valid ? 0 : -EAGAIN;
|
||||
|
||||
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
|
||||
data->is_valid = false;
|
||||
data->last_update = jiffies;
|
||||
|
||||
ret = data->xfer(data, chip->cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = vz89x_measurement_is_valid(data);
|
||||
ret = chip->valid(data);
|
||||
if (ret)
|
||||
return -EAGAIN;
|
||||
|
||||
data->last_update = jiffies;
|
||||
data->is_valid = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vz89x_get_resistance_reading(struct vz89x_data *data)
|
||||
static int vz89x_get_resistance_reading(struct vz89x_data *data,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val)
|
||||
{
|
||||
u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
|
||||
u8 *tmp = (u8 *) &data->buffer[chan->address];
|
||||
|
||||
return buf[0] | (buf[1] << 8);
|
||||
switch (chan->scan_type.endianness) {
|
||||
case IIO_LE:
|
||||
*val = le32_to_cpup((__le32 *) tmp) & GENMASK(23, 0);
|
||||
break;
|
||||
case IIO_BE:
|
||||
*val = be32_to_cpup((__be32 *) tmp) >> 8;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vz89x_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -187,15 +284,15 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (chan->address) {
|
||||
case VZ89X_VOC_CO2_IDX:
|
||||
case VZ89X_VOC_SHORT_IDX:
|
||||
case VZ89X_VOC_TVOC_IDX:
|
||||
switch (chan->type) {
|
||||
case IIO_CONCENTRATION:
|
||||
*val = data->buffer[chan->address];
|
||||
return IIO_VAL_INT;
|
||||
case VZ89X_VOC_RESISTANCE_IDX:
|
||||
*val = vz89x_get_resistance_reading(data);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_RESISTANCE:
|
||||
ret = vz89x_get_resistance_reading(data, chan, val);
|
||||
if (!ret)
|
||||
return IIO_VAL_INT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -210,12 +307,12 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
switch (chan->address) {
|
||||
case VZ89X_VOC_CO2_IDX:
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_CO2:
|
||||
*val = 44;
|
||||
*val2 = 250000;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case VZ89X_VOC_TVOC_IDX:
|
||||
case IIO_MOD_VOC:
|
||||
*val = -13;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
|
@ -232,11 +329,43 @@ static const struct iio_info vz89x_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct vz89x_chip_data vz89x_chips[] = {
|
||||
{
|
||||
.valid = vz89x_measurement_is_valid,
|
||||
|
||||
.cmd = VZ89X_REG_MEASUREMENT,
|
||||
.read_size = VZ89X_REG_MEASUREMENT_RD_SIZE,
|
||||
.write_size = VZ89X_REG_MEASUREMENT_WR_SIZE,
|
||||
|
||||
.channels = vz89x_channels,
|
||||
.num_channels = ARRAY_SIZE(vz89x_channels),
|
||||
},
|
||||
{
|
||||
.valid = vz89te_measurement_is_valid,
|
||||
|
||||
.cmd = VZ89TE_REG_MEASUREMENT,
|
||||
.read_size = VZ89TE_REG_MEASUREMENT_RD_SIZE,
|
||||
.write_size = VZ89TE_REG_MEASUREMENT_WR_SIZE,
|
||||
|
||||
.channels = vz89te_channels,
|
||||
.num_channels = ARRAY_SIZE(vz89te_channels),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id vz89x_dt_ids[] = {
|
||||
{ .compatible = "sgx,vz89x", .data = (void *) VZ89X },
|
||||
{ .compatible = "sgx,vz89te", .data = (void *) VZ89TE },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
|
||||
|
||||
static int vz89x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct vz89x_data *data;
|
||||
const struct of_device_id *of_id;
|
||||
int chip_id;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
@ -251,8 +380,15 @@ static int vz89x_probe(struct i2c_client *client,
|
|||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
of_id = of_match_device(vz89x_dt_ids, &client->dev);
|
||||
if (!of_id)
|
||||
chip_id = id->driver_data;
|
||||
else
|
||||
chip_id = (unsigned long)of_id->data;
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->chip = &vz89x_chips[chip_id];
|
||||
data->last_update = jiffies - HZ;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
|
@ -261,24 +397,19 @@ static int vz89x_probe(struct i2c_client *client,
|
|||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
indio_dev->channels = vz89x_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
|
||||
indio_dev->channels = data->chip->channels;
|
||||
indio_dev->num_channels = data->chip->num_channels;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id vz89x_id[] = {
|
||||
{ "vz89x", 0 },
|
||||
{ "vz89x", VZ89X },
|
||||
{ "vz89te", VZ89TE },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, vz89x_id);
|
||||
|
||||
static const struct of_device_id vz89x_dt_ids[] = {
|
||||
{ .compatible = "sgx,vz89x" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
|
||||
|
||||
static struct i2c_driver vz89x_driver = {
|
||||
.driver = {
|
||||
.name = "vz89x",
|
||||
|
|
|
@ -199,8 +199,7 @@ error_ret:
|
|||
}
|
||||
EXPORT_SYMBOL(hid_sensor_setup_trigger);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int hid_sensor_suspend(struct device *dev)
|
||||
static int __maybe_unused hid_sensor_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
@ -209,7 +208,7 @@ static int hid_sensor_suspend(struct device *dev)
|
|||
return _hid_sensor_power_state(attrb, false);
|
||||
}
|
||||
|
||||
static int hid_sensor_resume(struct device *dev)
|
||||
static int __maybe_unused hid_sensor_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
@ -218,7 +217,7 @@ static int hid_sensor_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hid_sensor_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
@ -226,8 +225,6 @@ static int hid_sensor_runtime_resume(struct device *dev)
|
|||
return _hid_sensor_power_state(attrb, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const struct dev_pm_ops hid_sensor_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
|
||||
SET_RUNTIME_PM_OPS(hid_sensor_suspend,
|
||||
|
|
|
@ -63,7 +63,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
|
|||
* the hardware trigger) and the hw_timestamp may get updated.
|
||||
* By storing it in a local variable first, we are safe.
|
||||
*/
|
||||
if (sdata->hw_irq_trigger)
|
||||
if (iio_trigger_using_own(indio_dev))
|
||||
timestamp = sdata->hw_timestamp;
|
||||
else
|
||||
timestamp = iio_get_time_ns(indio_dev);
|
||||
|
|
|
@ -234,39 +234,35 @@ int st_sensors_power_enable(struct iio_dev *indio_dev)
|
|||
int err;
|
||||
|
||||
/* Regulators not mandatory, but if requested we should enable them. */
|
||||
pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
|
||||
if (!IS_ERR(pdata->vdd)) {
|
||||
err = regulator_enable(pdata->vdd);
|
||||
if (err != 0) {
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd supply\n");
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
err = PTR_ERR(pdata->vdd);
|
||||
if (err != -ENODEV)
|
||||
return err;
|
||||
pdata->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
|
||||
if (IS_ERR(pdata->vdd)) {
|
||||
dev_err(&indio_dev->dev, "unable to get Vdd supply\n");
|
||||
return PTR_ERR(pdata->vdd);
|
||||
}
|
||||
err = regulator_enable(pdata->vdd);
|
||||
if (err != 0) {
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd supply\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
|
||||
if (!IS_ERR(pdata->vdd_io)) {
|
||||
err = regulator_enable(pdata->vdd_io);
|
||||
if (err != 0) {
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd_IO supply\n");
|
||||
goto st_sensors_disable_vdd;
|
||||
}
|
||||
} else {
|
||||
pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio");
|
||||
if (IS_ERR(pdata->vdd_io)) {
|
||||
dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n");
|
||||
err = PTR_ERR(pdata->vdd_io);
|
||||
if (err != -ENODEV)
|
||||
goto st_sensors_disable_vdd;
|
||||
goto st_sensors_disable_vdd;
|
||||
}
|
||||
err = regulator_enable(pdata->vdd_io);
|
||||
if (err != 0) {
|
||||
dev_warn(&indio_dev->dev,
|
||||
"Failed to enable specified Vdd_IO supply\n");
|
||||
goto st_sensors_disable_vdd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
st_sensors_disable_vdd:
|
||||
if (!IS_ERR_OR_NULL(pdata->vdd))
|
||||
regulator_disable(pdata->vdd);
|
||||
regulator_disable(pdata->vdd);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_enable);
|
||||
|
@ -275,11 +271,8 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct st_sensor_data *pdata = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(pdata->vdd))
|
||||
regulator_disable(pdata->vdd);
|
||||
|
||||
if (!IS_ERR_OR_NULL(pdata->vdd_io))
|
||||
regulator_disable(pdata->vdd_io);
|
||||
regulator_disable(pdata->vdd);
|
||||
regulator_disable(pdata->vdd_io);
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_power_disable);
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
|
|||
* @irq: irq number
|
||||
* @p: private handler data
|
||||
*/
|
||||
irqreturn_t st_sensors_irq_handler(int irq, void *p)
|
||||
static irqreturn_t st_sensors_irq_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_trigger *trig = p;
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
|
@ -82,7 +82,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p)
|
|||
* @irq: irq number
|
||||
* @p: private handler data
|
||||
*/
|
||||
irqreturn_t st_sensors_irq_thread(int irq, void *p)
|
||||
static irqreturn_t st_sensors_irq_thread(int irq, void *p)
|
||||
{
|
||||
struct iio_trigger *trig = p;
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
|
|
|
@ -190,6 +190,16 @@ config CIO_DAC
|
|||
base port addresses for the devices may be configured via the base
|
||||
array module parameter.
|
||||
|
||||
config AD8801
|
||||
tristate "Analog Devices AD8801/AD8803 DAC driver"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
Say yes here to build support for Analog Devices AD8801, AD8803 Digital to
|
||||
Analog Converters (DAC).
|
||||
|
||||
To compile this driver as a module choose M here: the module will be called
|
||||
ad8801.
|
||||
|
||||
config LPC18XX_DAC
|
||||
tristate "NXP LPC18xx DAC driver"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
|
@ -254,16 +264,6 @@ config MCP4922
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called mcp4922.
|
||||
|
||||
config STX104
|
||||
tristate "Apex Embedded Systems STX104 DAC driver"
|
||||
depends on X86 && ISA_BUS_API
|
||||
select GPIOLIB
|
||||
help
|
||||
Say yes here to build support for the 2-channel DAC and GPIO on the
|
||||
Apex Embedded Systems STX104 integrated analog PC/104 card. The base
|
||||
port addresses for the devices may be configured via the base array
|
||||
module parameter.
|
||||
|
||||
config VF610_DAC
|
||||
tristate "Vybrid vf610 DAC driver"
|
||||
depends on OF
|
||||
|
|
|
@ -20,6 +20,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
|
|||
obj-$(CONFIG_AD5791) += ad5791.o
|
||||
obj-$(CONFIG_AD5686) += ad5686.o
|
||||
obj-$(CONFIG_AD7303) += ad7303.o
|
||||
obj-$(CONFIG_AD8801) += ad8801.o
|
||||
obj-$(CONFIG_CIO_DAC) += cio-dac.o
|
||||
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
|
||||
obj-$(CONFIG_M62332) += m62332.o
|
||||
|
@ -27,5 +28,4 @@ obj-$(CONFIG_MAX517) += max517.o
|
|||
obj-$(CONFIG_MAX5821) += max5821.o
|
||||
obj-$(CONFIG_MCP4725) += mcp4725.o
|
||||
obj-$(CONFIG_MCP4922) += mcp4922.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
|
||||
|
|
|
@ -655,7 +655,7 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
|
|||
|
||||
devnr = 0;
|
||||
for_each_child_of_node(np, pp) {
|
||||
if (devnr > AD5755_NUM_CHANNELS) {
|
||||
if (devnr >= AD5755_NUM_CHANNELS) {
|
||||
dev_err(dev,
|
||||
"There is to many channels defined in DT\n");
|
||||
goto error_out;
|
||||
|
|
239
drivers/iio/dac/ad8801.c
Normal file
239
drivers/iio/dac/ad8801.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* IIO DAC driver for Analog Devices AD8801 DAC
|
||||
*
|
||||
* Copyright (C) 2016 Gwenhael Goavec-Merou
|
||||
* 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.
|
||||
*
|
||||
* 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/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define AD8801_CFG_ADDR_OFFSET 8
|
||||
|
||||
enum ad8801_device_ids {
|
||||
ID_AD8801,
|
||||
ID_AD8803,
|
||||
};
|
||||
|
||||
struct ad8801_state {
|
||||
struct spi_device *spi;
|
||||
unsigned char dac_cache[8]; /* Value write on each channel */
|
||||
unsigned int vrefh_mv;
|
||||
unsigned int vrefl_mv;
|
||||
struct regulator *vrefh_reg;
|
||||
struct regulator *vrefl_reg;
|
||||
|
||||
__be16 data ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static int ad8801_spi_write(struct ad8801_state *state,
|
||||
u8 channel, unsigned char value)
|
||||
{
|
||||
state->data = cpu_to_be16((channel << AD8801_CFG_ADDR_OFFSET) | value);
|
||||
return spi_write(state->spi, &state->data, sizeof(state->data));
|
||||
}
|
||||
|
||||
static int ad8801_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val, int val2, long mask)
|
||||
{
|
||||
struct ad8801_state *state = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val >= 256 || val < 0)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ad8801_spi_write(state, chan->channel, val);
|
||||
if (ret == 0)
|
||||
state->dac_cache[chan->channel] = val;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad8801_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2, long info)
|
||||
{
|
||||
struct ad8801_state *state = iio_priv(indio_dev);
|
||||
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = state->dac_cache[chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = state->vrefh_mv - state->vrefl_mv;
|
||||
*val2 = 8;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = state->vrefl_mv;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info ad8801_info = {
|
||||
.read_raw = ad8801_read_raw,
|
||||
.write_raw = ad8801_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
#define AD8801_CHANNEL(chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad8801_channels[] = {
|
||||
AD8801_CHANNEL(0),
|
||||
AD8801_CHANNEL(1),
|
||||
AD8801_CHANNEL(2),
|
||||
AD8801_CHANNEL(3),
|
||||
AD8801_CHANNEL(4),
|
||||
AD8801_CHANNEL(5),
|
||||
AD8801_CHANNEL(6),
|
||||
AD8801_CHANNEL(7),
|
||||
};
|
||||
|
||||
static int ad8801_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ad8801_state *state;
|
||||
const struct spi_device_id *id;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
|
||||
if (indio_dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
state = iio_priv(indio_dev);
|
||||
state->spi = spi;
|
||||
id = spi_get_device_id(spi);
|
||||
|
||||
state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh");
|
||||
if (IS_ERR(state->vrefh_reg)) {
|
||||
dev_err(&spi->dev, "Vrefh regulator not specified\n");
|
||||
return PTR_ERR(state->vrefh_reg);
|
||||
}
|
||||
|
||||
ret = regulator_enable(state->vrefh_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(state->vrefh_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
state->vrefh_mv = ret / 1000;
|
||||
|
||||
if (id->driver_data == ID_AD8803) {
|
||||
state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl");
|
||||
if (IS_ERR(state->vrefl_reg)) {
|
||||
dev_err(&spi->dev, "Vrefl regulator not specified\n");
|
||||
ret = PTR_ERR(state->vrefl_reg);
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
|
||||
ret = regulator_enable(state->vrefl_reg);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefh_reg;
|
||||
}
|
||||
|
||||
ret = regulator_get_voltage(state->vrefl_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefl_reg;
|
||||
}
|
||||
state->vrefl_mv = ret / 1000;
|
||||
} else {
|
||||
state->vrefl_mv = 0;
|
||||
state->vrefl_reg = NULL;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &ad8801_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ad8801_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ad8801_channels);
|
||||
indio_dev->name = id->name;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Failed to register iio device: %d\n",
|
||||
ret);
|
||||
goto error_disable_vrefl_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_disable_vrefl_reg:
|
||||
if (state->vrefl_reg)
|
||||
regulator_disable(state->vrefl_reg);
|
||||
error_disable_vrefh_reg:
|
||||
regulator_disable(state->vrefh_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad8801_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct ad8801_state *state = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
if (state->vrefl_reg)
|
||||
regulator_disable(state->vrefl_reg);
|
||||
regulator_disable(state->vrefh_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct spi_device_id ad8801_ids[] = {
|
||||
{"ad8801", ID_AD8801},
|
||||
{"ad8803", ID_AD8803},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ad8801_ids);
|
||||
|
||||
static struct spi_driver ad8801_driver = {
|
||||
.driver = {
|
||||
.name = "ad8801",
|
||||
},
|
||||
.probe = ad8801_probe,
|
||||
.remove = ad8801_remove,
|
||||
.id_table = ad8801_ids,
|
||||
};
|
||||
module_spi_driver(ad8801_driver);
|
||||
|
||||
MODULE_AUTHOR("Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices AD8801/AD8803 DAC");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1308,7 +1308,7 @@ static void devm_iio_device_release(struct device *dev, void *res)
|
|||
iio_device_free(*(struct iio_dev **)res);
|
||||
}
|
||||
|
||||
static int devm_iio_device_match(struct device *dev, void *res, void *data)
|
||||
int devm_iio_device_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
struct iio_dev **r = res;
|
||||
if (!r || !*r) {
|
||||
|
@ -1317,6 +1317,7 @@ static int devm_iio_device_match(struct device *dev, void *res, void *data)
|
|||
}
|
||||
return *r == data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_device_match);
|
||||
|
||||
/**
|
||||
* devm_iio_device_alloc - Resource-managed iio_device_alloc()
|
||||
|
|
|
@ -57,6 +57,11 @@ bool iio_event_enabled(const struct iio_event_interface *ev_int)
|
|||
*
|
||||
* Note: The caller must make sure that this function is not running
|
||||
* concurrently for the same indio_dev more than once.
|
||||
*
|
||||
* This function may be safely used as soon as a valid reference to iio_dev has
|
||||
* been obtained via iio_device_alloc(), but any events that are submitted
|
||||
* before iio_device_register() has successfully completed will be silently
|
||||
* discarded.
|
||||
**/
|
||||
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
||||
{
|
||||
|
@ -64,6 +69,9 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
|||
struct iio_event_data ev;
|
||||
int copied;
|
||||
|
||||
if (!ev_int)
|
||||
return 0;
|
||||
|
||||
/* Does anyone care? */
|
||||
if (iio_event_enabled(ev_int)) {
|
||||
|
||||
|
|
|
@ -119,6 +119,22 @@ void iio_trigger_unregister(struct iio_trigger *trig_info)
|
|||
}
|
||||
EXPORT_SYMBOL(iio_trigger_unregister);
|
||||
|
||||
int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig)
|
||||
{
|
||||
if (!indio_dev || !trig)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
WARN_ON(indio_dev->trig_readonly);
|
||||
|
||||
indio_dev->trig = iio_trigger_get(trig);
|
||||
indio_dev->trig_readonly = true;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_trigger_set_immutable);
|
||||
|
||||
/* Search for trigger by name, assuming iio_trigger_list_lock held */
|
||||
static struct iio_trigger *__iio_trigger_find_by_name(const char *name)
|
||||
{
|
||||
|
@ -255,6 +271,14 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,
|
|||
goto out_free_irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we just registered to our own trigger: we determine that
|
||||
* this is the case if the IIO device and the trigger device share the
|
||||
* same parent device.
|
||||
*/
|
||||
if (pf->indio_dev->dev.parent == trig->dev.parent)
|
||||
trig->attached_own_device = true;
|
||||
|
||||
return ret;
|
||||
|
||||
out_free_irq:
|
||||
|
@ -279,6 +303,8 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
|
|||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
if (pf->indio_dev->dev.parent == trig->dev.parent)
|
||||
trig->attached_own_device = false;
|
||||
iio_trigger_put_irq(trig, pf->irq);
|
||||
free_irq(pf->irq, pf);
|
||||
module_put(pf->indio_dev->info->driver_module);
|
||||
|
@ -384,6 +410,10 @@ static ssize_t iio_trigger_write_current(struct device *dev,
|
|||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (indio_dev->trig_readonly) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EPERM;
|
||||
}
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
trig = iio_trigger_find_by_name(buf, len);
|
||||
|
@ -622,6 +652,71 @@ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_trigger_free);
|
||||
|
||||
static void devm_iio_trigger_unreg(struct device *dev, void *res)
|
||||
{
|
||||
iio_trigger_unregister(*(struct iio_trigger **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_iio_trigger_register - Resource-managed iio_trigger_register()
|
||||
* @dev: device this trigger was allocated for
|
||||
* @trig_info: trigger to register
|
||||
*
|
||||
* Managed iio_trigger_register(). The IIO trigger registered with this
|
||||
* function is automatically unregistered on driver detach. This function
|
||||
* calls iio_trigger_register() internally. Refer to that function for more
|
||||
* information.
|
||||
*
|
||||
* If an iio_trigger registered with this function needs to be unregistered
|
||||
* separately, devm_iio_trigger_unregister() must be used.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, negative error number on failure.
|
||||
*/
|
||||
int devm_iio_trigger_register(struct device *dev, struct iio_trigger *trig_info)
|
||||
{
|
||||
struct iio_trigger **ptr;
|
||||
int ret;
|
||||
|
||||
ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
*ptr = trig_info;
|
||||
ret = iio_trigger_register(trig_info);
|
||||
if (!ret)
|
||||
devres_add(dev, ptr);
|
||||
else
|
||||
devres_free(ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_trigger_register);
|
||||
|
||||
/**
|
||||
* devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister()
|
||||
* @dev: device this iio_trigger belongs to
|
||||
* @trig_info: the trigger associated with the device
|
||||
*
|
||||
* Unregister trigger registered with devm_iio_trigger_register().
|
||||
*/
|
||||
void devm_iio_trigger_unregister(struct device *dev,
|
||||
struct iio_trigger *trig_info)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match,
|
||||
trig_info);
|
||||
WARN_ON(rc);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister);
|
||||
|
||||
bool iio_trigger_using_own(struct iio_dev *indio_dev)
|
||||
{
|
||||
return indio_dev->trig->attached_own_device;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_trigger_using_own);
|
||||
|
||||
void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
|
||||
{
|
||||
indio_dev->groups[indio_dev->groupcounter++] =
|
||||
|
|
|
@ -783,8 +783,7 @@ static int __exit ak8974_remove(struct i2c_client *i2c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ak8974_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused ak8974_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct ak8974 *ak8974 =
|
||||
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
@ -795,7 +794,7 @@ static int ak8974_runtime_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ak8974_runtime_resume(struct device *dev)
|
||||
static int __maybe_unused ak8974_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct ak8974 *ak8974 =
|
||||
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
|
||||
|
@ -822,7 +821,6 @@ out_regulator_disable:
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct dev_pm_ops ak8974_dev_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
|
@ -847,7 +845,6 @@ MODULE_DEVICE_TABLE(of, ak8974_of_match);
|
|||
static struct i2c_driver ak8974_driver = {
|
||||
.driver = {
|
||||
.name = "ak8974",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ak8974_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(ak8974_of_match),
|
||||
},
|
||||
|
|
|
@ -416,8 +416,7 @@ static int ms5611_init(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
|
||||
err_regulator_disable:
|
||||
if (!IS_ERR_OR_NULL(st->vdd))
|
||||
regulator_disable(st->vdd);
|
||||
regulator_disable(st->vdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -425,8 +424,7 @@ static void ms5611_fini(const struct iio_dev *indio_dev)
|
|||
{
|
||||
const struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(st->vdd))
|
||||
regulator_disable(st->vdd);
|
||||
regulator_disable(st->vdd);
|
||||
}
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
||||
|
|
|
@ -1025,6 +1025,12 @@ static const struct acpi_device_id sx9500_acpi_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
|
||||
|
||||
static const struct of_device_id sx9500_of_match[] = {
|
||||
{ .compatible = "semtech,sx9500", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sx9500_of_match);
|
||||
|
||||
static const struct i2c_device_id sx9500_id[] = {
|
||||
{"sx9500", 0},
|
||||
{ },
|
||||
|
@ -1035,6 +1041,7 @@ static struct i2c_driver sx9500_driver = {
|
|||
.driver = {
|
||||
.name = SX9500_DRIVER_NAME,
|
||||
.acpi_match_table = ACPI_PTR(sx9500_acpi_match),
|
||||
.of_match_table = of_match_ptr(sx9500_of_match),
|
||||
.pm = &sx9500_pm_ops,
|
||||
},
|
||||
.probe = sx9500_probe,
|
||||
|
|
|
@ -32,7 +32,7 @@ enum {
|
|||
MAX31855,
|
||||
};
|
||||
|
||||
const struct iio_chan_spec max6675_channels[] = {
|
||||
static const struct iio_chan_spec max6675_channels[] = {
|
||||
{ /* thermocouple temperature */
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate =
|
||||
|
@ -49,7 +49,7 @@ const struct iio_chan_spec max6675_channels[] = {
|
|||
IIO_CHAN_SOFT_TIMESTAMP(1),
|
||||
};
|
||||
|
||||
const struct iio_chan_spec max31855_channels[] = {
|
||||
static const struct iio_chan_spec max31855_channels[] = {
|
||||
{ /* thermocouple temperature */
|
||||
.type = IIO_TEMP,
|
||||
.address = 2,
|
||||
|
@ -95,7 +95,7 @@ struct maxim_thermocouple_chip {
|
|||
u32 status_bit;
|
||||
};
|
||||
|
||||
const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = {
|
||||
static const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = {
|
||||
[MAX6675] = {
|
||||
.channels = max6675_channels,
|
||||
.num_channels = ARRAY_SIZE(max6675_channels),
|
||||
|
|
|
@ -412,7 +412,7 @@ static const struct iio_event_spec sca3000_event = {
|
|||
}, \
|
||||
.event_spec = &sca3000_event, \
|
||||
.num_event_specs = 1, \
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec sca3000_channels[] = {
|
||||
SCA3000_CHAN(0, IIO_MOD_X),
|
||||
|
|
|
@ -483,6 +483,7 @@ struct iio_buffer_setup_ops {
|
|||
* @scan_timestamp: [INTERN] set if any buffers have requested timestamp
|
||||
* @scan_index_timestamp:[INTERN] cache of the index to the timestamp
|
||||
* @trig: [INTERN] current device trigger (buffer modes)
|
||||
* @trig_readonly [INTERN] mark the current trigger immutable
|
||||
* @pollfunc: [DRIVER] function run on trigger being received
|
||||
* @pollfunc_event: [DRIVER] function run on events trigger being received
|
||||
* @channels: [DRIVER] channel specification structure table
|
||||
|
@ -523,6 +524,7 @@ struct iio_dev {
|
|||
bool scan_timestamp;
|
||||
unsigned scan_index_timestamp;
|
||||
struct iio_trigger *trig;
|
||||
bool trig_readonly;
|
||||
struct iio_poll_func *pollfunc;
|
||||
struct iio_poll_func *pollfunc_event;
|
||||
|
||||
|
@ -642,6 +644,7 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv)
|
|||
}
|
||||
|
||||
void iio_device_free(struct iio_dev *indio_dev);
|
||||
int devm_iio_device_match(struct device *dev, void *res, void *data);
|
||||
struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv);
|
||||
void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev);
|
||||
struct iio_trigger *devm_iio_trigger_alloc(struct device *dev,
|
||||
|
|
|
@ -56,6 +56,9 @@ struct iio_trigger_ops {
|
|||
* @subirqs: [INTERN] information about the 'child' irqs.
|
||||
* @pool: [INTERN] bitmap of irqs currently in use.
|
||||
* @pool_lock: [INTERN] protection of the irq pool.
|
||||
* @attached_own_device:[INTERN] if we are using our own device as trigger,
|
||||
* i.e. if we registered a poll function to the same
|
||||
* device as the one providing the trigger.
|
||||
**/
|
||||
struct iio_trigger {
|
||||
const struct iio_trigger_ops *ops;
|
||||
|
@ -73,6 +76,7 @@ struct iio_trigger {
|
|||
struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER];
|
||||
unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)];
|
||||
struct mutex pool_lock;
|
||||
bool attached_own_device;
|
||||
};
|
||||
|
||||
|
||||
|
@ -125,12 +129,27 @@ static inline void *iio_trigger_get_drvdata(struct iio_trigger *trig)
|
|||
**/
|
||||
int iio_trigger_register(struct iio_trigger *trig_info);
|
||||
|
||||
int devm_iio_trigger_register(struct device *dev,
|
||||
struct iio_trigger *trig_info);
|
||||
|
||||
/**
|
||||
* iio_trigger_unregister() - unregister a trigger from the core
|
||||
* @trig_info: trigger to be unregistered
|
||||
**/
|
||||
void iio_trigger_unregister(struct iio_trigger *trig_info);
|
||||
|
||||
void devm_iio_trigger_unregister(struct device *dev,
|
||||
struct iio_trigger *trig_info);
|
||||
|
||||
/**
|
||||
* iio_trigger_set_immutable() - set an immutable trigger on destination
|
||||
*
|
||||
* @indio_dev - IIO device structure containing the device
|
||||
* @trig - trigger to assign to device
|
||||
*
|
||||
**/
|
||||
int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig);
|
||||
|
||||
/**
|
||||
* iio_trigger_poll() - called on a trigger occurring
|
||||
* @trig: trigger which occurred
|
||||
|
@ -145,6 +164,13 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
|
|||
__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...);
|
||||
void iio_trigger_free(struct iio_trigger *trig);
|
||||
|
||||
/**
|
||||
* iio_trigger_using_own() - tells us if we use our own HW trigger ourselves
|
||||
* @indio_dev: device to check
|
||||
*/
|
||||
bool iio_trigger_using_own(struct iio_dev *indio_dev);
|
||||
|
||||
|
||||
#else
|
||||
struct iio_trigger;
|
||||
struct iio_trigger_ops;
|
||||
|
|
|
@ -12,4 +12,12 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
|
|||
const struct iio_buffer_setup_ops *setup_ops);
|
||||
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev);
|
||||
|
||||
int devm_iio_triggered_buffer_setup(struct device *dev,
|
||||
struct iio_dev *indio_dev,
|
||||
irqreturn_t (*h)(int irq, void *p),
|
||||
irqreturn_t (*thread)(int irq, void *p),
|
||||
const struct iio_buffer_setup_ops *ops);
|
||||
void devm_iio_triggered_buffer_cleanup(struct device *dev,
|
||||
struct iio_dev *indio_dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -121,10 +121,6 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
|
|||
|
||||
ret = -ENOENT;
|
||||
while (ent = readdir(dp), ent)
|
||||
/*
|
||||
* Do we allow devices to override a generic name with
|
||||
* a specific one?
|
||||
*/
|
||||
if ((strcmp(builtname, ent->d_name) == 0) ||
|
||||
(strcmp(builtname_generic, ent->d_name) == 0)) {
|
||||
ret = asprintf(&filename,
|
||||
|
@ -178,6 +174,13 @@ int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used,
|
|||
sysfsfp = 0;
|
||||
free(filename);
|
||||
filename = 0;
|
||||
|
||||
/*
|
||||
* Avoid having a more generic entry overwriting
|
||||
* the settings.
|
||||
*/
|
||||
if (strcmp(builtname, ent->d_name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
error_close_sysfsfp:
|
||||
|
|
Loading…
Reference in a new issue