diff options
73 files changed, 3170 insertions, 2139 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6a5f34b4d5b9..731146c3b138 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -190,6 +190,13 @@ Description: but should match other such assignments on device). Units after application of scale and offset are m/s^2. +What: /sys/bus/iio/devices/iio:deviceX/in_angl_raw +KernelVersion: 4.17 +Contact: linux-iio@vger.kernel.org +Description: + Angle of rotation. Units after application of scale and offset + are radians. + What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw @@ -297,6 +304,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressure_offset What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_offset What: /sys/bus/iio/devices/iio:deviceX/in_magn_offset What: /sys/bus/iio/devices/iio:deviceX/in_rot_offset +What: /sys/bus/iio/devices/iio:deviceX/in_angl_offset KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -350,6 +358,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_scale What: /sys/bus/iio/devices/iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_scale What: /sys/bus/iio/devices/iio:deviceX/in_illuminance_scale What: /sys/bus/iio/devices/iio:deviceX/in_countY_scale +What: /sys/bus/iio/devices/iio:deviceX/in_angl_scale KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt index 1e6ee3deb4fa..d1acd5ea2737 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -7,6 +7,7 @@ Required properties: - "amlogic,meson-gxbb-saradc" for GXBB - "amlogic,meson-gxl-saradc" for GXL - "amlogic,meson-gxm-saradc" for GXM + - "amlogic,meson-axg-saradc" for AXG along with the generic "amlogic,meson-saradc" - reg: the physical base address and length of the registers - interrupts: the interrupt indicating end of sampling diff --git a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt index 7d64753df949..56373d643f76 100644 --- a/Documentation/devicetree/bindings/iio/adc/mcp320x.txt +++ b/Documentation/devicetree/bindings/iio/adc/mcp320x.txt @@ -49,7 +49,7 @@ Required properties: Examples: spi_controller { mcp3x0x@0 { - compatible = "mcp3002"; + compatible = "microchip,mcp3002"; reg = <0>; spi-max-frequency = <1000000>; vref-supply = <&vref_reg>; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index e8bb8243e92c..f1ead43a1a95 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -24,8 +24,11 @@ Required properties: - compatible: Should be one of: "st,stm32f4-adc-core" "st,stm32h7-adc-core" + "st,stm32mp1-adc-core" - reg: Offset and length of the ADC block register set. -- interrupts: Must contain the interrupt for ADC block. +- interrupts: One or more interrupts for ADC block. Some parts like stm32f4 + and stm32h7 share a common ADC interrupt line. stm32mp1 has two separate + interrupt lines, one for each ADC within ADC block. - clocks: Core can use up to two clocks, depending on part used: - "adc" clock: for the analog circuitry, common to all ADCs. It's required on stm32f4. @@ -53,6 +56,7 @@ Required properties: - compatible: Should be one of: "st,stm32f4-adc" "st,stm32h7-adc" + "st,stm32mp1-adc" - reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200). - clocks: Input clock private to this ADC instance. It's required only on stm32f4, that has per instance clock input for registers access. diff --git a/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt b/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt new file mode 100644 index 000000000000..0ddbaebba8ce --- /dev/null +++ b/Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt @@ -0,0 +1,26 @@ +Current Sense Amplifier +======================= + +When an io-channel measures the output voltage from a current sense +amplifier, the interesting mesaurement is almost always the current +through the sense resistor, not the voltage output. This binding +describes such a current sense circuit. + +Required properties: +- compatible : "current-sense-amplifier" +- io-channels : Channel node of a voltage io-channel. +- sense-resistor-micro-ohms : The sense resistance in microohms. + +Optional properties: +- sense-gain-mult: Amplifier gain multiplier. The default is <1>. +- sense-gain-div: Amplifier gain divider. The default is <1>. + +Example: + +sysi { + compatible = "current-sense-amplifier"; + io-channels = <&tiadc 0>; + + sense-resistor-micro-ohms = <20000>; + sense-gain-mul = <50>; +}; diff --git a/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt b/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt new file mode 100644 index 000000000000..8e7b3e408a52 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt @@ -0,0 +1,41 @@ +Current Sense Shunt +=================== + +When an io-channel measures the voltage over a current sense shunt, +the interesting mesaurement is almost always the current through the +shunt, not the voltage over it. This binding describes such a current +sense circuit. + +Required properties: +- compatible : "current-sense-shunt" +- io-channels : Channel node of a voltage io-channel. +- shunt-resistor-micro-ohms : The shunt resistance in microohms. + +Example: +The system current is measured by measuring the voltage over a +3.3 ohms shunt resistor. + +sysi { + compatible = "current-sense-shunt"; + io-channels = <&tiadc 0>; + + /* Divide the voltage by 3300000/1000000 (or 3.3) for the current. */ + shunt-resistor-micro-ohms = <3300000>; +}; + +&i2c { + tiadc: adc@48 { + compatible = "ti,ads1015"; + reg = <0x48>; + #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { /* IN0,IN1 differential */ + reg = <0>; + ti,gain = <1>; + ti,datarate = <4>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt b/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt new file mode 100644 index 000000000000..b452a8406107 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/afe/voltage-divider.txt @@ -0,0 +1,53 @@ +Voltage divider +=============== + +When an io-channel measures the midpoint of a voltage divider, the +interesting voltage is often the voltage over the full resistance +of the divider. This binding describes the voltage divider in such +a curcuit. + + Vin ----. + | + .-----. + | R | + '-----' + | + +---- Vout + | + .-----. + | Rout| + '-----' + | + GND + +Required properties: +- compatible : "voltage-divider" +- io-channels : Channel node of a voltage io-channel measuring Vout. +- output-ohms : Resistance Rout over which the output voltage is measured. + See full-ohms. +- full-ohms : Resistance R + Rout for the full divider. The io-channel + is scaled by the Rout / (R + Rout) quotient. + +Example: +The system voltage is circa 12V, but divided down with a 22/222 +voltage divider (R = 200 Ohms, Rout = 22 Ohms) and fed to an ADC. + +sysv { + compatible = "voltage-divider"; + io-channels = <&maxadc 1>; + + /* Scale the system voltage by 22/222 to fit the ADC range. */ + output-ohms = <22>; + full-ohms = <222>; /* 200 + 22 */ +}; + +&spi { + maxadc: adc@0 { + compatible = "maxim,max1027"; + reg = <0>; + #io-channel-cells = <1>; + interrupt-parent = <&gpio5>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt new file mode 100644 index 000000000000..03af6b9a4d07 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/ti,dac5571.txt @@ -0,0 +1,24 @@ +* Texas Instruments DAC5571 Family + +Required properties: + - compatible: Should contain + "ti,dac5571" + "ti,dac6571" + "ti,dac7571" + "ti,dac5574" + "ti,dac6574" + "ti,dac7574" + "ti,dac5573" + "ti,dac6573" + "ti,dac7573" + - reg: Should contain the DAC I2C address + +Optional properties: + - vref-supply: The regulator supply for DAC reference voltage + +Example: +dac@0 { + compatible = "ti,dac5571"; + reg = <0x4C>; + vref-supply = <&vdd_supply>; +}; diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt index 2b4514592f83..5f4777e8cc9e 100644 --- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt @@ -8,10 +8,16 @@ Required properties: "invensense,mpu6500" "invensense,mpu9150" "invensense,mpu9250" + "invensense,mpu9255" "invensense,icm20608" - reg : the I2C address of the sensor - interrupt-parent : should be the phandle for the interrupt controller - - interrupts : interrupt mapping for GPIO IRQ + - interrupts: interrupt mapping for IRQ. It should be configured with flags + IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt client node + bindings. Optional properties: - mount-matrix: an optional 3x3 mounting rotation matrix @@ -24,7 +30,7 @@ Example: compatible = "invensense,mpu6050"; reg = <0x68>; interrupt-parent = <&gpio1>; - interrupts = <18 1>; + interrupts = <18 IRQ_TYPE_EDGE_RISING>; mount-matrix = "-0.984807753012208", /* x0 */ "0", /* y0 */ "-0.173648177666930", /* z0 */ @@ -41,7 +47,7 @@ Example: compatible = "invensense,mpu9250"; reg = <0x68>; interrupt-parent = <&gpio3>; - interrupts = <21 1>; + interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; i2c-gate { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt index 1ff1af799c76..ef8a8566c63f 100644 --- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt @@ -6,6 +6,7 @@ Required properties: "st,lsm6ds3h" "st,lsm6dsl" "st,lsm6dsm" + "st,ism330dlc" - reg: i2c address of the sensor / spi cs line Optional properties: diff --git a/MAINTAINERS b/MAINTAINERS index afc87293d786..4b65225d443a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -794,6 +794,14 @@ M: Michael Hanselmann <linux-kernel@hansmi.ch> S: Supported F: drivers/macintosh/ams/ +ANALOG DEVICES INC AD5686 DRIVER +M: Stefan Popa <stefan.popa@analog.com> +L: linux-pm@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/dac/ad5686* +F: drivers/iio/dac/ad5696* + ANALOG DEVICES INC AD9389B DRIVER M: Hans Verkuil <hans.verkuil@cisco.com> L: linux-media@vger.kernel.org @@ -6914,6 +6922,15 @@ F: drivers/staging/iio/ F: include/linux/iio/ F: tools/iio/ +IIO UNIT CONVERTER +M: Peter Rosin <peda@axentia.se> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/afe/current-sense-amplifier.txt +F: Documentation/devicetree/bindings/iio/afe/current-sense-shunt.txt +F: Documentation/devicetree/bindings/iio/afe/voltage-divider.txt +F: drivers/iio/afe/iio-rescale.c + IKANOS/ADI EAGLE ADSL USB DRIVER M: Matthieu Castet <castet.matthieu@free.fr> M: Stanislaw Gruszka <stf_xl@wp.pl> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index b3c8c6ef0dff..d69e85a8bdc3 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -70,6 +70,7 @@ config IIO_TRIGGERED_EVENT source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" +source "drivers/iio/afe/Kconfig" source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/chemical/Kconfig" source "drivers/iio/common/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index b16b2e9ddc40..d8cba9c229c0 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_IIO_TRIGGERED_EVENT) += industrialio-triggered-event.o obj-y += accel/ obj-y += adc/ +obj-y += afe/ obj-y += amplifiers/ obj-y += buffer/ obj-y += chemical/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index c6d9517d7611..62ae7e5abcfa 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -5,6 +5,30 @@ menu "Accelerometers" +config ADIS16201 + tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say Y here to build support for Analog Devices adis16201 dual-axis + digital inclinometer and accelerometer. + + To compile this driver as a module, say M here: the module will + be called adis16201. + +config ADIS16209 + tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" + depends on SPI + select IIO_ADIS_LIB + select IIO_ADIS_LIB_BUFFER if IIO_BUFFER + help + Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer + and accelerometer. + + To compile this driver as a module, say M here: the module will be + called adis16209. + config ADXL345 tristate diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 368aedb6377a..636d4d1b2990 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,6 +4,8 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_ADIS16201) += adis16201.o +obj-$(CONFIG_ADIS16209) += adis16209.o obj-$(CONFIG_ADXL345) += adxl345_core.o obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c new file mode 100644 index 000000000000..4c1d482ea73a --- /dev/null +++ b/drivers/iio/accel/adis16201.c @@ -0,0 +1,321 @@ +/* + * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> + +#include <linux/iio/iio.h> +#include <linux/iio/imu/adis.h> + +#define ADIS16201_STARTUP_DELAY_MS 220 +#define ADIS16201_FLASH_CNT 0x00 + +/* Data Output Register Information */ +#define ADIS16201_SUPPLY_OUT_REG 0x02 +#define ADIS16201_XACCL_OUT_REG 0x04 +#define ADIS16201_YACCL_OUT_REG 0x06 +#define ADIS16201_AUX_ADC_REG 0x08 +#define ADIS16201_TEMP_OUT_REG 0x0A +#define ADIS16201_XINCL_OUT_REG 0x0C +#define ADIS16201_YINCL_OUT_REG 0x0E + +/* Calibration Register Definition */ +#define ADIS16201_XACCL_OFFS_REG 0x10 +#define ADIS16201_YACCL_OFFS_REG 0x12 +#define ADIS16201_XACCL_SCALE_REG 0x14 +#define ADIS16201_YACCL_SCALE_REG 0x16 +#define ADIS16201_XINCL_OFFS_REG 0x18 +#define ADIS16201_YINCL_OFFS_REG 0x1A +#define ADIS16201_XINCL_SCALE_REG 0x1C +#define ADIS16201_YINCL_SCALE_REG 0x1E + +/* Alarm Register Definition */ +#define ADIS16201_ALM_MAG1_REG 0x20 +#define ADIS16201_ALM_MAG2_REG 0x22 +#define ADIS16201_ALM_SMPL1_REG 0x24 +#define ADIS16201_ALM_SMPL2_REG 0x26 +#define ADIS16201_ALM_CTRL_REG 0x28 + +#define ADIS16201_AUX_DAC_REG 0x30 +#define ADIS16201_GPIO_CTRL_REG 0x32 +#define ADIS16201_SMPL_PRD_REG 0x36 +/* Operation, filter configuration */ +#define ADIS16201_AVG_CNT_REG 0x38 +#define ADIS16201_SLP_CNT_REG 0x3A + +/* Miscellaneous Control Register Definition */ +#define ADIS16201_MSC_CTRL_REG 0x34 +#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) +/* Data-ready enable: 1 = enabled, 0 = disabled */ +#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) +/* Data-ready polarity: 1 = active high, 0 = active low */ +#define ADIS16201_MSC_CTRL_ACTIVE_DATA_RDY_HIGH BIT(1) +/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ +#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) + +/* Diagnostics System Status Register Definition */ +#define ADIS16201_DIAG_STAT_REG 0x3C +#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) +#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) +#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 +#define ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT 2 +/* Power supply above 3.625 V */ +#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 +/* Power supply below 3.15 V */ +#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 + +/* System Command Register Definition */ +#define ADIS16201_GLOB_CMD_REG 0x3E +#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) +#define ADIS16201_GLOB_CMD_FACTORY_RESET BIT(1) + +#define ADIS16201_ERROR_ACTIVE BIT(14) + +enum adis16201_scan { + ADIS16201_SCAN_ACC_X, + ADIS16201_SCAN_ACC_Y, + ADIS16201_SCAN_INCLI_X, + ADIS16201_SCAN_INCLI_Y, + ADIS16201_SCAN_SUPPLY, + ADIS16201_SCAN_AUX_ADC, + ADIS16201_SCAN_TEMP, +}; + +static const u8 adis16201_addresses[] = { + [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS_REG, + [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS_REG, + [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS_REG, + [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS_REG, +}; + +static int adis16201_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int ret; + int bits; + u8 addr; + s16 val16; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return adis_single_conversion(indio_dev, chan, + ADIS16201_ERROR_ACTIVE, val); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->channel == 0) { + /* Voltage base units are mV hence 1.22 mV */ + *val = 1; + *val2 = 220000; + } else { + /* Voltage base units are mV hence 0.61 mV */ + *val = 0; + *val2 = 610000; + } + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = -470; + *val2 = 0; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + /* + * IIO base unit for sensitivity of accelerometer + * is milli g. + * 1 LSB represents 0.244 mg. + */ + *val = 0; + *val2 = IIO_G_TO_M_S_2(462400); + return IIO_VAL_INT_PLUS_NANO; + case IIO_INCLI: + *val = 0; + *val2 = 100000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_OFFSET: + /* + * The raw ADC value is 1278 when the temperature + * is 25 degrees and the scale factor per milli + * degree celcius is -470. + */ + *val = 25000 / -470 - 1278; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ACCEL: + bits = 12; + break; + case IIO_INCLI: + bits = 9; + break; + default: + return -EINVAL; + } + addr = adis16201_addresses[chan->scan_index]; + ret = adis_read_reg_16(st, addr, &val16); + if (ret) + return ret; + + *val = sign_extend32(val16, bits - 1); + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int adis16201_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct adis *st = iio_priv(indio_dev); + int m; + + if (mask != IIO_CHAN_INFO_CALIBBIAS) + return -EINVAL; + + switch (chan->type) { + case IIO_ACCEL: + m = GENMASK(11, 0); + break; + case IIO_INCLI: + m = GENMASK(8, 0); + break; + default: + return -EINVAL; + } + + return adis_write_reg_16(st, adis16201_addresses[chan->scan_index], + val & m); +} + +static const struct iio_chan_spec adis16201_channels[] = { + ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT_REG, ADIS16201_SCAN_SUPPLY, 0, + 12), + ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT_REG, ADIS16201_SCAN_TEMP, 0, 12), + ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT_REG, ADIS16201_SCAN_ACC_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT_REG, ADIS16201_SCAN_ACC_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC_REG, ADIS16201_SCAN_AUX_ADC, 0, 12), + ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT_REG, ADIS16201_SCAN_INCLI_X, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT_REG, ADIS16201_SCAN_INCLI_Y, + BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), + IIO_CHAN_SOFT_TIMESTAMP(7) +}; + +static const struct iio_info adis16201_info = { + .read_raw = adis16201_read_raw, + .write_raw = adis16201_write_raw, + .update_scan_mode = adis_update_scan_mode, +}; + +static const char * const adis16201_status_error_msgs[] = { + [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", + [ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT] = "Flash update failed", + [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", + [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", +}; + +static const struct adis_data adis16201_data = { + .read_delay = 20, + .msc_ctrl_reg = ADIS16201_MSC_CTRL_REG, + .glob_cmd_reg = ADIS16201_GLOB_CMD_REG, + .diag_stat_reg = ADIS16201_DIAG_STAT_REG, + + .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN, + .self_test_no_autoclear = true, + .startup_delay = ADIS16201_STARTUP_DELAY_MS, + + .status_error_msgs = adis16201_status_error_msgs, + .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) | + BIT(ADIS16201_DIAG_STAT_FLASH_UPT_FAIL_BIT) | + BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) | + BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT), +}; + +static int adis16201_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adis *st; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + + indio_dev->name = spi->dev.driver->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &adis16201_info; + + indio_dev->channels = adis16201_channels; + indio_dev->num_channels = ARRAY_SIZE(adis16201_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = adis_init(st, indio_dev, spi, &adis16201_data); + if (ret) + return ret; + + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); + if (ret) + return ret; + + ret = adis_initial_startup(st); + if (ret) + goto error_cleanup_buffer_trigger; + + ret = iio_device_register(indio_dev); + if (ret < 0) + goto error_cleanup_buffer_trigger; + + return 0; + +error_cleanup_buffer_trigger: + adis_cleanup_buffer_and_trigger(st, indio_dev); + return ret; +} + +static int adis16201_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + adis_cleanup_buffer_and_trigger(st, indio_dev); + + return 0; +} + +static struct spi_driver adis16201_driver = { + .driver = { + .name = "adis16201", + }, + .probe = adis16201_probe, + .remove = adis16201_remove, +}; +module_spi_driver(adis16201_driver); + +MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); +MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:adis16201"); diff --git a/drivers/staging/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 72a18cfe81ee..f2dc3a5f0463 100644 --- a/drivers/staging/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -6,7 +6,6 @@ * Licensed under the GPL-2 or later. */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/list.h> @@ -16,8 +15,6 @@ #include <linux/sysfs.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> #include <linux/iio/imu/adis.h> #define ADIS16209_STARTUP_DELAY_MS 220 @@ -71,13 +68,13 @@ #define ADIS16209_STAT_REG 0x3C #define ADIS16209_STAT_ALARM2 BIT(9) #define ADIS16209_STAT_ALARM1 BIT(8) -#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5 -#define ADIS16209_STAT_SPI_FAIL_BIT 3 -#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2 +#define ADIS16209_STAT_SELFTEST_FAIL_BIT 5 +#define ADIS16209_STAT_SPI_FAIL_BIT 3 +#define ADIS16209_STAT_FLASH_UPT_FAIL_BIT 2 /* Power supply above 3.625 V */ -#define ADIS16209_STAT_POWER_HIGH_BIT 1 +#define ADIS16209_STAT_POWER_HIGH_BIT 1 /* Power supply below 3.15 V */ -#define ADIS16209_STAT_POWER_LOW_BIT 0 +#define ADIS16209_STAT_POWER_LOW_BIT 0 #define ADIS16209_CMD_REG 0x3E #define ADIS16209_CMD_SW_RESET BIT(7) @@ -115,25 +112,22 @@ static int adis16209_write_raw(struct iio_dev *indio_dev, long mask) { struct adis *st = iio_priv(indio_dev); - int bits; - s16 val16; - u8 addr; + int m; - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - case IIO_INCLI: - bits = 14; - break; - default: - return -EINVAL; - } - val16 = val & ((1 << bits) - 1); - addr = adis16209_addresses[chan->scan_index][0]; - return adis_write_reg_16(st, addr, val16); + if (mask != IIO_CHAN_INFO_CALIBBIAS) + return -EINVAL; + + switch (chan->type) { + case IIO_ACCEL: + case IIO_INCLI: + m = GENMASK(13, 0); + break; + default: + return -EINVAL; } - return -EINVAL; + + return adis_write_reg_16(st, adis16209_addresses[chan->scan_index][0], + val & m); } static int adis16209_read_raw(struct iio_dev *indio_dev, @@ -195,7 +189,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_OFFSET: /* * The raw ADC value is 0x4FE when the temperature - * is 25 degrees and the scale factor per milli + * is 45 degrees and the scale factor per milli * degree celcius is -470. */ *val = 25000 / -470 - 0x4FE; @@ -270,13 +264,14 @@ static const struct adis_data adis16209_data = { static int adis16209_probe(struct spi_device *spi) { - int ret; - struct adis *st; struct iio_dev *indio_dev; + struct adis *st; + int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; + st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); @@ -290,6 +285,7 @@ static int adis16209_probe(struct spi_device *spi) ret = adis_init(st, indio_dev, spi, &adis16209_data); if (ret) return ret; + ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); if (ret) return ret; diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 208f2d9f0e8a..383c802eb5b8 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -837,29 +837,12 @@ static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data, int sample_length = 3 * 2; int ret; int total_length = samples * sample_length; - int i; - size_t step = regmap_get_raw_read_max(data->regmap); - - if (!step || step > total_length) - step = total_length; - else if (step < total_length) - step = sample_length; - - /* - * Seems we have a bus with size limitation so we have to execute - * multiple reads - */ - for (i = 0; i < total_length; i += step) { - ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, - &buffer[i], step); - if (ret) - break; - } + ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, + buffer, total_length); if (ret) dev_err(dev, - "Error transferring data from fifo in single steps of %zu\n", - step); + "Error transferring data from fifo: %d\n", ret); return ret; } diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index f33dadf7b262..4dceb75e3586 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -1277,7 +1277,7 @@ static int sca3000_configure_ring(struct iio_dev *indio_dev) { struct iio_buffer *buffer; - buffer = iio_kfifo_allocate(); + buffer = devm_iio_kfifo_allocate(&indio_dev->dev); if (!buffer) return -ENOMEM; @@ -1287,11 +1287,6 @@ static int sca3000_configure_ring(struct iio_dev *indio_dev) return 0; } -static void sca3000_unconfigure_ring(struct iio_dev *indio_dev) -{ - iio_kfifo_free(indio_dev->buffer); -} - static inline int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) { @@ -1486,7 +1481,9 @@ static int sca3000_probe(struct spi_device *spi) } indio_dev->modes = INDIO_DIRECT_MODE; - sca3000_configure_ring(indio_dev); + ret = sca3000_configure_ring(indio_dev); + if (ret) + return ret; if (spi->irq) { ret = request_threaded_irq(spi->irq, @@ -1546,8 +1543,6 @@ static int sca3000_remove(struct spi_device *spi) if (spi->irq) free_irq(spi->irq, indio_dev); - sca3000_unconfigure_ring(indio_dev); - return 0; } diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 6bdec8c451e0..056dddb27236 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -107,6 +107,7 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id st_accel_acpi_match[] = { + {"SMO8840", LNG2DM}, {"SMO8A90", LNG2DM}, { }, }; diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index 70fbf92f9827..a9ff0695ddf7 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -153,6 +153,17 @@ struct ad7791_state { const struct ad7791_chip_info *info; }; +static const int ad7791_sample_freq_avail[8][2] = { + [AD7791_FILTER_RATE_120] = { 120, 0 }, + [AD7791_FILTER_RATE_100] = { 100, 0 }, + [AD7791_FILTER_RATE_33_3] = { 33, 300000 }, + [AD7791_FILTER_RATE_20] = { 20, 0 }, + [AD7791_FILTER_RATE_16_6] = { 16, 600000 }, + [AD7791_FILTER_RATE_16_7] = { 16, 700000 }, + [AD7791_FILTER_RATE_13_3] = { 13, 300000 }, + [AD7791_FILTER_RATE_9_5] = { 9, 500000 }, +}; + static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd) { return container_of(sd, struct ad7791_state, sd); @@ -202,6 +213,7 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, { struct ad7791_state *st = iio_priv(indio_dev); bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR); + unsigned int rate; switch (info) { case IIO_CHAN_INFO_RAW: @@ -239,63 +251,56 @@ static int ad7791_read_raw(struct iio_dev *indio_dev, *val2 = chan->scan_type.realbits - 1; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + rate = st->filter & AD7791_FILTER_RATE_MASK; + *val = ad7791_sample_freq_avail[rate][0]; + *val2 = ad7791_sample_freq_avail[rate][1]; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } -static const char * const ad7791_sample_freq_avail[] = { - [AD7791_FILTER_RATE_120] = "120", - [AD7791_FILTER_RATE_100] = "100", - [AD7791_FILTER_RATE_33_3] = "33.3", - [AD7791_FILTER_RATE_20] = "20", - [AD7791_FILTER_RATE_16_6] = "16.6", - [AD7791_FILTER_RATE_16_7] = "16.7", - [AD7791_FILTER_RATE_13_3] = "13.3", - [AD7791_FILTER_RATE_9_5] = "9.5", -}; - -static ssize_t ad7791_read_frequency(struct device *dev, - struct device_attribute *attr, char *buf) +static int ad7791_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7791_state *st = iio_priv(indio_dev); - unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK; - - return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]); -} - -static ssize_t ad7791_write_frequency(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7791_state *st = iio_priv(indio_dev); - int i, ret; - - i = sysfs_match_string(ad7791_sample_freq_avail, buf); - if (i < 0) - return i; + int ret, i; ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; - st->filter &= ~AD7791_FILTER_RATE_MASK; - st->filter |= i; - ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, sizeof(st->filter), - st->filter); - iio_device_release_direct_mode(indio_dev); - return len; -} + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) { + if (ad7791_sample_freq_avail[i][0] == val && + ad7791_sample_freq_avail[i][1] == val2) + break; + } + + if (i == ARRAY_SIZE(ad7791_sample_freq_avail)) { + ret = -EINVAL; + break; + } + + st->filter &= ~AD7791_FILTER_RATE_MASK; + st->filter |= i; + ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, + sizeof(st->filter), + st->filter); + break; + default: + ret = -EINVAL; + } -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7791_read_frequency, - ad7791_write_frequency); + iio_device_release_direct_mode(indio_dev); + return ret; +} static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5"); static struct attribute *ad7791_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL }; @@ -306,12 +311,14 @@ static const struct attribute_group ad7791_attribute_group = { static const struct iio_info ad7791_info = { .read_raw = &ad7791_read_raw, + .write_raw = &ad7791_write_raw, .attrs = &ad7791_attribute_group, .validate_trigger = ad_sd_validate_trigger, }; static const struct iio_info ad7791_no_filter_info = { .read_raw = &ad7791_read_raw, + .write_raw = &ad7791_write_raw, .validate_trigger = ad_sd_validate_trigger, }; diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index ede955d9b2a4..2948909f3ee3 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -219,15 +219,19 @@ enum meson_sar_adc_chan7_mux_sel { CHAN7_MUX_CH7_INPUT = 0x7, }; -struct meson_sar_adc_data { +struct meson_sar_adc_param { bool has_bl30_integration; unsigned long clock_rate; u32 bandgap_reg; unsigned int resolution; - const char *name; const struct regmap_config *regmap_config; }; +struct meson_sar_adc_data { + const struct meson_sar_adc_param *param; + const char *name; +}; + struct meson_sar_adc_priv { struct regmap *regmap; struct regulator *vref; @@ -276,7 +280,7 @@ static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val) /* use val_calib = scale * val_raw + offset calibration function */ tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias; - return clamp(tmp, 0, (1 << priv->data->resolution) - 1); + return clamp(tmp, 0, (1 << priv->data->param->resolution) - 1); } static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev) @@ -328,7 +332,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, } fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); - fifo_val &= GENMASK(priv->data->resolution - 1, 0); + fifo_val &= GENMASK(priv->data->param->resolution - 1, 0); *val = meson_sar_adc_calib_val(indio_dev, fifo_val); return 0; @@ -447,7 +451,7 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) mutex_lock(&indio_dev->mlock); - if (priv->data->has_bl30_integration) { + if (priv->data->param->has_bl30_integration) { /* prevent BL30 from using the SAR ADC while we are using it */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, MESON_SAR_ADC_DELAY_KERNEL_BUSY, @@ -475,7 +479,7 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - if (priv->data->has_bl30_integration) + if (priv->data->param->has_bl30_integration) /* allow BL30 to use the SAR ADC again */ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); @@ -559,7 +563,7 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, } *val = ret / 1000; - *val2 = priv->data->resolution; + *val2 = priv->data->param->resolution; return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_CALIBBIAS: @@ -632,7 +636,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) */ meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); - if (priv->data->has_bl30_integration) { + if (priv->data->param->has_bl30_integration) { /* * leave sampling delay and the input clocks as configured by * BL30 to make sure BL30 gets the values it expects when @@ -712,7 +716,7 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) return ret; } - ret = clk_set_rate(priv->adc_clk, priv->data->clock_rate); + ret = clk_set_rate(priv->adc_clk, priv->data->param->clock_rate); if (ret) { dev_err(indio_dev->dev.parent, "failed to set adc clock rate\n"); @@ -725,14 +729,15 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + const struct meson_sar_adc_param *param = priv->data->param; u32 enable_mask; - if (priv->data->bandgap_reg == MESON_SAR_ADC_REG11) + if (param->bandgap_reg == MESON_SAR_ADC_REG11) enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN; else enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN; - regmap_update_bits(priv->regmap, priv->data->bandgap_reg, enable_mask, + regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask, on_off ? enable_mask : 0); } @@ -844,8 +849,8 @@ static int meson_sar_adc_calib(struct iio_dev *indio_dev) int ret, nominal0, nominal1, value0, value1; /* use points 25% and 75% for calibration */ - nominal0 = (1 << priv->data->resolution) / 4; - nominal1 = (1 << priv->data->resolution) * 3 / 4; + nominal0 = (1 << priv->data->param->resolution) / 4; + nominal1 = (1 << priv->data->param->resolution) * 3 / 4; meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4); usleep_range(10, 20); @@ -883,51 +888,60 @@ static const struct iio_info meson_sar_adc_iio_info = { .read_raw = meson_sar_adc_iio_info_read_raw, }; -static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { - .has_bl30_integration = false, - .clock_rate = 1150000, - .bandgap_reg = MESON_SAR_ADC_DELTA_10, - .regmap_config = &meson_sar_adc_regmap_config_meson8, - .resolution = 10, - .name = "meson-meson8-saradc", -}; - -static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { +static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { .has_bl30_integration = false, .clock_rate = 1150000, .bandgap_reg = MESON_SAR_ADC_DELTA_10, .regmap_config = &meson_sar_adc_regmap_config_meson8, .resolution = 10, - .name = "meson-meson8b-saradc", }; -static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { +static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { .has_bl30_integration = true, .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 10, - .name = "meson-gxbb-saradc", }; -static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { +static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { .has_bl30_integration = true, .clock_rate = 1200000, .bandgap_reg = MESON_SAR_ADC_REG11, .regmap_config = &meson_sar_adc_regmap_config_gxbb, .resolution = 12, +}; + +static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { + .param = &meson_sar_adc_meson8_param, + .name = "meson-meson8-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { + .param = &meson_sar_adc_meson8_param, + .name = "meson-meson8b-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { + .param = &meson_sar_adc_gxbb_param, + .name = "meson-gxbb-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { + .param = &meson_sar_adc_gxl_param, .name = "meson-gxl-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { - .has_bl30_integration = true, - .clock_rate = 1200000, - .bandgap_reg = MESON_SAR_ADC_REG11, - .regmap_config = &meson_sar_adc_regmap_config_gxbb, - .resolution = 12, + .param = &meson_sar_adc_gxl_param, .name = "meson-gxm-saradc", }; +static const struct meson_sar_adc_data meson_sar_adc_axg_data = { + .param = &meson_sar_adc_gxl_param, + .name = "meson-axg-saradc", +}; + static const struct of_device_id meson_sar_adc_of_match[] = { { .compatible = "amlogic,meson8-saradc", @@ -946,6 +960,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { }, { .compatible = "amlogic,meson-gxm-saradc", .data = &meson_sar_adc_gxm_data, + }, { + .compatible = "amlogic,meson-axg-saradc", + .data = &meson_sar_adc_axg_data, }, {}, }; @@ -1001,7 +1018,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) return ret; priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, - priv->data->regmap_config); + priv->data->param->regmap_config); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 40be7d9fadbf..ca432e7b6ff1 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -34,9 +34,6 @@ #define STM32F4_ADC_ADCPRE_SHIFT 16 #define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) -/* STM32 F4 maximum analog clock rate (from datasheet) */ -#define STM32F4_ADC_MAX_CLK_RATE 36000000 - /* STM32H7 - common registers for all ADC instances */ #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) #define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) @@ -51,9 +48,6 @@ #define STM32H7_CKMODE_SHIFT 16 #define STM32H7_CKMODE_MASK GENMASK(17, 16) -/* STM32 H7 maximum analog clock rate (from datasheet) */ -#define STM32H7_ADC_MAX_CLK_RATE 36000000 - /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset @@ -74,15 +68,17 @@ struct stm32_adc_priv; * stm32_adc_priv_cfg - stm32 core compatible configuration data * @regs: common registers for all instances * @clk_sel: clock selection routine + * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) */ struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); + u32 max_clk_rate_hz; }; /** * struct stm32_adc_priv - stm32 ADC core private data - * @irq: irq for ADC block + * @irq: irq(s) for ADC block * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used @@ -91,7 +87,7 @@ struct stm32_adc_priv_cfg { * @common: common data for all ADC instances */ struct stm32_adc_priv { - int irq; + int irq[STM32_ADC_MAX_ADCS]; struct irq_domain *domain; struct clk *aclk; struct clk *bclk; @@ -133,7 +129,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { - if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE) + if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz) break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { @@ -222,7 +218,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; - if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + if ((rate / div) <= priv->cfg->max_clk_rate_hz) goto out; } } @@ -242,7 +238,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; - if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) + if ((rate / div) <= priv->cfg->max_clk_rate_hz) goto out; } @@ -328,11 +324,24 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, struct stm32_adc_priv *priv) { struct device_node *np = pdev->dev.of_node; + unsigned int i; + + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + priv->irq[i] = platform_get_irq(pdev, i); + if (priv->irq[i] < 0) { + /* + * At least one interrupt must be provided, make others + * optional: + * - stm32f4/h7 shares a common interrupt. + * - stm32mp1, has one line per ADC (either for ADC1, + * ADC2 or both). + */ + if (i && priv->irq[i] == -ENXIO) + continue; + dev_err(&pdev->dev, "failed to get irq\n"); - priv->irq = platform_get_irq(pdev, 0); - if (priv->irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); - return priv->irq; + return priv->irq[i]; + } } priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, @@ -343,8 +352,12 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, return -ENOMEM; } - irq_set_chained_handler(priv->irq, stm32_adc_irq_handler); - irq_set_handler_data(priv->irq, priv); + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + if (priv->irq[i] < 0) + continue; + irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler); + irq_set_handler_data(priv->irq[i], priv); + } return 0; } @@ -353,11 +366,17 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, struct stm32_adc_priv *priv) { int hwirq; + unsigned int i; for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++) irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); irq_domain_remove(priv->domain); - irq_set_chained_handler(priv->irq, NULL); + + for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { + if (priv->irq[i] < 0) + continue; + irq_set_chained_handler(priv->irq[i], NULL); + } } static int stm32_adc_probe(struct platform_device *pdev) @@ -497,11 +516,19 @@ static int stm32_adc_remove(struct platform_device *pdev) static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { .regs = &stm32f4_adc_common_regs, .clk_sel = stm32f4_adc_clk_sel, + .max_clk_rate_hz = 36000000, }; static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 36000000, +}; + +static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { + .regs = &stm32h7_adc_common_regs, + .clk_sel = stm32h7_adc_clk_sel, + .max_clk_rate_hz = 40000000, }; static const struct of_device_id stm32_adc_of_match[] = { @@ -512,6 +539,9 @@ static const struct of_device_id stm32_adc_of_match[] = { .compatible = "st,stm32h7-adc-core", .data = (void *)&stm32h7_adc_priv_cfg }, { + .compatible = "st,stm32mp1-adc-core", + .data = (void *)&stm32mp1_adc_priv_cfg + }, { }, }; MODULE_DEVICE_TABLE(of, stm32_adc_of_match); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 9a2583caedaa..378411853d75 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -84,6 +84,7 @@ #define STM32H7_ADC_CALFACT2 0xC8 /* STM32H7_ADC_ISR - bit fields */ +#define STM32MP1_VREGREADY BIT(12) #define STM32H7_EOC BIT(2) #define STM32H7_ADRDY BIT(0) @@ -249,6 +250,7 @@ struct stm32_adc; * @adc_info: per instance input channels definitions * @trigs: external trigger sources * @clk_required: clock is required + * @has_vregready: vregready status flag presence * @selfcalib: optional routine for self-calibration * @prepare: optional prepare routine (power-up, enable) * @start_conv: routine to start conversions @@ -261,6 +263,7 @@ struct stm32_adc_cfg { const struct stm32_adc_info *adc_info; struct stm32_adc_trig_info *trigs; bool clk_required; + bool has_vregready; int (*selfcalib)(struct stm32_adc *); int (*prepare)(struct stm32_adc *); void (*start_conv)(struct stm32_adc *, bool dma); @@ -695,8 +698,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK); } -static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) { + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + int ret; + u32 val; + /* Exit deep power down, then enable ADC voltage regulator */ stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN); @@ -705,7 +712,20 @@ static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); /* Wait for startup time */ - usleep_range(10, 20); + if (!adc->cfg->has_vregready) { + usleep_range(10, 20); + return 0; + } + + ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_ISR, val, + val & STM32MP1_VREGREADY, 100, + STM32_ADC_TIMEOUT_US); + if (ret) { + stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); + dev_err(&indio_dev->dev, "Failed to exit power down\n"); + } + + return ret; } static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) @@ -888,7 +908,9 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) int ret; u32 val; - stm32h7_adc_exit_pwr_down(adc); + ret = stm32h7_adc_exit_pwr_down(adc); + if (ret) + return ret; /* * Select calibration mode: @@ -952,7 +974,10 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) { int ret; - stm32h7_adc_exit_pwr_down(adc); + ret = stm32h7_adc_exit_pwr_down(adc); + if (ret) + return ret; + stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); ret = stm32h7_adc_enable(adc); @@ -1944,9 +1969,23 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .smp_cycles = stm32h7_adc_smp_cycles, }; +static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .regs = &stm32h7_adc_regspec, + .adc_info = &stm32h7_adc_info, + .trigs = stm32h7_adc_trigs, + .has_vregready = true, + .selfcalib = stm32h7_adc_selfcalib, + .start_conv = stm32h7_adc_start_conv, + .stop_conv = stm32h7_adc_stop_conv, + .prepare = stm32h7_adc_prepare, + .unprepare = stm32h7_adc_unprepare, + .smp_cycles = stm32h7_adc_smp_cycles, +}; + static const struct of_device_id stm32_adc_of_match[] = { { .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg }, { .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg }, + { .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg }, {}, }; MODULE_DEVICE_TABLE(of, stm32_adc_of_match); diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 01422d11753c..1b78becaba5d 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -253,7 +253,8 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_RSWSTART(1)); } -static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, unsigned int fl_id) +static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, + unsigned int fl_id) { /* Disable conversion */ regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), @@ -337,7 +338,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, "st,adc-channel-types", chan_idx, &of_str); if (!ret) { - val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_type); if (val < 0) return val; } else { @@ -349,7 +350,7 @@ static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, "st,adc-channel-clk-src", chan_idx, &of_str); if (!ret) { - val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); + val = stm32_dfsdm_str2val(of_str, stm32_dfsdm_chan_src); if (val < 0) return val; } else { @@ -1093,7 +1094,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) char *name; int ret, irq, val; - dev_data = of_device_get_match_data(dev); iio = devm_iio_device_alloc(dev, sizeof(*adc)); if (!iio) { @@ -1111,8 +1111,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); ret = of_property_read_u32(dev->of_node, "reg", &adc->fl_id); - if (ret != 0) { - dev_err(dev, "Missing reg property\n"); + if (ret != 0 || adc->fl_id >= adc->dfsdm->num_fls) { + dev_err(dev, "Missing or bad reg property\n"); return -EINVAL; } @@ -1161,7 +1161,6 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) if (ret < 0) goto err_cleanup; - dev_err(dev, "of_platform_populate\n"); if (dev_data->type == DFSDM_AUDIO) { ret = of_platform_populate(np, NULL, NULL, dev); if (ret < 0) { diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c index e50efdcc41ff..1d0d8238d9b5 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -227,6 +227,11 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, } priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; + if (!priv->spi_clk_out_div) { + /* spi_clk_out_div == 0 means ckout is OFF */ + dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); + return -EINVAL; + } priv->dfsdm.spi_master_freq = spi_freq; if (rem) { diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c index 17b021f33180..0662ca199eb0 100644 --- a/drivers/iio/adc/stx104.c +++ b/drivers/iio/adc/stx104.c @@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(inb(stx104gpio->base) & BIT(offset)); } +static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, + unsigned long *bits) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + + *bits = inb(stx104gpio->base); + + return 0; +} + static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { @@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id) stx104gpio->chip.direction_input = stx104_gpio_direction_input; stx104gpio->chip.direction_output = stx104_gpio_direction_output; stx104gpio->chip.get = stx104_gpio_get; + stx104gpio->chip.get_multiple = stx104_gpio_get_multiple; stx104gpio->chip.set = stx104_gpio_set; stx104gpio->chip.set_multiple = stx104_gpio_set_multiple; stx104gpio->base = base[id] + 3; diff --git a/drivers/iio/afe/Kconfig b/drivers/iio/afe/Kconfig new file mode 100644 index 000000000000..c91eef04825a --- /dev/null +++ b/drivers/iio/afe/Kconfig @@ -0,0 +1,19 @@ +# +# Analog Front End drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Analog Front Ends" + +config IIO_RESCALE + tristate "IIO rescale" + depends on OF || COMPILE_TEST + help + Say yes here to build support for the IIO rescaling + that handles voltage dividers, current sense shunts and + current sense amplifiers. + + To compile this driver as a module, choose M here: the + module will be called iio-rescale. + +endmenu diff --git a/drivers/iio/afe/Makefile b/drivers/iio/afe/Makefile new file mode 100644 index 000000000000..5fabb7bcac47 --- /dev/null +++ b/drivers/iio/afe/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O Analog Front Ends (AFE) +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_IIO_RESCALE) += iio-rescale.o diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c new file mode 100644 index 000000000000..e9ceee66d1e7 --- /dev/null +++ b/drivers/iio/afe/iio-rescale.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IIO rescale driver + * + * Copyright (C) 2018 Axentia Technologies AB + * + * Author: Peter Rosin <peda@axentia.se> + */ + +#include <linux/err.h> +#include <linux/gcd.h> +#include <linux/iio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/property.h> + +struct rescale; + +struct rescale_cfg { + enum iio_chan_type type; + int (*props)(struct device *dev, struct rescale *rescale); +}; + +struct rescale { + const struct rescale_cfg *cfg; + struct iio_channel *source; + struct iio_chan_spec chan; + struct iio_chan_spec_ext_info *ext_info; + s32 numerator; + s32 denominator; +}; + +static int rescale_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rescale *rescale = iio_priv(indio_dev); + unsigned long long tmp; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return iio_read_channel_raw(rescale->source, val); + + case IIO_CHAN_INFO_SCALE: + ret = iio_read_channel_scale(rescale->source, val, val2); + switch (ret) { + case IIO_VAL_FRACTIONAL: + *val *= rescale->numerator; + *val2 *= rescale->denominator; + return ret; + case IIO_VAL_INT: + *val *= rescale->numerator; + if (rescale->denominator == 1) + return ret; + *val2 = rescale->denominator; + return IIO_VAL_FRACTIONAL; + case IIO_VAL_FRACTIONAL_LOG2: + tmp = *val * 1000000000LL; + do_div(tmp, rescale->denominator); + tmp *= rescale->numerator; + do_div(tmp, 1000000000LL); + *val = tmp; + return ret; + default: + return -EOPNOTSUPP; + } + default: + return -EINVAL; + } +} + +static int rescale_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct rescale *rescale = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *type = IIO_VAL_INT; + return iio_read_avail_channel_raw(rescale->source, + vals, length); + default: + return -EINVAL; + } +} + +static const struct iio_info rescale_info = { + .read_raw = rescale_read_raw, + .read_avail = rescale_read_avail, +}; + +static ssize_t rescale_read_ext_info(struct iio_dev *indio_dev, + uintptr_t private, + struct iio_chan_spec const *chan, + char *buf) +{ + struct rescale *rescale = iio_priv(indio_dev); + + return iio_read_channel_ext_info(rescale->source, + rescale->ext_info[private].name, + buf); +} + +static ssize_t rescale_write_ext_info(struct iio_dev *indio_dev, + uintptr_t private, + struct iio_chan_spec const *chan, + const char *buf, size_t len) +{ + struct rescale *rescale = iio_priv(indio_dev); + + return iio_write_channel_ext_info(rescale->source, + rescale->ext_info[private].name, + buf, len); +} + +static int rescale_configure_channel(struct device *dev, + struct rescale *rescale) +{ + struct iio_chan_spec *chan = &rescale->chan; + struct iio_chan_spec const *schan = rescale->source->channel; + + chan->indexed = 1; + chan->output = schan->output; + chan->ext_info = rescale->ext_info; + chan->type = rescale->cfg->type; + + if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || + !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { + dev_err(dev, "source channel does not support raw/scale\n"); + return -EINVAL; + } + + chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE); + + if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW)) + chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); + + return 0; +} + +static int rescale_current_sense_amplifier_props(struct device *dev, + struct rescale *rescale) +{ + u32 sense; + u32 gain_mult = 1; + u32 gain_div = 1; + u32 factor; + int ret; + + ret = device_property_read_u32(dev, "sense-resistor-micro-ohms", + &sense); + if (ret) { + dev_err(dev, "failed to read the sense resistance: %d\n", ret); + return ret; + } + + device_property_read_u32(dev, "sense-gain-mult", &gain_mult); + device_property_read_u32(dev, "sense-gain-div", &gain_div); + + /* + * Calculate the scaling factor, 1 / (gain * sense), or + * gain_div / (gain_mult * sense), while trying to keep the + * numerator/denominator from overflowing. + */ + factor = gcd(sense, 1000000); + rescale->numerator = 1000000 / factor; + rescale->denominator = sense / factor; + + factor = gcd(rescale->numerator, gain_mult); + rescale->numerator /= factor; + rescale->denominator *= gain_mult / factor; + + factor = gcd(rescale->denominator, gain_div); + rescale->numerator *= gain_div / factor; + rescale->denominator /= factor; + + return 0; +} + +static int rescale_current_sense_shunt_props(struct device *dev, + struct rescale *rescale) +{ + u32 shunt; + u32 factor; + int ret; + + ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", + &shunt); + if (ret) { + dev_err(dev, "failed to read the shunt resistance: %d\n", ret); + return ret; + } + + factor = gcd(shunt, 1000000); + rescale->numerator = 1000000 / factor; + rescale->denominator = shunt / factor; + + return 0; +} + +static int rescale_voltage_divider_props(struct device *dev, + struct rescale *rescale) +{ + int ret; + u32 factor; + + ret = device_property_read_u32(dev, "output-ohms", + &rescale->denominator); + if (ret) { + dev_err(dev, "failed to read output-ohms: %d\n", ret); + return ret; + } + + ret = device_property_read_u32(dev, "full-ohms", + &rescale->numerator); + if (ret) { + dev_err(dev, "failed to read full-ohms: %d\n", ret); + return ret; + } + + factor = gcd(rescale->numerator, rescale->denominator); + rescale->numerator /= factor; + rescale->denominator /= factor; + + return 0; +} + +enum rescale_variant { + CURRENT_SENSE_AMPLIFIER, + CURRENT_SENSE_SHUNT, + VOLTAGE_DIVIDER, +}; + +static const struct rescale_cfg rescale_cfg[] = { + [CURRENT_SENSE_AMPLIFIER] = { + .type = IIO_CURRENT, + .props = rescale_current_sense_amplifier_props, + }, + [CURRENT_SENSE_SHUNT] = { + .type = IIO_CURRENT, + .props = rescale_current_sense_shunt_props, + }, + [VOLTAGE_DIVIDER] = { + .type = IIO_VOLTAGE, + .props = rescale_voltage_divider_props, + }, +}; + +static const struct of_device_id rescale_match[] = { + { .compatible = "current-sense-amplifier", + .data = &rescale_cfg[CURRENT_SENSE_AMPLIFIER], }, + { .compatible = "current-sense-shunt", + .data = &rescale_cfg[CURRENT_SENSE_SHUNT], }, + { .compatible = "voltage-divider", + .data = &rescale_cfg[VOLTAGE_DIVIDER], }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rescale_match); + +static int rescale_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct iio_channel *source; + struct rescale *rescale; + int sizeof_ext_info; + int sizeof_priv; + int i; + int ret; + + source = devm_iio_channel_get(dev, NULL); + if (IS_ERR(source)) { + if (PTR_ERR(source) != -EPROBE_DEFER) + dev_err(dev, "failed to get source channel\n"); + return PTR_ERR(source); + } + + sizeof_ext_info = iio_get_channel_ext_info_count(source); + if (sizeof_ext_info) { + sizeof_ext_info += 1; /* one extra entry for the sentinel */ + sizeof_ext_info *= sizeof(*rescale->ext_info); + } + + sizeof_priv = sizeof(*rescale) + sizeof_ext_info; + + indio_dev = devm_iio_device_alloc(dev, sizeof_priv); + if (!indio_dev) + return -ENOMEM; + + rescale = iio_priv(indio_dev); + + rescale->cfg = of_device_get_match_data(dev); + rescale->numerator = 1; + rescale->denominator = 1; + + ret = rescale->cfg->props(dev, rescale); + if (ret) + return ret; + + if (!rescale->numerator || !rescale->denominator) { + dev_err(dev, "invalid scaling factor.\n"); + return -EINVAL; + } + + platform_set_drvdata(pdev, indio_dev); + + rescale->source = source; + + indio_dev->name = dev_name(dev); + indio_dev->dev.parent = dev; + indio_dev->info = &rescale_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = &rescale->chan; + indio_dev->num_channels = 1; + if (sizeof_ext_info) { + rescale->ext_info = devm_kmemdup(dev, + source->channel->ext_info, + sizeof_ext_info, GFP_KERNEL); + if (!rescale->ext_info) + return -ENOMEM; + + for (i = 0; rescale->ext_info[i].name; ++i) { + struct iio_chan_spec_ext_info *ext_info = + &rescale->ext_info[i]; + + if (source->channel->ext_info[i].read) + ext_info->read = rescale_read_ext_info; + if (source->channel->ext_info[i].write) + ext_info->write = rescale_write_ext_info; + ext_info->private = i; + } + } + + ret = rescale_configure_channel(dev, rescale); + if (ret) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} + +static struct platform_driver rescale_driver = { + .probe = rescale_probe, + .driver = { + .name = "iio-rescale", + .of_match_table = rescale_match, + }, +}; +module_platform_driver(rescale_driver); + +MODULE_DESCRIPTION("IIO rescale driver"); +MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index abfc4bbc4cfc..a406ad31b096 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -61,9 +61,9 @@ #define ATLAS_REG_ORP_CALIB_STATUS 0x0d #define ATLAS_REG_ORP_DATA 0x0e -#define ATLAS_PH_INT_TIME_IN_US 450000 -#define ATLAS_EC_INT_TIME_IN_US 650000 -#define ATLAS_ORP_INT_TIME_IN_US 450000 +#define ATLAS_PH_INT_TIME_IN_MS 450 +#define ATLAS_EC_INT_TIME_IN_MS 650 +#define ATLAS_ORP_INT_TIME_IN_MS 450 enum { ATLAS_PH_SM, @@ -270,21 +270,21 @@ static struct atlas_device atlas_devices[] = { .num_channels = 3, .data_reg = ATLAS_REG_PH_DATA, .calibration = &atlas_check_ph_calibration, - .delay = ATLAS_PH_INT_TIME_IN_US, + .delay = ATLAS_PH_INT_TIME_IN_MS, }, [ATLAS_EC_SM] = { .channels = atlas_ec_channels, .num_channels = 5, .data_reg = ATLAS_REG_EC_DATA, .calibration = &atlas_check_ec_calibration, - .delay = ATLAS_EC_INT_TIME_IN_US, + .delay = ATLAS_EC_INT_TIME_IN_MS, }, [ATLAS_ORP_SM] = { .channels = atlas_orp_channels, .num_channels = 2, .data_reg = ATLAS_REG_ORP_DATA, .calibration = &atlas_check_orp_calibration, - .delay = ATLAS_ORP_INT_TIME_IN_US, + .delay = ATLAS_ORP_INT_TIME_IN_MS, }, }; @@ -393,7 +393,7 @@ static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val) } if (suspended) - usleep_range(data->chip->delay, data->chip->delay + 100000); + msleep(data->chip->delay); ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val)); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 705cb3e72663..89cb0066a6e0 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> +#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger_consumer.h> @@ -31,8 +32,6 @@ #include <linux/slab.h> #include <linux/sysfs.h> -#include "cros_ec_sensors_core.h" - #define CROS_EC_SENSORS_MAX_CHANNELS 4 /* State data for ec_sensors iio driver. */ diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index a620eb5ce202..414cc43c287e 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> +#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger_consumer.h> @@ -27,8 +28,6 @@ #include <linux/sysfs.h> #include <linux/platform_device.h> -#include "cros_ec_sensors_core.h" - static char *cros_ec_loc[] = { [MOTIONSENSE_LOC_BASE] = "base", [MOTIONSENSE_LOC_LID] = "lid", @@ -448,8 +447,7 @@ EXPORT_SYMBOL_GPL(cros_ec_sensors_core_write); static int __maybe_unused cros_ec_sensors_prepare(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); if (st->curr_sampl_freq == 0) @@ -471,8 +469,7 @@ static int __maybe_unused cros_ec_sensors_prepare(struct device *dev) static void __maybe_unused cros_ec_sensors_complete(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct cros_ec_sensors_core_state *st = iio_priv(indio_dev); if (st->curr_sampl_freq == 0) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index cfb6588565ba..2ce0efd98cc0 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -304,8 +304,7 @@ EXPORT_SYMBOL(hid_sensor_setup_trigger); 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); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); return _hid_sensor_power_state(attrb, false); @@ -313,8 +312,7 @@ static int __maybe_unused hid_sensor_suspend(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); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); schedule_work(&attrb->work); return 0; @@ -322,8 +320,7 @@ static int __maybe_unused hid_sensor_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); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); return _hid_sensor_power_state(attrb, true); } diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 76db0768e454..06e90debb9f5 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -131,16 +131,31 @@ config LTC2632 module will be called ltc2632. config AD5686 - tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver" + tristate + +config AD5686_SPI + tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)" depends on SPI + select AD5686 help - Say yes here to build support for Analog Devices AD5686R, AD5685R, - AD5684R, AD5791 Voltage Output Digital to - Analog Converter. + Say yes here to build support for Analog Devices AD5672R, AD5676, + AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R. + Voltage Output Digital to Analog Converter. To compile this driver as a module, choose M here: the module will be called ad5686. +config AD5696_I2C + tristate "Analog Devices AD5696 and similar multi-channel DACs (I2C)" + depends on I2C + select AD5686 + help + Say yes here to build support for Analog Devices AD5671R, AD5675R, + AD5694, AD5694R, AD5695R, AD5696, AD5696R Voltage Output Digital to + Analog Converter. + To compile this driver as a module, choose M here: the module will be + called ad5696. + config AD5755 tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver" depends on SPI_MASTER @@ -321,6 +336,16 @@ config TI_DAC082S085 If compiled as a module, it will be called ti-dac082s085. +config TI_DAC5571 + tristate "Texas Instruments 8/10/12/16-bit 1/2/4-channel DAC driver" + depends on I2C + help + Driver for the Texas Instruments + DAC5571, DAC6571, DAC7571, DAC5574, DAC6574, DAC7574, DAC5573, + DAC6573, DAC7573, DAC8571, DAC8574. + + If compiled as a module, it will be called ti-dac5571. + config VF610_DAC tristate "Vybrid vf610 DAC driver" depends on OF diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 81e710ed7491..57aa230d34ab 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -20,6 +20,8 @@ obj-$(CONFIG_AD5761) += ad5761.o obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o +obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o +obj-$(CONFIG_AD5696_I2C) += ad5696-i2c.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_CIO_DAC) += cio-dac.o @@ -35,4 +37,5 @@ obj-$(CONFIG_MCP4922) += mcp4922.o obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o obj-$(CONFIG_STM32_DAC) += stm32-dac.o obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o +obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o obj-$(CONFIG_VF610_DAC) += vf610_dac.o diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c new file mode 100644 index 000000000000..6bb09e9259e6 --- /dev/null +++ b/drivers/iio/dac/ad5686-spi.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD5672R, AD5676, AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R + * Digital to analog converters driver + * + * Copyright 2018 Analog Devices Inc. + */ + +#include "ad5686.h" + +#include <linux/module.h> +#include <linux/spi/spi.h> + +static int ad5686_spi_write(struct ad5686_state *st, + u8 cmd, u8 addr, u16 val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | + AD5686_ADDR(addr) | + val); + + return spi_write(spi, &st->data[0].d8[1], 3); +} + +static int ad5686_spi_read(struct ad5686_state *st, u8 addr) +{ + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0].d8[1], + .len = 3, + .cs_change = 1, + }, { + .tx_buf = &st->data[1].d8[1], + .rx_buf = &st->data[2].d8[1], + .len = 3, + }, + }; + struct spi_device *spi = to_spi_device(st->dev); + int ret; + + st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | + AD5686_ADDR(addr)); + st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); + + ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t)); + if (ret < 0) + return ret; + + return be32_to_cpu(st->data[2].d32); +} + +static int ad5686_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + return ad5686_probe(&spi->dev, id->driver_data, id->name, + ad5686_spi_write, ad5686_spi_read); +} + +static int ad5686_spi_remove(struct spi_device *spi) +{ + return ad5686_remove(&spi->dev); +} + +static const struct spi_device_id ad5686_spi_id[] = { + {"ad5672r", ID_AD5672R}, + {"ad5676", ID_AD5676}, + {"ad5676r", ID_AD5676R}, + {"ad5684", ID_AD5684}, + {"ad5684r", ID_AD5684R}, + {"ad5685", ID_AD5685R}, /* Does not exist */ + {"ad5685r", ID_AD5685R}, + {"ad5686", ID_AD5686}, + {"ad5686r", ID_AD5686R}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad5686_spi_id); + +static struct spi_driver ad5686_spi_driver = { + .driver = { + .name = "ad5686", + }, + .probe = ad5686_spi_probe, + .remove = ad5686_spi_remove, + .id_table = ad5686_spi_id, +}; + +module_spi_driver(ad5686_spi_driver); + +MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 20254df7f9c7..89c5f089ae7f 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -1,9 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * AD5686R, AD5685R, AD5684R Digital to analog converters driver * * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. */ #include <linux/interrupt.h> @@ -11,7 +10,6 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/kernel.h> -#include <linux/spi/spi.h> #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/regulator/consumer.h> @@ -19,116 +17,7 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#define AD5686_DAC_CHANNELS 4 - -#define AD5686_ADDR(x) ((x) << 16) -#define AD5686_CMD(x) ((x) << 20) - -#define AD5686_ADDR_DAC(chan) (0x1 << (chan)) -#define AD5686_ADDR_ALL_DAC 0xF - -#define AD5686_CMD_NOOP 0x0 -#define AD5686_CMD_WRITE_INPUT_N 0x1 -#define AD5686_CMD_UPDATE_DAC_N 0x2 -#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3 -#define AD5686_CMD_POWERDOWN_DAC 0x4 -#define AD5686_CMD_LDAC_MASK 0x5 -#define AD5686_CMD_RESET 0x6 -#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7 -#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 -#define AD5686_CMD_READBACK_ENABLE 0x9 - -#define AD5686_LDAC_PWRDN_NONE 0x0 -#define AD5686_LDAC_PWRDN_1K 0x1 -#define AD5686_LDAC_PWRDN_100K 0x2 -#define AD5686_LDAC_PWRDN_3STATE 0x3 - -/** - * struct ad5686_chip_info - chip specific information - * @int_vref_mv: AD5620/40/60: the internal reference voltage - * @channel: channel specification -*/ - -struct ad5686_chip_info { - u16 int_vref_mv; - struct iio_chan_spec channel[AD5686_DAC_CHANNELS]; -}; - -/** - * struct ad5446_state - driver instance specific data - * @spi: spi_device - * @chip_info: chip model specific constants, available modes etc - * @reg: supply regulator - * @vref_mv: actual reference voltage used - * @pwr_down_mask: power down mask - * @pwr_down_mode: current power down mode - * @data: spi transfer buffers - */ - -struct ad5686_state { - struct spi_device *spi; - const struct ad5686_chip_info *chip_info; - struct regulator *reg; - unsigned short vref_mv; - unsigned pwr_down_mask; - unsigned pwr_down_mode; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - - union { - __be32 d32; - u8 d8[4]; - } data[3] ____cacheline_aligned; -}; - -/** - * ad5686_supported_device_ids: - */ - -enum ad5686_supported_device_ids { - ID_AD5684, - ID_AD5685, - ID_AD5686, -}; -static int ad5686_spi_write(struct ad5686_state *st, - u8 cmd, u8 addr, u16 val, u8 shift) -{ - val <<= shift; - - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | - AD5686_ADDR(addr) | - val); - - return spi_write(st->spi, &st->data[0].d8[1], 3); -} - -static int ad5686_spi_read(struct ad5686_state *st, u8 addr) -{ - struct spi_transfer t[] = { - { - .tx_buf = &st->data[0].d8[1], - .len = 3, - .cs_change = 1, - }, { - .tx_buf = &st->data[1].d8[1], - .rx_buf = &st->data[2].d8[1], - .len = 3, - }, - }; - int ret; - - st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | - AD5686_ADDR(addr)); - st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); - - ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); - if (ret < 0) - return ret; - - return be32_to_cpu(st->data[2].d32); -} +#include "ad5686.h" static const char * const ad5686_powerdown_modes[] = { "1kohm_to_gnd", @@ -137,7 +26,7 @@ static const char * const ad5686_powerdown_modes[] = { }; static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan) + const struct iio_chan_spec *chan) { struct ad5686_state *st = iio_priv(indio_dev); @@ -145,7 +34,8 @@ static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, } static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, unsigned int mode) + const struct iio_chan_spec *chan, + unsigned int mode) { struct ad5686_state *st = iio_priv(indio_dev); @@ -163,17 +53,19 @@ static const struct iio_enum ad5686_powerdown_mode_enum = { }; static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, char *buf) + uintptr_t private, const struct iio_chan_spec *chan, char *buf) { struct ad5686_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", !!(st->pwr_down_mask & - (0x3 << (chan->channel * 2)))); + (0x3 << (chan->channel * 2)))); } static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, - uintptr_t private, const struct iio_chan_spec *chan, const char *buf, - size_t len) + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, + size_t len) { bool readin; int ret; @@ -188,8 +80,9 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, else st->pwr_down_mask &= ~(0x3 << (chan->channel * 2)); - ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0, - st->pwr_down_mask & st->pwr_down_mode, 0); + ret = st->write(st, AD5686_CMD_POWERDOWN_DAC, 0, + st->pwr_down_mask & st->pwr_down_mode); + return ret ? ret : len; } @@ -206,7 +99,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); - ret = ad5686_spi_read(st, chan->address); + ret = st->read(st, chan->address); mutex_unlock(&indio_dev->mlock); if (ret < 0) return ret; @@ -221,10 +114,10 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, } static int ad5686_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { struct ad5686_state *st = iio_priv(indio_dev); int ret; @@ -235,11 +128,10 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&indio_dev->mlock); - ret = ad5686_spi_write(st, - AD5686_CMD_WRITE_INPUT_N_UPDATE_N, - chan->address, - val, - chan->scan_type.shift); + ret = st->write(st, + AD5686_CMD_WRITE_INPUT_N_UPDATE_N, + chan->address, + val << chan->scan_type.shift); mutex_unlock(&indio_dev->mlock); break; default: @@ -266,14 +158,14 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { { }, }; -#define AD5868_CHANNEL(chan, bits, _shift) { \ +#define AD5868_CHANNEL(chan, addr, bits, _shift) { \ .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),\ - .address = AD5686_ADDR_DAC(chan), \ + .address = addr, \ .scan_type = { \ .sign = 'u', \ .realbits = (bits), \ @@ -283,45 +175,121 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .ext_info = ad5686_ext_info, \ } +#define DECLARE_AD5686_CHANNELS(name, bits, _shift) \ +static struct iio_chan_spec name[] = { \ + AD5868_CHANNEL(0, 1, bits, _shift), \ + AD5868_CHANNEL(1, 2, bits, _shift), \ + AD5868_CHANNEL(2, 4, bits, _shift), \ + AD5868_CHANNEL(3, 8, bits, _shift), \ +} + +#define DECLARE_AD5676_CHANNELS(name, bits, _shift) \ +static struct iio_chan_spec name[] = { \ + AD5868_CHANNEL(0, 0, bits, _shift), \ + AD5868_CHANNEL(1, 1, bits, _shift), \ + AD5868_CHANNEL(2, 2, bits, _shift), \ + AD5868_CHANNEL(3, 3, bits, _shift), \ + AD5868_CHANNEL(4, 4, bits, _shift), \ + AD5868_CHANNEL(5, 5, bits, _shift), \ + AD5868_CHANNEL(6, 6, bits, _shift), \ + AD5868_CHANNEL(7, 7, bits, _shift), \ +} + +DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); +DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); +DECLARE_AD5686_CHANNELS(ad5684_channels, 12, 4); +DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2); +DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0); + static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { + [ID_AD5671R] = { + .channels = ad5672_channels, + .int_vref_mv = 2500, + .num_channels = 8, + }, + [ID_AD5672R] = { + .channels = ad5672_channels, + .int_vref_mv = 2500, + .num_channels = 8, + }, + [ID_AD5675R] = { + .channels = ad5676_channels, + .int_vref_mv = 2500, + .num_channels = 8, + }, + [ID_AD5676] = { + .channels = ad5676_channels, + .num_channels = 8, + }, + [ID_AD5676R] = { + .channels = ad5676_channels, + .int_vref_mv = 2500, + .num_channels = 8, + }, [ID_AD5684] = { - .channel[0] = AD5868_CHANNEL(0, 12, 4), - .channel[1] = AD5868_CHANNEL(1, 12, 4), - .channel[2] = AD5868_CHANNEL(2, 12, 4), - .channel[3] = AD5868_CHANNEL(3, 12, 4), + .channels = ad5684_channels, + .num_channels = 4, + }, + [ID_AD5684R] = { + .channels = ad5684_channels, .int_vref_mv = 2500, + .num_channels = 4, }, - [ID_AD5685] = { - .channel[0] = AD5868_CHANNEL(0, 14, 2), - .channel[1] = AD5868_CHANNEL(1, 14, 2), - .channel[2] = AD5868_CHANNEL(2, 14, 2), - .channel[3] = AD5868_CHANNEL(3, 14, 2), + [ID_AD5685R] = { + .channels = ad5685r_channels, .int_vref_mv = 2500, + .num_channels = 4, }, [ID_AD5686] = { - .channel[0] = AD5868_CHANNEL(0, 16, 0), - .channel[1] = AD5868_CHANNEL(1, 16, 0), - .channel[2] = AD5868_CHANNEL(2, 16, 0), - .channel[3] = AD5868_CHANNEL(3, 16, 0), + .channels = ad5686_channels, + .num_channels = 4, + }, + [ID_AD5686R] = { + .channels = ad5686_channels, .int_vref_mv = 2500, + .num_channels = 4, + }, + [ID_AD5694] = { + .channels = ad5684_channels, + .num_channels = 4, + }, + [ID_AD5694R] = { + .channels = ad5684_channels, + .int_vref_mv = 2500, + .num_channels = 4, + }, + [ID_AD5696] = { + .channels = ad5686_channels, + .num_channels = 4, + }, + [ID_AD5696R] = { + .channels = ad5686_channels, + .int_vref_mv = 2500, + .num_channels = 4, }, }; - -static int ad5686_probe(struct spi_device *spi) +int ad5686_probe(struct device *dev, + enum ad5686_supported_device_ids chip_type, + const char *name, ad5686_write_func write, + ad5686_read_func read) { struct ad5686_state *st; struct iio_dev *indio_dev; int ret, voltage_uv = 0; - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); + dev_set_drvdata(dev, indio_dev); + + st->dev = dev; + st->write = write; + st->read = read; - st->reg = devm_regulator_get_optional(&spi->dev, "vcc"); + st->reg = devm_regulator_get_optional(dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); if (ret) @@ -334,28 +302,25 @@ static int ad5686_probe(struct spi_device *spi) voltage_uv = ret; } - st->chip_info = - &ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + st->chip_info = &ad5686_chip_info_tbl[chip_type]; if (voltage_uv) st->vref_mv = voltage_uv / 1000; else st->vref_mv = st->chip_info->int_vref_mv; - st->spi = spi; - /* Set all the power down mode for all channels to 1K pulldown */ st->pwr_down_mode = 0x55; - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = dev; + indio_dev->name = name; indio_dev->info = &ad5686_info; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = AD5686_DAC_CHANNELS; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; - ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, - !!voltage_uv, 0); + ret = st->write(st, AD5686_CMD_INTERNAL_REFER_SETUP, + 0, !!voltage_uv); if (ret) goto error_disable_reg; @@ -370,10 +335,11 @@ error_disable_reg: regulator_disable(st->reg); return ret; } +EXPORT_SYMBOL_GPL(ad5686_probe); -static int ad5686_remove(struct spi_device *spi) +int ad5686_remove(struct device *dev) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5686_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); @@ -382,24 +348,7 @@ static int ad5686_remove(struct spi_device *spi) return 0; } - -static const struct spi_device_id ad5686_id[] = { - {"ad5684", ID_AD5684}, - {"ad5685", ID_AD5685}, - {"ad5686", ID_AD5686}, - {} -}; -MODULE_DEVICE_TABLE(spi, ad5686_id); - -static struct spi_driver ad5686_driver = { - .driver = { - .name = "ad5686", - }, - .probe = ad5686_probe, - .remove = ad5686_remove, - .id_table = ad5686_id, -}; -module_spi_driver(ad5686_driver); +EXPORT_SYMBOL_GPL(ad5686_remove); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h new file mode 100644 index 000000000000..05f0ce9d2de1 --- /dev/null +++ b/drivers/iio/dac/ad5686.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * This file is part of AD5686 DAC driver + * + * Copyright 2018 Analog Devices Inc. + */ + +#ifndef __DRIVERS_IIO_DAC_AD5686_H__ +#define __DRIVERS_IIO_DAC_AD5686_H__ + +#include <linux/types.h> +#include <linux/cache.h> +#include <linux/mutex.h> +#include <linux/kernel.h> + +#define AD5686_ADDR(x) ((x) << 16) +#define AD5686_CMD(x) ((x) << 20) + +#define AD5686_ADDR_DAC(chan) (0x1 << (chan)) +#define AD5686_ADDR_ALL_DAC 0xF + +#define AD5686_CMD_NOOP 0x0 +#define AD5686_CMD_WRITE_INPUT_N 0x1 +#define AD5686_CMD_UPDATE_DAC_N 0x2 +#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3 +#define AD5686_CMD_POWERDOWN_DAC 0x4 +#define AD5686_CMD_LDAC_MASK 0x5 +#define AD5686_CMD_RESET 0x6 +#define AD5686_CMD_INTERNAL_REFER_SETUP 0x7 +#define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 +#define AD5686_CMD_READBACK_ENABLE 0x9 + +#define AD5686_LDAC_PWRDN_NONE 0x0 +#define AD5686_LDAC_PWRDN_1K 0x1 +#define AD5686_LDAC_PWRDN_100K 0x2 +#define AD5686_LDAC_PWRDN_3STATE 0x3 + +/** + * ad5686_supported_device_ids: + */ +enum ad5686_supported_device_ids { + ID_AD5671R, + ID_AD5672R, + ID_AD5675R, + ID_AD5676, + ID_AD5676R, + ID_AD5684, + ID_AD5684R, + ID_AD5685R, + ID_AD5686, + ID_AD5686R, + ID_AD5694, + ID_AD5694R, + ID_AD5695R, + ID_AD5696, + ID_AD5696R, +}; + +struct ad5686_state; + +typedef int (*ad5686_write_func)(struct ad5686_state *st, + u8 cmd, u8 addr, u16 val); + +typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr); + +/** + * struct ad5686_chip_info - chip specific information + * @int_vref_mv: AD5620/40/60: the internal reference voltage + * @num_channels: number of channels + * @channel: channel specification + */ + +struct ad5686_chip_info { + u16 int_vref_mv; + unsigned int num_channels; + struct iio_chan_spec *channels; +}; + +/** + * struct ad5446_state - driver instance specific data + * @spi: spi_device + * @chip_info: chip model specific constants, available modes etc + * @reg: supply regulator + * @vref_mv: actual reference voltage used + * @pwr_down_mask: power down mask + * @pwr_down_mode: current power down mode + * @data: spi transfer buffers + */ + +struct ad5686_state { + struct device *dev; + const struct ad5686_chip_info *chip_info; + struct regulator *reg; + unsigned short vref_mv; + unsigned int pwr_down_mask; + unsigned int pwr_down_mode; + ad5686_write_func write; + ad5686_read_func read; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + + union { + __be32 d32; + __be16 d16; + u8 d8[4]; + } data[3] ____cacheline_aligned; +}; + + +int ad5686_probe(struct device *dev, + enum ad5686_supported_device_ids chip_type, + const char *name, ad5686_write_func write, + ad5686_read_func read); + +int ad5686_remove(struct device *dev); + + +#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */ diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c new file mode 100644 index 000000000000..275e0321bcf8 --- /dev/null +++ b/drivers/iio/dac/ad5696-i2c.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * AD5671R, AD5675R, AD5694, AD5694R, AD5695R, AD5696, AD5696R + * Digital to analog converters driver + * + * Copyright 2018 Analog Devices Inc. + */ + +#include "ad5686.h" + +#include <linux/module.h> +#include <linux/i2c.h> + +static int ad5686_i2c_read(struct ad5686_state *st, u8 addr) +{ + struct i2c_client *i2c = to_i2c_client(st->dev); + struct i2c_msg msg[2] = { + { + .addr = i2c->addr, + .flags = i2c->flags, + .len = 3, + .buf = &st->data[0].d8[1], + }, + { + .addr = i2c->addr, + .flags = i2c->flags | I2C_M_RD, + .len = 2, + .buf = (char *)&st->data[0].d16, + }, + }; + int ret; + + st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) | + AD5686_ADDR(addr) | + 0x00); + + ret = i2c_transfer(i2c->adapter, msg, 2); + if (ret < 0) + return ret; + + return be16_to_cpu(st->data[0].d16); +} + +static int ad5686_i2c_write(struct ad5686_state *st, + u8 cmd, u8 addr, u16 val) +{ + struct i2c_client *i2c = to_i2c_client(st->dev); + int ret; + + st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr) + | val); + + ret = i2c_master_send(i2c, &st->data[0].d8[1], 3); + if (ret < 0) + return ret; + + return (ret != 3) ? -EIO : 0; +} + +static int ad5686_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return ad5686_probe(&i2c->dev, id->driver_data, id->name, + ad5686_i2c_write, ad5686_i2c_read); +} + +static int ad5686_i2c_remove(struct i2c_client *i2c) +{ + return ad5686_remove(&i2c->dev); +} + +static const struct i2c_device_id ad5686_i2c_id[] = { + {"ad5671r", ID_AD5671R}, + {"ad5675r", ID_AD5675R}, + {"ad5694", ID_AD5694}, + {"ad5694r", ID_AD5694R}, + {"ad5695r", ID_AD5695R}, + {"ad5696", ID_AD5696}, + {"ad5696r", ID_AD5696R}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); + +static struct i2c_driver ad5686_i2c_driver = { + .driver = { + .name = "ad5696", + }, + .probe = ad5686_i2c_probe, + .remove = ad5686_i2c_remove, + .id_table = ad5686_i2c_id, +}; + +module_i2c_driver(ad5686_i2c_driver); + +MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c new file mode 100644 index 000000000000..dd21eebed6a8 --- /dev/null +++ b/drivers/iio/dac/ti-dac5571.c @@ -0,0 +1,439 @@ +/* + * ti-dac5571.c - Texas Instruments 8/10/12-bit 1/4-channel DAC driver + * + * Copyright (C) 2018 Prevas A/S + * + * http://www.ti.com/lit/ds/symlink/dac5571.pdf + * http://www.ti.com/lit/ds/symlink/dac6571.pdf + * http://www.ti.com/lit/ds/symlink/dac7571.pdf + * http://www.ti.com/lit/ds/symlink/dac5574.pdf + * http://www.ti.com/lit/ds/symlink/dac6574.pdf + * http://www.ti.com/lit/ds/symlink/dac7574.pdf + * http://www.ti.com/lit/ds/symlink/dac5573.pdf + * http://www.ti.com/lit/ds/symlink/dac6573.pdf + * http://www.ti.com/lit/ds/symlink/dac7573.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (version 2) as + * published by the Free Software Foundation. + */ + +#include <linux/iio/iio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> + +enum chip_id { + single_8bit, single_10bit, single_12bit, + quad_8bit, quad_10bit, quad_12bit +}; + +struct dac5571_spec { + u8 num_channels; + u8 resolution; +}; + +static const struct dac5571_spec dac5571_spec[] = { + [single_8bit] = {.num_channels = 1, .resolution = 8}, + [single_10bit] = {.num_channels = 1, .resolution = 10}, + [single_12bit] = {.num_channels = 1, .resolution = 12}, + [quad_8bit] = {.num_channels = 4, .resolution = 8}, + [quad_10bit] = {.num_channels = 4, .resolution = 10}, + [quad_12bit] = {.num_channels = 4, .resolution = 12}, +}; + +struct dac5571_data { + struct i2c_client *client; + int id; + struct mutex lock; + struct regulator *vref; + u16 val[4]; + bool powerdown; + u8 powerdown_mode; + struct dac5571_spec const *spec; + int (*dac5571_cmd)(struct dac5571_data *data, int channel, u16 val); + int (*dac5571_pwrdwn)(struct dac5571_data *data, int channel, u8 pwrdwn); + u8 buf[3] ____cacheline_aligned; +}; + +#define DAC5571_POWERDOWN(mode) ((mode) + 1) +#define DAC5571_POWERDOWN_FLAG BIT(0) +#define DAC5571_CHANNEL_SELECT 1 +#define DAC5571_LOADMODE_DIRECT BIT(4) +#define DAC5571_SINGLE_PWRDWN_BITS 4 +#define DAC5571_QUAD_PWRDWN_BITS 6 + +static int dac5571_cmd_single(struct dac5571_data *data, int channel, u16 val) +{ + unsigned int shift; + + shift = 12 - data->spec->resolution; + data->buf[1] = val << shift; + data->buf[0] = val >> (8 - shift); + + if (i2c_master_send(data->client, data->buf, 2) != 2) + return -EIO; + + return 0; +} + +static int dac5571_cmd_quad(struct dac5571_data *data, int channel, u16 val) +{ + unsigned int shift; + + shift = 16 - data->spec->resolution; + data->buf[2] = val << shift; + data->buf[1] = (val >> (8 - shift)); + data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | + DAC5571_LOADMODE_DIRECT; + + if (i2c_master_send(data->client, data->buf, 3) != 3) + return -EIO; + + return 0; +} + +static int dac5571_pwrdwn_single(struct dac5571_data *data, int channel, u8 pwrdwn) +{ + unsigned int shift; + + shift = 12 - data->spec->resolution; + data->buf[1] = 0; + data->buf[0] = pwrdwn << DAC5571_SINGLE_PWRDWN_BITS; + + if (i2c_master_send(data->client, data->buf, 2) != 2) + return -EIO; + + return 0; +} + +static int dac5571_pwrdwn_quad(struct dac5571_data *data, int channel, u8 pwrdwn) +{ + unsigned int shift; + + shift = 16 - data->spec->resolution; + data->buf[2] = 0; + data->buf[1] = pwrdwn << DAC5571_QUAD_PWRDWN_BITS; + data->buf[0] = (channel << DAC5571_CHANNEL_SELECT) | + DAC5571_LOADMODE_DIRECT | DAC5571_POWERDOWN_FLAG; + + if (i2c_master_send(data->client, data->buf, 3) != 3) + return -EIO; + + return 0; +} + +static const char *const dac5571_powerdown_modes[] = { + "1kohm_to_gnd", "100kohm_to_gnd", "three_state", +}; + +static int dac5571_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct dac5571_data *data = iio_priv(indio_dev); + + return data->powerdown_mode; +} + +static int dac5571_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct dac5571_data *data = iio_priv(indio_dev); + int ret = 0; + + if (data->powerdown_mode == mode) + return 0; + + mutex_lock(&data->lock); + if (data->powerdown) { + ret = data->dac5571_pwrdwn(data, chan->channel, + DAC5571_POWERDOWN(mode)); + if (ret) + goto out; + } + data->powerdown_mode = mode; + + out: + mutex_unlock(&data->lock); + + return ret; +} + +static const struct iio_enum dac5571_powerdown_mode = { + .items = dac5571_powerdown_modes, + .num_items = ARRAY_SIZE(dac5571_powerdown_modes), + .get = dac5571_get_powerdown_mode, + .set = dac5571_set_powerdown_mode, +}; + +static ssize_t dac5571_read_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct dac5571_data *data = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", data->powerdown); +} + +static ssize_t dac5571_write_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct dac5571_data *data = iio_priv(indio_dev); + bool powerdown; + int ret; + + ret = strtobool(buf, &powerdown); + if (ret) + return ret; + + if (data->powerdown == powerdown) + return len; + + mutex_lock(&data->lock); + if (powerdown) + ret = data->dac5571_pwrdwn(data, chan->channel, + DAC5571_POWERDOWN(data->powerdown_mode)); + else + ret = data->dac5571_cmd(data, chan->channel, data->val[0]); + if (ret) + goto out; + + data->powerdown = powerdown; + + out: + mutex_unlock(&data->lock); + + return ret ? ret : len; +} + + +static const struct iio_chan_spec_ext_info dac5571_ext_info[] = { + { + .name = "powerdown", + .read = dac5571_read_powerdown, + .write = dac5571_write_powerdown, + .shared = IIO_SHARED_BY_TYPE, + }, + IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &dac5571_powerdown_mode), + IIO_ENUM_AVAILABLE("powerdown_mode", &dac5571_powerdown_mode), + {}, +}; + +#define dac5571_CHANNEL(chan, name) { \ + .type = IIO_VOLTAGE, \ + .channel = (chan), \ + .address = (chan), \ + .indexed = true, \ + .output = true, \ + .datasheet_name = name, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = dac5571_ext_info, \ +} + +static const struct iio_chan_spec dac5571_channels[] = { + dac5571_CHANNEL(0, "A"), + dac5571_CHANNEL(1, "B"), + dac5571_CHANNEL(2, "C"), + dac5571_CHANNEL(3, "D"), +}; + +static int dac5571_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct dac5571_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = data->val[chan->channel]; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(data->vref); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = data->spec->resolution; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } +} + +static int dac5571_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct dac5571_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (data->val[chan->channel] == val) + return 0; + + if (val >= (1 << data->spec->resolution) || val < 0) + return -EINVAL; + + if (data->powerdown) + return -EBUSY; + + mutex_lock(&data->lock); + ret = data->dac5571_cmd(data, chan->channel, val); + if (ret == 0) + data->val[chan->channel] = val; + mutex_unlock(&data->lock); + return ret; + + default: + return -EINVAL; + } +} + +static int dac5571_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT; +} + +static const struct iio_info dac5571_info = { + .read_raw = dac5571_read_raw, + .write_raw = dac5571_write_raw, + .write_raw_get_fmt = dac5571_write_raw_get_fmt, +}; + +static int dac5571_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + const struct dac5571_spec *spec; + struct dac5571_data *data; + struct iio_dev *indio_dev; + int ret, i; + + indio_dev = devm_iio_device_alloc(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 = dev; + indio_dev->dev.of_node = client->dev.of_node; + indio_dev->info = &dac5571_info; + indio_dev->name = id->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = dac5571_channels; + + spec = &dac5571_spec[id->driver_data]; + indio_dev->num_channels = spec->num_channels; + data->spec = spec; + + data->vref = devm_regulator_get(dev, "vref"); + if (IS_ERR(data->vref)) + return PTR_ERR(data->vref); + + ret = regulator_enable(data->vref); + if (ret < 0) + return ret; + + mutex_init(&data->lock); + + switch (spec->num_channels) { + case 1: + data->dac5571_cmd = dac5571_cmd_single; + data->dac5571_pwrdwn = dac5571_pwrdwn_single; + break; + case 4: + data->dac5571_cmd = dac5571_cmd_quad; + data->dac5571_pwrdwn = dac5571_pwrdwn_quad; + break; + default: + goto err; + } + + for (i = 0; i < spec->num_channels; i++) { + ret = data->dac5571_cmd(data, i, 0); + if (ret) { + dev_err(dev, "failed to initialize channel %d to 0\n", i); + goto err; + } + } + + ret = iio_device_register(indio_dev); + if (ret) + goto err; + + return 0; + + err: + regulator_disable(data->vref); + return ret; +} + +static int dac5571_remove(struct i2c_client *i2c) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(i2c); + struct dac5571_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(data->vref); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id dac5571_of_id[] = { + {.compatible = "ti,dac5571"}, + {.compatible = "ti,dac6571"}, + {.compatible = "ti,dac7571"}, + {.compatible = "ti,dac5574"}, + {.compatible = "ti,dac6574"}, + {.compatible = "ti,dac7574"}, + {.compatible = "ti,dac5573"}, + {.compatible = "ti,dac6573"}, + {.compatible = "ti,dac7573"}, + {} +}; +MODULE_DEVICE_TABLE(of, dac5571_of_id); +#endif + +static const struct i2c_device_id dac5571_id[] = { + {"dac5571", single_8bit}, + {"dac6571", single_10bit}, + {"dac7571", single_12bit}, + {"dac5574", quad_8bit}, + {"dac6574", quad_10bit}, + {"dac7574", quad_12bit}, + {"dac5573", quad_8bit}, + {"dac6573", quad_10bit}, + {"dac7573", quad_12bit}, + {} +}; +MODULE_DEVICE_TABLE(i2c, dac5571_id); + +static struct i2c_driver dac5571_driver = { + .driver = { + .name = "ti-dac5571", + }, + .probe = dac5571_probe, + .remove = dac5571_remove, + .id_table = dac5571_id, +}; +module_i2c_driver(dac5571_driver); + +MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>"); +MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1/4-channel DAC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 7d64be353403..43fba5f7532b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/iio/iio.h> #include <linux/acpi.h> +#include <linux/platform_device.h> #include "inv_mpu_iio.h" /* @@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = { .raw_accl = INV_MPU6050_REG_RAW_ACCEL, .temperature = INV_MPU6050_REG_TEMPERATURE, .int_enable = INV_MPU6050_REG_INT_ENABLE, + .int_status = INV_MPU6050_REG_INT_STATUS, .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, @@ -86,6 +88,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = { .gyro_fifo_enable = false, .accl_fifo_enable = false, .accl_fs = INV_MPU6050_FS_02G, + .user_ctrl = 0, }; /* Indexed by enum inv_devices */ @@ -121,6 +124,12 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6050, }, { + .whoami = INV_MPU9255_WHOAMI_VALUE, + .name = "MPU9255", + .reg = ®_set_6500, + .config = &chip_config_6050, + }, + { .whoami = INV_ICM20608_WHOAMI_VALUE, .name = "ICM20608", .reg = ®_set_6500, @@ -168,7 +177,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) return result; if (en) { - /* Wait for output stabilize */ + /* Wait for output to stabilize */ msleep(INV_MPU6050_TEMP_UP_TIME); if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { /* switch internal clock to PLL */ @@ -185,26 +194,29 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) { - int result = 0; + int result; if (power_on) { - if (!st->powerup_count) + if (!st->powerup_count) { result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); - if (!result) - st->powerup_count++; + if (result) + return result; + usleep_range(INV_MPU6050_REG_UP_TIME_MIN, + INV_MPU6050_REG_UP_TIME_MAX); + } + st->powerup_count++; } else { - st->powerup_count--; - if (!st->powerup_count) + if (st->powerup_count == 1) { result = regmap_write(st->map, st->reg->pwr_mgmt_1, INV_MPU6050_BIT_SLEEP); + if (result) + return result; + } + st->powerup_count--; } - if (result) - return result; - - if (power_on) - usleep_range(INV_MPU6050_REG_UP_TIME_MIN, - INV_MPU6050_REG_UP_TIME_MAX); + dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n", + power_on, st->powerup_count); return 0; } @@ -262,26 +274,33 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); result = regmap_write(st->map, st->reg->gyro_config, d); if (result) - return result; + goto error_power_off; result = inv_mpu6050_set_lpf_regs(st, INV_MPU6050_FILTER_20HZ); if (result) - return result; + goto error_power_off; d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) - return result; + goto error_power_off; d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); result = regmap_write(st->map, st->reg->accl_config, d); if (result) + goto error_power_off; + + result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); + if (result) return result; memcpy(&st->chip_config, hw_info[st->chip_type].config, sizeof(struct inv_mpu6050_chip_config)); - result = inv_mpu6050_set_power_itg(st, false); + return inv_mpu6050_set_power_itg(st, false); + +error_power_off: + inv_mpu6050_set_power_itg(st, false); return result; } @@ -314,6 +333,65 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, return IIO_VAL_INT; } +static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + int ret; + + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + + switch (chan->type) { + case IIO_ANGL_VEL: + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_power_off; + ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, + chan->channel2, val); + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_power_off; + break; + case IIO_ACCEL: + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_power_off; + ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, + chan->channel2, val); + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_power_off; + break; + case IIO_TEMP: + /* wait for stablization */ + msleep(INV_MPU6050_SENSOR_UP_TIME); + ret = inv_mpu6050_sensor_show(st, st->reg->temperature, + IIO_MOD_X, val); + break; + default: + ret = -EINVAL; + break; + } + + result = inv_mpu6050_set_power_itg(st, false); + if (result) + goto error_power_off; + + return ret; + +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; +} + static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -324,63 +402,14 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - { - int result; - - ret = IIO_VAL_INT; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; mutex_lock(&st->lock); - result = iio_device_claim_direct_mode(indio_dev); - if (result) - goto error_read_raw_unlock; - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto error_read_raw_release; - switch (chan->type) { - case IIO_ANGL_VEL: - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw_power_off; - ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, - chan->channel2, val); - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw_power_off; - break; - case IIO_ACCEL: - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw_power_off; - ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, - chan->channel2, val); - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw_power_off; - break; - case IIO_TEMP: - /* wait for stablization */ - msleep(INV_MPU6050_SENSOR_UP_TIME); - ret = inv_mpu6050_sensor_show(st, st->reg->temperature, - IIO_MOD_X, val); - break; - default: - ret = -EINVAL; - break; - } -error_read_raw_power_off: - result |= inv_mpu6050_set_power_itg(st, false); -error_read_raw_release: - iio_device_release_direct_mode(indio_dev); -error_read_raw_unlock: + ret = inv_mpu6050_read_channel_data(indio_dev, chan, val); mutex_unlock(&st->lock); - if (result) - return result; - + iio_device_release_direct_mode(indio_dev); return ret; - } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: @@ -502,17 +531,18 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, struct inv_mpu6050_state *st = iio_priv(indio_dev); int result; - mutex_lock(&st->lock); /* * we should only update scale when the chip is disabled, i.e. * not running */ result = iio_device_claim_direct_mode(indio_dev); if (result) - goto error_write_raw_unlock; + return result; + + mutex_lock(&st->lock); result = inv_mpu6050_set_power_itg(st, true); if (result) - goto error_write_raw_release; + goto error_write_raw_unlock; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -551,10 +581,9 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, } result |= inv_mpu6050_set_power_itg(st, false); -error_write_raw_release: - iio_device_release_direct_mode(indio_dev); error_write_raw_unlock: mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); return result; } @@ -613,17 +642,18 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, fifo_rate > INV_MPU6050_MAX_FIFO_RATE) return -EINVAL; + result = iio_device_claim_direct_mode(indio_dev); + if (result) + return result; + mutex_lock(&st->lock); if (fifo_rate == st->chip_config.fifo_rate) { result = 0; goto fifo_rate_fail_unlock; } - result = iio_device_claim_direct_mode(indio_dev); - if (result) - goto fifo_rate_fail_unlock; result = inv_mpu6050_set_power_itg(st, true); if (result) - goto fifo_rate_fail_release; + goto fifo_rate_fail_unlock; d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; result = regmap_write(st->map, st->reg->sample_rate_div, d); @@ -637,10 +667,9 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, fifo_rate_fail_power_off: result |= inv_mpu6050_set_power_itg(st, false); -fifo_rate_fail_release: - iio_device_release_direct_mode(indio_dev); fifo_rate_fail_unlock: mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); if (result) return result; @@ -850,14 +879,11 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) msleep(INV_MPU6050_POWER_UP_TIME); /* - * toggle power state. After reset, the sleep bit could be on - * or off depending on the OTP settings. Toggling power would + * Turn power on. After reset, the sleep bit could be on + * or off depending on the OTP settings. Turning power on * make it in a definite state as well as making the hardware * state align with the software state */ - result = inv_mpu6050_set_power_itg(st, false); - if (result) - return result; result = inv_mpu6050_set_power_itg(st, true); if (result) return result; @@ -865,13 +891,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_power_off; result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_power_off; - return 0; + return inv_mpu6050_set_power_itg(st, false); + +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; } int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, @@ -882,6 +912,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, struct inv_mpu6050_platform_data *pdata; struct device *dev = regmap_get_device(regmap); int result; + struct irq_data *desc; + int irq_type; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) @@ -913,20 +945,43 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, st->plat_data = *pdata; } + desc = irq_get_irq_data(irq); + if (!desc) { + dev_err(dev, "Could not find IRQ %d\n", irq); + return -EINVAL; + } + + irq_type = irqd_get_trigger_type(desc); + if (irq_type == IRQF_TRIGGER_RISING) + st->irq_mask = INV_MPU6050_ACTIVE_HIGH; + else if (irq_type == IRQF_TRIGGER_FALLING) + st->irq_mask = INV_MPU6050_ACTIVE_LOW; + else if (irq_type == IRQF_TRIGGER_HIGH) + st->irq_mask = INV_MPU6050_ACTIVE_HIGH | + INV_MPU6050_LATCH_INT_EN; + else if (irq_type == IRQF_TRIGGER_LOW) + st->irq_mask = INV_MPU6050_ACTIVE_LOW | + INV_MPU6050_LATCH_INT_EN; + else { + dev_err(dev, "Invalid interrupt type 0x%x specified\n", + irq_type); + return -EINVAL; + } + /* power is turned on inside check chip type*/ result = inv_check_and_setup_chip(st); if (result) return result; - if (inv_mpu_bus_setup) - inv_mpu_bus_setup(indio_dev); - result = inv_mpu6050_init_config(indio_dev); if (result) { dev_err(dev, "Could not initialize device.\n"); return result; } + if (inv_mpu_bus_setup) + inv_mpu_bus_setup(indio_dev); + dev_set_drvdata(dev, indio_dev); indio_dev->dev.parent = dev; /* name will be NULL when enumerated via ACPI */ @@ -940,50 +995,32 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, indio_dev->info = &mpu_info; indio_dev->modes = INDIO_BUFFER_TRIGGERED; - result = iio_triggered_buffer_setup(indio_dev, - inv_mpu6050_irq_handler, - inv_mpu6050_read_fifo, - NULL); + result = devm_iio_triggered_buffer_setup(dev, indio_dev, + inv_mpu6050_irq_handler, + inv_mpu6050_read_fifo, + NULL); if (result) { dev_err(dev, "configure buffer fail %d\n", result); return result; } - result = inv_mpu6050_probe_trigger(indio_dev); + result = inv_mpu6050_probe_trigger(indio_dev, irq_type); if (result) { dev_err(dev, "trigger probe fail %d\n", result); - goto out_unreg_ring; + return result; } INIT_KFIFO(st->timestamps); spin_lock_init(&st->time_stamp_lock); - result = iio_device_register(indio_dev); + result = devm_iio_device_register(dev, indio_dev); if (result) { dev_err(dev, "IIO register fail %d\n", result); - goto out_remove_trigger; + return result; } return 0; - -out_remove_trigger: - inv_mpu6050_remove_trigger(st); -out_unreg_ring: - iio_triggered_buffer_cleanup(indio_dev); - return result; } EXPORT_SYMBOL_GPL(inv_mpu_core_probe); -int inv_mpu_core_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - - iio_device_unregister(indio_dev); - inv_mpu6050_remove_trigger(iio_priv(indio_dev)); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; -} -EXPORT_SYMBOL_GPL(inv_mpu_core_remove); - #ifdef CONFIG_PM_SLEEP static int inv_mpu_resume(struct device *dev) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index fcd7a92b6cf8..495409d56207 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -29,25 +29,18 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id) { struct iio_dev *indio_dev = i2c_mux_priv(muxc); struct inv_mpu6050_state *st = iio_priv(indio_dev); - int ret = 0; + int ret; - /* Use the same mutex which was used everywhere to protect power-op */ mutex_lock(&st->lock); - if (!st->powerup_count) { - ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); - if (ret) - goto write_error; - usleep_range(INV_MPU6050_REG_UP_TIME_MIN, - INV_MPU6050_REG_UP_TIME_MAX); - } - if (!ret) { - st->powerup_count++; - ret = regmap_write(st->map, st->reg->int_pin_cfg, - INV_MPU6050_INT_PIN_CFG | - INV_MPU6050_BIT_BYPASS_EN); - } -write_error: + ret = inv_mpu6050_set_power_itg(st, true); + if (ret) + goto error_unlock; + + ret = regmap_write(st->map, st->reg->int_pin_cfg, + st->irq_mask | INV_MPU6050_BIT_BYPASS_EN); + +error_unlock: mutex_unlock(&st->lock); return ret; @@ -59,12 +52,11 @@ static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id) struct inv_mpu6050_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); - /* It doesn't really mattter, if any of the calls fails */ - regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG); - st->powerup_count--; - if (!st->powerup_count) - regmap_write(st->map, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_SLEEP); + + /* It doesn't really matter if any of the calls fail */ + regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); + inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&st->lock); return 0; @@ -133,29 +125,32 @@ static int inv_mpu_probe(struct i2c_client *client, return result; st = iio_priv(dev_get_drvdata(&client->dev)); - st->muxc = i2c_mux_alloc(client->adapter, &client->dev, - 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, - inv_mpu6050_select_bypass, - inv_mpu6050_deselect_bypass); - if (!st->muxc) { - result = -ENOMEM; - goto out_unreg_device; + switch (st->chip_type) { + case INV_ICM20608: + /* no i2c auxiliary bus on the chip */ + break; + default: + /* declare i2c auxiliary bus */ + st->muxc = i2c_mux_alloc(client->adapter, &client->dev, + 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, + inv_mpu6050_select_bypass, + inv_mpu6050_deselect_bypass); + if (!st->muxc) + return -ENOMEM; + st->muxc->priv = dev_get_drvdata(&client->dev); + result = i2c_mux_add_adapter(st->muxc, 0, 0, 0); + if (result) + return result; + result = inv_mpu_acpi_create_mux_client(client); + if (result) + goto out_del_mux; + break; } - st->muxc->priv = dev_get_drvdata(&client->dev); - result = i2c_mux_add_adapter(st->muxc, 0, 0, 0); - if (result) - goto out_unreg_device; - - result = inv_mpu_acpi_create_mux_client(client); - if (result) - goto out_del_mux; return 0; out_del_mux: i2c_mux_del_adapters(st->muxc); -out_unreg_device: - inv_mpu_core_remove(&client->dev); return result; } @@ -164,10 +159,12 @@ static int inv_mpu_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct inv_mpu6050_state *st = iio_priv(indio_dev); - inv_mpu_acpi_delete_mux_client(client); - i2c_mux_del_adapters(st->muxc); + if (st->muxc) { + inv_mpu_acpi_delete_mux_client(client); + i2c_mux_del_adapters(st->muxc); + } - return inv_mpu_core_remove(&client->dev); + return 0; } /* @@ -179,6 +176,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, {"mpu9250", INV_MPU9250}, + {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, {} }; @@ -203,6 +201,10 @@ static const struct of_device_id inv_of_match[] = { .data = (void *)INV_MPU9250 }, { + .compatible = "invensense,mpu9255", + .data = (void *)INV_MPU9255 + }, + { .compatible = "invensense,icm20608", .data = (void *)INV_ICM20608 }, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 065794162d65..c54da777945d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -40,6 +40,7 @@ * @raw_accl: Address of first accel register. * @temperature: temperature register * @int_enable: Interrupt enable register. + * @int_status: Interrupt status register. * @pwr_mgmt_1: Controls chip's power state and clock source. * @pwr_mgmt_2: Controls power state of individual sensors. * @int_pin_cfg; Controls interrupt pin configuration. @@ -60,6 +61,7 @@ struct inv_mpu6050_reg_map { u8 raw_accl; u8 temperature; u8 int_enable; + u8 int_status; u8 pwr_mgmt_1; u8 pwr_mgmt_2; u8 int_pin_cfg; @@ -74,6 +76,7 @@ enum inv_devices { INV_MPU6000, INV_MPU9150, INV_MPU9250, + INV_MPU9255, INV_ICM20608, INV_NUM_PARTS }; @@ -94,6 +97,7 @@ struct inv_mpu6050_chip_config { unsigned int accl_fifo_enable:1; unsigned int gyro_fifo_enable:1; u16 fifo_rate; + u8 user_ctrl; }; /** @@ -125,6 +129,7 @@ struct inv_mpu6050_hw { * @timestamps: kfifo queue to store time stamp. * @map regmap pointer. * @irq interrupt number. + * @irq_mask the int_pin_cfg mask to configure interrupt type. */ struct inv_mpu6050_state { #define TIMESTAMP_FIFO_SIZE 16 @@ -143,6 +148,8 @@ struct inv_mpu6050_state { DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); struct regmap *map; int irq; + u8 irq_mask; + unsigned skip_samples; }; /*register and associated bit definition*/ @@ -166,6 +173,9 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_TEMPERATURE 0x41 #define INV_MPU6050_REG_RAW_GYRO 0x43 +#define INV_MPU6050_REG_INT_STATUS 0x3A +#define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01 + #define INV_MPU6050_REG_USER_CTRL 0x6A #define INV_MPU6050_BIT_FIFO_RST 0x04 #define INV_MPU6050_BIT_DMP_RST 0x08 @@ -215,8 +225,12 @@ struct inv_mpu6050_state { #define INV_MPU6050_OUTPUT_DATA_SIZE 24 #define INV_MPU6050_REG_INT_PIN_CFG 0x37 +#define INV_MPU6050_ACTIVE_HIGH 0x00 +#define INV_MPU6050_ACTIVE_LOW 0x80 +/* enable level triggering */ +#define INV_MPU6050_LATCH_INT_EN 0x20 #define INV_MPU6050_BIT_BYPASS_EN 0x2 -#define INV_MPU6050_INT_PIN_CFG 0 + /* init parameters */ #define INV_MPU6050_INIT_FIFO_RATE 50 @@ -232,6 +246,7 @@ struct inv_mpu6050_state { #define INV_MPU6500_WHOAMI_VALUE 0x70 #define INV_MPU9150_WHOAMI_VALUE 0x68 #define INV_MPU9250_WHOAMI_VALUE 0x71 +#define INV_MPU9255_WHOAMI_VALUE 0x73 #define INV_ICM20608_WHOAMI_VALUE 0xAF /* scan element definition */ @@ -287,8 +302,7 @@ enum inv_mpu6050_clock_sel_e { irqreturn_t inv_mpu6050_irq_handler(int irq, void *p); irqreturn_t inv_mpu6050_read_fifo(int irq, void *p); -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev); -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st); +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type); int inv_reset_fifo(struct iio_dev *indio_dev); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); @@ -297,6 +311,4 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client); void inv_mpu_acpi_delete_mux_client(struct i2c_client *client); int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type); -int inv_mpu_core_remove(struct device *dev); -int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); extern const struct dev_pm_ops inv_mpu_pmops; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index ff81c6aa009d..97d965181635 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -51,13 +51,14 @@ int inv_reset_fifo(struct iio_dev *indio_dev) if (result) goto reset_fifo_fail; /* disable fifo reading */ - result = regmap_write(st->map, st->reg->user_ctrl, 0); + result = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (result) goto reset_fifo_fail; /* reset FIFO*/ - result = regmap_write(st->map, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_RST); + d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST; + result = regmap_write(st->map, st->reg->user_ctrl, d); if (result) goto reset_fifo_fail; @@ -72,9 +73,9 @@ int inv_reset_fifo(struct iio_dev *indio_dev) if (result) return result; } - /* enable FIFO reading and I2C master interface*/ - result = regmap_write(st->map, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_EN); + /* enable FIFO reading */ + d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_EN; + result = regmap_write(st->map, st->reg->user_ctrl, d); if (result) goto reset_fifo_fail; /* enable sensor output to FIFO */ @@ -127,8 +128,23 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; u16 fifo_count; s64 timestamp; + int int_status; mutex_lock(&st->lock); + + /* ack interrupt and check status */ + result = regmap_read(st->map, st->reg->int_status, &int_status); + if (result) { + dev_err(regmap_get_device(st->map), + "failed to ack interrupt\n"); + goto flush_fifo; + } + if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) { + dev_warn(regmap_get_device(st->map), + "spurious interrupt with status 0x%x\n", int_status); + goto end_session; + } + if (!(st->chip_config.accl_fifo_enable | st->chip_config.gyro_fifo_enable)) goto end_session; @@ -140,7 +156,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; /* - * read fifo_count register to know how many bytes inside FIFO + * read fifo_count register to know how many bytes are inside the FIFO * right now */ result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data, @@ -150,7 +166,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) fifo_count = be16_to_cpup((__be16 *)(&data[0])); if (fifo_count < bytes_per_datum) goto end_session; - /* fifo count can't be odd number, if it is odd, reset fifo*/ + /* fifo count can't be an odd number. If it is odd, reset the FIFO. */ if (fifo_count & 1) goto flush_fifo; if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) @@ -170,10 +186,13 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (result == 0) timestamp = 0; - result = iio_push_to_buffers_with_timestamp(indio_dev, data, - timestamp); - if (result) - goto flush_fifo; + /* skip first samples if needed */ + if (st->skip_samples) + st->skip_samples--; + else + iio_push_to_buffers_with_timestamp(indio_dev, data, + timestamp); + fifo_count -= bytes_per_datum; } diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 74506e5ac0db..227f50afff22 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -31,8 +31,9 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_write(st->map, INV_MPU6050_REG_USER_CTRL, - INV_MPU6050_BIT_I2C_IF_DIS); + st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS; + ret = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (ret) { inv_mpu6050_set_power_itg(st, false); return ret; @@ -69,11 +70,6 @@ static int inv_mpu_probe(struct spi_device *spi) inv_mpu_i2c_disable, chip_type); } -static int inv_mpu_remove(struct spi_device *spi) -{ - return inv_mpu_core_remove(&spi->dev); -} - /* * device id table is used to identify what device can be * supported by this driver @@ -83,6 +79,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, {"mpu9250", INV_MPU9250}, + {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, {} }; @@ -97,7 +94,6 @@ MODULE_DEVICE_TABLE(acpi, inv_acpi_match); static struct spi_driver inv_mpu_driver = { .probe = inv_mpu_probe, - .remove = inv_mpu_remove, .id_table = inv_mpu_id, .driver = { .acpi_match_table = ACPI_PTR(inv_acpi_match), diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index f963f9fc98c0..6c3e1652a687 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -49,49 +49,66 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) if (result) return result; inv_scan_query(indio_dev); + st->skip_samples = 0; if (st->chip_config.gyro_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_power_off; + /* gyro first sample is out of specs, skip it */ + st->skip_samples = 1; } if (st->chip_config.accl_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_gyro_off; } result = inv_reset_fifo(indio_dev); if (result) - return result; + goto error_accl_off; } else { result = regmap_write(st->map, st->reg->fifo_en, 0); if (result) - return result; + goto error_accl_off; result = regmap_write(st->map, st->reg->int_enable, 0); if (result) - return result; + goto error_accl_off; - result = regmap_write(st->map, st->reg->user_ctrl, 0); + result = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (result) - return result; + goto error_accl_off; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); + INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_accl_off; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); + INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_gyro_off; + result = inv_mpu6050_set_power_itg(st, false); if (result) - return result; + goto error_power_off; } return 0; + +error_accl_off: + if (st->chip_config.accl_fifo_enable) + inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); +error_gyro_off: + if (st->chip_config.gyro_fifo_enable) + inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; } /** @@ -117,7 +134,7 @@ static const struct iio_trigger_ops inv_mpu_trigger_ops = { .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, }; -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type) { int ret; struct inv_mpu6050_state *st = iio_priv(indio_dev); @@ -131,7 +148,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ret = devm_request_irq(&indio_dev->dev, st->irq, &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, + irq_type, "inv_mpu", st->trig); if (ret) @@ -141,7 +158,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) st->trig->ops = &inv_mpu_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); - ret = iio_trigger_register(st->trig); + ret = devm_iio_trigger_register(&indio_dev->dev, st->trig); if (ret) return ret; @@ -149,8 +166,3 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) return 0; } - -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st) -{ - iio_trigger_unregister(st->trig); -} diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 14f2eb6e9fb7..ccc817e17eb8 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -8,7 +8,8 @@ config IIO_ST_LSM6DSX select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) help Say yes here to build support for STMicroelectronics LSM6DSx imu - sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm + sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, + ism330dlc To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index a3cc7cd97026..edcd838037cd 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -18,12 +18,14 @@ #define ST_LSM6DS3H_DEV_NAME "lsm6ds3h" #define ST_LSM6DSL_DEV_NAME "lsm6dsl" #define ST_LSM6DSM_DEV_NAME "lsm6dsm" +#define ST_ISM330DLC_DEV_NAME "ism330dlc" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, ST_LSM6DS3H_ID, ST_LSM6DSL_ID, ST_LSM6DSM_ID, + ST_ISM330DLC_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 1045e025e92b..4994f920a836 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -1,10 +1,10 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM: The FIFO buffer can be configured - * to store data from gyroscope and accelerometer. Samples are queued - * without any tag according to a specific pattern based on 'FIFO data sets' - * (6 bytes each): + * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be + * configured to store data from gyroscope and accelerometer. Samples are + * queued without any tag according to a specific pattern based on + * 'FIFO data sets' (6 bytes each): * - 1st data set is reserved for gyroscope data * - 2nd data set is reserved for accelerometer data * The FIFO pattern changes depending on the ODRs and decimation factors @@ -276,7 +276,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data, #define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \ sizeof(s64)) + sizeof(s64)) /** - * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine + * st_lsm6dsx_read_fifo() - hw FIFO read routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. * * Read samples from the hw FIFO and push them to IIO buffers. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 8656d72ef4ee..aebbe0ddd8d8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -17,7 +17,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DS3H/LSM6DSL/LSM6DSM: + * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 @@ -252,6 +252,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .id = { [0] = ST_LSM6DSL_ID, [1] = ST_LSM6DSM_ID, + [2] = ST_ISM330DLC_ID, }, .decimator = { [ST_LSM6DSX_ID_ACC] = { @@ -266,11 +267,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fifo_ops = { .fifo_th = { .addr = 0x06, - .mask = GENMASK(11, 0), + .mask = GENMASK(10, 0), }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(11, 0), + .mask = GENMASK(10, 0), }, .th_wl = 3, /* 1LSB = 2B */ }, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 41525dd2aab7..377c4e9997da 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, }, + { + .compatible = "st,ism330dlc", + .data = (void *)ST_ISM330DLC_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -66,6 +70,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, + { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 2c8135834479..fec5c6ce7eb7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, }, + { + .compatible = "st,ism330dlc", + .data = (void *)ST_ISM330DLC_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -66,6 +70,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, + { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index 8e8a0e7f78d1..fd1609e975ab 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> +#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger.h> @@ -29,8 +30,6 @@ #include <linux/slab.h> #include <linux/sysfs.h> -#include "../common/cros_ec_sensors/cros_ec_sensors_core.h" - /* * We only represent one entry for light or proximity. EC is merging different * light sensors to return the what the eye would see. For proximity, we diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c index 601b25d1f387..320a7c929777 100644 --- a/drivers/iio/potentiometer/mcp4018.c +++ b/drivers/iio/potentiometer/mcp4018.c @@ -99,6 +99,23 @@ static const struct iio_info mcp4018_info = { .write_raw = mcp4018_write_raw, }; +static const struct i2c_device_id mcp4018_id[] = { + { "mcp4017-502", MCP4018_502 }, + { "mcp4017-103", MCP4018_103 }, + { "mcp4017-503", MCP4018_503 }, + { "mcp4017-104", MCP4018_104 }, + { "mcp4018-502", MCP4018_502 }, + { "mcp4018-103", MCP4018_103 }, + { "mcp4018-503", MCP4018_503 }, + { "mcp4018-104", MCP4018_104 }, + { "mcp4019-502", MCP4018_502 }, + { "mcp4019-103", MCP4018_103 }, + { "mcp4019-503", MCP4018_503 }, + { "mcp4019-104", MCP4018_104 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mcp4018_id); + #ifdef CONFIG_OF #define MCP4018_COMPATIBLE(of_compatible, cfg) { \ @@ -125,8 +142,7 @@ MODULE_DEVICE_TABLE(of, mcp4018_of_match); #endif -static int mcp4018_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mcp4018_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct mcp4018_data *data; @@ -150,7 +166,7 @@ static int mcp4018_probe(struct i2c_client *client, if (match) data->cfg = of_device_get_match_data(dev); else - data->cfg = &mcp4018_cfg[id->driver_data]; + data->cfg = &mcp4018_cfg[i2c_match_id(mcp4018_id, client)->driver_data]; indio_dev->dev.parent = dev; indio_dev->info = &mcp4018_info; @@ -161,29 +177,12 @@ static int mcp4018_probe(struct i2c_client *client, return devm_iio_device_register(dev, indio_dev); } -static const struct i2c_device_id mcp4018_id[] = { - { "mcp4017-502", MCP4018_502 }, - { "mcp4017-103", MCP4018_103 }, - { "mcp4017-503", MCP4018_503 }, - { "mcp4017-104", MCP4018_104 }, - { "mcp4018-502", MCP4018_502 }, - { "mcp4018-103", MCP4018_103 }, - { "mcp4018-503", MCP4018_503 }, - { "mcp4018-104", MCP4018_104 }, - { "mcp4019-502", MCP4018_502 }, - { "mcp4019-103", MCP4018_103 }, - { "mcp4019-503", MCP4018_503 }, - { "mcp4019-104", MCP4018_104 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, mcp4018_id); - static struct i2c_driver mcp4018_driver = { .driver = { .name = "mcp4018", .of_match_table = of_match_ptr(mcp4018_of_match), }, - .probe = mcp4018_probe, + .probe_new = mcp4018_probe, .id_table = mcp4018_id, }; diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index 114ab876fcc6..df894af6cccb 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -209,6 +209,75 @@ static const struct iio_info mcp4531_info = { .write_raw = mcp4531_write_raw, }; +static const struct i2c_device_id mcp4531_id[] = { + { "mcp4531-502", MCP453x_502 }, + { "mcp4531-103", MCP453x_103 }, + { "mcp4531-503", MCP453x_503 }, + { "mcp4531-104", MCP453x_104 }, + { "mcp4532-502", MCP453x_502 }, + { "mcp4532-103", MCP453x_103 }, + { "mcp4532-503", MCP453x_503 }, + { "mcp4532-104", MCP453x_104 }, + { "mcp4541-502", MCP454x_502 }, + { "mcp4541-103", MCP454x_103 }, + { "mcp4541-503", MCP454x_503 }, + { "mcp4541-104", MCP454x_104 }, + { "mcp4542-502", MCP454x_502 }, + { "mcp4542-103", MCP454x_103 }, + { "mcp4542-503", MCP454x_503 }, + { "mcp4542-104", MCP454x_104 }, + { "mcp4551-502", MCP455x_502 }, + { "mcp4551-103", MCP455x_103 }, + { "mcp4551-503", MCP455x_503 }, + { "mcp4551-104", MCP455x_104 }, + { "mcp4552-502", MCP455x_502 }, + { "mcp4552-103", MCP455x_103 }, + { "mcp4552-503", MCP455x_503 }, + { "mcp4552-104", MCP455x_104 }, + { "mcp4561-502", MCP456x_502 }, + { "mcp4561-103", MCP456x_103 }, + { "mcp4561-503", MCP456x_503 }, + { "mcp4561-104", MCP456x_104 }, + { "mcp4562-502", MCP456x_502 }, + { "mcp4562-103", MCP456x_103 }, + { "mcp4562-503", MCP456x_503 }, + { "mcp4562-104", MCP456x_104 }, + { "mcp4631-502", MCP463x_502 }, + { "mcp4631-103", MCP463x_103 }, + { "mcp4631-503", MCP463x_503 }, + { "mcp4631-104", MCP463x_104 }, + { "mcp4632-502", MCP463x_502 }, + { "mcp4632-103", MCP463x_103 }, + { "mcp4632-503", MCP463x_503 }, + { "mcp4632-104", MCP463x_104 }, + { "mcp4641-502", MCP464x_502 }, + { "mcp4641-103", MCP464x_103 }, + { "mcp4641-503", MCP464x_503 }, + { "mcp4641-104", MCP464x_104 }, + { "mcp4642-502", MCP464x_502 }, + { "mcp4642-103", MCP464x_103 }, + { "mcp4642-503", MCP464x_503 }, + { "mcp4642-104", MCP464x_104 }, + { "mcp4651-502", MCP465x_502 }, + { "mcp4651-103", MCP465x_103 }, + { "mcp4651-503", MCP465x_503 }, + { "mcp4651-104", MCP465x_104 }, + { "mcp4652-502", MCP465x_502 }, + { "mcp4652-103", MCP465x_103 }, + { "mcp4652-503", MCP465x_503 }, + { "mcp4652-104", MCP465x_104 }, + { "mcp4661-502", MCP466x_502 }, + { "mcp4661-103", MCP466x_103 }, + { "mcp4661-503", MCP466x_503 }, + { "mcp4661-104", MCP466x_104 }, + { "mcp4662-502", MCP466x_502 }, + { "mcp4662-103", MCP466x_103 }, + { "mcp4662-503", MCP466x_503 }, + { "mcp4662-104", MCP466x_104 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, mcp4531_id); + #ifdef CONFIG_OF #define MCP4531_COMPATIBLE(of_compatible, cfg) { \ @@ -286,8 +355,7 @@ static const struct of_device_id mcp4531_of_match[] = { MODULE_DEVICE_TABLE(of, mcp4531_of_match); #endif -static int mcp4531_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mcp4531_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct mcp4531_data *data; @@ -311,7 +379,7 @@ static int mcp4531_probe(struct i2c_client *client, if (match) data->cfg = of_device_get_match_data(dev); else - data->cfg = &mcp4531_cfg[id->driver_data]; + data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data]; indio_dev->dev.parent = dev; indio_dev->info = &mcp4531_info; @@ -322,81 +390,12 @@ static int mcp4531_probe(struct i2c_client *client, return devm_iio_device_register(dev, indio_dev); } -static const struct i2c_device_id mcp4531_id[] = { - { "mcp4531-502", MCP453x_502 }, - { "mcp4531-103", MCP453x_103 }, - { "mcp4531-503", MCP453x_503 }, - { "mcp4531-104", MCP453x_104 }, - { "mcp4532-502", MCP453x_502 }, - { "mcp4532-103", MCP453x_103 }, - { "mcp4532-503", MCP453x_503 }, - { "mcp4532-104", MCP453x_104 }, - { "mcp4541-502", MCP454x_502 }, - { "mcp4541-103", MCP454x_103 }, - { "mcp4541-503", MCP454x_503 }, - { "mcp4541-104", MCP454x_104 }, - { "mcp4542-502", MCP454x_502 }, - { "mcp4542-103", MCP454x_103 }, - { "mcp4542-503", MCP454x_503 }, - { "mcp4542-104", MCP454x_104 }, - { "mcp4551-502", MCP455x_502 }, - { "mcp4551-103", MCP455x_103 }, - { "mcp4551-503", MCP455x_503 }, - { "mcp4551-104", MCP455x_104 }, - { "mcp4552-502", MCP455x_502 }, - { "mcp4552-103", MCP455x_103 }, - { "mcp4552-503", MCP455x_503 }, - { "mcp4552-104", MCP455x_104 }, - { "mcp4561-502", MCP456x_502 }, - { "mcp4561-103", MCP456x_103 }, - { "mcp4561-503", MCP456x_503 }, - { "mcp4561-104", MCP456x_104 }, - { "mcp4562-502", MCP456x_502 }, - { "mcp4562-103", MCP456x_103 }, - { "mcp4562-503", MCP456x_503 }, - { "mcp4562-104", MCP456x_104 }, - { "mcp4631-502", MCP463x_502 }, - { "mcp4631-103", MCP463x_103 }, - { "mcp4631-503", MCP463x_503 }, - { "mcp4631-104", MCP463x_104 }, - { "mcp4632-502", MCP463x_502 }, - { "mcp4632-103", MCP463x_103 }, - { "mcp4632-503", MCP463x_503 }, - { "mcp4632-104", MCP463x_104 }, - { "mcp4641-502", MCP464x_502 }, - { "mcp4641-103", MCP464x_103 }, - { "mcp4641-503", MCP464x_503 }, - { "mcp4641-104", MCP464x_104 }, - { "mcp4642-502", MCP464x_502 }, - { "mcp4642-103", MCP464x_103 }, - { "mcp4642-503", MCP464x_503 }, - { "mcp4642-104", MCP464x_104 }, - { "mcp4651-502", MCP465x_502 }, - { "mcp4651-103", MCP465x_103 }, - { "mcp4651-503", MCP465x_503 }, - { "mcp4651-104", MCP465x_104 }, - { "mcp4652-502", MCP465x_502 }, - { "mcp4652-103", MCP465x_103 }, - { "mcp4652-503", MCP465x_503 }, - { "mcp4652-104", MCP465x_104 }, - { "mcp4661-502", MCP466x_502 }, - { "mcp4661-103", MCP466x_103 }, - { "mcp4661-503", MCP466x_503 }, - { "mcp4661-104", MCP466x_104 }, - { "mcp4662-502", MCP466x_502 }, - { "mcp4662-103", MCP466x_103 }, - { "mcp4662-503", MCP466x_503 }, - { "mcp4662-104", MCP466x_104 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, mcp4531_id); - static struct i2c_driver mcp4531_driver = { .driver = { .name = "mcp4531", .of_match_table = of_match_ptr(mcp4531_of_match), }, - .probe = mcp4531_probe, + .probe_new = mcp4531_probe, .id_table = mcp4531_id, }; diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 4599fde4dd25..87c07af9181f 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/iio/buffer.h> +#include <linux/iio/common/cros_ec_sensors_core.h> #include <linux/iio/iio.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger.h> @@ -28,8 +29,6 @@ #include <linux/slab.h> #include <linux/platform_device.h> -#include "../common/cros_ec_sensors/cros_ec_sensors_core.h" - /* * One channel for pressure, the other for timestamp. */ diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index c6b0f5eae7ab..befbbfe911c2 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -3,18 +3,6 @@ # menu "Accelerometers" -config ADIS16201 - tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16201 dual-axis - digital inclinometer and accelerometer. - - To compile this driver as a module, say M here: the module will - be called adis16201. - config ADIS16203 tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer" depends on SPI @@ -27,18 +15,6 @@ config ADIS16203 To compile this driver as a module, say M here: the module will be called adis16203. -config ADIS16209 - tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer - and accelerometer. - - To compile this driver as a module, say M here: the module will be - called adis16209. - config ADIS16240 tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" depends on SPI diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 5d8ad21a0dae..773212e0c859 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -2,7 +2,5 @@ # Makefile for industrial I/O accelerometer drivers # -obj-$(CONFIG_ADIS16201) += adis16201.o obj-$(CONFIG_ADIS16203) += adis16203.o -obj-$(CONFIG_ADIS16209) += adis16209.o obj-$(CONFIG_ADIS16240) += adis16240.o diff --git a/drivers/staging/iio/accel/adis16201.c b/drivers/staging/iio/accel/adis16201.c deleted file mode 100644 index 0fae8aaf1cf4..000000000000 --- a/drivers/staging/iio/accel/adis16201.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <linux/spi/spi.h> -#include <linux/sysfs.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> -#include <linux/iio/imu/adis.h> - -#define ADIS16201_STARTUP_DELAY 220 /* ms */ - -/* Flash memory write count */ -#define ADIS16201_FLASH_CNT 0x00 - -/* Output, power supply */ -#define ADIS16201_SUPPLY_OUT 0x02 - -/* Output, x-axis accelerometer */ -#define ADIS16201_XACCL_OUT 0x04 - -/* Output, y-axis accelerometer */ -#define ADIS16201_YACCL_OUT 0x06 - -/* Output, auxiliary ADC input */ -#define ADIS16201_AUX_ADC 0x08 - -/* Output, temperature */ -#define ADIS16201_TEMP_OUT 0x0A - -/* Output, x-axis inclination */ -#define ADIS16201_XINCL_OUT 0x0C - -/* Output, y-axis inclination */ -#define ADIS16201_YINCL_OUT 0x0E - -/* Calibration, x-axis acceleration offset */ -#define ADIS16201_XACCL_OFFS 0x10 - -/* Calibration, y-axis acceleration offset */ -#define ADIS16201_YACCL_OFFS 0x12 - -/* x-axis acceleration scale factor */ -#define ADIS16201_XACCL_SCALE 0x14 - -/* y-axis acceleration scale factor */ -#define ADIS16201_YACCL_SCALE 0x16 - -/* Calibration, x-axis inclination offset */ -#define ADIS16201_XINCL_OFFS 0x18 - -/* Calibration, y-axis inclination offset */ -#define ADIS16201_YINCL_OFFS 0x1A - -/* x-axis inclination scale factor */ -#define ADIS16201_XINCL_SCALE 0x1C - -/* y-axis inclination scale factor */ -#define ADIS16201_YINCL_SCALE 0x1E - -/* Alarm 1 amplitude threshold */ -#define ADIS16201_ALM_MAG1 0x20 - -/* Alarm 2 amplitude threshold */ -#define ADIS16201_ALM_MAG2 0x22 - -/* Alarm 1, sample period */ -#define ADIS16201_ALM_SMPL1 0x24 - -/* Alarm 2, sample period */ -#define ADIS16201_ALM_SMPL2 0x26 - -/* Alarm control */ -#define ADIS16201_ALM_CTRL 0x28 - -/* Auxiliary DAC data */ -#define ADIS16201_AUX_DAC 0x30 - -/* General-purpose digital input/output control */ -#define ADIS16201_GPIO_CTRL 0x32 - -/* Miscellaneous control */ -#define ADIS16201_MSC_CTRL 0x34 - -/* Internal sample period (rate) control */ -#define ADIS16201_SMPL_PRD 0x36 - -/* Operation, filter configuration */ -#define ADIS16201_AVG_CNT 0x38 - -/* Operation, sleep mode control */ -#define ADIS16201_SLP_CNT 0x3A - -/* Diagnostics, system status register */ -#define ADIS16201_DIAG_STAT 0x3C - -/* Operation, system command register */ -#define ADIS16201_GLOB_CMD 0x3E - -/* MSC_CTRL */ - -/* Self-test enable */ -#define ADIS16201_MSC_CTRL_SELF_TEST_EN BIT(8) - -/* Data-ready enable: 1 = enabled, 0 = disabled */ -#define ADIS16201_MSC_CTRL_DATA_RDY_EN BIT(2) - -/* Data-ready polarity: 1 = active high, 0 = active low */ -#define ADIS16201_MSC_CTRL_ACTIVE_HIGH BIT(1) - -/* Data-ready line selection: 1 = DIO1, 0 = DIO0 */ -#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1 BIT(0) - -/* DIAG_STAT */ - -/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM2 BIT(9) - -/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */ -#define ADIS16201_DIAG_STAT_ALARM1 BIT(8) - -/* SPI communications failure */ -#define ADIS16201_DIAG_STAT_SPI_FAIL_BIT 3 - -/* Flash update failure */ -#define ADIS16201_DIAG_STAT_FLASH_UPT_BIT 2 - -/* Power supply above 3.625 V */ -#define ADIS16201_DIAG_STAT_POWER_HIGH_BIT 1 - -/* Power supply below 3.15 V */ -#define ADIS16201_DIAG_STAT_POWER_LOW_BIT 0 - -/* GLOB_CMD */ - -#define ADIS16201_GLOB_CMD_SW_RESET BIT(7) -#define ADIS16201_GLOB_CMD_FACTORY_CAL BIT(1) - -#define ADIS16201_ERROR_ACTIVE BIT(14) - -enum adis16201_scan { - ADIS16201_SCAN_ACC_X, - ADIS16201_SCAN_ACC_Y, - ADIS16201_SCAN_INCLI_X, - ADIS16201_SCAN_INCLI_Y, - ADIS16201_SCAN_SUPPLY, - ADIS16201_SCAN_AUX_ADC, - ADIS16201_SCAN_TEMP, -}; - -static const u8 adis16201_addresses[] = { - [ADIS16201_SCAN_ACC_X] = ADIS16201_XACCL_OFFS, - [ADIS16201_SCAN_ACC_Y] = ADIS16201_YACCL_OFFS, - [ADIS16201_SCAN_INCLI_X] = ADIS16201_XINCL_OFFS, - [ADIS16201_SCAN_INCLI_Y] = ADIS16201_YINCL_OFFS, -}; - -static int adis16201_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int ret; - int bits; - u8 addr; - s16 val16; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - return adis_single_conversion(indio_dev, chan, - ADIS16201_ERROR_ACTIVE, val); - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->channel == 0) { - *val = 1; - *val2 = 220000; /* 1.22 mV */ - } else { - *val = 0; - *val2 = 610000; /* 0.610 mV */ - } - return IIO_VAL_INT_PLUS_MICRO; - case IIO_TEMP: - *val = -470; /* 0.47 C */ - *val2 = 0; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(462400); /* 0.4624 mg */ - return IIO_VAL_INT_PLUS_NANO; - case IIO_INCLI: - *val = 0; - *val2 = 100000; /* 0.1 degree */ - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_OFFSET: - *val = 25000 / -470 - 1278; /* 25 C = 1278 */ - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - bits = 12; - break; - case IIO_INCLI: - bits = 9; - break; - default: - return -EINVAL; - } - addr = adis16201_addresses[chan->scan_index]; - ret = adis_read_reg_16(st, addr, &val16); - if (ret) - return ret; - val16 &= (1 << bits) - 1; - val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); - *val = val16; - return IIO_VAL_INT; - } - - return -EINVAL; -} - -static int adis16201_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct adis *st = iio_priv(indio_dev); - int bits; - s16 val16; - u8 addr; - - switch (mask) { - case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->type) { - case IIO_ACCEL: - bits = 12; - break; - case IIO_INCLI: - bits = 9; - break; - default: - return -EINVAL; - } - val16 = val & ((1 << bits) - 1); - addr = adis16201_addresses[chan->scan_index]; - return adis_write_reg_16(st, addr, val16); - } - - return -EINVAL; -} - -static const struct iio_chan_spec adis16201_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12), - ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12), - ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_AUX_ADC_CHAN(ADIS16201_AUX_ADC, ADIS16201_SCAN_AUX_ADC, 0, 12), - ADIS_INCLI_CHAN(X, ADIS16201_XINCL_OUT, ADIS16201_SCAN_INCLI_X, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - ADIS_INCLI_CHAN(X, ADIS16201_YINCL_OUT, ADIS16201_SCAN_INCLI_Y, - BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), - IIO_CHAN_SOFT_TIMESTAMP(7) -}; - -static const struct iio_info adis16201_info = { - .read_raw = adis16201_read_raw, - .write_raw = adis16201_write_raw, - .update_scan_mode = adis_update_scan_mode, -}; - -static const char * const adis16201_status_error_msgs[] = { - [ADIS16201_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure", - [ADIS16201_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed", - [ADIS16201_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V", - [ADIS16201_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V", -}; - -static const struct adis_data adis16201_data = { - .read_delay = 20, - .msc_ctrl_reg = ADIS16201_MSC_CTRL, - .glob_cmd_reg = ADIS16201_GLOB_CMD, - .diag_stat_reg = ADIS16201_DIAG_STAT, - - .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN, - .self_test_no_autoclear = true, - .startup_delay = ADIS16201_STARTUP_DELAY, - - .status_error_msgs = adis16201_status_error_msgs, - .status_error_mask = BIT(ADIS16201_DIAG_STAT_SPI_FAIL_BIT) | - BIT(ADIS16201_DIAG_STAT_FLASH_UPT_BIT) | - BIT(ADIS16201_DIAG_STAT_POWER_HIGH_BIT) | - BIT(ADIS16201_DIAG_STAT_POWER_LOW_BIT), -}; - -static int adis16201_probe(struct spi_device *spi) -{ - int ret; - struct adis *st; - struct iio_dev *indio_dev; - - /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!indio_dev) - return -ENOMEM; - - st = iio_priv(indio_dev); - /* this is only used for removal purposes */ - spi_set_drvdata(spi, indio_dev); - - indio_dev->name = spi->dev.driver->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->info = &adis16201_info; - - indio_dev->channels = adis16201_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16201_channels); - indio_dev->modes = INDIO_DIRECT_MODE; - - ret = adis_init(st, indio_dev, spi, &adis16201_data); - if (ret) - return ret; - - ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL); - if (ret) - return ret; - - /* Get the device into a sane initial state */ - ret = adis_initial_startup(st); - if (ret) - goto error_cleanup_buffer_trigger; - - ret = iio_device_register(indio_dev); - if (ret < 0) - goto error_cleanup_buffer_trigger; - - return 0; - -error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(st, indio_dev); - return ret; -} - -static int adis16201_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - adis_cleanup_buffer_and_trigger(st, indio_dev); - - return 0; -} - -static struct spi_driver adis16201_driver = { - .driver = { - .name = "adis16201", - }, - .probe = adis16201_probe, - .remove = adis16201_remove, -}; -module_spi_driver(adis16201_driver); - -MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); -MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:adis16201"); diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 3eb6f8f312dd..a34c2a1d5373 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -18,8 +18,7 @@ static int ad7606_par16_read_block(struct device *dev, int count, void *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); insw((unsigned long)st->base_address, buf, count); @@ -34,8 +33,7 @@ static const struct ad7606_bus_ops ad7606_par16_bops = { static int ad7606_par8_read_block(struct device *dev, int count, void *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); insb((unsigned long)st->base_address, buf, count * 2); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index a7797af579b9..16d72072c076 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -128,7 +128,7 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { }; #define AD7780_CHANNEL(bits, wordsize) \ - AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits) + AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits) static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7170] = { diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index 4882dbc81c53..f53612a6461d 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -6,15 +6,15 @@ * Licensed under the GPL-2. */ -#include <linux/interrupt.h> +#include <linux/delay.h> #include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/sysfs.h> #include <linux/i2c.h> -#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> #include <linux/module.h> +#include <linux/slab.h> #include <linux/stat.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -220,8 +220,8 @@ static int ad7746_select_channel(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { struct ad7746_chip_info *chip = iio_priv(indio_dev); - int ret, delay, idx; u8 vt_setup, cap_setup; + int ret, delay, idx; switch (chan->type) { case IIO_CAPACITANCE: @@ -289,8 +289,8 @@ static inline ssize_t ad7746_start_calib(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7746_chip_info *chip = iio_priv(indio_dev); - bool doit; int ret, timeout = 10; + bool doit; ret = strtobool(buf, &doit); if (ret < 0) @@ -410,8 +410,7 @@ static struct attribute *ad7746_attributes[] = { &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_voltage0_calibscale_calibration.dev_attr.attr, &iio_const_attr_in_voltage_sampling_frequency_available.dev_attr.attr, - &iio_const_attr_in_capacitance_sampling_frequency_available. - dev_attr.attr, + &iio_const_attr_in_capacitance_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -451,26 +450,26 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, goto out; } - ret = i2c_smbus_write_word_data(chip->client, reg, swab16(val)); + ret = i2c_smbus_write_word_swapped(chip->client, reg, val); if (ret < 0) goto out; ret = 0; break; case IIO_CHAN_INFO_CALIBBIAS: - if ((val < 0) | (val > 0xFFFF)) { + if (val < 0 || val > 0xFFFF) { ret = -EINVAL; goto out; } - ret = i2c_smbus_write_word_data(chip->client, - AD7746_REG_CAP_OFFH, swab16(val)); + ret = i2c_smbus_write_word_swapped(chip->client, + AD7746_REG_CAP_OFFH, val); if (ret < 0) goto out; ret = 0; break; case IIO_CHAN_INFO_OFFSET: - if ((val < 0) | (val > 43008000)) { /* 21pF */ + if (val < 0 || val > 43008000) { /* 21pF */ ret = -EINVAL; goto out; } @@ -556,7 +555,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, /* Now read the actual register */ ret = i2c_smbus_read_i2c_block_data(chip->client, - chan->address >> 8, 3, &chip->data.d8[1]); + chan->address >> 8, 3, + &chip->data.d8[1]); if (ret < 0) goto out; @@ -594,27 +594,27 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, goto out; } - ret = i2c_smbus_read_word_data(chip->client, reg); + ret = i2c_smbus_read_word_swapped(chip->client, reg); if (ret < 0) goto out; /* 1 + gain_val / 2^16 */ *val = 1; - *val2 = (15625 * swab16(ret)) / 1024; + *val2 = (15625 * ret) / 1024; ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_CALIBBIAS: - ret = i2c_smbus_read_word_data(chip->client, - AD7746_REG_CAP_OFFH); + ret = i2c_smbus_read_word_swapped(chip->client, + AD7746_REG_CAP_OFFH); if (ret < 0) goto out; - *val = swab16(ret); + *val = ret; ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_OFFSET: *val = AD7746_CAPDAC_DACP(chip->capdac[chan->channel] - [chan->differential]) * 338646; + [chan->differential]) * 338646; ret = IIO_VAL_INT; break; @@ -680,8 +680,8 @@ static int ad7746_probe(struct i2c_client *client, struct ad7746_platform_data *pdata = client->dev.platform_data; struct ad7746_chip_info *chip; struct iio_dev *indio_dev; - int ret = 0; unsigned char regval = 0; + int ret = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (!indio_dev) diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c index 82681300e106..cc863e8927f5 100644 --- a/drivers/staging/iio/light/tsl2x7x.c +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * Device driver for monitoring ambient light intensity in (lux) - * and proximity detection (prox) within the TAOS TSL2X7X family of devices. + * Device driver for monitoring ambient light intensity in (lux) and proximity + * detection (prox) within the TAOS TSL2X7X family of devices. * * Copyright (c) 2012, TAOS Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * Copyright (c) 2017-2018 Brian Masney <masneyb@onstation.org> */ #include <linux/delay.h> @@ -28,7 +20,7 @@ #include <linux/iio/sysfs.h> #include "tsl2x7x.h" -/* Cal defs*/ +/* Cal defs */ #define PROX_STAT_CAL 0 #define PROX_STAT_SAMP 1 #define MAX_SAMPLES_CAL 200 @@ -41,10 +33,11 @@ /* Lux calculation constants */ #define TSL2X7X_LUX_CALC_OVER_FLOW 65535 -/* TAOS Register definitions - note: - * depending on device, some of these register are not used and the - * register address is benign. +/* + * TAOS Register definitions - Note: depending on device, some of these register + * are not used and the register address is benign. */ + /* 2X7X register offsets */ #define TSL2X7X_MAX_CONFIG_REG 16 @@ -62,7 +55,7 @@ #define TSL2X7X_PRX_MAXTHRESHLO 0X0A #define TSL2X7X_PRX_MAXTHRESHHI 0X0B #define TSL2X7X_PERSISTENCE 0x0C -#define TSL2X7X_PRX_CONFIG 0x0D +#define TSL2X7X_ALS_PRX_CONFIG 0x0D #define TSL2X7X_PRX_COUNT 0x0E #define TSL2X7X_GAIN 0x0F #define TSL2X7X_NOTUSED 0x10 @@ -79,6 +72,8 @@ /* tsl2X7X cmd reg masks */ #define TSL2X7X_CMD_REG 0x80 #define TSL2X7X_CMD_SPL_FN 0x60 +#define TSL2X7X_CMD_REPEAT_PROTO 0x00 +#define TSL2X7X_CMD_AUTOINC_PROTO 0x20 #define TSL2X7X_CMD_PROX_INT_CLR 0X05 #define TSL2X7X_CMD_ALS_INT_CLR 0x06 @@ -108,18 +103,6 @@ #define TSL2X7X_CNTL_PROXPON_ENBL 0x0F #define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F -/*Prox diode to use */ -#define TSL2X7X_DIODE0 0x01 -#define TSL2X7X_DIODE1 0x02 -#define TSL2X7X_DIODE_BOTH 0x03 - -/* LED Power */ -#define TSL2X7X_100_mA 0x00 -#define TSL2X7X_50_mA 0x01 -#define TSL2X7X_25_mA 0x02 -#define TSL2X7X_13_mA 0x03 -#define TSL2X7X_MAX_TIMER_CNT 0xFF - #define TSL2X7X_MIN_ITIME 3 /* TAOS txx2x7x Device family members */ @@ -149,17 +132,11 @@ struct tsl2x7x_als_info { u16 lux; }; -struct tsl2x7x_prox_stat { - int min; - int max; - int mean; - unsigned long stddev; -}; - struct tsl2x7x_chip_info { int chan_table_elements; - struct iio_chan_spec channel[4]; - const struct iio_info *info; + struct iio_chan_spec channel_with_events[4]; + struct iio_chan_spec channel_without_events[4]; + const struct iio_info *info; }; struct tsl2X7X_chip { @@ -171,7 +148,7 @@ struct tsl2X7X_chip { struct tsl2x7x_als_info als_cur_info; struct tsl2x7x_settings settings; struct tsl2X7X_platform_data *pdata; - int als_time_scale; + int als_gain_time_scale; int als_saturation; int tsl2x7x_chip_status; u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG]; @@ -186,29 +163,36 @@ struct tsl2X7X_chip { struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE]; }; -/* Different devices require different coefficents */ +/* + * Different devices require different coefficents, and these numbers were + * derived from the 'Lux Equation' section of the various device datasheets. + * All of these coefficients assume a Glass Attenuation (GA) factor of 1. + * The coefficients are multiplied by 1000 to avoid floating point operations. + * The two rows in each table correspond to the Lux1 and Lux2 equations from + * the datasheets. + */ static const struct tsl2x7x_lux tsl2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = { - { 14461, 611, 1211 }, - { 18540, 352, 623 }, - { 0, 0, 0 }, + { 53000, 106000 }, + { 31800, 53000 }, + { 0, 0 }, }; static const struct tsl2x7x_lux tmd2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = { - { 11635, 115, 256 }, - { 15536, 87, 179 }, - { 0, 0, 0 }, + { 24000, 48000 }, + { 14400, 24000 }, + { 0, 0 }, }; static const struct tsl2x7x_lux tsl2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = { - { 14013, 466, 917 }, - { 18222, 310, 552 }, - { 0, 0, 0 }, + { 60000, 112200 }, + { 37800, 60000 }, + { 0, 0 }, }; static const struct tsl2x7x_lux tmd2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = { - { 13218, 130, 262 }, - { 17592, 92, 169 }, - { 0, 0, 0 }, + { 20000, 35000 }, + { 12600, 20000 }, + { 0, 0 }, }; static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { @@ -225,18 +209,20 @@ static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { }; static const struct tsl2x7x_settings tsl2x7x_default_settings = { - .als_time = 219, /* 101 ms */ + .als_time = 255, /* 2.73 ms */ .als_gain = 0, - .prx_time = 254, /* 5.4 ms */ + .prox_time = 255, /* 2.73 ms */ .prox_gain = 0, - .wait_time = 245, - .prox_config = 0, + .wait_time = 255, + .als_prox_config = 0, .als_gain_trim = 1000, .als_cal_target = 150, + .als_persistence = 1, + .als_interrupt_en = false, .als_thresh_low = 200, .als_thresh_high = 256, - .persistence = 255, - .interrupts_en = 0, + .prox_persistence = 1, + .prox_interrupt_en = false, .prox_thres_low = 0, .prox_thres_high = 512, .prox_max_samples_cal = 30, @@ -252,7 +238,7 @@ static const s16 tsl2x7x_als_gain[] = { 120 }; -static const s16 tsl2x7x_prx_gain[] = { +static const s16 tsl2x7x_prox_gain[] = { 1, 2, 4, @@ -269,32 +255,18 @@ enum { }; static const u8 device_channel_config[] = { - ALS, - PRX, - PRX, - ALSPRX, - ALSPRX, - ALS, - PRX2, - PRX2, - ALSPRX2, - ALSPRX2 + [tsl2571] = ALS, + [tsl2671] = PRX, + [tmd2671] = PRX, + [tsl2771] = ALSPRX, + [tmd2771] = ALSPRX, + [tsl2572] = ALS, + [tsl2672] = PRX2, + [tmd2672] = PRX2, + [tsl2772] = ALSPRX2, + [tmd2772] = ALSPRX2 }; -static int tsl2x7x_clear_interrupts(struct tsl2X7X_chip *chip, int reg) -{ - int ret; - - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | reg); - if (ret < 0) - dev_err(&chip->client->dev, - "%s: failed to clear interrupt status %x: %d\n", - __func__, reg, ret); - - return ret; -} - static int tsl2x7x_read_status(struct tsl2X7X_chip *chip) { int ret; @@ -324,38 +296,76 @@ static int tsl2x7x_write_control_reg(struct tsl2X7X_chip *chip, u8 data) return ret; } +static int tsl2x7x_read_autoinc_regs(struct tsl2X7X_chip *chip, int lower_reg, + int upper_reg) +{ + u8 buf[2]; + int ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_AUTOINC_PROTO | + lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to enable auto increment protocol: %d\n", + __func__, ret); + return ret; + } + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read from register %x: %d\n", __func__, + lower_reg, ret); + return ret; + } + buf[0] = ret; + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | upper_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read from register %x: %d\n", __func__, + upper_reg, ret); + return ret; + } + buf[1] = ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_REPEAT_PROTO | + lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to enable repeated byte protocol: %d\n", + __func__, ret); + return ret; + } + + return le16_to_cpup((const __le16 *)&buf[0]); +} + /** * tsl2x7x_get_lux() - Reads and calculates current lux value. * @indio_dev: pointer to IIO device * * The raw ch0 and ch1 values of the ambient light sensed in the last - * integration cycle are read from the device. - * Time scale factor array values are adjusted based on the integration time. - * The raw values are multiplied by a scale factor, and device gain is obtained - * using gain index. Limit checks are done next, then the ratio of a multiple - * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[] - * is then scanned to find the first ratio value that is just above the ratio - * we just calculated. The ch0 and ch1 multiplier constants in the array are - * then used along with the time scale factor array values, to calculate the - * lux. + * integration cycle are read from the device. The raw values are multiplied + * by a device-specific scale factor, and divided by the integration time and + * device gain. The code supports multiple lux equations through the lux table + * coefficients. A lux gain trim is applied to each lux equation, and then the + * maximum lux within the interval 0..65535 is selected. */ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) { - u16 ch0, ch1; /* separated ch0/ch1 data from device */ - u32 lux; /* raw lux calculated from device data */ - u64 lux64; - u32 ratio; - u8 buf[4]; - struct tsl2x7x_lux *p; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int i, ret; - u32 ch0lux = 0; - u32 ch1lux = 0; + struct tsl2x7x_lux *p; + int max_lux, ret; + bool overflow; mutex_lock(&chip->als_mutex); if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { - /* device is not enabled */ dev_err(&chip->client->dev, "%s: device is not enabled\n", __func__); ret = -EBUSY; @@ -366,7 +376,6 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) if (ret < 0) goto out_unlock; - /* is data new & valid */ if (!(ret & TSL2X7X_STA_ADC_VALID)) { dev_err(&chip->client->dev, "%s: data not valid yet\n", __func__); @@ -374,91 +383,61 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev) goto out_unlock; } - for (i = 0; i < 4; i++) { - int reg = TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i); - - ret = i2c_smbus_read_byte_data(chip->client, reg); - if (ret < 0) { - dev_err(&chip->client->dev, - "failed to read. err=%x\n", ret); - goto out_unlock; - } - - buf[i] = ret; - } - - ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_ALS_INT_CLR); + ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_ALS_CHAN0LO, + TSL2X7X_ALS_CHAN0HI); if (ret < 0) goto out_unlock; + chip->als_cur_info.als_ch0 = ret; - /* extract ALS/lux data */ - ch0 = le16_to_cpup((const __le16 *)&buf[0]); - ch1 = le16_to_cpup((const __le16 *)&buf[2]); - - chip->als_cur_info.als_ch0 = ch0; - chip->als_cur_info.als_ch1 = ch1; + ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_ALS_CHAN1LO, + TSL2X7X_ALS_CHAN1HI); + if (ret < 0) + goto out_unlock; + chip->als_cur_info.als_ch1 = ret; - if (ch0 >= chip->als_saturation || ch1 >= chip->als_saturation) { - lux = TSL2X7X_LUX_CALC_OVER_FLOW; - goto return_max; + if (chip->als_cur_info.als_ch0 >= chip->als_saturation) { + max_lux = TSL2X7X_LUX_CALC_OVER_FLOW; + goto update_struct_with_max_lux; } - if (!ch0) { + if (!chip->als_cur_info.als_ch0) { /* have no data, so return LAST VALUE */ ret = chip->als_cur_info.lux; goto out_unlock; } - /* calculate ratio */ - ratio = (ch1 << 15) / ch0; - /* convert to unscaled lux using the pointer to the table */ - p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; - while (p->ratio != 0 && p->ratio < ratio) - p++; - - if (p->ratio == 0) { - lux = 0; - } else { - lux = DIV_ROUND_UP(ch0 * p->ch0, - tsl2x7x_als_gain[chip->settings.als_gain]) - - DIV_ROUND_UP(ch1 * p->ch1, - tsl2x7x_als_gain[chip->settings.als_gain]); - } - - /* note: lux is 31 bit max at this point */ - if (ch1lux > ch0lux) { - dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n"); - ret = chip->als_cur_info.lux; - goto out_unlock; - } - /* adjust for active time scale */ - if (chip->als_time_scale == 0) - lux = 0; - else - lux = (lux + (chip->als_time_scale >> 1)) / - chip->als_time_scale; - - /* adjust for active gain scale - * The tsl2x7x_device_lux tables have a factor of 256 built-in. - * User-specified gain provides a multiplier. - * Apply user-specified gain before shifting right to retain precision. - * Use 64 bits to avoid overflow on multiplication. - * Then go back to 32 bits before division to avoid using div_u64(). - */ + max_lux = 0; + overflow = false; + for (p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; p->ch0 != 0; + p++) { + int lux; + + lux = ((chip->als_cur_info.als_ch0 * p->ch0) - + (chip->als_cur_info.als_ch1 * p->ch1)) / + chip->als_gain_time_scale; + + /* + * The als_gain_trim can have a value within the range 250..4000 + * and is a multiplier for the lux. A trim of 1000 makes no + * changes to the lux, less than 1000 scales it down, and + * greater than 1000 scales it up. + */ + lux = (lux * chip->settings.als_gain_trim) / 1000; + + if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) { + overflow = true; + continue; + } - lux64 = lux; - lux64 = lux64 * chip->settings.als_gain_trim; - lux64 >>= 8; - lux = lux64; - lux = (lux + 500) / 1000; + max_lux = max(max_lux, lux); + } - if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */ - lux = TSL2X7X_LUX_CALC_OVER_FLOW; + if (overflow && max_lux == 0) + max_lux = TSL2X7X_LUX_CALC_OVER_FLOW; - /* Update the structure with the latest lux. */ -return_max: - chip->als_cur_info.lux = lux; - ret = lux; +update_struct_with_max_lux: + chip->als_cur_info.lux = max_lux; + ret = max_lux; out_unlock: mutex_unlock(&chip->als_mutex); @@ -474,10 +453,8 @@ out_unlock: */ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) { - int i; - int ret; - u8 chdata[2]; struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret; mutex_lock(&chip->prox_mutex); @@ -508,18 +485,10 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev) break; } - for (i = 0; i < 2; i++) { - int reg = TSL2X7X_CMD_REG | (TSL2X7X_PRX_LO + i); - - ret = i2c_smbus_read_byte_data(chip->client, reg); - if (ret < 0) - goto prox_poll_err; - - chdata[i] = ret; - } - - chip->prox_data = le16_to_cpup((const __le16 *)&chdata[0]); - ret = chip->prox_data; + ret = tsl2x7x_read_autoinc_regs(chip, TSL2X7X_PRX_LO, TSL2X7X_PRX_HI); + if (ret < 0) + goto prox_poll_err; + chip->prox_data = ret; prox_poll_err: mutex_unlock(&chip->prox_mutex); @@ -545,7 +514,7 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) sizeof(tsl2x7x_default_settings)); /* Load up the proper lux table. */ - if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0) + if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0) memcpy(chip->tsl2x7x_device_lux, chip->pdata->platform_lux_table, sizeof(chip->pdata->platform_lux_table)); @@ -601,26 +570,22 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) return -ERANGE; chip->settings.als_gain_trim = ret; - dev_info(&chip->client->dev, - "%s als_calibrate completed\n", chip->client->name); return ret; } static int tsl2x7x_chip_on(struct iio_dev *indio_dev) { - int i; - int ret = 0; - u8 *dev_reg; - int als_count; - int als_time; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 reg_val = 0; + int ret, i, als_count, als_time_us; + u8 *dev_reg, reg_val; /* Non calculated parameters */ - chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prx_time; + chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = chip->settings.als_time; + chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prox_time; chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time; - chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = chip->settings.prox_config; + chip->tsl2x7x_config[TSL2X7X_ALS_PRX_CONFIG] = + chip->settings.als_prox_config; chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = (chip->settings.als_thresh_low) & 0xFF; @@ -630,7 +595,9 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) (chip->settings.als_thresh_high) & 0xFF; chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = (chip->settings.als_thresh_high >> 8) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = chip->settings.persistence; + chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = + (chip->settings.prox_persistence & 0xFF) << 4 | + (chip->settings.als_persistence & 0xFF); chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = chip->settings.prox_pulse_count; @@ -650,15 +617,6 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) return -EINVAL; } - /* determine als integration register */ - als_count = (chip->settings.als_time * 100 + 135) / 270; - if (!als_count) - als_count = 1; /* ensure at least one cycle */ - - /* convert back to time (encompasses overrides) */ - als_time = (als_count * 27 + 5) / 10; - chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; - /* Set the gain based on tsl2x7x_settings struct */ chip->tsl2x7x_config[TSL2X7X_GAIN] = (chip->settings.als_gain & 0xFF) | @@ -666,9 +624,12 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) (chip->settings.prox_diode << 4) | (chip->settings.prox_power << 6); - /* set chip struct re scaling and saturation */ - chip->als_saturation = als_count * 922; /* 90% of full scale */ - chip->als_time_scale = (als_time + 25) / 50; + /* set chip time scaling and saturation */ + als_count = 256 - chip->settings.als_time; + als_time_us = als_count * 2720; + chip->als_saturation = als_count * 768; /* 75% of full scale */ + chip->als_gain_time_scale = als_time_us * + tsl2x7x_als_gain[chip->settings.als_gain]; /* * TSL2X7X Specific power-on / adc enable sequence @@ -684,12 +645,14 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) */ for (i = 0, dev_reg = chip->tsl2x7x_config; i < TSL2X7X_MAX_CONFIG_REG; i++) { - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG + i, + int reg = TSL2X7X_CMD_REG + i; + + ret = i2c_smbus_write_byte_data(chip->client, reg, *dev_reg++); if (ret < 0) { dev_err(&chip->client->dev, - "failed on write to reg %d.\n", i); + "%s: failed to write to register %x: %d\n", + __func__, reg, ret); return ret; } } @@ -697,38 +660,29 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev) /* Power-on settling time */ usleep_range(3000, 3500); - /* - * NOW enable the ADC - * initialize the desired mode of operation - */ - ret = tsl2x7x_write_control_reg(chip, - TSL2X7X_CNTL_PWR_ON | - TSL2X7X_CNTL_ADC_ENBL | - TSL2X7X_CNTL_PROX_DET_ENBL); + reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL | + TSL2X7X_CNTL_PROX_DET_ENBL; + if (chip->settings.als_interrupt_en) + reg_val |= TSL2X7X_CNTL_ALS_INT_ENBL; + if (chip->settings.prox_interrupt_en) + reg_val |= TSL2X7X_CNTL_PROX_INT_ENBL; + + ret = tsl2x7x_write_control_reg(chip, reg_val); if (ret < 0) return ret; - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; - - if (chip->settings.interrupts_en != 0) { - dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); - - reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL; - if (chip->settings.interrupts_en == 0x20 || - chip->settings.interrupts_en == 0x30) - reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL; - - reg_val |= chip->settings.interrupts_en; - ret = tsl2x7x_write_control_reg(chip, reg_val); - if (ret < 0) - return ret; - - ret = tsl2x7x_clear_interrupts(chip, - TSL2X7X_CMD_PROXALS_INT_CLR); - if (ret < 0) - return ret; + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to clear interrupt status: %d\n", + __func__, ret); + return ret; } + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; + return ret; } @@ -742,14 +696,13 @@ static int tsl2x7x_chip_off(struct iio_dev *indio_dev) } /** - * tsl2x7x_invoke_change + * tsl2x7x_invoke_change - power cycle the device to implement the user + * parameters * @indio_dev: pointer to IIO device * - * Obtain and lock both ALS and PROX resources, - * determine and save device state (On/Off), - * cycle device to implement updated parameter, - * put device back into proper state, and unlock - * resource. + * Obtain and lock both ALS and PROX resources, determine and save device state + * (On/Off), cycle device to implement updated parameter, put device back into + * proper state, and unlock resource. */ static int tsl2x7x_invoke_change(struct iio_dev *indio_dev) { @@ -775,130 +728,43 @@ unlock: return ret; } -static void tsl2x7x_prox_calculate(int *data, int length, - struct tsl2x7x_prox_stat *stat) -{ - int i; - int sample_sum; - int tmp; - - if (!length) - length = 1; - - sample_sum = 0; - stat->min = INT_MAX; - stat->max = INT_MIN; - for (i = 0; i < length; i++) { - sample_sum += data[i]; - stat->min = min(stat->min, data[i]); - stat->max = max(stat->max, data[i]); - } - - stat->mean = sample_sum / length; - sample_sum = 0; - for (i = 0; i < length; i++) { - tmp = data[i] - stat->mean; - sample_sum += tmp * tmp; - } - stat->stddev = int_sqrt((long)sample_sum / length); -} - -/** - * tsl2x7x_prox_cal() - Calculates std. and sets thresholds. - * @indio_dev: pointer to IIO device - * - * Calculates a standard deviation based on the samples, - * and sets the threshold accordingly. - */ static int tsl2x7x_prox_cal(struct iio_dev *indio_dev) { - int prox_history[MAX_SAMPLES_CAL + 1]; - int i, ret; - struct tsl2x7x_prox_stat prox_stat_data[2]; - struct tsl2x7x_prox_stat *cal; struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 tmp_irq_settings; - u8 current_state = chip->tsl2x7x_chip_status; - - if (chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) { - dev_err(&chip->client->dev, - "max prox samples cal is too big: %d\n", - chip->settings.prox_max_samples_cal); - chip->settings.prox_max_samples_cal = MAX_SAMPLES_CAL; - } - - /* have to stop to change settings */ - ret = tsl2x7x_chip_off(indio_dev); - if (ret < 0) - return ret; - - /* Enable proximity detection save just in case prox not wanted yet*/ - tmp_irq_settings = chip->settings.interrupts_en; - chip->settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL; + int prox_history[MAX_SAMPLES_CAL + 1]; + int i, ret, mean, max, sample_sum; - /*turn on device if not already on*/ - ret = tsl2x7x_chip_on(indio_dev); - if (ret < 0) - return ret; + if (chip->settings.prox_max_samples_cal < 1 || + chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) + return -EINVAL; - /*gather the samples*/ for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { usleep_range(15000, 17500); ret = tsl2x7x_get_prox(indio_dev); if (ret < 0) return ret; + prox_history[i] = chip->prox_data; - dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", - i, chip->prox_data); } - ret = tsl2x7x_chip_off(indio_dev); - if (ret < 0) - return ret; - cal = &prox_stat_data[PROX_STAT_CAL]; - tsl2x7x_prox_calculate(prox_history, - chip->settings.prox_max_samples_cal, cal); - chip->settings.prox_thres_high = (cal->max << 1) - cal->mean; - - dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", - cal->min, cal->mean, cal->max); - dev_info(&chip->client->dev, - "%s proximity threshold set to %d\n", - chip->client->name, chip->settings.prox_thres_high); - - /* back to the way they were */ - chip->settings.interrupts_en = tmp_irq_settings; - if (current_state == TSL2X7X_CHIP_WORKING) { - ret = tsl2x7x_chip_on(indio_dev); - if (ret < 0) - return ret; + sample_sum = 0; + max = INT_MIN; + for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { + sample_sum += prox_history[i]; + max = max(max, prox_history[i]); } + mean = sample_sum / chip->settings.prox_max_samples_cal; - return 0; -} - -static ssize_t -in_illuminance0_calibscale_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); - } + chip->settings.prox_thres_high = (max << 1) - mean; - return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); + return tsl2x7x_invoke_change(indio_dev); } +static IIO_CONST_ATTR(in_intensity0_calibscale_available, "1 8 16 120"); + static IIO_CONST_ATTR(in_proximity0_calibscale_available, "1 2 4 8"); -static IIO_CONST_ATTR(in_illuminance0_integration_time_available, +static IIO_CONST_ATTR(in_intensity0_integration_time_available, ".00272 - .696"); static ssize_t in_illuminance0_target_input_show(struct device *dev, @@ -916,15 +782,13 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2X7X_chip *chip = iio_priv(indio_dev); - unsigned long value; + u16 value; int ret; - if (kstrtoul(buf, 0, &value)) + if (kstrtou16(buf, 0, &value)) return -EINVAL; - if (value) - chip->settings.als_cal_target = value; - + chip->settings.als_cal_target = value; ret = tsl2x7x_invoke_change(indio_dev); if (ret < 0) return ret; @@ -940,14 +804,12 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev, bool value; int ret; - if (strtobool(buf, &value)) + if (kstrtobool(buf, &value) || !value) return -EINVAL; - if (value) { - ret = tsl2x7x_als_calibrate(indio_dev); - if (ret < 0) - return ret; - } + ret = tsl2x7x_als_calibrate(indio_dev); + if (ret < 0) + return ret; ret = tsl2x7x_invoke_change(indio_dev); if (ret < 0) @@ -965,11 +827,10 @@ static ssize_t in_illuminance0_lux_table_show(struct device *dev, int offset = 0; while (i < TSL2X7X_MAX_LUX_TABLE_SIZE) { - offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,", - chip->tsl2x7x_device_lux[i].ratio, + offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,", chip->tsl2x7x_device_lux[i].ch0, chip->tsl2x7x_device_lux[i].ch1); - if (chip->tsl2x7x_device_lux[i].ratio == 0) { + if (chip->tsl2x7x_device_lux[i].ch0 == 0) { /* * We just printed the first "0" entry. * Now get rid of the extra "," and break. @@ -990,27 +851,24 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1]; + int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 2 + 1]; int n, ret; get_options(buf, ARRAY_SIZE(value), value); - /* We now have an array of ints starting at value[1], and + /* + * We now have an array of ints starting at value[1], and * enumerated by value[0]. - * We expect each group of three ints is one table entry, + * We expect each group of two ints to be one table entry, * and the last table entry is all 0. */ n = value[0]; - if ((n % 3) || n < 6 || - n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { - dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); + if ((n % 2) || n < 4 || + n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 2)) return -EINVAL; - } - if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { - dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); + if ((value[(n - 1)] | value[n]) != 0) return -EINVAL; - } if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { ret = tsl2x7x_chip_off(indio_dev); @@ -1037,14 +895,12 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev, bool value; int ret; - if (strtobool(buf, &value)) + if (kstrtobool(buf, &value) || !value) return -EINVAL; - if (value) { - ret = tsl2x7x_prox_cal(indio_dev); - if (ret < 0) - return ret; - } + ret = tsl2x7x_prox_cal(indio_dev); + if (ret < 0) + return ret; ret = tsl2x7x_invoke_change(indio_dev); if (ret < 0) @@ -1059,14 +915,11 @@ static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret; if (chan->type == IIO_INTENSITY) - ret = !!(chip->settings.interrupts_en & 0x10); + return chip->settings.als_interrupt_en; else - ret = !!(chip->settings.interrupts_en & 0x20); - - return ret; + return chip->settings.prox_interrupt_en; } static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, @@ -1076,25 +929,13 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, int val) { struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret; - if (chan->type == IIO_INTENSITY) { - if (val) - chip->settings.interrupts_en |= 0x10; - else - chip->settings.interrupts_en &= 0x20; - } else { - if (val) - chip->settings.interrupts_en |= 0x20; - else - chip->settings.interrupts_en &= 0x10; - } - - ret = tsl2x7x_invoke_change(indio_dev); - if (ret < 0) - return ret; + if (chan->type == IIO_INTENSITY) + chip->settings.als_interrupt_en = val ? true : false; + else + chip->settings.prox_interrupt_en = val ? true : false; - return 0; + return tsl2x7x_invoke_change(indio_dev); } static int tsl2x7x_write_event_value(struct iio_dev *indio_dev, @@ -1142,27 +983,17 @@ static int tsl2x7x_write_event_value(struct iio_dev *indio_dev, if (chan->type == IIO_INTENSITY) time = chip->settings.als_time; else - time = chip->settings.prx_time; + time = chip->settings.prox_time; y = (TSL2X7X_MAX_TIMER_CNT - time) + 1; z = y * TSL2X7X_MIN_ITIME; filter_delay = DIV_ROUND_UP((val * 1000) + val2, z); - if (chan->type == IIO_INTENSITY) { - chip->settings.persistence &= 0xF0; - chip->settings.persistence |= - (filter_delay & 0x0F); - dev_info(&chip->client->dev, "%s: ALS persistence = %d", - __func__, filter_delay); - } else { - chip->settings.persistence &= 0x0F; - chip->settings.persistence |= - ((filter_delay << 4) & 0xF0); - dev_info(&chip->client->dev, - "%s: Proximity persistence = %d", - __func__, filter_delay); - } + if (chan->type == IIO_INTENSITY) + chip->settings.als_persistence = filter_delay; + else + chip->settings.prox_persistence = filter_delay; ret = 0; break; default: @@ -1219,10 +1050,10 @@ static int tsl2x7x_read_event_value(struct iio_dev *indio_dev, case IIO_EV_INFO_PERIOD: if (chan->type == IIO_INTENSITY) { time = chip->settings.als_time; - mult = chip->settings.persistence & 0x0F; + mult = chip->settings.als_persistence; } else { - time = chip->settings.prx_time; - mult = (chip->settings.persistence & 0xF0) >> 4; + time = chip->settings.prox_time; + mult = chip->settings.prox_persistence; } /* Determine integration time */ @@ -1246,8 +1077,8 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { - int ret = -EINVAL; struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL; switch (mask) { case IIO_CHAN_INFO_PROCESSED: @@ -1284,7 +1115,7 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, if (chan->type == IIO_LIGHT) *val = tsl2x7x_als_gain[chip->settings.als_gain]; else - *val = tsl2x7x_prx_gain[chip->settings.prox_gain]; + *val = tsl2x7x_prox_gain[chip->settings.prox_gain]; ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_CALIBBIAS: @@ -1292,8 +1123,8 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_INT_TIME: - *val = (TSL2X7X_MAX_TIMER_CNT - chip->settings.als_time) + 1; - *val2 = ((*val * TSL2X7X_MIN_ITIME) % 1000) / 1000; + *val = 0; + *val2 = (256 - chip->settings.als_time) * 2720; ret = IIO_VAL_INT_PLUS_MICRO; break; default: @@ -1325,25 +1156,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, chip->settings.als_gain = 2; break; case 120: - switch (chip->id) { - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - return -EINVAL; - } - chip->settings.als_gain = 3; - break; - case 128: - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - return -EINVAL; - } chip->settings.als_gain = 3; break; default: @@ -1372,11 +1184,7 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, chip->settings.als_gain_trim = val; break; case IIO_CHAN_INFO_INT_TIME: - chip->settings.als_time = - TSL2X7X_MAX_TIMER_CNT - (val2 / TSL2X7X_MIN_ITIME); - - dev_info(&chip->client->dev, "%s: als time = %d", - __func__, chip->settings.als_time); + chip->settings.als_time = 256 - (val2 / 2720); break; default: return -EINVAL; @@ -1385,8 +1193,6 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, return tsl2x7x_invoke_change(indio_dev); } -static DEVICE_ATTR_RO(in_illuminance0_calibscale_available); - static DEVICE_ATTR_RW(in_illuminance0_target_input); static DEVICE_ATTR_WO(in_illuminance0_calibrate); @@ -1396,22 +1202,22 @@ static DEVICE_ATTR_WO(in_proximity0_calibrate); static DEVICE_ATTR_RW(in_illuminance0_lux_table); /* Use the default register values to identify the Taos device */ -static int tsl2x7x_device_id(int *id, int target) +static int tsl2x7x_device_id_verif(int id, int target) { switch (target) { case tsl2571: case tsl2671: case tsl2771: - return (*id & 0xf0) == TRITON_ID; + return (id & 0xf0) == TRITON_ID; case tmd2671: case tmd2771: - return (*id & 0xf0) == HALIBUT_ID; + return (id & 0xf0) == HALIBUT_ID; case tsl2572: case tsl2672: case tmd2672: case tsl2772: case tmd2772: - return (*id & 0xf0) == SWORDFISH_ID; + return (id & 0xf0) == SWORDFISH_ID; } return -EINVAL; @@ -1426,11 +1232,10 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) ret = tsl2x7x_read_status(chip); if (ret < 0) - return ret; + return IRQ_HANDLED; /* What type of interrupt do we need to process */ if (ret & TSL2X7X_STA_PRX_INTR) { - tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, @@ -1440,7 +1245,6 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) } if (ret & TSL2X7X_STA_ALS_INTR) { - tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */ iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, @@ -1449,17 +1253,20 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private) timestamp); } - ret = tsl2x7x_clear_interrupts(chip, TSL2X7X_CMD_PROXALS_INT_CLR); + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); if (ret < 0) - return ret; + dev_err(&chip->client->dev, + "%s: failed to clear interrupt status: %d\n", + __func__, ret); return IRQ_HANDLED; } static struct attribute *tsl2x7x_ALS_device_attrs[] = { - &dev_attr_in_illuminance0_calibscale_available.attr, - &iio_const_attr_in_illuminance0_integration_time_available - .dev_attr.attr, + &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr, + &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr, &dev_attr_in_illuminance0_target_input.attr, &dev_attr_in_illuminance0_calibrate.attr, &dev_attr_in_illuminance0_lux_table.attr, @@ -1472,9 +1279,8 @@ static struct attribute *tsl2x7x_PRX_device_attrs[] = { }; static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { - &dev_attr_in_illuminance0_calibscale_available.attr, - &iio_const_attr_in_illuminance0_integration_time_available - .dev_attr.attr, + &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr, + &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr, &dev_attr_in_illuminance0_target_input.attr, &dev_attr_in_illuminance0_calibrate.attr, &dev_attr_in_illuminance0_lux_table.attr, @@ -1488,9 +1294,8 @@ static struct attribute *tsl2x7x_PRX2_device_attrs[] = { }; static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = { - &dev_attr_in_illuminance0_calibscale_available.attr, - &iio_const_attr_in_illuminance0_integration_time_available - .dev_attr.attr, + &iio_const_attr_in_intensity0_calibscale_available.dev_attr.attr, + &iio_const_attr_in_intensity0_integration_time_available.dev_attr.attr, &dev_attr_in_illuminance0_target_input.attr, &dev_attr_in_illuminance0_calibrate.attr, &dev_attr_in_illuminance0_lux_table.attr, @@ -1569,34 +1374,33 @@ static const struct iio_event_spec tsl2x7x_events[] = { { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), + .mask_separate = BIT(IIO_EV_INFO_VALUE), }, { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), + .mask_separate = BIT(IIO_EV_INFO_VALUE), }, { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_PERIOD), + .mask_separate = BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_ENABLE), }, }; static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { [ALS] = { - .channel = { + .channel_with_events = { { .type = IIO_LIGHT, .indexed = 1, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, { .type = IIO_INTENSITY, .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), .event_spec = tsl2x7x_events, @@ -1607,11 +1411,31 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .channel = 1, }, }, - .chan_table_elements = 3, - .info = &tsl2X7X_device_info[ALS], + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + }, + }, + .chan_table_elements = 3, + .info = &tsl2X7X_device_info[ALS], }, [PRX] = { - .channel = { + .channel_with_events = { { .type = IIO_PROXIMITY, .indexed = 1, @@ -1621,22 +1445,30 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, - .chan_table_elements = 1, - .info = &tsl2X7X_device_info[PRX], + .channel_without_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX], }, [ALSPRX] = { - .channel = { + .channel_with_events = { { .type = IIO_LIGHT, .indexed = 1, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, { .type = IIO_INTENSITY, .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), .event_spec = tsl2x7x_events, @@ -1655,11 +1487,37 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, - .chan_table_elements = 4, - .info = &tsl2X7X_device_info[ALSPRX], + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX], }, [PRX2] = { - .channel = { + .channel_with_events = { { .type = IIO_PROXIMITY, .indexed = 1, @@ -1670,22 +1528,31 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, - .chan_table_elements = 1, - .info = &tsl2X7X_device_info[PRX2], + .channel_without_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX2], }, [ALSPRX2] = { - .channel = { + .channel_with_events = { { .type = IIO_LIGHT, .indexed = 1, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_INT_TIME), + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, { .type = IIO_INTENSITY, .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS), .event_spec = tsl2x7x_events, @@ -1705,17 +1572,44 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { .num_event_specs = ARRAY_SIZE(tsl2x7x_events), }, }, - .chan_table_elements = 4, - .info = &tsl2X7X_device_info[ALSPRX2], + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX2], }, }; static int tsl2x7x_probe(struct i2c_client *clientp, const struct i2c_device_id *id) { - int ret; struct iio_dev *indio_dev; struct tsl2X7X_chip *chip; + int ret; indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); if (!indio_dev) @@ -1730,8 +1624,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp, if (ret < 0) return ret; - if ((!tsl2x7x_device_id(&ret, id->driver_data)) || - (tsl2x7x_device_id(&ret, id->driver_data) == -EINVAL)) { + if (tsl2x7x_device_id_verif(ret, id->driver_data) <= 0) { dev_info(&chip->client->dev, "%s: i2c device found does not match expected id\n", __func__); @@ -1740,15 +1633,12 @@ static int tsl2x7x_probe(struct i2c_client *clientp, ret = i2c_smbus_write_byte(clientp, TSL2X7X_CMD_REG | TSL2X7X_CNTRL); if (ret < 0) { - dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n", - ret); + dev_err(&clientp->dev, + "%s: Failed to write to CMD register: %d\n", + __func__, ret); return ret; } - /* - * ALS and PROX functions can be invoked via user space poll - * or H/W interrupt. If busy return last sample. - */ mutex_init(&chip->als_mutex); mutex_init(&chip->prox_mutex); @@ -1762,27 +1652,28 @@ static int tsl2x7x_probe(struct i2c_client *clientp, indio_dev->dev.parent = &clientp->dev; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->name = chip->client->name; - indio_dev->channels = chip->chip_info->channel; indio_dev->num_channels = chip->chip_info->chan_table_elements; if (clientp->irq) { + indio_dev->channels = chip->chip_info->channel_with_events; + ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, NULL, &tsl2x7x_event_handler, - IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "TSL2X7X_event", indio_dev); if (ret) { dev_err(&clientp->dev, - "%s: irq request failed", __func__); + "%s: irq request failed\n", __func__); return ret; } + } else { + indio_dev->channels = chip->chip_info->channel_without_events; } - /* Load up the defaults */ tsl2x7x_defaults(chip); - /* Make sure the chip is on */ tsl2x7x_chip_on(indio_dev); ret = iio_device_register(indio_dev); @@ -1792,35 +1683,21 @@ static int tsl2x7x_probe(struct i2c_client *clientp, return ret; } - dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); - return 0; } static int tsl2x7x_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret = 0; - - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { - ret = tsl2x7x_chip_off(indio_dev); - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; - } - return ret; + return tsl2x7x_chip_off(indio_dev); } static int tsl2x7x_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret = 0; - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) - ret = tsl2x7x_chip_on(indio_dev); - - return ret; + return tsl2x7x_chip_on(indio_dev); } static int tsl2x7x_remove(struct i2c_client *client) @@ -1870,7 +1747,6 @@ static const struct dev_pm_ops tsl2x7x_pm_ops = { .resume = tsl2x7x_resume, }; -/* Driver definition */ static struct i2c_driver tsl2x7x_driver = { .driver = { .name = "tsl2x7x", @@ -1884,6 +1760,7 @@ static struct i2c_driver tsl2x7x_driver = { module_i2c_driver(tsl2x7x_driver); -MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); +MODULE_AUTHOR("J. August Brenner <Jon.Brenner@ams.com>"); +MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>"); MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h index 28b0e7fdc9b8..1097ee890ce2 100644 --- a/drivers/staging/iio/light/tsl2x7x.h +++ b/drivers/staging/iio/light/tsl2x7x.h @@ -1,79 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Device driver for monitoring ambient light intensity (lux) * and proximity (prox) within the TAOS TSL2X7X family of devices. * * Copyright (c) 2012, TAOS Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __TSL2X7X_H #define __TSL2X7X_H struct tsl2x7x_lux { - unsigned int ratio; unsigned int ch0; unsigned int ch1; }; /* Max number of segments allowable in LUX table */ -#define TSL2X7X_MAX_LUX_TABLE_SIZE 9 +#define TSL2X7X_MAX_LUX_TABLE_SIZE 6 /* The default LUX tables all have 3 elements. */ #define TSL2X7X_DEF_LUX_TABLE_SZ 3 #define TSL2X7X_DEFAULT_TABLE_BYTES (sizeof(struct tsl2x7x_lux) * \ TSL2X7X_DEF_LUX_TABLE_SZ) +/* Proximity diode to use */ +#define TSL2X7X_DIODE0 0x01 +#define TSL2X7X_DIODE1 0x02 +#define TSL2X7X_DIODE_BOTH 0x03 + +/* LED Power */ +#define TSL2X7X_100_mA 0x00 +#define TSL2X7X_50_mA 0x01 +#define TSL2X7X_25_mA 0x02 +#define TSL2X7X_13_mA 0x03 +#define TSL2X7X_MAX_TIMER_CNT 0xFF + /** - * struct tsl2x7x_default_settings - power on defaults unless - * overridden by platform data. - * @als_time: ALS Integration time - multiple of 50mS - * @als_gain: Index into the ALS gain table. - * @als_gain_trim: default gain trim to account for - * aperture effects. - * @wait_time: Time between PRX and ALS cycles - * in 2.7 periods - * @prx_time: 5.2ms prox integration time - - * decrease in 2.7ms periods - * @prx_gain: Proximity gain index - * @prox_config: Prox configuration filters. - * @als_cal_target: Known external ALS reading for - * calibration. - * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als, - * 0x20 = prx, 0x30 = bth - * @persistence: H/W Filters, Number of 'out of limits' - * ADC readings PRX/ALS. + * struct tsl2x7x_settings - Settings for the tsl2x7x driver + * @als_time: Integration time of the ALS channel ADCs in 2.73 ms + * increments. Total integration time is + * (256 - als_time) * 2.73. + * @als_gain: Index into the tsl2x7x_als_gain array. + * @als_gain_trim: Default gain trim to account for aperture effects. + * @wait_time: Time between proximity and ALS cycles in 2.73 + * periods. + * @prox_time: Integration time of the proximity ADC in 2.73 ms + * increments. Total integration time is + * (256 - prx_time) * 2.73. + * @prox_gain: Index into the tsl2x7x_prx_gain array. + * @als_prox_config: The value of the ALS / Proximity configuration + * register. + * @als_cal_target: Known external ALS reading for calibration. + * @als_persistence: H/W Filters, Number of 'out of limits' ALS readings. + * @als_interrupt_en: Enable/Disable ALS interrupts * @als_thresh_low: CH0 'low' count to trigger interrupt. * @als_thresh_high: CH0 'high' count to trigger interrupt. + * @prox_persistence: H/W Filters, Number of 'out of limits' proximity + * readings. + * @prox_interrupt_en: Enable/Disable proximity interrupts. * @prox_thres_low: Low threshold proximity detection. - * @prox_thres_high: High threshold proximity detection - * @prox_pulse_count: Number if proximity emitter pulses - * @prox_max_samples_cal: Used for prox cal. + * @prox_thres_high: High threshold proximity detection. + * @prox_pulse_count: Number if proximity emitter pulses. + * @prox_max_samples_cal: The number of samples that are taken when performing + * a proximity calibration. + * @prox_diode Which diode(s) to use for driving the external + * LED(s) for proximity sensing. + * @prox_power The amount of power to use for the external LED(s). */ struct tsl2x7x_settings { int als_time; int als_gain; int als_gain_trim; int wait_time; - int prx_time; + int prox_time; int prox_gain; - int prox_config; + int als_prox_config; int als_cal_target; - u8 interrupts_en; - u8 persistence; + u8 als_persistence; + bool als_interrupt_en; int als_thresh_low; int als_thresh_high; + u8 prox_persistence; + bool prox_interrupt_en; int prox_thres_low; int prox_thres_high; int prox_pulse_count; @@ -84,9 +90,6 @@ struct tsl2x7x_settings { /** * struct tsl2X7X_platform_data - Platform callback, glass and defaults - * @platform_power: Suspend/resume platform callback - * @power_on: Power on callback - * @power_off: Power off callback * @platform_lux_table: Device specific glass coefficents * @platform_default_settings: Device specific power on defaults * diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index 317e4f0d8176..c3aa6ea9d036 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -15,91 +15,60 @@ #include <linux/iio/iio.h> #include "ade7854.h" -static int ade7854_i2c_write_reg_8(struct device *dev, - u16 reg_address, - u8 val) +static int ade7854_i2c_write_reg(struct device *dev, + u16 reg_address, + u32 val, + int bits) { int ret; + int count; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); mutex_lock(&st->buf_lock); st->tx[0] = (reg_address >> 8) & 0xFF; st->tx[1] = reg_address & 0xFF; - st->tx[2] = val; - ret = i2c_master_send(st->i2c, st->tx, 3); + switch (bits) { + case 8: + st->tx[2] = val & 0xFF; + count = 3; + break; + case 16: + st->tx[2] = (val >> 8) & 0xFF; + st->tx[3] = val & 0xFF; + count = 4; + break; + case 24: + st->tx[2] = (val >> 16) & 0xFF; + st->tx[3] = (val >> 8) & 0xFF; + st->tx[4] = val & 0xFF; + count = 5; + break; + case 32: + st->tx[2] = (val >> 24) & 0xFF; + st->tx[3] = (val >> 16) & 0xFF; + st->tx[4] = (val >> 8) & 0xFF; + st->tx[5] = val & 0xFF; + count = 6; + break; + default: + ret = -EINVAL; + goto unlock; + } + + ret = i2c_master_send(st->i2c, st->tx, count); + +unlock: mutex_unlock(&st->buf_lock); - return ret; + return ret < 0 ? ret : 0; } -static int ade7854_i2c_write_reg_16(struct device *dev, - u16 reg_address, - u16 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - st->tx[2] = (val >> 8) & 0xFF; - st->tx[3] = val & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 4); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_i2c_write_reg_24(struct device *dev, - u16 reg_address, - u32 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - st->tx[2] = (val >> 16) & 0xFF; - st->tx[3] = (val >> 8) & 0xFF; - st->tx[4] = val & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 5); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_i2c_write_reg_32(struct device *dev, - u16 reg_address, - u32 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - st->tx[2] = (val >> 24) & 0xFF; - st->tx[3] = (val >> 16) & 0xFF; - st->tx[4] = (val >> 8) & 0xFF; - st->tx[5] = val & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 6); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_i2c_read_reg_8(struct device *dev, - u16 reg_address, - u8 *val) +static int ade7854_i2c_read_reg(struct device *dev, + u16 reg_address, + u32 *val, + int bits) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -110,94 +79,33 @@ static int ade7854_i2c_read_reg_8(struct device *dev, st->tx[1] = reg_address & 0xFF; ret = i2c_master_send(st->i2c, st->tx, 2); - if (ret) - goto out; - - ret = i2c_master_recv(st->i2c, st->rx, 1); - if (ret) - goto out; - - *val = st->rx[0]; -out: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_i2c_read_reg_16(struct device *dev, - u16 reg_address, - u16 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 2); - if (ret) - goto out; - - ret = i2c_master_recv(st->i2c, st->rx, 2); - if (ret) - goto out; - - *val = (st->rx[0] << 8) | st->rx[1]; -out: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_i2c_read_reg_24(struct device *dev, - u16 reg_address, - u32 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 2); - if (ret) - goto out; - - ret = i2c_master_recv(st->i2c, st->rx, 3); - if (ret) - goto out; - - *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; -out: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_i2c_read_reg_32(struct device *dev, - u16 reg_address, - u32 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->buf_lock); - st->tx[0] = (reg_address >> 8) & 0xFF; - st->tx[1] = reg_address & 0xFF; - - ret = i2c_master_send(st->i2c, st->tx, 2); - if (ret) - goto out; - - ret = i2c_master_recv(st->i2c, st->rx, 3); - if (ret) - goto out; - - *val = (st->rx[0] << 24) | (st->rx[1] << 16) | - (st->rx[2] << 8) | st->rx[3]; -out: + if (ret < 0) + goto unlock; + + ret = i2c_master_recv(st->i2c, st->rx, bits); + if (ret < 0) + goto unlock; + + switch (bits) { + case 8: + *val = st->rx[0]; + break; + case 16: + *val = (st->rx[0] << 8) | st->rx[1]; + break; + case 24: + *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; + break; + case 32: + *val = (st->rx[0] << 24) | (st->rx[1] << 16) | + (st->rx[2] << 8) | st->rx[3]; + break; + default: + ret = -EINVAL; + goto unlock; + } + +unlock: mutex_unlock(&st->buf_lock); return ret; } @@ -213,14 +121,8 @@ static int ade7854_i2c_probe(struct i2c_client *client, return -ENOMEM; st = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); - st->read_reg_8 = ade7854_i2c_read_reg_8; - st->read_reg_16 = ade7854_i2c_read_reg_16; - st->read_reg_24 = ade7854_i2c_read_reg_24; - st->read_reg_32 = ade7854_i2c_read_reg_32; - st->write_reg_8 = ade7854_i2c_write_reg_8; - st->write_reg_16 = ade7854_i2c_write_reg_16; - st->write_reg_24 = ade7854_i2c_write_reg_24; - st->write_reg_32 = ade7854_i2c_write_reg_32; + st->read_reg = ade7854_i2c_read_reg; + st->write_reg = ade7854_i2c_write_reg; st->i2c = client; st->irq = client->irq; diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index 4419b8f06197..fc9146757283 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -15,9 +15,10 @@ #include <linux/iio/iio.h> #include "ade7854.h" -static int ade7854_spi_write_reg_8(struct device *dev, - u16 reg_address, - u8 val) +static int ade7854_spi_write_reg(struct device *dev, + u16 reg_address, + u32 val, + int bits) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -32,173 +33,44 @@ static int ade7854_spi_write_reg_8(struct device *dev, st->tx[0] = ADE7854_WRITE_REG; st->tx[1] = (reg_address >> 8) & 0xFF; st->tx[2] = reg_address & 0xFF; - st->tx[3] = val & 0xFF; - - ret = spi_sync_transfer(st->spi, &xfer, 1); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_spi_write_reg_16(struct device *dev, - u16 reg_address, - u16 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 5, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_WRITE_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - st->tx[3] = (val >> 8) & 0xFF; - st->tx[4] = val & 0xFF; - - ret = spi_sync_transfer(st->spi, &xfer, 1); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_spi_write_reg_24(struct device *dev, - u16 reg_address, - u32 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 6, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_WRITE_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - st->tx[3] = (val >> 16) & 0xFF; - st->tx[4] = (val >> 8) & 0xFF; - st->tx[5] = val & 0xFF; - - ret = spi_sync_transfer(st->spi, &xfer, 1); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_spi_write_reg_32(struct device *dev, - u16 reg_address, - u32 val) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - struct spi_transfer xfer = { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 7, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_WRITE_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - st->tx[3] = (val >> 24) & 0xFF; - st->tx[4] = (val >> 16) & 0xFF; - st->tx[5] = (val >> 8) & 0xFF; - st->tx[6] = val & 0xFF; - - ret = spi_sync_transfer(st->spi, &xfer, 1); - mutex_unlock(&st->buf_lock); - - return ret; -} - -static int ade7854_spi_read_reg_8(struct device *dev, - u16 reg_address, - u8 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 3, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 1, - } - }; - - mutex_lock(&st->buf_lock); - - st->tx[0] = ADE7854_READ_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - - ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - if (ret) { - dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X", - reg_address); - goto error_ret; + switch (bits) { + case 8: + st->tx[3] = val & 0xFF; + break; + case 16: + xfer.len = 5; + st->tx[3] = (val >> 8) & 0xFF; + st->tx[4] = val & 0xFF; + break; + case 24: + xfer.len = 6; + st->tx[3] = (val >> 16) & 0xFF; + st->tx[4] = (val >> 8) & 0xFF; + st->tx[5] = val & 0xFF; + break; + case 32: + xfer.len = 7; + st->tx[3] = (val >> 24) & 0xFF; + st->tx[4] = (val >> 16) & 0xFF; + st->tx[5] = (val >> 8) & 0xFF; + st->tx[6] = val & 0xFF; + break; + default: + ret = -EINVAL; + goto unlock; } - *val = st->rx[0]; -error_ret: + ret = spi_sync_transfer(st->spi, &xfer, 1); +unlock: mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_spi_read_reg_16(struct device *dev, - u16 reg_address, - u16 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 3, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 2, - } - }; - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_READ_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - - ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - if (ret) { - dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X", - reg_address); - goto error_ret; - } - *val = be16_to_cpup((const __be16 *)st->rx); - -error_ret: - mutex_unlock(&st->buf_lock); return ret; } -static int ade7854_spi_read_reg_24(struct device *dev, - u16 reg_address, - u32 *val) +static int ade7854_spi_read_reg(struct device *dev, + u16 reg_address, + u32 *val, + int bits) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -211,7 +83,7 @@ static int ade7854_spi_read_reg_24(struct device *dev, }, { .rx_buf = st->rx, .bits_per_word = 8, - .len = 3, + .len = bits, } }; @@ -222,52 +94,28 @@ static int ade7854_spi_read_reg_24(struct device *dev, st->tx[2] = reg_address & 0xFF; ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - if (ret) { - dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X", + if (ret < 0) { + dev_err(&st->spi->dev, "problem when reading register 0x%02X", reg_address); - goto error_ret; + goto unlock; } - *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; - -error_ret: - mutex_unlock(&st->buf_lock); - return ret; -} - -static int ade7854_spi_read_reg_32(struct device *dev, - u16 reg_address, - u32 *val) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ade7854_state *st = iio_priv(indio_dev); - int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 3, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 4, - } - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADE7854_READ_REG; - st->tx[1] = (reg_address >> 8) & 0xFF; - st->tx[2] = reg_address & 0xFF; - - ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - if (ret) { - dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X", - reg_address); - goto error_ret; + switch (bits) { + case 8: + *val = st->rx[0]; + break; + case 16: + *val = be16_to_cpup((const __be16 *)st->rx); + break; + case 24: + *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; + break; + case 32: + *val = be32_to_cpup((const __be32 *)st->rx); + break; } - *val = be32_to_cpup((const __be32 *)st->rx); -error_ret: +unlock: mutex_unlock(&st->buf_lock); return ret; } @@ -282,14 +130,8 @@ static int ade7854_spi_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); spi_set_drvdata(spi, indio_dev); - st->read_reg_8 = ade7854_spi_read_reg_8; - st->read_reg_16 = ade7854_spi_read_reg_16; - st->read_reg_24 = ade7854_spi_read_reg_24; - st->read_reg_32 = ade7854_spi_read_reg_32; - st->write_reg_8 = ade7854_spi_write_reg_8; - st->write_reg_16 = ade7854_spi_write_reg_16; - st->write_reg_24 = ade7854_spi_write_reg_24; - st->write_reg_32 = ade7854_spi_write_reg_32; + st->read_reg = ade7854_spi_read_reg; + st->write_reg = ade7854_spi_write_reg; st->irq = spi->irq; st->spi = spi; diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index 90d07cdca4b8..029c3bf42d4d 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -27,13 +27,13 @@ static ssize_t ade7854_read_8bit(struct device *dev, char *buf) { int ret; - u8 val = 0; + u32 val = 0; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - ret = st->read_reg_8(dev, this_attr->address, &val); - if (ret) + ret = st->read_reg(dev, this_attr->address, &val, 8); + if (ret < 0) return ret; return sprintf(buf, "%u\n", val); @@ -44,13 +44,13 @@ static ssize_t ade7854_read_16bit(struct device *dev, char *buf) { int ret; - u16 val = 0; + u32 val = 0; struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - ret = st->read_reg_16(dev, this_attr->address, &val); - if (ret) + ret = st->read_reg(dev, this_attr->address, &val, 16); + if (ret < 0) return ret; return sprintf(buf, "%u\n", val); @@ -66,8 +66,8 @@ static ssize_t ade7854_read_24bit(struct device *dev, struct ade7854_state *st = iio_priv(indio_dev); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - ret = st->read_reg_24(dev, this_attr->address, &val); - if (ret) + ret = st->read_reg(dev, this_attr->address, &val, 24); + if (ret < 0) return ret; return sprintf(buf, "%u\n", val); @@ -83,8 +83,8 @@ static ssize_t ade7854_read_32bit(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); - ret = st->read_reg_32(dev, this_attr->address, &val); - if (ret) + ret = st->read_reg(dev, this_attr->address, &val, 32); + if (ret < 0) return ret; return sprintf(buf, "%u\n", val); @@ -105,7 +105,7 @@ static ssize_t ade7854_write_8bit(struct device *dev, ret = kstrtou8(buf, 10, &val); if (ret) goto error_ret; - ret = st->write_reg_8(dev, this_attr->address, val); + ret = st->write_reg(dev, this_attr->address, val, 8); error_ret: return ret ? ret : len; @@ -126,7 +126,7 @@ static ssize_t ade7854_write_16bit(struct device *dev, ret = kstrtou16(buf, 10, &val); if (ret) goto error_ret; - ret = st->write_reg_16(dev, this_attr->address, val); + ret = st->write_reg(dev, this_attr->address, val, 16); error_ret: return ret ? ret : len; @@ -147,7 +147,7 @@ static ssize_t ade7854_write_24bit(struct device *dev, ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; - ret = st->write_reg_24(dev, this_attr->address, val); + ret = st->write_reg(dev, this_attr->address, val, 24); error_ret: return ret ? ret : len; @@ -168,7 +168,7 @@ static ssize_t ade7854_write_32bit(struct device *dev, ret = kstrtou32(buf, 10, &val); if (ret) goto error_ret; - ret = st->write_reg_32(dev, this_attr->address, val); + ret = st->write_reg(dev, this_attr->address, val, 32); error_ret: return ret ? ret : len; @@ -178,12 +178,12 @@ static int ade7854_reset(struct device *dev) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); - u16 val; + u32 val; - st->read_reg_16(dev, ADE7854_CONFIG, &val); + st->read_reg(dev, ADE7854_CONFIG, &val, 16); val |= BIT(7); /* Software Chip Reset */ - return st->write_reg_16(dev, ADE7854_CONFIG, val); + return st->write_reg(dev, ADE7854_CONFIG, val, 16); } static IIO_DEV_ATTR_AIGAIN(0644, @@ -415,8 +415,8 @@ static int ade7854_set_irq(struct device *dev, bool enable) int ret; u32 irqen; - ret = st->read_reg_32(dev, ADE7854_MASK0, &irqen); - if (ret) + ret = st->read_reg(dev, ADE7854_MASK0, &irqen, 32); + if (ret < 0) return ret; if (enable) @@ -426,7 +426,7 @@ static int ade7854_set_irq(struct device *dev, bool enable) else irqen &= ~BIT(17); - return st->write_reg_32(dev, ADE7854_MASK0, irqen); + return st->write_reg(dev, ADE7854_MASK0, irqen, 32); } static int ade7854_initial_setup(struct iio_dev *indio_dev) diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h index a82d38224cbd..a51e6e3183d3 100644 --- a/drivers/staging/iio/meter/ade7854.h +++ b/drivers/staging/iio/meter/ade7854.h @@ -145,7 +145,9 @@ /** * struct ade7854_state - device instance specific data - * @spi: actual spi_device + * @spi: actual spi_device + * @read_reg Wrapper function for I2C and SPI read + * @write_reg Wrapper function for I2C and SPI write * @indio_dev: industrial I/O device structure * @buf_lock: mutex to protect tx and rx * @tx: transmit buffer @@ -154,14 +156,10 @@ struct ade7854_state { struct spi_device *spi; struct i2c_client *i2c; - int (*read_reg_8)(struct device *dev, u16 reg_address, u8 *val); - int (*read_reg_16)(struct device *dev, u16 reg_address, u16 *val); - int (*read_reg_24)(struct device *dev, u16 reg_address, u32 *val); - int (*read_reg_32)(struct device *dev, u16 reg_address, u32 *val); - int (*write_reg_8)(struct device *dev, u16 reg_address, u8 val); - int (*write_reg_16)(struct device *dev, u16 reg_address, u16 val); - int (*write_reg_24)(struct device *dev, u16 reg_address, u32 val); - int (*write_reg_32)(struct device *dev, u16 reg_address, u32 val); + int (*read_reg)(struct device *dev, u16 reg_address, u32 *val, + int bits); + int (*write_reg)(struct device *dev, u16 reg_address, u32 val, + int bits); int irq; struct mutex buf_lock; u8 tx[ADE7854_MAX_TX] ____cacheline_aligned; diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index aa62c64e9bc4..ea7336645116 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -9,16 +9,16 @@ * published by the Free Software Foundation. * */ -#include <linux/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> + +#include <linux/bitops.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/gpio.h> #include <linux/module.h> -#include <linux/bitops.h> +#include <linux/mutex.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/types.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -38,7 +38,7 @@ struct ad2s1200_state { struct spi_device *sdev; int sample; int rdvel; - u8 rx[2] ____cacheline_aligned; + __be16 rx ____cacheline_aligned; }; static int ad2s1200_read_raw(struct iio_dev *indio_dev, @@ -47,17 +47,18 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev, int *val2, long m) { - int ret = 0; - s16 vel; struct ad2s1200_state *st = iio_priv(indio_dev); + int ret = 0; mutex_lock(&st->lock); gpio_set_value(st->sample, 0); + /* delay (6 * AD2S1200_TSCLK + 20) nano seconds */ udelay(1); gpio_set_value(st->sample, 1); gpio_set_value(st->rdvel, !!(chan->type == IIO_ANGL)); - ret = spi_read(st->sdev, st->rx, 2); + + ret = spi_read(st->sdev, &st->rx, 2); if (ret < 0) { mutex_unlock(&st->lock); return ret; @@ -65,20 +66,20 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_ANGL: - *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); + *val = be16_to_cpup(&st->rx) >> 4; break; case IIO_ANGL_VEL: - vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); - vel = sign_extend32(vel, 11); - *val = vel; + *val = sign_extend32(be16_to_cpup(&st->rx) >> 4, 11); break; default: mutex_unlock(&st->lock); return -EINVAL; } + /* delay (2 * AD2S1200_TSCLK + 20) ns for sample pulse */ udelay(1); mutex_unlock(&st->lock); + return IIO_VAL_INT; } @@ -102,10 +103,10 @@ static const struct iio_info ad2s1200_info = { static int ad2s1200_probe(struct spi_device *spi) { + unsigned short *pins = spi->dev.platform_data; struct ad2s1200_state *st; struct iio_dev *indio_dev; int pn, ret = 0; - unsigned short *pins = spi->dev.platform_data; for (pn = 0; pn < AD2S1200_PN; pn++) { ret = devm_gpio_request_one(&spi->dev, pins[pn], GPIOF_DIR_OUT, @@ -116,9 +117,11 @@ static int ad2s1200_probe(struct spi_device *spi) return ret; } } + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; + spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); mutex_init(&st->lock); diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 1fc7abd28b0b..730ead1a46df 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -127,7 +127,7 @@ void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev); int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); #define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, _extend_name, _type) \ + _storagebits, _shift, _extend_name, _type, _mask_all) \ { \ .type = (_type), \ .differential = (_channel2 == -1 ? 0 : 1), \ @@ -139,7 +139,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all = _mask_all, \ .scan_index = (_si), \ .scan_type = { \ .sign = 'u', \ @@ -153,25 +153,35 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); #define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE) + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \ - _storagebits, _shift, "shorted", IIO_VOLTAGE) + _storagebits, _shift, "shorted", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_CHANNEL(_si, _channel, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE) + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD_SD_CHANNEL_NO_SAMP_FREQ(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, 0) #define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \ __AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_TEMP) + _storagebits, _shift, NULL, IIO_TEMP, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ _shift) \ __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, "supply", IIO_VOLTAGE) + _storagebits, _shift, "supply", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #endif diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h index 2edf68dc7336..ce16445411ac 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.h +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -16,7 +16,9 @@ #ifndef __CROS_EC_SENSORS_CORE_H #define __CROS_EC_SENSORS_CORE_H +#include <linux/iio/iio.h> #include <linux/irqreturn.h> +#include <linux/mfd/cros_ec.h> enum { CROS_EC_SENSOR_X, @@ -103,6 +105,7 @@ int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask, int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask, s16 *data); +struct platform_device; /** * cros_ec_sensors_core_init() - basic initialization of the core structure * @pdev: platform device created for the sensors diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 11579fd4126e..a74cb177dc6f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -183,18 +183,18 @@ struct iio_event_spec { * @address: Driver specific identifier. * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. - * @scan_type: sign: 's' or 'u' to specify signed or unsigned - * realbits: Number of valid bits of data - * storagebits: Realbits + padding - * shift: Shift right by this before masking out - * realbits. - * repeat: Number of times real/storage bits - * repeats. When the repeat element is - * more than 1, then the type element in - * sysfs will show a repeat value. - * Otherwise, the number of repetitions is - * omitted. - * endianness: little or big endian + * @scan_type: struct describing the scan type + * @scan_type.sign: 's' or 'u' to specify signed or unsigned + * @scan_type.realbits: Number of valid bits of data + * @scan_type.storagebits: Realbits + padding + * @scan_type.shift: Shift right by this before masking out + * realbits. + * @scan_type.repeat: Number of times real/storage bits repeats. + * When the repeat element is more than 1, then + * the type element in sysfs will show a repeat + * value. Otherwise, the number of repetitions + * is omitted. + * @scan_type.endianness: little or big endian * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be |