Commit 6a8b25ab authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.18a' of...

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

Jonathan writes:

1st round of IIO new device support, features and cleanup for the 4.18 cycle

A nice mix this time of excellent cleanups (many to send drivers
speeding toward staging graduations) and new drivers / device support.
A good part of this is Brian Masney's never ending task on the tsl2x7x
driver.  The end is in sight so hopefully we'll get that one out of
staging very soon!

New device support
* AD5686
  - Support AD5685R (was wrongly present as AD5685)
  - Support AD5672R, AD5676, AD5676, AD5684R and AD5686R 4 and 8 channel
    SPI DACs with various precisions.
  - Support AD5671R, AD5675R, AD5694, AD5694R, AD5695R, AD5696 and AD5696R
    I2C DACs with various percisions and numbers of channels.
* Analog front end rescale driver - New driver.
  - Support current sensing usings a shunt resistor.
  - Support simple voltage dividers.
  - support simple current sense amplifiers.
* TI dac5571
  - New driver and device bindings supporting:
    dac5571, dac6571, dac7571, dac5574, dac6574, dac7574,
    dac5573, dac6573 and dac7573
* Meson-adc
  - Support for Meson AXG with DT bindings.
* mpu6050
  - Support the mpu9255 which only requires additional WHOAMI entry and
    compatible string.
* st_lsm6dsx
  - Support for lsm330dlc combinded accelerometer and gyro sensors with
    DT bindings.
* stm32_adc
  - Add support for STM32MP1 with bindings.

Staging graduations
* adis16201 after some excelent cleanup by Himanshu Jha.
* adis16029 after some excelent cleanup by Shreeya Patel.

New features:
* ABI docs
  - Add core ABI docs for angle channels.
* inv_mpu6050
  - Provide support for the full range of interrupts the device
    supports.
* st_accel
  - Add SMO8840 ACPI ID seen in the wild on some Lenovo machines.
* stx104
  - Provide a multiple gpio get function.

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