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
38 changed files with 1610 additions and 140 deletions
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");
|
||||
380
drivers/iio/adc/stx104.c
Normal file
380
drivers/iio/adc/stx104.c
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* 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
|
||||
* 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/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/types.h>
|
||||
#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_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
|
||||
|
||||
static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
|
||||
static unsigned int num_stx104;
|
||||
module_param_array(base, uint, &num_stx104, 0);
|
||||
MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
|
||||
|
||||
/**
|
||||
* struct stx104_iio - IIO device private data structure
|
||||
* @chan_out_states: channels' output states
|
||||
* @base: base port address of the IIO device
|
||||
*/
|
||||
struct stx104_iio {
|
||||
unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
|
||||
unsigned int base;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stx104_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @lock: synchronization lock to prevent I/O race conditions
|
||||
* @base: base port address of the GPIO device
|
||||
* @out_state: output bits state
|
||||
*/
|
||||
struct stx104_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
unsigned int base;
|
||||
unsigned int out_state;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stx104_dev - STX104 device private data structure
|
||||
* @indio_dev: IIO device
|
||||
* @chip: instance of the gpio_chip
|
||||
*/
|
||||
struct stx104_dev {
|
||||
struct iio_dev *indio_dev;
|
||||
struct gpio_chip *chip;
|
||||
};
|
||||
|
||||
static int stx104_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
|
||||
{
|
||||
struct stx104_iio *const priv = iio_priv(indio_dev);
|
||||
unsigned int adc_config;
|
||||
int adbu;
|
||||
int gain;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
/* get gain configuration */
|
||||
adc_config = inb(priv->base + 11);
|
||||
gain = adc_config & 0x3;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info stx104_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = stx104_read_raw,
|
||||
.write_raw = stx104_write_raw
|
||||
};
|
||||
|
||||
/* 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,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* GPIO 0-3 are input only, while the rest are output only */
|
||||
if (offset < 4)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (offset >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
if (offset < 4)
|
||||
return -EINVAL;
|
||||
|
||||
chip->set(chip, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
|
||||
if (offset >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
return !!(inb(stx104gpio->base) & BIT(offset));
|
||||
}
|
||||
|
||||
static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
const unsigned int mask = BIT(offset) >> 4;
|
||||
unsigned long flags;
|
||||
|
||||
if (offset < 4)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&stx104gpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
stx104gpio->out_state |= mask;
|
||||
else
|
||||
stx104gpio->out_state &= ~mask;
|
||||
|
||||
outb(stx104gpio->out_state, stx104gpio->base);
|
||||
|
||||
spin_unlock_irqrestore(&stx104gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int stx104_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct stx104_iio *priv;
|
||||
struct stx104_gpio *stx104gpio;
|
||||
struct stx104_dev *stx104dev;
|
||||
int err;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
|
||||
if (!stx104gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
stx104dev = devm_kzalloc(dev, sizeof(*stx104dev), GFP_KERNEL);
|
||||
if (!stx104dev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!devm_request_region(dev, base[id], STX104_EXTENT,
|
||||
dev_name(dev))) {
|
||||
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||
base[id], base[id] + STX104_EXTENT);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
indio_dev->info = &stx104_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
/* 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);
|
||||
|
||||
stx104gpio->chip.label = dev_name(dev);
|
||||
stx104gpio->chip.parent = dev;
|
||||
stx104gpio->chip.owner = THIS_MODULE;
|
||||
stx104gpio->chip.base = -1;
|
||||
stx104gpio->chip.ngpio = 8;
|
||||
stx104gpio->chip.get_direction = stx104_gpio_get_direction;
|
||||
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
|
||||
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
|
||||
stx104gpio->chip.get = stx104_gpio_get;
|
||||
stx104gpio->chip.set = stx104_gpio_set;
|
||||
stx104gpio->base = base[id] + 3;
|
||||
stx104gpio->out_state = 0x0;
|
||||
|
||||
spin_lock_init(&stx104gpio->lock);
|
||||
|
||||
stx104dev->indio_dev = indio_dev;
|
||||
stx104dev->chip = &stx104gpio->chip;
|
||||
dev_set_drvdata(dev, stx104dev);
|
||||
|
||||
err = gpiochip_add_data(&stx104gpio->chip, stx104gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "IIO device registering failed (%d)\n", err);
|
||||
gpiochip_remove(&stx104gpio->chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_remove(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct stx104_dev *const stx104dev = dev_get_drvdata(dev);
|
||||
|
||||
iio_device_unregister(stx104dev->indio_dev);
|
||||
gpiochip_remove(stx104dev->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct isa_driver stx104_driver = {
|
||||
.probe = stx104_probe,
|
||||
.driver = {
|
||||
.name = "stx104"
|
||||
},
|
||||
.remove = stx104_remove
|
||||
};
|
||||
|
||||
module_isa_driver(stx104_driver, num_stx104);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
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);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue