diff options
93 files changed, 6842 insertions, 2875 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index fee35c00cc4e..b8f220f978dd 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -329,6 +329,7 @@ What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale 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 KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -1579,3 +1580,20 @@ Contact: linux-iio@vger.kernel.org Description: Raw (unscaled no offset etc.) electric conductivity reading that can be processed to siemens per meter. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_raw +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Raw counter device counts from channel Y. For quadrature + counters, multiplication by an available [Y]_scale results in + the counts of a single quadrature signal phase from channel Y. + +What: /sys/bus/iio/devices/iio:deviceX/in_indexY_raw +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Raw counter device index value from channel Y. This attribute + provides an absolute positional reference (e.g. a pulse once per + revolution) which may be used to home positional systems as + required. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 new file mode 100644 index 000000000000..ba676520b953 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8 @@ -0,0 +1,125 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_count_count_direction_available +What: /sys/bus/iio/devices/iio:deviceX/in_count_count_mode_available +What: /sys/bus/iio/devices/iio:deviceX/in_count_noise_error_available +What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available +What: /sys/bus/iio/devices/iio:deviceX/in_index_index_polarity_available +What: /sys/bus/iio/devices/iio:deviceX/in_index_synchronous_mode_available +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Discrete set of available values for the respective counter + configuration are listed in this file. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_direction +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Read-only attribute that indicates whether the counter for + channel Y is counting up or down. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_count_mode +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Count mode for channel Y. Four count modes are available: + normal, range limit, non-recycle, and modulo-n. The preset value + for channel Y is used by the count mode where required. + + Normal: + Counting is continuous in either direction. + + Range Limit: + An upper or lower limit is set, mimicking limit switches + in the mechanical counterpart. The upper limit is set to + the preset value, while the lower limit is set to 0. The + counter freezes at count = preset when counting up, and + at count = 0 when counting down. At either of these + limits, the counting is resumed only when the count + direction is reversed. + + Non-recycle: + Counter is disabled whenever a 24-bit count overflow or + underflow takes place. The counter is re-enabled when a + new count value is loaded to the counter via a preset + operation or write to raw. + + Modulo-N: + A count boundary is set between 0 and the preset value. + The counter is reset to 0 at count = preset when + counting up, while the counter is set to the preset + value at count = 0 when counting down; the counter does + not freeze at the bundary points, but counts + continuously throughout. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_noise_error +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Read-only attribute that indicates whether excessive noise is + present at the channel Y count inputs in quadrature clock mode; + irrelevant in non-quadrature clock mode. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_preset +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + If the counter device supports preset registers, the preset + count for channel Y is provided by this attribute. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_quadrature_mode +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Configure channel Y counter for non-quadrature or quadrature + clock mode. Selecting non-quadrature clock mode will disable + synchronous load mode. In quadrature clock mode, the channel Y + scale attribute selects the encoder phase division (scale of 1 + selects full-cycle, scale of 0.5 selects half-cycle, scale of + 0.25 selects quarter-cycle) processed by the channel Y counter. + + Non-quadrature: + The filter and decoder circuit are bypassed. Encoder A + input serves as the count input and B as the UP/DOWN + direction control input, with B = 1 selecting UP Count + mode and B = 0 selecting Down Count mode. + + Quadrature: + Encoder A and B inputs are digitally filtered and + decoded for UP/DN clock. + +What: /sys/bus/iio/devices/iio:deviceX/in_countY_set_to_preset_on_index +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Whether to set channel Y counter with channel Y preset value + when channel Y index input is active, or continuously count. + Valid attribute values are boolean. + +What: /sys/bus/iio/devices/iio:deviceX/in_indexY_index_polarity +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Active level of channel Y index input; irrelevant in + non-synchronous load mode. + +What: /sys/bus/iio/devices/iio:deviceX/in_indexY_synchronous_mode +KernelVersion: 4.9 +Contact: linux-iio@vger.kernel.org +Description: + Configure channel Y counter for non-synchronous or synchronous + load mode. Synchronous load mode cannot be selected in + non-quadrature clock mode. + + Non-synchronous: + A logic low level is the active level at this index + input. The index function (as enabled via + set_to_preset_on_index) is performed directly on the + active level of the index input. + + Synchronous: + Intended for interfacing with encoder Index output in + quadrature clock mode. The active level is configured + via index_polarity. The index function (as enabled via + set_to_preset_on_index) is performed synchronously with + the quadrature clock on the active level of the index + input. diff --git a/Documentation/ABI/testing/sysfs-bus-iio-light-isl29018 b/Documentation/ABI/testing/sysfs-bus-iio-light-isl29018 new file mode 100644 index 000000000000..f0ce0a0476ea --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-light-isl29018 @@ -0,0 +1,19 @@ +What: /sys/bus/iio/devices/iio:deviceX/proximity_on_chip_ambient_infrared_suppression +Date: January 2011 +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the + infrared suppression: + + Scheme 0, makes full n (4, 8, 12, 16) bits (unsigned) proximity + detection. The range of Scheme 0 proximity count is from 0 to + 2^n. Logic 1 of this bit, Scheme 1, makes n-1 (3, 7, 11, 15) + bits (2's complementary) proximity_less_ambient detection. The + range of Scheme 1 proximity count is from -2^(n-1) to 2^(n-1). + The sign bit is extended for resolutions less than 16. While + Scheme 0 has wider dynamic range, Scheme 1 proximity detection + is less affected by the ambient IR noise variation. + + 0 Sensing IR from LED and ambient + 1 Sensing IR from LED with ambient IR rejection diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index fbbad6446741..6e4ba816094b 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -39,11 +39,13 @@ dallas,ds75 Digital Thermometer and Thermostat dlg,da9053 DA9053: flexible system level PMIC with multicore support dlg,da9063 DA9063: system PMIC for quad-core application processors domintech,dmard09 DMARD09: 3-axis Accelerometer +domintech,dmard10 DMARD10: 3-axis Accelerometer epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer fsl,mc13892 MC13892: Power Management Integrated Circuit (PMIC) for i.MX35/51 +fsl,mma7660 MMA7660FC: 3-Axis Orientation/Motion Detection Sensor fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer fsl,mpl3115 MPL3115: Absolute Digital Pressure Sensor fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller @@ -57,6 +59,7 @@ maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface mc,rv3029c2 Real Time Clock Module with I2C-Bus mcube,mc3230 mCube 3-axis 8-bit digital accelerometer +memsic,mxc6225 MEMSIC 2-axis 8-bit digital accelerometer microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k) microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k) microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k) @@ -121,6 +124,9 @@ microchip,mcp4662-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Mem microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) +miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer +miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer +miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer national,lm63 Temperature sensor with integrated fan control national,lm75 I2C TEMP SENSOR national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc161s626.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc161s626.txt index 9ed2315781e4..3d25011f0c99 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti-adc161s626.txt +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc161s626.txt @@ -3,6 +3,7 @@ Required properties: - compatible: Should be "ti,adc141s626" or "ti,adc161s626" - reg: spi chip select number for the device + - vdda-supply: supply voltage to VDDA pin Recommended properties: - spi-max-frequency: Definition as per @@ -11,6 +12,7 @@ Recommended properties: Example: adc@0 { compatible = "ti,adc161s626"; + vdda-supply = <&vdda_fixed>; reg = <0>; spi-max-frequency = <4300000>; }; diff --git a/Documentation/devicetree/bindings/iio/dac/mcp4725.txt b/Documentation/devicetree/bindings/iio/dac/mcp4725.txt new file mode 100644 index 000000000000..1bc6c093fbfe --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/mcp4725.txt @@ -0,0 +1,35 @@ +Microchip mcp4725 and mcp4726 DAC device driver + +Required properties: + - compatible: Must be "microchip,mcp4725" or "microchip,mcp4726" + - reg: Should contain the DAC I2C address + - vdd-supply: Phandle to the Vdd power supply. This supply is used as a + voltage reference on mcp4725. It is used as a voltage reference on + mcp4726 if there is no vref-supply specified. + +Optional properties (valid only for mcp4726): + - vref-supply: Optional phandle to the Vref power supply. Vref pin is + used as a voltage reference when this supply is specified. + - microchip,vref-buffered: Boolean to enable buffering of the external + Vref pin. This boolean is not valid without the vref-supply. Quoting + the datasheet: This is offered in cases where the reference voltage + does not have the current capability not to drop its voltage when + connected to the internal resistor ladder circuit. + +Examples: + + /* simple mcp4725 */ + mcp4725@60 { + compatible = "microchip,mcp4725"; + reg = <0x60>; + vdd-supply = <&vdac_vdd>; + }; + + /* mcp4726 with the buffered external reference voltage */ + mcp4726@60 { + compatible = "microchip,mcp4726"; + reg = <0x60>; + vdd-supply = <&vdac_vdd>; + vref-supply = <&vdac_vref>; + microchip,vref-buffered; + }; diff --git a/Documentation/devicetree/bindings/iio/humidity/hts221.txt b/Documentation/devicetree/bindings/iio/humidity/hts221.txt new file mode 100644 index 000000000000..b20ab9c12080 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/humidity/hts221.txt @@ -0,0 +1,22 @@ +* HTS221 STM humidity + temperature sensor + +Required properties: +- compatible: should be "st,hts221" +- reg: i2c address of the sensor / spi cs line + +Optional properties: +- interrupt-parent: should be the phandle for the interrupt controller +- interrupts: interrupt mapping for IRQ. It should be configured with + flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt + client node bindings. + +Example: + +hts221@5f { + compatible = "st,hts221"; + reg = <0x5f>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/Documentation/devicetree/bindings/iio/light/isl29018.txt b/Documentation/devicetree/bindings/iio/light/isl29018.txt new file mode 100644 index 000000000000..425ab459e209 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/isl29018.txt @@ -0,0 +1,28 @@ +* ISL 29018/29023/29035 I2C ALS, Proximity, and Infrared sensor + +Required properties: + + - compatible: Should be one of + "isil,isl29018" + "isil,isl29023" + "isil,isl29035" + - reg: the I2C address of the device + +Optional properties: + + - interrupt-parent: should be the phandle for the interrupt controller + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + + - vcc-supply: phandle to the regulator that provides power to the sensor. + +Example: + +isl29018@44 { + compatible = "isil,isl29018"; + reg = <0x44>; + interrupt-parent = <&gpio>; + interrupts = <TEGRA_GPIO(Z, 2) IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/Documentation/devicetree/bindings/iio/potentiostat/lmp91000.txt b/Documentation/devicetree/bindings/iio/potentiostat/lmp91000.txt new file mode 100644 index 000000000000..b9b621e94cd7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/potentiostat/lmp91000.txt @@ -0,0 +1,30 @@ +* Texas Instruments LMP91000 potentiostat + +http://www.ti.com/lit/ds/symlink/lmp91000.pdf + +Required properties: + + - compatible: should be "ti,lmp91000" + - reg: the I2C address of the device + - io-channels: the phandle of the iio provider + + - ti,external-tia-resistor: if the property ti,tia-gain-ohm is not defined this + needs to be set to signal that an external resistor value is being used. + +Optional properties: + + - ti,tia-gain-ohm: ohm value of the internal resistor for the transimpedance + amplifier. Must be 2750, 3500, 7000, 14000, 35000, 120000, or 350000 ohms. + + - ti,rload-ohm: ohm value of the internal resistor load applied to the gas + sensor. Must be 10, 33, 50, or 100 (default) ohms. + +Example: + +lmp91000@48 { + compatible = "ti,lmp91000"; + reg = <0x48>; + ti,tia-gain-ohm = <7500>; + ti,rload = <100>; + io-channels = <&adc>; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index f0a48ea78659..8d04aa99187c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -160,16 +160,19 @@ lltc Linear Technology Corporation lsi LSI Corp. (LSI Logic) marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products +mcube mCube meas Measurement Specialties mediatek MediaTek Inc. melexis Melexis N.V. melfas MELFAS Inc. +memsic MEMSIC Inc. merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. microcrystal Micro Crystal AG micron Micron Technology Inc. minix MINIX Technology Ltd. +miramems MiraMEMS Sensing Technology Co., Ltd. mitsubishi Mitsubishi Electric Corporation mosaixtech Mosaix Technologies, Inc. moxa Moxa diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064..7084d8e8592f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -255,6 +255,12 @@ L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-104-idio-16.c +ACCES 104-QUAD-8 IIO DRIVER +M: William Breathitt Gray <vilhelm.gray@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: drivers/iio/counter/104-quad-8.c + ACENIC DRIVER M: Jes Sorensen <jes@trained-monkey.org> L: linux-acenic@sunsite.dk @@ -787,7 +793,7 @@ S: Supported F: drivers/iio/*/ad* X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* -F: staging/iio/trigger/iio-trig-bfin-timer.c +F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c ANALOG DEVICES INC DMA DRIVERS M: Lars-Peter Clausen <lars@metafoo.de> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 6743b18194fb..a918270d6f54 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -73,6 +73,7 @@ source "drivers/iio/adc/Kconfig" source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/chemical/Kconfig" source "drivers/iio/common/Kconfig" +source "drivers/iio/counter/Kconfig" source "drivers/iio/dac/Kconfig" source "drivers/iio/dummy/Kconfig" source "drivers/iio/frequency/Kconfig" @@ -87,6 +88,7 @@ if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER source "drivers/iio/potentiometer/Kconfig" +source "drivers/iio/potentiostat/Kconfig" source "drivers/iio/pressure/Kconfig" source "drivers/iio/proximity/Kconfig" source "drivers/iio/temperature/Kconfig" diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 87e4c4369e2f..33fa4026f92c 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -18,6 +18,7 @@ obj-y += amplifiers/ obj-y += buffer/ obj-y += chemical/ obj-y += common/ +obj-y += counter/ obj-y += dac/ obj-y += dummy/ obj-y += gyro/ @@ -29,6 +30,7 @@ obj-y += light/ obj-y += magnetometer/ obj-y += orientation/ obj-y += potentiometer/ +obj-y += potentiostat/ obj-y += pressure/ obj-y += proximity/ obj-y += temperature/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 2b791fe1e2bc..c6cc2c0909a1 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -52,6 +52,26 @@ config BMC150_ACCEL_SPI tristate select REGMAP_SPI +config DA280 + tristate "MiraMEMS DA280 3-axis 14-bit digital accelerometer driver" + depends on I2C + help + Say yes here to build support for the MiraMEMS DA280 3-axis 14-bit + digital accelerometer. + + To compile this driver as a module, choose M here: the + module will be called da280. + +config DA311 + tristate "MiraMEMS DA311 3-axis 12-bit digital accelerometer driver" + depends on I2C + help + Say yes here to build support for the MiraMEMS DA311 3-axis 12-bit + digital accelerometer. + + To compile this driver as a module, choose M here: the + module will be called da311. + config DMARD06 tristate "Domintech DMARD06 Digital Accelerometer Driver" depends on OF || COMPILE_TEST @@ -73,6 +93,16 @@ config DMARD09 Choosing M will build the driver as a module. If so, the module will be called dmard09. +config DMARD10 + tristate "Domintech DMARD10 3-axis Accelerometer Driver" + depends on I2C + help + Say yes here to get support for the Domintech DMARD10 3-axis + accelerometer. + + Choosing M will build the driver as a module. If so, the module + will be called dmard10. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER @@ -273,6 +303,18 @@ config MXC6255 To compile this driver as a module, choose M here: the module will be called mxc6255. +config SCA3000 + select IIO_BUFFER + select IIO_KFIFO_BUF + depends on SPI + tristate "VTI SCA3000 series accelerometers" + help + Say Y here to build support for the VTI SCA3000 series of SPI + accelerometers. These devices use a hardware ring buffer. + + To compile this driver as a module, say M here: the module will be + called sca3000. + config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index f5d3ddee619e..69fe8edc57a2 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -8,8 +8,11 @@ obj-$(CONFIG_BMA220) += bma220_spi.o obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o +obj-$(CONFIG_DA280) += da280.o +obj-$(CONFIG_DA311) += da311.o obj-$(CONFIG_DMARD06) += dmard06.o obj-$(CONFIG_DMARD09) += dmard09.o +obj-$(CONFIG_DMARD10) += dmard10.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o @@ -32,6 +35,8 @@ obj-$(CONFIG_MMA9553) += mma9553.o obj-$(CONFIG_MXC4005) += mxc4005.o obj-$(CONFIG_MXC6255) += mxc6255.o +obj-$(CONFIG_SCA3000) += sca3000.o + obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o diff --git a/drivers/iio/accel/da280.c b/drivers/iio/accel/da280.c new file mode 100644 index 000000000000..ed8343aeac9c --- /dev/null +++ b/drivers/iio/accel/da280.c @@ -0,0 +1,183 @@ +/** + * IIO driver for the MiraMEMS DA280 3-axis accelerometer and + * IIO driver for the MiraMEMS DA226 2-axis accelerometer + * + * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/byteorder/generic.h> + +#define DA280_REG_CHIP_ID 0x01 +#define DA280_REG_ACC_X_LSB 0x02 +#define DA280_REG_ACC_Y_LSB 0x04 +#define DA280_REG_ACC_Z_LSB 0x06 +#define DA280_REG_MODE_BW 0x11 + +#define DA280_CHIP_ID 0x13 +#define DA280_MODE_ENABLE 0x1e +#define DA280_MODE_DISABLE 0x9e + +enum { da226, da280 }; + +/* + * a value of + or -4096 corresponds to + or - 1G + * scale = 9.81 / 4096 = 0.002395019 + */ + +static const int da280_nscale = 2395019; + +#define DA280_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec da280_channels[] = { + DA280_CHANNEL(DA280_REG_ACC_X_LSB, X), + DA280_CHANNEL(DA280_REG_ACC_Y_LSB, Y), + DA280_CHANNEL(DA280_REG_ACC_Z_LSB, Z), +}; + +struct da280_data { + struct i2c_client *client; +}; + +static int da280_enable(struct i2c_client *client, bool enable) +{ + u8 data = enable ? DA280_MODE_ENABLE : DA280_MODE_DISABLE; + + return i2c_smbus_write_byte_data(client, DA280_REG_MODE_BW, data); +} + +static int da280_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct da280_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + /* + * Values are 14 bits, stored as 16 bits with the 2 + * least significant bits always 0. + */ + *val = (short)ret >> 2; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = da280_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info da280_info = { + .driver_module = THIS_MODULE, + .read_raw = da280_read_raw, +}; + +static int da280_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct da280_data *data; + + ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID); + if (ret != DA280_CHIP_ID) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &da280_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = da280_channels; + if (id->driver_data == da226) { + indio_dev->name = "da226"; + indio_dev->num_channels = 2; + } else { + indio_dev->name = "da280"; + indio_dev->num_channels = 3; + } + + ret = da280_enable(client, true); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + da280_enable(client, false); + } + + return ret; +} + +static int da280_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return da280_enable(client, false); +} + +#ifdef CONFIG_PM_SLEEP +static int da280_suspend(struct device *dev) +{ + return da280_enable(to_i2c_client(dev), false); +} + +static int da280_resume(struct device *dev) +{ + return da280_enable(to_i2c_client(dev), true); +} +#endif + +static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume); + +static const struct i2c_device_id da280_i2c_id[] = { + { "da226", da226 }, + { "da280", da280 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, da280_i2c_id); + +static struct i2c_driver da280_driver = { + .driver = { + .name = "da280", + .pm = &da280_pm_ops, + }, + .probe = da280_probe, + .remove = da280_remove, + .id_table = da280_i2c_id, +}; + +module_i2c_driver(da280_driver); + +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("MiraMEMS DA280 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/da311.c b/drivers/iio/accel/da311.c new file mode 100644 index 000000000000..537cfa8b6edf --- /dev/null +++ b/drivers/iio/accel/da311.c @@ -0,0 +1,305 @@ +/** + * IIO driver for the MiraMEMS DA311 3-axis accelerometer + * + * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> + * Copyright (c) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/byteorder/generic.h> + +#define DA311_CHIP_ID 0x13 + +/* + * Note register addressed go from 0 - 0x3f and then wrap. + * For some reason there are 2 banks with 0 - 0x3f addresses, + * rather then a single 0-0x7f bank. + */ + +/* Bank 0 regs */ +#define DA311_REG_BANK 0x0000 +#define DA311_REG_LDO_REG 0x0006 +#define DA311_REG_CHIP_ID 0x000f +#define DA311_REG_TEMP_CFG_REG 0x001f +#define DA311_REG_CTRL_REG1 0x0020 +#define DA311_REG_CTRL_REG3 0x0022 +#define DA311_REG_CTRL_REG4 0x0023 +#define DA311_REG_CTRL_REG5 0x0024 +#define DA311_REG_CTRL_REG6 0x0025 +#define DA311_REG_STATUS_REG 0x0027 +#define DA311_REG_OUT_X_L 0x0028 +#define DA311_REG_OUT_X_H 0x0029 +#define DA311_REG_OUT_Y_L 0x002a +#define DA311_REG_OUT_Y_H 0x002b +#define DA311_REG_OUT_Z_L 0x002c +#define DA311_REG_OUT_Z_H 0x002d +#define DA311_REG_INT1_CFG 0x0030 +#define DA311_REG_INT1_SRC 0x0031 +#define DA311_REG_INT1_THS 0x0032 +#define DA311_REG_INT1_DURATION 0x0033 +#define DA311_REG_INT2_CFG 0x0034 +#define DA311_REG_INT2_SRC 0x0035 +#define DA311_REG_INT2_THS 0x0036 +#define DA311_REG_INT2_DURATION 0x0037 +#define DA311_REG_CLICK_CFG 0x0038 +#define DA311_REG_CLICK_SRC 0x0039 +#define DA311_REG_CLICK_THS 0x003a +#define DA311_REG_TIME_LIMIT 0x003b +#define DA311_REG_TIME_LATENCY 0x003c +#define DA311_REG_TIME_WINDOW 0x003d + +/* Bank 1 regs */ +#define DA311_REG_SOFT_RESET 0x0105 +#define DA311_REG_OTP_XOFF_L 0x0110 +#define DA311_REG_OTP_XOFF_H 0x0111 +#define DA311_REG_OTP_YOFF_L 0x0112 +#define DA311_REG_OTP_YOFF_H 0x0113 +#define DA311_REG_OTP_ZOFF_L 0x0114 +#define DA311_REG_OTP_ZOFF_H 0x0115 +#define DA311_REG_OTP_XSO 0x0116 +#define DA311_REG_OTP_YSO 0x0117 +#define DA311_REG_OTP_ZSO 0x0118 +#define DA311_REG_OTP_TRIM_OSC 0x011b +#define DA311_REG_LPF_ABSOLUTE 0x011c +#define DA311_REG_TEMP_OFF1 0x0127 +#define DA311_REG_TEMP_OFF2 0x0128 +#define DA311_REG_TEMP_OFF3 0x0129 +#define DA311_REG_OTP_TRIM_THERM_H 0x011a + +/* + * a value of + or -1024 corresponds to + or - 1G + * scale = 9.81 / 1024 = 0.009580078 + */ + +static const int da311_nscale = 9580078; + +#define DA311_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec da311_channels[] = { + /* | 0x80 comes from the android driver */ + DA311_CHANNEL(DA311_REG_OUT_X_L | 0x80, X), + DA311_CHANNEL(DA311_REG_OUT_Y_L | 0x80, Y), + DA311_CHANNEL(DA311_REG_OUT_Z_L | 0x80, Z), +}; + +struct da311_data { + struct i2c_client *client; +}; + +static int da311_register_mask_write(struct i2c_client *client, u16 addr, + u8 mask, u8 data) +{ + int ret; + u8 tmp_data = 0; + + if (addr & 0xff00) { + /* Select bank 1 */ + ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x01); + if (ret < 0) + return ret; + } + + if (mask != 0xff) { + ret = i2c_smbus_read_byte_data(client, addr); + if (ret < 0) + return ret; + tmp_data = ret; + } + + tmp_data &= ~mask; + tmp_data |= data & mask; + ret = i2c_smbus_write_byte_data(client, addr & 0xff, tmp_data); + if (ret < 0) + return ret; + + if (addr & 0xff00) { + /* Back to bank 0 */ + ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, 0x00); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Init sequence taken from the android driver */ +static int da311_reset(struct i2c_client *client) +{ + const struct { + u16 addr; + u8 mask; + u8 data; + } init_data[] = { + { DA311_REG_TEMP_CFG_REG, 0xff, 0x08 }, + { DA311_REG_CTRL_REG5, 0xff, 0x80 }, + { DA311_REG_CTRL_REG4, 0x30, 0x00 }, + { DA311_REG_CTRL_REG1, 0xff, 0x6f }, + { DA311_REG_TEMP_CFG_REG, 0xff, 0x88 }, + { DA311_REG_LDO_REG, 0xff, 0x02 }, + { DA311_REG_OTP_TRIM_OSC, 0xff, 0x27 }, + { DA311_REG_LPF_ABSOLUTE, 0xff, 0x30 }, + { DA311_REG_TEMP_OFF1, 0xff, 0x3f }, + { DA311_REG_TEMP_OFF2, 0xff, 0xff }, + { DA311_REG_TEMP_OFF3, 0xff, 0x0f }, + }; + int i, ret; + + /* Reset */ + ret = da311_register_mask_write(client, DA311_REG_SOFT_RESET, + 0xff, 0xaa); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(init_data); i++) { + ret = da311_register_mask_write(client, + init_data[i].addr, + init_data[i].mask, + init_data[i].data); + if (ret < 0) + return ret; + } + + return 0; +} + +static int da311_enable(struct i2c_client *client, bool enable) +{ + u8 data = enable ? 0x00 : 0x20; + + return da311_register_mask_write(client, DA311_REG_TEMP_CFG_REG, + 0x20, data); +} + +static int da311_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct da311_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) + return ret; + /* + * Values are 12 bits, stored as 16 bits with the 4 + * least significant bits always 0. + */ + *val = (short)ret >> 4; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = da311_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info da311_info = { + .driver_module = THIS_MODULE, + .read_raw = da311_read_raw, +}; + +static int da311_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct da311_data *data; + + ret = i2c_smbus_read_byte_data(client, DA311_REG_CHIP_ID); + if (ret != DA311_CHIP_ID) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &da311_info; + indio_dev->name = "da311"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = da311_channels; + indio_dev->num_channels = ARRAY_SIZE(da311_channels); + + ret = da311_reset(client); + if (ret < 0) + return ret; + + ret = da311_enable(client, true); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + da311_enable(client, false); + } + + return ret; +} + +static int da311_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return da311_enable(client, false); +} + +#ifdef CONFIG_PM_SLEEP +static int da311_suspend(struct device *dev) +{ + return da311_enable(to_i2c_client(dev), false); +} + +static int da311_resume(struct device *dev) +{ + return da311_enable(to_i2c_client(dev), true); +} +#endif + +static SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); + +static const struct i2c_device_id da311_i2c_id[] = { + {"da311", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, da311_i2c_id); + +static struct i2c_driver da311_driver = { + .driver = { + .name = "da311", + .pm = &da311_pm_ops, + }, + .probe = da311_probe, + .remove = da311_remove, + .id_table = da311_i2c_id, +}; + +module_i2c_driver(da311_driver); + +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("MiraMEMS DA311 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/dmard10.c b/drivers/iio/accel/dmard10.c new file mode 100644 index 000000000000..b8736cc75656 --- /dev/null +++ b/drivers/iio/accel/dmard10.c @@ -0,0 +1,266 @@ +/** + * IIO driver for the 3-axis accelerometer Domintech ARD10. + * + * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> + * Copyright (c) 2012 Domintech Technology Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/byteorder/generic.h> + +#define DMARD10_REG_ACTR 0x00 +#define DMARD10_REG_AFEM 0x0c +#define DMARD10_REG_STADR 0x12 +#define DMARD10_REG_STAINT 0x1c +#define DMARD10_REG_MISC2 0x1f +#define DMARD10_REG_PD 0x21 + +#define DMARD10_MODE_OFF 0x00 +#define DMARD10_MODE_STANDBY 0x02 +#define DMARD10_MODE_ACTIVE 0x06 +#define DMARD10_MODE_READ_OTP 0x12 +#define DMARD10_MODE_RESET_DATA_PATH 0x82 + +/* AFEN set 1, ATM[2:0]=b'000 (normal), EN_Z/Y/X/T=1 */ +#define DMARD10_VALUE_AFEM_AFEN_NORMAL 0x8f +/* ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) */ +#define DMARD10_VALUE_CKSEL_ODR_100_204 0x74 +/* INTC[6:5]=b'00 */ +#define DMARD10_VALUE_INTC 0x00 +/* TAP1/TAP2 Average 2 */ +#define DMARD10_VALUE_TAPNS_AVE_2 0x11 + +#define DMARD10_VALUE_STADR 0x55 +#define DMARD10_VALUE_STAINT 0xaa +#define DMARD10_VALUE_MISC2_OSCA_EN 0x08 +#define DMARD10_VALUE_PD_RST 0x52 + +/* Offsets into the buffer read in dmard10_read_raw() */ +#define DMARD10_X_OFFSET 1 +#define DMARD10_Y_OFFSET 2 +#define DMARD10_Z_OFFSET 3 + +/* + * a value of + or -128 corresponds to + or - 1G + * scale = 9.81 / 128 = 0.076640625 + */ + +static const int dmard10_nscale = 76640625; + +#define DMARD10_CHANNEL(reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec dmard10_channels[] = { + DMARD10_CHANNEL(DMARD10_X_OFFSET, X), + DMARD10_CHANNEL(DMARD10_Y_OFFSET, Y), + DMARD10_CHANNEL(DMARD10_Z_OFFSET, Z), +}; + +struct dmard10_data { + struct i2c_client *client; +}; + +/* Init sequence taken from the android driver */ +static int dmard10_reset(struct i2c_client *client) +{ + unsigned char buffer[7]; + int ret; + + /* 1. Powerdown reset */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_PD, + DMARD10_VALUE_PD_RST); + if (ret < 0) + return ret; + + /* + * 2. ACTR => Standby mode => Download OTP to parameter reg => + * Standby mode => Reset data path => Standby mode + */ + buffer[0] = DMARD10_REG_ACTR; + buffer[1] = DMARD10_MODE_STANDBY; + buffer[2] = DMARD10_MODE_READ_OTP; + buffer[3] = DMARD10_MODE_STANDBY; + buffer[4] = DMARD10_MODE_RESET_DATA_PATH; + buffer[5] = DMARD10_MODE_STANDBY; + ret = i2c_master_send(client, buffer, 6); + if (ret < 0) + return ret; + + /* 3. OSCA_EN = 1, TSTO = b'000 (INT1 = normal, TEST0 = normal) */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_MISC2, + DMARD10_VALUE_MISC2_OSCA_EN); + if (ret < 0) + return ret; + + /* 4. AFEN = 1 (AFE will powerdown after ADC) */ + buffer[0] = DMARD10_REG_AFEM; + buffer[1] = DMARD10_VALUE_AFEM_AFEN_NORMAL; + buffer[2] = DMARD10_VALUE_CKSEL_ODR_100_204; + buffer[3] = DMARD10_VALUE_INTC; + buffer[4] = DMARD10_VALUE_TAPNS_AVE_2; + buffer[5] = 0x00; /* DLYC, no delay timing */ + buffer[6] = 0x07; /* INTD=1 push-pull, INTA=1 active high, AUTOT=1 */ + ret = i2c_master_send(client, buffer, 7); + if (ret < 0) + return ret; + + /* 5. Activation mode */ + ret = i2c_smbus_write_byte_data(client, DMARD10_REG_ACTR, + DMARD10_MODE_ACTIVE); + if (ret < 0) + return ret; + + return 0; +} + +/* Shutdown sequence taken from the android driver */ +static int dmard10_shutdown(struct i2c_client *client) +{ + unsigned char buffer[3]; + + buffer[0] = DMARD10_REG_ACTR; + buffer[1] = DMARD10_MODE_STANDBY; + buffer[2] = DMARD10_MODE_OFF; + + return i2c_master_send(client, buffer, 3); +} + +static int dmard10_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct dmard10_data *data = iio_priv(indio_dev); + __le16 buf[4]; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * Read 8 bytes starting at the REG_STADR register, trying to + * read the individual X, Y, Z registers will always read 0. + */ + ret = i2c_smbus_read_i2c_block_data(data->client, + DMARD10_REG_STADR, + sizeof(buf), (u8 *)buf); + if (ret < 0) + return ret; + ret = le16_to_cpu(buf[chan->address]); + *val = sign_extend32(ret, 12); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = dmard10_nscale; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static const struct iio_info dmard10_info = { + .driver_module = THIS_MODULE, + .read_raw = dmard10_read_raw, +}; + +static int dmard10_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct dmard10_data *data; + + /* These 2 registers have special POR reset values used for id */ + ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STADR); + if (ret != DMARD10_VALUE_STADR) + return (ret < 0) ? ret : -ENODEV; + + ret = i2c_smbus_read_byte_data(client, DMARD10_REG_STAINT); + if (ret != DMARD10_VALUE_STAINT) + return (ret < 0) ? ret : -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) { + dev_err(&client->dev, "iio allocation failed!\n"); + return -ENOMEM; + } + + data = iio_priv(indio_dev); + data->client = client; + i2c_set_clientdata(client, indio_dev); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &dmard10_info; + indio_dev->name = "dmard10"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = dmard10_channels; + indio_dev->num_channels = ARRAY_SIZE(dmard10_channels); + + ret = dmard10_reset(client); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "device_register failed\n"); + dmard10_shutdown(client); + } + + return ret; +} + +static int dmard10_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + return dmard10_shutdown(client); +} + +#ifdef CONFIG_PM_SLEEP +static int dmard10_suspend(struct device *dev) +{ + return dmard10_shutdown(to_i2c_client(dev)); +} + +static int dmard10_resume(struct device *dev) +{ + return dmard10_reset(to_i2c_client(dev)); +} +#endif + +static SIMPLE_DEV_PM_OPS(dmard10_pm_ops, dmard10_suspend, dmard10_resume); + +static const struct i2c_device_id dmard10_i2c_id[] = { + {"dmard10", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, dmard10_i2c_id); + +static struct i2c_driver dmard10_driver = { + .driver = { + .name = "dmard10", + .pm = &dmard10_pm_ops, + }, + .probe = dmard10_probe, + .remove = dmard10_remove, + .id_table = dmard10_i2c_id, +}; + +module_i2c_driver(dmard10_driver); + +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); +MODULE_DESCRIPTION("Domintech ARD10 3-Axis Accelerometer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 03beadf14ad3..3a40774cca74 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -39,7 +39,7 @@ #define MMA7660_SCALE_AVAIL "0.467142857" -const int mma7660_nscale = 467142857; +static const int mma7660_nscale = 467142857; #define MMA7660_CHANNEL(reg, axis) { \ .type = IIO_ACCEL, \ diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index d41e1b588e68..f418c588af6a 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -459,12 +459,14 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; mutex_lock(&data->lock); ret = mma8452_read(data, buffer); mutex_unlock(&data->lock); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; @@ -664,37 +666,46 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, struct mma8452_data *data = iio_priv(indio_dev); int i, ret; - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); - if (i < 0) - return i; - + if (i < 0) { + ret = i; + break; + } data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; - return mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); + ret = mma8452_change_config(data, MMA8452_CTRL_REG1, + data->ctrl_reg1); + break; case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); - if (i < 0) - return i; + if (i < 0) { + ret = i; + break; + } data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; - return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + ret = mma8452_change_config(data, MMA8452_DATA_CFG, + data->data_cfg); + break; case IIO_CHAN_INFO_CALIBBIAS: - if (val < -128 || val > 127) - return -EINVAL; + if (val < -128 || val > 127) { + ret = -EINVAL; + break; + } - return mma8452_change_config(data, - MMA8452_OFF_X + chan->scan_index, - val); + ret = mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); + break; case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -703,23 +714,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, data->data_cfg |= MMA8452_DATA_CFG_HPF_MASK; ret = mma8452_set_hp_filter_frequency(data, val, val2); if (ret < 0) - return ret; + break; } - return mma8452_change_config(data, MMA8452_DATA_CFG, + ret = mma8452_change_config(data, MMA8452_DATA_CFG, data->data_cfg); + break; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: ret = mma8452_get_odr_index(data); for (i = 0; i < ARRAY_SIZE(mma8452_os_ratio); i++) { - if (mma8452_os_ratio[i][ret] == val) - return mma8452_set_power_mode(data, i); + if (mma8452_os_ratio[i][ret] == val) { + ret = mma8452_set_power_mode(data, i); + break; + } } - + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; } static int mma8452_read_thresh(struct iio_dev *indio_dev, @@ -1347,20 +1365,9 @@ static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig, return mma8452_change_config(data, MMA8452_CTRL_REG4, reg); } -static int mma8452_validate_device(struct iio_trigger *trig, - struct iio_dev *indio_dev) -{ - struct iio_dev *indio = iio_trigger_get_drvdata(trig); - - if (indio != indio_dev) - return -EINVAL; - - return 0; -} - static const struct iio_trigger_ops mma8452_trigger_ops = { .set_trigger_state = mma8452_data_rdy_trigger_set_state, - .validate_device = mma8452_validate_device, + .validate_device = iio_trigger_validate_own_device, .owner = THIS_MODULE, }; diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c new file mode 100644 index 000000000000..cb1d83fa19a0 --- /dev/null +++ b/drivers/iio/accel/sca3000.c @@ -0,0 +1,1576 @@ +/* + * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI + * + * 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. + * + * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> + * + * See industrialio/accels/sca3000.h for comments. + */ + +#include <linux/interrupt.h> +#include <linux/fs.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> +#include <linux/iio/buffer.h> +#include <linux/iio/kfifo_buf.h> + +#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) +#define SCA3000_READ_REG(a) ((a) << 2) + +#define SCA3000_REG_REVID_ADDR 0x00 +#define SCA3000_REG_REVID_MAJOR_MASK GENMASK(8, 4) +#define SCA3000_REG_REVID_MINOR_MASK GENMASK(3, 0) + +#define SCA3000_REG_STATUS_ADDR 0x02 +#define SCA3000_LOCKED BIT(5) +#define SCA3000_EEPROM_CS_ERROR BIT(1) +#define SCA3000_SPI_FRAME_ERROR BIT(0) + +/* All reads done using register decrement so no need to directly access LSBs */ +#define SCA3000_REG_X_MSB_ADDR 0x05 +#define SCA3000_REG_Y_MSB_ADDR 0x07 +#define SCA3000_REG_Z_MSB_ADDR 0x09 + +#define SCA3000_REG_RING_OUT_ADDR 0x0f + +/* Temp read untested - the e05 doesn't have the sensor */ +#define SCA3000_REG_TEMP_MSB_ADDR 0x13 + +#define SCA3000_REG_MODE_ADDR 0x14 +#define SCA3000_MODE_PROT_MASK 0x28 +#define SCA3000_REG_MODE_RING_BUF_ENABLE BIT(7) +#define SCA3000_REG_MODE_RING_BUF_8BIT BIT(6) + +/* + * Free fall detection triggers an interrupt if the acceleration + * is below a threshold for equivalent of 25cm drop + */ +#define SCA3000_REG_MODE_FREE_FALL_DETECT BIT(4) +#define SCA3000_REG_MODE_MEAS_MODE_NORMAL 0x00 +#define SCA3000_REG_MODE_MEAS_MODE_OP_1 0x01 +#define SCA3000_REG_MODE_MEAS_MODE_OP_2 0x02 + +/* + * In motion detection mode the accelerations are band pass filtered + * (approx 1 - 25Hz) and then a programmable threshold used to trigger + * and interrupt. + */ +#define SCA3000_REG_MODE_MEAS_MODE_MOT_DET 0x03 +#define SCA3000_REG_MODE_MODE_MASK 0x03 + +#define SCA3000_REG_BUF_COUNT_ADDR 0x15 + +#define SCA3000_REG_INT_STATUS_ADDR 0x16 +#define SCA3000_REG_INT_STATUS_THREE_QUARTERS BIT(7) +#define SCA3000_REG_INT_STATUS_HALF BIT(6) + +#define SCA3000_INT_STATUS_FREE_FALL BIT(3) +#define SCA3000_INT_STATUS_Y_TRIGGER BIT(2) +#define SCA3000_INT_STATUS_X_TRIGGER BIT(1) +#define SCA3000_INT_STATUS_Z_TRIGGER BIT(0) + +/* Used to allow access to multiplexed registers */ +#define SCA3000_REG_CTRL_SEL_ADDR 0x18 +/* Only available for SCA3000-D03 and SCA3000-D01 */ +#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 +#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 +#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 +#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 +#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 +/* + * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device + * will not function + */ +#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B + +#define SCA3000_REG_OUT_CTRL_PROT_MASK 0xE0 +#define SCA3000_REG_OUT_CTRL_BUF_X_EN 0x10 +#define SCA3000_REG_OUT_CTRL_BUF_Y_EN 0x08 +#define SCA3000_REG_OUT_CTRL_BUF_Z_EN 0x04 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_MASK 0x03 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_4 0x02 +#define SCA3000_REG_OUT_CTRL_BUF_DIV_2 0x01 + + +/* + * Control which motion detector interrupts are on. + * For now only OR combinations are supported. + */ +#define SCA3000_MD_CTRL_PROT_MASK 0xC0 +#define SCA3000_MD_CTRL_OR_Y BIT(0) +#define SCA3000_MD_CTRL_OR_X BIT(1) +#define SCA3000_MD_CTRL_OR_Z BIT(2) +/* Currently unsupported */ +#define SCA3000_MD_CTRL_AND_Y BIT(3) +#define SCA3000_MD_CTRL_AND_X BIT(4) +#define SAC3000_MD_CTRL_AND_Z BIT(5) + +/* + * Some control registers of complex access methods requiring this register to + * be used to remove a lock. + */ +#define SCA3000_REG_UNLOCK_ADDR 0x1e + +#define SCA3000_REG_INT_MASK_ADDR 0x21 +#define SCA3000_REG_INT_MASK_PROT_MASK 0x1C + +#define SCA3000_REG_INT_MASK_RING_THREE_QUARTER BIT(7) +#define SCA3000_REG_INT_MASK_RING_HALF BIT(6) + +#define SCA3000_REG_INT_MASK_ALL_INTS 0x02 +#define SCA3000_REG_INT_MASK_ACTIVE_HIGH 0x01 +#define SCA3000_REG_INT_MASK_ACTIVE_LOW 0x00 +/* Values of multiplexed registers (write to ctrl_data after select) */ +#define SCA3000_REG_CTRL_DATA_ADDR 0x22 + +/* + * Measurement modes available on some sca3000 series chips. Code assumes others + * may become available in the future. + * + * Bypass - Bypass the low-pass filter in the signal channel so as to increase + * signal bandwidth. + * + * Narrow - Narrow low-pass filtering of the signal channel and half output + * data rate by decimation. + * + * Wide - Widen low-pass filtering of signal channel to increase bandwidth + */ +#define SCA3000_OP_MODE_BYPASS 0x01 +#define SCA3000_OP_MODE_NARROW 0x02 +#define SCA3000_OP_MODE_WIDE 0x04 +#define SCA3000_MAX_TX 6 +#define SCA3000_MAX_RX 2 + +/** + * struct sca3000_state - device instance state information + * @us: the associated spi device + * @info: chip variant information + * @last_timestamp: the timestamp of the last event + * @mo_det_use_count: reference counter for the motion detection unit + * @lock: lock used to protect elements of sca3000_state + * and the underlying device state. + * @tx: dma-able transmit buffer + * @rx: dma-able receive buffer + **/ +struct sca3000_state { + struct spi_device *us; + const struct sca3000_chip_info *info; + s64 last_timestamp; + int mo_det_use_count; + struct mutex lock; + /* Can these share a cacheline ? */ + u8 rx[384] ____cacheline_aligned; + u8 tx[6] ____cacheline_aligned; +}; + +/** + * struct sca3000_chip_info - model dependent parameters + * @scale: scale * 10^-6 + * @temp_output: some devices have temperature sensors. + * @measurement_mode_freq: normal mode sampling frequency + * @measurement_mode_3db_freq: 3db cutoff frequency of the low pass filter for + * the normal measurement mode. + * @option_mode_1: first optional mode. Not all models have one + * @option_mode_1_freq: option mode 1 sampling frequency + * @option_mode_1_3db_freq: 3db cutoff frequency of the low pass filter for + * the first option mode. + * @option_mode_2: second optional mode. Not all chips have one + * @option_mode_2_freq: option mode 2 sampling frequency + * @option_mode_2_3db_freq: 3db cutoff frequency of the low pass filter for + * the second option mode. + * @mod_det_mult_xz: Bit wise multipliers to calculate the threshold + * for motion detection in the x and z axis. + * @mod_det_mult_y: Bit wise multipliers to calculate the threshold + * for motion detection in the y axis. + * + * This structure is used to hold information about the functionality of a given + * sca3000 variant. + **/ +struct sca3000_chip_info { + unsigned int scale; + bool temp_output; + int measurement_mode_freq; + int measurement_mode_3db_freq; + int option_mode_1; + int option_mode_1_freq; + int option_mode_1_3db_freq; + int option_mode_2; + int option_mode_2_freq; + int option_mode_2_3db_freq; + int mot_det_mult_xz[6]; + int mot_det_mult_y[7]; +}; + +enum sca3000_variant { + d01, + e02, + e04, + e05, +}; + +/* + * Note where option modes are not defined, the chip simply does not + * support any. + * Other chips in the sca3000 series use i2c and are not included here. + * + * Some of these devices are only listed in the family data sheet and + * do not actually appear to be available. + */ +static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { + [d01] = { + .scale = 7357, + .temp_output = true, + .measurement_mode_freq = 250, + .measurement_mode_3db_freq = 45, + .option_mode_1 = SCA3000_OP_MODE_BYPASS, + .option_mode_1_freq = 250, + .option_mode_1_3db_freq = 70, + .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, + .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, + }, + [e02] = { + .scale = 9810, + .measurement_mode_freq = 125, + .measurement_mode_3db_freq = 40, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 63, + .option_mode_1_3db_freq = 11, + .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, + .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, + }, + [e04] = { + .scale = 19620, + .measurement_mode_freq = 100, + .measurement_mode_3db_freq = 38, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 70, + .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, + .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, + }, + [e05] = { + .scale = 61313, + .measurement_mode_freq = 200, + .measurement_mode_3db_freq = 60, + .option_mode_1 = SCA3000_OP_MODE_NARROW, + .option_mode_1_freq = 50, + .option_mode_1_3db_freq = 9, + .option_mode_2 = SCA3000_OP_MODE_WIDE, + .option_mode_2_freq = 400, + .option_mode_2_3db_freq = 75, + .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, + .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, + }, +}; + +static int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) +{ + st->tx[0] = SCA3000_WRITE_REG(address); + st->tx[1] = val; + return spi_write(st->us, st->tx, 2); +} + +static int sca3000_read_data_short(struct sca3000_state *st, + u8 reg_address_high, + int len) +{ + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = st->rx, + } + }; + st->tx[0] = SCA3000_READ_REG(reg_address_high); + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_reg_lock_on() - test if the ctrl register lock is on + * @st: Driver specific device instance data. + * + * Lock must be held. + **/ +static int sca3000_reg_lock_on(struct sca3000_state *st) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_STATUS_ADDR, 1); + if (ret < 0) + return ret; + + return !(st->rx[0] & SCA3000_LOCKED); +} + +/** + * __sca3000_unlock_reg_lock() - unlock the control registers + * @st: Driver specific device instance data. + * + * Note the device does not appear to support doing this in a single transfer. + * This should only ever be used as part of ctrl reg read. + * Lock must be held before calling this + */ +static int __sca3000_unlock_reg_lock(struct sca3000_state *st) +{ + struct spi_transfer xfer[3] = { + { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx, + }, { + .len = 2, + .cs_change = 1, + .tx_buf = st->tx + 2, + }, { + .len = 2, + .tx_buf = st->tx + 4, + }, + }; + st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[1] = 0x00; + st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[3] = 0x50; + st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_UNLOCK_ADDR); + st->tx[5] = 0xA0; + + return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); +} + +/** + * sca3000_write_ctrl_reg() write to a lock protect ctrl register + * @st: Driver specific device instance data. + * @sel: selects which registers we wish to write to + * @val: the value to be written + * + * Certain control registers are protected against overwriting by the lock + * register and use a shared write address. This function allows writing of + * these registers. + * Lock must be held. + */ +static int sca3000_write_ctrl_reg(struct sca3000_state *st, + u8 sel, + uint8_t val) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, sel); + if (ret) + goto error_ret; + + /* Write the actual value into the register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_DATA_ADDR, val); + +error_ret: + return ret; +} + +/** + * sca3000_read_ctrl_reg() read from lock protected control register. + * @st: Driver specific device instance data. + * @ctrl_reg: Which ctrl register do we want to read. + * + * Lock must be held. + */ +static int sca3000_read_ctrl_reg(struct sca3000_state *st, + u8 ctrl_reg) +{ + int ret; + + ret = sca3000_reg_lock_on(st); + if (ret < 0) + goto error_ret; + if (ret) { + ret = __sca3000_unlock_reg_lock(st); + if (ret) + goto error_ret; + } + /* Set the control select register */ + ret = sca3000_write_reg(st, SCA3000_REG_CTRL_SEL_ADDR, ctrl_reg); + if (ret) + goto error_ret; + ret = sca3000_read_data_short(st, SCA3000_REG_CTRL_DATA_ADDR, 1); + if (ret) + goto error_ret; + return st->rx[0]; +error_ret: + return ret; +} + +/** + * sca3000_show_rev() - sysfs interface to read the chip revision number + * @indio_dev: Device instance specific generic IIO data. + * Driver specific device instance data can be obtained via + * via iio_priv(indio_dev) + */ +static int sca3000_print_rev(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_REVID_ADDR, 1); + if (ret < 0) + goto error_ret; + dev_info(&indio_dev->dev, + "sca3000 revision major=%lu, minor=%lu\n", + st->rx[0] & SCA3000_REG_REVID_MAJOR_MASK, + st->rx[0] & SCA3000_REG_REVID_MINOR_MASK); +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static ssize_t +sca3000_show_available_3db_freqs(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len; + + len = sprintf(buf, "%d", st->info->measurement_mode_3db_freq); + if (st->info->option_mode_1) + len += sprintf(buf + len, " %d", + st->info->option_mode_1_3db_freq); + if (st->info->option_mode_2) + len += sprintf(buf + len, " %d", + st->info->option_mode_2_3db_freq); + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, + S_IRUGO, sca3000_show_available_3db_freqs, + NULL, 0); + +static const struct iio_event_spec sca3000_event = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), +}; + +/* + * Note the hack in the number of bits to pretend we have 2 more than + * we do in the fifo. + */ +#define SCA3000_CHAN(index, mod) \ + { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),\ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 13, \ + .storagebits = 16, \ + .shift = 3, \ + .endianness = IIO_BE, \ + }, \ + .event_spec = &sca3000_event, \ + .num_event_specs = 1, \ + } + +static const struct iio_event_spec sca3000_freefall_event_spec = { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD), +}; + +static const struct iio_chan_spec sca3000_channels[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, +}; + +static const struct iio_chan_spec sca3000_channels_with_temp[] = { + SCA3000_CHAN(0, IIO_MOD_X), + SCA3000_CHAN(1, IIO_MOD_Y), + SCA3000_CHAN(2, IIO_MOD_Z), + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + /* No buffer support */ + .scan_index = -1, + }, + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X_AND_Y_AND_Z, + .scan_index = -1, /* Fake channel */ + .event_spec = &sca3000_freefall_event_spec, + .num_event_specs = 1, + }, +}; + +static u8 sca3000_addresses[3][3] = { + [0] = {SCA3000_REG_X_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_X_TH, + SCA3000_MD_CTRL_OR_X}, + [1] = {SCA3000_REG_Y_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Y_TH, + SCA3000_MD_CTRL_OR_Y}, + [2] = {SCA3000_REG_Z_MSB_ADDR, SCA3000_REG_CTRL_SEL_MD_Z_TH, + SCA3000_MD_CTRL_OR_Z}, +}; + +/** + * __sca3000_get_base_freq() - obtain mode specific base frequency + * @st: Private driver specific device instance specific state. + * @info: chip type specific information. + * @base_freq: Base frequency for the current measurement mode. + * + * lock must be held + */ +static inline int __sca3000_get_base_freq(struct sca3000_state *st, + const struct sca3000_chip_info *info, + int *base_freq) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + switch (SCA3000_REG_MODE_MODE_MASK & st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + *base_freq = info->measurement_mode_freq; + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + *base_freq = info->option_mode_1_freq; + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + *base_freq = info->option_mode_2_freq; + break; + default: + ret = -EINVAL; + } +error_ret: + return ret; +} + +/** + * sca3000_read_raw_samp_freq() - read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency read back. + * + * lock must be held + **/ +static int sca3000_read_raw_samp_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = __sca3000_get_base_freq(st, st->info, val); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + if (*val > 0) { + ret &= SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; + switch (ret) { + case SCA3000_REG_OUT_CTRL_BUF_DIV_2: + *val /= 2; + break; + case SCA3000_REG_OUT_CTRL_BUF_DIV_4: + *val /= 4; + break; + } + } + + return 0; +} + +/** + * sca3000_write_raw_samp_freq() - write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * @st: Private driver specific device instance specific state. + * @val: The frequency desired. + * + * lock must be held + */ +static int sca3000_write_raw_samp_freq(struct sca3000_state *st, int val) +{ + int ret, base_freq, ctrlval; + + ret = __sca3000_get_base_freq(st, st->info, &base_freq); + if (ret) + return ret; + + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + return ret; + + ctrlval = ret & ~SCA3000_REG_OUT_CTRL_BUF_DIV_MASK; + + if (val == base_freq / 2) + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_2; + if (val == base_freq / 4) + ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_4; + else if (val != base_freq) + return -EINVAL; + + return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + ctrlval); +} + +static int sca3000_read_3db_freq(struct sca3000_state *st, int *val) +{ + int ret; + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + /* mask bottom 2 bits - only ones that are relevant */ + st->rx[0] &= SCA3000_REG_MODE_MODE_MASK; + switch (st->rx[0]) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + *val = st->info->measurement_mode_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_MOT_DET: + return -EBUSY; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + *val = st->info->option_mode_1_3db_freq; + return IIO_VAL_INT; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + *val = st->info->option_mode_2_3db_freq; + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int sca3000_write_3db_freq(struct sca3000_state *st, int val) +{ + int ret; + int mode; + + if (val == st->info->measurement_mode_3db_freq) + mode = SCA3000_REG_MODE_MEAS_MODE_NORMAL; + else if (st->info->option_mode_1 && + (val == st->info->option_mode_1_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_1; + else if (st->info->option_mode_2 && + (val == st->info->option_mode_2_3db_freq)) + mode = SCA3000_REG_MODE_MEAS_MODE_OP_2; + else + return -EINVAL; + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + st->rx[0] &= ~SCA3000_REG_MODE_MODE_MASK; + st->rx[0] |= (mode & SCA3000_REG_MODE_MODE_MASK); + + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, st->rx[0]); +} + +static int sca3000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + u8 address; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + if (chan->type == IIO_ACCEL) { + if (st->mo_det_use_count) { + mutex_unlock(&st->lock); + return -EBUSY; + } + address = sca3000_addresses[chan->address][0]; + ret = sca3000_read_data_short(st, address, 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; + *val = ((*val) << (sizeof(*val) * 8 - 13)) >> + (sizeof(*val) * 8 - 13); + } else { + /* get the temperature when available */ + ret = sca3000_read_data_short(st, + SCA3000_REG_TEMP_MSB_ADDR, + 2); + if (ret < 0) { + mutex_unlock(&st->lock); + return ret; + } + *val = ((st->rx[0] & 0x3F) << 3) | + ((st->rx[1] & 0xE0) >> 5); + } + mutex_unlock(&st->lock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + if (chan->type == IIO_ACCEL) + *val2 = st->info->scale; + else /* temperature */ + *val2 = 555556; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = -214; + *val2 = 600000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&st->lock); + ret = sca3000_read_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret ? ret : IIO_VAL_INT; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + mutex_lock(&st->lock); + ret = sca3000_read_3db_freq(st, val); + mutex_unlock(&st->lock); + return ret; + default: + return -EINVAL; + } +} + +static int sca3000_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = sca3000_write_raw_samp_freq(st, val); + mutex_unlock(&st->lock); + return ret; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (val2) + return -EINVAL; + mutex_lock(&st->lock); + ret = sca3000_write_3db_freq(st, val); + mutex_unlock(&st->lock); + default: + return -EINVAL; + } + + return ret; +} + +/** + * sca3000_read_av_freq() - sysfs function to get available frequencies + * @dev: Device structure for this device. + * @attr: Description of the attribute. + * @buf: Incoming string + * + * The later modes are only relevant to the ring buffer - and depend on current + * mode. Note that data sheet gives rather wide tolerances for these so integer + * division will give good enough answer and not all chips have them specified + * at all. + **/ +static ssize_t sca3000_read_av_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct sca3000_state *st = iio_priv(indio_dev); + int len = 0, ret, val; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto error_ret; + + switch (val & SCA3000_REG_MODE_MODE_MASK) { + case SCA3000_REG_MODE_MEAS_MODE_NORMAL: + len += sprintf(buf + len, "%d %d %d\n", + st->info->measurement_mode_freq, + st->info->measurement_mode_freq / 2, + st->info->measurement_mode_freq / 4); + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_1: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_1_freq, + st->info->option_mode_1_freq / 2, + st->info->option_mode_1_freq / 4); + break; + case SCA3000_REG_MODE_MEAS_MODE_OP_2: + len += sprintf(buf + len, "%d %d %d\n", + st->info->option_mode_2_freq, + st->info->option_mode_2_freq / 2, + st->info->option_mode_2_freq / 4); + break; + } + return len; +error_ret: + return ret; +} + +/* + * Should only really be registered if ring buffer support is compiled in. + * Does no harm however and doing it right would add a fair bit of complexity + */ +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); + +/** + * sca3000_read_event_value() - query of a threshold or period + **/ +static int sca3000_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + int ret, i; + struct sca3000_state *st = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + mutex_lock(&st->lock); + ret = sca3000_read_ctrl_reg(st, + sca3000_addresses[chan->address][1]); + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + *val = 0; + if (chan->channel2 == IIO_MOD_Y) + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_y)) + *val += st->info->mot_det_mult_y[i]; + else + for_each_set_bit(i, (unsigned long *)&ret, + ARRAY_SIZE(st->info->mot_det_mult_xz)) + *val += st->info->mot_det_mult_xz[i]; + + return IIO_VAL_INT; + case IIO_EV_INFO_PERIOD: + *val = 0; + *val2 = 226000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +/** + * sca3000_write_value() - control of threshold and period + * @indio_dev: Device instance specific IIO information. + * @chan: Description of the channel for which the event is being + * configured. + * @type: The type of event being configured, here magnitude rising + * as everything else is read only. + * @dir: Direction of the event (here rising) + * @info: What information about the event are we configuring. + * Here the threshold only. + * @val: Integer part of the value being written.. + * @val2: Non integer part of the value being written. Here always 0. + */ +static int sca3000_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + int i; + u8 nonlinear = 0; + + if (chan->channel2 == IIO_MOD_Y) { + i = ARRAY_SIZE(st->info->mot_det_mult_y); + while (i > 0) + if (val >= st->info->mot_det_mult_y[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_y[i]; + } + } else { + i = ARRAY_SIZE(st->info->mot_det_mult_xz); + while (i > 0) + if (val >= st->info->mot_det_mult_xz[--i]) { + nonlinear |= (1 << i); + val -= st->info->mot_det_mult_xz[i]; + } + } + + mutex_lock(&st->lock); + ret = sca3000_write_ctrl_reg(st, + sca3000_addresses[chan->address][1], + nonlinear); + mutex_unlock(&st->lock); + + return ret; +} + +static struct attribute *sca3000_attributes[] = { + &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group sca3000_attribute_group = { + .attrs = sca3000_attributes, +}; + +static int sca3000_read_data(struct sca3000_state *st, + u8 reg_address_high, + u8 *rx, + int len) +{ + int ret; + struct spi_transfer xfer[2] = { + { + .len = 1, + .tx_buf = st->tx, + }, { + .len = len, + .rx_buf = rx, + } + }; + + st->tx[0] = SCA3000_READ_REG(reg_address_high); + ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); + if (ret) { + dev_err(get_device(&st->us->dev), "problem reading register"); + return ret; + } + + return 0; +} + +/** + * sca3000_ring_int_process() - ring specific interrupt handling. + * @val: Value of the interrupt status register. + * @indio_dev: Device instance specific IIO device structure. + */ +static void sca3000_ring_int_process(u8 val, struct iio_dev *indio_dev) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret, i, num_available; + + mutex_lock(&st->lock); + + if (val & SCA3000_REG_INT_STATUS_HALF) { + ret = sca3000_read_data_short(st, SCA3000_REG_BUF_COUNT_ADDR, + 1); + if (ret) + goto error_ret; + num_available = st->rx[0]; + /* + * num_available is the total number of samples available + * i.e. number of time points * number of channels. + */ + ret = sca3000_read_data(st, SCA3000_REG_RING_OUT_ADDR, st->rx, + num_available * 2); + if (ret) + goto error_ret; + for (i = 0; i < num_available / 3; i++) { + /* + * Dirty hack to cover for 11 bit in fifo, 13 bit + * direct reading. + * + * In theory the bottom two bits are undefined. + * In reality they appear to always be 0. + */ + iio_push_to_buffers(indio_dev, st->rx + i * 3 * 2); + } + } +error_ret: + mutex_unlock(&st->lock); +} + +/** + * sca3000_event_handler() - handling ring and non ring events + * @irq: The irq being handled. + * @private: struct iio_device pointer for the device. + * + * Ring related interrupt handler. Depending on event, push to + * the ring buffer event chrdev or the event one. + * + * This function is complicated by the fact that the devices can signify ring + * and non ring events via the same interrupt line and they can only + * be distinguished via a read of the relevant status register. + */ +static irqreturn_t sca3000_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sca3000_state *st = iio_priv(indio_dev); + int ret, val; + s64 last_timestamp = iio_get_time_ns(indio_dev); + + /* + * Could lead if badly timed to an extra read of status reg, + * but ensures no interrupt is missed. + */ + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); + val = st->rx[0]; + mutex_unlock(&st->lock); + if (ret) + goto done; + + sca3000_ring_int_process(val, indio_dev); + + if (val & SCA3000_INT_STATUS_FREE_FALL) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X_AND_Y_AND_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_FALLING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Y_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_X_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + + if (val & SCA3000_INT_STATUS_Z_TRIGGER) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + last_timestamp); + +done: + return IRQ_HANDLED; +} + +/** + * sca3000_read_event_config() what events are enabled + **/ +static int sca3000_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + /* read current value of mode register */ + mutex_lock(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = !!(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT); + break; + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + /* + * Motion detection mode cannot run at the same time as + * acceleration data being read. + */ + if ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET) { + ret = 0; + } else { + ret = sca3000_read_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + /* only supporting logical or's for now */ + ret = !!(ret & sca3000_addresses[chan->address][2]); + } + break; + default: + ret = -EINVAL; + } + +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_freefall_set_state(struct iio_dev *indio_dev, int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + + /* if off and should be on */ + if (state && !(st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] | SCA3000_REG_MODE_FREE_FALL_DETECT); + /* if on and should be off */ + else if (!state && (st->rx[0] & SCA3000_REG_MODE_FREE_FALL_DETECT)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & ~SCA3000_REG_MODE_FREE_FALL_DETECT); + else + return 0; +} + +static int sca3000_motion_detect_set_state(struct iio_dev *indio_dev, int axis, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret, ctrlval; + + /* + * First read the motion detector config to find out if + * this axis is on + */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + return ret; + ctrlval = ret; + /* if off and should be on */ + if (state && !(ctrlval & sca3000_addresses[axis][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval | + sca3000_addresses[axis][2]); + if (ret) + return ret; + st->mo_det_use_count++; + } else if (!state && (ctrlval & sca3000_addresses[axis][2])) { + ret = sca3000_write_ctrl_reg(st, + SCA3000_REG_CTRL_SEL_MD_CTRL, + ctrlval & + ~(sca3000_addresses[axis][2])); + if (ret) + return ret; + st->mo_det_use_count--; + } + + /* read current value of mode register */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + return ret; + /* if off and should be on */ + if ((st->mo_det_use_count) && + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + != SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_MODE_MASK) + | SCA3000_REG_MODE_MEAS_MODE_MOT_DET); + /* if on and should be off */ + else if (!(st->mo_det_use_count) && + ((st->rx[0] & SCA3000_REG_MODE_MODE_MASK) + == SCA3000_REG_MODE_MEAS_MODE_MOT_DET)) + return sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + st->rx[0] & SCA3000_REG_MODE_MODE_MASK); + else + return 0; +} + +/** + * sca3000_write_event_config() - simple on off control for motion detector + * @indio_dev: IIO device instance specific structure. Data specific to this + * particular driver may be accessed via iio_priv(indio_dev). + * @chan: Description of the channel whose event we are configuring. + * @type: The type of event. + * @dir: The direction of the event. + * @state: Desired state of event being configured. + * + * This is a per axis control, but enabling any will result in the + * motion detector unit being enabled. + * N.B. enabling motion detector stops normal data acquisition. + * There is a complexity in knowing which mode to return to when + * this mode is disabled. Currently normal mode is assumed. + **/ +static int sca3000_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + switch (chan->channel2) { + case IIO_MOD_X_AND_Y_AND_Z: + ret = sca3000_freefall_set_state(indio_dev, state); + break; + + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + ret = sca3000_motion_detect_set_state(indio_dev, + chan->address, + state); + break; + default: + ret = -EINVAL; + break; + } + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_configure_ring(struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + + buffer = iio_kfifo_allocate(); + if (!buffer) + return -ENOMEM; + + iio_device_attach_buffer(indio_dev, buffer); + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + + 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) +{ + struct sca3000_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + if (state) { + dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); + ret = sca3000_write_reg(st, + SCA3000_REG_MODE_ADDR, + (st->rx[0] | SCA3000_REG_MODE_RING_BUF_ENABLE)); + } else + ret = sca3000_write_reg(st, + SCA3000_REG_MODE_ADDR, + (st->rx[0] & ~SCA3000_REG_MODE_RING_BUF_ENABLE)); +error_ret: + mutex_unlock(&st->lock); + + return ret; +} + +/** + * sca3000_hw_ring_preenable() - hw ring buffer preenable function + * @indio_dev: structure representing the IIO device. Device instance + * specific state can be accessed via iio_priv(indio_dev). + * + * Very simple enable function as the chip will allows normal reads + * during ring buffer operation so as long as it is indeed running + * before we notify the core, the precise ordering does not matter. + */ +static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + mutex_lock(&st->lock); + + /* Enable the 50% full interrupt */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] | SCA3000_REG_INT_MASK_RING_HALF); + if (ret) + goto error_unlock; + + mutex_unlock(&st->lock); + + return __sca3000_hw_ring_state_set(indio_dev, 1); + +error_unlock: + mutex_unlock(&st->lock); + + return ret; +} + +static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) +{ + int ret; + struct sca3000_state *st = iio_priv(indio_dev); + + ret = __sca3000_hw_ring_state_set(indio_dev, 0); + if (ret) + return ret; + + /* Disable the 50% full interrupt */ + mutex_lock(&st->lock); + + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto unlock; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + st->rx[0] & ~SCA3000_REG_INT_MASK_RING_HALF); +unlock: + mutex_unlock(&st->lock); + return ret; +} + +static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { + .preenable = &sca3000_hw_ring_preenable, + .postdisable = &sca3000_hw_ring_postdisable, +}; + +/** + * sca3000_clean_setup() - get the device into a predictable state + * @st: Device instance specific private data structure + * + * Devices use flash memory to store many of the register values + * and hence can come up in somewhat unpredictable states. + * Hence reset everything on driver load. + */ +static int sca3000_clean_setup(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + /* Ensure all interrupts have been acknowledged */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_STATUS_ADDR, 1); + if (ret) + goto error_ret; + + /* Turn off all motion detection channels */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, + ret & SCA3000_MD_CTRL_PROT_MASK); + if (ret) + goto error_ret; + + /* Disable ring buffer */ + ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); + if (ret < 0) + goto error_ret; + ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, + (ret & SCA3000_REG_OUT_CTRL_PROT_MASK) + | SCA3000_REG_OUT_CTRL_BUF_X_EN + | SCA3000_REG_OUT_CTRL_BUF_Y_EN + | SCA3000_REG_OUT_CTRL_BUF_Z_EN + | SCA3000_REG_OUT_CTRL_BUF_DIV_4); + if (ret) + goto error_ret; + /* Enable interrupts, relevant to mode and set up as active low */ + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, + SCA3000_REG_INT_MASK_ADDR, + (ret & SCA3000_REG_INT_MASK_PROT_MASK) + | SCA3000_REG_INT_MASK_ACTIVE_LOW); + if (ret) + goto error_ret; + /* + * Select normal measurement mode, free fall off, ring off + * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 + * as that occurs in one of the example on the datasheet + */ + ret = sca3000_read_data_short(st, SCA3000_REG_MODE_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_MODE_ADDR, + (st->rx[0] & SCA3000_MODE_PROT_MASK)); + +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static const struct iio_info sca3000_info = { + .attrs = &sca3000_attribute_group, + .read_raw = &sca3000_read_raw, + .write_raw = &sca3000_write_raw, + .read_event_value = &sca3000_read_event_value, + .write_event_value = &sca3000_write_event_value, + .read_event_config = &sca3000_read_event_config, + .write_event_config = &sca3000_write_event_config, + .driver_module = THIS_MODULE, +}; + +static int sca3000_probe(struct spi_device *spi) +{ + int ret; + struct sca3000_state *st; + struct iio_dev *indio_dev; + + 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); + st->us = spi; + mutex_init(&st->lock); + st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) + ->driver_data]; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &sca3000_info; + if (st->info->temp_output) { + indio_dev->channels = sca3000_channels_with_temp; + indio_dev->num_channels = + ARRAY_SIZE(sca3000_channels_with_temp); + } else { + indio_dev->channels = sca3000_channels; + indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); + } + indio_dev->modes = INDIO_DIRECT_MODE; + + sca3000_configure_ring(indio_dev); + + if (spi->irq) { + ret = request_threaded_irq(spi->irq, + NULL, + &sca3000_event_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "sca3000", + indio_dev); + if (ret) + return ret; + } + indio_dev->setup_ops = &sca3000_ring_setup_ops; + ret = sca3000_clean_setup(st); + if (ret) + goto error_free_irq; + + ret = sca3000_print_rev(indio_dev); + if (ret) + goto error_free_irq; + + return iio_device_register(indio_dev); + +error_free_irq: + if (spi->irq) + free_irq(spi->irq, indio_dev); + + return ret; +} + +static int sca3000_stop_all_interrupts(struct sca3000_state *st) +{ + int ret; + + mutex_lock(&st->lock); + ret = sca3000_read_data_short(st, SCA3000_REG_INT_MASK_ADDR, 1); + if (ret) + goto error_ret; + ret = sca3000_write_reg(st, SCA3000_REG_INT_MASK_ADDR, + (st->rx[0] & + ~(SCA3000_REG_INT_MASK_RING_THREE_QUARTER | + SCA3000_REG_INT_MASK_RING_HALF | + SCA3000_REG_INT_MASK_ALL_INTS))); +error_ret: + mutex_unlock(&st->lock); + return ret; +} + +static int sca3000_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct sca3000_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + /* Must ensure no interrupts can be generated after this! */ + sca3000_stop_all_interrupts(st); + if (spi->irq) + free_irq(spi->irq, indio_dev); + + sca3000_unconfigure_ring(indio_dev); + + return 0; +} + +static const struct spi_device_id sca3000_id[] = { + {"sca3000_d01", d01}, + {"sca3000_e02", e02}, + {"sca3000_e04", e04}, + {"sca3000_e05", e05}, + {} +}; +MODULE_DEVICE_TABLE(spi, sca3000_id); + +static struct spi_driver sca3000_driver = { + .driver = { + .name = "sca3000", + }, + .probe = sca3000_probe, + .remove = sca3000_remove, + .id_table = sca3000_id, +}; +module_spi_driver(sca3000_driver); + +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); +MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7edcf3238620..c3fe98d2dc3b 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -58,6 +58,18 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. +config AD7766 + tristate "Analog Devices AD7766/AD7767 ADC driver" + depends on SPI_MASTER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices AD7766, AD7766-1, + AD7766-2, AD7767, AD7767-1, AD7767-2 SPI analog to digital converters. + + To compile this driver as a module, choose M here: the module will be + called ad7766. + config AD7791 tristate "Analog Devices AD7791 ADC driver" depends on SPI @@ -447,6 +459,8 @@ config TI_ADC081C config TI_ADC0832 tristate "Texas Instruments ADC0831/ADC0832/ADC0834/ADC0838" depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help If you say yes here you get support for Texas Instruments ADC0831, ADC0832, ADC0834, ADC0838 ADC chips. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 7a40c04c311f..96894b32300d 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7923) += ad7923.o obj-$(CONFIG_AD7476) += ad7476.o +obj-$(CONFIG_AD7766) += ad7766.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c new file mode 100644 index 000000000000..d906686c48eb --- /dev/null +++ b/drivers/iio/adc/ad7766.c @@ -0,0 +1,330 @@ +/* + * AD7766/AD7767 SPI ADC driver + * + * Copyright 2016 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +struct ad7766_chip_info { + unsigned int decimation_factor; +}; + +enum { + AD7766_SUPPLY_AVDD = 0, + AD7766_SUPPLY_DVDD = 1, + AD7766_SUPPLY_VREF = 2, + AD7766_NUM_SUPPLIES = 3 +}; + +struct ad7766 { + const struct ad7766_chip_info *chip_info; + struct spi_device *spi; + struct clk *mclk; + struct gpio_desc *pd_gpio; + struct regulator_bulk_data reg[AD7766_NUM_SUPPLIES]; + + struct iio_trigger *trig; + + struct spi_transfer xfer; + struct spi_message msg; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Make the buffer large enough for one 24 bit sample and one 64 bit + * aligned 64 bit timestamp. + */ + unsigned char data[ALIGN(3, sizeof(s64)) + sizeof(s64)] + ____cacheline_aligned; +}; + +/* + * AD7766 and AD7767 variations are interface compatible, the main difference is + * analog performance. Both parts will use the same ID. + */ +enum ad7766_device_ids { + ID_AD7766, + ID_AD7766_1, + ID_AD7766_2, +}; + +static irqreturn_t ad7766_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7766 *ad7766 = iio_priv(indio_dev); + int ret; + + ret = spi_sync(ad7766->spi, &ad7766->msg); + if (ret < 0) + goto done; + + iio_push_to_buffers_with_timestamp(indio_dev, ad7766->data, + pf->timestamp); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ad7766_preenable(struct iio_dev *indio_dev) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + if (ret < 0) { + dev_err(&ad7766->spi->dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + ret = clk_prepare_enable(ad7766->mclk); + if (ret < 0) { + dev_err(&ad7766->spi->dev, "Failed to enable MCLK: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + return ret; + } + + if (ad7766->pd_gpio) + gpiod_set_value(ad7766->pd_gpio, 0); + + return 0; +} + +static int ad7766_postdisable(struct iio_dev *indio_dev) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + + if (ad7766->pd_gpio) + gpiod_set_value(ad7766->pd_gpio, 1); + + /* + * The PD pin is synchronous to the clock, so give it some time to + * notice the change before we disable the clock. + */ + msleep(20); + + clk_disable_unprepare(ad7766->mclk); + regulator_bulk_disable(ARRAY_SIZE(ad7766->reg), ad7766->reg); + + return 0; +} + +static int ad7766_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct ad7766 *ad7766 = iio_priv(indio_dev); + struct regulator *vref = ad7766->reg[AD7766_SUPPLY_VREF].consumer; + int scale_uv; + + switch (info) { + case IIO_CHAN_INFO_SCALE: + scale_uv = regulator_get_voltage(vref); + if (scale_uv < 0) + return scale_uv; + *val = scale_uv / 1000; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(ad7766->mclk) / + ad7766->chip_info->decimation_factor; + return IIO_VAL_INT; + } + return -EINVAL; +} + +static const struct iio_chan_spec ad7766_channels[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_type = { + .sign = 's', + .realbits = 24, + .storagebits = 32, + .endianness = IIO_BE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static const struct ad7766_chip_info ad7766_chip_info[] = { + [ID_AD7766] = { + .decimation_factor = 8, + }, + [ID_AD7766_1] = { + .decimation_factor = 16, + }, + [ID_AD7766_2] = { + .decimation_factor = 32, + }, +}; + +static const struct iio_buffer_setup_ops ad7766_buffer_setup_ops = { + .preenable = &ad7766_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &ad7766_postdisable, +}; + +static const struct iio_info ad7766_info = { + .driver_module = THIS_MODULE, + .read_raw = &ad7766_read_raw, +}; + +static irqreturn_t ad7766_irq(int irq, void *private) +{ + iio_trigger_poll(private); + return IRQ_HANDLED; +} + +static int ad7766_set_trigger_state(struct iio_trigger *trig, bool enable) +{ + struct ad7766 *ad7766 = iio_trigger_get_drvdata(trig); + + if (enable) + enable_irq(ad7766->spi->irq); + else + disable_irq(ad7766->spi->irq); + + return 0; +} + +static const struct iio_trigger_ops ad7766_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ad7766_set_trigger_state, + .validate_device = iio_trigger_validate_own_device, +}; + +static int ad7766_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + struct iio_dev *indio_dev; + struct ad7766 *ad7766; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*ad7766)); + if (!indio_dev) + return -ENOMEM; + + ad7766 = iio_priv(indio_dev); + ad7766->chip_info = &ad7766_chip_info[id->driver_data]; + + ad7766->mclk = devm_clk_get(&spi->dev, "mclk"); + if (IS_ERR(ad7766->mclk)) + return PTR_ERR(ad7766->mclk); + + ad7766->reg[AD7766_SUPPLY_AVDD].supply = "avdd"; + ad7766->reg[AD7766_SUPPLY_DVDD].supply = "dvdd"; + ad7766->reg[AD7766_SUPPLY_VREF].supply = "vref"; + + ret = devm_regulator_bulk_get(&spi->dev, ARRAY_SIZE(ad7766->reg), + ad7766->reg); + if (IS_ERR(ad7766->reg)) + return PTR_ERR(ad7766->reg); + + ad7766->pd_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ad7766->pd_gpio)) + return PTR_ERR(ad7766->pd_gpio); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad7766_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7766_channels); + indio_dev->info = &ad7766_info; + + if (spi->irq > 0) { + ad7766->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!ad7766->trig) + return -ENOMEM; + + ad7766->trig->ops = &ad7766_trigger_ops; + ad7766->trig->dev.parent = &spi->dev; + iio_trigger_set_drvdata(ad7766->trig, ad7766); + + ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq, + IRQF_TRIGGER_FALLING, dev_name(&spi->dev), + ad7766->trig); + if (ret < 0) + return ret; + + /* + * The device generates interrupts as long as it is powered up. + * Some platforms might not allow the option to power it down so + * disable the interrupt to avoid extra load on the system + */ + disable_irq(spi->irq); + + ret = devm_iio_trigger_register(&spi->dev, ad7766->trig); + if (ret) + return ret; + } + + spi_set_drvdata(spi, indio_dev); + + ad7766->spi = spi; + + /* First byte always 0 */ + ad7766->xfer.rx_buf = &ad7766->data[1]; + ad7766->xfer.len = 3; + + spi_message_init(&ad7766->msg); + spi_message_add_tail(&ad7766->xfer, &ad7766->msg); + + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, &ad7766_trigger_handler, + &ad7766_buffer_setup_ops); + if (ret) + return ret; + + ret = devm_iio_device_register(&spi->dev, indio_dev); + if (ret) + return ret; + return 0; +} + +static const struct spi_device_id ad7766_id[] = { + {"ad7766", ID_AD7766}, + {"ad7766-1", ID_AD7766_1}, + {"ad7766-2", ID_AD7766_2}, + {"ad7767", ID_AD7766}, + {"ad7767-1", ID_AD7766_1}, + {"ad7767-2", ID_AD7766_2}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7766_id); + +static struct spi_driver ad7766_driver = { + .driver = { + .name = "ad7766", + }, + .probe = ad7766_probe, + .id_table = ad7766_id, +}; +module_spi_driver(ad7766_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD7766 and AD7767 ADCs driver support"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 712fbd2b1f16..3b7c4f78f37a 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -238,7 +238,9 @@ static int max1027_read_single_value(struct iio_dev *indio_dev, /* Configure conversion register with the requested chan */ st->reg = MAX1027_CONV_REG | MAX1027_CHAN(chan->channel) | - MAX1027_NOSCAN | !!(chan->type == IIO_TEMP); + MAX1027_NOSCAN; + if (chan->type == IIO_TEMP) + st->reg |= MAX1027_TEMP; ret = spi_write(st->spi, &st->reg, 1); if (ret < 0) { dev_err(&indio_dev->dev, @@ -360,17 +362,6 @@ static int max1027_set_trigger_state(struct iio_trigger *trig, bool state) return 0; } -static int max1027_validate_device(struct iio_trigger *trig, - struct iio_dev *indio_dev) -{ - struct iio_dev *indio = iio_trigger_get_drvdata(trig); - - if (indio != indio_dev) - return -EINVAL; - - return 0; -} - static irqreturn_t max1027_trigger_handler(int irq, void *private) { struct iio_poll_func *pf = (struct iio_poll_func *)private; @@ -391,7 +382,7 @@ static irqreturn_t max1027_trigger_handler(int irq, void *private) static const struct iio_trigger_ops max1027_trigger_ops = { .owner = THIS_MODULE, - .validate_device = &max1027_validate_device, + .validate_device = &iio_trigger_validate_own_device, .set_trigger_state = &max1027_set_trigger_state, }; diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index f4ba23effe9a..e952e94a14af 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -14,6 +14,10 @@ #include <linux/spi/spi.h> #include <linux/iio/iio.h> #include <linux/regulator/consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> enum { adc0831, @@ -38,10 +42,16 @@ struct adc0832 { .indexed = 1, \ .channel = chan, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = chan, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ } -#define ADC0832_VOLTAGE_CHANNEL_DIFF(chan1, chan2) \ +#define ADC0832_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -49,18 +59,26 @@ struct adc0832 { .channel2 = (chan2), \ .differential = 1, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = si, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 8, \ + }, \ } static const struct iio_chan_spec adc0831_channels[] = { - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 0), + IIO_CHAN_SOFT_TIMESTAMP(1), }; static const struct iio_chan_spec adc0832_channels[] = { ADC0832_VOLTAGE_CHANNEL(0), ADC0832_VOLTAGE_CHANNEL(1), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 2), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 3), + IIO_CHAN_SOFT_TIMESTAMP(4), }; static const struct iio_chan_spec adc0834_channels[] = { @@ -68,10 +86,11 @@ static const struct iio_chan_spec adc0834_channels[] = { ADC0832_VOLTAGE_CHANNEL(1), ADC0832_VOLTAGE_CHANNEL(2), ADC0832_VOLTAGE_CHANNEL(3), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), - ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3), - ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 4), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 5), + ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3, 6), + ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2, 7), + IIO_CHAN_SOFT_TIMESTAMP(8), }; static const struct iio_chan_spec adc0838_channels[] = { @@ -83,14 +102,15 @@ static const struct iio_chan_spec adc0838_channels[] = { ADC0832_VOLTAGE_CHANNEL(5), ADC0832_VOLTAGE_CHANNEL(6), ADC0832_VOLTAGE_CHANNEL(7), - ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1), - ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0), - ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3), - ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2), - ADC0832_VOLTAGE_CHANNEL_DIFF(4, 5), - ADC0832_VOLTAGE_CHANNEL_DIFF(5, 4), - ADC0832_VOLTAGE_CHANNEL_DIFF(6, 7), - ADC0832_VOLTAGE_CHANNEL_DIFF(7, 6), + ADC0832_VOLTAGE_CHANNEL_DIFF(0, 1, 8), + ADC0832_VOLTAGE_CHANNEL_DIFF(1, 0, 9), + ADC0832_VOLTAGE_CHANNEL_DIFF(2, 3, 10), + ADC0832_VOLTAGE_CHANNEL_DIFF(3, 2, 11), + ADC0832_VOLTAGE_CHANNEL_DIFF(4, 5, 12), + ADC0832_VOLTAGE_CHANNEL_DIFF(5, 4, 13), + ADC0832_VOLTAGE_CHANNEL_DIFF(6, 7, 14), + ADC0832_VOLTAGE_CHANNEL_DIFF(7, 6, 15), + IIO_CHAN_SOFT_TIMESTAMP(16), }; static int adc0831_adc_conversion(struct adc0832 *adc) @@ -178,6 +198,42 @@ static const struct iio_info adc0832_info = { .driver_module = THIS_MODULE, }; +static irqreturn_t adc0832_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adc0832 *adc = iio_priv(indio_dev); + u8 data[24] = { }; /* 16x 1 byte ADC data + 8 bytes timestamp */ + int scan_index; + int i = 0; + + mutex_lock(&adc->lock); + + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + const struct iio_chan_spec *scan_chan = + &indio_dev->channels[scan_index]; + int ret = adc0832_adc_conversion(adc, scan_chan->channel, + scan_chan->differential); + if (ret < 0) { + dev_warn(&adc->spi->dev, + "failed to get conversion data\n"); + goto out; + } + + data[i] = ret; + i++; + } + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); +out: + mutex_unlock(&adc->lock); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static int adc0832_probe(struct spi_device *spi) { struct iio_dev *indio_dev; @@ -233,9 +289,20 @@ static int adc0832_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + adc0832_trigger_handler, NULL); + if (ret) + goto err_reg_disable; + ret = iio_device_register(indio_dev); if (ret) - regulator_disable(adc->reg); + goto err_buffer_cleanup; + + return 0; +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +err_reg_disable: + regulator_disable(adc->reg); return ret; } @@ -246,6 +313,7 @@ static int adc0832_remove(struct spi_device *spi) struct adc0832 *adc = iio_priv(indio_dev); iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); regulator_disable(adc->reg); return 0; diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index f94b69f9c288..4836a0d7aef5 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -27,6 +27,7 @@ #include <linux/iio/buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <linux/regulator/consumer.h> #define TI_ADC_DRV_NAME "ti-adc161s626" @@ -39,7 +40,9 @@ static const struct iio_chan_spec ti_adc141s626_channels[] = { { .type = IIO_VOLTAGE, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 0, .scan_type = { .sign = 's', @@ -54,7 +57,9 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = { { .type = IIO_VOLTAGE, .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 0, .scan_type = { .sign = 's', @@ -68,6 +73,8 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = { struct ti_adc_data { struct iio_dev *indio_dev; struct spi_device *spi; + struct regulator *ref; + u8 read_size; u8 shift; @@ -135,18 +142,32 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev, struct ti_adc_data *data = iio_priv(indio_dev); int ret; - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; + ret = ti_adc_read_measurement(data, chan, val); + iio_device_release_direct_mode(indio_dev); - ret = ti_adc_read_measurement(data, chan, val); - iio_device_release_direct_mode(indio_dev); + if (ret) + return ret; - if (!ret) return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(data->ref); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + *val = 1 << (chan->scan_type.realbits - 1); + return IIO_VAL_INT; + } return 0; } @@ -191,10 +212,17 @@ static int ti_adc_probe(struct spi_device *spi) break; } + data->ref = devm_regulator_get(&spi->dev, "vdda"); + if (!IS_ERR(data->ref)) { + ret = regulator_enable(data->ref); + if (ret < 0) + return ret; + } + ret = iio_triggered_buffer_setup(indio_dev, NULL, ti_adc_trigger_handler, NULL); if (ret) - return ret; + goto error_regulator_disable; ret = iio_device_register(indio_dev); if (ret) @@ -205,15 +233,20 @@ static int ti_adc_probe(struct spi_device *spi) error_unreg_buffer: iio_triggered_buffer_cleanup(indio_dev); +error_regulator_disable: + regulator_disable(data->ref); + return ret; } static int ti_adc_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ti_adc_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(data->ref); return 0; } diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c new file mode 100644 index 000000000000..2d2ee353dde7 --- /dev/null +++ b/drivers/iio/counter/104-quad-8.c @@ -0,0 +1,593 @@ +/* + * IIO driver for the ACCES 104-QUAD-8 + * Copyright (C) 2016 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * This driver supports the ACCES 104-QUAD-8 and ACCES 104-QUAD-4. + */ +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/iio/iio.h> +#include <linux/iio/types.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/isa.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> + +#define QUAD8_EXTENT 32 + +static unsigned int base[max_num_isa_dev(QUAD8_EXTENT)]; +static unsigned int num_quad8; +module_param_array(base, uint, &num_quad8, 0); +MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses"); + +#define QUAD8_NUM_COUNTERS 8 + +/** + * struct quad8_iio - IIO device private data structure + * @preset: array of preset values + * @count_mode: array of count mode configurations + * @quadrature_mode: array of quadrature mode configurations + * @quadrature_scale: array of quadrature mode scale configurations + * @ab_enable: array of A and B inputs enable configurations + * @preset_enable: array of set_to_preset_on_index attribute configurations + * @synchronous_mode: array of index function synchronous mode configurations + * @index_polarity: array of index function polarity configurations + * @base: base port address of the IIO device + */ +struct quad8_iio { + unsigned int preset[QUAD8_NUM_COUNTERS]; + unsigned int count_mode[QUAD8_NUM_COUNTERS]; + unsigned int quadrature_mode[QUAD8_NUM_COUNTERS]; + unsigned int quadrature_scale[QUAD8_NUM_COUNTERS]; + unsigned int ab_enable[QUAD8_NUM_COUNTERS]; + unsigned int preset_enable[QUAD8_NUM_COUNTERS]; + unsigned int synchronous_mode[QUAD8_NUM_COUNTERS]; + unsigned int index_polarity[QUAD8_NUM_COUNTERS]; + unsigned int base; +}; + +static int quad8_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + unsigned int flags; + unsigned int borrow; + unsigned int carry; + int i; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_INDEX) { + *val = !!(inb(priv->base + 0x16) & BIT(chan->channel)); + return IIO_VAL_INT; + } + + flags = inb(base_offset); + borrow = flags & BIT(0); + carry = !!(flags & BIT(1)); + + /* Borrow XOR Carry effectively doubles count range */ + *val = (borrow ^ carry) << 24; + + /* Reset Byte Pointer; transfer Counter to Output Latch */ + outb(0x11, base_offset + 1); + + for (i = 0; i < 3; i++) + *val |= (unsigned int)inb(base_offset) << (8 * i); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_ENABLE: + *val = priv->ab_enable[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 1; + *val2 = priv->quadrature_scale[chan->channel]; + return IIO_VAL_FRACTIONAL_LOG2; + } + + return -EINVAL; +} + +static int quad8_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + int i; + unsigned int ior_cfg; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (chan->type == IIO_INDEX) + return -EINVAL; + + /* Only 24-bit values are supported */ + if ((unsigned int)val > 0xFFFFFF) + return -EINVAL; + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Counter can only be set via Preset Register */ + for (i = 0; i < 3; i++) + outb(val >> (8 * i), base_offset); + + /* Transfer Preset Register to Counter */ + outb(0x08, base_offset + 1); + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Set Preset Register back to original value */ + val = priv->preset[chan->channel]; + for (i = 0; i < 3; i++) + outb(val >> (8 * i), base_offset); + + /* Reset Borrow, Carry, Compare, and Sign flags */ + outb(0x02, base_offset + 1); + /* Reset Error flag */ + outb(0x06, base_offset + 1); + + return 0; + case IIO_CHAN_INFO_ENABLE: + /* only boolean values accepted */ + if (val < 0 || val > 1) + return -EINVAL; + + priv->ab_enable[chan->channel] = val; + + ior_cfg = val | priv->preset_enable[chan->channel] << 1; + + /* Load I/O control configuration */ + outb(0x40 | ior_cfg, base_offset); + + return 0; + case IIO_CHAN_INFO_SCALE: + /* Quadrature scaling only available in quadrature mode */ + if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) + return -EINVAL; + + /* Only three gain states (1, 0.5, 0.25) */ + if (val == 1 && !val2) + priv->quadrature_scale[chan->channel] = 0; + else if (!val) + switch (val2) { + case 500000: + priv->quadrature_scale[chan->channel] = 1; + break; + case 250000: + priv->quadrature_scale[chan->channel] = 2; + break; + default: + return -EINVAL; + } + else + return -EINVAL; + + return 0; + } + + return -EINVAL; +} + +static const struct iio_info quad8_info = { + .driver_module = THIS_MODULE, + .read_raw = quad8_read_raw, + .write_raw = quad8_write_raw +}; + +static ssize_t quad8_read_preset(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, char *buf) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", priv->preset[chan->channel]); +} + +static ssize_t quad8_write_preset(struct iio_dev *indio_dev, uintptr_t private, + const struct iio_chan_spec *chan, const char *buf, size_t len) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + unsigned int preset; + int ret; + int i; + + ret = kstrtouint(buf, 0, &preset); + if (ret) + return ret; + + /* Only 24-bit values are supported */ + if (preset > 0xFFFFFF) + return -EINVAL; + + priv->preset[chan->channel] = preset; + + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + + /* Set Preset Register */ + for (i = 0; i < 3; i++) + outb(preset >> (8 * i), base_offset); + + return len; +} + +static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, + uintptr_t private, const struct iio_chan_spec *chan, char *buf) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + priv->preset_enable[chan->channel]); +} + +static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, + uintptr_t private, const struct iio_chan_spec *chan, const char *buf, + size_t len) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel; + bool preset_enable; + int ret; + unsigned int ior_cfg; + + ret = kstrtobool(buf, &preset_enable); + if (ret) + return ret; + + priv->preset_enable[chan->channel] = preset_enable; + + ior_cfg = priv->ab_enable[chan->channel] | + (unsigned int)preset_enable << 1; + + /* Load I/O control configuration to Input / Output Control Register */ + outb(0x40 | ior_cfg, base_offset); + + return len; +} + +static const char *const quad8_noise_error_states[] = { + "No excessive noise is present at the count inputs", + "Excessive noise is present at the count inputs" +}; + +static int quad8_get_noise_error(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel + 1; + + return !!(inb(base_offset) & BIT(4)); +} + +static const struct iio_enum quad8_noise_error_enum = { + .items = quad8_noise_error_states, + .num_items = ARRAY_SIZE(quad8_noise_error_states), + .get = quad8_get_noise_error +}; + +static const char *const quad8_count_direction_states[] = { + "down", + "up" +}; + +static int quad8_get_count_direction(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const int base_offset = priv->base + 2 * chan->channel + 1; + + return !!(inb(base_offset) & BIT(5)); +} + +static const struct iio_enum quad8_count_direction_enum = { + .items = quad8_count_direction_states, + .num_items = ARRAY_SIZE(quad8_count_direction_states), + .get = quad8_get_count_direction +}; + +static const char *const quad8_count_modes[] = { + "normal", + "range limit", + "non-recycle", + "modulo-n" +}; + +static int quad8_set_count_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int count_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + unsigned int mode_cfg = count_mode << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + priv->count_mode[chan->channel] = count_mode; + + /* Add quadrature mode configuration */ + if (priv->quadrature_mode[chan->channel]) + mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; + + /* Load mode configuration to Counter Mode Register */ + outb(0x20 | mode_cfg, base_offset); + + return 0; +} + +static int quad8_get_count_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->count_mode[chan->channel]; +} + +static const struct iio_enum quad8_count_mode_enum = { + .items = quad8_count_modes, + .num_items = ARRAY_SIZE(quad8_count_modes), + .set = quad8_set_count_mode, + .get = quad8_get_count_mode +}; + +static const char *const quad8_synchronous_modes[] = { + "non-synchronous", + "synchronous" +}; + +static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int synchronous_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const unsigned int idr_cfg = synchronous_mode | + priv->index_polarity[chan->channel] << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + /* Index function must be non-synchronous in non-quadrature mode */ + if (synchronous_mode && !priv->quadrature_mode[chan->channel]) + return -EINVAL; + + priv->synchronous_mode[chan->channel] = synchronous_mode; + + /* Load Index Control configuration to Index Control Register */ + outb(0x40 | idr_cfg, base_offset); + + return 0; +} + +static int quad8_get_synchronous_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->synchronous_mode[chan->channel]; +} + +static const struct iio_enum quad8_synchronous_mode_enum = { + .items = quad8_synchronous_modes, + .num_items = ARRAY_SIZE(quad8_synchronous_modes), + .set = quad8_set_synchronous_mode, + .get = quad8_get_synchronous_mode +}; + +static const char *const quad8_quadrature_modes[] = { + "non-quadrature", + "quadrature" +}; + +static int quad8_set_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int quadrature_mode) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + unsigned int mode_cfg = priv->count_mode[chan->channel] << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + if (quadrature_mode) + mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; + else { + /* Quadrature scaling only available in quadrature mode */ + priv->quadrature_scale[chan->channel] = 0; + + /* Synchronous function not supported in non-quadrature mode */ + if (priv->synchronous_mode[chan->channel]) + quad8_set_synchronous_mode(indio_dev, chan, 0); + } + + priv->quadrature_mode[chan->channel] = quadrature_mode; + + /* Load mode configuration to Counter Mode Register */ + outb(0x20 | mode_cfg, base_offset); + + return 0; +} + +static int quad8_get_quadrature_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->quadrature_mode[chan->channel]; +} + +static const struct iio_enum quad8_quadrature_mode_enum = { + .items = quad8_quadrature_modes, + .num_items = ARRAY_SIZE(quad8_quadrature_modes), + .set = quad8_set_quadrature_mode, + .get = quad8_get_quadrature_mode +}; + +static const char *const quad8_index_polarity_modes[] = { + "negative", + "positive" +}; + +static int quad8_set_index_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, unsigned int index_polarity) +{ + struct quad8_iio *const priv = iio_priv(indio_dev); + const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | + index_polarity << 1; + const int base_offset = priv->base + 2 * chan->channel + 1; + + priv->index_polarity[chan->channel] = index_polarity; + + /* Load Index Control configuration to Index Control Register */ + outb(0x40 | idr_cfg, base_offset); + + return 0; +} + +static int quad8_get_index_polarity(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + const struct quad8_iio *const priv = iio_priv(indio_dev); + + return priv->index_polarity[chan->channel]; +} + +static const struct iio_enum quad8_index_polarity_enum = { + .items = quad8_index_polarity_modes, + .num_items = ARRAY_SIZE(quad8_index_polarity_modes), + .set = quad8_set_index_polarity, + .get = quad8_get_index_polarity +}; + +static const struct iio_chan_spec_ext_info quad8_count_ext_info[] = { + { + .name = "preset", + .shared = IIO_SEPARATE, + .read = quad8_read_preset, + .write = quad8_write_preset + }, + { + .name = "set_to_preset_on_index", + .shared = IIO_SEPARATE, + .read = quad8_read_set_to_preset_on_index, + .write = quad8_write_set_to_preset_on_index + }, + IIO_ENUM("noise_error", IIO_SEPARATE, &quad8_noise_error_enum), + IIO_ENUM_AVAILABLE("noise_error", &quad8_noise_error_enum), + IIO_ENUM("count_direction", IIO_SEPARATE, &quad8_count_direction_enum), + IIO_ENUM_AVAILABLE("count_direction", &quad8_count_direction_enum), + IIO_ENUM("count_mode", IIO_SEPARATE, &quad8_count_mode_enum), + IIO_ENUM_AVAILABLE("count_mode", &quad8_count_mode_enum), + IIO_ENUM("quadrature_mode", IIO_SEPARATE, &quad8_quadrature_mode_enum), + IIO_ENUM_AVAILABLE("quadrature_mode", &quad8_quadrature_mode_enum), + {} +}; + +static const struct iio_chan_spec_ext_info quad8_index_ext_info[] = { + IIO_ENUM("synchronous_mode", IIO_SEPARATE, + &quad8_synchronous_mode_enum), + IIO_ENUM_AVAILABLE("synchronous_mode", &quad8_synchronous_mode_enum), + IIO_ENUM("index_polarity", IIO_SEPARATE, &quad8_index_polarity_enum), + IIO_ENUM_AVAILABLE("index_polarity", &quad8_index_polarity_enum), + {} +}; + +#define QUAD8_COUNT_CHAN(_chan) { \ + .type = IIO_COUNT, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_ENABLE) | BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = quad8_count_ext_info, \ + .indexed = 1 \ +} + +#define QUAD8_INDEX_CHAN(_chan) { \ + .type = IIO_INDEX, \ + .channel = (_chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .ext_info = quad8_index_ext_info, \ + .indexed = 1 \ +} + +static const struct iio_chan_spec quad8_channels[] = { + QUAD8_COUNT_CHAN(0), QUAD8_INDEX_CHAN(0), + QUAD8_COUNT_CHAN(1), QUAD8_INDEX_CHAN(1), + QUAD8_COUNT_CHAN(2), QUAD8_INDEX_CHAN(2), + QUAD8_COUNT_CHAN(3), QUAD8_INDEX_CHAN(3), + QUAD8_COUNT_CHAN(4), QUAD8_INDEX_CHAN(4), + QUAD8_COUNT_CHAN(5), QUAD8_INDEX_CHAN(5), + QUAD8_COUNT_CHAN(6), QUAD8_INDEX_CHAN(6), + QUAD8_COUNT_CHAN(7), QUAD8_INDEX_CHAN(7) +}; + +static int quad8_probe(struct device *dev, unsigned int id) +{ + struct iio_dev *indio_dev; + struct quad8_iio *priv; + int i, j; + unsigned int base_offset; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + if (!devm_request_region(dev, base[id], QUAD8_EXTENT, + dev_name(dev))) { + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", + base[id], base[id] + QUAD8_EXTENT); + return -EBUSY; + } + + indio_dev->info = &quad8_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = ARRAY_SIZE(quad8_channels); + indio_dev->channels = quad8_channels; + indio_dev->name = dev_name(dev); + + priv = iio_priv(indio_dev); + priv->base = base[id]; + + /* Reset all counters and disable interrupt function */ + outb(0x01, base[id] + 0x11); + /* Set initial configuration for all counters */ + for (i = 0; i < QUAD8_NUM_COUNTERS; i++) { + base_offset = base[id] + 2 * i; + /* Reset Byte Pointer */ + outb(0x01, base_offset + 1); + /* Reset Preset Register */ + for (j = 0; j < 3; j++) + outb(0x00, base_offset); + /* Reset Borrow, Carry, Compare, and Sign flags */ + outb(0x04, base_offset + 1); + /* Reset Error flag */ + outb(0x06, base_offset + 1); + /* Binary encoding; Normal count; non-quadrature mode */ + outb(0x20, base_offset + 1); + /* Disable A and B inputs; preset on index; FLG1 as Carry */ + outb(0x40, base_offset + 1); + /* Disable index function; negative index polarity */ + outb(0x60, base_offset + 1); + } + /* Enable all counters */ + outb(0x00, base[id] + 0x11); + + return devm_iio_device_register(dev, indio_dev); +} + +static struct isa_driver quad8_driver = { + .probe = quad8_probe, + .driver = { + .name = "104-quad-8" + } +}; + +module_isa_driver(quad8_driver, num_quad8); + +MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); +MODULE_DESCRIPTION("ACCES 104-QUAD-8 IIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/counter/Kconfig b/drivers/iio/counter/Kconfig new file mode 100644 index 000000000000..44627f6e4861 --- /dev/null +++ b/drivers/iio/counter/Kconfig @@ -0,0 +1,24 @@ +# +# Counter devices +# +# When adding new entries keep the list in alphabetical order + +menu "Counters" + +config 104_QUAD_8 + tristate "ACCES 104-QUAD-8 driver" + depends on X86 && ISA_BUS_API + help + Say yes here to build support for the ACCES 104-QUAD-8 quadrature + encoder counter/interface device family (104-QUAD-8, 104-QUAD-4). + + Performing a write to a counter's IIO_CHAN_INFO_RAW sets the counter and + also clears the counter's respective error flag. Although the counters + have a 25-bit range, only the lower 24 bits may be set, either directly + or via a counter's preset attribute. Interrupts are not supported by + this driver. + + The base port addresses for the devices may be configured via the base + array module parameter. + +endmenu diff --git a/drivers/iio/counter/Makefile b/drivers/iio/counter/Makefile new file mode 100644 index 000000000000..007e88411648 --- /dev/null +++ b/drivers/iio/counter/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for IIO counter devices +# + +# When adding new entries keep the list in alphabetical order + +obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 0b235a2c7359..6eed5b7729be 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -17,7 +17,7 @@ #define AD5592R_GPIO_READBACK_EN BIT(10) #define AD5592R_LDAC_READBACK_EN BIT(6) -static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, u16 *buf) +static int ad5592r_spi_wnop_r16(struct ad5592r_state *st, __be16 *buf) { struct spi_device *spi = container_of(st->dev, struct spi_device, dev); struct spi_transfer t = { diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index cca935c06f2b..db109f0cdd8c 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -18,6 +18,8 @@ #include <linux/i2c.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -26,12 +28,20 @@ #define MCP4725_DRV_NAME "mcp4725" +#define MCP472X_REF_VDD 0x00 +#define MCP472X_REF_VREF_UNBUFFERED 0x02 +#define MCP472X_REF_VREF_BUFFERED 0x03 + struct mcp4725_data { struct i2c_client *client; - u16 vref_mv; + int id; + unsigned ref_mode; + bool vref_buffered; u16 dac_value; bool powerdown; unsigned powerdown_mode; + struct regulator *vdd_reg; + struct regulator *vref_reg; }; static int mcp4725_suspend(struct device *dev) @@ -86,6 +96,7 @@ static ssize_t mcp4725_store_eeprom(struct device *dev, return 0; inoutbuf[0] = 0x60; /* write EEPROM */ + inoutbuf[0] |= data->ref_mode << 3; inoutbuf[1] = data->dac_value >> 4; inoutbuf[2] = (data->dac_value & 0xf) << 4; @@ -278,18 +289,49 @@ static int mcp4725_set_value(struct iio_dev *indio_dev, int val) return 0; } +static int mcp4726_set_cfg(struct iio_dev *indio_dev) +{ + struct mcp4725_data *data = iio_priv(indio_dev); + u8 outbuf[3]; + int ret; + + outbuf[0] = 0x40; + outbuf[0] |= data->ref_mode << 3; + if (data->powerdown) + outbuf[0] |= data->powerdown << 1; + outbuf[1] = data->dac_value >> 4; + outbuf[2] = (data->dac_value & 0xf) << 4; + + ret = i2c_master_send(data->client, outbuf, 3); + if (ret < 0) + return ret; + else if (ret != 3) + return -EIO; + else + return 0; +} + static int mcp4725_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct mcp4725_data *data = iio_priv(indio_dev); + int ret; switch (mask) { case IIO_CHAN_INFO_RAW: *val = data->dac_value; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = data->vref_mv; + if (data->ref_mode == MCP472X_REF_VDD) + ret = regulator_get_voltage(data->vdd_reg); + else + ret = regulator_get_voltage(data->vref_reg); + + if (ret < 0) + return ret; + + *val = ret / 1000; *val2 = 12; return IIO_VAL_FRACTIONAL_LOG2; } @@ -323,27 +365,98 @@ static const struct iio_info mcp4725_info = { .driver_module = THIS_MODULE, }; +#ifdef CONFIG_OF +static int mcp4725_probe_dt(struct device *dev, + struct mcp4725_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + + if (!np) + return -ENODEV; + + /* check if is the vref-supply defined */ + pdata->use_vref = of_property_read_bool(np, "vref-supply"); + pdata->vref_buffered = + of_property_read_bool(np, "microchip,vref-buffered"); + + return 0; +} +#else +static int mcp4725_probe_dt(struct device *dev, + struct mcp4725_platform_data *platform_data) +{ + return -ENODEV; +} +#endif + static int mcp4725_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mcp4725_data *data; struct iio_dev *indio_dev; - struct mcp4725_platform_data *platform_data = client->dev.platform_data; - u8 inbuf[3]; + struct mcp4725_platform_data *pdata, pdata_dt; + u8 inbuf[4]; u8 pd; + u8 ref; int err; - if (!platform_data || !platform_data->vref_mv) { - dev_err(&client->dev, "invalid platform data"); - return -EINVAL; - } - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (indio_dev == NULL) return -ENOMEM; data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; + data->id = id->driver_data; + pdata = dev_get_platdata(&client->dev); + + if (!pdata) { + err = mcp4725_probe_dt(&client->dev, &pdata_dt); + if (err) { + dev_err(&client->dev, + "invalid platform or devicetree data"); + return err; + } + pdata = &pdata_dt; + } + + if (data->id == MCP4725 && pdata->use_vref) { + dev_err(&client->dev, + "external reference is unavailable on MCP4725"); + return -EINVAL; + } + + if (!pdata->use_vref && pdata->vref_buffered) { + dev_err(&client->dev, + "buffering is unavailable on the internal reference"); + return -EINVAL; + } + + if (!pdata->use_vref) + data->ref_mode = MCP472X_REF_VDD; + else + data->ref_mode = pdata->vref_buffered ? + MCP472X_REF_VREF_BUFFERED : + MCP472X_REF_VREF_UNBUFFERED; + + data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(data->vdd_reg)) + return PTR_ERR(data->vdd_reg); + + err = regulator_enable(data->vdd_reg); + if (err) + return err; + + if (pdata->use_vref) { + data->vref_reg = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(data->vref_reg)) { + err = PTR_ERR(data->vref_reg); + goto err_disable_vdd_reg; + } + + err = regulator_enable(data->vref_reg); + if (err) + goto err_disable_vdd_reg; + } indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; @@ -352,25 +465,56 @@ static int mcp4725_probe(struct i2c_client *client, indio_dev->num_channels = 1; indio_dev->modes = INDIO_DIRECT_MODE; - data->vref_mv = platform_data->vref_mv; + /* read current DAC value and settings */ + err = i2c_master_recv(client, inbuf, data->id == MCP4725 ? 3 : 4); - /* read current DAC value */ - err = i2c_master_recv(client, inbuf, 3); if (err < 0) { dev_err(&client->dev, "failed to read DAC value"); - return err; + goto err_disable_vref_reg; } pd = (inbuf[0] >> 1) & 0x3; data->powerdown = pd > 0 ? true : false; - data->powerdown_mode = pd ? pd - 1 : 2; /* largest register to gnd */ + data->powerdown_mode = pd ? pd - 1 : 2; /* largest resistor to gnd */ data->dac_value = (inbuf[1] << 4) | (inbuf[2] >> 4); + if (data->id == MCP4726) + ref = (inbuf[3] >> 3) & 0x3; + + if (data->id == MCP4726 && ref != data->ref_mode) { + dev_info(&client->dev, + "voltage reference mode differs (conf: %u, eeprom: %u), setting %u", + data->ref_mode, ref, data->ref_mode); + err = mcp4726_set_cfg(indio_dev); + if (err < 0) + goto err_disable_vref_reg; + } + + err = iio_device_register(indio_dev); + if (err) + goto err_disable_vref_reg; + + return 0; + +err_disable_vref_reg: + if (data->vref_reg) + regulator_disable(data->vref_reg); - return iio_device_register(indio_dev); +err_disable_vdd_reg: + regulator_disable(data->vdd_reg); + + return err; } static int mcp4725_remove(struct i2c_client *client) { - iio_device_unregister(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mcp4725_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + if (data->vref_reg) + regulator_disable(data->vref_reg); + regulator_disable(data->vdd_reg); + return 0; } diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index b17e2e2bd4f5..912477d54be2 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -27,6 +27,8 @@ config DHT11 config HDC100X tristate "TI HDC100x relative humidity and temperature sensor" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for the Texas Instruments HDC1000 and HDC1008 relative humidity and temperature sensors. @@ -34,6 +36,28 @@ config HDC100X To compile this driver as a module, choose M here: the module will be called hdc100x. +config HTS221 + tristate "STMicroelectronics HTS221 sensor Driver" + depends on (I2C || SPI) + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HTS221_I2C if (I2C) + select HTS221_SPI if (SPI_MASTER) + help + Say yes here to build support for STMicroelectronics HTS221 + temperature-humidity sensor + + To compile this driver as a module, choose M here: the module + will be called hts221. + +config HTS221_I2C + tristate + depends on HTS221 + +config HTS221_SPI + tristate + depends on HTS221 + config HTU21 tristate "Measurement Specialties HTU21 humidity & temperature sensor" depends on I2C diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile index 4a73442fcd9c..a6850e47c100 100644 --- a/drivers/iio/humidity/Makefile +++ b/drivers/iio/humidity/Makefile @@ -5,6 +5,13 @@ obj-$(CONFIG_AM2315) += am2315.o obj-$(CONFIG_DHT11) += dht11.o obj-$(CONFIG_HDC100X) += hdc100x.o + +hts221-y := hts221_core.o \ + hts221_buffer.o +obj-$(CONFIG_HTS221) += hts221.o +obj-$(CONFIG_HTS221_I2C) += hts221_i2c.o +obj-$(CONFIG_HTS221_SPI) += hts221_spi.o + obj-$(CONFIG_HTU21) += htu21.o obj-$(CONFIG_SI7005) += si7005.o obj-$(CONFIG_SI7020) += si7020.o diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index e0c9c70c2a4a..265c34da52d1 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -22,11 +22,15 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define HDC100X_REG_TEMP 0x00 #define HDC100X_REG_HUMIDITY 0x01 #define HDC100X_REG_CONFIG 0x02 +#define HDC100X_REG_CONFIG_ACQ_MODE BIT(12) #define HDC100X_REG_CONFIG_HEATER_EN BIT(13) struct hdc100x_data { @@ -87,22 +91,40 @@ static const struct iio_chan_spec hdc100x_channels[] = { BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_INT_TIME) | BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, }, { .type = IIO_HUMIDITYRELATIVE, .address = HDC100X_REG_HUMIDITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_INT_TIME) + BIT(IIO_CHAN_INFO_INT_TIME), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_BE, + }, }, { .type = IIO_CURRENT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .extend_name = "heater", .output = 1, + .scan_index = -1, }, + IIO_CHAN_SOFT_TIMESTAMP(2), }; +static const unsigned long hdc100x_scan_masks[] = {0x3, 0}; + static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val) { int tmp = (~mask & data->config) | val; @@ -183,7 +205,14 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev, *val = hdc100x_get_heater_status(data); ret = IIO_VAL_INT; } else { + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) { + mutex_unlock(&data->lock); + return ret; + } + ret = hdc100x_get_measurement(data, chan); + iio_device_release_direct_mode(indio_dev); if (ret >= 0) { *val = ret; ret = IIO_VAL_INT; @@ -246,6 +275,78 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev, } } +static int hdc100x_buffer_postenable(struct iio_dev *indio_dev) +{ + struct hdc100x_data *data = iio_priv(indio_dev); + int ret; + + /* Buffer is enabled. First set ACQ Mode, then attach poll func */ + mutex_lock(&data->lock); + ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, + HDC100X_REG_CONFIG_ACQ_MODE); + mutex_unlock(&data->lock); + if (ret) + return ret; + + return iio_triggered_buffer_postenable(indio_dev); +} + +static int hdc100x_buffer_predisable(struct iio_dev *indio_dev) +{ + struct hdc100x_data *data = iio_priv(indio_dev); + int ret; + + /* First detach poll func, then reset ACQ mode. OK to disable buffer */ + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret) + return ret; + + mutex_lock(&data->lock); + ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); + mutex_unlock(&data->lock); + + return ret; +} + +static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = { + .postenable = hdc100x_buffer_postenable, + .predisable = hdc100x_buffer_predisable, +}; + +static irqreturn_t hdc100x_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct hdc100x_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int delay = data->adc_int_us[0] + data->adc_int_us[1]; + int ret; + s16 buf[8]; /* 2x s16 + padding + 8 byte timestamp */ + + /* dual read starts at temp register */ + mutex_lock(&data->lock); + ret = i2c_smbus_write_byte(client, HDC100X_REG_TEMP); + if (ret < 0) { + dev_err(&client->dev, "cannot start measurement\n"); + goto err; + } + usleep_range(delay, delay + 1000); + + ret = i2c_master_recv(client, (u8 *)buf, 4); + if (ret < 0) { + dev_err(&client->dev, "cannot read sensor data\n"); + goto err; + } + + iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_get_time_ns(indio_dev)); +err: + mutex_unlock(&data->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct iio_info hdc100x_info = { .read_raw = hdc100x_read_raw, .write_raw = hdc100x_write_raw, @@ -258,6 +359,7 @@ static int hdc100x_probe(struct i2c_client *client, { struct iio_dev *indio_dev; struct hdc100x_data *data; + int ret; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) @@ -279,12 +381,35 @@ static int hdc100x_probe(struct i2c_client *client, indio_dev->channels = hdc100x_channels; indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels); + indio_dev->available_scan_masks = hdc100x_scan_masks; /* be sure we are in a known state */ hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]); hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]); + hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0); + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + hdc100x_trigger_handler, + &hdc_buffer_setup_ops); + if (ret < 0) { + dev_err(&client->dev, "iio triggered buffer setup failed\n"); + return ret; + } + ret = iio_device_register(indio_dev); + if (ret < 0) + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} + +static int hdc100x_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); - return devm_iio_device_register(&client->dev, indio_dev); + return 0; } static const struct i2c_device_id hdc100x_id[] = { @@ -298,6 +423,7 @@ static struct i2c_driver hdc100x_driver = { .name = "hdc100x", }, .probe = hdc100x_probe, + .remove = hdc100x_remove, .id_table = hdc100x_id, }; module_i2c_driver(hdc100x_driver); diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h new file mode 100644 index 000000000000..c7154665512e --- /dev/null +++ b/drivers/iio/humidity/hts221.h @@ -0,0 +1,73 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi <lorenzo.bianconi@st.com> + * + * Licensed under the GPL-2. + */ + +#ifndef HTS221_H +#define HTS221_H + +#define HTS221_DEV_NAME "hts221" + +#include <linux/iio/iio.h> + +#define HTS221_RX_MAX_LENGTH 8 +#define HTS221_TX_MAX_LENGTH 8 + +#define HTS221_DATA_SIZE 2 + +struct hts221_transfer_buffer { + u8 rx_buf[HTS221_RX_MAX_LENGTH]; + u8 tx_buf[HTS221_TX_MAX_LENGTH] ____cacheline_aligned; +}; + +struct hts221_transfer_function { + int (*read)(struct device *dev, u8 addr, int len, u8 *data); + int (*write)(struct device *dev, u8 addr, int len, u8 *data); +}; + +#define HTS221_AVG_DEPTH 8 +struct hts221_avg_avl { + u16 avg; + u8 val; +}; + +enum hts221_sensor_type { + HTS221_SENSOR_H, + HTS221_SENSOR_T, + HTS221_SENSOR_MAX, +}; + +struct hts221_sensor { + u8 cur_avg_idx; + int slope, b_gen; +}; + +struct hts221_hw { + const char *name; + struct device *dev; + + struct mutex lock; + struct iio_trigger *trig; + int irq; + + struct hts221_sensor sensors[HTS221_SENSOR_MAX]; + + u8 odr; + + const struct hts221_transfer_function *tf; + struct hts221_transfer_buffer tb; +}; + +int hts221_config_drdy(struct hts221_hw *hw, bool enable); +int hts221_probe(struct iio_dev *iio_dev); +int hts221_power_on(struct hts221_hw *hw); +int hts221_power_off(struct hts221_hw *hw); +int hts221_allocate_buffers(struct hts221_hw *hw); +int hts221_allocate_trigger(struct hts221_hw *hw); + +#endif /* HTS221_H */ diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c new file mode 100644 index 000000000000..76b2e8130b6f --- /dev/null +++ b/drivers/iio/humidity/hts221_buffer.c @@ -0,0 +1,169 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi <lorenzo.bianconi@st.com> + * + * Licensed under the GPL-2. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/irqreturn.h> + +#include <linux/iio/iio.h> +#include <linux/iio/trigger.h> +#include <linux/interrupt.h> +#include <linux/iio/events.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/buffer.h> + +#include "hts221.h" + +#define HTS221_REG_STATUS_ADDR 0x27 +#define HTS221_RH_DRDY_MASK BIT(1) +#define HTS221_TEMP_DRDY_MASK BIT(0) + +static int hts221_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig); + struct hts221_hw *hw = iio_priv(iio_dev); + + return hts221_config_drdy(hw, state); +} + +static const struct iio_trigger_ops hts221_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = hts221_trig_set_state, +}; + +static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) +{ + struct hts221_hw *hw = (struct hts221_hw *)private; + u8 status; + int err; + + err = hw->tf->read(hw->dev, HTS221_REG_STATUS_ADDR, sizeof(status), + &status); + if (err < 0) + return IRQ_HANDLED; + + /* + * H_DA bit (humidity data available) is routed to DRDY line. + * Humidity sample is computed after temperature one. + * Here we can assume data channels are both available if H_DA bit + * is set in status register + */ + if (!(status & HTS221_RH_DRDY_MASK)) + return IRQ_NONE; + + iio_trigger_poll_chained(hw->trig); + + return IRQ_HANDLED; +} + +int hts221_allocate_trigger(struct hts221_hw *hw) +{ + struct iio_dev *iio_dev = iio_priv_to_dev(hw); + unsigned long irq_type; + int err; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + break; + default: + dev_info(hw->dev, + "mode %lx unsupported, using IRQF_TRIGGER_RISING\n", + irq_type); + irq_type = IRQF_TRIGGER_RISING; + break; + } + + err = devm_request_threaded_irq(hw->dev, hw->irq, NULL, + hts221_trigger_handler_thread, + irq_type | IRQF_ONESHOT, + hw->name, hw); + if (err) { + dev_err(hw->dev, "failed to request trigger irq %d\n", + hw->irq); + return err; + } + + hw->trig = devm_iio_trigger_alloc(hw->dev, "%s-trigger", + iio_dev->name); + if (!hw->trig) + return -ENOMEM; + + iio_trigger_set_drvdata(hw->trig, iio_dev); + hw->trig->ops = &hts221_trigger_ops; + hw->trig->dev.parent = hw->dev; + iio_dev->trig = iio_trigger_get(hw->trig); + + return devm_iio_trigger_register(hw->dev, hw->trig); +} + +static int hts221_buffer_preenable(struct iio_dev *iio_dev) +{ + return hts221_power_on(iio_priv(iio_dev)); +} + +static int hts221_buffer_postdisable(struct iio_dev *iio_dev) +{ + return hts221_power_off(iio_priv(iio_dev)); +} + +static const struct iio_buffer_setup_ops hts221_buffer_ops = { + .preenable = hts221_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = hts221_buffer_postdisable, +}; + +static irqreturn_t hts221_buffer_handler_thread(int irq, void *p) +{ + u8 buffer[ALIGN(2 * HTS221_DATA_SIZE, sizeof(s64)) + sizeof(s64)]; + struct iio_poll_func *pf = p; + struct iio_dev *iio_dev = pf->indio_dev; + struct hts221_hw *hw = iio_priv(iio_dev); + struct iio_chan_spec const *ch; + int err; + + /* humidity data */ + ch = &iio_dev->channels[HTS221_SENSOR_H]; + err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, + buffer); + if (err < 0) + goto out; + + /* temperature data */ + ch = &iio_dev->channels[HTS221_SENSOR_T]; + err = hw->tf->read(hw->dev, ch->address, HTS221_DATA_SIZE, + buffer + HTS221_DATA_SIZE); + if (err < 0) + goto out; + + iio_push_to_buffers_with_timestamp(iio_dev, buffer, + iio_get_time_ns(iio_dev)); + +out: + iio_trigger_notify_done(hw->trig); + + return IRQ_HANDLED; +} + +int hts221_allocate_buffers(struct hts221_hw *hw) +{ + return devm_iio_triggered_buffer_setup(hw->dev, iio_priv_to_dev(hw), + NULL, hts221_buffer_handler_thread, + &hts221_buffer_ops); +} + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics hts221 buffer driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c new file mode 100644 index 000000000000..3f3ef4a1a474 --- /dev/null +++ b/drivers/iio/humidity/hts221_core.c @@ -0,0 +1,687 @@ +/* + * STMicroelectronics hts221 sensor driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi <lorenzo.bianconi@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/iio/sysfs.h> +#include <linux/delay.h> +#include <asm/unaligned.h> + +#include "hts221.h" + +#define HTS221_REG_WHOAMI_ADDR 0x0f +#define HTS221_REG_WHOAMI_VAL 0xbc + +#define HTS221_REG_CNTRL1_ADDR 0x20 +#define HTS221_REG_CNTRL2_ADDR 0x21 +#define HTS221_REG_CNTRL3_ADDR 0x22 + +#define HTS221_REG_AVG_ADDR 0x10 +#define HTS221_REG_H_OUT_L 0x28 +#define HTS221_REG_T_OUT_L 0x2a + +#define HTS221_HUMIDITY_AVG_MASK 0x07 +#define HTS221_TEMP_AVG_MASK 0x38 + +#define HTS221_ODR_MASK 0x87 +#define HTS221_BDU_MASK BIT(2) + +#define HTS221_DRDY_MASK BIT(2) + +#define HTS221_ENABLE_SENSOR BIT(7) + +#define HTS221_HUMIDITY_AVG_4 0x00 /* 0.4 %RH */ +#define HTS221_HUMIDITY_AVG_8 0x01 /* 0.3 %RH */ +#define HTS221_HUMIDITY_AVG_16 0x02 /* 0.2 %RH */ +#define HTS221_HUMIDITY_AVG_32 0x03 /* 0.15 %RH */ +#define HTS221_HUMIDITY_AVG_64 0x04 /* 0.1 %RH */ +#define HTS221_HUMIDITY_AVG_128 0x05 /* 0.07 %RH */ +#define HTS221_HUMIDITY_AVG_256 0x06 /* 0.05 %RH */ +#define HTS221_HUMIDITY_AVG_512 0x07 /* 0.03 %RH */ + +#define HTS221_TEMP_AVG_2 0x00 /* 0.08 degC */ +#define HTS221_TEMP_AVG_4 0x08 /* 0.05 degC */ +#define HTS221_TEMP_AVG_8 0x10 /* 0.04 degC */ +#define HTS221_TEMP_AVG_16 0x18 /* 0.03 degC */ +#define HTS221_TEMP_AVG_32 0x20 /* 0.02 degC */ +#define HTS221_TEMP_AVG_64 0x28 /* 0.015 degC */ +#define HTS221_TEMP_AVG_128 0x30 /* 0.01 degC */ +#define HTS221_TEMP_AVG_256 0x38 /* 0.007 degC */ + +/* calibration registers */ +#define HTS221_REG_0RH_CAL_X_H 0x36 +#define HTS221_REG_1RH_CAL_X_H 0x3a +#define HTS221_REG_0RH_CAL_Y_H 0x30 +#define HTS221_REG_1RH_CAL_Y_H 0x31 +#define HTS221_REG_0T_CAL_X_L 0x3c +#define HTS221_REG_1T_CAL_X_L 0x3e +#define HTS221_REG_0T_CAL_Y_H 0x32 +#define HTS221_REG_1T_CAL_Y_H 0x33 +#define HTS221_REG_T1_T0_CAL_Y_H 0x35 + +struct hts221_odr { + u8 hz; + u8 val; +}; + +struct hts221_avg { + u8 addr; + u8 mask; + struct hts221_avg_avl avg_avl[HTS221_AVG_DEPTH]; +}; + +static const struct hts221_odr hts221_odr_table[] = { + { 1, 0x01 }, /* 1Hz */ + { 7, 0x02 }, /* 7Hz */ + { 13, 0x03 }, /* 12.5Hz */ +}; + +static const struct hts221_avg hts221_avg_list[] = { + { + .addr = HTS221_REG_AVG_ADDR, + .mask = HTS221_HUMIDITY_AVG_MASK, + .avg_avl = { + { 4, HTS221_HUMIDITY_AVG_4 }, + { 8, HTS221_HUMIDITY_AVG_8 }, + { 16, HTS221_HUMIDITY_AVG_16 }, + { 32, HTS221_HUMIDITY_AVG_32 }, + { 64, HTS221_HUMIDITY_AVG_64 }, + { 128, HTS221_HUMIDITY_AVG_128 }, + { 256, HTS221_HUMIDITY_AVG_256 }, + { 512, HTS221_HUMIDITY_AVG_512 }, + }, + }, + { + .addr = HTS221_REG_AVG_ADDR, + .mask = HTS221_TEMP_AVG_MASK, + .avg_avl = { + { 2, HTS221_TEMP_AVG_2 }, + { 4, HTS221_TEMP_AVG_4 }, + { 8, HTS221_TEMP_AVG_8 }, + { 16, HTS221_TEMP_AVG_16 }, + { 32, HTS221_TEMP_AVG_32 }, + { 64, HTS221_TEMP_AVG_64 }, + { 128, HTS221_TEMP_AVG_128 }, + { 256, HTS221_TEMP_AVG_256 }, + }, + }, +}; + +static const struct iio_chan_spec hts221_channels[] = { + { + .type = IIO_HUMIDITYRELATIVE, + .address = HTS221_REG_H_OUT_L, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + { + .type = IIO_TEMP, + .address = HTS221_REG_T_OUT_L, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + .scan_index = 1, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_LE, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(2), +}; + +static int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, + u8 val) +{ + u8 data; + int err; + + mutex_lock(&hw->lock); + + err = hw->tf->read(hw->dev, addr, sizeof(data), &data); + if (err < 0) { + dev_err(hw->dev, "failed to read %02x register\n", addr); + goto unlock; + } + + data = (data & ~mask) | (val & mask); + + err = hw->tf->write(hw->dev, addr, sizeof(data), &data); + if (err < 0) + dev_err(hw->dev, "failed to write %02x register\n", addr); + +unlock: + mutex_unlock(&hw->lock); + + return err; +} + +static int hts221_check_whoami(struct hts221_hw *hw) +{ + u8 data; + int err; + + err = hw->tf->read(hw->dev, HTS221_REG_WHOAMI_ADDR, sizeof(data), + &data); + if (err < 0) { + dev_err(hw->dev, "failed to read whoami register\n"); + return err; + } + + if (data != HTS221_REG_WHOAMI_VAL) { + dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n", + data, HTS221_REG_WHOAMI_VAL); + return -ENODEV; + } + + return 0; +} + +int hts221_config_drdy(struct hts221_hw *hw, bool enable) +{ + u8 val = enable ? BIT(2) : 0; + int err; + + err = hts221_write_with_mask(hw, HTS221_REG_CNTRL3_ADDR, + HTS221_DRDY_MASK, val); + + return err < 0 ? err : 0; +} + +static int hts221_update_odr(struct hts221_hw *hw, u8 odr) +{ + int i, err; + u8 val; + + for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) + if (hts221_odr_table[i].hz == odr) + break; + + if (i == ARRAY_SIZE(hts221_odr_table)) + return -EINVAL; + + val = HTS221_ENABLE_SENSOR | HTS221_BDU_MASK | hts221_odr_table[i].val; + err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR, + HTS221_ODR_MASK, val); + if (err < 0) + return err; + + hw->odr = odr; + + return 0; +} + +static int hts221_update_avg(struct hts221_hw *hw, + enum hts221_sensor_type type, + u16 val) +{ + int i, err; + const struct hts221_avg *avg = &hts221_avg_list[type]; + + for (i = 0; i < HTS221_AVG_DEPTH; i++) + if (avg->avg_avl[i].avg == val) + break; + + if (i == HTS221_AVG_DEPTH) + return -EINVAL; + + err = hts221_write_with_mask(hw, avg->addr, avg->mask, + avg->avg_avl[i].val); + if (err < 0) + return err; + + hw->sensors[type].cur_avg_idx = i; + + return 0; +} + +static ssize_t hts221_sysfs_sampling_freq(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + ssize_t len = 0; + + for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + hts221_odr_table[i].hz); + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t +hts221_sysfs_rh_oversampling_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H]; + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + avg->avg_avl[i].avg); + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t +hts221_sysfs_temp_oversampling_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T]; + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", + avg->avg_avl[i].avg); + buf[len - 1] = '\n'; + + return len; +} + +int hts221_power_on(struct hts221_hw *hw) +{ + return hts221_update_odr(hw, hw->odr); +} + +int hts221_power_off(struct hts221_hw *hw) +{ + u8 data[] = {0x00, 0x00}; + + return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), + data); +} + +static int hts221_parse_temp_caldata(struct hts221_hw *hw) +{ + int err, *slope, *b_gen; + s16 cal_x0, cal_x1, cal_y0, cal_y1; + u8 cal0, cal1; + + err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_Y_H, + sizeof(cal0), &cal0); + if (err < 0) + return err; + + err = hw->tf->read(hw->dev, HTS221_REG_T1_T0_CAL_Y_H, + sizeof(cal1), &cal1); + if (err < 0) + return err; + cal_y0 = (le16_to_cpu(cal1 & 0x3) << 8) | cal0; + + err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_Y_H, + sizeof(cal0), &cal0); + if (err < 0) + return err; + cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0; + + err = hw->tf->read(hw->dev, HTS221_REG_0T_CAL_X_L, sizeof(cal_x0), + (u8 *)&cal_x0); + if (err < 0) + return err; + cal_x0 = le16_to_cpu(cal_x0); + + err = hw->tf->read(hw->dev, HTS221_REG_1T_CAL_X_L, sizeof(cal_x1), + (u8 *)&cal_x1); + if (err < 0) + return err; + cal_x1 = le16_to_cpu(cal_x1); + + slope = &hw->sensors[HTS221_SENSOR_T].slope; + b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen; + + *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); + *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / + (cal_x1 - cal_x0); + *b_gen *= 8; + + return 0; +} + +static int hts221_parse_rh_caldata(struct hts221_hw *hw) +{ + int err, *slope, *b_gen; + s16 cal_x0, cal_x1, cal_y0, cal_y1; + u8 data; + + err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_Y_H, sizeof(data), + &data); + if (err < 0) + return err; + cal_y0 = data; + + err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_Y_H, sizeof(data), + &data); + if (err < 0) + return err; + cal_y1 = data; + + err = hw->tf->read(hw->dev, HTS221_REG_0RH_CAL_X_H, sizeof(cal_x0), + (u8 *)&cal_x0); + if (err < 0) + return err; + cal_x0 = le16_to_cpu(cal_x0); + + err = hw->tf->read(hw->dev, HTS221_REG_1RH_CAL_X_H, sizeof(cal_x1), + (u8 *)&cal_x1); + if (err < 0) + return err; + cal_x1 = le16_to_cpu(cal_x1); + + slope = &hw->sensors[HTS221_SENSOR_H].slope; + b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen; + + *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); + *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / + (cal_x1 - cal_x0); + *b_gen *= 8; + + return 0; +} + +static int hts221_get_sensor_scale(struct hts221_hw *hw, + enum iio_chan_type ch_type, + int *val, int *val2) +{ + s64 tmp; + s32 rem, div, data; + + switch (ch_type) { + case IIO_HUMIDITYRELATIVE: + data = hw->sensors[HTS221_SENSOR_H].slope; + div = (1 << 4) * 1000; + break; + case IIO_TEMP: + data = hw->sensors[HTS221_SENSOR_T].slope; + div = (1 << 6) * 1000; + break; + default: + return -EINVAL; + } + + tmp = div_s64(data * 1000000000LL, div); + tmp = div_s64_rem(tmp, 1000000000LL, &rem); + + *val = tmp; + *val2 = rem; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int hts221_get_sensor_offset(struct hts221_hw *hw, + enum iio_chan_type ch_type, + int *val, int *val2) +{ + s64 tmp; + s32 rem, div, data; + + switch (ch_type) { + case IIO_HUMIDITYRELATIVE: + data = hw->sensors[HTS221_SENSOR_H].b_gen; + div = hw->sensors[HTS221_SENSOR_H].slope; + break; + case IIO_TEMP: + data = hw->sensors[HTS221_SENSOR_T].b_gen; + div = hw->sensors[HTS221_SENSOR_T].slope; + break; + default: + return -EINVAL; + } + + tmp = div_s64(data * 1000000000LL, div); + tmp = div_s64_rem(tmp, 1000000000LL, &rem); + + *val = tmp; + *val2 = rem; + + return IIO_VAL_INT_PLUS_NANO; +} + +static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) +{ + u8 data[HTS221_DATA_SIZE]; + int err; + + err = hts221_power_on(hw); + if (err < 0) + return err; + + msleep(50); + + err = hw->tf->read(hw->dev, addr, sizeof(data), data); + if (err < 0) + return err; + + hts221_power_off(hw); + + *val = (s16)get_unaligned_le16(data); + + return IIO_VAL_INT; +} + +static int hts221_read_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *ch, + int *val, int *val2, long mask) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int ret; + + ret = iio_device_claim_direct_mode(iio_dev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = hts221_read_oneshot(hw, ch->address, val); + break; + case IIO_CHAN_INFO_SCALE: + ret = hts221_get_sensor_scale(hw, ch->type, val, val2); + break; + case IIO_CHAN_INFO_OFFSET: + ret = hts221_get_sensor_offset(hw, ch->type, val, val2); + break; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = hw->odr; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + u8 idx; + const struct hts221_avg *avg; + + switch (ch->type) { + case IIO_HUMIDITYRELATIVE: + avg = &hts221_avg_list[HTS221_SENSOR_H]; + idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx; + *val = avg->avg_avl[idx].avg; + ret = IIO_VAL_INT; + break; + case IIO_TEMP: + avg = &hts221_avg_list[HTS221_SENSOR_T]; + idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx; + *val = avg->avg_avl[idx].avg; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + break; + } + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(iio_dev); + + return ret; +} + +static int hts221_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int ret; + + ret = iio_device_claim_direct_mode(iio_dev); + if (ret) + return ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hts221_update_odr(hw, val); + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_HUMIDITYRELATIVE: + ret = hts221_update_avg(hw, HTS221_SENSOR_H, val); + break; + case IIO_TEMP: + ret = hts221_update_avg(hw, HTS221_SENSOR_T, val); + break; + default: + ret = -EINVAL; + break; + } + break; + default: + ret = -EINVAL; + break; + } + + iio_device_release_direct_mode(iio_dev); + + return ret; +} + +static int hts221_validate_trigger(struct iio_dev *iio_dev, + struct iio_trigger *trig) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + + return hw->trig == trig ? 0 : -EINVAL; +} + +static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO, + hts221_sysfs_rh_oversampling_avail, NULL, 0); +static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO, + hts221_sysfs_temp_oversampling_avail, NULL, 0); +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq); + +static struct attribute *hts221_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr, + &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group hts221_attribute_group = { + .attrs = hts221_attributes, +}; + +static const struct iio_info hts221_info = { + .driver_module = THIS_MODULE, + .attrs = &hts221_attribute_group, + .read_raw = hts221_read_raw, + .write_raw = hts221_write_raw, + .validate_trigger = hts221_validate_trigger, +}; + +static const unsigned long hts221_scan_masks[] = {0x3, 0x0}; + +int hts221_probe(struct iio_dev *iio_dev) +{ + struct hts221_hw *hw = iio_priv(iio_dev); + int err; + u8 data; + + mutex_init(&hw->lock); + + err = hts221_check_whoami(hw); + if (err < 0) + return err; + + hw->odr = hts221_odr_table[0].hz; + + iio_dev->modes = INDIO_DIRECT_MODE; + iio_dev->dev.parent = hw->dev; + iio_dev->available_scan_masks = hts221_scan_masks; + iio_dev->channels = hts221_channels; + iio_dev->num_channels = ARRAY_SIZE(hts221_channels); + iio_dev->name = HTS221_DEV_NAME; + iio_dev->info = &hts221_info; + + /* configure humidity sensor */ + err = hts221_parse_rh_caldata(hw); + if (err < 0) { + dev_err(hw->dev, "failed to get rh calibration data\n"); + return err; + } + + data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3].avg; + err = hts221_update_avg(hw, HTS221_SENSOR_H, data); + if (err < 0) { + dev_err(hw->dev, "failed to set rh oversampling ratio\n"); + return err; + } + + /* configure temperature sensor */ + err = hts221_parse_temp_caldata(hw); + if (err < 0) { + dev_err(hw->dev, + "failed to get temperature calibration data\n"); + return err; + } + + data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3].avg; + err = hts221_update_avg(hw, HTS221_SENSOR_T, data); + if (err < 0) { + dev_err(hw->dev, + "failed to set temperature oversampling ratio\n"); + return err; + } + + if (hw->irq > 0) { + err = hts221_allocate_buffers(hw); + if (err < 0) + return err; + + err = hts221_allocate_trigger(hw); + if (err) + return err; + } + + return devm_iio_device_register(hw->dev, iio_dev); +} +EXPORT_SYMBOL(hts221_probe); + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c new file mode 100644 index 000000000000..367ecd509f31 --- /dev/null +++ b/drivers/iio/humidity/hts221_i2c.c @@ -0,0 +1,110 @@ +/* + * STMicroelectronics hts221 i2c driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi <lorenzo.bianconi@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include "hts221.h" + +#define I2C_AUTO_INCREMENT 0x80 + +static int hts221_i2c_read(struct device *dev, u8 addr, int len, u8 *data) +{ + struct i2c_msg msg[2]; + struct i2c_client *client = to_i2c_client(dev); + + if (len > 1) + addr |= I2C_AUTO_INCREMENT; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].len = 1; + msg[0].buf = &addr; + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + return i2c_transfer(client->adapter, msg, 2); +} + +static int hts221_i2c_write(struct device *dev, u8 addr, int len, u8 *data) +{ + u8 send[len + 1]; + struct i2c_msg msg; + struct i2c_client *client = to_i2c_client(dev); + + if (len > 1) + addr |= I2C_AUTO_INCREMENT; + + send[0] = addr; + memcpy(&send[1], data, len * sizeof(u8)); + + msg.addr = client->addr; + msg.flags = client->flags; + msg.len = len + 1; + msg.buf = send; + + return i2c_transfer(client->adapter, &msg, 1); +} + +static const struct hts221_transfer_function hts221_transfer_fn = { + .read = hts221_i2c_read, + .write = hts221_i2c_write, +}; + +static int hts221_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct hts221_hw *hw; + struct iio_dev *iio_dev; + + iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*hw)); + if (!iio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, iio_dev); + + hw = iio_priv(iio_dev); + hw->name = client->name; + hw->dev = &client->dev; + hw->irq = client->irq; + hw->tf = &hts221_transfer_fn; + + return hts221_probe(iio_dev); +} + +static const struct of_device_id hts221_i2c_of_match[] = { + { .compatible = "st,hts221", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hts221_i2c_of_match); + +static const struct i2c_device_id hts221_i2c_id_table[] = { + { HTS221_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); + +static struct i2c_driver hts221_driver = { + .driver = { + .name = "hts221_i2c", + .of_match_table = of_match_ptr(hts221_i2c_of_match), + }, + .probe = hts221_i2c_probe, + .id_table = hts221_i2c_id_table, +}; +module_i2c_driver(hts221_driver); + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics hts221 i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c new file mode 100644 index 000000000000..70df5e7150c1 --- /dev/null +++ b/drivers/iio/humidity/hts221_spi.c @@ -0,0 +1,125 @@ +/* + * STMicroelectronics hts221 spi driver + * + * Copyright 2016 STMicroelectronics Inc. + * + * Lorenzo Bianconi <lorenzo.bianconi@st.com> + * + * Licensed under the GPL-2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include "hts221.h" + +#define SENSORS_SPI_READ 0x80 +#define SPI_AUTO_INCREMENT 0x40 + +static int hts221_spi_read(struct device *dev, u8 addr, int len, u8 *data) +{ + int err; + struct spi_device *spi = to_spi_device(dev); + struct iio_dev *iio_dev = spi_get_drvdata(spi); + struct hts221_hw *hw = iio_priv(iio_dev); + + struct spi_transfer xfers[] = { + { + .tx_buf = hw->tb.tx_buf, + .bits_per_word = 8, + .len = 1, + }, + { + .rx_buf = hw->tb.rx_buf, + .bits_per_word = 8, + .len = len, + } + }; + + if (len > 1) + addr |= SPI_AUTO_INCREMENT; + hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ; + + err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + if (err < 0) + return err; + + memcpy(data, hw->tb.rx_buf, len * sizeof(u8)); + + return len; +} + +static int hts221_spi_write(struct device *dev, u8 addr, int len, u8 *data) +{ + struct spi_device *spi = to_spi_device(dev); + struct iio_dev *iio_dev = spi_get_drvdata(spi); + struct hts221_hw *hw = iio_priv(iio_dev); + + struct spi_transfer xfers = { + .tx_buf = hw->tb.tx_buf, + .bits_per_word = 8, + .len = len + 1, + }; + + if (len >= HTS221_TX_MAX_LENGTH) + return -ENOMEM; + + if (len > 1) + addr |= SPI_AUTO_INCREMENT; + hw->tb.tx_buf[0] = addr; + memcpy(&hw->tb.tx_buf[1], data, len); + + return spi_sync_transfer(spi, &xfers, 1); +} + +static const struct hts221_transfer_function hts221_transfer_fn = { + .read = hts221_spi_read, + .write = hts221_spi_write, +}; + +static int hts221_spi_probe(struct spi_device *spi) +{ + struct hts221_hw *hw; + struct iio_dev *iio_dev; + + iio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*hw)); + if (!iio_dev) + return -ENOMEM; + + spi_set_drvdata(spi, iio_dev); + + hw = iio_priv(iio_dev); + hw->name = spi->modalias; + hw->dev = &spi->dev; + hw->irq = spi->irq; + hw->tf = &hts221_transfer_fn; + + return hts221_probe(iio_dev); +} + +static const struct of_device_id hts221_spi_of_match[] = { + { .compatible = "st,hts221", }, + {}, +}; +MODULE_DEVICE_TABLE(of, hts221_spi_of_match); + +static const struct spi_device_id hts221_spi_id_table[] = { + { HTS221_DEV_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); + +static struct spi_driver hts221_driver = { + .driver = { + .name = "hts221_spi", + .of_match_table = of_match_ptr(hts221_spi_of_match), + }, + .probe = hts221_spi_probe, + .id_table = hts221_spi_id_table, +}; +module_spi_driver(hts221_driver); + +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics hts221 spi driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index e0251b8c1a52..5355507f8fa1 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -398,7 +398,8 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct bmi160_data *data = iio_priv(indio_dev); - s16 buf[16]; /* 3 sens x 3 axis x s16 + 3 x s16 pad + 4 x s16 tstamp */ + __le16 buf[16]; + /* 3 sens x 3 axis x __le16 + 3 x __le16 pad + 4 x __le16 tstamp */ int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L; __le16 sample; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 158aaf44dd95..b12830b09c7d 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -307,10 +307,9 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = kmalloc(sizeof(*trialmask)* - BITS_TO_LONGS(indio_dev->masklength), - GFP_KERNEL); - + trialmask = kmalloc_array(BITS_TO_LONGS(indio_dev->masklength), + sizeof(*trialmask), + GFP_KERNEL); if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index fc340ed3dca1..649725bc15c1 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -81,6 +81,8 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_PH] = "ph", [IIO_UVINDEX] = "uvindex", [IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity", + [IIO_COUNT] = "count", + [IIO_INDEX] = "index", }; static const char * const iio_modifier_names[] = { diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index e1e104845e38..978729f6d7c4 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -717,6 +717,27 @@ bool iio_trigger_using_own(struct iio_dev *indio_dev) } EXPORT_SYMBOL(iio_trigger_using_own); +/** + * iio_trigger_validate_own_device - Check if a trigger and IIO device belong to + * the same device + * @trig: The IIO trigger to check + * @indio_dev: the IIO device to check + * + * This function can be used as the validate_device callback for triggers that + * can only be attached to their own device. + * + * Return: 0 if both the trigger and the IIO device belong to the same + * device, -EINVAL otherwise. + */ +int iio_trigger_validate_own_device(struct iio_trigger *trig, + struct iio_dev *indio_dev) +{ + if (indio_dev->dev.parent != trig->dev.parent) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(iio_trigger_validate_own_device); + void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index c4757e6367e7..29df11572858 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -658,6 +658,31 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); +static int iio_read_channel_attribute(struct iio_channel *chan, + int *val, int *val2, + enum iio_chan_info_enum attribute) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_channel_read(chan, val, val2, attribute); +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} + +int iio_read_channel_offset(struct iio_channel *chan, int *val, int *val2) +{ + return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_OFFSET); +} +EXPORT_SYMBOL_GPL(iio_read_channel_offset); + int iio_read_channel_processed(struct iio_channel *chan, int *val) { int ret; @@ -687,19 +712,7 @@ EXPORT_SYMBOL_GPL(iio_read_channel_processed); int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { - int ret; - - mutex_lock(&chan->indio_dev->info_exist_lock); - if (chan->indio_dev->info == NULL) { - ret = -ENODEV; - goto err_unlock; - } - - ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE); -err_unlock: - mutex_unlock(&chan->indio_dev->info_exist_lock); - - return ret; + return iio_read_channel_attribute(chan, val, val2, IIO_CHAN_INFO_SCALE); } EXPORT_SYMBOL_GPL(iio_read_channel_scale); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index ba2e64d7ee58..d01172089828 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -140,6 +140,18 @@ config GP2AP020A00F To compile this driver as a module, choose M here: the module will be called gp2ap020a00f. +config SENSORS_ISL29018 + tristate "Intersil 29018 light and proximity sensor" + depends on I2C + select REGMAP_I2C + default n + help + If you say yes here you get support for ambient light sensing and + proximity infrared sensing from Intersil ISL29018. + This driver will provide the measurements of ambient light intensity + in lux, proximity infrared sensing and normal infrared sensing. + Data from sensor is accessible via sysfs. + config ISL29125 tristate "Intersil ISL29125 digital color light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index c5768df87a17..15f24c557f5f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CM36651) += cm36651.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o +obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index a767a43c995c..917dd8b43e72 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -62,16 +62,6 @@ #define ISL29035_BOUT_SHIFT 0x07 #define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) -#define ISL29018_INT_TIME_AVAIL "0.090000 0.005630 0.000351 0.000021" -#define ISL29023_INT_TIME_AVAIL "0.090000 0.005600 0.000352 0.000022" -#define ISL29035_INT_TIME_AVAIL "0.105000 0.006500 0.000410 0.000025" - -static const char * const int_time_avail[] = { - ISL29018_INT_TIME_AVAIL, - ISL29023_INT_TIME_AVAIL, - ISL29035_INT_TIME_AVAIL, -}; - enum isl29018_int_time { ISL29018_INT_TIME_16, ISL29018_INT_TIME_12, @@ -110,7 +100,8 @@ struct isl29018_chip { static int isl29018_set_integration_time(struct isl29018_chip *chip, unsigned int utime) { - int i, ret; + unsigned int i; + int ret; unsigned int int_time, new_int_time; for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) { @@ -145,7 +136,8 @@ static int isl29018_set_integration_time(struct isl29018_chip *chip, static int isl29018_set_scale(struct isl29018_chip *chip, int scale, int uscale) { - int i, ret; + unsigned int i; + int ret; struct isl29018_scale new_scale; for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) { @@ -276,29 +268,35 @@ static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme, return 0; } -static ssize_t isl29018_show_scale_available(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t in_illuminance_scale_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - int i, len = 0; + unsigned int i; + int len = 0; + mutex_lock(&chip->lock); for (i = 0; i < ARRAY_SIZE(isl29018_scales[chip->int_time]); ++i) len += sprintf(buf + len, "%d.%06d ", isl29018_scales[chip->int_time][i].scale, isl29018_scales[chip->int_time][i].uscale); + mutex_unlock(&chip->lock); buf[len - 1] = '\n'; return len; } -static ssize_t isl29018_show_int_time_available(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t in_illuminance_integration_time_available_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); - int i, len = 0; + unsigned int i; + int len = 0; for (i = 0; i < ARRAY_SIZE(isl29018_int_utimes[chip->type]); ++i) len += sprintf(buf + len, "0.%06d ", @@ -309,9 +307,27 @@ static ssize_t isl29018_show_int_time_available(struct device *dev, return len; } -static ssize_t isl29018_show_prox_infrared_suppression(struct device *dev, - struct device_attribute *attr, - char *buf) +/* + * From ISL29018 Data Sheet (FN6619.4, Oct 8, 2012) regarding the + * infrared suppression: + * + * Proximity Sensing Scheme: Bit 7. This bit programs the function + * of the proximity detection. Logic 0 of this bit, Scheme 0, makes + * full n (4, 8, 12, 16) bits (unsigned) proximity detection. The range + * of Scheme 0 proximity count is from 0 to 2^n. Logic 1 of this bit, + * Scheme 1, makes n-1 (3, 7, 11, 15) bits (2's complementary) + * proximity_less_ambient detection. The range of Scheme 1 + * proximity count is from -2^(n-1) to 2^(n-1) . The sign bit is extended + * for resolutions less than 16. While Scheme 0 has wider dynamic + * range, Scheme 1 proximity detection is less affected by the + * ambient IR noise variation. + * + * 0 Sensing IR from LED and ambient + * 1 Sensing IR from LED with ambient IR rejection + */ +static ssize_t proximity_on_chip_ambient_infrared_suppression_show + (struct device *dev, struct device_attribute *attr, + char *buf) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -323,9 +339,9 @@ static ssize_t isl29018_show_prox_infrared_suppression(struct device *dev, return sprintf(buf, "%d\n", chip->prox_scheme); } -static ssize_t isl29018_store_prox_infrared_suppression(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t proximity_on_chip_ambient_infrared_suppression_store + (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct isl29018_chip *chip = iio_priv(indio_dev); @@ -357,6 +373,10 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, int ret = -EINVAL; mutex_lock(&chip->lock); + if (chip->suspended) { + ret = -EBUSY; + goto write_done; + } switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) { @@ -366,13 +386,8 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, } break; case IIO_CHAN_INFO_INT_TIME: - if (chan->type == IIO_LIGHT) { - if (val) { - mutex_unlock(&chip->lock); - return -EINVAL; - } + if (chan->type == IIO_LIGHT && !val) ret = isl29018_set_integration_time(chip, val2); - } break; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_LIGHT) @@ -381,6 +396,8 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, default: break; } + +write_done: mutex_unlock(&chip->lock); return ret; @@ -397,8 +414,8 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, mutex_lock(&chip->lock); if (chip->suspended) { - mutex_unlock(&chip->lock); - return -EBUSY; + ret = -EBUSY; + goto read_done; } switch (mask) { case IIO_CHAN_INFO_RAW: @@ -445,7 +462,10 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, default: break; } + +read_done: mutex_unlock(&chip->lock); + return ret; } @@ -482,14 +502,9 @@ static const struct iio_chan_spec isl29023_channels[] = { ISL29018_IR_CHANNEL, }; -static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, S_IRUGO, - isl29018_show_int_time_available, NULL, 0); -static IIO_DEVICE_ATTR(in_illuminance_scale_available, S_IRUGO, - isl29018_show_scale_available, NULL, 0); -static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_suppression, - S_IRUGO | S_IWUSR, - isl29018_show_prox_infrared_suppression, - isl29018_store_prox_infrared_suppression, 0); +static IIO_DEVICE_ATTR_RO(in_illuminance_integration_time_available, 0); +static IIO_DEVICE_ATTR_RO(in_illuminance_scale_available, 0); +static IIO_DEVICE_ATTR_RW(proximity_on_chip_ambient_infrared_suppression, 0); #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) @@ -514,30 +529,6 @@ static const struct attribute_group isl29023_group = { .attrs = isl29023_attributes, }; -static int isl29035_detect(struct isl29018_chip *chip) -{ - int status; - unsigned int id; - struct device *dev = regmap_get_device(chip->regmap); - - status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); - if (status < 0) { - dev_err(dev, - "Error reading ID register with error %d\n", - status); - return status; - } - - id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; - - if (id != ISL29035_DEVICE_ID) - return -ENODEV; - - /* Clear brownout bit */ - return regmap_update_bits(chip->regmap, ISL29035_REG_DEVICE_ID, - ISL29035_BOUT_MASK, 0); -} - enum { isl29018, isl29023, @@ -550,12 +541,31 @@ static int isl29018_chip_init(struct isl29018_chip *chip) struct device *dev = regmap_get_device(chip->regmap); if (chip->type == isl29035) { - status = isl29035_detect(chip); + unsigned int id; + + status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); + if (status < 0) { + dev_err(dev, + "Error reading ID register with error %d\n", + status); + return status; + } + + id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; + + if (id != ISL29035_DEVICE_ID) + return -ENODEV; + + /* Clear brownout bit */ + status = regmap_update_bits(chip->regmap, + ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK, 0); if (status < 0) return status; } - /* Code added per Intersil Application Note 1534: + /* + * Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD * recovers to 2.25V (or greater), the part may thus be in an @@ -582,7 +592,8 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return status; } - /* See Intersil AN1534 comments above. + /* + * See Intersil AN1534 comments above. * "Operating Mode" (COMMAND1) register is reprogrammed when * data is read from the device. */ @@ -605,12 +616,10 @@ static int isl29018_chip_init(struct isl29018_chip *chip) status = isl29018_set_integration_time(chip, isl29018_int_utimes[chip->type][chip->int_time]); - if (status < 0) { + if (status < 0) dev_err(dev, "Init of isl29018 fails\n"); - return status; - } - return 0; + return status; } static const struct iio_info isl29018_info = { @@ -713,6 +722,7 @@ static int isl29018_probe(struct i2c_client *client, indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (!indio_dev) return -ENOMEM; + chip = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); @@ -752,6 +762,7 @@ static int isl29018_probe(struct i2c_client *client, indio_dev->name = name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; + return devm_iio_device_register(&client->dev, indio_dev); } @@ -762,13 +773,15 @@ static int isl29018_suspend(struct device *dev) mutex_lock(&chip->lock); - /* Since this driver uses only polling commands, we are by default in + /* + * Since this driver uses only polling commands, we are by default in * auto shutdown (ie, power-down) mode. * So we do not have much to do here. */ chip->suspended = true; mutex_unlock(&chip->lock); + return 0; } @@ -784,6 +797,7 @@ static int isl29018_resume(struct device *dev) chip->suspended = false; mutex_unlock(&chip->lock); + return err; } @@ -807,7 +821,6 @@ static const struct i2c_device_id isl29018_id[] = { {"isl29035", isl29035}, {} }; - MODULE_DEVICE_TABLE(i2c, isl29018_id); static const struct of_device_id isl29018_of_match[] = { diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 3afc53a3d0b6..b30e0c1c6cc4 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -631,14 +631,16 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_PROCESSED: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - switch (chan->type) { case IIO_LIGHT: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&data->lock_als); ret = ltr501_read_als(data, buf); mutex_unlock(&data->lock_als); + iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; *val = ltr501_calculate_lux(le16_to_cpu(buf[1]), @@ -648,8 +650,9 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, return -EINVAL; } case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (chan->type) { case IIO_INTENSITY: @@ -657,21 +660,28 @@ static int ltr501_read_raw(struct iio_dev *indio_dev, ret = ltr501_read_als(data, buf); mutex_unlock(&data->lock_als); if (ret < 0) - return ret; + break; *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? buf[0] : buf[1]); - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; case IIO_PROXIMITY: mutex_lock(&data->lock_ps); ret = ltr501_read_ps(data); mutex_unlock(&data->lock_ps); if (ret < 0) - return ret; + break; *val = ret & LTR501_PS_DATA_MASK; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_INTENSITY: @@ -729,8 +739,9 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, int i, ret, freq_val, freq_val2; struct ltr501_chip_info *info = data->chip_info; - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -739,85 +750,105 @@ static int ltr501_write_raw(struct iio_dev *indio_dev, i = ltr501_get_gain_index(info->als_gain, info->als_gain_tbl_size, val, val2); - if (i < 0) - return -EINVAL; + if (i < 0) { + ret = -EINVAL; + break; + } data->als_contr &= ~info->als_gain_mask; data->als_contr |= i << info->als_gain_shift; - return regmap_write(data->regmap, LTR501_ALS_CONTR, - data->als_contr); + ret = regmap_write(data->regmap, LTR501_ALS_CONTR, + data->als_contr); + break; case IIO_PROXIMITY: i = ltr501_get_gain_index(info->ps_gain, info->ps_gain_tbl_size, val, val2); - if (i < 0) - return -EINVAL; + if (i < 0) { + ret = -EINVAL; + break; + } data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; - return regmap_write(data->regmap, LTR501_PS_CONTR, - data->ps_contr); + ret = regmap_write(data->regmap, LTR501_PS_CONTR, + data->ps_contr); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + case IIO_CHAN_INFO_INT_TIME: switch (chan->type) { case IIO_INTENSITY: - if (val != 0) - return -EINVAL; + if (val != 0) { + ret = -EINVAL; + break; + } mutex_lock(&data->lock_als); - i = ltr501_set_it_time(data, val2); + ret = ltr501_set_it_time(data, val2); mutex_unlock(&data->lock_als); - return i; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { case IIO_INTENSITY: ret = ltr501_als_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - return ret; + break; ret = ltr501_als_write_samp_freq(data, val, val2); if (ret < 0) - return ret; + break; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->als_period); if (ret < 0) - return ltr501_als_write_samp_freq(data, - freq_val, - freq_val2); - return ret; + ret = ltr501_als_write_samp_freq(data, freq_val, + freq_val2); + break; case IIO_PROXIMITY: ret = ltr501_ps_read_samp_freq(data, &freq_val, &freq_val2); if (ret < 0) - return ret; + break; ret = ltr501_ps_write_samp_freq(data, val, val2); if (ret < 0) - return ret; + break; /* update persistence count when changing frequency */ ret = ltr501_write_intr_prst(data, chan->type, 0, data->ps_period); if (ret < 0) - return ltr501_ps_write_samp_freq(data, - freq_val, - freq_val2); - return ret; + ret = ltr501_ps_write_samp_freq(data, freq_val, + freq_val2); + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + break; + + default: + ret = -EINVAL; + break; } - return -EINVAL; + + iio_device_release_direct_mode(indio_dev); + return ret; } static int ltr501_read_thresh(struct iio_dev *indio_dev, diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 6511b20a2a29..a144ca3461fc 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -204,17 +204,18 @@ static int max44000_write_alspga(struct max44000_data *data, int val) static int max44000_read_alsval(struct max44000_data *data) { u16 regval; + __be16 val; int alstim, ret; ret = regmap_bulk_read(data->regmap, MAX44000_REG_ALS_DATA_HI, - ®val, sizeof(regval)); + &val, sizeof(val)); if (ret < 0) return ret; alstim = ret = max44000_read_alstim(data); if (ret < 0) return ret; - regval = be16_to_cpu(regval); + regval = be16_to_cpu(val); /* * Overflow is explained on datasheet page 17. diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 217353145676..ce09d771c1fb 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -287,7 +287,7 @@ static int ak8974_await_drdy(struct ak8974 *ak8974) return 0; } -static int ak8974_getresult(struct ak8974 *ak8974, s16 *result) +static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result) { unsigned int src; int ret; @@ -395,7 +395,7 @@ static int ak8974_selftest(struct ak8974 *ak8974) static int ak8974_get_u16_val(struct ak8974 *ak8974, u8 reg, u16 *val) { int ret; - u16 bulk; + __le16 bulk; ret = regmap_bulk_read(ak8974->map, reg, &bulk, 2); if (ret) @@ -453,7 +453,7 @@ static int ak8974_read_raw(struct iio_dev *indio_dev, long mask) { struct ak8974 *ak8974 = iio_priv(indio_dev); - s16 hw_values[3]; + __le16 hw_values[3]; int ret = -EINVAL; pm_runtime_get_sync(&ak8974->i2c->dev); @@ -494,7 +494,7 @@ static void ak8974_fill_buffer(struct iio_dev *indio_dev) { struct ak8974 *ak8974 = iio_priv(indio_dev); int ret; - s16 hw_values[8]; /* Three axes + 64bit padding */ + __le16 hw_values[8]; /* Three axes + 64bit padding */ pm_runtime_get_sync(&ak8974->i2c->dev); mutex_lock(&ak8974->lock); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index af8606cc7812..825369fb1c57 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -690,6 +690,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) struct ak8975_data *data = iio_priv(indio_dev); const struct i2c_client *client = data->client; const struct ak_def *def = data->def; + __le16 rval; u16 buff; int ret; @@ -703,7 +704,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) ret = i2c_smbus_read_i2c_block_data_or_emulated( client, def->data_regs[index], - sizeof(buff), (u8*)&buff); + sizeof(rval), (u8*)&rval); if (ret < 0) goto exit; @@ -713,7 +714,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) pm_runtime_put_autosuspend(&data->client->dev); /* Swap bytes and convert to valid range. */ - buff = le16_to_cpu(buff); + buff = le16_to_cpu(rval); *val = clamp_t(s16, buff, -def->range, def->range); return IIO_VAL_INT; @@ -813,6 +814,7 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) const struct ak_def *def = data->def; int ret; s16 buff[8]; /* 3 x 16 bits axis values + 1 aligned 64 bits timestamp */ + __le16 fval[3]; mutex_lock(&data->lock); @@ -826,17 +828,17 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) */ ret = i2c_smbus_read_i2c_block_data_or_emulated(client, def->data_regs[0], - 3 * sizeof(buff[0]), - (u8 *)buff); + 3 * sizeof(fval[0]), + (u8 *)fval); if (ret < 0) goto unlock; mutex_unlock(&data->lock); /* Clamp to valid range. */ - buff[0] = clamp_t(s16, le16_to_cpu(buff[0]), -def->range, def->range); - buff[1] = clamp_t(s16, le16_to_cpu(buff[1]), -def->range, def->range); - buff[2] = clamp_t(s16, le16_to_cpu(buff[2]), -def->range, def->range); + buff[0] = clamp_t(s16, le16_to_cpu(fval[0]), -def->range, def->range); + buff[1] = clamp_t(s16, le16_to_cpu(fval[1]), -def->range, def->range); + buff[2] = clamp_t(s16, le16_to_cpu(fval[2]), -def->range, def->range); iio_push_to_buffers_with_timestamp(indio_dev, buff, iio_get_time_ns(indio_dev)); diff --git a/drivers/iio/potentiostat/Kconfig b/drivers/iio/potentiostat/Kconfig new file mode 100644 index 000000000000..1e3baf2cc97d --- /dev/null +++ b/drivers/iio/potentiostat/Kconfig @@ -0,0 +1,22 @@ +# +# Potentiostat drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Digital potentiostats" + +config LMP91000 + tristate "Texas Instruments LMP91000 potentiostat driver" + depends on I2C + select REGMAP_I2C + select IIO_BUFFER + select IIO_BUFFER_CB + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Texas Instruments + LMP91000 digital potentiostat chip. + + To compile this driver as a module, choose M here: the + module will be called lmp91000 + +endmenu diff --git a/drivers/iio/potentiostat/Makefile b/drivers/iio/potentiostat/Makefile new file mode 100644 index 000000000000..64d315ef4449 --- /dev/null +++ b/drivers/iio/potentiostat/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O potentiostat drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_LMP91000) += lmp91000.o diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c new file mode 100644 index 000000000000..e22714365022 --- /dev/null +++ b/drivers/iio/potentiostat/lmp91000.c @@ -0,0 +1,446 @@ +/* + * lmp91000.c - Support for Texas Instruments digital potentiostats + * + * Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com> + * + * 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. + * + * TODO: bias voltage + polarity control, and multiple chip support + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/consumer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define LMP91000_REG_LOCK 0x01 +#define LMP91000_REG_TIACN 0x10 +#define LMP91000_REG_TIACN_GAIN_SHIFT 2 + +#define LMP91000_REG_REFCN 0x11 +#define LMP91000_REG_REFCN_EXT_REF 0x20 +#define LMP91000_REG_REFCN_50_ZERO 0x80 + +#define LMP91000_REG_MODECN 0x12 +#define LMP91000_REG_MODECN_3LEAD 0x03 +#define LMP91000_REG_MODECN_TEMP 0x07 + +#define LMP91000_DRV_NAME "lmp91000" + +static const int lmp91000_tia_gain[] = { 0, 2750, 3500, 7000, 14000, 35000, + 120000, 350000 }; + +static const int lmp91000_rload[] = { 10, 33, 50, 100 }; + +#define LMP91000_TEMP_BASE -40 + +static const u16 lmp91000_temp_lut[] = { + 1875, 1867, 1860, 1852, 1844, 1836, 1828, 1821, 1813, 1805, + 1797, 1789, 1782, 1774, 1766, 1758, 1750, 1742, 1734, 1727, + 1719, 1711, 1703, 1695, 1687, 1679, 1671, 1663, 1656, 1648, + 1640, 1632, 1624, 1616, 1608, 1600, 1592, 1584, 1576, 1568, + 1560, 1552, 1544, 1536, 1528, 1520, 1512, 1504, 1496, 1488, + 1480, 1472, 1464, 1456, 1448, 1440, 1432, 1424, 1415, 1407, + 1399, 1391, 1383, 1375, 1367, 1359, 1351, 1342, 1334, 1326, + 1318, 1310, 1302, 1293, 1285, 1277, 1269, 1261, 1253, 1244, + 1236, 1228, 1220, 1212, 1203, 1195, 1187, 1179, 1170, 1162, + 1154, 1146, 1137, 1129, 1121, 1112, 1104, 1096, 1087, 1079, + 1071, 1063, 1054, 1046, 1038, 1029, 1021, 1012, 1004, 996, + 987, 979, 971, 962, 954, 945, 937, 929, 920, 912, + 903, 895, 886, 878, 870, 861 }; + +static const struct regmap_config lmp91000_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +struct lmp91000_data { + struct regmap *regmap; + struct device *dev; + + struct iio_trigger *trig; + struct iio_cb_buffer *cb_buffer; + struct iio_channel *adc_chan; + + struct completion completion; + u8 chan_select; + + u32 buffer[4]; /* 64-bit data + 64-bit timestamp */ +}; + +static const struct iio_chan_spec lmp91000_channels[] = { + { /* chemical channel mV */ + .type = IIO_VOLTAGE, + .channel = 0, + .address = LMP91000_REG_MODECN_3LEAD, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + }, + }, + IIO_CHAN_SOFT_TIMESTAMP(1), + { /* temperature channel mV */ + .type = IIO_TEMP, + .channel = 1, + .address = LMP91000_REG_MODECN_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = -1, + }, +}; + +static int lmp91000_read(struct lmp91000_data *data, int channel, int *val) +{ + int state, ret; + + ret = regmap_read(data->regmap, LMP91000_REG_MODECN, &state); + if (ret) + return -EINVAL; + + ret = regmap_write(data->regmap, LMP91000_REG_MODECN, channel); + if (ret) + return -EINVAL; + + /* delay till first temperature reading is complete */ + if ((state != channel) && (channel == LMP91000_REG_MODECN_TEMP)) + usleep_range(3000, 4000); + + data->chan_select = channel != LMP91000_REG_MODECN_3LEAD; + + iio_trigger_poll_chained(data->trig); + + ret = wait_for_completion_timeout(&data->completion, HZ); + reinit_completion(&data->completion); + + if (!ret) + return -ETIMEDOUT; + + *val = data->buffer[data->chan_select]; + + return 0; +} + +static irqreturn_t lmp91000_buffer_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct lmp91000_data *data = iio_priv(indio_dev); + int ret, val; + + memset(data->buffer, 0, sizeof(data->buffer)); + + ret = lmp91000_read(data, LMP91000_REG_MODECN_3LEAD, &val); + if (!ret) { + data->buffer[0] = val; + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + iio_get_time_ns(indio_dev)); + } + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int lmp91000_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: { + int ret = iio_channel_start_all_cb(data->cb_buffer); + + if (ret) + return ret; + + ret = lmp91000_read(data, chan->address, val); + + iio_channel_stop_all_cb(data->cb_buffer); + + if (ret) + return ret; + + if (mask == IIO_CHAN_INFO_PROCESSED) { + int tmp, i; + + ret = iio_convert_raw_to_processed(data->adc_chan, + *val, &tmp, 1); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(lmp91000_temp_lut); i++) + if (lmp91000_temp_lut[i] < tmp) + break; + + *val = (LMP91000_TEMP_BASE + i) * 1000; + } + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OFFSET: + return iio_read_channel_offset(data->adc_chan, val, val2); + case IIO_CHAN_INFO_SCALE: + return iio_read_channel_scale(data->adc_chan, val, val2); + } + + return -EINVAL; +} + +static const struct iio_info lmp91000_info = { + .driver_module = THIS_MODULE, + .read_raw = lmp91000_read_raw, +}; + +static int lmp91000_read_config(struct lmp91000_data *data) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + unsigned int reg, val; + int i, ret; + + ret = of_property_read_u32(np, "ti,tia-gain-ohm", &val); + if (ret) { + if (of_property_read_bool(np, "ti,external-tia-resistor")) + val = 0; + else { + dev_err(dev, "no ti,tia-gain-ohm defined"); + return ret; + } + } + + ret = -EINVAL; + for (i = 0; i < ARRAY_SIZE(lmp91000_tia_gain); i++) { + if (lmp91000_tia_gain[i] == val) { + reg = i << LMP91000_REG_TIACN_GAIN_SHIFT; + ret = 0; + break; + } + } + + if (ret) { + dev_err(dev, "invalid ti,tia-gain-ohm %d\n", val); + return ret; + } + + ret = of_property_read_u32(np, "ti,rload-ohm", &val); + if (ret) { + val = 100; + dev_info(dev, "no ti,rload-ohm defined, default to %d\n", val); + } + + ret = -EINVAL; + for (i = 0; i < ARRAY_SIZE(lmp91000_rload); i++) { + if (lmp91000_rload[i] == val) { + reg |= i; + ret = 0; + break; + } + } + + if (ret) { + dev_err(dev, "invalid ti,rload-ohm %d\n", val); + return ret; + } + + regmap_write(data->regmap, LMP91000_REG_LOCK, 0); + regmap_write(data->regmap, LMP91000_REG_TIACN, reg); + regmap_write(data->regmap, LMP91000_REG_REFCN, LMP91000_REG_REFCN_EXT_REF + | LMP91000_REG_REFCN_50_ZERO); + regmap_write(data->regmap, LMP91000_REG_LOCK, 1); + + return 0; +} + +static int lmp91000_buffer_cb(const void *val, void *private) +{ + struct iio_dev *indio_dev = private; + struct lmp91000_data *data = iio_priv(indio_dev); + + data->buffer[data->chan_select] = *((int *)val); + complete_all(&data->completion); + + return 0; +} + +static const struct iio_trigger_ops lmp91000_trigger_ops = { + .owner = THIS_MODULE, +}; + + +static int lmp91000_buffer_preenable(struct iio_dev *indio_dev) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + return iio_channel_start_all_cb(data->cb_buffer); +} + +static int lmp91000_buffer_predisable(struct iio_dev *indio_dev) +{ + struct lmp91000_data *data = iio_priv(indio_dev); + + iio_channel_stop_all_cb(data->cb_buffer); + + return 0; +} + +static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = { + .preenable = lmp91000_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = lmp91000_buffer_predisable, +}; + +static int lmp91000_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct lmp91000_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + indio_dev->info = &lmp91000_info; + indio_dev->channels = lmp91000_channels; + indio_dev->num_channels = ARRAY_SIZE(lmp91000_channels); + indio_dev->name = LMP91000_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + i2c_set_clientdata(client, indio_dev); + + data = iio_priv(indio_dev); + data->dev = dev; + data->regmap = devm_regmap_init_i2c(client, &lmp91000_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(dev, "regmap initialization failed.\n"); + return PTR_ERR(data->regmap); + } + + data->trig = devm_iio_trigger_alloc(data->dev, "%s-mux%d", + indio_dev->name, indio_dev->id); + if (!data->trig) { + dev_err(dev, "cannot allocate iio trigger.\n"); + return -ENOMEM; + } + + data->trig->ops = &lmp91000_trigger_ops; + data->trig->dev.parent = dev; + init_completion(&data->completion); + + ret = lmp91000_read_config(data); + if (ret) + return ret; + + ret = iio_trigger_set_immutable(iio_channel_cb_get_iio_dev(data->cb_buffer), + data->trig); + if (ret) { + dev_err(dev, "cannot set immutable trigger.\n"); + return ret; + } + + ret = iio_trigger_register(data->trig); + if (ret) { + dev_err(dev, "cannot register iio trigger.\n"); + return ret; + } + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &lmp91000_buffer_handler, + &lmp91000_buffer_setup_ops); + if (ret) + goto error_unreg_trigger; + + data->cb_buffer = iio_channel_get_all_cb(dev, &lmp91000_buffer_cb, + indio_dev); + + if (IS_ERR(data->cb_buffer)) { + if (PTR_ERR(data->cb_buffer) == -ENODEV) + ret = -EPROBE_DEFER; + else + ret = PTR_ERR(data->cb_buffer); + + goto error_unreg_buffer; + } + + data->adc_chan = iio_channel_cb_get_channels(data->cb_buffer); + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unreg_cb_buffer; + + return 0; + +error_unreg_cb_buffer: + iio_channel_release_all_cb(data->cb_buffer); + +error_unreg_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +error_unreg_trigger: + iio_trigger_unregister(data->trig); + + return ret; +} + +static int lmp91000_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct lmp91000_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + iio_channel_stop_all_cb(data->cb_buffer); + iio_channel_release_all_cb(data->cb_buffer); + + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->trig); + + return 0; +} + +static const struct of_device_id lmp91000_of_match[] = { + { .compatible = "ti,lmp91000", }, + { }, +}; +MODULE_DEVICE_TABLE(of, lmp91000_of_match); + +static const struct i2c_device_id lmp91000_id[] = { + { "lmp91000", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, lmp91000_id); + +static struct i2c_driver lmp91000_driver = { + .driver = { + .name = LMP91000_DRV_NAME, + .of_match_table = of_match_ptr(lmp91000_of_match), + }, + .probe = lmp91000_probe, + .remove = lmp91000_remove, + .id_table = lmp91000_id, +}; +module_i2c_driver(lmp91000_driver); + +MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>"); +MODULE_DESCRIPTION("LMP91000 digital potentiostat"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 15cd416365c1..bd8d96b96771 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -5,6 +5,16 @@ menu "Pressure sensors" +config ABP060MG + tristate "Honeywell ABP pressure sensor driver" + depends on I2C + help + Say yes here to build support for the Honeywell ABP pressure + sensors. + + To compile this driver as a module, choose M here: the module + will be called abp060mg. + config BMP280 tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" depends on (I2C || SPI_MASTER) diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index fff77185a5cc..de3dbc81dc5a 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_ABP060MG) += abp060mg.o obj-$(CONFIG_BMP280) += bmp280.o bmp280-objs := bmp280-core.o bmp280-regmap.o obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c new file mode 100644 index 000000000000..43bdd0b9155f --- /dev/null +++ b/drivers/iio/pressure/abp060mg.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2016 - Marcin Malagowski <mrc@bourne.st> + * + * 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. + */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/iio/iio.h> + +#define ABP060MG_ERROR_MASK 0xC000 +#define ABP060MG_RESP_TIME_MS 40 +#define ABP060MG_MIN_COUNTS 1638 /* = 0x0666 (10% of u14) */ +#define ABP060MG_MAX_COUNTS 14745 /* = 0x3999 (90% of u14) */ +#define ABP060MG_NUM_COUNTS (ABP060MG_MAX_COUNTS - ABP060MG_MIN_COUNTS) + +enum abp_variant { + /* gage [kPa] */ + ABP006KG, ABP010KG, ABP016KG, ABP025KG, ABP040KG, ABP060KG, ABP100KG, + ABP160KG, ABP250KG, ABP400KG, ABP600KG, ABP001GG, + /* differential [kPa] */ + ABP006KD, ABP010KD, ABP016KD, ABP025KD, ABP040KD, ABP060KD, ABP100KD, + ABP160KD, ABP250KD, ABP400KD, + /* gage [psi] */ + ABP001PG, ABP005PG, ABP015PG, ABP030PG, ABP060PG, ABP100PG, ABP150PG, + /* differential [psi] */ + ABP001PD, ABP005PD, ABP015PD, ABP030PD, ABP060PD, +}; + +struct abp_config { + int min; + int max; +}; + +static struct abp_config abp_config[] = { + /* mbar & kPa variants */ + [ABP006KG] = { .min = 0, .max = 6000 }, + [ABP010KG] = { .min = 0, .max = 10000 }, + [ABP016KG] = { .min = 0, .max = 16000 }, + [ABP025KG] = { .min = 0, .max = 25000 }, + [ABP040KG] = { .min = 0, .max = 40000 }, + [ABP060KG] = { .min = 0, .max = 60000 }, + [ABP100KG] = { .min = 0, .max = 100000 }, + [ABP160KG] = { .min = 0, .max = 160000 }, + [ABP250KG] = { .min = 0, .max = 250000 }, + [ABP400KG] = { .min = 0, .max = 400000 }, + [ABP600KG] = { .min = 0, .max = 600000 }, + [ABP001GG] = { .min = 0, .max = 1000000 }, + [ABP006KD] = { .min = -6000, .max = 6000 }, + [ABP010KD] = { .min = -10000, .max = 10000 }, + [ABP016KD] = { .min = -16000, .max = 16000 }, + [ABP025KD] = { .min = -25000, .max = 25000 }, + [ABP040KD] = { .min = -40000, .max = 40000 }, + [ABP060KD] = { .min = -60000, .max = 60000 }, + [ABP100KD] = { .min = -100000, .max = 100000 }, + [ABP160KD] = { .min = -160000, .max = 160000 }, + [ABP250KD] = { .min = -250000, .max = 250000 }, + [ABP400KD] = { .min = -400000, .max = 400000 }, + /* psi variants (1 psi ~ 6895 Pa) */ + [ABP001PG] = { .min = 0, .max = 6985 }, + [ABP005PG] = { .min = 0, .max = 34474 }, + [ABP015PG] = { .min = 0, .max = 103421 }, + [ABP030PG] = { .min = 0, .max = 206843 }, + [ABP060PG] = { .min = 0, .max = 413686 }, + [ABP100PG] = { .min = 0, .max = 689476 }, + [ABP150PG] = { .min = 0, .max = 1034214 }, + [ABP001PD] = { .min = -6895, .max = 6895 }, + [ABP005PD] = { .min = -34474, .max = 34474 }, + [ABP015PD] = { .min = -103421, .max = 103421 }, + [ABP030PD] = { .min = -206843, .max = 206843 }, + [ABP060PD] = { .min = -413686, .max = 413686 }, +}; + +struct abp_state { + struct i2c_client *client; + struct mutex lock; + + /* + * bus-dependent MEASURE_REQUEST length. + * If no SMBUS_QUICK support, need to send dummy byte + */ + int mreq_len; + + /* model-dependent values (calculated on probe) */ + int scale; + int offset; +}; + +static const struct iio_chan_spec abp060mg_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int abp060mg_get_measurement(struct abp_state *state, int *val) +{ + struct i2c_client *client = state->client; + __be16 buf[2]; + u16 pressure; + int ret; + + buf[0] = 0; + ret = i2c_master_send(client, (u8 *)&buf, state->mreq_len); + if (ret < 0) + return ret; + + msleep_interruptible(ABP060MG_RESP_TIME_MS); + + ret = i2c_master_recv(client, (u8 *)&buf, sizeof(buf)); + if (ret < 0) + return ret; + + pressure = be16_to_cpu(buf[0]); + if (pressure & ABP060MG_ERROR_MASK) + return -EIO; + + if (pressure < ABP060MG_MIN_COUNTS || pressure > ABP060MG_MAX_COUNTS) + return -EIO; + + *val = pressure; + + return IIO_VAL_INT; +} + +static int abp060mg_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct abp_state *state = iio_priv(indio_dev); + int ret; + + mutex_lock(&state->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = abp060mg_get_measurement(state, val); + break; + case IIO_CHAN_INFO_OFFSET: + *val = state->offset; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = state->scale; + *val2 = ABP060MG_NUM_COUNTS * 1000; /* to kPa */ + ret = IIO_VAL_FRACTIONAL; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&state->lock); + return ret; +} + +static const struct iio_info abp060mg_info = { + .driver_module = THIS_MODULE, + .read_raw = abp060mg_read_raw, +}; + +static void abp060mg_init_device(struct iio_dev *indio_dev, unsigned long id) +{ + struct abp_state *state = iio_priv(indio_dev); + struct abp_config *cfg = &abp_config[id]; + + state->scale = cfg->max - cfg->min; + state->offset = -ABP060MG_MIN_COUNTS; + + if (cfg->min < 0) /* differential */ + state->offset -= ABP060MG_NUM_COUNTS >> 1; +} + +static int abp060mg_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct abp_state *state; + unsigned long cfg_id = id->driver_data; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*state)); + if (!indio_dev) + return -ENOMEM; + + state = iio_priv(indio_dev); + i2c_set_clientdata(client, state); + state->client = client; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_QUICK)) + state->mreq_len = 1; + + abp060mg_init_device(indio_dev, cfg_id); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &abp060mg_info; + + indio_dev->channels = abp060mg_channels; + indio_dev->num_channels = ARRAY_SIZE(abp060mg_channels); + + mutex_init(&state->lock); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id abp060mg_id_table[] = { + /* mbar & kPa variants (abp060m [60 mbar] == abp006k [6 kPa]) */ + /* gage: */ + { "abp060mg", ABP006KG }, { "abp006kg", ABP006KG }, + { "abp100mg", ABP010KG }, { "abp010kg", ABP010KG }, + { "abp160mg", ABP016KG }, { "abp016kg", ABP016KG }, + { "abp250mg", ABP025KG }, { "abp025kg", ABP025KG }, + { "abp400mg", ABP040KG }, { "abp040kg", ABP040KG }, + { "abp600mg", ABP060KG }, { "abp060kg", ABP060KG }, + { "abp001bg", ABP100KG }, { "abp100kg", ABP100KG }, + { "abp1_6bg", ABP160KG }, { "abp160kg", ABP160KG }, + { "abp2_5bg", ABP250KG }, { "abp250kg", ABP250KG }, + { "abp004bg", ABP400KG }, { "abp400kg", ABP400KG }, + { "abp006bg", ABP600KG }, { "abp600kg", ABP600KG }, + { "abp010bg", ABP001GG }, { "abp001gg", ABP001GG }, + /* differential: */ + { "abp060md", ABP006KD }, { "abp006kd", ABP006KD }, + { "abp100md", ABP010KD }, { "abp010kd", ABP010KD }, + { "abp160md", ABP016KD }, { "abp016kd", ABP016KD }, + { "abp250md", ABP025KD }, { "abp025kd", ABP025KD }, + { "abp400md", ABP040KD }, { "abp040kd", ABP040KD }, + { "abp600md", ABP060KD }, { "abp060kd", ABP060KD }, + { "abp001bd", ABP100KD }, { "abp100kd", ABP100KD }, + { "abp1_6bd", ABP160KD }, { "abp160kd", ABP160KD }, + { "abp2_5bd", ABP250KD }, { "abp250kd", ABP250KD }, + { "abp004bd", ABP400KD }, { "abp400kd", ABP400KD }, + /* psi variants */ + /* gage: */ + { "abp001pg", ABP001PG }, + { "abp005pg", ABP005PG }, + { "abp015pg", ABP015PG }, + { "abp030pg", ABP030PG }, + { "abp060pg", ABP060PG }, + { "abp100pg", ABP100PG }, + { "abp150pg", ABP150PG }, + /* differential: */ + { "abp001pd", ABP001PD }, + { "abp005pd", ABP005PD }, + { "abp015pd", ABP015PD }, + { "abp030pd", ABP030PD }, + { "abp060pd", ABP060PD }, + { /* empty */ }, +}; +MODULE_DEVICE_TABLE(i2c, abp060mg_id_table); + +static struct i2c_driver abp060mg_driver = { + .driver = { + .name = "abp060mg", + }, + .probe = abp060mg_probe, + .id_table = abp060mg_id_table, +}; +module_i2c_driver(abp060mg_driver); + +MODULE_AUTHOR("Marcin Malagowski <mrc@bourne.st>"); +MODULE_DESCRIPTION("Honeywell ABP pressure sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index 6392d7b62841..cc3f84139157 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -82,8 +82,9 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; switch (chan->type) { case IIO_PRESSURE: /* in 0.25 pascal / LSB */ @@ -91,32 +92,39 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, ret = mpl3115_request(data); if (ret < 0) { mutex_unlock(&data->lock); - return ret; + break; } ret = i2c_smbus_read_i2c_block_data(data->client, MPL3115_OUT_PRESS, 3, (u8 *) &tmp); mutex_unlock(&data->lock); if (ret < 0) - return ret; + break; *val = be32_to_cpu(tmp) >> 12; - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; case IIO_TEMP: /* in 0.0625 celsius / LSB */ mutex_lock(&data->lock); ret = mpl3115_request(data); if (ret < 0) { mutex_unlock(&data->lock); - return ret; + break; } ret = i2c_smbus_read_i2c_block_data(data->client, MPL3115_OUT_TEMP, 2, (u8 *) &tmp); mutex_unlock(&data->lock); if (ret < 0) - return ret; + break; *val = sign_extend32(be32_to_cpu(tmp) >> 20, 11); - return IIO_VAL_INT; + ret = IIO_VAL_INT; + break; default: - return -EINVAL; + ret = -EINVAL; + break; } + + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_PRESSURE: diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index a74ed1f0c880..6bd53e702667 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -392,17 +392,14 @@ static int ms5611_init(struct iio_dev *indio_dev) /* Enable attached regulator if any. */ st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd"); - if (!IS_ERR(st->vdd)) { - ret = regulator_enable(st->vdd); - if (ret) { - dev_err(indio_dev->dev.parent, - "failed to enable Vdd supply: %d\n", ret); - return ret; - } - } else { - ret = PTR_ERR(st->vdd); - if (ret != -ENODEV) - return ret; + if (IS_ERR(st->vdd)) + return PTR_ERR(st->vdd); + + ret = regulator_enable(st->vdd); + if (ret) { + dev_err(indio_dev->dev.parent, + "failed to enable Vdd supply: %d\n", ret); + return ret; } ret = ms5611_reset(indio_dev); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 19d2eb46fda6..c720c3ac0b9b 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -147,12 +147,8 @@ struct zpa2326_private { #define zpa2326_warn(_idev, _format, _arg...) \ dev_warn(_idev->dev.parent, _format, ##_arg) -#ifdef DEBUG #define zpa2326_dbg(_idev, _format, _arg...) \ dev_dbg(_idev->dev.parent, _format, ##_arg) -#else -#define zpa2326_dbg(_idev, _format, _arg...) -#endif bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg) { diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 3141c3c161bb..1fa9eefa0982 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -301,8 +301,6 @@ static int lidar_probe(struct i2c_client *client, if (ret) goto error_unreg_buffer; pm_runtime_enable(&client->dev); - - pm_runtime_mark_last_busy(&client->dev); pm_runtime_idle(&client->dev); return 0; diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index 93a896883e37..4922402e2e98 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -1,76 +1,8 @@ -2009 8/18 - -Core: -1) Get reviews -2) Additional testing -3) Ensure all desirable features present by adding more devices. - Major changes not expected except in response to comments - -Max1363 core: -1) Possibly add sysfs exports of constant useful to userspace. -Would be nice -2) Support hardware generated interrupts -3) Expand device set. Lots of other maxim adc's have very - similar interfaces. - -MXS LRADC driver: -This is a classic MFD device as it combines the following subdevices - - touchscreen controller (input subsystem related device) - - general purpose ADC channels - - battery voltage monitor (power subsystem related device) - - die temperature monitor (thermal management) - -At least the battery voltage and die temperature feature is required in-kernel -by a driver of the SoC's battery charging unit to avoid any damage to the -silicon and the battery. - -TSL2561 -Would be nice -1) Open question of userspace vs kernel space balance when -converting to useful light measurements from device ones. -2) Add sysfs elements necessary to allow device agnostic -unit conversion. - -LIS3L02DQ core - -LIS3L02DQ ring - -KXSD9 -Currently minimal driver, would be nice to add: -1) Support for all chip generated interrupts (events), -basically get support up to level of lis3l02dq driver. - -Ring buffer core - -SCA3000 -Would be nice -1) Testing on devices other than sca3000-e05 - -Trigger core support -1) Discussion of approach. Is it general enough? - -Ring Buffer: -1) Discussion of approach. -There are probably better ways of doing this. The -intention is to allow for more than one software ring -buffer implementation as different users will have -different requirements. This one suits mid range -frequencies (100Hz - 4kHz). -2) Lots of testing - -GPIO trigger -1) Add control over the type of interrupt etc. This will -necessitate a header that is also visible from arch board -files. (avoided at the moment to keep the driver set -contained in staging). +2016 10/09 ADI Drivers: CC the device-drivers-devel@blackfin.uclinux.org mailing list when e-mailing the normal IIO list (see below). -Documentation -1) Lots of cleanup and expansion. -2) Some device require individual docs. - Contact: Jonathan Cameron <jic23@kernel.org>. Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig index 1c994b57c7d2..c6b0f5eae7ab 100644 --- a/drivers/staging/iio/accel/Kconfig +++ b/drivers/staging/iio/accel/Kconfig @@ -51,14 +51,4 @@ config ADIS16240 To compile this driver as a module, say M here: the module will be called adis16240. -config SCA3000 - depends on IIO_BUFFER - depends on SPI - tristate "VTI SCA3000 series accelerometers" - help - Say Y here to build support for the VTI SCA3000 series of SPI - accelerometers. These devices use a hardware ring buffer. - - To compile this driver as a module, say M here: the module will be - called sca3000. endmenu diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile index 1810a434a755..febb137b60c4 100644 --- a/drivers/staging/iio/accel/Makefile +++ b/drivers/staging/iio/accel/Makefile @@ -13,6 +13,3 @@ obj-$(CONFIG_ADIS16209) += adis16209.o adis16240-y := adis16240_core.o obj-$(CONFIG_ADIS16240) += adis16240.o - -sca3000-y := sca3000_core.o sca3000_ring.o -obj-$(CONFIG_SCA3000) += sca3000.o diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h deleted file mode 100644 index 4dcc8575cbe3..000000000000 --- a/drivers/staging/iio/accel/sca3000.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * sca3000.c -- support VTI sca3000 series accelerometers - * via SPI - * - * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> - * - * Partly based upon tle62x0.c - * - * 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. - * - * Initial mode is direct measurement. - * - * Untested things - * - * Temperature reading (the e05 I'm testing with doesn't have a sensor) - * - * Free fall detection mode - supported but untested as I'm not droping my - * dubious wire rig far enough to test it. - * - * Unsupported as yet - * - * Time stamping of data from ring. Various ideas on how to do this but none - * are remotely simple. Suggestions welcome. - * - * Individual enabling disabling of channels going into ring buffer - * - * Overflow handling (this is signaled for all but 8 bit ring buffer mode.) - * - * Motion detector using AND combinations of signals. - * - * Note: Be very careful about not touching an register bytes marked - * as reserved on the data sheet. They really mean it as changing convents of - * some will cause the device to lock up. - * - * Known issues - on rare occasions the interrupts lock up. Not sure why as yet. - * Can probably alleviate this by reading the interrupt register on start, but - * that is really just brushing the problem under the carpet. - */ -#ifndef _SCA3000 -#define _SCA3000 - -#define SCA3000_WRITE_REG(a) (((a) << 2) | 0x02) -#define SCA3000_READ_REG(a) ((a) << 2) - -#define SCA3000_REG_ADDR_REVID 0x00 -#define SCA3000_REVID_MAJOR_MASK 0xf0 -#define SCA3000_REVID_MINOR_MASK 0x0f - -#define SCA3000_REG_ADDR_STATUS 0x02 -#define SCA3000_LOCKED 0x20 -#define SCA3000_EEPROM_CS_ERROR 0x02 -#define SCA3000_SPI_FRAME_ERROR 0x01 - -/* All reads done using register decrement so no need to directly access LSBs */ -#define SCA3000_REG_ADDR_X_MSB 0x05 -#define SCA3000_REG_ADDR_Y_MSB 0x07 -#define SCA3000_REG_ADDR_Z_MSB 0x09 - -#define SCA3000_REG_ADDR_RING_OUT 0x0f - -/* Temp read untested - the e05 doesn't have the sensor */ -#define SCA3000_REG_ADDR_TEMP_MSB 0x13 - -#define SCA3000_REG_ADDR_MODE 0x14 -#define SCA3000_MODE_PROT_MASK 0x28 - -#define SCA3000_RING_BUF_ENABLE 0x80 -#define SCA3000_RING_BUF_8BIT 0x40 -/* - * Free fall detection triggers an interrupt if the acceleration - * is below a threshold for equivalent of 25cm drop - */ -#define SCA3000_FREE_FALL_DETECT 0x10 -#define SCA3000_MEAS_MODE_NORMAL 0x00 -#define SCA3000_MEAS_MODE_OP_1 0x01 -#define SCA3000_MEAS_MODE_OP_2 0x02 - -/* - * In motion detection mode the accelerations are band pass filtered - * (approx 1 - 25Hz) and then a programmable threshold used to trigger - * and interrupt. - */ -#define SCA3000_MEAS_MODE_MOT_DET 0x03 - -#define SCA3000_REG_ADDR_BUF_COUNT 0x15 - -#define SCA3000_REG_ADDR_INT_STATUS 0x16 - -#define SCA3000_INT_STATUS_THREE_QUARTERS 0x80 -#define SCA3000_INT_STATUS_HALF 0x40 - -#define SCA3000_INT_STATUS_FREE_FALL 0x08 -#define SCA3000_INT_STATUS_Y_TRIGGER 0x04 -#define SCA3000_INT_STATUS_X_TRIGGER 0x02 -#define SCA3000_INT_STATUS_Z_TRIGGER 0x01 - -/* Used to allow access to multiplexed registers */ -#define SCA3000_REG_ADDR_CTRL_SEL 0x18 -/* Only available for SCA3000-D03 and SCA3000-D01 */ -#define SCA3000_REG_CTRL_SEL_I2C_DISABLE 0x01 -#define SCA3000_REG_CTRL_SEL_MD_CTRL 0x02 -#define SCA3000_REG_CTRL_SEL_MD_Y_TH 0x03 -#define SCA3000_REG_CTRL_SEL_MD_X_TH 0x04 -#define SCA3000_REG_CTRL_SEL_MD_Z_TH 0x05 -/* - * BE VERY CAREFUL WITH THIS, IF 3 BITS ARE NOT SET the device - * will not function - */ -#define SCA3000_REG_CTRL_SEL_OUT_CTRL 0x0B -#define SCA3000_OUT_CTRL_PROT_MASK 0xE0 -#define SCA3000_OUT_CTRL_BUF_X_EN 0x10 -#define SCA3000_OUT_CTRL_BUF_Y_EN 0x08 -#define SCA3000_OUT_CTRL_BUF_Z_EN 0x04 -#define SCA3000_OUT_CTRL_BUF_DIV_MASK 0x03 -#define SCA3000_OUT_CTRL_BUF_DIV_4 0x02 -#define SCA3000_OUT_CTRL_BUF_DIV_2 0x01 - -/* - * Control which motion detector interrupts are on. - * For now only OR combinations are supported. - */ -#define SCA3000_MD_CTRL_PROT_MASK 0xC0 -#define SCA3000_MD_CTRL_OR_Y 0x01 -#define SCA3000_MD_CTRL_OR_X 0x02 -#define SCA3000_MD_CTRL_OR_Z 0x04 -/* Currently unsupported */ -#define SCA3000_MD_CTRL_AND_Y 0x08 -#define SCA3000_MD_CTRL_AND_X 0x10 -#define SAC3000_MD_CTRL_AND_Z 0x20 - -/* - * Some control registers of complex access methods requiring this register to - * be used to remove a lock. - */ -#define SCA3000_REG_ADDR_UNLOCK 0x1e - -#define SCA3000_REG_ADDR_INT_MASK 0x21 -#define SCA3000_INT_MASK_PROT_MASK 0x1C - -#define SCA3000_INT_MASK_RING_THREE_QUARTER 0x80 -#define SCA3000_INT_MASK_RING_HALF 0x40 - -#define SCA3000_INT_MASK_ALL_INTS 0x02 -#define SCA3000_INT_MASK_ACTIVE_HIGH 0x01 -#define SCA3000_INT_MASK_ACTIVE_LOW 0x00 - -/* Values of multiplexed registers (write to ctrl_data after select) */ -#define SCA3000_REG_ADDR_CTRL_DATA 0x22 - -/* - * Measurement modes available on some sca3000 series chips. Code assumes others - * may become available in the future. - * - * Bypass - Bypass the low-pass filter in the signal channel so as to increase - * signal bandwidth. - * - * Narrow - Narrow low-pass filtering of the signal channel and half output - * data rate by decimation. - * - * Wide - Widen low-pass filtering of signal channel to increase bandwidth - */ -#define SCA3000_OP_MODE_BYPASS 0x01 -#define SCA3000_OP_MODE_NARROW 0x02 -#define SCA3000_OP_MODE_WIDE 0x04 -#define SCA3000_MAX_TX 6 -#define SCA3000_MAX_RX 2 - -/** - * struct sca3000_state - device instance state information - * @us: the associated spi device - * @info: chip variant information - * @interrupt_handler_ws: event interrupt handler for all events - * @last_timestamp: the timestamp of the last event - * @mo_det_use_count: reference counter for the motion detection unit - * @lock: lock used to protect elements of sca3000_state - * and the underlying device state. - * @bpse: number of bits per scan element - * @tx: dma-able transmit buffer - * @rx: dma-able receive buffer - **/ -struct sca3000_state { - struct spi_device *us; - const struct sca3000_chip_info *info; - struct work_struct interrupt_handler_ws; - s64 last_timestamp; - int mo_det_use_count; - struct mutex lock; - int bpse; - /* Can these share a cacheline ? */ - u8 rx[2] ____cacheline_aligned; - u8 tx[6] ____cacheline_aligned; -}; - -/** - * struct sca3000_chip_info - model dependent parameters - * @scale: scale * 10^-6 - * @temp_output: some devices have temperature sensors. - * @measurement_mode_freq: normal mode sampling frequency - * @option_mode_1: first optional mode. Not all models have one - * @option_mode_1_freq: option mode 1 sampling frequency - * @option_mode_2: second optional mode. Not all chips have one - * @option_mode_2_freq: option mode 2 sampling frequency - * - * This structure is used to hold information about the functionality of a given - * sca3000 variant. - **/ -struct sca3000_chip_info { - unsigned int scale; - bool temp_output; - int measurement_mode_freq; - int option_mode_1; - int option_mode_1_freq; - int option_mode_2; - int option_mode_2_freq; - int mot_det_mult_xz[6]; - int mot_det_mult_y[7]; -}; - -int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len); - -/** - * sca3000_write_reg() write a single register - * @address: address of register on chip - * @val: value to be written to register - * - * The main lock must be held. - **/ -int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val); - -#ifdef CONFIG_IIO_BUFFER -/** - * sca3000_register_ring_funcs() setup the ring state change functions - **/ -void sca3000_register_ring_funcs(struct iio_dev *indio_dev); - -/** - * sca3000_configure_ring() - allocate and configure ring buffer - * @indio_dev: iio-core device whose ring is to be configured - * - * The hardware ring buffer needs far fewer ring buffer functions than - * a software one as a lot of things are handled automatically. - * This function also tells the iio core that our device supports a - * hardware ring buffer mode. - **/ -int sca3000_configure_ring(struct iio_dev *indio_dev); - -/** - * sca3000_unconfigure_ring() - deallocate the ring buffer - * @indio_dev: iio-core device whose ring we are freeing - **/ -void sca3000_unconfigure_ring(struct iio_dev *indio_dev); - -/** - * sca3000_ring_int_process() handles ring related event pushing and escalation - * @val: the event code - **/ -void sca3000_ring_int_process(u8 val, struct iio_buffer *ring); - -#else -static inline void sca3000_register_ring_funcs(struct iio_dev *indio_dev) -{ -} - -static inline -int sca3000_register_ring_access_and_init(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void sca3000_ring_int_process(u8 val, void *ring) -{ -} - -#endif -#endif /* _SCA3000 */ diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c deleted file mode 100644 index d626125d7af9..000000000000 --- a/drivers/staging/iio/accel/sca3000_core.c +++ /dev/null @@ -1,1208 +0,0 @@ -/* - * sca3000_core.c -- support VTI sca3000 series accelerometers via SPI - * - * 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. - * - * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> - * - * See industrialio/accels/sca3000.h for comments. - */ - -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/sysfs.h> -#include <linux/module.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/events.h> -#include <linux/iio/buffer.h> - -#include "sca3000.h" - -enum sca3000_variant { - d01, - e02, - e04, - e05, -}; - -/* - * Note where option modes are not defined, the chip simply does not - * support any. - * Other chips in the sca3000 series use i2c and are not included here. - * - * Some of these devices are only listed in the family data sheet and - * do not actually appear to be available. - */ -static const struct sca3000_chip_info sca3000_spi_chip_info_tbl[] = { - [d01] = { - .scale = 7357, - .temp_output = true, - .measurement_mode_freq = 250, - .option_mode_1 = SCA3000_OP_MODE_BYPASS, - .option_mode_1_freq = 250, - .mot_det_mult_xz = {50, 100, 200, 350, 650, 1300}, - .mot_det_mult_y = {50, 100, 150, 250, 450, 850, 1750}, - }, - [e02] = { - .scale = 9810, - .measurement_mode_freq = 125, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 63, - .mot_det_mult_xz = {100, 150, 300, 550, 1050, 2050}, - .mot_det_mult_y = {50, 100, 200, 350, 700, 1350, 2700}, - }, - [e04] = { - .scale = 19620, - .measurement_mode_freq = 100, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .mot_det_mult_xz = {200, 300, 600, 1100, 2100, 4100}, - .mot_det_mult_y = {100, 200, 400, 7000, 1400, 2700, 54000}, - }, - [e05] = { - .scale = 61313, - .measurement_mode_freq = 200, - .option_mode_1 = SCA3000_OP_MODE_NARROW, - .option_mode_1_freq = 50, - .option_mode_2 = SCA3000_OP_MODE_WIDE, - .option_mode_2_freq = 400, - .mot_det_mult_xz = {600, 900, 1700, 3200, 6100, 11900}, - .mot_det_mult_y = {300, 600, 1200, 2000, 4100, 7800, 15600}, - }, -}; - -int sca3000_write_reg(struct sca3000_state *st, u8 address, u8 val) -{ - st->tx[0] = SCA3000_WRITE_REG(address); - st->tx[1] = val; - return spi_write(st->us, st->tx, 2); -} - -int sca3000_read_data_short(struct sca3000_state *st, - u8 reg_address_high, - int len) -{ - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - .rx_buf = st->rx, - } - }; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_reg_lock_on() test if the ctrl register lock is on - * - * Lock must be held. - **/ -static int sca3000_reg_lock_on(struct sca3000_state *st) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1); - if (ret < 0) - return ret; - - return !(st->rx[0] & SCA3000_LOCKED); -} - -/** - * __sca3000_unlock_reg_lock() unlock the control registers - * - * Note the device does not appear to support doing this in a single transfer. - * This should only ever be used as part of ctrl reg read. - * Lock must be held before calling this - **/ -static int __sca3000_unlock_reg_lock(struct sca3000_state *st) -{ - struct spi_transfer xfer[3] = { - { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx, - }, { - .len = 2, - .cs_change = 1, - .tx_buf = st->tx + 2, - }, { - .len = 2, - .tx_buf = st->tx + 4, - }, - }; - st->tx[0] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[1] = 0x00; - st->tx[2] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[3] = 0x50; - st->tx[4] = SCA3000_WRITE_REG(SCA3000_REG_ADDR_UNLOCK); - st->tx[5] = 0xA0; - - return spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); -} - -/** - * sca3000_write_ctrl_reg() write to a lock protect ctrl register - * @sel: selects which registers we wish to write to - * @val: the value to be written - * - * Certain control registers are protected against overwriting by the lock - * register and use a shared write address. This function allows writing of - * these registers. - * Lock must be held. - **/ -static int sca3000_write_ctrl_reg(struct sca3000_state *st, - u8 sel, - uint8_t val) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, sel); - if (ret) - goto error_ret; - - /* Write the actual value into the register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_DATA, val); - -error_ret: - return ret; -} - -/** - * sca3000_read_ctrl_reg() read from lock protected control register. - * - * Lock must be held. - **/ -static int sca3000_read_ctrl_reg(struct sca3000_state *st, - u8 ctrl_reg) -{ - int ret; - - ret = sca3000_reg_lock_on(st); - if (ret < 0) - goto error_ret; - if (ret) { - ret = __sca3000_unlock_reg_lock(st); - if (ret) - goto error_ret; - } - /* Set the control select register */ - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_CTRL_SEL, ctrl_reg); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_CTRL_DATA, 1); - if (ret) - goto error_ret; - return st->rx[0]; -error_ret: - return ret; -} - -/** - * sca3000_show_rev() - sysfs interface to read the chip revision number - **/ -static ssize_t sca3000_show_rev(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int len = 0, ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_REVID, 1); - if (ret < 0) - goto error_ret; - len += sprintf(buf + len, - "major=%d, minor=%d\n", - st->rx[0] & SCA3000_REVID_MAJOR_MASK, - st->rx[0] & SCA3000_REVID_MINOR_MASK); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_show_available_measurement_modes() display available modes - * - * This is all read from chip specific data in the driver. Not all - * of the sca3000 series support modes other than normal. - **/ -static ssize_t -sca3000_show_available_measurement_modes(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0; - - len += sprintf(buf + len, "0 - normal mode"); - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, ", 1 - narrow mode"); - break; - case SCA3000_OP_MODE_BYPASS: - len += sprintf(buf + len, ", 1 - bypass mode"); - break; - } - switch (st->info->option_mode_2) { - case SCA3000_OP_MODE_WIDE: - len += sprintf(buf + len, ", 2 - wide mode"); - break; - } - /* always supported */ - len += sprintf(buf + len, " 3 - motion detection\n"); - - return len; -} - -/** - * sca3000_show_measurement_mode() sysfs read of current mode - **/ -static ssize_t -sca3000_show_measurement_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - /* mask bottom 2 bits - only ones that are relevant */ - st->rx[0] &= 0x03; - switch (st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "0 - normal mode\n"); - break; - case SCA3000_MEAS_MODE_MOT_DET: - len += sprintf(buf + len, "3 - motion detection\n"); - break; - case SCA3000_MEAS_MODE_OP_1: - switch (st->info->option_mode_1) { - case SCA3000_OP_MODE_NARROW: - len += sprintf(buf + len, "1 - narrow mode\n"); - break; - case SCA3000_OP_MODE_BYPASS: - len += sprintf(buf + len, "1 - bypass mode\n"); - break; - } - break; - case SCA3000_MEAS_MODE_OP_2: - switch (st->info->option_mode_2) { - case SCA3000_OP_MODE_WIDE: - len += sprintf(buf + len, "2 - wide mode\n"); - break; - } - break; - } - -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_store_measurement_mode() set the current mode - **/ -static ssize_t -sca3000_store_measurement_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 mask = 0x03; - u8 val; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - if (val > 3) { - ret = -EINVAL; - goto error_ret; - } - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - st->rx[0] &= ~mask; - st->rx[0] |= (val & mask); - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, st->rx[0]); - if (ret) - goto error_ret; - mutex_unlock(&st->lock); - - return len; - -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/* - * Not even vaguely standard attributes so defined here rather than - * in the relevant IIO core headers - */ -static IIO_DEVICE_ATTR(measurement_mode_available, S_IRUGO, - sca3000_show_available_measurement_modes, - NULL, 0); - -static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR, - sca3000_show_measurement_mode, - sca3000_store_measurement_mode, - 0); - -/* More standard attributes */ - -static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); - -static const struct iio_event_spec sca3000_event = { - .type = IIO_EV_TYPE_MAG, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), -}; - -#define SCA3000_CHAN(index, mod) \ - { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = mod, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ - .address = index, \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 11, \ - .storagebits = 16, \ - .shift = 5, \ - }, \ - .event_spec = &sca3000_event, \ - .num_event_specs = 1, \ - } - -static const struct iio_chan_spec sca3000_channels[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), -}; - -static const struct iio_chan_spec sca3000_channels_with_temp[] = { - SCA3000_CHAN(0, IIO_MOD_X), - SCA3000_CHAN(1, IIO_MOD_Y), - SCA3000_CHAN(2, IIO_MOD_Z), - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - /* No buffer support */ - .scan_index = -1, - }, -}; - -static u8 sca3000_addresses[3][3] = { - [0] = {SCA3000_REG_ADDR_X_MSB, SCA3000_REG_CTRL_SEL_MD_X_TH, - SCA3000_MD_CTRL_OR_X}, - [1] = {SCA3000_REG_ADDR_Y_MSB, SCA3000_REG_CTRL_SEL_MD_Y_TH, - SCA3000_MD_CTRL_OR_Y}, - [2] = {SCA3000_REG_ADDR_Z_MSB, SCA3000_REG_CTRL_SEL_MD_Z_TH, - SCA3000_MD_CTRL_OR_Z}, -}; - -/** - * __sca3000_get_base_freq() obtain mode specific base frequency - * - * lock must be held - **/ -static inline int __sca3000_get_base_freq(struct sca3000_state *st, - const struct sca3000_chip_info *info, - int *base_freq) -{ - int ret; - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - switch (0x03 & st->rx[0]) { - case SCA3000_MEAS_MODE_NORMAL: - *base_freq = info->measurement_mode_freq; - break; - case SCA3000_MEAS_MODE_OP_1: - *base_freq = info->option_mode_1_freq; - break; - case SCA3000_MEAS_MODE_OP_2: - *base_freq = info->option_mode_2_freq; - break; - } -error_ret: - return ret; -} - -/** - * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * - * lock must be held - **/ -static int read_raw_samp_freq(struct sca3000_state *st, int *val) -{ - int ret; - - ret = __sca3000_get_base_freq(st, st->info, val); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - if (*val > 0) { - ret &= SCA3000_OUT_CTRL_BUF_DIV_MASK; - switch (ret) { - case SCA3000_OUT_CTRL_BUF_DIV_2: - *val /= 2; - break; - case SCA3000_OUT_CTRL_BUF_DIV_4: - *val /= 4; - break; - } - } - - return 0; -} - -/** - * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ - * - * lock must be held - **/ -static int write_raw_samp_freq(struct sca3000_state *st, int val) -{ - int ret, base_freq, ctrlval; - - ret = __sca3000_get_base_freq(st, st->info, &base_freq); - if (ret) - return ret; - - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - return ret; - - ctrlval = ret & ~SCA3000_OUT_CTRL_BUF_DIV_MASK; - - if (val == base_freq / 2) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_2; - if (val == base_freq / 4) - ctrlval |= SCA3000_OUT_CTRL_BUF_DIV_4; - else if (val != base_freq) - return -EINVAL; - - return sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - ctrlval); -} - -static int sca3000_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 address; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&st->lock); - if (chan->type == IIO_ACCEL) { - if (st->mo_det_use_count) { - mutex_unlock(&st->lock); - return -EBUSY; - } - address = sca3000_addresses[chan->address][0]; - ret = sca3000_read_data_short(st, address, 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF; - *val = ((*val) << (sizeof(*val) * 8 - 13)) >> - (sizeof(*val) * 8 - 13); - } else { - /* get the temperature when available */ - ret = sca3000_read_data_short(st, - SCA3000_REG_ADDR_TEMP_MSB, - 2); - if (ret < 0) { - mutex_unlock(&st->lock); - return ret; - } - *val = ((st->rx[0] & 0x3F) << 3) | - ((st->rx[1] & 0xE0) >> 5); - } - mutex_unlock(&st->lock); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - *val = 0; - if (chan->type == IIO_ACCEL) - *val2 = st->info->scale; - else /* temperature */ - *val2 = 555556; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_OFFSET: - *val = -214; - *val2 = 600000; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&st->lock); - ret = read_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret ? ret : IIO_VAL_INT; - default: - return -EINVAL; - } -} - -static int sca3000_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - if (val2) - return -EINVAL; - mutex_lock(&st->lock); - ret = write_raw_samp_freq(st, val); - mutex_unlock(&st->lock); - return ret; - default: - return -EINVAL; - } - - return ret; -} - -/** - * sca3000_read_av_freq() sysfs function to get available frequencies - * - * The later modes are only relevant to the ring buffer - and depend on current - * mode. Note that data sheet gives rather wide tolerances for these so integer - * division will give good enough answer and not all chips have them specified - * at all. - **/ -static ssize_t sca3000_read_av_freq(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int len = 0, ret, val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto error_ret; - - switch (val & 0x03) { - case SCA3000_MEAS_MODE_NORMAL: - len += sprintf(buf + len, "%d %d %d\n", - st->info->measurement_mode_freq, - st->info->measurement_mode_freq / 2, - st->info->measurement_mode_freq / 4); - break; - case SCA3000_MEAS_MODE_OP_1: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_1_freq, - st->info->option_mode_1_freq / 2, - st->info->option_mode_1_freq / 4); - break; - case SCA3000_MEAS_MODE_OP_2: - len += sprintf(buf + len, "%d %d %d\n", - st->info->option_mode_2_freq, - st->info->option_mode_2_freq / 2, - st->info->option_mode_2_freq / 4); - break; - } - return len; -error_ret: - return ret; -} - -/* - * Should only really be registered if ring buffer support is compiled in. - * Does no harm however and doing it right would add a fair bit of complexity - */ -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sca3000_read_av_freq); - -/** - * sca3000_read_thresh() - query of a threshold - **/ -static int sca3000_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - int ret, i; - struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; - - mutex_lock(&st->lock); - ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - *val = 0; - if (num == 1) - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_y)) - *val += st->info->mot_det_mult_y[i]; - else - for_each_set_bit(i, (unsigned long *)&ret, - ARRAY_SIZE(st->info->mot_det_mult_xz)) - *val += st->info->mot_det_mult_xz[i]; - - return IIO_VAL_INT; -} - -/** - * sca3000_write_thresh() control of threshold - **/ -static int sca3000_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int num = chan->channel2; - int ret; - int i; - u8 nonlinear = 0; - - if (num == 1) { - i = ARRAY_SIZE(st->info->mot_det_mult_y); - while (i > 0) - if (val >= st->info->mot_det_mult_y[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_y[i]; - } - } else { - i = ARRAY_SIZE(st->info->mot_det_mult_xz); - while (i > 0) - if (val >= st->info->mot_det_mult_xz[--i]) { - nonlinear |= (1 << i); - val -= st->info->mot_det_mult_xz[i]; - } - } - - mutex_lock(&st->lock); - ret = sca3000_write_ctrl_reg(st, sca3000_addresses[num][1], nonlinear); - mutex_unlock(&st->lock); - - return ret; -} - -static struct attribute *sca3000_attributes[] = { - &iio_dev_attr_revision.dev_attr.attr, - &iio_dev_attr_measurement_mode_available.dev_attr.attr, - &iio_dev_attr_measurement_mode.dev_attr.attr, - &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group sca3000_attribute_group = { - .attrs = sca3000_attributes, -}; - -/** - * sca3000_event_handler() - handling ring and non ring events - * - * Ring related interrupt handler. Depending on event, push to - * the ring buffer event chrdev or the event one. - * - * This function is complicated by the fact that the devices can signify ring - * and non ring events via the same interrupt line and they can only - * be distinguished via a read of the relevant status register. - **/ -static irqreturn_t sca3000_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct sca3000_state *st = iio_priv(indio_dev); - int ret, val; - s64 last_timestamp = iio_get_time_ns(indio_dev); - - /* - * Could lead if badly timed to an extra read of status reg, - * but ensures no interrupt is missed. - */ - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - goto done; - - sca3000_ring_int_process(val, indio_dev->buffer); - - if (val & SCA3000_INT_STATUS_FREE_FALL) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X_AND_Y_AND_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_FALLING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Y_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_X_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - - if (val & SCA3000_INT_STATUS_Z_TRIGGER) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_MAG, - IIO_EV_DIR_RISING), - last_timestamp); - -done: - return IRQ_HANDLED; -} - -/** - * sca3000_read_event_config() what events are enabled - **/ -static int sca3000_read_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - u8 protect_mask = 0x03; - int num = chan->channel2; - - /* read current value of mode register */ - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - - if ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET) { - ret = 0; - } else { - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - /* only supporting logical or's for now */ - ret = !!(ret & sca3000_addresses[num][2]); - } -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/** - * sca3000_query_free_fall_mode() is free fall mode enabled - **/ -static ssize_t sca3000_query_free_fall_mode(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int ret; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - int val; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret < 0) - return ret; - return sprintf(buf, "%d\n", !!(val & SCA3000_FREE_FALL_DETECT)); -} - -/** - * sca3000_set_free_fall_mode() simple on off control for free fall int - * - * In these chips the free fall detector should send an interrupt if - * the device falls more than 25cm. This has not been tested due - * to fragile wiring. - **/ -static ssize_t sca3000_set_free_fall_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - u8 val; - int ret; - u8 protect_mask = SCA3000_FREE_FALL_DETECT; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - - /* if off and should be on */ - if (val && !(st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_FREE_FALL_DETECT)); - /* if on and should be off */ - else if (!val && (st->rx[0] & protect_mask)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -/** - * sca3000_write_event_config() simple on off control for motion detector - * - * This is a per axis control, but enabling any will result in the - * motion detector unit being enabled. - * N.B. enabling motion detector stops normal data acquisition. - * There is a complexity in knowing which mode to return to when - * this mode is disabled. Currently normal mode is assumed. - **/ -static int sca3000_write_event_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret, ctrlval; - u8 protect_mask = 0x03; - int num = chan->channel2; - - mutex_lock(&st->lock); - /* - * First read the motion detector config to find out if - * this axis is on - */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto exit_point; - ctrlval = ret; - /* if off and should be on */ - if (state && !(ctrlval & sca3000_addresses[num][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval | - sca3000_addresses[num][2]); - if (ret) - goto exit_point; - st->mo_det_use_count++; - } else if (!state && (ctrlval & sca3000_addresses[num][2])) { - ret = sca3000_write_ctrl_reg(st, - SCA3000_REG_CTRL_SEL_MD_CTRL, - ctrlval & - ~(sca3000_addresses[num][2])); - if (ret) - goto exit_point; - st->mo_det_use_count--; - } - - /* read current value of mode register */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto exit_point; - /* if off and should be on */ - if ((st->mo_det_use_count) && - ((st->rx[0] & protect_mask) != SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask) - | SCA3000_MEAS_MODE_MOT_DET); - /* if on and should be off */ - else if (!(st->mo_det_use_count) && - ((st->rx[0] & protect_mask) == SCA3000_MEAS_MODE_MOT_DET)) - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~protect_mask)); -exit_point: - mutex_unlock(&st->lock); - - return ret; -} - -/* Free fall detector related event attribute */ -static IIO_DEVICE_ATTR_NAMED(accel_xayaz_mag_falling_en, - in_accel_x & y & z_mag_falling_en, - S_IRUGO | S_IWUSR, - sca3000_query_free_fall_mode, - sca3000_set_free_fall_mode, - 0); - -static IIO_CONST_ATTR_NAMED(accel_xayaz_mag_falling_period, - in_accel_x & y & z_mag_falling_period, - "0.226"); - -static struct attribute *sca3000_event_attributes[] = { - &iio_dev_attr_accel_xayaz_mag_falling_en.dev_attr.attr, - &iio_const_attr_accel_xayaz_mag_falling_period.dev_attr.attr, - NULL, -}; - -static struct attribute_group sca3000_event_attribute_group = { - .attrs = sca3000_event_attributes, - .name = "events", -}; - -/** - * sca3000_clean_setup() get the device into a predictable state - * - * Devices use flash memory to store many of the register values - * and hence can come up in somewhat unpredictable states. - * Hence reset everything on driver load. - **/ -static int sca3000_clean_setup(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - /* Ensure all interrupts have been acknowledged */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_STATUS, 1); - if (ret) - goto error_ret; - - /* Turn off all motion detection channels */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_MD_CTRL, - ret & SCA3000_MD_CTRL_PROT_MASK); - if (ret) - goto error_ret; - - /* Disable ring buffer */ - ret = sca3000_read_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL); - if (ret < 0) - goto error_ret; - ret = sca3000_write_ctrl_reg(st, SCA3000_REG_CTRL_SEL_OUT_CTRL, - (ret & SCA3000_OUT_CTRL_PROT_MASK) - | SCA3000_OUT_CTRL_BUF_X_EN - | SCA3000_OUT_CTRL_BUF_Y_EN - | SCA3000_OUT_CTRL_BUF_Z_EN - | SCA3000_OUT_CTRL_BUF_DIV_4); - if (ret) - goto error_ret; - /* Enable interrupts, relevant to mode and set up as active low */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - (ret & SCA3000_INT_MASK_PROT_MASK) - | SCA3000_INT_MASK_ACTIVE_LOW); - if (ret) - goto error_ret; - /* - * Select normal measurement mode, free fall off, ring off - * Ring in 12 bit mode - it is fine to overwrite reserved bits 3,5 - * as that occurs in one of the example on the datasheet - */ - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_MODE, - (st->rx[0] & SCA3000_MODE_PROT_MASK)); - st->bpse = 11; - -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static const struct iio_info sca3000_info = { - .attrs = &sca3000_attribute_group, - .read_raw = &sca3000_read_raw, - .write_raw = &sca3000_write_raw, - .event_attrs = &sca3000_event_attribute_group, - .read_event_value = &sca3000_read_thresh, - .write_event_value = &sca3000_write_thresh, - .read_event_config = &sca3000_read_event_config, - .write_event_config = &sca3000_write_event_config, - .driver_module = THIS_MODULE, -}; - -static int sca3000_probe(struct spi_device *spi) -{ - int ret; - struct sca3000_state *st; - struct iio_dev *indio_dev; - - 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); - st->us = spi; - mutex_init(&st->lock); - st->info = &sca3000_spi_chip_info_tbl[spi_get_device_id(spi) - ->driver_data]; - - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->info = &sca3000_info; - if (st->info->temp_output) { - indio_dev->channels = sca3000_channels_with_temp; - indio_dev->num_channels = - ARRAY_SIZE(sca3000_channels_with_temp); - } else { - indio_dev->channels = sca3000_channels; - indio_dev->num_channels = ARRAY_SIZE(sca3000_channels); - } - indio_dev->modes = INDIO_DIRECT_MODE; - - sca3000_configure_ring(indio_dev); - ret = iio_device_register(indio_dev); - if (ret < 0) - return ret; - - if (spi->irq) { - ret = request_threaded_irq(spi->irq, - NULL, - &sca3000_event_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "sca3000", - indio_dev); - if (ret) - goto error_unregister_dev; - } - sca3000_register_ring_funcs(indio_dev); - ret = sca3000_clean_setup(st); - if (ret) - goto error_free_irq; - return 0; - -error_free_irq: - if (spi->irq) - free_irq(spi->irq, indio_dev); -error_unregister_dev: - iio_device_unregister(indio_dev); - return ret; -} - -static int sca3000_stop_all_interrupts(struct sca3000_state *st) -{ - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - ret = sca3000_write_reg(st, SCA3000_REG_ADDR_INT_MASK, - (st->rx[0] & - ~(SCA3000_INT_MASK_RING_THREE_QUARTER | - SCA3000_INT_MASK_RING_HALF | - SCA3000_INT_MASK_ALL_INTS))); -error_ret: - mutex_unlock(&st->lock); - return ret; -} - -static int sca3000_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct sca3000_state *st = iio_priv(indio_dev); - - /* Must ensure no interrupts can be generated after this! */ - sca3000_stop_all_interrupts(st); - if (spi->irq) - free_irq(spi->irq, indio_dev); - iio_device_unregister(indio_dev); - sca3000_unconfigure_ring(indio_dev); - - return 0; -} - -static const struct spi_device_id sca3000_id[] = { - {"sca3000_d01", d01}, - {"sca3000_e02", e02}, - {"sca3000_e04", e04}, - {"sca3000_e05", e05}, - {} -}; -MODULE_DEVICE_TABLE(spi, sca3000_id); - -static struct spi_driver sca3000_driver = { - .driver = { - .name = "sca3000", - }, - .probe = sca3000_probe, - .remove = sca3000_remove, - .id_table = sca3000_id, -}; -module_spi_driver(sca3000_driver); - -MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); -MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c deleted file mode 100644 index d1cb9b9cf22b..000000000000 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * sca3000_ring.c -- support VTI sca3000 series accelerometers via SPI - * - * 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. - * - * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> - * - */ - -#include <linux/interrupt.h> -#include <linux/fs.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/spi/spi.h> -#include <linux/sysfs.h> -#include <linux/sched.h> -#include <linux/poll.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/buffer.h> -#include "../ring_hw.h" -#include "sca3000.h" - -/* RFC / future work - * - * The internal ring buffer doesn't actually change what it holds depending - * on which signals are enabled etc, merely whether you can read them. - * As such the scan mode selection is somewhat different than for a software - * ring buffer and changing it actually covers any data already in the buffer. - * Currently scan elements aren't configured so it doesn't matter. - */ - -static int sca3000_read_data(struct sca3000_state *st, - u8 reg_address_high, - u8 **rx_p, - int len) -{ - int ret; - struct spi_transfer xfer[2] = { - { - .len = 1, - .tx_buf = st->tx, - }, { - .len = len, - } - }; - *rx_p = kmalloc(len, GFP_KERNEL); - if (!*rx_p) { - ret = -ENOMEM; - goto error_ret; - } - xfer[1].rx_buf = *rx_p; - st->tx[0] = SCA3000_READ_REG(reg_address_high); - ret = spi_sync_transfer(st->us, xfer, ARRAY_SIZE(xfer)); - if (ret) { - dev_err(get_device(&st->us->dev), "problem reading register"); - goto error_free_rx; - } - - return 0; -error_free_rx: - kfree(*rx_p); -error_ret: - return ret; -} - -/** - * sca3000_read_first_n_hw_rb() - main ring access, pulls data from ring - * @r: the ring - * @count: number of samples to try and pull - * @data: output the actual samples pulled from the hw ring - * - * Currently does not provide timestamps. As the hardware doesn't add them they - * can only be inferred approximately from ring buffer events such as 50% full - * and knowledge of when buffer was last emptied. This is left to userspace. - **/ -static int sca3000_read_first_n_hw_rb(struct iio_buffer *r, - size_t count, char __user *buf) -{ - struct iio_hw_buffer *hw_ring = iio_to_hw_buf(r); - struct iio_dev *indio_dev = hw_ring->private; - struct sca3000_state *st = iio_priv(indio_dev); - u8 *rx; - int ret, i, num_available, num_read = 0; - int bytes_per_sample = 1; - - if (st->bpse == 11) - bytes_per_sample = 2; - - mutex_lock(&st->lock); - if (count % bytes_per_sample) { - ret = -EINVAL; - goto error_ret; - } - - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_BUF_COUNT, 1); - if (ret) - goto error_ret; - num_available = st->rx[0]; - /* - * num_available is the total number of samples available - * i.e. number of time points * number of channels. - */ - if (count > num_available * bytes_per_sample) - num_read = num_available * bytes_per_sample; - else - num_read = count; - - ret = sca3000_read_data(st, - SCA3000_REG_ADDR_RING_OUT, - &rx, num_read); - if (ret) - goto error_ret; - - for (i = 0; i < num_read / sizeof(u16); i++) - *(((u16 *)rx) + i) = be16_to_cpup((__be16 *)rx + i); - - if (copy_to_user(buf, rx, num_read)) - ret = -EFAULT; - kfree(rx); - r->stufftoread = 0; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : num_read; -} - -static size_t sca3000_ring_buf_data_available(struct iio_buffer *r) -{ - return r->stufftoread ? r->watermark : 0; -} - -/** - * sca3000_query_ring_int() is the hardware ring status interrupt enabled - **/ -static ssize_t sca3000_query_ring_int(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int ret, val; - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - val = st->rx[0]; - mutex_unlock(&st->lock); - if (ret) - return ret; - - return sprintf(buf, "%d\n", !!(val & this_attr->address)); -} - -/** - * sca3000_set_ring_int() set state of ring status interrupt - **/ -static ssize_t sca3000_set_ring_int(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - u8 val; - int ret; - - mutex_lock(&st->lock); - ret = kstrtou8(buf, 10, &val); - if (ret) - goto error_ret; - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_INT_MASK, 1); - if (ret) - goto error_ret; - if (val) - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] | this_attr->address); - else - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_INT_MASK, - st->rx[0] & ~this_attr->address); -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(50_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_HALF); - -static IIO_DEVICE_ATTR(75_percent, S_IRUGO | S_IWUSR, - sca3000_query_ring_int, - sca3000_set_ring_int, - SCA3000_INT_MASK_RING_THREE_QUARTER); - -static ssize_t sca3000_show_buffer_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct sca3000_state *st = iio_priv(indio_dev); - - return sprintf(buf, "0.%06d\n", 4 * st->info->scale); -} - -static IIO_DEVICE_ATTR(in_accel_scale, - S_IRUGO, - sca3000_show_buffer_scale, - NULL, - 0); - -/* - * Ring buffer attributes - * This device is a bit unusual in that the sampling frequency and bpse - * only apply to the ring buffer. At all times full rate and accuracy - * is available via direct reading from registers. - */ -static const struct attribute *sca3000_ring_attributes[] = { - &iio_dev_attr_50_percent.dev_attr.attr, - &iio_dev_attr_75_percent.dev_attr.attr, - &iio_dev_attr_in_accel_scale.dev_attr.attr, - NULL, -}; - -static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev) -{ - struct iio_buffer *buf; - struct iio_hw_buffer *ring; - - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - return NULL; - - ring->private = indio_dev; - buf = &ring->buf; - buf->stufftoread = 0; - buf->length = 64; - buf->attrs = sca3000_ring_attributes; - iio_buffer_init(buf); - - return buf; -} - -static void sca3000_ring_release(struct iio_buffer *r) -{ - kfree(iio_to_hw_buf(r)); -} - -static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { - .read_first_n = &sca3000_read_first_n_hw_rb, - .data_available = sca3000_ring_buf_data_available, - .release = sca3000_ring_release, - - .modes = INDIO_BUFFER_HARDWARE, -}; - -int sca3000_configure_ring(struct iio_dev *indio_dev) -{ - struct iio_buffer *buffer; - - buffer = sca3000_rb_allocate(indio_dev); - if (!buffer) - return -ENOMEM; - indio_dev->modes |= INDIO_BUFFER_HARDWARE; - - indio_dev->buffer->access = &sca3000_ring_access_funcs; - - iio_device_attach_buffer(indio_dev, buffer); - - return 0; -} - -void sca3000_unconfigure_ring(struct iio_dev *indio_dev) -{ - iio_buffer_put(indio_dev->buffer); -} - -static inline -int __sca3000_hw_ring_state_set(struct iio_dev *indio_dev, bool state) -{ - struct sca3000_state *st = iio_priv(indio_dev); - int ret; - - mutex_lock(&st->lock); - ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_MODE, 1); - if (ret) - goto error_ret; - if (state) { - dev_info(&indio_dev->dev, "supposedly enabling ring buffer\n"); - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] | SCA3000_RING_BUF_ENABLE)); - } else - ret = sca3000_write_reg(st, - SCA3000_REG_ADDR_MODE, - (st->rx[0] & ~SCA3000_RING_BUF_ENABLE)); -error_ret: - mutex_unlock(&st->lock); - - return ret; -} - -/** - * sca3000_hw_ring_preenable() hw ring buffer preenable function - * - * Very simple enable function as the chip will allows normal reads - * during ring buffer operation so as long as it is indeed running - * before we notify the core, the precise ordering does not matter. - **/ -static int sca3000_hw_ring_preenable(struct iio_dev *indio_dev) -{ - return __sca3000_hw_ring_state_set(indio_dev, 1); -} - -static int sca3000_hw_ring_postdisable(struct iio_dev *indio_dev) -{ - return __sca3000_hw_ring_state_set(indio_dev, 0); -} - -static const struct iio_buffer_setup_ops sca3000_ring_setup_ops = { - .preenable = &sca3000_hw_ring_preenable, - .postdisable = &sca3000_hw_ring_postdisable, -}; - -void sca3000_register_ring_funcs(struct iio_dev *indio_dev) -{ - indio_dev->setup_ops = &sca3000_ring_setup_ops; -} - -/** - * sca3000_ring_int_process() ring specific interrupt handling. - * - * This is only split from the main interrupt handler so as to - * reduce the amount of code if the ring buffer is not enabled. - **/ -void sca3000_ring_int_process(u8 val, struct iio_buffer *ring) -{ - if (val & (SCA3000_INT_STATUS_THREE_QUARTERS | - SCA3000_INT_STATUS_HALF)) { - ring->stufftoread = true; - wake_up_interruptible(&ring->pollq); - } -} diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 3cdd83ccec8e..ac09485923b6 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -2,7 +2,6 @@ # Makefile for industrial I/O ADC drivers # -ad7606-y := ad7606_core.o ad7606_ring.o obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o obj-$(CONFIG_AD7606) += ad7606.o diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 1cf6b79801a9..bfa12ceb1e1f 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -322,57 +322,6 @@ out: return ret; } -static ssize_t ad7192_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7192_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", st->mclk / - (st->f_order * 1024 * AD7192_MODE_RATE(st->mode))); -} - -static ssize_t ad7192_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 ad7192_state *st = iio_priv(indio_dev); - unsigned long lval; - int div, ret; - - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; - if (lval == 0) - return -EINVAL; - - ret = iio_device_claim_direct_mode(indio_dev); - if (ret) - return ret; - - div = st->mclk / (lval * st->f_order * 1024); - if (div < 1 || div > 1023) { - ret = -EINVAL; - goto out; - } - - st->mode &= ~AD7192_MODE_RATE(-1); - st->mode |= AD7192_MODE_RATE(div); - ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); - -out: - iio_device_release_direct_mode(indio_dev); - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7192_read_frequency, - ad7192_write_frequency); - static ssize_t ad7192_show_scale_available(struct device *dev, struct device_attribute *attr, char *buf) @@ -471,7 +420,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, S_IRUGO | S_IWUSR, AD7192_REG_MODE); static struct attribute *ad7192_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, @@ -484,7 +432,6 @@ static const struct attribute_group ad7192_attribute_group = { }; static struct attribute *ad7195_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage_scale_available.dev_attr.attr, &iio_dev_attr_bridge_switch_en.dev_attr.attr, @@ -536,6 +483,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, if (chan->type == IIO_TEMP) *val -= 273 * ad7192_get_temp_scale(unipolar); return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->mclk / + (st->f_order * 1024 * AD7192_MODE_RATE(st->mode)); + return IIO_VAL_INT; } return -EINVAL; @@ -548,7 +499,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7192_state *st = iio_priv(indio_dev); - int ret, i; + int ret, i, div; unsigned int tmp; ret = iio_device_claim_direct_mode(indio_dev); @@ -572,6 +523,22 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (!val) { + ret = -EINVAL; + break; + } + + div = st->mclk / (val * st->f_order * 1024); + if (div < 1 || div > 1023) { + ret = -EINVAL; + break; + } + + st->mode &= ~AD7192_MODE_RATE(-1); + st->mode |= AD7192_MODE_RATE(div); + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); + break; default: ret = -EINVAL; } @@ -585,7 +552,14 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) { - return IIO_VAL_INT_PLUS_NANO; + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_SAMP_FREQ: + return IIO_VAL_INT; + default: + return -EINVAL; + } } static const struct iio_info ad7192_info = { diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index b460dda7eb65..ee679ac0368f 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -777,7 +777,7 @@ static struct attribute *ad7280_event_attributes[] = { NULL, }; -static struct attribute_group ad7280_event_attrs_group = { +static const struct attribute_group ad7280_event_attrs_group = { .attrs = ad7280_event_attributes, }; diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606.c index f79ee61851f6..453190864b2f 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -13,7 +13,7 @@ #include <linux/sysfs.h> #include <linux/regulator/consumer.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/module.h> @@ -21,58 +21,109 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include "ad7606.h" -int ad7606_reset(struct ad7606_state *st) +static int ad7606_reset(struct ad7606_state *st) { - if (gpio_is_valid(st->pdata->gpio_reset)) { - gpio_set_value(st->pdata->gpio_reset, 1); + if (st->gpio_reset) { + gpiod_set_value(st->gpio_reset, 1); ndelay(100); /* t_reset >= 100ns */ - gpio_set_value(st->pdata->gpio_reset, 0); + gpiod_set_value(st->gpio_reset, 0); return 0; } return -ENODEV; } +static int ad7606_read_samples(struct ad7606_state *st) +{ + unsigned int num = st->chip_info->num_channels; + u16 *data = st->data; + int ret; + + /* + * The frstdata signal is set to high while and after reading the sample + * of the first channel and low for all other channels. This can be used + * to check that the incoming data is correctly aligned. During normal + * operation the data should never become unaligned, but some glitch or + * electrostatic discharge might cause an extra read or clock cycle. + * Monitoring the frstdata signal allows to recover from such failure + * situations. + */ + + if (st->gpio_frstdata) { + ret = st->bops->read_block(st->dev, 1, data); + if (ret) + return ret; + + if (!gpiod_get_value(st->gpio_frstdata)) { + ad7606_reset(st); + return -EIO; + } + + data++; + num--; + } + + return st->bops->read_block(st->dev, num, data); +} + +static irqreturn_t ad7606_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct ad7606_state *st = iio_priv(pf->indio_dev); + + gpiod_set_value(st->gpio_convst, 1); + + return IRQ_HANDLED; +} + +/** + * ad7606_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad7606_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad7606_state *st = container_of(work_s, struct ad7606_state, + poll_work); + struct iio_dev *indio_dev = iio_priv_to_dev(st); + int ret; + + ret = ad7606_read_samples(st); + if (ret == 0) + iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_get_time_ns(indio_dev)); + + gpiod_set_value(st->gpio_convst, 0); + iio_trigger_notify_done(indio_dev->trig); +} + static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch) { struct ad7606_state *st = iio_priv(indio_dev); int ret; st->done = false; - gpio_set_value(st->pdata->gpio_convst, 1); + gpiod_set_value(st->gpio_convst, 1); ret = wait_event_interruptible(st->wq_data_avail, st->done); if (ret) goto error_ret; - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = st->bops->read_block(st->dev, 1, st->data); - if (ret) - goto error_ret; - if (!gpio_get_value(st->pdata->gpio_frstdata)) { - /* This should never happen */ - ad7606_reset(st); - ret = -EIO; - goto error_ret; - } - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels - 1, &st->data[1]); - if (ret) - goto error_ret; - } else { - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels, st->data); - if (ret) - goto error_ret; - } - - ret = st->data[ch]; + ret = ad7606_read_samples(st); + if (ret == 0) + ret = st->data[ch]; error_ret: - gpio_set_value(st->pdata->gpio_convst, 0); + gpiod_set_value(st->gpio_convst, 0); return ret; } @@ -103,6 +154,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev, *val = st->range * 2; *val2 = st->chip_info->channels[0].scan_type.realbits; return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *val = st->oversampling; + return IIO_VAL_INT; } return -EINVAL; } @@ -129,12 +183,11 @@ static ssize_t ad7606_store_range(struct device *dev, if (ret) return ret; - if (!(lval == 5000 || lval == 10000)) { - dev_err(dev, "range is not supported\n"); + if (!(lval == 5000 || lval == 10000)) return -EINVAL; - } + mutex_lock(&indio_dev->mlock); - gpio_set_value(st->pdata->gpio_range, lval == 10000); + gpiod_set_value(st->gpio_range, lval == 10000); st->range = lval; mutex_unlock(&indio_dev->mlock); @@ -145,19 +198,9 @@ static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, ad7606_show_range, ad7606_store_range, 0); static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); -static ssize_t ad7606_show_oversampling_ratio(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7606_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%u\n", st->oversampling); -} - static int ad7606_oversampling_get_index(unsigned int val) { - unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64}; + unsigned char supported[] = {1, 2, 4, 8, 16, 32, 64}; int i; for (i = 0; i < ARRAY_SIZE(supported); i++) @@ -167,44 +210,45 @@ static int ad7606_oversampling_get_index(unsigned int val) return -EINVAL; } -static ssize_t ad7606_store_oversampling_ratio(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int ad7606_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 ad7606_state *st = iio_priv(indio_dev); - unsigned long lval; + int values[3]; int ret; - ret = kstrtoul(buf, 10, &lval); - if (ret) - return ret; + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + if (val2) + return -EINVAL; + ret = ad7606_oversampling_get_index(val); + if (ret < 0) + return ret; - ret = ad7606_oversampling_get_index(lval); - if (ret < 0) { - dev_err(dev, "oversampling %lu is not supported\n", lval); - return ret; - } + values[0] = (ret >> 0) & 1; + values[1] = (ret >> 1) & 1; + values[2] = (ret >> 2) & 1; - mutex_lock(&indio_dev->mlock); - gpio_set_value(st->pdata->gpio_os0, (ret >> 0) & 1); - gpio_set_value(st->pdata->gpio_os1, (ret >> 1) & 1); - gpio_set_value(st->pdata->gpio_os1, (ret >> 2) & 1); - st->oversampling = lval; - mutex_unlock(&indio_dev->mlock); + mutex_lock(&indio_dev->mlock); + gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, + values); + st->oversampling = val; + mutex_unlock(&indio_dev->mlock); - return count; + return 0; + default: + return -EINVAL; + } } -static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR, - ad7606_show_oversampling_ratio, - ad7606_store_oversampling_ratio, 0); -static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64"); +static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64"); static struct attribute *ad7606_attributes_os_and_range[] = { &iio_dev_attr_in_voltage_range.dev_attr.attr, &iio_const_attr_in_voltage_range_available.dev_attr.attr, - &iio_dev_attr_oversampling_ratio.dev_attr.attr, &iio_const_attr_oversampling_ratio_available.dev_attr.attr, NULL, }; @@ -214,7 +258,6 @@ static const struct attribute_group ad7606_attribute_group_os_and_range = { }; static struct attribute *ad7606_attributes_os[] = { - &iio_dev_attr_oversampling_ratio.dev_attr.attr, &iio_const_attr_oversampling_ratio_available.dev_attr.attr, NULL, }; @@ -241,6 +284,8 @@ static const struct attribute_group ad7606_attribute_group_range = { .address = num, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + .info_mask_shared_by_all = \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .scan_index = num, \ .scan_type = { \ .sign = 's', \ @@ -267,20 +312,14 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { * More devices added in future */ [ID_AD7606_8] = { - .name = "ad7606", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 9, }, [ID_AD7606_6] = { - .name = "ad7606-6", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 7, }, [ID_AD7606_4] = { - .name = "ad7606-4", - .int_vref_mv = 2500, .channels = ad7606_channels, .num_channels = 5, }, @@ -288,119 +327,34 @@ static const struct ad7606_chip_info ad7606_chip_info_tbl[] = { static int ad7606_request_gpios(struct ad7606_state *st) { - struct gpio gpio_array[3] = { - [0] = { - .gpio = st->pdata->gpio_os0, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 1) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS0", - }, - [1] = { - .gpio = st->pdata->gpio_os1, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 2) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS1", - }, - [2] = { - .gpio = st->pdata->gpio_os2, - .flags = GPIOF_DIR_OUT | ((st->oversampling & 4) ? - GPIOF_INIT_HIGH : GPIOF_INIT_LOW), - .label = "AD7606_OS2", - }, - }; - int ret; - - if (gpio_is_valid(st->pdata->gpio_convst)) { - ret = gpio_request_one(st->pdata->gpio_convst, - GPIOF_OUT_INIT_LOW, - "AD7606_CONVST"); - if (ret) { - dev_err(st->dev, "failed to request GPIO CONVST\n"); - goto error_ret; - } - } else { - ret = -EIO; - goto error_ret; - } - - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array)); - if (ret < 0) - goto error_free_convst; - } - - if (gpio_is_valid(st->pdata->gpio_reset)) { - ret = gpio_request_one(st->pdata->gpio_reset, - GPIOF_OUT_INIT_LOW, - "AD7606_RESET"); - if (ret < 0) - goto error_free_os; - } - - if (gpio_is_valid(st->pdata->gpio_range)) { - ret = gpio_request_one(st->pdata->gpio_range, GPIOF_DIR_OUT | - ((st->range == 10000) ? GPIOF_INIT_HIGH : - GPIOF_INIT_LOW), "AD7606_RANGE"); - if (ret < 0) - goto error_free_reset; - } - if (gpio_is_valid(st->pdata->gpio_stby)) { - ret = gpio_request_one(st->pdata->gpio_stby, - GPIOF_OUT_INIT_HIGH, - "AD7606_STBY"); - if (ret < 0) - goto error_free_range; - } - - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = gpio_request_one(st->pdata->gpio_frstdata, GPIOF_IN, - "AD7606_FRSTDATA"); - if (ret < 0) - goto error_free_stby; - } - - return 0; - -error_free_stby: - if (gpio_is_valid(st->pdata->gpio_stby)) - gpio_free(st->pdata->gpio_stby); -error_free_range: - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_free(st->pdata->gpio_range); -error_free_reset: - if (gpio_is_valid(st->pdata->gpio_reset)) - gpio_free(st->pdata->gpio_reset); -error_free_os: - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) - gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array)); -error_free_convst: - gpio_free(st->pdata->gpio_convst); -error_ret: - return ret; -} - -static void ad7606_free_gpios(struct ad7606_state *st) -{ - if (gpio_is_valid(st->pdata->gpio_frstdata)) - gpio_free(st->pdata->gpio_frstdata); - if (gpio_is_valid(st->pdata->gpio_stby)) - gpio_free(st->pdata->gpio_stby); - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_free(st->pdata->gpio_range); - if (gpio_is_valid(st->pdata->gpio_reset)) - gpio_free(st->pdata->gpio_reset); - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - gpio_free(st->pdata->gpio_os2); - gpio_free(st->pdata->gpio_os1); - gpio_free(st->pdata->gpio_os0); - } - gpio_free(st->pdata->gpio_convst); + struct device *dev = st->dev; + + st->gpio_convst = devm_gpiod_get(dev, "conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_convst)) + return PTR_ERR(st->gpio_convst); + + st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_reset)) + return PTR_ERR(st->gpio_reset); + + st->gpio_range = devm_gpiod_get_optional(dev, "range", GPIOD_OUT_LOW); + if (IS_ERR(st->gpio_range)) + return PTR_ERR(st->gpio_range); + + st->gpio_standby = devm_gpiod_get_optional(dev, "standby", + GPIOD_OUT_HIGH); + if (IS_ERR(st->gpio_standby)) + return PTR_ERR(st->gpio_standby); + + st->gpio_frstdata = devm_gpiod_get_optional(dev, "first-data", + GPIOD_IN); + if (IS_ERR(st->gpio_frstdata)) + return PTR_ERR(st->gpio_frstdata); + + st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio", + GPIOD_OUT_LOW); + return PTR_ERR_OR_ZERO(st->gpio_os); } /** @@ -429,12 +383,14 @@ static const struct iio_info ad7606_info_no_os_or_range = { static const struct iio_info ad7606_info_os_and_range = { .driver_module = THIS_MODULE, .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os_and_range, }; static const struct iio_info ad7606_info_os = { .driver_module = THIS_MODULE, .read_raw = &ad7606_read_raw, + .write_raw = &ad7606_write_raw, .attrs = &ad7606_attribute_group_os, }; @@ -444,81 +400,73 @@ static const struct iio_info ad7606_info_range = { .attrs = &ad7606_attribute_group_range, }; -struct iio_dev *ad7606_probe(struct device *dev, int irq, - void __iomem *base_address, - unsigned int id, - const struct ad7606_bus_ops *bops) +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops) { - struct ad7606_platform_data *pdata = dev->platform_data; struct ad7606_state *st; int ret; struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) - return ERR_PTR(-ENOMEM); + return -ENOMEM; st = iio_priv(indio_dev); st->dev = dev; st->bops = bops; st->base_address = base_address; - st->range = pdata->default_range == 10000 ? 10000 : 5000; + st->range = 5000; + st->oversampling = 1; + INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); - ret = ad7606_oversampling_get_index(pdata->default_os); - if (ret < 0) { - dev_warn(dev, "oversampling %d is not supported\n", - pdata->default_os); - st->oversampling = 0; - } else { - st->oversampling = pdata->default_os; - } + st->reg = devm_regulator_get(dev, "avcc"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); - st->reg = devm_regulator_get(dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - return ERR_PTR(ret); + ret = regulator_enable(st->reg); + if (ret) { + dev_err(dev, "Failed to enable specified AVcc supply\n"); + return ret; } - st->pdata = pdata; + ret = ad7606_request_gpios(st); + if (ret) + goto error_disable_reg; + st->chip_info = &ad7606_chip_info_tbl[id]; indio_dev->dev.parent = dev; - if (gpio_is_valid(st->pdata->gpio_os0) && - gpio_is_valid(st->pdata->gpio_os1) && - gpio_is_valid(st->pdata->gpio_os2)) { - if (gpio_is_valid(st->pdata->gpio_range)) + if (st->gpio_os) { + if (st->gpio_range) indio_dev->info = &ad7606_info_os_and_range; else indio_dev->info = &ad7606_info_os; } else { - if (gpio_is_valid(st->pdata->gpio_range)) + if (st->gpio_range) indio_dev->info = &ad7606_info_range; else indio_dev->info = &ad7606_info_no_os_or_range; } indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = st->chip_info->name; + indio_dev->name = name; indio_dev->channels = st->chip_info->channels; indio_dev->num_channels = st->chip_info->num_channels; init_waitqueue_head(&st->wq_data_avail); - ret = ad7606_request_gpios(st); - if (ret) - goto error_disable_reg; - ret = ad7606_reset(st); if (ret) dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n"); - ret = request_irq(irq, ad7606_interrupt, - IRQF_TRIGGER_FALLING, st->chip_info->name, indio_dev); + ret = request_irq(irq, ad7606_interrupt, IRQF_TRIGGER_FALLING, name, + indio_dev); if (ret) - goto error_free_gpios; + goto error_disable_reg; - ret = ad7606_register_ring_funcs_and_init(indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, &ad7606_trigger_handler, + NULL, NULL); if (ret) goto error_free_irq; @@ -526,35 +474,31 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq, if (ret) goto error_unregister_ring; - return indio_dev; + dev_set_drvdata(dev, indio_dev); + + return 0; error_unregister_ring: - ad7606_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); error_free_irq: free_irq(irq, indio_dev); -error_free_gpios: - ad7606_free_gpios(st); - error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - return ERR_PTR(ret); + regulator_disable(st->reg); + return ret; } EXPORT_SYMBOL_GPL(ad7606_probe); -int ad7606_remove(struct iio_dev *indio_dev, int irq) +int ad7606_remove(struct device *dev, int irq) { + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ad7606_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); free_irq(irq, indio_dev); - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); - - ad7606_free_gpios(st); + regulator_disable(st->reg); return 0; } @@ -567,10 +511,9 @@ static int ad7606_suspend(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); - if (gpio_is_valid(st->pdata->gpio_stby)) { - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_set_value(st->pdata->gpio_range, 1); - gpio_set_value(st->pdata->gpio_stby, 0); + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, 1); + gpiod_set_value(st->gpio_standby, 0); } return 0; @@ -581,12 +524,9 @@ static int ad7606_resume(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad7606_state *st = iio_priv(indio_dev); - if (gpio_is_valid(st->pdata->gpio_stby)) { - if (gpio_is_valid(st->pdata->gpio_range)) - gpio_set_value(st->pdata->gpio_range, - st->range == 10000); - - gpio_set_value(st->pdata->gpio_stby, 1); + if (st->gpio_standby) { + gpiod_set_value(st->gpio_range, st->range == 10000); + gpiod_set_value(st->gpio_standby, 1); ad7606_reset(st); } diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 39f50440d915..746f9553d2ba 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -9,48 +9,14 @@ #ifndef IIO_ADC_AD7606_H_ #define IIO_ADC_AD7606_H_ -/* - * TODO: struct ad7606_platform_data needs to go into include/linux/iio - */ - -/** - * struct ad7606_platform_data - platform/board specific information - * @default_os: default oversampling value {0, 2, 4, 8, 16, 32, 64} - * @default_range: default range +/-{5000, 10000} mVolt - * @gpio_convst: number of gpio connected to the CONVST pin - * @gpio_reset: gpio connected to the RESET pin, if not used set to -1 - * @gpio_range: gpio connected to the RANGE pin, if not used set to -1 - * @gpio_os0: gpio connected to the OS0 pin, if not used set to -1 - * @gpio_os1: gpio connected to the OS1 pin, if not used set to -1 - * @gpio_os2: gpio connected to the OS2 pin, if not used set to -1 - * @gpio_frstdata: gpio connected to the FRSTDAT pin, if not used set to -1 - * @gpio_stby: gpio connected to the STBY pin, if not used set to -1 - */ - -struct ad7606_platform_data { - unsigned int default_os; - unsigned int default_range; - unsigned int gpio_convst; - unsigned int gpio_reset; - unsigned int gpio_range; - unsigned int gpio_os0; - unsigned int gpio_os1; - unsigned int gpio_os2; - unsigned int gpio_frstdata; - unsigned int gpio_stby; -}; - /** * struct ad7606_chip_info - chip specific information * @name: identification string for chip - * @int_vref_mv: the internal reference voltage * @channels: channel specification * @num_channels: number of channels */ struct ad7606_chip_info { - const char *name; - u16 int_vref_mv; const struct iio_chan_spec *channels; unsigned int num_channels; }; @@ -62,7 +28,6 @@ struct ad7606_chip_info { struct ad7606_state { struct device *dev; const struct ad7606_chip_info *chip_info; - struct ad7606_platform_data *pdata; struct regulator *reg; struct work_struct poll_work; wait_queue_head_t wq_data_avail; @@ -72,12 +37,19 @@ struct ad7606_state { bool done; void __iomem *base_address; + struct gpio_desc *gpio_convst; + struct gpio_desc *gpio_reset; + struct gpio_desc *gpio_range; + struct gpio_desc *gpio_standby; + struct gpio_desc *gpio_frstdata; + struct gpio_descs *gpio_os; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. + * 8 * 16-bit samples + 64-bit timestamp */ - - unsigned short data[8] ____cacheline_aligned; + unsigned short data[12] ____cacheline_aligned; }; struct ad7606_bus_ops { @@ -85,11 +57,10 @@ struct ad7606_bus_ops { int (*read_block)(struct device *, int, void *); }; -struct iio_dev *ad7606_probe(struct device *dev, int irq, - void __iomem *base_address, unsigned int id, - const struct ad7606_bus_ops *bops); -int ad7606_remove(struct iio_dev *indio_dev, int irq); -int ad7606_reset(struct ad7606_state *st); +int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, + const char *name, unsigned int id, + const struct ad7606_bus_ops *bops); +int ad7606_remove(struct device *dev, int irq); enum ad7606_supported_device_ids { ID_AD7606_8, @@ -97,9 +68,6 @@ enum ad7606_supported_device_ids { ID_AD7606_4 }; -int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev); -void ad7606_ring_cleanup(struct iio_dev *indio_dev); - #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops ad7606_pm_ops; #define AD7606_PM_OPS (&ad7606_pm_ops) diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c index 84d23930fdde..cd6c410c0484 100644 --- a/drivers/staging/iio/adc/ad7606_par.c +++ b/drivers/staging/iio/adc/ad7606_par.c @@ -49,8 +49,8 @@ static const struct ad7606_bus_ops ad7606_par8_bops = { static int ad7606_par_probe(struct platform_device *pdev) { + const struct platform_device_id *id = platform_get_device_id(pdev); struct resource *res; - struct iio_dev *indio_dev; void __iomem *addr; resource_size_t remap_size; int irq; @@ -68,26 +68,15 @@ static int ad7606_par_probe(struct platform_device *pdev) remap_size = resource_size(res); - indio_dev = ad7606_probe(&pdev->dev, irq, addr, - platform_get_device_id(pdev)->driver_data, - remap_size > 1 ? &ad7606_par16_bops : - &ad7606_par8_bops); - - if (IS_ERR(indio_dev)) - return PTR_ERR(indio_dev); - - platform_set_drvdata(pdev, indio_dev); - - return 0; + return ad7606_probe(&pdev->dev, irq, addr, + id->name, id->driver_data, + remap_size > 1 ? &ad7606_par16_bops : + &ad7606_par8_bops); } static int ad7606_par_remove(struct platform_device *pdev) { - struct iio_dev *indio_dev = platform_get_drvdata(pdev); - - ad7606_remove(indio_dev, platform_get_irq(pdev, 0)); - - return 0; + return ad7606_remove(&pdev->dev, platform_get_irq(pdev, 0)); } static const struct platform_device_id ad7606_driver_ids[] = { diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c deleted file mode 100644 index 0572df9aad85..000000000000 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2011-2012 Analog Devices Inc. - * - * Licensed under the GPL-2. - * - */ - -#include <linux/interrupt.h> -#include <linux/gpio.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> - -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> - -#include "ad7606.h" - -/** - * ad7606_trigger_handler_th() th/bh of trigger launched polling to ring buffer - * - **/ -static irqreturn_t ad7606_trigger_handler_th_bh(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct ad7606_state *st = iio_priv(pf->indio_dev); - - gpio_set_value(st->pdata->gpio_convst, 1); - - return IRQ_HANDLED; -} - -/** - * ad7606_poll_bh_to_ring() bh of trigger launched polling to ring buffer - * @work_s: the work struct through which this was scheduled - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - * I think the one copy of this at a time was to avoid problems if the - * trigger was set far too high and the reads then locked up the computer. - **/ -static void ad7606_poll_bh_to_ring(struct work_struct *work_s) -{ - struct ad7606_state *st = container_of(work_s, struct ad7606_state, - poll_work); - struct iio_dev *indio_dev = iio_priv_to_dev(st); - __u8 *buf; - int ret; - - buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (!buf) - return; - - if (gpio_is_valid(st->pdata->gpio_frstdata)) { - ret = st->bops->read_block(st->dev, 1, buf); - if (ret) - goto done; - if (!gpio_get_value(st->pdata->gpio_frstdata)) { - /* This should never happen. However - * some signal glitch caused by bad PCB desgin or - * electrostatic discharge, could cause an extra read - * or clock. This allows recovery. - */ - ad7606_reset(st); - goto done; - } - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels - 1, buf + 2); - if (ret) - goto done; - } else { - ret = st->bops->read_block(st->dev, - st->chip_info->num_channels, buf); - if (ret) - goto done; - } - - iio_push_to_buffers_with_timestamp(indio_dev, buf, - iio_get_time_ns(indio_dev)); -done: - gpio_set_value(st->pdata->gpio_convst, 0); - iio_trigger_notify_done(indio_dev->trig); - kfree(buf); -} - -int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - struct ad7606_state *st = iio_priv(indio_dev); - - INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring); - - return iio_triggered_buffer_setup(indio_dev, - &ad7606_trigger_handler_th_bh, &ad7606_trigger_handler_th_bh, - NULL); -} - -void ad7606_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c index 9587fa86dc69..c9b1f26685f4 100644 --- a/drivers/staging/iio/adc/ad7606_spi.c +++ b/drivers/staging/iio/adc/ad7606_spi.c @@ -42,25 +42,16 @@ static const struct ad7606_bus_ops ad7606_spi_bops = { static int ad7606_spi_probe(struct spi_device *spi) { - struct iio_dev *indio_dev; + const struct spi_device_id *id = spi_get_device_id(spi); - indio_dev = ad7606_probe(&spi->dev, spi->irq, NULL, - spi_get_device_id(spi)->driver_data, - &ad7606_spi_bops); - - if (IS_ERR(indio_dev)) - return PTR_ERR(indio_dev); - - spi_set_drvdata(spi, indio_dev); - - return 0; + return ad7606_probe(&spi->dev, spi->irq, NULL, + id->name, id->driver_data, + &ad7606_spi_bops); } static int ad7606_spi_remove(struct spi_device *spi) { - struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev); - - return ad7606_remove(indio_dev, spi->irq); + return ad7606_remove(&spi->dev, spi->irq); } static const struct spi_device_id ad7606_id[] = { diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c index 5e8115b01011..72551f827382 100644 --- a/drivers/staging/iio/adc/ad7816.c +++ b/drivers/staging/iio/adc/ad7816.c @@ -327,7 +327,7 @@ static struct attribute *ad7816_event_attributes[] = { NULL, }; -static struct attribute_group ad7816_event_attribute_group = { +static const struct attribute_group ad7816_event_attribute_group = { .attrs = ad7816_event_attributes, .name = "events", }; diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 3faffe59c933..a7d90c8bac5e 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -2039,7 +2039,7 @@ static struct attribute *adt7316_event_attributes[] = { NULL, }; -static struct attribute_group adt7316_event_attribute_group = { +static const struct attribute_group adt7316_event_attribute_group = { .attrs = adt7316_event_attributes, .name = "events", }; @@ -2060,7 +2060,7 @@ static struct attribute *adt7516_event_attributes[] = { NULL, }; -static struct attribute_group adt7516_event_attribute_group = { +static const struct attribute_group adt7516_event_attribute_group = { .attrs = adt7516_event_attributes, .name = "events", }; diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 5578a077fcfb..6998c3ddfb6a 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -562,7 +562,7 @@ static struct attribute *ad7150_event_attributes[] = { NULL, }; -static struct attribute_group ad7150_event_attribute_group = { +static const struct attribute_group ad7150_event_attribute_group = { .attrs = ad7150_event_attributes, .name = "events", }; diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c index 485d0a5af53c..b91b50f345bd 100644 --- a/drivers/staging/iio/cdc/ad7152.c +++ b/drivers/staging/iio/cdc/ad7152.c @@ -89,6 +89,7 @@ struct ad7152_chip_info { */ u8 filter_rate_setup; u8 setup[2]; + struct mutex state_lock; /* protect hardware state */ }; static inline ssize_t ad7152_start_calib(struct device *dev, @@ -115,10 +116,10 @@ static inline ssize_t ad7152_start_calib(struct device *dev, else regval |= AD7152_CONF_CH2EN; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG, regval); if (ret < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -126,14 +127,15 @@ static inline ssize_t ad7152_start_calib(struct device *dev, mdelay(20); ret = i2c_smbus_read_byte_data(chip->client, AD7152_REG_CFG); if (ret < 0) { - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } } while ((ret == regval) && timeout--); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return len; } + static ssize_t ad7152_start_offset_calib(struct device *dev, struct device_attribute *attr, const char *buf, @@ -142,6 +144,7 @@ static ssize_t ad7152_start_offset_calib(struct device *dev, return ad7152_start_calib(dev, attr, buf, len, AD7152_CONF_MODE_OFFS_CAL); } + static ssize_t ad7152_start_gain_calib(struct device *dev, struct device_attribute *attr, const char *buf, @@ -165,63 +168,12 @@ static const unsigned char ad7152_filter_rate_table[][2] = { {200, 5 + 1}, {50, 20 + 1}, {20, 50 + 1}, {17, 60 + 1}, }; -static ssize_t ad7152_show_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7152_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", - ad7152_filter_rate_table[chip->filter_rate_setup][0]); -} - -static ssize_t ad7152_store_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7152_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; - - for (i = 0; i < ARRAY_SIZE(ad7152_filter_rate_table); i++) - if (data >= ad7152_filter_rate_table[i][0]) - break; - - if (i >= ARRAY_SIZE(ad7152_filter_rate_table)) - i = ARRAY_SIZE(ad7152_filter_rate_table) - 1; - - mutex_lock(&indio_dev->mlock); - ret = i2c_smbus_write_byte_data(chip->client, - AD7152_REG_CFG2, AD7152_CFG2_OSR(i)); - if (ret < 0) { - mutex_unlock(&indio_dev->mlock); - return ret; - } - - chip->filter_rate_setup = i; - mutex_unlock(&indio_dev->mlock); - - return len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, - ad7152_show_filter_rate_setup, - ad7152_store_filter_rate_setup); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("200 50 20 17"); static IIO_CONST_ATTR(in_capacitance_scale_available, "0.000061050 0.000030525 0.000015263 0.000007631"); static struct attribute *ad7152_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance1_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr, @@ -247,6 +199,51 @@ static const int ad7152_scale_table[] = { 30525, 7631, 15263, 61050 }; +/** + * read_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int ad7152_read_raw_samp_freq(struct device *dev, int *val) +{ + struct ad7152_chip_info *chip = iio_priv(dev_to_iio_dev(dev)); + + *val = ad7152_filter_rate_table[chip->filter_rate_setup][0]; + + return 0; +} + +/** + * write_raw handler for IIO_CHAN_INFO_SAMP_FREQ + * + * lock must be held + **/ +static int ad7152_write_raw_samp_freq(struct device *dev, int val) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7152_chip_info *chip = iio_priv(indio_dev); + int ret, i; + + for (i = 0; i < ARRAY_SIZE(ad7152_filter_rate_table); i++) + if (val >= ad7152_filter_rate_table[i][0]) + break; + + if (i >= ARRAY_SIZE(ad7152_filter_rate_table)) + i = ARRAY_SIZE(ad7152_filter_rate_table) - 1; + + mutex_lock(&chip->state_lock); + ret = i2c_smbus_write_byte_data(chip->client, + AD7152_REG_CFG2, AD7152_CFG2_OSR(i)); + if (ret < 0) { + mutex_unlock(&chip->state_lock); + return ret; + } + + chip->filter_rate_setup = i; + mutex_unlock(&chip->state_lock); + + return ret; +} static int ad7152_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, @@ -256,7 +253,7 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, struct ad7152_chip_info *chip = iio_priv(indio_dev); int ret, i; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); switch (mask) { case IIO_CHAN_INFO_CALIBSCALE: @@ -309,14 +306,26 @@ static int ad7152_write_raw(struct iio_dev *indio_dev, ret = 0; break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) { + ret = -EINVAL; + goto out; + } + ret = ad7152_write_raw_samp_freq(&indio_dev->dev, val); + if (ret < 0) + goto out; + + ret = 0; + break; default: ret = -EINVAL; } out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } + static int ad7152_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, @@ -326,7 +335,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, int ret; u8 regval = 0; - mutex_lock(&indio_dev->mlock); + mutex_lock(&chip->state_lock); switch (mask) { case IIO_CHAN_INFO_RAW: @@ -403,11 +412,18 @@ static int ad7152_read_raw(struct iio_dev *indio_dev, ret = IIO_VAL_INT_PLUS_NANO; break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = ad7152_read_raw_samp_freq(&indio_dev->dev, val); + if (ret < 0) + goto out; + + ret = IIO_VAL_INT; + break; default: ret = -EINVAL; } out: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&chip->state_lock); return ret; } @@ -440,6 +456,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .differential = 1, @@ -450,6 +467,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .indexed = 1, @@ -458,6 +476,7 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_CAPACITANCE, .differential = 1, @@ -468,8 +487,10 @@ static const struct iio_chan_spec ad7152_channels[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } }; + /* * device probe and remove */ @@ -489,6 +510,7 @@ static int ad7152_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); chip->client = client; + mutex_init(&chip->state_lock); /* Establish that the iio_dev is a child of the i2c device */ indio_dev->name = id->name; diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c index 5771d4ee8ef1..f41251ceeacd 100644 --- a/drivers/staging/iio/cdc/ad7746.c +++ b/drivers/staging/iio/cdc/ad7746.c @@ -122,7 +122,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .indexed = 1, .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_EXT_VIN, }, @@ -132,7 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = { .channel = 1, .extend_name = "supply", .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_VT_DATA_HIGH << 8 | AD7746_VTSETUP_VTMD_VDD_MON, }, @@ -159,7 +161,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8, }, [CIN1_DIFF] = { @@ -171,7 +173,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF }, @@ -182,7 +184,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CIN2, }, @@ -195,7 +197,7 @@ static const struct iio_chan_spec ad7746_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_CALIBSCALE) | BIT(IIO_CHAN_INFO_OFFSET), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBBIAS) | - BIT(IIO_CHAN_INFO_SCALE), + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7746_REG_CAP_DATA_HIGH << 8 | AD7746_CAPSETUP_CAPDIFF | AD7746_CAPSETUP_CIN2, } @@ -355,101 +357,47 @@ static IIO_DEVICE_ATTR(in_capacitance1_calibscale_calibration, static IIO_DEVICE_ATTR(in_voltage0_calibscale_calibration, S_IWUSR, NULL, ad7746_start_gain_calib, VIN); -static ssize_t ad7746_show_cap_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad7746_store_cap_filter_rate_setup(struct ad7746_chip_info *chip, + int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[ - (chip->config >> 3) & 0x7][0]); -} - -static ssize_t ad7746_store_cap_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; + int i; for (i = 0; i < ARRAY_SIZE(ad7746_cap_filter_rate_table); i++) - if (data >= ad7746_cap_filter_rate_table[i][0]) + if (val >= ad7746_cap_filter_rate_table[i][0]) break; if (i >= ARRAY_SIZE(ad7746_cap_filter_rate_table)) i = ARRAY_SIZE(ad7746_cap_filter_rate_table) - 1; - mutex_lock(&indio_dev->mlock); chip->config &= ~AD7746_CONF_CAPFS(0x7); chip->config |= AD7746_CONF_CAPFS(i); - mutex_unlock(&indio_dev->mlock); - return len; + return 0; } -static ssize_t ad7746_show_vt_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - char *buf) +static int ad7746_store_vt_filter_rate_setup(struct ad7746_chip_info *chip, + int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[ - (chip->config >> 6) & 0x3][0]); -} - -static ssize_t ad7746_store_vt_filter_rate_setup(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7746_chip_info *chip = iio_priv(indio_dev); - u8 data; - int ret, i; - - ret = kstrtou8(buf, 10, &data); - if (ret < 0) - return ret; + int i; for (i = 0; i < ARRAY_SIZE(ad7746_vt_filter_rate_table); i++) - if (data >= ad7746_vt_filter_rate_table[i][0]) + if (val >= ad7746_vt_filter_rate_table[i][0]) break; if (i >= ARRAY_SIZE(ad7746_vt_filter_rate_table)) i = ARRAY_SIZE(ad7746_vt_filter_rate_table) - 1; - mutex_lock(&indio_dev->mlock); chip->config &= ~AD7746_CONF_VTFS(0x3); chip->config |= AD7746_CONF_VTFS(i); - mutex_unlock(&indio_dev->mlock); - return len; + return 0; } -static IIO_DEVICE_ATTR(in_capacitance_sampling_frequency, - S_IRUGO | S_IWUSR, ad7746_show_cap_filter_rate_setup, - ad7746_store_cap_filter_rate_setup, 0); - -static IIO_DEVICE_ATTR(in_voltage_sampling_frequency, - S_IRUGO | S_IWUSR, ad7746_show_vt_filter_rate_setup, - ad7746_store_vt_filter_rate_setup, 0); - static IIO_CONST_ATTR(in_voltage_sampling_frequency_available, "50 31 16 8"); static IIO_CONST_ATTR(in_capacitance_sampling_frequency_available, "91 84 50 26 16 13 11 9"); static struct attribute *ad7746_attributes[] = { - &iio_dev_attr_in_capacitance_sampling_frequency.dev_attr.attr, - &iio_dev_attr_in_voltage_sampling_frequency.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibbias_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance0_calibscale_calibration.dev_attr.attr, &iio_dev_attr_in_capacitance1_calibscale_calibration.dev_attr.attr, @@ -547,6 +495,23 @@ static int ad7746_write_raw(struct iio_dev *indio_dev, ret = 0; break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) { + ret = -EINVAL; + goto out; + } + + switch (chan->type) { + case IIO_CAPACITANCE: + ret = ad7746_store_cap_filter_rate_setup(chip, val); + break; + case IIO_VOLTAGE: + ret = ad7746_store_vt_filter_rate_setup(chip, val); + break; + default: + ret = -EINVAL; + } + break; default: ret = -EINVAL; } @@ -667,6 +632,21 @@ static int ad7746_read_raw(struct iio_dev *indio_dev, } break; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_CAPACITANCE: + *val = ad7746_cap_filter_rate_table[ + (chip->config >> 3) & 0x7][0]; + ret = IIO_VAL_INT; + break; + case IIO_VOLTAGE: + *val = ad7746_vt_filter_rate_table[ + (chip->config >> 6) & 0x3][0]; + break; + default: + ret = -EINVAL; + } + break; default: ret = -EINVAL; } diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index ca8d6e66c899..dbf22d396ddf 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -3,18 +3,6 @@ # menu "Light sensors" -config SENSORS_ISL29018 - tristate "ISL 29018 light and proximity sensor" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for ambient light sensing and - proximity infrared sensing from Intersil ISL29018. - This driver will provide the measurements of ambient light intensity - in lux, proximity infrared sensing and normal infrared sensing. - Data from sensor is accessible via sysfs. - config SENSORS_ISL29028 tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" depends on I2C diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 9960fdf7c15b..6480856e1682 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,7 +2,6 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_TSL2583) += tsl2583.o obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index ebb8a1993303..3af8f77b8e41 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -465,38 +465,26 @@ err_ret: return ret; } -static ssize_t ade7758_read_frequency(struct device *dev, - struct device_attribute *attr, char *buf) +static int ade7758_read_samp_freq(struct device *dev, int *val) { int ret; u8 t; - int sps; ret = ade7758_spi_read_reg_8(dev, ADE7758_WAVMODE, &t); if (ret) return ret; t = (t >> 5) & 0x3; - sps = 26040 / (1 << t); + *val = 26040 / (1 << t); - return sprintf(buf, "%d SPS\n", sps); + return 0; } -static ssize_t ade7758_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static int ade7758_write_samp_freq(struct device *dev, int val) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - u16 val; int ret; u8 reg, t; - ret = kstrtou16(buf, 10, &val); - if (ret) - return ret; - - mutex_lock(&indio_dev->mlock); - switch (val) { case 26040: t = 0; @@ -525,9 +513,49 @@ static ssize_t ade7758_write_frequency(struct device *dev, ret = ade7758_spi_write_reg_8(dev, ADE7758_WAVMODE, reg); out: - mutex_unlock(&indio_dev->mlock); + return ret; +} - return ret ? ret : len; +static int ade7758_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&indio_dev->mlock); + ret = ade7758_read_samp_freq(&indio_dev->dev, val); + mutex_unlock(&indio_dev->mlock); + return ret; + default: + return -EINVAL; + } + + return ret; +} + +static int ade7758_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (val2) + return -EINVAL; + mutex_lock(&indio_dev->mlock); + ret = ade7758_write_samp_freq(&indio_dev->dev, val); + mutex_unlock(&indio_dev->mlock); + return ret; + default: + return -EINVAL; + } + + return ret; } static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit); @@ -553,17 +581,12 @@ static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit, static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit, ADE7758_CVAHR); -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ade7758_read_frequency, - ade7758_write_frequency); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26040 13020 6510 3255"); static struct attribute *ade7758_attributes[] = { &iio_dev_attr_in_temp_raw.dev_attr.attr, &iio_const_attr_in_temp_offset.dev_attr.attr, &iio_const_attr_in_temp_scale.dev_attr.attr, - &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_awatthr.dev_attr.attr, &iio_dev_attr_bwatthr.dev_attr.attr, @@ -611,6 +634,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 0, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE), .scan_index = 0, .scan_type = { @@ -622,6 +646,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 0, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT), .scan_index = 1, .scan_type = { @@ -634,6 +659,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR), .scan_index = 2, .scan_type = { @@ -646,6 +672,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR), .scan_index = 3, .scan_type = { @@ -658,6 +685,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 0, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR), .scan_index = 4, .scan_type = { @@ -669,6 +697,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE), .scan_index = 5, .scan_type = { @@ -680,6 +709,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 1, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT), .scan_index = 6, .scan_type = { @@ -692,6 +722,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR), .scan_index = 7, .scan_type = { @@ -704,6 +735,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR), .scan_index = 8, .scan_type = { @@ -716,6 +748,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 1, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR), .scan_index = 9, .scan_type = { @@ -727,6 +760,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_VOLTAGE, .indexed = 1, .channel = 2, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE), .scan_index = 10, .scan_type = { @@ -738,6 +772,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .type = IIO_CURRENT, .indexed = 1, .channel = 2, + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT), .scan_index = 11, .scan_type = { @@ -750,6 +785,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "apparent", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR), .scan_index = 12, .scan_type = { @@ -762,6 +798,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "active", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR), .scan_index = 13, .scan_type = { @@ -774,6 +811,7 @@ static const struct iio_chan_spec ade7758_channels[] = { .indexed = 1, .channel = 2, .extend_name = "reactive", + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR), .scan_index = 14, .scan_type = { @@ -787,6 +825,8 @@ static const struct iio_chan_spec ade7758_channels[] = { static const struct iio_info ade7758_info = { .attrs = &ade7758_attribute_group, + .read_raw = &ade7758_read_raw, + .write_raw = &ade7758_write_raw, .driver_module = THIS_MODULE, }; diff --git a/drivers/staging/iio/ring_hw.h b/drivers/staging/iio/ring_hw.h deleted file mode 100644 index 75bf47bfee78..000000000000 --- a/drivers/staging/iio/ring_hw.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ring_hw.h - common functionality for iio hardware ring buffers - * - * 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. - * - * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> - * - */ - -#ifndef _RING_HW_H_ -#define _RING_HW_H_ - -/** - * struct iio_hw_ring_buffer- hardware ring buffer - * @buf: generic ring buffer elements - * @private: device specific data - */ -struct iio_hw_buffer { - struct iio_buffer buf; - void *private; -}; - -#define iio_to_hw_buf(r) container_of(r, struct iio_hw_buffer, buf) - -#endif /* _RING_HW_H_ */ diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index e7fdec4db9da..5ba430cc9a87 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -136,6 +136,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), \ .scan_index = (_si), \ .scan_type = { \ .sign = 'u', \ diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 9edccfba1ffb..638157234357 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -236,6 +236,19 @@ int iio_get_channel_type(struct iio_channel *channel, enum iio_chan_type *type); /** + * iio_read_channel_offset() - read the offset value for a channel + * @chan: The channel being queried. + * @val: First part of value read back. + * @val2: Second part of value read back. + * + * Note returns a description of what is in val and val2, such + * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val + * + val2/1e6 + */ +int iio_read_channel_offset(struct iio_channel *chan, int *val, + int *val2); + +/** * iio_read_channel_scale() - read the scale value for a channel * @chan: The channel being queried. * @val: First part of value read back. diff --git a/include/linux/iio/dac/mcp4725.h b/include/linux/iio/dac/mcp4725.h index 91530e6611e9..628b2cf54c50 100644 --- a/include/linux/iio/dac/mcp4725.h +++ b/include/linux/iio/dac/mcp4725.h @@ -9,8 +9,18 @@ #ifndef IIO_DAC_MCP4725_H_ #define IIO_DAC_MCP4725_H_ +/** + * struct mcp4725_platform_data - MCP4725/6 DAC specific data. + * @use_vref: Whether an external reference voltage on Vref pin should be used. + * Additional vref-supply must be specified when used. + * @vref_buffered: Controls buffering of the external reference voltage. + * + * Vref related settings are available only on MCP4756. See + * Documentation/devicetree/bindings/iio/dac/mcp4725.txt for more information. + */ struct mcp4725_platform_data { - u16 vref_mv; + bool use_vref; + bool vref_buffered; }; #endif /* IIO_DAC_MCP4725_H_ */ diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index b4a0679e4a49..4591d8ea41bd 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -381,7 +381,7 @@ struct iio_dev; **/ struct iio_info { struct module *driver_module; - struct attribute_group *event_attrs; + const struct attribute_group *event_attrs; const struct attribute_group *attrs; int (*read_raw)(struct iio_dev *indio_dev, diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h index 9cd8f747212f..ce9426c507fd 100644 --- a/include/linux/iio/sysfs.h +++ b/include/linux/iio/sysfs.h @@ -55,10 +55,34 @@ struct iio_const_attr { { .dev_attr = __ATTR(_name, _mode, _show, _store), \ .address = _addr } +#define IIO_ATTR_RO(_name, _addr) \ + { .dev_attr = __ATTR_RO(_name), \ + .address = _addr } + +#define IIO_ATTR_WO(_name, _addr) \ + { .dev_attr = __ATTR_WO(_name), \ + .address = _addr } + +#define IIO_ATTR_RW(_name, _addr) \ + { .dev_attr = __ATTR_RW(_name), \ + .address = _addr } + #define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr) \ struct iio_dev_attr iio_dev_attr_##_name \ = IIO_ATTR(_name, _mode, _show, _store, _addr) +#define IIO_DEVICE_ATTR_RO(_name, _addr) \ + struct iio_dev_attr iio_dev_attr_##_name \ + = IIO_ATTR_RO(_name, _addr) + +#define IIO_DEVICE_ATTR_WO(_name, _addr) \ + struct iio_dev_attr iio_dev_attr_##_name \ + = IIO_ATTR_WO(_name, _addr) + +#define IIO_DEVICE_ATTR_RW(_name, _addr) \ + struct iio_dev_attr iio_dev_attr_##_name \ + = IIO_ATTR_RW(_name, _addr) + #define IIO_DEVICE_ATTR_NAMED(_vname, _name, _mode, _show, _store, _addr) \ struct iio_dev_attr iio_dev_attr_##_vname \ = IIO_ATTR(_name, _mode, _show, _store, _addr) diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 4f1154f7a33c..ea08302f2d7b 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -170,6 +170,8 @@ void iio_trigger_free(struct iio_trigger *trig); */ bool iio_trigger_using_own(struct iio_dev *indio_dev); +int iio_trigger_validate_own_device(struct iio_trigger *trig, + struct iio_dev *indio_dev); #else struct iio_trigger; diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 22e5e589a274..e54d14a7f876 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -40,6 +40,8 @@ enum iio_chan_type { IIO_PH, IIO_UVINDEX, IIO_ELECTRICALCONDUCTIVITY, + IIO_COUNT, + IIO_INDEX, }; enum iio_modifier { diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index f39c0e9c0d5c..f0c6f54a8b2f 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -247,6 +247,7 @@ void print_usage(void) fprintf(stderr, "Usage: generic_buffer [options]...\n" "Capture, convert and output data from IIO device buffer\n" " -a Auto-activate all available channels\n" + " -A Force-activate ALL channels\n" " -c <n> Do n conversions\n" " -e Disable wait for event (new data)\n" " -g Use trigger-less mode\n" @@ -347,16 +348,22 @@ int main(int argc, char **argv) int noevents = 0; int notrigger = 0; char *dummy; + bool force_autochannels = false; struct iio_channel_info *channels = NULL; register_cleanup(); - while ((c = getopt_long(argc, argv, "ac:egl:n:N:t:T:w:", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, + NULL)) != -1) { switch (c) { case 'a': autochannels = AUTOCHANNELS_ENABLED; break; + case 'A': + autochannels = AUTOCHANNELS_ENABLED; + force_autochannels = true; + break; case 'c': errno = 0; num_loops = strtoul(optarg, &dummy, 10); @@ -519,15 +526,16 @@ int main(int argc, char **argv) "diag %s\n", dev_dir_name); goto error; } - if (num_channels && autochannels == AUTOCHANNELS_ENABLED) { + if (num_channels && autochannels == AUTOCHANNELS_ENABLED && + !force_autochannels) { fprintf(stderr, "Auto-channels selected but some channels " "are already activated in sysfs\n"); fprintf(stderr, "Proceeding without activating any channels\n"); } - if (!num_channels && autochannels == AUTOCHANNELS_ENABLED) { - fprintf(stderr, - "No channels are enabled, enabling all channels\n"); + if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || + (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { + fprintf(stderr, "Enabling all channels\n"); ret = enable_disable_all_channels(dev_dir_name, 1); if (ret) { |