First round of IIO new device support, features and cleanups for the 4.7 cycle.
New core support * UV light modifier (for intensity) * UV light index channel type. New device support * hp206c barometer and altimeter - new driver. * mcp4131 potentiometer - new driver supporting lots of parts from Microchip. * mma8452 - FXLS8471Q support - NXP LPC18XX SOC ADC - new driver. - NXP LPC18XX SOC DAC - new driver. - rockchip_saradc - support rk3399 * st accel - h3lis331dl support Staging driver removals * adis16204 - obsolete part making it hard to get parts to test the driver in order to clean it up. * adis16220 - obsolete part making it hard to get the parts test the driver in order to clean it up. Features * core - convenience functions to claim / release direct access to the device. Makes more consistent handling of this corner easier. Used in ad7192 driver. * ak8975 - power regulator support. * at91-sama5d2 - differential channel support. * mma8452 - runtime pm support - drop device specific autosleep and use the runtime pm one instead. * ms5611 - DT bindings - oversampling ratio support Cleanups and minor fixes * MAINTAINERS - Peter got married - hence name change! * Documentation - Fix a typo in in_proximity_raw description. - Add some missing docs for iio_buffer_access_funcs. * Tools - update iio_event_monitor names to match new stuff. - make generic_buffer look for triggers ending in -trigger as we let these in for a number of drivers a long time back and now it is a fairly common option. Drivers * staging wide - convert bare unsigned usage to unsigned int to comply with coding style. * non staging wide: - since boiler plate gpio handling of interrupts has been moved into the ACPI core we don't need to include gpio/consumer.h in a load of drivers so drop it. * ad7606 - fix an endian casting sparse warning. * ak8975 - fix a possible unitialized warning from gcc. - drop and unused field left over from earlier cleanups - fix a missing regulator_disable on exit. * at91-sama5d2 - typo and indentation - missing IOMEM dependency. - cleanup mode register usage by avoidling erasing whole thing when changing the sampling frequency. * bmc150 - use the core demux and available_scan_masks to simplify buffer handling - optimize the transfers in the trigger handler now we have a magic function to emulate bulk reads (under circumstances met here). This matters with some rather dumb i2c adapters in particular. - use a single regmap_conf for all bus types as they were all the same. * bmg160 - use the core demux and available_scan_masks to simplify the buffer handling - optimize the transfers in the trigger handler now we have a magic funciton to emulate bulk rads (under circumstances met here). - drop gpio interrupt probing from the driver (ACPI) as now handled by the ACPI core. * ina2xx-adc - update the CALIB register when RShunt changes. - fix scale for VShunt - in reality this error canceled out when used. * isl29028 - use regmap to retrieve the struct device instead of carrying a second copy of it around. * kxcjk-1013 - use core demux - optimize i2c transfers in the trigger handler. * mcp4531 - refactor to use a pointer to access model parameters instead of indexing into the array each time. * mma8452 - style fixes - avoid swtiching to active whenever the config changes - add missin i2c_device_id for mma8451 * mpu6050 - fix possible NULL dereference. - fix the name / chip_id used when ACPI used (otherwise reports as NULL). * ms5611 - fix a missing regulator_disable that left the regulator on during removal. * mxc4005 - drop gpio interrupt handling for ACPI case from driver as the core now handles this case. * st-sensors - note that there are only ever a maximum of 3 axis on current st-sensors so just allocate a fixed sized buffer big enough for that. * tpl0102 - change the i2c_check_functionality condition to bring it inline with other IIO users as EOPNOTSUPP. * tsl2563 - replace deprecated flush_scheduled_work -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJXAYogAAoJEFSFNJnE9BaIhtsQAK9hsojCFC4EmcE0LdlC7A6r h/Any+ehurHSQIZmAZ1mn8QDBedf6Afpj+jl/qt/DADQk3e3u+TO1TbVHHUDB8Na ynvt1eibnUPAKxjbetUnPfOTaksp2GN8oScjPqk/3xmP1ip/uP3l2DM+jBOspW2K 44UDpKE/aeulyCeG8wBHLY0ySuipQ8ZJyebETM3E94UrNdMHiuMyRA+SEbhcG+0T GyHYrlmPScFlk3xlhuYk7kS6gJQG0xg6u/qyuaBlQMKY1KXMGknU8sxSmqxRmCNn pJ3MeHZY6hFe3PNTgd30z+xbXN4JAifyUBHT2foRF86+f0BJSNIZJo/ynfCPli4z Rl+4M9NziYxw4V6osjKtPBquvk8UV6G/1tcgrr5pNFJor4dk6xRg/xCotYsqZuMX ypWOMuvkPQq+mqf68uJYlE++/A3xHP7aHdOlsXMgM8605KH1aSecbUP2dhRbHdRs u8XTt8Xj6uumQnxUnKjDZGIsDaxyw5JwarjhiNdJaCRgAgFw2qmNiFWYNkBaxxOt BheQBceoHLHDk/qTDsi0b5KDLqvArrbY8L6WBR+gW21isFpho5VDMgBSfNfdObGB nYaYTBcdx6sXm1SC1bMwVcgMnd3Bs4eWJRw79VFz/pFtTOc5Xpj4uVvnNCzuomqb MygKzQb48Gx23saBy4Za =SgQo -----END PGP SIGNATURE----- Merge tag 'iio-for-4.7a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: First round of IIO new device support, features and cleanups for the 4.7 cycle. New core support * UV light modifier (for intensity) * UV light index channel type. New device support * hp206c barometer and altimeter - new driver. * mcp4131 potentiometer - new driver supporting lots of parts from Microchip. * mma8452 - FXLS8471Q support - NXP LPC18XX SOC ADC - new driver. - NXP LPC18XX SOC DAC - new driver. - rockchip_saradc - support rk3399 * st accel - h3lis331dl support Staging driver removals * adis16204 - obsolete part making it hard to get parts to test the driver in order to clean it up. * adis16220 - obsolete part making it hard to get the parts test the driver in order to clean it up. Features * core - convenience functions to claim / release direct access to the device. Makes more consistent handling of this corner easier. Used in ad7192 driver. * ak8975 - power regulator support. * at91-sama5d2 - differential channel support. * mma8452 - runtime pm support - drop device specific autosleep and use the runtime pm one instead. * ms5611 - DT bindings - oversampling ratio support Cleanups and minor fixes * MAINTAINERS - Peter got married - hence name change! * Documentation - Fix a typo in in_proximity_raw description. - Add some missing docs for iio_buffer_access_funcs. * Tools - update iio_event_monitor names to match new stuff. - make generic_buffer look for triggers ending in -trigger as we let these in for a number of drivers a long time back and now it is a fairly common option. Drivers * staging wide - convert bare unsigned usage to unsigned int to comply with coding style. * non staging wide: - since boiler plate gpio handling of interrupts has been moved into the ACPI core we don't need to include gpio/consumer.h in a load of drivers so drop it. * ad7606 - fix an endian casting sparse warning. * ak8975 - fix a possible unitialized warning from gcc. - drop and unused field left over from earlier cleanups - fix a missing regulator_disable on exit. * at91-sama5d2 - typo and indentation - missing IOMEM dependency. - cleanup mode register usage by avoidling erasing whole thing when changing the sampling frequency. * bmc150 - use the core demux and available_scan_masks to simplify buffer handling - optimize the transfers in the trigger handler now we have a magic function to emulate bulk reads (under circumstances met here). This matters with some rather dumb i2c adapters in particular. - use a single regmap_conf for all bus types as they were all the same. * bmg160 - use the core demux and available_scan_masks to simplify the buffer handling - optimize the transfers in the trigger handler now we have a magic funciton to emulate bulk rads (under circumstances met here). - drop gpio interrupt probing from the driver (ACPI) as now handled by the ACPI core. * ina2xx-adc - update the CALIB register when RShunt changes. - fix scale for VShunt - in reality this error canceled out when used. * isl29028 - use regmap to retrieve the struct device instead of carrying a second copy of it around. * kxcjk-1013 - use core demux - optimize i2c transfers in the trigger handler. * mcp4531 - refactor to use a pointer to access model parameters instead of indexing into the array each time. * mma8452 - style fixes - avoid swtiching to active whenever the config changes - add missin i2c_device_id for mma8451 * mpu6050 - fix possible NULL dereference. - fix the name / chip_id used when ACPI used (otherwise reports as NULL). * ms5611 - fix a missing regulator_disable that left the regulator on during removal. * mxc4005 - drop gpio interrupt handling for ACPI case from driver as the core now handles this case. * st-sensors - note that there are only ever a maximum of 3 axis on current st-sensors so just allocate a fixed sized buffer big enough for that. * tpl0102 - change the i2c_check_functionality condition to bring it inline with other IIO users as EOPNOTSUPP. * tsl2563 - replace deprecated flush_scheduled_work
This commit is contained in:
commit
eb7bfed901
78 changed files with 2494 additions and 1475 deletions
|
@ -1233,7 +1233,7 @@ KernelVersion: 3.4
|
|||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Proximity measurement indicating that some
|
||||
object is near the sensor, usually be observing
|
||||
object is near the sensor, usually by observing
|
||||
reflectivity of infrared or ultrasound emitted.
|
||||
Often these sensors are unit less and as such conversion
|
||||
to SI units is not possible. Higher proximity measurements
|
||||
|
@ -1255,12 +1255,23 @@ Description:
|
|||
What: /sys/.../iio:deviceX/in_intensityY_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_both_raw
|
||||
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
|
||||
KernelVersion: 3.4
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Unit-less light intensity. Modifiers both and ir indicate
|
||||
that measurements contains visible and infrared light
|
||||
components or just infrared light, respectively.
|
||||
components or just infrared light, respectively. Modifier uv indicates
|
||||
that measurements contain ultraviolet light components.
|
||||
|
||||
What: /sys/.../iio:deviceX/in_uvindex_input
|
||||
KernelVersion: 4.6
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
UV light intensity index measuring the human skin's response to
|
||||
different wavelength of sunlight weighted according to the
|
||||
standardised CIE Erythemal Action Spectrum. UV index values range
|
||||
from 0 (low) to >=11 (extreme).
|
||||
|
||||
What: /sys/.../iio:deviceX/in_intensity_red_integration_time
|
||||
What: /sys/.../iio:deviceX/in_intensity_green_integration_time
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC or MMA8653FC
|
||||
Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC or FXLS8471Q
|
||||
triaxial accelerometer
|
||||
|
||||
Required properties:
|
||||
|
@ -9,6 +9,7 @@ Required properties:
|
|||
* "fsl,mma8453"
|
||||
* "fsl,mma8652"
|
||||
* "fsl,mma8653"
|
||||
* "fsl,fxls8471"
|
||||
|
||||
- reg: the I2C address of the chip
|
||||
|
||||
|
|
21
Documentation/devicetree/bindings/iio/adc/lpc1850-adc.txt
Normal file
21
Documentation/devicetree/bindings/iio/adc/lpc1850-adc.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
NXP LPC1850 ADC bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,lpc1850-adc"
|
||||
- reg: Offset and length of the register set for the ADC device
|
||||
- interrupts: The interrupt number for the ADC device
|
||||
- clocks: The root clock of the ADC controller
|
||||
- vref-supply: The regulator supply ADC reference voltage
|
||||
- resets: phandle to reset controller and line specifier
|
||||
|
||||
Example:
|
||||
|
||||
adc0: adc@400e3000 {
|
||||
compatible = "nxp,lpc1850-adc";
|
||||
reg = <0x400e3000 0x1000>;
|
||||
interrupts = <17>;
|
||||
clocks = <&ccu1 CLK_APB3_ADC0>;
|
||||
vref-supply = <®_vdda>;
|
||||
resets = <&rgu 40>;
|
||||
status = "disabled";
|
||||
};
|
|
@ -1,7 +1,11 @@
|
|||
Rockchip Successive Approximation Register (SAR) A/D Converter bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "rockchip,saradc" or "rockchip,rk3066-tsadc"
|
||||
- compatible: should be "rockchip,<name>-saradc" or "rockchip,rk3066-tsadc"
|
||||
- "rockchip,saradc": for rk3188, rk3288
|
||||
- "rockchip,rk3066-tsadc": for rk3036
|
||||
- "rockchip,rk3399-saradc": for rk3399
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: The interrupt number to the cpu. The interrupt specifier format
|
||||
|
|
20
Documentation/devicetree/bindings/iio/dac/lpc1850-dac.txt
Normal file
20
Documentation/devicetree/bindings/iio/dac/lpc1850-dac.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
NXP LPC1850 DAC bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,lpc1850-dac"
|
||||
- reg: Offset and length of the register set for the ADC device
|
||||
- interrupts: The interrupt number for the ADC device
|
||||
- clocks: The root clock of the ADC controller
|
||||
- vref-supply: The regulator supply ADC reference voltage
|
||||
- resets: phandle to reset controller and line specifier
|
||||
|
||||
Example:
|
||||
dac: dac@400e1000 {
|
||||
compatible = "nxp,lpc1850-dac";
|
||||
reg = <0x400e1000 0x1000>;
|
||||
interrupts = <0>;
|
||||
clocks = <&ccu1 CLK_APB3_DAC>;
|
||||
vref-supply = <®_vdda>;
|
||||
resets = <&rgu 42>;
|
||||
status = "disabled";
|
||||
};
|
|
@ -8,6 +8,7 @@ Required properties:
|
|||
Optional properties:
|
||||
|
||||
- gpios : should be device tree identifier of the magnetometer DRDY pin
|
||||
- vdd-supply: an optional regulator that needs to be on to provide VDD
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -15,4 +16,5 @@ ak8975@0c {
|
|||
compatible = "asahi-kasei,ak8975";
|
||||
reg = <0x0c>;
|
||||
gpios = <&gpj0 7 0>;
|
||||
vdd-supply = <&ldo_3v3_gnss>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
* Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer
|
||||
driver
|
||||
|
||||
The node for this driver must be a child node of a SPI controller, hence
|
||||
all mandatory properties described in
|
||||
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
must be specified.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be one of the following, depending on the
|
||||
model:
|
||||
"microchip,mcp4131-502"
|
||||
"microchip,mcp4131-103"
|
||||
"microchip,mcp4131-503"
|
||||
"microchip,mcp4131-104"
|
||||
"microchip,mcp4132-502"
|
||||
"microchip,mcp4132-103"
|
||||
"microchip,mcp4132-503"
|
||||
"microchip,mcp4132-104"
|
||||
"microchip,mcp4141-502"
|
||||
"microchip,mcp4141-103"
|
||||
"microchip,mcp4141-503"
|
||||
"microchip,mcp4141-104"
|
||||
"microchip,mcp4142-502"
|
||||
"microchip,mcp4142-103"
|
||||
"microchip,mcp4142-503"
|
||||
"microchip,mcp4142-104"
|
||||
"microchip,mcp4151-502"
|
||||
"microchip,mcp4151-103"
|
||||
"microchip,mcp4151-503"
|
||||
"microchip,mcp4151-104"
|
||||
"microchip,mcp4152-502"
|
||||
"microchip,mcp4152-103"
|
||||
"microchip,mcp4152-503"
|
||||
"microchip,mcp4152-104"
|
||||
"microchip,mcp4161-502"
|
||||
"microchip,mcp4161-103"
|
||||
"microchip,mcp4161-503"
|
||||
"microchip,mcp4161-104"
|
||||
"microchip,mcp4162-502"
|
||||
"microchip,mcp4162-103"
|
||||
"microchip,mcp4162-503"
|
||||
"microchip,mcp4162-104"
|
||||
"microchip,mcp4231-502"
|
||||
"microchip,mcp4231-103"
|
||||
"microchip,mcp4231-503"
|
||||
"microchip,mcp4231-104"
|
||||
"microchip,mcp4232-502"
|
||||
"microchip,mcp4232-103"
|
||||
"microchip,mcp4232-503"
|
||||
"microchip,mcp4232-104"
|
||||
"microchip,mcp4241-502"
|
||||
"microchip,mcp4241-103"
|
||||
"microchip,mcp4241-503"
|
||||
"microchip,mcp4241-104"
|
||||
"microchip,mcp4242-502"
|
||||
"microchip,mcp4242-103"
|
||||
"microchip,mcp4242-503"
|
||||
"microchip,mcp4242-104"
|
||||
"microchip,mcp4251-502"
|
||||
"microchip,mcp4251-103"
|
||||
"microchip,mcp4251-503"
|
||||
"microchip,mcp4251-104"
|
||||
"microchip,mcp4252-502"
|
||||
"microchip,mcp4252-103"
|
||||
"microchip,mcp4252-503"
|
||||
"microchip,mcp4252-104"
|
||||
"microchip,mcp4261-502"
|
||||
"microchip,mcp4261-103"
|
||||
"microchip,mcp4261-503"
|
||||
"microchip,mcp4261-104"
|
||||
"microchip,mcp4262-502"
|
||||
"microchip,mcp4262-103"
|
||||
"microchip,mcp4262-503"
|
||||
"microchip,mcp4262-104"
|
||||
|
||||
Example:
|
||||
mcp4131: mcp4131@0 {
|
||||
compatible = "mcp4131-502";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
};
|
19
Documentation/devicetree/bindings/iio/pressure/ms5611.txt
Normal file
19
Documentation/devicetree/bindings/iio/pressure/ms5611.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
MEAS ms5611 family pressure sensors
|
||||
|
||||
Pressure sensors from MEAS Switzerland with SPI and I2C bus interfaces.
|
||||
|
||||
Required properties:
|
||||
- compatible: "meas,ms5611" or "meas,ms5607"
|
||||
- reg: the I2C address or SPI chip select the device will respond to
|
||||
|
||||
Optional properties:
|
||||
- vdd-supply: an optional regulator that needs to be on to provide VDD
|
||||
power to the sensor.
|
||||
|
||||
Example:
|
||||
|
||||
ms5607@77 {
|
||||
compatible = "meas,ms5607";
|
||||
reg = <0x77>;
|
||||
vdd-supply = <&ldo_3v3_gnss>;
|
||||
};
|
|
@ -37,6 +37,7 @@ Accelerometers:
|
|||
- st,lsm330-accel
|
||||
- st,lsm303agr-accel
|
||||
- st,lis2dh12-accel
|
||||
- st,h3lis331dl-accel
|
||||
|
||||
Gyroscopes:
|
||||
- st,l3g4200d-gyro
|
||||
|
|
|
@ -141,6 +141,7 @@ lsi LSI Corp. (LSI Logic)
|
|||
lltc Linear Technology Corporation
|
||||
marvell Marvell Technology Group Ltd.
|
||||
maxim Maxim Integrated Products
|
||||
meas Measurement Specialties
|
||||
mediatek MediaTek Inc.
|
||||
melexis Melexis N.V.
|
||||
merrii Merrii Technology Co., Ltd.
|
||||
|
|
|
@ -5538,7 +5538,7 @@ IIO SUBSYSTEM AND DRIVERS
|
|||
M: Jonathan Cameron <jic23@kernel.org>
|
||||
R: Hartmut Knaack <knaack.h@gmx.de>
|
||||
R: Lars-Peter Clausen <lars@metafoo.de>
|
||||
R: Peter Meerwald <pmeerw@pmeerw.net>
|
||||
R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/iio/
|
||||
|
|
|
@ -64,7 +64,7 @@ config IIO_ST_ACCEL_3AXIS
|
|||
help
|
||||
Say yes here to build support for STMicroelectronics accelerometers:
|
||||
LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
|
||||
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
|
||||
LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL.
|
||||
|
||||
This driver can also be built as a module. If so, these modules
|
||||
will be created:
|
||||
|
@ -143,7 +143,8 @@ config MMA8452
|
|||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for the following Freescale 3-axis
|
||||
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC.
|
||||
accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC,
|
||||
FXLS8471Q.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called mma8452.
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -138,6 +137,7 @@ enum bmc150_accel_axis {
|
|||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_MAX,
|
||||
};
|
||||
|
||||
enum bmc150_power_modes {
|
||||
|
@ -246,11 +246,12 @@ static const struct {
|
|||
{500000, BMC150_ACCEL_SLEEP_500_MS},
|
||||
{1000000, BMC150_ACCEL_SLEEP_1_SEC} };
|
||||
|
||||
static const struct regmap_config bmc150_i2c_regmap_conf = {
|
||||
const struct regmap_config bmc150_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x3f,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(bmc150_regmap_conf);
|
||||
|
||||
static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
|
||||
enum bmc150_power_modes mode,
|
||||
|
@ -988,6 +989,7 @@ static const struct iio_event_spec bmc150_accel_event = {
|
|||
.realbits = (bits), \
|
||||
.storagebits = 16, \
|
||||
.shift = 16 - (bits), \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
.event_spec = &bmc150_accel_event, \
|
||||
.num_event_specs = 1 \
|
||||
|
@ -1104,27 +1106,23 @@ static const struct iio_info bmc150_accel_info_fifo = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long bmc150_accel_scan_masks[] = {
|
||||
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
|
||||
0};
|
||||
|
||||
static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct bmc150_accel_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
unsigned int raw_val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = regmap_bulk_read(data->regmap,
|
||||
BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val,
|
||||
2);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
goto err_read;
|
||||
}
|
||||
data->buffer[i++] = raw_val;
|
||||
}
|
||||
ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_REG_XOUT_L,
|
||||
data->buffer, AXIS_MAX * 2);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret < 0)
|
||||
goto err_read;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
pf->timestamp);
|
||||
|
@ -1574,6 +1572,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
indio_dev->channels = data->chip_info->channels;
|
||||
indio_dev->num_channels = data->chip_info->num_channels;
|
||||
indio_dev->name = name ? name : data->chip_info->name;
|
||||
indio_dev->available_scan_masks = bmc150_accel_scan_masks;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &bmc150_accel_info;
|
||||
|
||||
|
|
|
@ -28,11 +28,6 @@
|
|||
|
||||
#include "bmc150-accel.h"
|
||||
|
||||
static const struct regmap_config bmc150_i2c_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int bmc150_accel_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -43,7 +38,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
|
|||
i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK);
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
|
||||
regmap = devm_regmap_init_i2c(client, &bmc150_regmap_conf);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "Failed to initialize i2c regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
|
|
|
@ -25,18 +25,12 @@
|
|||
|
||||
#include "bmc150-accel.h"
|
||||
|
||||
static const struct regmap_config bmc150_spi_regmap_conf = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x3f,
|
||||
};
|
||||
|
||||
static int bmc150_accel_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
|
||||
regmap = devm_regmap_init_spi(spi, &bmc150_regmap_conf);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "Failed to initialize spi regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
|
|
|
@ -16,5 +16,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
const char *name, bool block_supported);
|
||||
int bmc150_accel_core_remove(struct device *dev);
|
||||
extern const struct dev_pm_ops bmc150_accel_pm_ops;
|
||||
extern const struct regmap_config bmc150_regmap_conf;
|
||||
|
||||
#endif /* _BMC150_ACCEL_H_ */
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -115,6 +114,7 @@ enum kxcjk1013_axis {
|
|||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_MAX,
|
||||
};
|
||||
|
||||
enum kxcjk1013_mode {
|
||||
|
@ -922,7 +922,7 @@ static const struct iio_event_spec kxcjk1013_event = {
|
|||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_CPU, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
.event_spec = &kxcjk1013_event, \
|
||||
.num_event_specs = 1 \
|
||||
|
@ -953,25 +953,23 @@ static const struct iio_info kxcjk1013_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long kxcjk1013_scan_masks[] = {0x7, 0};
|
||||
|
||||
static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = kxcjk1013_get_acc_reg(data, bit);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[i++] = ret;
|
||||
}
|
||||
ret = i2c_smbus_read_i2c_block_data_or_emulated(data->client,
|
||||
KXCJK1013_REG_XOUT_L,
|
||||
AXIS_MAX * 2,
|
||||
(u8 *)data->buffer);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
data->timestamp);
|
||||
|
@ -1204,6 +1202,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
|||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = kxcjk1013_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels);
|
||||
indio_dev->available_scan_masks = kxcjk1013_scan_masks;
|
||||
indio_dev->name = name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &kxcjk1013_info;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* MMA8453Q (10 bit)
|
||||
* MMA8652FC (12 bit)
|
||||
* MMA8653FC (10 bit)
|
||||
* FXLS8471Q (14 bit)
|
||||
*
|
||||
* Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
|
||||
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
|
||||
|
@ -16,7 +17,7 @@
|
|||
*
|
||||
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
|
||||
*
|
||||
* TODO: orientation events, autosleep
|
||||
* TODO: orientation events
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -31,6 +32,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define MMA8452_STATUS 0x00
|
||||
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
|
||||
|
@ -91,6 +93,9 @@
|
|||
#define MMA8453_DEVICE_ID 0x3a
|
||||
#define MMA8652_DEVICE_ID 0x4a
|
||||
#define MMA8653_DEVICE_ID 0x5a
|
||||
#define FXLS8471_DEVICE_ID 0x6a
|
||||
|
||||
#define MMA8452_AUTO_SUSPEND_DELAY_MS 2000
|
||||
|
||||
struct mma8452_data {
|
||||
struct i2c_client *client;
|
||||
|
@ -172,6 +177,31 @@ static int mma8452_drdy(struct mma8452_data *data)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static int mma8452_set_runtime_pm_state(struct i2c_client *client, bool on)
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
int ret;
|
||||
|
||||
if (on) {
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
} else {
|
||||
pm_runtime_mark_last_busy(&client->dev);
|
||||
ret = pm_runtime_put_autosuspend(&client->dev);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"failed to change power state to %d\n", on);
|
||||
if (on)
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
|
||||
{
|
||||
int ret = mma8452_drdy(data);
|
||||
|
@ -179,8 +209,16 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3])
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
|
||||
3 * sizeof(__be16), (u8 *)buf);
|
||||
ret = mma8452_set_runtime_pm_state(data->client, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
|
||||
3 * sizeof(__be16), (u8 *)buf);
|
||||
|
||||
ret = mma8452_set_runtime_pm_state(data->client, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2],
|
||||
|
@ -357,7 +395,8 @@ static int mma8452_read_raw(struct iio_dev *indio_dev,
|
|||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
ret = i2c_smbus_read_byte_data(data->client,
|
||||
MMA8452_OFF_X + chan->scan_index);
|
||||
MMA8452_OFF_X +
|
||||
chan->scan_index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -392,24 +431,47 @@ static int mma8452_active(struct mma8452_data *data)
|
|||
data->ctrl_reg1);
|
||||
}
|
||||
|
||||
/* returns >0 if active, 0 if in standby and <0 on error */
|
||||
static int mma8452_is_active(struct mma8452_data *data)
|
||||
{
|
||||
int reg;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG1);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
|
||||
return reg & MMA8452_CTRL_ACTIVE;
|
||||
}
|
||||
|
||||
static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
|
||||
{
|
||||
int ret;
|
||||
int is_active;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
/* config can only be changed when in standby */
|
||||
ret = mma8452_standby(data);
|
||||
if (ret < 0)
|
||||
is_active = mma8452_is_active(data);
|
||||
if (is_active < 0) {
|
||||
ret = is_active;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* config can only be changed when in standby */
|
||||
if (is_active > 0) {
|
||||
ret = mma8452_standby(data);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(data->client, reg, val);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = mma8452_active(data);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
if (is_active > 0) {
|
||||
ret = mma8452_active(data);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
|
@ -418,7 +480,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* returns >0 if in freefall mode, 0 if not or <0 if an error occured */
|
||||
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
|
||||
static int mma8452_freefall_mode_enabled(struct mma8452_data *data)
|
||||
{
|
||||
int val;
|
||||
|
@ -668,7 +730,8 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift));
|
||||
return !!(ret & BIT(chan->scan_index +
|
||||
chip->ev_cfg_chan_shift));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -682,7 +745,11 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev,
|
|||
{
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
const struct mma_chip_info *chip = data->chip_info;
|
||||
int val;
|
||||
int val, ret;
|
||||
|
||||
ret = mma8452_set_runtime_pm_state(data->client, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_FALLING:
|
||||
|
@ -990,6 +1057,7 @@ enum {
|
|||
mma8453,
|
||||
mma8652,
|
||||
mma8653,
|
||||
fxls8471,
|
||||
};
|
||||
|
||||
static const struct mma_chip_info mma_chip_info_table[] = {
|
||||
|
@ -1003,7 +1071,7 @@ static const struct mma_chip_info mma_chip_info_table[] = {
|
|||
* bit.
|
||||
* The userspace interface uses m/s^2 and we declare micro units
|
||||
* So scale factor for 12 bit here is given by:
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
|
||||
* g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
|
||||
*/
|
||||
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
|
||||
.ev_cfg = MMA8452_TRANSIENT_CFG,
|
||||
|
@ -1081,6 +1149,22 @@ static const struct mma_chip_info mma_chip_info_table[] = {
|
|||
.ev_ths_mask = MMA8452_FF_MT_THS_MASK,
|
||||
.ev_count = MMA8452_FF_MT_COUNT,
|
||||
},
|
||||
[fxls8471] = {
|
||||
.chip_id = FXLS8471_DEVICE_ID,
|
||||
.channels = mma8451_channels,
|
||||
.num_channels = ARRAY_SIZE(mma8451_channels),
|
||||
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} },
|
||||
.ev_cfg = MMA8452_TRANSIENT_CFG,
|
||||
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
|
||||
.ev_cfg_chan_shift = 1,
|
||||
.ev_src = MMA8452_TRANSIENT_SRC,
|
||||
.ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE,
|
||||
.ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE,
|
||||
.ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE,
|
||||
.ev_ths = MMA8452_TRANSIENT_THS,
|
||||
.ev_ths_mask = MMA8452_TRANSIENT_THS_MASK,
|
||||
.ev_count = MMA8452_TRANSIENT_COUNT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct attribute *mma8452_attributes[] = {
|
||||
|
@ -1114,7 +1198,11 @@ static int mma8452_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
|||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
int reg;
|
||||
int reg, ret;
|
||||
|
||||
ret = mma8452_set_runtime_pm_state(data->client, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(data->client, MMA8452_CTRL_REG4);
|
||||
if (reg < 0)
|
||||
|
@ -1206,6 +1294,7 @@ static const struct of_device_id mma8452_dt_ids[] = {
|
|||
{ .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] },
|
||||
{ .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] },
|
||||
{ .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] },
|
||||
{ .compatible = "fsl,fxls8471", .data = &mma_chip_info_table[fxls8471] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mma8452_dt_ids);
|
||||
|
@ -1243,6 +1332,7 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
case MMA8453_DEVICE_ID:
|
||||
case MMA8652_DEVICE_ID:
|
||||
case MMA8653_DEVICE_ID:
|
||||
case FXLS8471_DEVICE_ID:
|
||||
if (ret == data->chip_info->chip_id)
|
||||
break;
|
||||
default:
|
||||
|
@ -1340,6 +1430,15 @@ static int mma8452_probe(struct i2c_client *client,
|
|||
goto buffer_cleanup;
|
||||
}
|
||||
|
||||
ret = pm_runtime_set_active(&client->dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev,
|
||||
MMA8452_AUTO_SUSPEND_DELAY_MS);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
@ -1364,6 +1463,11 @@ static int mma8452_remove(struct i2c_client *client)
|
|||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
mma8452_trigger_cleanup(indio_dev);
|
||||
mma8452_standby(iio_priv(indio_dev));
|
||||
|
@ -1371,6 +1475,45 @@ static int mma8452_remove(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mma8452_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = mma8452_standby(data);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "powering off device failed\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mma8452_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
|
||||
struct mma8452_data *data = iio_priv(indio_dev);
|
||||
int ret, sleep_val;
|
||||
|
||||
ret = mma8452_active(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mma8452_get_odr_index(data);
|
||||
sleep_val = 1000 / mma8452_samp_freq[ret][0];
|
||||
if (sleep_val < 20)
|
||||
usleep_range(sleep_val * 1000, 20000);
|
||||
else
|
||||
msleep_interruptible(sleep_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mma8452_suspend(struct device *dev)
|
||||
{
|
||||
|
@ -1383,18 +1526,21 @@ static int mma8452_resume(struct device *dev)
|
|||
return mma8452_active(iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev))));
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume);
|
||||
#define MMA8452_PM_OPS (&mma8452_pm_ops)
|
||||
#else
|
||||
#define MMA8452_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops mma8452_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mma8452_suspend, mma8452_resume)
|
||||
SET_RUNTIME_PM_OPS(mma8452_runtime_suspend,
|
||||
mma8452_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id mma8452_id[] = {
|
||||
{ "mma8451", mma8451 },
|
||||
{ "mma8452", mma8452 },
|
||||
{ "mma8453", mma8453 },
|
||||
{ "mma8652", mma8652 },
|
||||
{ "mma8653", mma8653 },
|
||||
{ "fxls8471", fxls8471 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma8452_id);
|
||||
|
@ -1403,7 +1549,7 @@ static struct i2c_driver mma8452_driver = {
|
|||
.driver = {
|
||||
.name = "mma8452",
|
||||
.of_match_table = of_match_ptr(mma8452_dt_ids),
|
||||
.pm = MMA8452_PM_OPS,
|
||||
.pm = &mma8452_pm_ops,
|
||||
},
|
||||
.probe = mma8452_probe,
|
||||
.remove = mma8452_remove,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
|
@ -380,31 +379,6 @@ static const struct iio_trigger_ops mxc4005_trigger_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mxc4005_gpio_probe(struct i2c_client *client,
|
||||
struct mxc4005_data *data)
|
||||
{
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
int ret;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "failed to get acpi gpio index\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ret = gpiod_to_irq(gpio);
|
||||
|
||||
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxc4005_chip_init(struct mxc4005_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
@ -470,9 +444,6 @@ static int mxc4005_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq < 0)
|
||||
client->irq = mxc4005_gpio_probe(client, data);
|
||||
|
||||
if (client->irq > 0) {
|
||||
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
||||
"%s-dev%d",
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/iio/common/st_sensors.h>
|
||||
|
||||
#define H3LIS331DL_DRIVER_NAME "h3lis331dl_accel"
|
||||
#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel"
|
||||
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
|
||||
#define LIS3DH_ACCEL_DEV_NAME "lis3dh"
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
#define ST_ACCEL_FS_AVL_6G 6
|
||||
#define ST_ACCEL_FS_AVL_8G 8
|
||||
#define ST_ACCEL_FS_AVL_16G 16
|
||||
#define ST_ACCEL_FS_AVL_100G 100
|
||||
#define ST_ACCEL_FS_AVL_200G 200
|
||||
#define ST_ACCEL_FS_AVL_400G 400
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 1 */
|
||||
#define ST_ACCEL_1_WAI_EXP 0x33
|
||||
|
@ -181,6 +184,33 @@
|
|||
#define ST_ACCEL_5_IG1_EN_MASK 0x08
|
||||
#define ST_ACCEL_5_MULTIREAD_BIT false
|
||||
|
||||
/* CUSTOM VALUES FOR SENSOR 6 */
|
||||
#define ST_ACCEL_6_WAI_EXP 0x32
|
||||
#define ST_ACCEL_6_ODR_ADDR 0x20
|
||||
#define ST_ACCEL_6_ODR_MASK 0x18
|
||||
#define ST_ACCEL_6_ODR_AVL_50HZ_VAL 0x00
|
||||
#define ST_ACCEL_6_ODR_AVL_100HZ_VAL 0x01
|
||||
#define ST_ACCEL_6_ODR_AVL_400HZ_VAL 0x02
|
||||
#define ST_ACCEL_6_ODR_AVL_1000HZ_VAL 0x03
|
||||
#define ST_ACCEL_6_PW_ADDR 0x20
|
||||
#define ST_ACCEL_6_PW_MASK 0x20
|
||||
#define ST_ACCEL_6_FS_ADDR 0x23
|
||||
#define ST_ACCEL_6_FS_MASK 0x30
|
||||
#define ST_ACCEL_6_FS_AVL_100_VAL 0x00
|
||||
#define ST_ACCEL_6_FS_AVL_200_VAL 0x01
|
||||
#define ST_ACCEL_6_FS_AVL_400_VAL 0x03
|
||||
#define ST_ACCEL_6_FS_AVL_100_GAIN IIO_G_TO_M_S_2(49000)
|
||||
#define ST_ACCEL_6_FS_AVL_200_GAIN IIO_G_TO_M_S_2(98000)
|
||||
#define ST_ACCEL_6_FS_AVL_400_GAIN IIO_G_TO_M_S_2(195000)
|
||||
#define ST_ACCEL_6_BDU_ADDR 0x23
|
||||
#define ST_ACCEL_6_BDU_MASK 0x80
|
||||
#define ST_ACCEL_6_DRDY_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_6_DRDY_IRQ_INT1_MASK 0x02
|
||||
#define ST_ACCEL_6_DRDY_IRQ_INT2_MASK 0x10
|
||||
#define ST_ACCEL_6_IHL_IRQ_ADDR 0x22
|
||||
#define ST_ACCEL_6_IHL_IRQ_MASK 0x80
|
||||
#define ST_ACCEL_6_MULTIREAD_BIT true
|
||||
|
||||
static const struct iio_chan_spec st_accel_8bit_channels[] = {
|
||||
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
|
||||
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
|
||||
|
@ -557,6 +587,68 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
|
|||
.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
|
||||
.bootime = 2, /* guess */
|
||||
},
|
||||
{
|
||||
.wai = ST_ACCEL_6_WAI_EXP,
|
||||
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
|
||||
.sensors_supported = {
|
||||
[0] = H3LIS331DL_DRIVER_NAME,
|
||||
},
|
||||
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
|
||||
.odr = {
|
||||
.addr = ST_ACCEL_6_ODR_ADDR,
|
||||
.mask = ST_ACCEL_6_ODR_MASK,
|
||||
.odr_avl = {
|
||||
{ 50, ST_ACCEL_6_ODR_AVL_50HZ_VAL },
|
||||
{ 100, ST_ACCEL_6_ODR_AVL_100HZ_VAL, },
|
||||
{ 400, ST_ACCEL_6_ODR_AVL_400HZ_VAL, },
|
||||
{ 1000, ST_ACCEL_6_ODR_AVL_1000HZ_VAL, },
|
||||
},
|
||||
},
|
||||
.pw = {
|
||||
.addr = ST_ACCEL_6_PW_ADDR,
|
||||
.mask = ST_ACCEL_6_PW_MASK,
|
||||
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
|
||||
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
|
||||
},
|
||||
.enable_axis = {
|
||||
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
|
||||
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
|
||||
},
|
||||
.fs = {
|
||||
.addr = ST_ACCEL_6_FS_ADDR,
|
||||
.mask = ST_ACCEL_6_FS_MASK,
|
||||
.fs_avl = {
|
||||
[0] = {
|
||||
.num = ST_ACCEL_FS_AVL_100G,
|
||||
.value = ST_ACCEL_6_FS_AVL_100_VAL,
|
||||
.gain = ST_ACCEL_6_FS_AVL_100_GAIN,
|
||||
},
|
||||
[1] = {
|
||||
.num = ST_ACCEL_FS_AVL_200G,
|
||||
.value = ST_ACCEL_6_FS_AVL_200_VAL,
|
||||
.gain = ST_ACCEL_6_FS_AVL_200_GAIN,
|
||||
},
|
||||
[2] = {
|
||||
.num = ST_ACCEL_FS_AVL_400G,
|
||||
.value = ST_ACCEL_6_FS_AVL_400_VAL,
|
||||
.gain = ST_ACCEL_6_FS_AVL_400_GAIN,
|
||||
},
|
||||
},
|
||||
},
|
||||
.bdu = {
|
||||
.addr = ST_ACCEL_6_BDU_ADDR,
|
||||
.mask = ST_ACCEL_6_BDU_MASK,
|
||||
},
|
||||
.drdy_irq = {
|
||||
.addr = ST_ACCEL_6_DRDY_IRQ_ADDR,
|
||||
.mask_int1 = ST_ACCEL_6_DRDY_IRQ_INT1_MASK,
|
||||
.mask_int2 = ST_ACCEL_6_DRDY_IRQ_INT2_MASK,
|
||||
.addr_ihl = ST_ACCEL_6_IHL_IRQ_ADDR,
|
||||
.mask_ihl = ST_ACCEL_6_IHL_IRQ_MASK,
|
||||
},
|
||||
.multi_read_bit = ST_ACCEL_6_MULTIREAD_BIT,
|
||||
.bootime = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static int st_accel_read_raw(struct iio_dev *indio_dev,
|
||||
|
|
|
@ -76,6 +76,10 @@ static const struct of_device_id st_accel_of_match[] = {
|
|||
.compatible = "st,lis2dh12-accel",
|
||||
.data = LIS2DH12_ACCEL_DEV_NAME,
|
||||
},
|
||||
{
|
||||
.compatible = "st,h3lis331dl-accel",
|
||||
.data = H3LIS331DL_DRIVER_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_accel_of_match);
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
@ -134,6 +134,7 @@ config AT91_ADC
|
|||
config AT91_SAMA5D2_ADC
|
||||
tristate "Atmel AT91 SAMA5D2 ADC"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say yes here to build support for Atmel SAMA5D2 ADC which is
|
||||
available on SAMA5D2 SoC family.
|
||||
|
@ -241,6 +242,16 @@ config LP8788_ADC
|
|||
To compile this driver as a module, choose M here: the module will be
|
||||
called lp8788_adc.
|
||||
|
||||
config LPC18XX_ADC
|
||||
tristate "NXP LPC18xx ADC driver"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
depends on OF && HAS_IOMEM
|
||||
help
|
||||
Say yes here to build support for NXP LPC18XX ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called lpc18xx_adc.
|
||||
|
||||
config MAX1027
|
||||
tristate "Maxim max1027 ADC driver"
|
||||
depends on SPI
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_HI8435) += hi8435.o
|
|||
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
|
||||
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
obj-$(CONFIG_MCP320X) += mcp320x.o
|
||||
|
|
|
@ -66,8 +66,10 @@
|
|||
#define AT91_SAMA5D2_MR_PRESCAL(v) ((v) << AT91_SAMA5D2_MR_PRESCAL_OFFSET)
|
||||
#define AT91_SAMA5D2_MR_PRESCAL_OFFSET 8
|
||||
#define AT91_SAMA5D2_MR_PRESCAL_MAX 0xff
|
||||
#define AT91_SAMA5D2_MR_PRESCAL_MASK GENMASK(15, 8)
|
||||
/* Startup Time */
|
||||
#define AT91_SAMA5D2_MR_STARTUP(v) ((v) << 16)
|
||||
#define AT91_SAMA5D2_MR_STARTUP_MASK GENMASK(19, 16)
|
||||
/* Analog Change */
|
||||
#define AT91_SAMA5D2_MR_ANACH BIT(23)
|
||||
/* Tracking Time */
|
||||
|
@ -92,13 +94,13 @@
|
|||
/* Last Converted Data Register */
|
||||
#define AT91_SAMA5D2_LCDR 0x20
|
||||
/* Interrupt Enable Register */
|
||||
#define AT91_SAMA5D2_IER 0x24
|
||||
#define AT91_SAMA5D2_IER 0x24
|
||||
/* Interrupt Disable Register */
|
||||
#define AT91_SAMA5D2_IDR 0x28
|
||||
#define AT91_SAMA5D2_IDR 0x28
|
||||
/* Interrupt Mask Register */
|
||||
#define AT91_SAMA5D2_IMR 0x2c
|
||||
#define AT91_SAMA5D2_IMR 0x2c
|
||||
/* Interrupt Status Register */
|
||||
#define AT91_SAMA5D2_ISR 0x30
|
||||
#define AT91_SAMA5D2_ISR 0x30
|
||||
/* Last Channel Trigger Mode Register */
|
||||
#define AT91_SAMA5D2_LCTMR 0x34
|
||||
/* Last Channel Compare Window Register */
|
||||
|
@ -106,17 +108,20 @@
|
|||
/* Overrun Status Register */
|
||||
#define AT91_SAMA5D2_OVER 0x3c
|
||||
/* Extended Mode Register */
|
||||
#define AT91_SAMA5D2_EMR 0x40
|
||||
#define AT91_SAMA5D2_EMR 0x40
|
||||
/* Compare Window Register */
|
||||
#define AT91_SAMA5D2_CWR 0x44
|
||||
#define AT91_SAMA5D2_CWR 0x44
|
||||
/* Channel Gain Register */
|
||||
#define AT91_SAMA5D2_CGR 0x48
|
||||
#define AT91_SAMA5D2_CGR 0x48
|
||||
|
||||
/* Channel Offset Register */
|
||||
#define AT91_SAMA5D2_COR 0x4c
|
||||
#define AT91_SAMA5D2_COR 0x4c
|
||||
#define AT91_SAMA5D2_COR_DIFF_OFFSET 16
|
||||
|
||||
/* Channel Data Register 0 */
|
||||
#define AT91_SAMA5D2_CDR0 0x50
|
||||
/* Analog Control Register */
|
||||
#define AT91_SAMA5D2_ACR 0x94
|
||||
#define AT91_SAMA5D2_ACR 0x94
|
||||
/* Touchscreen Mode Register */
|
||||
#define AT91_SAMA5D2_TSMR 0xb0
|
||||
/* Touchscreen X Position Register */
|
||||
|
@ -130,7 +135,7 @@
|
|||
/* Correction Select Register */
|
||||
#define AT91_SAMA5D2_COSR 0xd0
|
||||
/* Correction Value Register */
|
||||
#define AT91_SAMA5D2_CVR 0xd4
|
||||
#define AT91_SAMA5D2_CVR 0xd4
|
||||
/* Channel Error Correction Register */
|
||||
#define AT91_SAMA5D2_CECR 0xd8
|
||||
/* Write Protection Mode Register */
|
||||
|
@ -140,7 +145,7 @@
|
|||
/* Version Register */
|
||||
#define AT91_SAMA5D2_VERSION 0xfc
|
||||
|
||||
#define AT91_AT91_SAMA5D2_CHAN(num, addr) \
|
||||
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = num, \
|
||||
|
@ -156,6 +161,24 @@
|
|||
.indexed = 1, \
|
||||
}
|
||||
|
||||
#define AT91_SAMA5D2_CHAN_DIFF(num, num2, addr) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.differential = 1, \
|
||||
.channel = num, \
|
||||
.channel2 = num2, \
|
||||
.address = addr, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
}, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
|
||||
.datasheet_name = "CH"#num"-CH"#num2, \
|
||||
.indexed = 1, \
|
||||
}
|
||||
|
||||
#define at91_adc_readl(st, reg) readl_relaxed(st->base + reg)
|
||||
#define at91_adc_writel(st, reg, val) writel_relaxed(val, st->base + reg)
|
||||
|
||||
|
@ -185,18 +208,24 @@ struct at91_adc_state {
|
|||
};
|
||||
|
||||
static const struct iio_chan_spec at91_adc_channels[] = {
|
||||
AT91_AT91_SAMA5D2_CHAN(0, 0x50),
|
||||
AT91_AT91_SAMA5D2_CHAN(1, 0x54),
|
||||
AT91_AT91_SAMA5D2_CHAN(2, 0x58),
|
||||
AT91_AT91_SAMA5D2_CHAN(3, 0x5c),
|
||||
AT91_AT91_SAMA5D2_CHAN(4, 0x60),
|
||||
AT91_AT91_SAMA5D2_CHAN(5, 0x64),
|
||||
AT91_AT91_SAMA5D2_CHAN(6, 0x68),
|
||||
AT91_AT91_SAMA5D2_CHAN(7, 0x6c),
|
||||
AT91_AT91_SAMA5D2_CHAN(8, 0x70),
|
||||
AT91_AT91_SAMA5D2_CHAN(9, 0x74),
|
||||
AT91_AT91_SAMA5D2_CHAN(10, 0x78),
|
||||
AT91_AT91_SAMA5D2_CHAN(11, 0x7c),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(3, 0x5c),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(4, 0x60),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(5, 0x64),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(6, 0x68),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(7, 0x6c),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(8, 0x70),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(9, 0x74),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(10, 0x78),
|
||||
AT91_SAMA5D2_CHAN_SINGLE(11, 0x7c),
|
||||
AT91_SAMA5D2_CHAN_DIFF(0, 1, 0x50),
|
||||
AT91_SAMA5D2_CHAN_DIFF(2, 3, 0x58),
|
||||
AT91_SAMA5D2_CHAN_DIFF(4, 5, 0x60),
|
||||
AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
|
||||
AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
|
||||
AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
|
||||
};
|
||||
|
||||
static unsigned at91_adc_startup_time(unsigned startup_time_min,
|
||||
|
@ -226,7 +255,7 @@ static unsigned at91_adc_startup_time(unsigned startup_time_min,
|
|||
static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_priv_to_dev(st);
|
||||
unsigned f_per, prescal, startup;
|
||||
unsigned f_per, prescal, startup, mr;
|
||||
|
||||
f_per = clk_get_rate(st->per_clk);
|
||||
prescal = (f_per / (2 * freq)) - 1;
|
||||
|
@ -234,10 +263,11 @@ static void at91_adc_setup_samp_freq(struct at91_adc_state *st, unsigned freq)
|
|||
startup = at91_adc_startup_time(st->soc_info.startup_time,
|
||||
freq / 1000);
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_MR,
|
||||
AT91_SAMA5D2_MR_TRANSFER(2)
|
||||
| AT91_SAMA5D2_MR_STARTUP(startup)
|
||||
| AT91_SAMA5D2_MR_PRESCAL(prescal));
|
||||
mr = at91_adc_readl(st, AT91_SAMA5D2_MR);
|
||||
mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
|
||||
mr |= AT91_SAMA5D2_MR_STARTUP(startup);
|
||||
mr |= AT91_SAMA5D2_MR_PRESCAL(prescal);
|
||||
at91_adc_writel(st, AT91_SAMA5D2_MR, mr);
|
||||
|
||||
dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u\n",
|
||||
freq, startup, prescal);
|
||||
|
@ -278,6 +308,7 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
|
|||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct at91_adc_state *st = iio_priv(indio_dev);
|
||||
u32 cor = 0;
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -286,6 +317,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
st->chan = chan;
|
||||
|
||||
if (chan->differential)
|
||||
cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
|
||||
AT91_SAMA5D2_COR_DIFF_OFFSET;
|
||||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
|
||||
at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
|
||||
|
@ -298,6 +334,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
if (ret > 0) {
|
||||
*val = st->conversion_value;
|
||||
if (chan->scan_type.sign == 's')
|
||||
*val = sign_extend32(*val, 11);
|
||||
ret = IIO_VAL_INT;
|
||||
st->conversion_done = false;
|
||||
}
|
||||
|
@ -310,6 +348,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = st->vref_uv / 1000;
|
||||
if (chan->differential)
|
||||
*val *= 2;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
|
@ -444,6 +484,12 @@ static int at91_adc_probe(struct platform_device *pdev)
|
|||
|
||||
at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
|
||||
at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
|
||||
/*
|
||||
* Transfer field must be set to 2 according to the datasheet and
|
||||
* allows different analog settings for each channel.
|
||||
*/
|
||||
at91_adc_writel(st, AT91_SAMA5D2_MR,
|
||||
AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
|
||||
|
||||
at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
|
||||
|
||||
|
|
|
@ -185,9 +185,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->address) {
|
||||
case INA2XX_SHUNT_VOLTAGE:
|
||||
/* processed (mV) = raw*1000/shunt_div */
|
||||
/* processed (mV) = raw/shunt_div */
|
||||
*val2 = chip->config->shunt_div;
|
||||
*val = 1000;
|
||||
*val = 1;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
|
||||
case INA2XX_BUS_VOLTAGE:
|
||||
|
@ -350,6 +350,23 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
|
|||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set current LSB to 1mA, shunt is in uOhms
|
||||
* (equation 13 in datasheet). We hardcode a Current_LSB
|
||||
* of 1.0 x10-6. The only remaining parameter is RShunt.
|
||||
* There is no need to expose the CALIBRATION register
|
||||
* to the user for now. But we need to reset this register
|
||||
* if the user updates RShunt after driver init, e.g upon
|
||||
* reading an EEPROM/Probe-type value.
|
||||
*/
|
||||
static int ina2xx_set_calibration(struct ina2xx_chip_info *chip)
|
||||
{
|
||||
u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
|
||||
chip->shunt_resistor);
|
||||
|
||||
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
|
||||
}
|
||||
|
||||
static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
|
||||
{
|
||||
if (val <= 0 || val > chip->config->calibration_factor)
|
||||
|
@ -385,6 +402,11 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Update the Calibration register */
|
||||
ret = ina2xx_set_calibration(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -602,24 +624,11 @@ static const struct iio_info ina2xx_info = {
|
|||
/* Initialize the configuration and calibration registers. */
|
||||
static int ina2xx_init(struct ina2xx_chip_info *chip, unsigned int config)
|
||||
{
|
||||
u16 regval;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
|
||||
int ret = regmap_write(chip->regmap, INA2XX_CONFIG, config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set current LSB to 1mA, shunt is in uOhms
|
||||
* (equation 13 in datasheet). We hardcode a Current_LSB
|
||||
* of 1.0 x10-6. The only remaining parameter is RShunt.
|
||||
* There is no need to expose the CALIBRATION register
|
||||
* to the user for now.
|
||||
*/
|
||||
regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
|
||||
chip->shunt_resistor);
|
||||
|
||||
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
|
||||
return ina2xx_set_calibration(chip);
|
||||
}
|
||||
|
||||
static int ina2xx_probe(struct i2c_client *client,
|
||||
|
|
231
drivers/iio/adc/lpc18xx_adc.c
Normal file
231
drivers/iio/adc/lpc18xx_adc.c
Normal file
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* IIO ADC driver for NXP LPC18xx ADC
|
||||
*
|
||||
* Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* UNSUPPORTED hardware features:
|
||||
* - Hardware triggers
|
||||
* - Burst mode
|
||||
* - Interrupts
|
||||
* - DMA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* LPC18XX ADC registers and bits */
|
||||
#define LPC18XX_ADC_CR 0x000
|
||||
#define LPC18XX_ADC_CR_CLKDIV_SHIFT 8
|
||||
#define LPC18XX_ADC_CR_PDN BIT(21)
|
||||
#define LPC18XX_ADC_CR_START_NOW (0x1 << 24)
|
||||
#define LPC18XX_ADC_GDR 0x004
|
||||
|
||||
/* Data register bits */
|
||||
#define LPC18XX_ADC_SAMPLE_SHIFT 6
|
||||
#define LPC18XX_ADC_SAMPLE_MASK 0x3ff
|
||||
#define LPC18XX_ADC_CONV_DONE BIT(31)
|
||||
|
||||
/* Clock should be 4.5 MHz or less */
|
||||
#define LPC18XX_ADC_CLK_TARGET 4500000
|
||||
|
||||
struct lpc18xx_adc {
|
||||
struct regulator *vref;
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
u32 cr_reg;
|
||||
};
|
||||
|
||||
#define LPC18XX_ADC_CHAN(_idx) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = _idx, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec lpc18xx_adc_iio_channels[] = {
|
||||
LPC18XX_ADC_CHAN(0),
|
||||
LPC18XX_ADC_CHAN(1),
|
||||
LPC18XX_ADC_CHAN(2),
|
||||
LPC18XX_ADC_CHAN(3),
|
||||
LPC18XX_ADC_CHAN(4),
|
||||
LPC18XX_ADC_CHAN(5),
|
||||
LPC18XX_ADC_CHAN(6),
|
||||
LPC18XX_ADC_CHAN(7),
|
||||
};
|
||||
|
||||
static int lpc18xx_adc_read_chan(struct lpc18xx_adc *adc, unsigned int ch)
|
||||
{
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
reg = adc->cr_reg | BIT(ch) | LPC18XX_ADC_CR_START_NOW;
|
||||
writel(reg, adc->base + LPC18XX_ADC_CR);
|
||||
|
||||
ret = readl_poll_timeout(adc->base + LPC18XX_ADC_GDR, reg,
|
||||
reg & LPC18XX_ADC_CONV_DONE, 3, 9);
|
||||
if (ret) {
|
||||
dev_warn(adc->dev, "adc read timed out\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return (reg >> LPC18XX_ADC_SAMPLE_SHIFT) & LPC18XX_ADC_SAMPLE_MASK;
|
||||
}
|
||||
|
||||
static int lpc18xx_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct lpc18xx_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&adc->lock);
|
||||
*val = lpc18xx_adc_read_chan(adc, chan->channel);
|
||||
mutex_unlock(&adc->lock);
|
||||
if (*val < 0)
|
||||
return *val;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = regulator_get_voltage(adc->vref) / 1000;
|
||||
*val2 = 10;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info lpc18xx_adc_info = {
|
||||
.read_raw = lpc18xx_adc_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct lpc18xx_adc *adc;
|
||||
struct resource *res;
|
||||
unsigned int clkdiv;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
adc = iio_priv(indio_dev);
|
||||
adc->dev = &pdev->dev;
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
adc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(adc->clk)) {
|
||||
dev_err(&pdev->dev, "error getting clock\n");
|
||||
return PTR_ERR(adc->clk);
|
||||
}
|
||||
|
||||
rate = clk_get_rate(adc->clk);
|
||||
clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET);
|
||||
|
||||
adc->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(adc->vref)) {
|
||||
dev_err(&pdev->dev, "error getting regulator\n");
|
||||
return PTR_ERR(adc->vref);
|
||||
}
|
||||
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &lpc18xx_adc_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = lpc18xx_adc_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(lpc18xx_adc_iio_channels);
|
||||
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable regulator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable clock\n");
|
||||
goto dis_reg;
|
||||
}
|
||||
|
||||
adc->cr_reg = (clkdiv << LPC18XX_ADC_CR_CLKDIV_SHIFT) |
|
||||
LPC18XX_ADC_CR_PDN;
|
||||
writel(adc->cr_reg, adc->base + LPC18XX_ADC_CR);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
goto dis_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clk:
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
clk_disable_unprepare(adc->clk);
|
||||
dis_reg:
|
||||
regulator_disable(adc->vref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc18xx_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct lpc18xx_adc *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
clk_disable_unprepare(adc->clk);
|
||||
regulator_disable(adc->vref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_adc_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-adc" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_adc_match);
|
||||
|
||||
static struct platform_driver lpc18xx_adc_driver = {
|
||||
.probe = lpc18xx_adc_probe,
|
||||
.remove = lpc18xx_adc_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-adc",
|
||||
.of_match_table = lpc18xx_adc_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_adc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("LPC18xx ADC driver");
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -159,6 +159,22 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = {
|
|||
.clk_rate = 50000,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
|
||||
ADC_CHANNEL(0, "adc0"),
|
||||
ADC_CHANNEL(1, "adc1"),
|
||||
ADC_CHANNEL(2, "adc2"),
|
||||
ADC_CHANNEL(3, "adc3"),
|
||||
ADC_CHANNEL(4, "adc4"),
|
||||
ADC_CHANNEL(5, "adc5"),
|
||||
};
|
||||
|
||||
static const struct rockchip_saradc_data rk3399_saradc_data = {
|
||||
.num_bits = 10,
|
||||
.channels = rockchip_rk3399_saradc_iio_channels,
|
||||
.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
|
||||
.clk_rate = 1000000,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_saradc_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,saradc",
|
||||
|
@ -166,6 +182,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
|
|||
}, {
|
||||
.compatible = "rockchip,rk3066-tsadc",
|
||||
.data = &rk3066_tsadc_data,
|
||||
}, {
|
||||
.compatible = "rockchip,rk3399-saradc",
|
||||
.data = &rk3399_saradc_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
|
@ -24,19 +24,13 @@
|
|||
|
||||
int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
|
||||
{
|
||||
u8 *addr;
|
||||
u8 addr[3]; /* no ST sensor has more than 3 channels */
|
||||
int i, n = 0, len;
|
||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||
unsigned int num_data_channels = sdata->num_data_channels;
|
||||
unsigned int byte_for_channel =
|
||||
indio_dev->channels[0].scan_type.storagebits >> 3;
|
||||
|
||||
addr = kmalloc(num_data_channels, GFP_KERNEL);
|
||||
if (!addr) {
|
||||
len = -ENOMEM;
|
||||
goto st_sensors_get_buffer_element_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_data_channels; i++) {
|
||||
if (test_bit(i, indio_dev->active_scan_mask)) {
|
||||
addr[n] = indio_dev->channels[i].address;
|
||||
|
@ -57,10 +51,8 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
|
|||
u8 *rx_array;
|
||||
rx_array = kmalloc(byte_for_channel * num_data_channels,
|
||||
GFP_KERNEL);
|
||||
if (!rx_array) {
|
||||
len = -ENOMEM;
|
||||
goto st_sensors_free_memory;
|
||||
}
|
||||
if (!rx_array)
|
||||
return -ENOMEM;
|
||||
|
||||
len = sdata->tf->read_multiple_byte(&sdata->tb,
|
||||
sdata->dev, addr[0],
|
||||
|
@ -68,7 +60,7 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
|
|||
rx_array, sdata->multiread_bit);
|
||||
if (len < 0) {
|
||||
kfree(rx_array);
|
||||
goto st_sensors_free_memory;
|
||||
return len;
|
||||
}
|
||||
|
||||
for (i = 0; i < n * byte_for_channel; i++) {
|
||||
|
@ -87,17 +79,11 @@ int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
|
|||
buf, sdata->multiread_bit);
|
||||
break;
|
||||
default:
|
||||
len = -EINVAL;
|
||||
goto st_sensors_free_memory;
|
||||
}
|
||||
if (len != byte_for_channel * n) {
|
||||
len = -EIO;
|
||||
goto st_sensors_free_memory;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (len != byte_for_channel * n)
|
||||
return -EIO;
|
||||
|
||||
st_sensors_free_memory:
|
||||
kfree(addr);
|
||||
st_sensors_get_buffer_element_error:
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(st_sensors_get_buffer_element);
|
||||
|
|
|
@ -154,6 +154,16 @@ config AD7303
|
|||
To compile this driver as module choose M here: the module will be called
|
||||
ad7303.
|
||||
|
||||
config LPC18XX_DAC
|
||||
tristate "NXP LPC18xx DAC driver"
|
||||
depends on ARCH_LPC18XX || COMPILE_TEST
|
||||
depends on OF && HAS_IOMEM
|
||||
help
|
||||
Say yes here to build support for NXP LPC18XX DAC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called lpc18xx_dac.
|
||||
|
||||
config M62332
|
||||
tristate "Mitsubishi M62332 DAC driver"
|
||||
depends on I2C
|
||||
|
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
|
|||
obj-$(CONFIG_AD5791) += ad5791.o
|
||||
obj-$(CONFIG_AD5686) += ad5686.o
|
||||
obj-$(CONFIG_AD7303) += ad7303.o
|
||||
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
|
||||
obj-$(CONFIG_M62332) += m62332.o
|
||||
obj-$(CONFIG_MAX517) += max517.o
|
||||
obj-$(CONFIG_MAX5821) += max5821.o
|
||||
|
|
210
drivers/iio/dac/lpc18xx_dac.c
Normal file
210
drivers/iio/dac/lpc18xx_dac.c
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* IIO DAC driver for NXP LPC18xx DAC
|
||||
*
|
||||
* Copyright (C) 2016 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* UNSUPPORTED hardware features:
|
||||
* - Interrupts
|
||||
* - DMA
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* LPC18XX DAC registers and bits */
|
||||
#define LPC18XX_DAC_CR 0x000
|
||||
#define LPC18XX_DAC_CR_VALUE_SHIFT 6
|
||||
#define LPC18XX_DAC_CR_VALUE_MASK 0x3ff
|
||||
#define LPC18XX_DAC_CR_BIAS BIT(16)
|
||||
#define LPC18XX_DAC_CTRL 0x004
|
||||
#define LPC18XX_DAC_CTRL_DMA_ENA BIT(3)
|
||||
|
||||
struct lpc18xx_dac {
|
||||
struct regulator *vref;
|
||||
void __iomem *base;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec lpc18xx_dac_iio_channels[] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.output = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static int lpc18xx_dac_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct lpc18xx_dac *dac = iio_priv(indio_dev);
|
||||
u32 reg;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
reg = readl(dac->base + LPC18XX_DAC_CR);
|
||||
*val = reg >> LPC18XX_DAC_CR_VALUE_SHIFT;
|
||||
*val &= LPC18XX_DAC_CR_VALUE_MASK;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = regulator_get_voltage(dac->vref) / 1000;
|
||||
*val2 = 10;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int lpc18xx_dac_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct lpc18xx_dac *dac = iio_priv(indio_dev);
|
||||
u32 reg;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val < 0 || val > LPC18XX_DAC_CR_VALUE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
reg = LPC18XX_DAC_CR_BIAS;
|
||||
reg |= val << LPC18XX_DAC_CR_VALUE_SHIFT;
|
||||
|
||||
mutex_lock(&dac->lock);
|
||||
writel(reg, dac->base + LPC18XX_DAC_CR);
|
||||
writel(LPC18XX_DAC_CTRL_DMA_ENA, dac->base + LPC18XX_DAC_CTRL);
|
||||
mutex_unlock(&dac->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info lpc18xx_dac_info = {
|
||||
.read_raw = lpc18xx_dac_read_raw,
|
||||
.write_raw = lpc18xx_dac_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc18xx_dac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct lpc18xx_dac *dac;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
dac = iio_priv(indio_dev);
|
||||
mutex_init(&dac->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dac->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dac->base))
|
||||
return PTR_ERR(dac->base);
|
||||
|
||||
dac->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(dac->clk)) {
|
||||
dev_err(&pdev->dev, "error getting clock\n");
|
||||
return PTR_ERR(dac->clk);
|
||||
}
|
||||
|
||||
dac->vref = devm_regulator_get(&pdev->dev, "vref");
|
||||
if (IS_ERR(dac->vref)) {
|
||||
dev_err(&pdev->dev, "error getting regulator\n");
|
||||
return PTR_ERR(dac->vref);
|
||||
}
|
||||
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &lpc18xx_dac_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = lpc18xx_dac_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(lpc18xx_dac_iio_channels);
|
||||
|
||||
ret = regulator_enable(dac->vref);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable regulator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(dac->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable clock\n");
|
||||
goto dis_reg;
|
||||
}
|
||||
|
||||
writel(0, dac->base + LPC18XX_DAC_CTRL);
|
||||
writel(0, dac->base + LPC18XX_DAC_CR);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
goto dis_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clk:
|
||||
clk_disable_unprepare(dac->clk);
|
||||
dis_reg:
|
||||
regulator_disable(dac->vref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc18xx_dac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct lpc18xx_dac *dac = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
writel(0, dac->base + LPC18XX_DAC_CTRL);
|
||||
clk_disable_unprepare(dac->clk);
|
||||
regulator_disable(dac->vref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_dac_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-dac" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_dac_match);
|
||||
|
||||
static struct platform_driver lpc18xx_dac_driver = {
|
||||
.probe = lpc18xx_dac_probe,
|
||||
.remove = lpc18xx_dac_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-dac",
|
||||
.of_match_table = lpc18xx_dac_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_dac_driver);
|
||||
|
||||
MODULE_DESCRIPTION("LPC18xx DAC driver");
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -31,7 +30,6 @@
|
|||
#include "bmg160.h"
|
||||
|
||||
#define BMG160_IRQ_NAME "bmg160_event"
|
||||
#define BMG160_GPIO_NAME "gpio_int"
|
||||
|
||||
#define BMG160_REG_CHIP_ID 0x00
|
||||
#define BMG160_CHIP_ID_VAL 0x0F
|
||||
|
@ -116,6 +114,7 @@ enum bmg160_axis {
|
|||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_MAX,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
|
@ -733,6 +732,7 @@ static const struct iio_event_spec bmg160_event = {
|
|||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
.event_spec = &bmg160_event, \
|
||||
.num_event_specs = 1 \
|
||||
|
@ -763,26 +763,23 @@ static const struct iio_info bmg160_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long bmg160_accel_scan_masks[] = {
|
||||
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
|
||||
0};
|
||||
|
||||
static irqreturn_t bmg160_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct bmg160_data *data = iio_priv(indio_dev);
|
||||
int bit, ret, i = 0;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
indio_dev->masklength) {
|
||||
ret = regmap_bulk_read(data->regmap, BMG160_AXIS_TO_REG(bit),
|
||||
&val, 2);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->mutex);
|
||||
goto err;
|
||||
}
|
||||
data->buffer[i++] = ret;
|
||||
}
|
||||
ret = regmap_bulk_read(data->regmap, BMG160_REG_XOUT_L,
|
||||
data->buffer, AXIS_MAX * 2);
|
||||
mutex_unlock(&data->mutex);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
pf->timestamp);
|
||||
|
@ -955,29 +952,6 @@ static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
|
|||
.postdisable = bmg160_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int bmg160_gpio_probe(struct bmg160_data *data)
|
||||
|
||||
{
|
||||
struct device *dev;
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
dev = data->dev;
|
||||
|
||||
/* data ready gpio interrupt pin */
|
||||
gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(dev, "acpi gpio get index failed\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
data->irq = gpiod_to_irq(gpio);
|
||||
|
||||
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio),
|
||||
data->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *bmg160_match_acpi_device(struct device *dev)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
@ -1019,12 +993,10 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
indio_dev->channels = bmg160_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(bmg160_channels);
|
||||
indio_dev->name = name;
|
||||
indio_dev->available_scan_masks = bmg160_accel_scan_masks;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &bmg160_info;
|
||||
|
||||
if (data->irq <= 0)
|
||||
bmg160_gpio_probe(data);
|
||||
|
||||
if (data->irq > 0) {
|
||||
ret = devm_request_threaded_irq(dev,
|
||||
data->irq,
|
||||
|
|
|
@ -104,6 +104,19 @@ static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *inv_mpu_match_acpi_device(struct device *dev, int *chip_id)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return NULL;
|
||||
|
||||
*chip_id = (int)id->driver_data;
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* inv_mpu_probe() - probe function.
|
||||
* @client: i2c client.
|
||||
|
@ -115,14 +128,25 @@ static int inv_mpu_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct inv_mpu6050_state *st;
|
||||
int result;
|
||||
const char *name = id ? id->name : NULL;
|
||||
int result, chip_type;
|
||||
struct regmap *regmap;
|
||||
const char *name;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (id) {
|
||||
chip_type = (int)id->driver_data;
|
||||
name = id->name;
|
||||
} else if (ACPI_HANDLE(&client->dev)) {
|
||||
name = inv_mpu_match_acpi_device(&client->dev, &chip_type);
|
||||
if (!name)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
|
||||
|
@ -131,7 +155,7 @@ static int inv_mpu_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
result = inv_mpu_core_probe(regmap, client->irq, name,
|
||||
NULL, id->driver_data);
|
||||
NULL, chip_type);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ static int inv_mpu_probe(struct spi_device *spi)
|
|||
struct regmap *regmap;
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
const char *name = id ? id->name : NULL;
|
||||
const int chip_type = id ? id->driver_data : 0;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
|
@ -55,7 +56,7 @@ static int inv_mpu_probe(struct spi_device *spi)
|
|||
}
|
||||
|
||||
return inv_mpu_core_probe(regmap, spi->irq, name,
|
||||
inv_mpu_i2c_disable, id->driver_data);
|
||||
inv_mpu_i2c_disable, chip_type);
|
||||
}
|
||||
|
||||
static int inv_mpu_remove(struct spi_device *spi)
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include "iio_core.h"
|
||||
#include "iio_core_trigger.h"
|
||||
|
@ -78,6 +79,7 @@ static const char * const iio_chan_type_name_spec[] = {
|
|||
[IIO_CONCENTRATION] = "concentration",
|
||||
[IIO_RESISTANCE] = "resistance",
|
||||
[IIO_PH] = "ph",
|
||||
[IIO_UVINDEX] = "uvindex",
|
||||
};
|
||||
|
||||
static const char * const iio_modifier_names[] = {
|
||||
|
@ -100,6 +102,7 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_LIGHT_RED] = "red",
|
||||
[IIO_MOD_LIGHT_GREEN] = "green",
|
||||
[IIO_MOD_LIGHT_BLUE] = "blue",
|
||||
[IIO_MOD_LIGHT_UV] = "uv",
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
|
@ -1375,6 +1378,44 @@ void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(devm_iio_device_unregister);
|
||||
|
||||
/**
|
||||
* iio_device_claim_direct_mode - Keep device in direct mode
|
||||
* @indio_dev: the iio_dev associated with the device
|
||||
*
|
||||
* If the device is in direct mode it is guaranteed to stay
|
||||
* that way until iio_device_release_direct_mode() is called.
|
||||
*
|
||||
* Use with iio_device_release_direct_mode()
|
||||
*
|
||||
* Returns: 0 on success, -EBUSY on failure
|
||||
*/
|
||||
int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
|
||||
{
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
|
||||
|
||||
/**
|
||||
* iio_device_release_direct_mode - releases claim on direct mode
|
||||
* @indio_dev: the iio_dev associated with the device
|
||||
*
|
||||
* Release the claim. Device is no longer guaranteed to stay
|
||||
* in direct mode.
|
||||
*
|
||||
* Use with iio_device_claim_direct_mode()
|
||||
*/
|
||||
void iio_device_release_direct_mode(struct iio_dev *indio_dev)
|
||||
{
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
|
||||
|
||||
subsys_initcall(iio_init);
|
||||
module_exit(iio_exit);
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
|
|
@ -806,8 +806,7 @@ static int tsl2563_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
cancel_delayed_work(&chip->poweroff_work);
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&chip->poweroff_work);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
@ -361,7 +362,6 @@ static const struct ak_def ak_def_array[AK_MAX_TYPE] = {
|
|||
struct ak8975_data {
|
||||
struct i2c_client *client;
|
||||
const struct ak_def *def;
|
||||
struct attribute_group attrs;
|
||||
struct mutex lock;
|
||||
u8 asa[3];
|
||||
long raw_to_gauss[3];
|
||||
|
@ -370,8 +370,40 @@ struct ak8975_data {
|
|||
wait_queue_head_t data_ready_queue;
|
||||
unsigned long flags;
|
||||
u8 cntl_cache;
|
||||
struct regulator *vdd;
|
||||
};
|
||||
|
||||
/* Enable attached power regulator if any. */
|
||||
static int ak8975_power_on(struct i2c_client *client)
|
||||
{
|
||||
const struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ak8975_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
data->vdd = devm_regulator_get(&client->dev, "vdd");
|
||||
if (IS_ERR_OR_NULL(data->vdd)) {
|
||||
ret = PTR_ERR(data->vdd);
|
||||
if (ret == -ENODEV)
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = regulator_enable(data->vdd);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(&client->dev, "failed to enable Vdd supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Disable attached power regulator if any. */
|
||||
static void ak8975_power_off(const struct i2c_client *client)
|
||||
{
|
||||
const struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
const struct ak8975_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(data->vdd))
|
||||
regulator_disable(data->vdd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 if the i2c device is the one we expect.
|
||||
* return a negative error number otherwise
|
||||
|
@ -774,8 +806,11 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
if (id) {
|
||||
chipset = (enum asahi_compass_chipset)(id->driver_data);
|
||||
name = id->name;
|
||||
} else if (ACPI_HANDLE(&client->dev))
|
||||
} else if (ACPI_HANDLE(&client->dev)) {
|
||||
name = ak8975_match_acpi_device(&client->dev, &chipset);
|
||||
if (!name)
|
||||
return -ENODEV;
|
||||
}
|
||||
else
|
||||
return -ENOSYS;
|
||||
|
||||
|
@ -786,10 +821,15 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
data->def = &ak_def_array[chipset];
|
||||
|
||||
err = ak8975_power_on(client);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ak8975_who_i_am(client, data->def->type);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unexpected device\n");
|
||||
return err;
|
||||
goto power_off;
|
||||
}
|
||||
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
|
||||
|
||||
|
@ -797,7 +837,7 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
err = ak8975_setup(client);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "%s initialization fails\n", name);
|
||||
return err;
|
||||
goto power_off;
|
||||
}
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
@ -807,7 +847,26 @@ static int ak8975_probe(struct i2c_client *client,
|
|||
indio_dev->info = &ak8975_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->name = name;
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err)
|
||||
goto power_off;
|
||||
|
||||
return 0;
|
||||
|
||||
power_off:
|
||||
ak8975_power_off(client);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ak8975_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
ak8975_power_off(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak8975_id[] = {
|
||||
|
@ -841,6 +900,7 @@ static struct i2c_driver ak8975_driver = {
|
|||
.acpi_match_table = ACPI_PTR(ak_acpi_match),
|
||||
},
|
||||
.probe = ak8975_probe,
|
||||
.remove = ak8975_remove,
|
||||
.id_table = ak8975_id,
|
||||
};
|
||||
module_i2c_driver(ak8975_driver);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iio/iio.h>
|
||||
|
|
|
@ -5,6 +5,24 @@
|
|||
|
||||
menu "Digital potentiometers"
|
||||
|
||||
config MCP4131
|
||||
tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver"
|
||||
depends on SPI
|
||||
help
|
||||
Say yes here to build support for the Microchip
|
||||
MCP4131, MCP4132,
|
||||
MCP4141, MCP4142,
|
||||
MCP4151, MCP4152,
|
||||
MCP4161, MCP4162,
|
||||
MCP4231, MCP4232,
|
||||
MCP4241, MCP4242,
|
||||
MCP4251, MCP4252,
|
||||
MCP4261, MCP4262,
|
||||
digital potentiomenter chips.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mcp4131.
|
||||
|
||||
config MCP4531
|
||||
tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
|
||||
depends on I2C
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_MCP4131) += mcp4131.o
|
||||
obj-$(CONFIG_MCP4531) += mcp4531.o
|
||||
obj-$(CONFIG_TPL0102) += tpl0102.o
|
||||
|
|
494
drivers/iio/potentiometer/mcp4131.c
Normal file
494
drivers/iio/potentiometer/mcp4131.c
Normal file
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* Industrial I/O driver for Microchip digital potentiometers
|
||||
*
|
||||
* Copyright (c) 2016 Slawomir Stepien
|
||||
* Based on: Peter Rosin's code from mcp4531.c
|
||||
*
|
||||
* Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/22060b.pdf
|
||||
*
|
||||
* DEVID #Wipers #Positions Resistor Opts (kOhm)
|
||||
* mcp4131 1 129 5, 10, 50, 100
|
||||
* mcp4132 1 129 5, 10, 50, 100
|
||||
* mcp4141 1 129 5, 10, 50, 100
|
||||
* mcp4142 1 129 5, 10, 50, 100
|
||||
* mcp4151 1 257 5, 10, 50, 100
|
||||
* mcp4152 1 257 5, 10, 50, 100
|
||||
* mcp4161 1 257 5, 10, 50, 100
|
||||
* mcp4162 1 257 5, 10, 50, 100
|
||||
* mcp4231 2 129 5, 10, 50, 100
|
||||
* mcp4232 2 129 5, 10, 50, 100
|
||||
* mcp4241 2 129 5, 10, 50, 100
|
||||
* mcp4242 2 129 5, 10, 50, 100
|
||||
* mcp4251 2 257 5, 10, 50, 100
|
||||
* mcp4252 2 257 5, 10, 50, 100
|
||||
* mcp4261 2 257 5, 10, 50, 100
|
||||
* mcp4262 2 257 5, 10, 50, 100
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* 1. Write wiper setting to EEPROM for EEPROM capable models.
|
||||
*/
|
||||
|
||||
#include <linux/cache.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define MCP4131_WRITE (0x00 << 2)
|
||||
#define MCP4131_READ (0x03 << 2)
|
||||
|
||||
#define MCP4131_WIPER_SHIFT 4
|
||||
#define MCP4131_CMDERR(r) ((r[0]) & 0x02)
|
||||
#define MCP4131_RAW(r) ((r[0]) == 0xff ? 0x100 : (r[1]))
|
||||
|
||||
struct mcp4131_cfg {
|
||||
int wipers;
|
||||
int max_pos;
|
||||
int kohms;
|
||||
};
|
||||
|
||||
enum mcp4131_type {
|
||||
MCP413x_502 = 0,
|
||||
MCP413x_103,
|
||||
MCP413x_503,
|
||||
MCP413x_104,
|
||||
MCP414x_502,
|
||||
MCP414x_103,
|
||||
MCP414x_503,
|
||||
MCP414x_104,
|
||||
MCP415x_502,
|
||||
MCP415x_103,
|
||||
MCP415x_503,
|
||||
MCP415x_104,
|
||||
MCP416x_502,
|
||||
MCP416x_103,
|
||||
MCP416x_503,
|
||||
MCP416x_104,
|
||||
MCP423x_502,
|
||||
MCP423x_103,
|
||||
MCP423x_503,
|
||||
MCP423x_104,
|
||||
MCP424x_502,
|
||||
MCP424x_103,
|
||||
MCP424x_503,
|
||||
MCP424x_104,
|
||||
MCP425x_502,
|
||||
MCP425x_103,
|
||||
MCP425x_503,
|
||||
MCP425x_104,
|
||||
MCP426x_502,
|
||||
MCP426x_103,
|
||||
MCP426x_503,
|
||||
MCP426x_104,
|
||||
};
|
||||
|
||||
static const struct mcp4131_cfg mcp4131_cfg[] = {
|
||||
[MCP413x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
|
||||
[MCP413x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
|
||||
[MCP413x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
|
||||
[MCP413x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
|
||||
[MCP414x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
|
||||
[MCP414x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
|
||||
[MCP414x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
|
||||
[MCP414x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
|
||||
[MCP415x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
|
||||
[MCP415x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
|
||||
[MCP415x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
|
||||
[MCP415x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
|
||||
[MCP416x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
|
||||
[MCP416x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
|
||||
[MCP416x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
|
||||
[MCP416x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
|
||||
[MCP423x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
|
||||
[MCP423x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
|
||||
[MCP423x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
|
||||
[MCP423x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
|
||||
[MCP424x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
|
||||
[MCP424x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
|
||||
[MCP424x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
|
||||
[MCP424x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
|
||||
[MCP425x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
|
||||
[MCP425x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
|
||||
[MCP425x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
|
||||
[MCP425x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
|
||||
[MCP426x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
|
||||
[MCP426x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
|
||||
[MCP426x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
|
||||
[MCP426x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
|
||||
};
|
||||
|
||||
struct mcp4131_data {
|
||||
struct spi_device *spi;
|
||||
const struct mcp4131_cfg *cfg;
|
||||
struct mutex lock;
|
||||
u8 buf[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#define MCP4131_CHANNEL(ch) { \
|
||||
.type = IIO_RESISTANCE, \
|
||||
.indexed = 1, \
|
||||
.output = 1, \
|
||||
.channel = (ch), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mcp4131_channels[] = {
|
||||
MCP4131_CHANNEL(0),
|
||||
MCP4131_CHANNEL(1),
|
||||
};
|
||||
|
||||
static int mcp4131_read(struct spi_device *spi, void *buf, size_t len)
|
||||
{
|
||||
struct spi_transfer t = {
|
||||
.tx_buf = buf, /* We need to send addr, cmd and 12 bits */
|
||||
.rx_buf = buf,
|
||||
.len = len,
|
||||
};
|
||||
struct spi_message m;
|
||||
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
return spi_sync(spi, &m);
|
||||
}
|
||||
|
||||
static int mcp4131_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
int err;
|
||||
struct mcp4131_data *data = iio_priv(indio_dev);
|
||||
int address = chan->channel;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
data->buf[0] = (address << MCP4131_WIPER_SHIFT) | MCP4131_READ;
|
||||
data->buf[1] = 0;
|
||||
|
||||
err = mcp4131_read(data->spi, data->buf, 2);
|
||||
if (err) {
|
||||
mutex_unlock(&data->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Error, bad address/command combination */
|
||||
if (!MCP4131_CMDERR(data->buf)) {
|
||||
mutex_unlock(&data->lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*val = MCP4131_RAW(data->buf);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 1000 * data->cfg->kohms;
|
||||
*val2 = data->cfg->max_pos;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mcp4131_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int err;
|
||||
struct mcp4131_data *data = iio_priv(indio_dev);
|
||||
int address = chan->channel << MCP4131_WIPER_SHIFT;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val > data->cfg->max_pos || val < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
data->buf[0] = address << MCP4131_WIPER_SHIFT;
|
||||
data->buf[0] |= MCP4131_WRITE | (val >> 8);
|
||||
data->buf[1] = val & 0xFF; /* 8 bits here */
|
||||
|
||||
err = spi_write(data->spi, data->buf, 2);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct iio_info mcp4131_info = {
|
||||
.read_raw = mcp4131_read_raw,
|
||||
.write_raw = mcp4131_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int mcp4131_probe(struct spi_device *spi)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = &spi->dev;
|
||||
unsigned long devid = spi_get_device_id(spi)->driver_data;
|
||||
struct mcp4131_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
data->spi = spi;
|
||||
data->cfg = &mcp4131_cfg[devid];
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &mcp4131_info;
|
||||
indio_dev->channels = mcp4131_channels;
|
||||
indio_dev->num_channels = data->cfg->wipers;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
|
||||
err = devm_iio_device_register(dev, indio_dev);
|
||||
if (err) {
|
||||
dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id mcp4131_dt_ids[] = {
|
||||
{ .compatible = "microchip,mcp4131-502",
|
||||
.data = &mcp4131_cfg[MCP413x_502] },
|
||||
{ .compatible = "microchip,mcp4131-103",
|
||||
.data = &mcp4131_cfg[MCP413x_103] },
|
||||
{ .compatible = "microchip,mcp4131-503",
|
||||
.data = &mcp4131_cfg[MCP413x_503] },
|
||||
{ .compatible = "microchip,mcp4131-104",
|
||||
.data = &mcp4131_cfg[MCP413x_104] },
|
||||
{ .compatible = "microchip,mcp4132-502",
|
||||
.data = &mcp4131_cfg[MCP413x_502] },
|
||||
{ .compatible = "microchip,mcp4132-103",
|
||||
.data = &mcp4131_cfg[MCP413x_103] },
|
||||
{ .compatible = "microchip,mcp4132-503",
|
||||
.data = &mcp4131_cfg[MCP413x_503] },
|
||||
{ .compatible = "microchip,mcp4132-104",
|
||||
.data = &mcp4131_cfg[MCP413x_104] },
|
||||
{ .compatible = "microchip,mcp4141-502",
|
||||
.data = &mcp4131_cfg[MCP414x_502] },
|
||||
{ .compatible = "microchip,mcp4141-103",
|
||||
.data = &mcp4131_cfg[MCP414x_103] },
|
||||
{ .compatible = "microchip,mcp4141-503",
|
||||
.data = &mcp4131_cfg[MCP414x_503] },
|
||||
{ .compatible = "microchip,mcp4141-104",
|
||||
.data = &mcp4131_cfg[MCP414x_104] },
|
||||
{ .compatible = "microchip,mcp4142-502",
|
||||
.data = &mcp4131_cfg[MCP414x_502] },
|
||||
{ .compatible = "microchip,mcp4142-103",
|
||||
.data = &mcp4131_cfg[MCP414x_103] },
|
||||
{ .compatible = "microchip,mcp4142-503",
|
||||
.data = &mcp4131_cfg[MCP414x_503] },
|
||||
{ .compatible = "microchip,mcp4142-104",
|
||||
.data = &mcp4131_cfg[MCP414x_104] },
|
||||
{ .compatible = "microchip,mcp4151-502",
|
||||
.data = &mcp4131_cfg[MCP415x_502] },
|
||||
{ .compatible = "microchip,mcp4151-103",
|
||||
.data = &mcp4131_cfg[MCP415x_103] },
|
||||
{ .compatible = "microchip,mcp4151-503",
|
||||
.data = &mcp4131_cfg[MCP415x_503] },
|
||||
{ .compatible = "microchip,mcp4151-104",
|
||||
.data = &mcp4131_cfg[MCP415x_104] },
|
||||
{ .compatible = "microchip,mcp4152-502",
|
||||
.data = &mcp4131_cfg[MCP415x_502] },
|
||||
{ .compatible = "microchip,mcp4152-103",
|
||||
.data = &mcp4131_cfg[MCP415x_103] },
|
||||
{ .compatible = "microchip,mcp4152-503",
|
||||
.data = &mcp4131_cfg[MCP415x_503] },
|
||||
{ .compatible = "microchip,mcp4152-104",
|
||||
.data = &mcp4131_cfg[MCP415x_104] },
|
||||
{ .compatible = "microchip,mcp4161-502",
|
||||
.data = &mcp4131_cfg[MCP416x_502] },
|
||||
{ .compatible = "microchip,mcp4161-103",
|
||||
.data = &mcp4131_cfg[MCP416x_103] },
|
||||
{ .compatible = "microchip,mcp4161-503",
|
||||
.data = &mcp4131_cfg[MCP416x_503] },
|
||||
{ .compatible = "microchip,mcp4161-104",
|
||||
.data = &mcp4131_cfg[MCP416x_104] },
|
||||
{ .compatible = "microchip,mcp4162-502",
|
||||
.data = &mcp4131_cfg[MCP416x_502] },
|
||||
{ .compatible = "microchip,mcp4162-103",
|
||||
.data = &mcp4131_cfg[MCP416x_103] },
|
||||
{ .compatible = "microchip,mcp4162-503",
|
||||
.data = &mcp4131_cfg[MCP416x_503] },
|
||||
{ .compatible = "microchip,mcp4162-104",
|
||||
.data = &mcp4131_cfg[MCP416x_104] },
|
||||
{ .compatible = "microchip,mcp4231-502",
|
||||
.data = &mcp4131_cfg[MCP423x_502] },
|
||||
{ .compatible = "microchip,mcp4231-103",
|
||||
.data = &mcp4131_cfg[MCP423x_103] },
|
||||
{ .compatible = "microchip,mcp4231-503",
|
||||
.data = &mcp4131_cfg[MCP423x_503] },
|
||||
{ .compatible = "microchip,mcp4231-104",
|
||||
.data = &mcp4131_cfg[MCP423x_104] },
|
||||
{ .compatible = "microchip,mcp4232-502",
|
||||
.data = &mcp4131_cfg[MCP423x_502] },
|
||||
{ .compatible = "microchip,mcp4232-103",
|
||||
.data = &mcp4131_cfg[MCP423x_103] },
|
||||
{ .compatible = "microchip,mcp4232-503",
|
||||
.data = &mcp4131_cfg[MCP423x_503] },
|
||||
{ .compatible = "microchip,mcp4232-104",
|
||||
.data = &mcp4131_cfg[MCP423x_104] },
|
||||
{ .compatible = "microchip,mcp4241-502",
|
||||
.data = &mcp4131_cfg[MCP424x_502] },
|
||||
{ .compatible = "microchip,mcp4241-103",
|
||||
.data = &mcp4131_cfg[MCP424x_103] },
|
||||
{ .compatible = "microchip,mcp4241-503",
|
||||
.data = &mcp4131_cfg[MCP424x_503] },
|
||||
{ .compatible = "microchip,mcp4241-104",
|
||||
.data = &mcp4131_cfg[MCP424x_104] },
|
||||
{ .compatible = "microchip,mcp4242-502",
|
||||
.data = &mcp4131_cfg[MCP424x_502] },
|
||||
{ .compatible = "microchip,mcp4242-103",
|
||||
.data = &mcp4131_cfg[MCP424x_103] },
|
||||
{ .compatible = "microchip,mcp4242-503",
|
||||
.data = &mcp4131_cfg[MCP424x_503] },
|
||||
{ .compatible = "microchip,mcp4242-104",
|
||||
.data = &mcp4131_cfg[MCP424x_104] },
|
||||
{ .compatible = "microchip,mcp4251-502",
|
||||
.data = &mcp4131_cfg[MCP425x_502] },
|
||||
{ .compatible = "microchip,mcp4251-103",
|
||||
.data = &mcp4131_cfg[MCP425x_103] },
|
||||
{ .compatible = "microchip,mcp4251-503",
|
||||
.data = &mcp4131_cfg[MCP425x_503] },
|
||||
{ .compatible = "microchip,mcp4251-104",
|
||||
.data = &mcp4131_cfg[MCP425x_104] },
|
||||
{ .compatible = "microchip,mcp4252-502",
|
||||
.data = &mcp4131_cfg[MCP425x_502] },
|
||||
{ .compatible = "microchip,mcp4252-103",
|
||||
.data = &mcp4131_cfg[MCP425x_103] },
|
||||
{ .compatible = "microchip,mcp4252-503",
|
||||
.data = &mcp4131_cfg[MCP425x_503] },
|
||||
{ .compatible = "microchip,mcp4252-104",
|
||||
.data = &mcp4131_cfg[MCP425x_104] },
|
||||
{ .compatible = "microchip,mcp4261-502",
|
||||
.data = &mcp4131_cfg[MCP426x_502] },
|
||||
{ .compatible = "microchip,mcp4261-103",
|
||||
.data = &mcp4131_cfg[MCP426x_103] },
|
||||
{ .compatible = "microchip,mcp4261-503",
|
||||
.data = &mcp4131_cfg[MCP426x_503] },
|
||||
{ .compatible = "microchip,mcp4261-104",
|
||||
.data = &mcp4131_cfg[MCP426x_104] },
|
||||
{ .compatible = "microchip,mcp4262-502",
|
||||
.data = &mcp4131_cfg[MCP426x_502] },
|
||||
{ .compatible = "microchip,mcp4262-103",
|
||||
.data = &mcp4131_cfg[MCP426x_103] },
|
||||
{ .compatible = "microchip,mcp4262-503",
|
||||
.data = &mcp4131_cfg[MCP426x_503] },
|
||||
{ .compatible = "microchip,mcp4262-104",
|
||||
.data = &mcp4131_cfg[MCP426x_104] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static const struct spi_device_id mcp4131_id[] = {
|
||||
{ "mcp4131-502", MCP413x_502 },
|
||||
{ "mcp4131-103", MCP413x_103 },
|
||||
{ "mcp4131-503", MCP413x_503 },
|
||||
{ "mcp4131-104", MCP413x_104 },
|
||||
{ "mcp4132-502", MCP413x_502 },
|
||||
{ "mcp4132-103", MCP413x_103 },
|
||||
{ "mcp4132-503", MCP413x_503 },
|
||||
{ "mcp4132-104", MCP413x_104 },
|
||||
{ "mcp4141-502", MCP414x_502 },
|
||||
{ "mcp4141-103", MCP414x_103 },
|
||||
{ "mcp4141-503", MCP414x_503 },
|
||||
{ "mcp4141-104", MCP414x_104 },
|
||||
{ "mcp4142-502", MCP414x_502 },
|
||||
{ "mcp4142-103", MCP414x_103 },
|
||||
{ "mcp4142-503", MCP414x_503 },
|
||||
{ "mcp4142-104", MCP414x_104 },
|
||||
{ "mcp4151-502", MCP415x_502 },
|
||||
{ "mcp4151-103", MCP415x_103 },
|
||||
{ "mcp4151-503", MCP415x_503 },
|
||||
{ "mcp4151-104", MCP415x_104 },
|
||||
{ "mcp4152-502", MCP415x_502 },
|
||||
{ "mcp4152-103", MCP415x_103 },
|
||||
{ "mcp4152-503", MCP415x_503 },
|
||||
{ "mcp4152-104", MCP415x_104 },
|
||||
{ "mcp4161-502", MCP416x_502 },
|
||||
{ "mcp4161-103", MCP416x_103 },
|
||||
{ "mcp4161-503", MCP416x_503 },
|
||||
{ "mcp4161-104", MCP416x_104 },
|
||||
{ "mcp4162-502", MCP416x_502 },
|
||||
{ "mcp4162-103", MCP416x_103 },
|
||||
{ "mcp4162-503", MCP416x_503 },
|
||||
{ "mcp4162-104", MCP416x_104 },
|
||||
{ "mcp4231-502", MCP423x_502 },
|
||||
{ "mcp4231-103", MCP423x_103 },
|
||||
{ "mcp4231-503", MCP423x_503 },
|
||||
{ "mcp4231-104", MCP423x_104 },
|
||||
{ "mcp4232-502", MCP423x_502 },
|
||||
{ "mcp4232-103", MCP423x_103 },
|
||||
{ "mcp4232-503", MCP423x_503 },
|
||||
{ "mcp4232-104", MCP423x_104 },
|
||||
{ "mcp4241-502", MCP424x_502 },
|
||||
{ "mcp4241-103", MCP424x_103 },
|
||||
{ "mcp4241-503", MCP424x_503 },
|
||||
{ "mcp4241-104", MCP424x_104 },
|
||||
{ "mcp4242-502", MCP424x_502 },
|
||||
{ "mcp4242-103", MCP424x_103 },
|
||||
{ "mcp4242-503", MCP424x_503 },
|
||||
{ "mcp4242-104", MCP424x_104 },
|
||||
{ "mcp4251-502", MCP425x_502 },
|
||||
{ "mcp4251-103", MCP425x_103 },
|
||||
{ "mcp4251-503", MCP425x_503 },
|
||||
{ "mcp4251-104", MCP425x_104 },
|
||||
{ "mcp4252-502", MCP425x_502 },
|
||||
{ "mcp4252-103", MCP425x_103 },
|
||||
{ "mcp4252-503", MCP425x_503 },
|
||||
{ "mcp4252-104", MCP425x_104 },
|
||||
{ "mcp4261-502", MCP426x_502 },
|
||||
{ "mcp4261-103", MCP426x_103 },
|
||||
{ "mcp4261-503", MCP426x_503 },
|
||||
{ "mcp4261-104", MCP426x_104 },
|
||||
{ "mcp4262-502", MCP426x_502 },
|
||||
{ "mcp4262-103", MCP426x_103 },
|
||||
{ "mcp4262-503", MCP426x_503 },
|
||||
{ "mcp4262-104", MCP426x_104 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, mcp4131_id);
|
||||
|
||||
static struct spi_driver mcp4131_driver = {
|
||||
.driver = {
|
||||
.name = "mcp4131",
|
||||
.of_match_table = of_match_ptr(mcp4131_dt_ids),
|
||||
},
|
||||
.probe = mcp4131_probe,
|
||||
.id_table = mcp4131_id,
|
||||
};
|
||||
|
||||
module_spi_driver(mcp4131_driver);
|
||||
|
||||
MODULE_AUTHOR("Slawomir Stepien <sst@poczta.fm>");
|
||||
MODULE_DESCRIPTION("MCP4131 digital potentiometer");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -79,7 +79,7 @@ static const struct mcp4531_cfg mcp4531_cfg[] = {
|
|||
|
||||
struct mcp4531_data {
|
||||
struct i2c_client *client;
|
||||
unsigned long devid;
|
||||
const struct mcp4531_cfg *cfg;
|
||||
};
|
||||
|
||||
#define MCP4531_CHANNEL(ch) { \
|
||||
|
@ -113,8 +113,8 @@ static int mcp4531_read_raw(struct iio_dev *indio_dev,
|
|||
*val = ret;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 1000 * mcp4531_cfg[data->devid].kohms;
|
||||
*val2 = mcp4531_cfg[data->devid].max_pos;
|
||||
*val = 1000 * data->cfg->kohms;
|
||||
*val2 = data->cfg->max_pos;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ static int mcp4531_write_raw(struct iio_dev *indio_dev,
|
|||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
|
||||
if (val > data->cfg->max_pos || val < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
|
@ -152,7 +152,6 @@ static int mcp4531_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
unsigned long devid = id->driver_data;
|
||||
struct mcp4531_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
|
@ -168,12 +167,12 @@ static int mcp4531_probe(struct i2c_client *client,
|
|||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->devid = devid;
|
||||
data->cfg = &mcp4531_cfg[id->driver_data];
|
||||
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->info = &mcp4531_info;
|
||||
indio_dev->channels = mcp4531_channels;
|
||||
indio_dev->num_channels = mcp4531_cfg[devid].wipers;
|
||||
indio_dev->num_channels = data->cfg->wipers;
|
||||
indio_dev->name = client->name;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
|
|
|
@ -118,7 +118,7 @@ static int tpl0102_probe(struct i2c_client *client,
|
|||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
|
|
|
@ -148,4 +148,14 @@ config T5403
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called t5403.
|
||||
|
||||
config HP206C
|
||||
tristate "HOPERF HP206C precision barometer and altimeter sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for the HOPREF HP206C precision
|
||||
barometer and altimeter sensor.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called hp206c.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -17,6 +17,7 @@ obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
|
|||
st_pressure-y := st_pressure_core.o
|
||||
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
|
||||
obj-$(CONFIG_T5403) += t5403.o
|
||||
obj-$(CONFIG_HP206C) += hp206c.o
|
||||
|
||||
obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o
|
||||
|
|
426
drivers/iio/pressure/hp206c.c
Normal file
426
drivers/iio/pressure/hp206c.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* hp206c.c - HOPERF HP206C precision barometer and altimeter sensor
|
||||
*
|
||||
* Copyright (c) 2016, Intel Corporation.
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* (7-bit I2C slave address 0x76)
|
||||
*
|
||||
* Datasheet:
|
||||
* http://www.hoperf.com/upload/sensor/HP206C_DataSheet_EN_V2.0.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/util_macros.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
/* I2C commands: */
|
||||
#define HP206C_CMD_SOFT_RST 0x06
|
||||
|
||||
#define HP206C_CMD_ADC_CVT 0x40
|
||||
|
||||
#define HP206C_CMD_ADC_CVT_OSR_4096 0x00
|
||||
#define HP206C_CMD_ADC_CVT_OSR_2048 0x04
|
||||
#define HP206C_CMD_ADC_CVT_OSR_1024 0x08
|
||||
#define HP206C_CMD_ADC_CVT_OSR_512 0x0c
|
||||
#define HP206C_CMD_ADC_CVT_OSR_256 0x10
|
||||
#define HP206C_CMD_ADC_CVT_OSR_128 0x14
|
||||
|
||||
#define HP206C_CMD_ADC_CVT_CHNL_PT 0x00
|
||||
#define HP206C_CMD_ADC_CVT_CHNL_T 0x02
|
||||
|
||||
#define HP206C_CMD_READ_P 0x30
|
||||
#define HP206C_CMD_READ_T 0x32
|
||||
|
||||
#define HP206C_CMD_READ_REG 0x80
|
||||
#define HP206C_CMD_WRITE_REG 0xc0
|
||||
|
||||
#define HP206C_REG_INT_EN 0x0b
|
||||
#define HP206C_REG_INT_CFG 0x0c
|
||||
|
||||
#define HP206C_REG_INT_SRC 0x0d
|
||||
#define HP206C_FLAG_DEV_RDY 0x40
|
||||
|
||||
#define HP206C_REG_PARA 0x0f
|
||||
#define HP206C_FLAG_CMPS_EN 0x80
|
||||
|
||||
/* Maximum spin for DEV_RDY */
|
||||
#define HP206C_MAX_DEV_RDY_WAIT_COUNT 20
|
||||
#define HP206C_DEV_RDY_WAIT_US 20000
|
||||
|
||||
struct hp206c_data {
|
||||
struct mutex mutex;
|
||||
struct i2c_client *client;
|
||||
int temp_osr_index;
|
||||
int pres_osr_index;
|
||||
};
|
||||
|
||||
struct hp206c_osr_setting {
|
||||
u8 osr_mask;
|
||||
unsigned int temp_conv_time_us;
|
||||
unsigned int pres_conv_time_us;
|
||||
};
|
||||
|
||||
/* Data from Table 5 in datasheet. */
|
||||
static const struct hp206c_osr_setting hp206c_osr_settings[] = {
|
||||
{ HP206C_CMD_ADC_CVT_OSR_4096, 65600, 131100 },
|
||||
{ HP206C_CMD_ADC_CVT_OSR_2048, 32800, 65600 },
|
||||
{ HP206C_CMD_ADC_CVT_OSR_1024, 16400, 32800 },
|
||||
{ HP206C_CMD_ADC_CVT_OSR_512, 8200, 16400 },
|
||||
{ HP206C_CMD_ADC_CVT_OSR_256, 4100, 8200 },
|
||||
{ HP206C_CMD_ADC_CVT_OSR_128, 2100, 4100 },
|
||||
};
|
||||
static const int hp206c_osr_rates[] = { 4096, 2048, 1024, 512, 256, 128 };
|
||||
static const char hp206c_osr_rates_str[] = "4096 2048 1024 512 256 128";
|
||||
|
||||
static inline int hp206c_read_reg(struct i2c_client *client, u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, HP206C_CMD_READ_REG | reg);
|
||||
}
|
||||
|
||||
static inline int hp206c_write_reg(struct i2c_client *client, u8 reg, u8 val)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client,
|
||||
HP206C_CMD_WRITE_REG | reg, val);
|
||||
}
|
||||
|
||||
static int hp206c_read_20bit(struct i2c_client *client, u8 cmd)
|
||||
{
|
||||
int ret;
|
||||
u8 values[3];
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, cmd, 3, values);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret != 3)
|
||||
return -EIO;
|
||||
return ((values[0] & 0xF) << 16) | (values[1] << 8) | (values[2]);
|
||||
}
|
||||
|
||||
/* Spin for max 160ms until DEV_RDY is 1, or return error. */
|
||||
static int hp206c_wait_dev_rdy(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
int count = 0;
|
||||
struct hp206c_data *data = iio_priv(indio_dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
while (++count <= HP206C_MAX_DEV_RDY_WAIT_COUNT) {
|
||||
ret = hp206c_read_reg(client, HP206C_REG_INT_SRC);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed READ_REG INT_SRC: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (ret & HP206C_FLAG_DEV_RDY)
|
||||
return 0;
|
||||
usleep_range(HP206C_DEV_RDY_WAIT_US, HP206C_DEV_RDY_WAIT_US * 3 / 2);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int hp206c_set_compensation(struct i2c_client *client, bool enabled)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = hp206c_read_reg(client, HP206C_REG_PARA);
|
||||
if (val < 0)
|
||||
return val;
|
||||
if (enabled)
|
||||
val |= HP206C_FLAG_CMPS_EN;
|
||||
else
|
||||
val &= ~HP206C_FLAG_CMPS_EN;
|
||||
|
||||
return hp206c_write_reg(client, HP206C_REG_PARA, val);
|
||||
}
|
||||
|
||||
/* Do a soft reset */
|
||||
static int hp206c_soft_reset(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
struct hp206c_data *data = iio_priv(indio_dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
ret = i2c_smbus_write_byte(client, HP206C_CMD_SOFT_RST);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to reset device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(400, 600);
|
||||
|
||||
ret = hp206c_wait_dev_rdy(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Device not ready after soft reset: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hp206c_set_compensation(client, true);
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Failed to enable compensation: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hp206c_conv_and_read(struct iio_dev *indio_dev,
|
||||
u8 conv_cmd, u8 read_cmd,
|
||||
unsigned int sleep_us)
|
||||
{
|
||||
int ret;
|
||||
struct hp206c_data *data = iio_priv(indio_dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
ret = hp206c_wait_dev_rdy(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte(client, conv_cmd);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Failed convert: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
usleep_range(sleep_us, sleep_us * 3 / 2);
|
||||
|
||||
ret = hp206c_wait_dev_rdy(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&indio_dev->dev, "Device not ready: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = hp206c_read_20bit(client, read_cmd);
|
||||
if (ret < 0)
|
||||
dev_err(&indio_dev->dev, "Failed read: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hp206c_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
struct hp206c_data *data = iio_priv(indio_dev);
|
||||
const struct hp206c_osr_setting *osr_setting;
|
||||
u8 conv_cmd;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = hp206c_osr_rates[data->temp_osr_index];
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
|
||||
case IIO_PRESSURE:
|
||||
*val = hp206c_osr_rates[data->pres_osr_index];
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
osr_setting = &hp206c_osr_settings[data->temp_osr_index];
|
||||
conv_cmd = HP206C_CMD_ADC_CVT |
|
||||
osr_setting->osr_mask |
|
||||
HP206C_CMD_ADC_CVT_CHNL_T;
|
||||
ret = hp206c_conv_and_read(indio_dev,
|
||||
conv_cmd,
|
||||
HP206C_CMD_READ_T,
|
||||
osr_setting->temp_conv_time_us);
|
||||
if (ret >= 0) {
|
||||
/* 20 significant bits are provided.
|
||||
* Extend sign over the rest.
|
||||
*/
|
||||
*val = sign_extend32(ret, 19);
|
||||
ret = IIO_VAL_INT;
|
||||
}
|
||||
break;
|
||||
|
||||
case IIO_PRESSURE:
|
||||
osr_setting = &hp206c_osr_settings[data->pres_osr_index];
|
||||
conv_cmd = HP206C_CMD_ADC_CVT |
|
||||
osr_setting->osr_mask |
|
||||
HP206C_CMD_ADC_CVT_CHNL_PT;
|
||||
ret = hp206c_conv_and_read(indio_dev,
|
||||
conv_cmd,
|
||||
HP206C_CMD_READ_P,
|
||||
osr_setting->pres_conv_time_us);
|
||||
if (ret >= 0) {
|
||||
*val = ret;
|
||||
ret = IIO_VAL_INT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = 0;
|
||||
*val2 = 10000;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
|
||||
case IIO_PRESSURE:
|
||||
*val = 0;
|
||||
*val2 = 1000;
|
||||
ret = IIO_VAL_INT_PLUS_MICRO;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hp206c_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
int ret = 0;
|
||||
struct hp206c_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->mutex);
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
data->temp_osr_index = find_closest_descending(val,
|
||||
hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
|
||||
break;
|
||||
case IIO_PRESSURE:
|
||||
data->pres_osr_index = find_closest_descending(val,
|
||||
hp206c_osr_rates, ARRAY_SIZE(hp206c_osr_rates));
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec hp206c_channels[] = {
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
},
|
||||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
}
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(hp206c_osr_rates_str);
|
||||
|
||||
static struct attribute *hp206c_attributes[] = {
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group hp206c_attribute_group = {
|
||||
.attrs = hp206c_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info hp206c_info = {
|
||||
.attrs = &hp206c_attribute_group,
|
||||
.read_raw = hp206c_read_raw,
|
||||
.write_raw = hp206c_write_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int hp206c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct hp206c_data *data;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
||||
dev_err(&client->dev, "Adapter does not support "
|
||||
"all required i2c functionality\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
indio_dev->info = &hp206c_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = hp206c_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(hp206c_channels);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
/* Do a soft reset on probe */
|
||||
ret = hp206c_soft_reset(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to reset on startup: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id hp206c_id[] = {
|
||||
{"hp206c"},
|
||||
{}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id hp206c_acpi_match[] = {
|
||||
{"HOP206C", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, hp206c_acpi_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver hp206c_driver = {
|
||||
.probe = hp206c_probe,
|
||||
.id_table = hp206c_id,
|
||||
.driver = {
|
||||
.name = "hp206c",
|
||||
.acpi_match_table = ACPI_PTR(hp206c_acpi_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_i2c_driver(hp206c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("HOPERF HP206C precision barometer and altimeter sensor");
|
||||
MODULE_AUTHOR("Leonard Crestez <leonard.crestez@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -16,15 +16,11 @@
|
|||
#include <linux/iio/iio.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct regulator;
|
||||
|
||||
#define MS5611_RESET 0x1e
|
||||
#define MS5611_READ_ADC 0x00
|
||||
#define MS5611_READ_PROM_WORD 0xA0
|
||||
#define MS5611_START_TEMP_CONV 0x58
|
||||
#define MS5611_START_PRESSURE_CONV 0x48
|
||||
|
||||
#define MS5611_CONV_TIME_MIN 9040
|
||||
#define MS5611_CONV_TIME_MAX 10000
|
||||
|
||||
#define MS5611_PROM_WORDS_NB 8
|
||||
|
||||
enum {
|
||||
|
@ -39,16 +35,31 @@ struct ms5611_chip_info {
|
|||
s32 *temp, s32 *pressure);
|
||||
};
|
||||
|
||||
/*
|
||||
* OverSampling Rate descriptor.
|
||||
* Warning: cmd MUST be kept aligned on a word boundary (see
|
||||
* m5611_spi_read_adc_temp_and_pressure in ms5611_spi.c).
|
||||
*/
|
||||
struct ms5611_osr {
|
||||
unsigned long conv_usec;
|
||||
u8 cmd;
|
||||
unsigned short rate;
|
||||
};
|
||||
|
||||
struct ms5611_state {
|
||||
void *client;
|
||||
struct mutex lock;
|
||||
|
||||
const struct ms5611_osr *pressure_osr;
|
||||
const struct ms5611_osr *temp_osr;
|
||||
|
||||
int (*reset)(struct device *dev);
|
||||
int (*read_prom_word)(struct device *dev, int index, u16 *word);
|
||||
int (*read_adc_temp_and_pressure)(struct device *dev,
|
||||
s32 *temp, s32 *pressure);
|
||||
|
||||
struct ms5611_chip_info *chip_info;
|
||||
struct regulator *vdd;
|
||||
};
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
||||
|
|
|
@ -18,11 +18,44 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include "ms5611.h"
|
||||
|
||||
#define MS5611_INIT_OSR(_cmd, _conv_usec, _rate) \
|
||||
{ .cmd = _cmd, .conv_usec = _conv_usec, .rate = _rate }
|
||||
|
||||
static const struct ms5611_osr ms5611_avail_pressure_osr[] = {
|
||||
MS5611_INIT_OSR(0x40, 600, 256),
|
||||
MS5611_INIT_OSR(0x42, 1170, 512),
|
||||
MS5611_INIT_OSR(0x44, 2280, 1024),
|
||||
MS5611_INIT_OSR(0x46, 4540, 2048),
|
||||
MS5611_INIT_OSR(0x48, 9040, 4096)
|
||||
};
|
||||
|
||||
static const struct ms5611_osr ms5611_avail_temp_osr[] = {
|
||||
MS5611_INIT_OSR(0x50, 600, 256),
|
||||
MS5611_INIT_OSR(0x52, 1170, 512),
|
||||
MS5611_INIT_OSR(0x54, 2280, 1024),
|
||||
MS5611_INIT_OSR(0x56, 4540, 2048),
|
||||
MS5611_INIT_OSR(0x58, 9040, 4096)
|
||||
};
|
||||
|
||||
static const char ms5611_show_osr[] = "256 512 1024 2048 4096";
|
||||
|
||||
static IIO_CONST_ATTR(oversampling_ratio_available, ms5611_show_osr);
|
||||
|
||||
static struct attribute *ms5611_attributes[] = {
|
||||
&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ms5611_attribute_group = {
|
||||
.attrs = ms5611_attributes,
|
||||
};
|
||||
|
||||
static bool ms5611_prom_is_valid(u16 *prom, size_t len)
|
||||
{
|
||||
int i, j;
|
||||
|
@ -239,11 +272,70 @@ static int ms5611_read_raw(struct iio_dev *indio_dev,
|
|||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
if (chan->type != IIO_TEMP && chan->type != IIO_PRESSURE)
|
||||
break;
|
||||
mutex_lock(&st->lock);
|
||||
if (chan->type == IIO_TEMP)
|
||||
*val = (int)st->temp_osr->rate;
|
||||
else
|
||||
*val = (int)st->pressure_osr->rate;
|
||||
mutex_unlock(&st->lock);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct ms5611_osr *ms5611_find_osr(int rate,
|
||||
const struct ms5611_osr *osr,
|
||||
size_t count)
|
||||
{
|
||||
unsigned int r;
|
||||
|
||||
for (r = 0; r < count; r++)
|
||||
if ((unsigned short)rate == osr[r].rate)
|
||||
break;
|
||||
if (r >= count)
|
||||
return NULL;
|
||||
return &osr[r];
|
||||
}
|
||||
|
||||
static int ms5611_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
const struct ms5611_osr *osr = NULL;
|
||||
|
||||
if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
|
||||
return -EINVAL;
|
||||
|
||||
if (chan->type == IIO_TEMP)
|
||||
osr = ms5611_find_osr(val, ms5611_avail_temp_osr,
|
||||
ARRAY_SIZE(ms5611_avail_temp_osr));
|
||||
else if (chan->type == IIO_PRESSURE)
|
||||
osr = ms5611_find_osr(val, ms5611_avail_pressure_osr,
|
||||
ARRAY_SIZE(ms5611_avail_pressure_osr));
|
||||
if (!osr)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&st->lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (chan->type == IIO_TEMP)
|
||||
st->temp_osr = osr;
|
||||
else
|
||||
st->pressure_osr = osr;
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned long ms5611_scan_masks[] = {0x3, 0};
|
||||
|
||||
static struct ms5611_chip_info chip_info_tbl[] = {
|
||||
|
@ -259,7 +351,8 @@ static const struct iio_chan_spec ms5611_channels[] = {
|
|||
{
|
||||
.type = IIO_PRESSURE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
|
@ -271,7 +364,8 @@ static const struct iio_chan_spec ms5611_channels[] = {
|
|||
{
|
||||
.type = IIO_TEMP,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
|
@ -285,30 +379,53 @@ static const struct iio_chan_spec ms5611_channels[] = {
|
|||
|
||||
static const struct iio_info ms5611_info = {
|
||||
.read_raw = &ms5611_read_raw,
|
||||
.write_raw = &ms5611_write_raw,
|
||||
.attrs = &ms5611_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ms5611_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
int ret;
|
||||
struct regulator *vdd = devm_regulator_get(indio_dev->dev.parent,
|
||||
"vdd");
|
||||
struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
/* Enable attached regulator if any. */
|
||||
if (!IS_ERR(vdd)) {
|
||||
ret = regulator_enable(vdd);
|
||||
st->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
|
||||
if (!IS_ERR(st->vdd)) {
|
||||
ret = regulator_enable(st->vdd);
|
||||
if (ret) {
|
||||
dev_err(indio_dev->dev.parent,
|
||||
"failed to enable Vdd supply: %d\n", ret);
|
||||
"failed to enable Vdd supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = PTR_ERR(st->vdd);
|
||||
if (ret != -ENODEV)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ms5611_reset(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto err_regulator_disable;
|
||||
|
||||
return ms5611_read_prom(indio_dev);
|
||||
ret = ms5611_read_prom(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_regulator_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_regulator_disable:
|
||||
if (!IS_ERR_OR_NULL(st->vdd))
|
||||
regulator_disable(st->vdd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ms5611_fini(const struct iio_dev *indio_dev)
|
||||
{
|
||||
const struct ms5611_state *st = iio_priv(indio_dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(st->vdd))
|
||||
regulator_disable(st->vdd);
|
||||
}
|
||||
|
||||
int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
||||
|
@ -319,6 +436,11 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
|||
|
||||
mutex_init(&st->lock);
|
||||
st->chip_info = &chip_info_tbl[type];
|
||||
st->temp_osr =
|
||||
&ms5611_avail_temp_osr[ARRAY_SIZE(ms5611_avail_temp_osr) - 1];
|
||||
st->pressure_osr =
|
||||
&ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr)
|
||||
- 1];
|
||||
indio_dev->dev.parent = dev;
|
||||
indio_dev->name = name;
|
||||
indio_dev->info = &ms5611_info;
|
||||
|
@ -335,7 +457,7 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
|||
ms5611_trigger_handler, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "iio triggered buffer setup failed\n");
|
||||
return ret;
|
||||
goto err_fini;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -348,7 +470,8 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev,
|
|||
|
||||
err_buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
err_fini:
|
||||
ms5611_fini(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ms5611_probe);
|
||||
|
@ -357,6 +480,7 @@ int ms5611_remove(struct iio_dev *indio_dev)
|
|||
{
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
ms5611_fini(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "ms5611.h"
|
||||
|
||||
|
@ -62,23 +63,23 @@ static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev,
|
|||
{
|
||||
int ret;
|
||||
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
const struct ms5611_osr *osr = st->temp_osr;
|
||||
|
||||
ret = i2c_smbus_write_byte(st->client, MS5611_START_TEMP_CONV);
|
||||
ret = i2c_smbus_write_byte(st->client, osr->cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
|
||||
|
||||
usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
|
||||
ret = ms5611_i2c_read_adc(st, temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte(st->client, MS5611_START_PRESSURE_CONV);
|
||||
osr = st->pressure_osr;
|
||||
ret = i2c_smbus_write_byte(st->client, osr->cmd);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
|
||||
|
||||
usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
|
||||
return ms5611_i2c_read_adc(st, pressure);
|
||||
}
|
||||
|
||||
|
@ -113,6 +114,17 @@ static int ms5611_i2c_remove(struct i2c_client *client)
|
|||
return ms5611_remove(i2c_get_clientdata(client));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id ms5611_i2c_matches[] = {
|
||||
{ .compatible = "meas,ms5611" },
|
||||
{ .compatible = "ms5611" },
|
||||
{ .compatible = "meas,ms5607" },
|
||||
{ .compatible = "ms5607" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id ms5611_id[] = {
|
||||
{ "ms5611", MS5611 },
|
||||
{ "ms5607", MS5607 },
|
||||
|
@ -123,6 +135,7 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id);
|
|||
static struct i2c_driver ms5611_driver = {
|
||||
.driver = {
|
||||
.name = "ms5611",
|
||||
.of_match_table = of_match_ptr(ms5611_i2c_matches)
|
||||
},
|
||||
.id_table = ms5611_id,
|
||||
.probe = ms5611_i2c_probe,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "ms5611.h"
|
||||
|
||||
|
@ -55,28 +56,29 @@ static int ms5611_spi_read_adc(struct device *dev, s32 *val)
|
|||
static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev,
|
||||
s32 *temp, s32 *pressure)
|
||||
{
|
||||
u8 cmd;
|
||||
int ret;
|
||||
struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev));
|
||||
const struct ms5611_osr *osr = st->temp_osr;
|
||||
|
||||
cmd = MS5611_START_TEMP_CONV;
|
||||
ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
|
||||
/*
|
||||
* Warning: &osr->cmd MUST be aligned on a word boundary since used as
|
||||
* 2nd argument (void*) of spi_write_then_read.
|
||||
*/
|
||||
ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
|
||||
|
||||
usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
|
||||
ret = ms5611_spi_read_adc(dev, temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cmd = MS5611_START_PRESSURE_CONV;
|
||||
ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0);
|
||||
osr = st->pressure_osr;
|
||||
ret = spi_write_then_read(st->client, &osr->cmd, 1, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX);
|
||||
|
||||
usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL));
|
||||
return ms5611_spi_read_adc(dev, pressure);
|
||||
}
|
||||
|
||||
|
@ -114,6 +116,17 @@ static int ms5611_spi_remove(struct spi_device *spi)
|
|||
return ms5611_remove(spi_get_drvdata(spi));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id ms5611_spi_matches[] = {
|
||||
{ .compatible = "meas,ms5611" },
|
||||
{ .compatible = "ms5611" },
|
||||
{ .compatible = "meas,ms5607" },
|
||||
{ .compatible = "ms5607" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
|
||||
#endif
|
||||
|
||||
static const struct spi_device_id ms5611_id[] = {
|
||||
{ "ms5611", MS5611 },
|
||||
{ "ms5607", MS5607 },
|
||||
|
@ -124,6 +137,7 @@ MODULE_DEVICE_TABLE(spi, ms5611_id);
|
|||
static struct spi_driver ms5611_driver = {
|
||||
.driver = {
|
||||
.name = "ms5611",
|
||||
.of_match_table = of_match_ptr(ms5611_spi_matches)
|
||||
},
|
||||
.id_table = ms5611_id,
|
||||
.probe = ms5611_spi_probe,
|
||||
|
|
|
@ -27,18 +27,6 @@ config ADIS16203
|
|||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16203.
|
||||
|
||||
config ADIS16204
|
||||
tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
|
||||
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 adis16204 Programmable
|
||||
High-g Digital Impact Sensor and Recorder.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16204.
|
||||
|
||||
config ADIS16209
|
||||
tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
|
||||
depends on SPI
|
||||
|
@ -51,17 +39,6 @@ config ADIS16209
|
|||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16209.
|
||||
|
||||
config ADIS16220
|
||||
tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor"
|
||||
depends on SPI
|
||||
select IIO_ADIS_LIB
|
||||
help
|
||||
Say Y here to build support for Analog Devices adis16220 programmable
|
||||
digital vibration sensor.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called adis16220.
|
||||
|
||||
config ADIS16240
|
||||
tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
|
||||
depends on SPI
|
||||
|
|
|
@ -8,15 +8,9 @@ obj-$(CONFIG_ADIS16201) += adis16201.o
|
|||
adis16203-y := adis16203_core.o
|
||||
obj-$(CONFIG_ADIS16203) += adis16203.o
|
||||
|
||||
adis16204-y := adis16204_core.o
|
||||
obj-$(CONFIG_ADIS16204) += adis16204.o
|
||||
|
||||
adis16209-y := adis16209_core.o
|
||||
obj-$(CONFIG_ADIS16209) += adis16209.o
|
||||
|
||||
adis16220-y := adis16220_core.o
|
||||
obj-$(CONFIG_ADIS16220) += adis16220.o
|
||||
|
||||
adis16240-y := adis16240_core.o
|
||||
obj-$(CONFIG_ADIS16240) += adis16240.o
|
||||
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
#ifndef SPI_ADIS16204_H_
|
||||
#define SPI_ADIS16204_H_
|
||||
|
||||
#define ADIS16204_STARTUP_DELAY 220 /* ms */
|
||||
|
||||
/* Flash memory write count */
|
||||
#define ADIS16204_FLASH_CNT 0x00
|
||||
|
||||
/* Output, power supply */
|
||||
#define ADIS16204_SUPPLY_OUT 0x02
|
||||
|
||||
/* Output, x-axis accelerometer */
|
||||
#define ADIS16204_XACCL_OUT 0x04
|
||||
|
||||
/* Output, y-axis accelerometer */
|
||||
#define ADIS16204_YACCL_OUT 0x06
|
||||
|
||||
/* Output, auxiliary ADC input */
|
||||
#define ADIS16204_AUX_ADC 0x08
|
||||
|
||||
/* Output, temperature */
|
||||
#define ADIS16204_TEMP_OUT 0x0A
|
||||
|
||||
/* Twos complement */
|
||||
#define ADIS16204_X_PEAK_OUT 0x0C
|
||||
#define ADIS16204_Y_PEAK_OUT 0x0E
|
||||
|
||||
/* Calibration, x-axis acceleration offset null */
|
||||
#define ADIS16204_XACCL_NULL 0x10
|
||||
|
||||
/* Calibration, y-axis acceleration offset null */
|
||||
#define ADIS16204_YACCL_NULL 0x12
|
||||
|
||||
/* X-axis scale factor calibration register */
|
||||
#define ADIS16204_XACCL_SCALE 0x14
|
||||
|
||||
/* Y-axis scale factor calibration register */
|
||||
#define ADIS16204_YACCL_SCALE 0x16
|
||||
|
||||
/* XY combined acceleration (RSS) */
|
||||
#define ADIS16204_XY_RSS_OUT 0x18
|
||||
|
||||
/* Peak, XY combined output (RSS) */
|
||||
#define ADIS16204_XY_PEAK_OUT 0x1A
|
||||
|
||||
/* Capture buffer output register 1 */
|
||||
#define ADIS16204_CAP_BUF_1 0x1C
|
||||
|
||||
/* Capture buffer output register 2 */
|
||||
#define ADIS16204_CAP_BUF_2 0x1E
|
||||
|
||||
/* Alarm 1 amplitude threshold */
|
||||
#define ADIS16204_ALM_MAG1 0x20
|
||||
|
||||
/* Alarm 2 amplitude threshold */
|
||||
#define ADIS16204_ALM_MAG2 0x22
|
||||
|
||||
/* Alarm control */
|
||||
#define ADIS16204_ALM_CTRL 0x28
|
||||
|
||||
/* Capture register address pointer */
|
||||
#define ADIS16204_CAPT_PNTR 0x2A
|
||||
|
||||
/* Auxiliary DAC data */
|
||||
#define ADIS16204_AUX_DAC 0x30
|
||||
|
||||
/* General-purpose digital input/output control */
|
||||
#define ADIS16204_GPIO_CTRL 0x32
|
||||
|
||||
/* Miscellaneous control */
|
||||
#define ADIS16204_MSC_CTRL 0x34
|
||||
|
||||
/* Internal sample period (rate) control */
|
||||
#define ADIS16204_SMPL_PRD 0x36
|
||||
|
||||
/* Operation, filter configuration */
|
||||
#define ADIS16204_AVG_CNT 0x38
|
||||
|
||||
/* Operation, sleep mode control */
|
||||
#define ADIS16204_SLP_CNT 0x3A
|
||||
|
||||
/* Diagnostics, system status register */
|
||||
#define ADIS16204_DIAG_STAT 0x3C
|
||||
|
||||
/* Operation, system command register */
|
||||
#define ADIS16204_GLOB_CMD 0x3E
|
||||
|
||||
/* MSC_CTRL */
|
||||
|
||||
/* Self-test at power-on: 1 = disabled, 0 = enabled */
|
||||
#define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST BIT(10)
|
||||
|
||||
/* Self-test enable */
|
||||
#define ADIS16204_MSC_CTRL_SELF_TEST_EN BIT(8)
|
||||
|
||||
/* Data-ready enable: 1 = enabled, 0 = disabled */
|
||||
#define ADIS16204_MSC_CTRL_DATA_RDY_EN BIT(2)
|
||||
|
||||
/* Data-ready polarity: 1 = active high, 0 = active low */
|
||||
#define ADIS16204_MSC_CTRL_ACTIVE_HIGH BIT(1)
|
||||
|
||||
/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
|
||||
#define ADIS16204_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
|
||||
|
||||
/* DIAG_STAT */
|
||||
|
||||
/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
|
||||
#define ADIS16204_DIAG_STAT_ALARM2 BIT(9)
|
||||
|
||||
/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
|
||||
#define ADIS16204_DIAG_STAT_ALARM1 BIT(8)
|
||||
|
||||
/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */
|
||||
#define ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT 5
|
||||
|
||||
/* SPI communications failure */
|
||||
#define ADIS16204_DIAG_STAT_SPI_FAIL_BIT 3
|
||||
|
||||
/* Flash update failure */
|
||||
#define ADIS16204_DIAG_STAT_FLASH_UPT_BIT 2
|
||||
|
||||
/* Power supply above 3.625 V */
|
||||
#define ADIS16204_DIAG_STAT_POWER_HIGH_BIT 1
|
||||
|
||||
/* Power supply below 2.975 V */
|
||||
#define ADIS16204_DIAG_STAT_POWER_LOW_BIT 0
|
||||
|
||||
/* GLOB_CMD */
|
||||
|
||||
#define ADIS16204_GLOB_CMD_SW_RESET BIT(7)
|
||||
#define ADIS16204_GLOB_CMD_CLEAR_STAT BIT(4)
|
||||
#define ADIS16204_GLOB_CMD_FACTORY_CAL BIT(1)
|
||||
|
||||
#define ADIS16204_ERROR_ACTIVE BIT(14)
|
||||
|
||||
enum adis16204_scan {
|
||||
ADIS16204_SCAN_ACC_X,
|
||||
ADIS16204_SCAN_ACC_Y,
|
||||
ADIS16204_SCAN_ACC_XY,
|
||||
ADIS16204_SCAN_SUPPLY,
|
||||
ADIS16204_SCAN_AUX_ADC,
|
||||
ADIS16204_SCAN_TEMP,
|
||||
};
|
||||
|
||||
#endif /* SPI_ADIS16204_H_ */
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* ADIS16204 Programmable High-g Digital Impact Sensor and Recorder
|
||||
*
|
||||
* Copyright 2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
||||
#include "adis16204.h"
|
||||
|
||||
/* Unique to this driver currently */
|
||||
|
||||
static const u8 adis16204_addresses[][2] = {
|
||||
[ADIS16204_SCAN_ACC_X] = { ADIS16204_XACCL_NULL, ADIS16204_X_PEAK_OUT },
|
||||
[ADIS16204_SCAN_ACC_Y] = { ADIS16204_YACCL_NULL, ADIS16204_Y_PEAK_OUT },
|
||||
[ADIS16204_SCAN_ACC_XY] = { 0, ADIS16204_XY_PEAK_OUT },
|
||||
};
|
||||
|
||||
static int adis16204_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct adis *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
int bits;
|
||||
u8 addr;
|
||||
s16 val16;
|
||||
int addrind;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return adis_single_conversion(indio_dev, chan,
|
||||
ADIS16204_ERROR_ACTIVE, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (chan->channel == 0) {
|
||||
*val = 1;
|
||||
*val2 = 220000; /* 1.22 mV */
|
||||
} else {
|
||||
*val = 0;
|
||||
*val2 = 610000; /* 0.61 mV */
|
||||
}
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_TEMP:
|
||||
*val = -470; /* 0.47 C */
|
||||
*val2 = 0;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_ACCEL:
|
||||
*val = 0;
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_X:
|
||||
case IIO_MOD_ROOT_SUM_SQUARED_X_Y:
|
||||
*val2 = IIO_G_TO_M_S_2(17125); /* 17.125 mg */
|
||||
break;
|
||||
case IIO_MOD_Y:
|
||||
case IIO_MOD_Z:
|
||||
*val2 = IIO_G_TO_M_S_2(8407); /* 8.407 mg */
|
||||
break;
|
||||
}
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = 25000 / -470 - 1278; /* 25 C = 1278 */
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
case IIO_CHAN_INFO_PEAK:
|
||||
if (mask == IIO_CHAN_INFO_CALIBBIAS) {
|
||||
bits = 12;
|
||||
addrind = 0;
|
||||
} else { /* PEAK_SEPARATE */
|
||||
bits = 14;
|
||||
addrind = 1;
|
||||
}
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
addr = adis16204_addresses[chan->scan_index][addrind];
|
||||
ret = adis_read_reg_16(st, addr, &val16);
|
||||
if (ret) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
val16 &= (1 << bits) - 1;
|
||||
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
|
||||
*val = val16;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adis16204_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
int val2,
|
||||
long mask)
|
||||
{
|
||||
struct adis *st = iio_priv(indio_dev);
|
||||
int bits;
|
||||
s16 val16;
|
||||
u8 addr;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
switch (chan->type) {
|
||||
case IIO_ACCEL:
|
||||
bits = 12;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
val16 = val & ((1 << bits) - 1);
|
||||
addr = adis16204_addresses[chan->scan_index][1];
|
||||
return adis_write_reg_16(st, addr, val16);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adis16204_channels[] = {
|
||||
ADIS_SUPPLY_CHAN(ADIS16204_SUPPLY_OUT, ADIS16204_SCAN_SUPPLY, 0, 12),
|
||||
ADIS_AUX_ADC_CHAN(ADIS16204_AUX_ADC, ADIS16204_SCAN_AUX_ADC, 0, 12),
|
||||
ADIS_TEMP_CHAN(ADIS16204_TEMP_OUT, ADIS16204_SCAN_TEMP, 0, 12),
|
||||
ADIS_ACCEL_CHAN(X, ADIS16204_XACCL_OUT, ADIS16204_SCAN_ACC_X,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK),
|
||||
0, 14),
|
||||
ADIS_ACCEL_CHAN(Y, ADIS16204_YACCL_OUT, ADIS16204_SCAN_ACC_Y,
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | BIT(IIO_CHAN_INFO_PEAK),
|
||||
0, 14),
|
||||
ADIS_ACCEL_CHAN(ROOT_SUM_SQUARED_X_Y, ADIS16204_XY_RSS_OUT,
|
||||
ADIS16204_SCAN_ACC_XY, BIT(IIO_CHAN_INFO_PEAK), 0, 14),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(5),
|
||||
};
|
||||
|
||||
static const struct iio_info adis16204_info = {
|
||||
.read_raw = &adis16204_read_raw,
|
||||
.write_raw = &adis16204_write_raw,
|
||||
.update_scan_mode = adis_update_scan_mode,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const char * const adis16204_status_error_msgs[] = {
|
||||
[ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT] = "Self test failure",
|
||||
[ADIS16204_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
|
||||
[ADIS16204_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
|
||||
[ADIS16204_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
|
||||
[ADIS16204_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 2.975V",
|
||||
};
|
||||
|
||||
static const struct adis_data adis16204_data = {
|
||||
.read_delay = 20,
|
||||
.msc_ctrl_reg = ADIS16204_MSC_CTRL,
|
||||
.glob_cmd_reg = ADIS16204_GLOB_CMD,
|
||||
.diag_stat_reg = ADIS16204_DIAG_STAT,
|
||||
|
||||
.self_test_mask = ADIS16204_MSC_CTRL_SELF_TEST_EN,
|
||||
.startup_delay = ADIS16204_STARTUP_DELAY,
|
||||
|
||||
.status_error_msgs = adis16204_status_error_msgs,
|
||||
.status_error_mask = BIT(ADIS16204_DIAG_STAT_SELFTEST_FAIL_BIT) |
|
||||
BIT(ADIS16204_DIAG_STAT_SPI_FAIL_BIT) |
|
||||
BIT(ADIS16204_DIAG_STAT_FLASH_UPT_BIT) |
|
||||
BIT(ADIS16204_DIAG_STAT_POWER_HIGH_BIT) |
|
||||
BIT(ADIS16204_DIAG_STAT_POWER_LOW_BIT),
|
||||
};
|
||||
|
||||
static int adis16204_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct adis *st;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
/* setup the industrialio driver allocated elements */
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
st = iio_priv(indio_dev);
|
||||
/* this is only used for removal purposes */
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi->dev.driver->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &adis16204_info;
|
||||
indio_dev->channels = adis16204_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adis16204_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = adis_init(st, indio_dev, spi, &adis16204_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = adis_setup_buffer_and_trigger(st, indio_dev, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Get the device into a sane initial state */
|
||||
ret = adis_initial_startup(st);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer_trigger;
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_cleanup_buffer_trigger;
|
||||
|
||||
return 0;
|
||||
|
||||
error_cleanup_buffer_trigger:
|
||||
adis_cleanup_buffer_and_trigger(st, indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adis16204_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct adis *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
adis_cleanup_buffer_and_trigger(st, indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver adis16204_driver = {
|
||||
.driver = {
|
||||
.name = "adis16204",
|
||||
},
|
||||
.probe = adis16204_probe,
|
||||
.remove = adis16204_remove,
|
||||
};
|
||||
module_spi_driver(adis16204_driver);
|
||||
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_DESCRIPTION("ADIS16204 High-g Digital Impact Sensor and Recorder");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("spi:adis16204");
|
|
@ -1,188 +0,0 @@
|
|||
#ifndef SPI_ADIS16220_H_
|
||||
#define SPI_ADIS16220_H_
|
||||
|
||||
#include <linux/iio/imu/adis.h>
|
||||
|
||||
#define ADIS16220_STARTUP_DELAY 220 /* ms */
|
||||
|
||||
/* Flash memory write count */
|
||||
#define ADIS16220_FLASH_CNT 0x00
|
||||
|
||||
/* Control, acceleration offset adjustment control */
|
||||
#define ADIS16220_ACCL_NULL 0x02
|
||||
|
||||
/* Control, AIN1 offset adjustment control */
|
||||
#define ADIS16220_AIN1_NULL 0x04
|
||||
|
||||
/* Control, AIN2 offset adjustment control */
|
||||
#define ADIS16220_AIN2_NULL 0x06
|
||||
|
||||
/* Output, power supply during capture */
|
||||
#define ADIS16220_CAPT_SUPPLY 0x0A
|
||||
|
||||
/* Output, temperature during capture */
|
||||
#define ADIS16220_CAPT_TEMP 0x0C
|
||||
|
||||
/* Output, peak acceleration during capture */
|
||||
#define ADIS16220_CAPT_PEAKA 0x0E
|
||||
|
||||
/* Output, peak AIN1 level during capture */
|
||||
#define ADIS16220_CAPT_PEAK1 0x10
|
||||
|
||||
/* Output, peak AIN2 level during capture */
|
||||
#define ADIS16220_CAPT_PEAK2 0x12
|
||||
|
||||
/* Output, capture buffer for acceleration */
|
||||
#define ADIS16220_CAPT_BUFA 0x14
|
||||
|
||||
/* Output, capture buffer for AIN1 */
|
||||
#define ADIS16220_CAPT_BUF1 0x16
|
||||
|
||||
/* Output, capture buffer for AIN2 */
|
||||
#define ADIS16220_CAPT_BUF2 0x18
|
||||
|
||||
/* Control, capture buffer address pointer */
|
||||
#define ADIS16220_CAPT_PNTR 0x1A
|
||||
|
||||
/* Control, capture control register */
|
||||
#define ADIS16220_CAPT_CTRL 0x1C
|
||||
|
||||
/* Control, capture period (automatic mode) */
|
||||
#define ADIS16220_CAPT_PRD 0x1E
|
||||
|
||||
/* Control, Alarm A, acceleration peak threshold */
|
||||
#define ADIS16220_ALM_MAGA 0x20
|
||||
|
||||
/* Control, Alarm 1, AIN1 peak threshold */
|
||||
#define ADIS16220_ALM_MAG1 0x22
|
||||
|
||||
/* Control, Alarm 2, AIN2 peak threshold */
|
||||
#define ADIS16220_ALM_MAG2 0x24
|
||||
|
||||
/* Control, Alarm S, peak threshold */
|
||||
#define ADIS16220_ALM_MAGS 0x26
|
||||
|
||||
/* Control, alarm configuration register */
|
||||
#define ADIS16220_ALM_CTRL 0x28
|
||||
|
||||
/* Control, general I/O configuration */
|
||||
#define ADIS16220_GPIO_CTRL 0x32
|
||||
|
||||
/* Control, self-test control, AIN configuration */
|
||||
#define ADIS16220_MSC_CTRL 0x34
|
||||
|
||||
/* Control, digital I/O configuration */
|
||||
#define ADIS16220_DIO_CTRL 0x36
|
||||
|
||||
/* Control, filter configuration */
|
||||
#define ADIS16220_AVG_CNT 0x38
|
||||
|
||||
/* Status, system status */
|
||||
#define ADIS16220_DIAG_STAT 0x3C
|
||||
|
||||
/* Control, system commands */
|
||||
#define ADIS16220_GLOB_CMD 0x3E
|
||||
|
||||
/* Status, self-test response */
|
||||
#define ADIS16220_ST_DELTA 0x40
|
||||
|
||||
/* Lot Identification Code 1 */
|
||||
#define ADIS16220_LOT_ID1 0x52
|
||||
|
||||
/* Lot Identification Code 2 */
|
||||
#define ADIS16220_LOT_ID2 0x54
|
||||
|
||||
/* Product identifier; convert to decimal = 16220 */
|
||||
#define ADIS16220_PROD_ID 0x56
|
||||
|
||||
/* Serial number */
|
||||
#define ADIS16220_SERIAL_NUM 0x58
|
||||
|
||||
#define ADIS16220_CAPTURE_SIZE 2048
|
||||
|
||||
/* MSC_CTRL */
|
||||
|
||||
#define ADIS16220_MSC_CTRL_SELF_TEST_EN BIT(8)
|
||||
#define ADIS16220_MSC_CTRL_POWER_SUP_COM_AIN1 BIT(1)
|
||||
#define ADIS16220_MSC_CTRL_POWER_SUP_COM_AIN2 BIT(0)
|
||||
|
||||
/* DIO_CTRL */
|
||||
|
||||
#define ADIS16220_MSC_CTRL_DIO2_BUSY_IND (BIT(5) | BIT(4))
|
||||
#define ADIS16220_MSC_CTRL_DIO1_BUSY_IND (BIT(3) | BIT(2))
|
||||
#define ADIS16220_MSC_CTRL_DIO2_ACT_HIGH BIT(1)
|
||||
#define ADIS16220_MSC_CTRL_DIO1_ACT_HIGH BIT(0)
|
||||
|
||||
/* DIAG_STAT */
|
||||
|
||||
/* AIN2 sample > ALM_MAG2 */
|
||||
#define ADIS16220_DIAG_STAT_ALM_MAG2 BIT(14)
|
||||
|
||||
/* AIN1 sample > ALM_MAG1 */
|
||||
#define ADIS16220_DIAG_STAT_ALM_MAG1 BIT(13)
|
||||
|
||||
/* Acceleration sample > ALM_MAGA */
|
||||
#define ADIS16220_DIAG_STAT_ALM_MAGA BIT(12)
|
||||
|
||||
/* Error condition programmed into ALM_MAGS[11:0] and ALM_CTRL[5:4] is true */
|
||||
#define ADIS16220_DIAG_STAT_ALM_MAGS BIT(11)
|
||||
|
||||
/* |Peak value in AIN2 data capture| > ALM_MAG2 */
|
||||
#define ADIS16220_DIAG_STAT_PEAK_AIN2 BIT(10)
|
||||
|
||||
/* |Peak value in AIN1 data capture| > ALM_MAG1 */
|
||||
#define ADIS16220_DIAG_STAT_PEAK_AIN1 BIT(9)
|
||||
|
||||
/* |Peak value in acceleration data capture| > ALM_MAGA */
|
||||
#define ADIS16220_DIAG_STAT_PEAK_ACCEL BIT(8)
|
||||
|
||||
/* Data ready, capture complete */
|
||||
#define ADIS16220_DIAG_STAT_DATA_RDY BIT(7)
|
||||
|
||||
#define ADIS16220_DIAG_STAT_FLASH_CHK BIT(6)
|
||||
|
||||
#define ADIS16220_DIAG_STAT_SELF_TEST BIT(5)
|
||||
|
||||
/* Capture period violation/interruption */
|
||||
#define ADIS16220_DIAG_STAT_VIOLATION_BIT 4
|
||||
|
||||
/* SPI communications failure */
|
||||
#define ADIS16220_DIAG_STAT_SPI_FAIL_BIT 3
|
||||
|
||||
/* Flash update failure */
|
||||
#define ADIS16220_DIAG_STAT_FLASH_UPT_BIT 2
|
||||
|
||||
/* Power supply above 3.625 V */
|
||||
#define ADIS16220_DIAG_STAT_POWER_HIGH_BIT 1
|
||||
|
||||
/* Power supply below 3.15 V */
|
||||
#define ADIS16220_DIAG_STAT_POWER_LOW_BIT 0
|
||||
|
||||
/* GLOB_CMD */
|
||||
|
||||
#define ADIS16220_GLOB_CMD_SW_RESET BIT(7)
|
||||
#define ADIS16220_GLOB_CMD_SELF_TEST BIT(2)
|
||||
#define ADIS16220_GLOB_CMD_PWR_DOWN BIT(1)
|
||||
|
||||
#define ADIS16220_MAX_TX 2048
|
||||
#define ADIS16220_MAX_RX 2048
|
||||
|
||||
#define ADIS16220_SPI_BURST (u32)(1000 * 1000)
|
||||
#define ADIS16220_SPI_FAST (u32)(2000 * 1000)
|
||||
|
||||
/**
|
||||
* struct adis16220_state - device instance specific data
|
||||
* @adis: adis device
|
||||
* @tx: transmit buffer
|
||||
* @rx: receive buffer
|
||||
* @buf_lock: mutex to protect tx and rx
|
||||
**/
|
||||
struct adis16220_state {
|
||||
struct adis adis;
|
||||
|
||||
struct mutex buf_lock;
|
||||
u8 tx[ADIS16220_MAX_TX] ____cacheline_aligned;
|
||||
u8 rx[ADIS16220_MAX_RX];
|
||||
};
|
||||
|
||||
#endif /* SPI_ADIS16220_H_ */
|
|
@ -1,494 +0,0 @@
|
|||
/*
|
||||
* ADIS16220 Programmable Digital Vibration Sensor driver
|
||||
*
|
||||
* Copyright 2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#include "adis16220.h"
|
||||
|
||||
static ssize_t adis16220_read_16bit(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct adis16220_state *st = iio_priv(indio_dev);
|
||||
ssize_t ret;
|
||||
u16 val;
|
||||
|
||||
/* Take the iio_dev status lock */
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = adis_read_reg_16(&st->adis, this_attr->address, &val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret)
|
||||
return ret;
|
||||
return sprintf(buf, "%u\n", val);
|
||||
}
|
||||
|
||||
static ssize_t adis16220_write_16bit(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
struct adis16220_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u16 val;
|
||||
|
||||
ret = kstrtou16(buf, 10, &val);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
ret = adis_write_reg_16(&st->adis, this_attr->address, val);
|
||||
|
||||
error_ret:
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
||||
static int adis16220_capture(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct adis16220_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
/* initiates a manual data capture */
|
||||
ret = adis_write_reg_16(&st->adis, ADIS16220_GLOB_CMD, 0xBF08);
|
||||
if (ret)
|
||||
dev_err(&indio_dev->dev, "problem beginning capture");
|
||||
|
||||
usleep_range(10000, 11000); /* delay for capture to finish */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t adis16220_write_capture(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
bool val;
|
||||
int ret;
|
||||
|
||||
ret = strtobool(buf, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
ret = adis16220_capture(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
|
||||
char *buf,
|
||||
loff_t off,
|
||||
size_t count,
|
||||
int addr)
|
||||
{
|
||||
struct adis16220_state *st = iio_priv(indio_dev);
|
||||
struct spi_transfer xfers[] = {
|
||||
{
|
||||
.tx_buf = st->tx,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = 25,
|
||||
}, {
|
||||
.tx_buf = st->tx,
|
||||
.rx_buf = st->rx,
|
||||
.bits_per_word = 8,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = 25,
|
||||
},
|
||||
};
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (unlikely(!count))
|
||||
return count;
|
||||
|
||||
if ((off >= ADIS16220_CAPTURE_SIZE) || (count & 1) || (off & 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (off + count > ADIS16220_CAPTURE_SIZE)
|
||||
count = ADIS16220_CAPTURE_SIZE - off;
|
||||
|
||||
/* write the begin position of capture buffer */
|
||||
ret = adis_write_reg_16(&st->adis,
|
||||
ADIS16220_CAPT_PNTR,
|
||||
off > 1);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
/* read count/2 values from capture buffer */
|
||||
mutex_lock(&st->buf_lock);
|
||||
|
||||
for (i = 0; i < count; i += 2) {
|
||||
st->tx[i] = ADIS_READ_REG(addr);
|
||||
st->tx[i + 1] = 0;
|
||||
}
|
||||
xfers[1].len = count;
|
||||
|
||||
ret = spi_sync_transfer(st->adis.spi, xfers, ARRAY_SIZE(xfers));
|
||||
if (ret) {
|
||||
mutex_unlock(&st->buf_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(buf, st->rx, count);
|
||||
|
||||
mutex_unlock(&st->buf_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf,
|
||||
loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
|
||||
|
||||
return adis16220_capture_buffer_read(indio_dev, buf,
|
||||
off, count,
|
||||
ADIS16220_CAPT_BUFA);
|
||||
}
|
||||
|
||||
static struct bin_attribute accel_bin = {
|
||||
.attr = {
|
||||
.name = "accel_bin",
|
||||
.mode = S_IRUGO,
|
||||
},
|
||||
.read = adis16220_accel_bin_read,
|
||||
.size = ADIS16220_CAPTURE_SIZE,
|
||||
};
|
||||
|
||||
static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
|
||||
|
||||
return adis16220_capture_buffer_read(indio_dev, buf,
|
||||
off, count,
|
||||
ADIS16220_CAPT_BUF1);
|
||||
}
|
||||
|
||||
static struct bin_attribute adc1_bin = {
|
||||
.attr = {
|
||||
.name = "in0_bin",
|
||||
.mode = S_IRUGO,
|
||||
},
|
||||
.read = adis16220_adc1_bin_read,
|
||||
.size = ADIS16220_CAPTURE_SIZE,
|
||||
};
|
||||
|
||||
static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
|
||||
|
||||
return adis16220_capture_buffer_read(indio_dev, buf,
|
||||
off, count,
|
||||
ADIS16220_CAPT_BUF2);
|
||||
}
|
||||
|
||||
static struct bin_attribute adc2_bin = {
|
||||
.attr = {
|
||||
.name = "in1_bin",
|
||||
.mode = S_IRUGO,
|
||||
},
|
||||
.read = adis16220_adc2_bin_read,
|
||||
.size = ADIS16220_CAPTURE_SIZE,
|
||||
};
|
||||
|
||||
#define IIO_DEV_ATTR_CAPTURE(_store) \
|
||||
IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0)
|
||||
|
||||
static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture);
|
||||
|
||||
#define IIO_DEV_ATTR_CAPTURE_COUNT(_mode, _show, _store, _addr) \
|
||||
IIO_DEVICE_ATTR(capture_count, _mode, _show, _store, _addr)
|
||||
|
||||
static IIO_DEV_ATTR_CAPTURE_COUNT(S_IWUSR | S_IRUGO,
|
||||
adis16220_read_16bit,
|
||||
adis16220_write_16bit,
|
||||
ADIS16220_CAPT_PNTR);
|
||||
|
||||
enum adis16220_channel {
|
||||
in_supply, in_1, in_2, accel, temp
|
||||
};
|
||||
|
||||
struct adis16220_address_spec {
|
||||
u8 addr;
|
||||
u8 bits;
|
||||
bool sign;
|
||||
};
|
||||
|
||||
/* Address / bits / signed */
|
||||
static const struct adis16220_address_spec adis16220_addresses[][3] = {
|
||||
[in_supply] = { { ADIS16220_CAPT_SUPPLY, 12, 0 }, },
|
||||
[in_1] = { { ADIS16220_CAPT_BUF1, 16, 1 },
|
||||
{ ADIS16220_AIN1_NULL, 16, 1 },
|
||||
{ ADIS16220_CAPT_PEAK1, 16, 1 }, },
|
||||
[in_2] = { { ADIS16220_CAPT_BUF2, 16, 1 },
|
||||
{ ADIS16220_AIN2_NULL, 16, 1 },
|
||||
{ ADIS16220_CAPT_PEAK2, 16, 1 }, },
|
||||
[accel] = { { ADIS16220_CAPT_BUFA, 16, 1 },
|
||||
{ ADIS16220_ACCL_NULL, 16, 1 },
|
||||
{ ADIS16220_CAPT_PEAKA, 16, 1 }, },
|
||||
[temp] = { { ADIS16220_CAPT_TEMP, 12, 0 }, }
|
||||
};
|
||||
|
||||
static int adis16220_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2,
|
||||
long mask)
|
||||
{
|
||||
struct adis16220_state *st = iio_priv(indio_dev);
|
||||
const struct adis16220_address_spec *addr;
|
||||
int ret = -EINVAL;
|
||||
int addrind = 0;
|
||||
u16 uval;
|
||||
s16 sval;
|
||||
u8 bits;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
addrind = 0;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
if (chan->type == IIO_TEMP) {
|
||||
*val = 25000 / -470 - 1278; /* 25 C = 1278 */
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
addrind = 1;
|
||||
break;
|
||||
case IIO_CHAN_INFO_PEAK:
|
||||
addrind = 2;
|
||||
break;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = -470; /* -0.47 C */
|
||||
*val2 = 0;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_ACCEL:
|
||||
*val2 = IIO_G_TO_M_S_2(19073); /* 19.073 g */
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_VOLTAGE:
|
||||
if (chan->channel == 0) {
|
||||
*val = 1;
|
||||
*val2 = 220700; /* 1.2207 mV */
|
||||
} else {
|
||||
/* Should really be dependent on VDD */
|
||||
*val2 = 305180; /* 305.18 uV */
|
||||
}
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
addr = &adis16220_addresses[chan->address][addrind];
|
||||
if (addr->sign) {
|
||||
ret = adis_read_reg_16(&st->adis, addr->addr, &sval);
|
||||
if (ret)
|
||||
return ret;
|
||||
bits = addr->bits;
|
||||
sval &= (1 << bits) - 1;
|
||||
sval = (s16)(sval << (16 - bits)) >> (16 - bits);
|
||||
*val = sval;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
ret = adis_read_reg_16(&st->adis, addr->addr, &uval);
|
||||
if (ret)
|
||||
return ret;
|
||||
bits = addr->bits;
|
||||
uval &= (1 << bits) - 1;
|
||||
*val = uval;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec adis16220_channels[] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.extend_name = "supply",
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = in_supply,
|
||||
}, {
|
||||
.type = IIO_ACCEL,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_PEAK),
|
||||
.address = accel,
|
||||
}, {
|
||||
.type = IIO_TEMP,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = temp,
|
||||
}, {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = in_1,
|
||||
}, {
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 2,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.address = in_2,
|
||||
}
|
||||
};
|
||||
|
||||
static struct attribute *adis16220_attributes[] = {
|
||||
&iio_dev_attr_capture.dev_attr.attr,
|
||||
&iio_dev_attr_capture_count.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group adis16220_attribute_group = {
|
||||
.attrs = adis16220_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info adis16220_info = {
|
||||
.attrs = &adis16220_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &adis16220_read_raw,
|
||||
};
|
||||
|
||||
static const char * const adis16220_status_error_msgs[] = {
|
||||
[ADIS16220_DIAG_STAT_VIOLATION_BIT] = "Capture period violation/interruption",
|
||||
[ADIS16220_DIAG_STAT_SPI_FAIL_BIT] = "SPI failure",
|
||||
[ADIS16220_DIAG_STAT_FLASH_UPT_BIT] = "Flash update failed",
|
||||
[ADIS16220_DIAG_STAT_POWER_HIGH_BIT] = "Power supply above 3.625V",
|
||||
[ADIS16220_DIAG_STAT_POWER_LOW_BIT] = "Power supply below 3.15V",
|
||||
};
|
||||
|
||||
static const struct adis_data adis16220_data = {
|
||||
.read_delay = 35,
|
||||
.write_delay = 35,
|
||||
.msc_ctrl_reg = ADIS16220_MSC_CTRL,
|
||||
.glob_cmd_reg = ADIS16220_GLOB_CMD,
|
||||
.diag_stat_reg = ADIS16220_DIAG_STAT,
|
||||
|
||||
.self_test_mask = ADIS16220_MSC_CTRL_SELF_TEST_EN,
|
||||
.startup_delay = ADIS16220_STARTUP_DELAY,
|
||||
|
||||
.status_error_msgs = adis16220_status_error_msgs,
|
||||
.status_error_mask = BIT(ADIS16220_DIAG_STAT_VIOLATION_BIT) |
|
||||
BIT(ADIS16220_DIAG_STAT_SPI_FAIL_BIT) |
|
||||
BIT(ADIS16220_DIAG_STAT_FLASH_UPT_BIT) |
|
||||
BIT(ADIS16220_DIAG_STAT_POWER_HIGH_BIT) |
|
||||
BIT(ADIS16220_DIAG_STAT_POWER_LOW_BIT),
|
||||
};
|
||||
|
||||
static int adis16220_probe(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
struct adis16220_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
|
||||
/* setup the industrialio driver allocated elements */
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
/* this is only used for removal purposes */
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
indio_dev->name = spi->dev.driver->name;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->info = &adis16220_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = adis16220_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(adis16220_channels);
|
||||
|
||||
ret = devm_iio_device_register(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &accel_bin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &adc1_bin);
|
||||
if (ret)
|
||||
goto error_rm_accel_bin;
|
||||
|
||||
ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &adc2_bin);
|
||||
if (ret)
|
||||
goto error_rm_adc1_bin;
|
||||
|
||||
ret = adis_init(&st->adis, indio_dev, spi, &adis16220_data);
|
||||
if (ret)
|
||||
goto error_rm_adc2_bin;
|
||||
/* Get the device into a sane initial state */
|
||||
ret = adis_initial_startup(&st->adis);
|
||||
if (ret)
|
||||
goto error_rm_adc2_bin;
|
||||
return 0;
|
||||
|
||||
error_rm_adc2_bin:
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc2_bin);
|
||||
error_rm_adc1_bin:
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
|
||||
error_rm_accel_bin:
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adis16220_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc2_bin);
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
|
||||
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver adis16220_driver = {
|
||||
.driver = {
|
||||
.name = "adis16220",
|
||||
},
|
||||
.probe = adis16220_probe,
|
||||
.remove = adis16220_remove,
|
||||
};
|
||||
module_spi_driver(adis16220_driver);
|
||||
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_DESCRIPTION("Analog Devices ADIS16220 Digital Vibration Sensor");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("spi:adis16220");
|
|
@ -349,11 +349,9 @@ static ssize_t ad7192_write_frequency(struct device *dev,
|
|||
if (lval == 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
div = st->mclk / (lval * st->f_order * 1024);
|
||||
if (div < 1 || div > 1023) {
|
||||
|
@ -366,7 +364,7 @@ static ssize_t ad7192_write_frequency(struct device *dev,
|
|||
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
@ -434,11 +432,9 @@ static ssize_t ad7192_set(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch ((u32)this_attr->address) {
|
||||
case AD7192_REG_GPOCON:
|
||||
|
@ -461,7 +457,7 @@ static ssize_t ad7192_set(struct device *dev,
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
@ -555,11 +551,9 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
|
|||
int ret, i;
|
||||
unsigned int tmp;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return -EBUSY;
|
||||
}
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
|
@ -582,7 +576,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ static void ad7280_crc8_build_table(unsigned char *crc_tab)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned val)
|
||||
static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val)
|
||||
{
|
||||
unsigned char crc;
|
||||
|
||||
|
@ -165,7 +165,7 @@ static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned val)
|
|||
return crc ^ (val & 0xFF);
|
||||
}
|
||||
|
||||
static int ad7280_check_crc(struct ad7280_state *st, unsigned val)
|
||||
static int ad7280_check_crc(struct ad7280_state *st, unsigned int val)
|
||||
{
|
||||
unsigned char crc = ad7280_calc_crc8(st->crc_tab, val >> 10);
|
||||
|
||||
|
@ -191,7 +191,7 @@ static void ad7280_delay(struct ad7280_state *st)
|
|||
usleep_range(250, 500);
|
||||
}
|
||||
|
||||
static int __ad7280_read32(struct ad7280_state *st, unsigned *val)
|
||||
static int __ad7280_read32(struct ad7280_state *st, unsigned int *val)
|
||||
{
|
||||
int ret;
|
||||
struct spi_transfer t = {
|
||||
|
@ -211,10 +211,10 @@ static int __ad7280_read32(struct ad7280_state *st, unsigned *val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ad7280_write(struct ad7280_state *st, unsigned devaddr,
|
||||
unsigned addr, bool all, unsigned val)
|
||||
static int ad7280_write(struct ad7280_state *st, unsigned int devaddr,
|
||||
unsigned int addr, bool all, unsigned int val)
|
||||
{
|
||||
unsigned reg = devaddr << 27 | addr << 21 |
|
||||
unsigned int reg = devaddr << 27 | addr << 21 |
|
||||
(val & 0xFF) << 13 | all << 12;
|
||||
|
||||
reg |= ad7280_calc_crc8(st->crc_tab, reg >> 11) << 3 | 0x2;
|
||||
|
@ -223,11 +223,11 @@ static int ad7280_write(struct ad7280_state *st, unsigned devaddr,
|
|||
return spi_write(st->spi, &st->buf[0], 4);
|
||||
}
|
||||
|
||||
static int ad7280_read(struct ad7280_state *st, unsigned devaddr,
|
||||
unsigned addr)
|
||||
static int ad7280_read(struct ad7280_state *st, unsigned int devaddr,
|
||||
unsigned int addr)
|
||||
{
|
||||
int ret;
|
||||
unsigned tmp;
|
||||
unsigned int tmp;
|
||||
|
||||
/* turns off the read operation on all parts */
|
||||
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
|
||||
|
@ -261,11 +261,11 @@ static int ad7280_read(struct ad7280_state *st, unsigned devaddr,
|
|||
return (tmp >> 13) & 0xFF;
|
||||
}
|
||||
|
||||
static int ad7280_read_channel(struct ad7280_state *st, unsigned devaddr,
|
||||
unsigned addr)
|
||||
static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr,
|
||||
unsigned int addr)
|
||||
{
|
||||
int ret;
|
||||
unsigned tmp;
|
||||
unsigned int tmp;
|
||||
|
||||
ret = ad7280_write(st, devaddr, AD7280A_READ, 0, addr << 2);
|
||||
if (ret)
|
||||
|
@ -299,11 +299,11 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned devaddr,
|
|||
return (tmp >> 11) & 0xFFF;
|
||||
}
|
||||
|
||||
static int ad7280_read_all_channels(struct ad7280_state *st, unsigned cnt,
|
||||
unsigned *array)
|
||||
static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
|
||||
unsigned int *array)
|
||||
{
|
||||
int i, ret;
|
||||
unsigned tmp, sum = 0;
|
||||
unsigned int tmp, sum = 0;
|
||||
|
||||
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1,
|
||||
AD7280A_CELL_VOLTAGE_1 << 2);
|
||||
|
@ -338,7 +338,7 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned cnt,
|
|||
|
||||
static int ad7280_chain_setup(struct ad7280_state *st)
|
||||
{
|
||||
unsigned val, n;
|
||||
unsigned int val, n;
|
||||
int ret;
|
||||
|
||||
ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_LB, 1,
|
||||
|
@ -401,7 +401,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev,
|
|||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
bool readin;
|
||||
int ret;
|
||||
unsigned devaddr, ch;
|
||||
unsigned int devaddr, ch;
|
||||
|
||||
ret = strtobool(buf, &readin);
|
||||
if (ret)
|
||||
|
@ -431,7 +431,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev,
|
|||
struct ad7280_state *st = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int ret;
|
||||
unsigned msecs;
|
||||
unsigned int msecs;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad7280_read(st, this_attr->address >> 8,
|
||||
|
@ -602,7 +602,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev,
|
|||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad7280_state *st = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
unsigned val;
|
||||
unsigned int val;
|
||||
|
||||
switch ((u32)this_attr->address) {
|
||||
case AD7280A_CELL_OVERVOLTAGE:
|
||||
|
@ -683,7 +683,7 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
|
|||
{
|
||||
struct iio_dev *indio_dev = private;
|
||||
struct ad7280_state *st = iio_priv(indio_dev);
|
||||
unsigned *channels;
|
||||
unsigned int *channels;
|
||||
int i, ret;
|
||||
|
||||
channels = kcalloc(st->scan_cnt, sizeof(*channels), GFP_KERNEL);
|
||||
|
|
|
@ -29,10 +29,10 @@
|
|||
#define AD7280A_ALERT_REMOVE_AUX4_AUX5 BIT(1)
|
||||
|
||||
struct ad7280_platform_data {
|
||||
unsigned acquisition_time;
|
||||
unsigned conversion_averaging;
|
||||
unsigned chain_last_alert_ignore;
|
||||
bool thermistor_term_en;
|
||||
unsigned int acquisition_time;
|
||||
unsigned int conversion_averaging;
|
||||
unsigned int chain_last_alert_ignore;
|
||||
bool thermistor_term_en;
|
||||
};
|
||||
|
||||
#endif /* IIO_ADC_AD7280_H_ */
|
||||
|
|
|
@ -28,16 +28,16 @@
|
|||
*/
|
||||
|
||||
struct ad7606_platform_data {
|
||||
unsigned default_os;
|
||||
unsigned default_range;
|
||||
unsigned gpio_convst;
|
||||
unsigned gpio_reset;
|
||||
unsigned gpio_range;
|
||||
unsigned gpio_os0;
|
||||
unsigned gpio_os1;
|
||||
unsigned gpio_os2;
|
||||
unsigned gpio_frstdata;
|
||||
unsigned gpio_stby;
|
||||
unsigned int default_os;
|
||||
unsigned int default_range;
|
||||
unsigned int gpio_convst;
|
||||
unsigned int gpio_reset;
|
||||
unsigned int gpio_range;
|
||||
unsigned int gpio_os0;
|
||||
unsigned int gpio_os1;
|
||||
unsigned int gpio_os2;
|
||||
unsigned int gpio_frstdata;
|
||||
unsigned int gpio_stby;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ struct ad7606_chip_info {
|
|||
const char *name;
|
||||
u16 int_vref_mv;
|
||||
const struct iio_chan_spec *channels;
|
||||
unsigned num_channels;
|
||||
unsigned int num_channels;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -67,8 +67,8 @@ struct ad7606_state {
|
|||
struct work_struct poll_work;
|
||||
wait_queue_head_t wq_data_avail;
|
||||
const struct ad7606_bus_ops *bops;
|
||||
unsigned range;
|
||||
unsigned oversampling;
|
||||
unsigned int range;
|
||||
unsigned int oversampling;
|
||||
bool done;
|
||||
void __iomem *base_address;
|
||||
|
||||
|
@ -86,7 +86,7 @@ struct ad7606_bus_ops {
|
|||
};
|
||||
|
||||
struct iio_dev *ad7606_probe(struct device *dev, int irq,
|
||||
void __iomem *base_address, unsigned id,
|
||||
void __iomem *base_address, unsigned int id,
|
||||
const struct ad7606_bus_ops *bops);
|
||||
int ad7606_remove(struct iio_dev *indio_dev, int irq);
|
||||
int ad7606_reset(struct ad7606_state *st);
|
||||
|
|
|
@ -36,7 +36,7 @@ int ad7606_reset(struct ad7606_state *st)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned ch)
|
||||
static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch)
|
||||
{
|
||||
struct ad7606_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
@ -155,7 +155,7 @@ static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
|
|||
return sprintf(buf, "%u\n", st->oversampling);
|
||||
}
|
||||
|
||||
static int ad7606_oversampling_get_index(unsigned val)
|
||||
static int ad7606_oversampling_get_index(unsigned int val)
|
||||
{
|
||||
unsigned char supported[] = {0, 2, 4, 8, 16, 32, 64};
|
||||
int i;
|
||||
|
@ -446,7 +446,7 @@ static const struct iio_info ad7606_info_range = {
|
|||
|
||||
struct iio_dev *ad7606_probe(struct device *dev, int irq,
|
||||
void __iomem *base_address,
|
||||
unsigned id,
|
||||
unsigned int id,
|
||||
const struct ad7606_bus_ops *bops)
|
||||
{
|
||||
struct ad7606_platform_data *pdata = dev->platform_data;
|
||||
|
|
|
@ -63,7 +63,7 @@ static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
|
|||
enum ad_sigma_delta_mode mode)
|
||||
{
|
||||
struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta);
|
||||
unsigned val;
|
||||
unsigned int val;
|
||||
|
||||
switch (mode) {
|
||||
case AD_SD_MODE_SINGLE:
|
||||
|
|
|
@ -101,14 +101,14 @@ struct ad5933_state {
|
|||
unsigned long mclk_hz;
|
||||
unsigned char ctrl_hb;
|
||||
unsigned char ctrl_lb;
|
||||
unsigned range_avail[4];
|
||||
unsigned int range_avail[4];
|
||||
unsigned short vref_mv;
|
||||
unsigned short settling_cycles;
|
||||
unsigned short freq_points;
|
||||
unsigned freq_start;
|
||||
unsigned freq_inc;
|
||||
unsigned state;
|
||||
unsigned poll_time_jiffies;
|
||||
unsigned int freq_start;
|
||||
unsigned int freq_inc;
|
||||
unsigned int state;
|
||||
unsigned int poll_time_jiffies;
|
||||
};
|
||||
|
||||
static struct ad5933_platform_data ad5933_default_pdata = {
|
||||
|
@ -222,7 +222,7 @@ static int ad5933_wait_busy(struct ad5933_state *st, unsigned char event)
|
|||
}
|
||||
|
||||
static int ad5933_set_freq(struct ad5933_state *st,
|
||||
unsigned reg, unsigned long freq)
|
||||
unsigned int reg, unsigned long freq)
|
||||
{
|
||||
unsigned long long freqreg;
|
||||
union {
|
||||
|
@ -282,7 +282,7 @@ static int ad5933_setup(struct ad5933_state *st)
|
|||
static void ad5933_calc_out_ranges(struct ad5933_state *st)
|
||||
{
|
||||
int i;
|
||||
unsigned normalized_3v3[4] = {1980, 198, 383, 970};
|
||||
unsigned int normalized_3v3[4] = {1980, 198, 383, 970};
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
st->range_avail[i] = normalized_3v3[i] * st->vref_mv / 3300;
|
||||
|
|
|
@ -69,7 +69,6 @@ enum als_ir_mode {
|
|||
};
|
||||
|
||||
struct isl29028_chip {
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
|
||||
|
@ -166,20 +165,21 @@ static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
|
|||
|
||||
static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
|
||||
{
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
unsigned int lsb;
|
||||
unsigned int msb;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in reading register ALSIR_L err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in reading register ALSIR_U err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -190,12 +190,13 @@ static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
|
|||
|
||||
static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
|
||||
{
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
unsigned int data;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Error in reading register %d, error %d\n",
|
||||
dev_err(dev, "Error in reading register %d, error %d\n",
|
||||
ISL29028_REG_PROX_DATA, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -218,13 +219,14 @@ static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
|
|||
|
||||
static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
int ret;
|
||||
int als_ir_data;
|
||||
|
||||
if (chip->als_ir_mode != MODE_ALS) {
|
||||
ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in enabling ALS mode err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -251,12 +253,13 @@ static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
|
|||
|
||||
static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
|
||||
{
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
int ret;
|
||||
|
||||
if (chip->als_ir_mode != MODE_IR) {
|
||||
ret = isl29028_set_als_ir_mode(chip, MODE_IR);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Error in enabling IR mode err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -271,25 +274,26 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
|
|||
int val, int val2, long mask)
|
||||
{
|
||||
struct isl29028_chip *chip = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
int ret = -EINVAL;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"proximity: mask value 0x%08lx not supported\n",
|
||||
mask);
|
||||
break;
|
||||
}
|
||||
if (val < 1 || val > 100) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Samp_freq %d is not in range[1:100]\n", val);
|
||||
break;
|
||||
}
|
||||
ret = isl29028_set_proxim_sampling(chip, val);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Setting proximity samp_freq fail, err %d\n",
|
||||
ret);
|
||||
break;
|
||||
|
@ -299,19 +303,19 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
|
|||
|
||||
case IIO_LIGHT:
|
||||
if (mask != IIO_CHAN_INFO_SCALE) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"light: mask value 0x%08lx not supported\n",
|
||||
mask);
|
||||
break;
|
||||
}
|
||||
if ((val != 125) && (val != 2000)) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"lux scale %d is invalid [125, 2000]\n", val);
|
||||
break;
|
||||
}
|
||||
ret = isl29028_set_als_scale(chip, val);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev,
|
||||
dev_err(dev,
|
||||
"Setting lux scale fail with error %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
@ -319,7 +323,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev,
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_err(chip->dev, "Unsupported channel type\n");
|
||||
dev_err(dev, "Unsupported channel type\n");
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&chip->lock);
|
||||
|
@ -331,6 +335,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
|
|||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct isl29028_chip *chip = iio_priv(indio_dev);
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
int ret = -EINVAL;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
|
@ -370,7 +375,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev,
|
|||
break;
|
||||
|
||||
default:
|
||||
dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
|
||||
dev_err(dev, "mask value 0x%08lx not supported\n", mask);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&chip->lock);
|
||||
|
@ -417,6 +422,7 @@ static const struct iio_info isl29028_info = {
|
|||
|
||||
static int isl29028_chip_init(struct isl29028_chip *chip)
|
||||
{
|
||||
struct device *dev = regmap_get_device(chip->regmap);
|
||||
int ret;
|
||||
|
||||
chip->enable_prox = false;
|
||||
|
@ -426,35 +432,33 @@ static int isl29028_chip_init(struct isl29028_chip *chip)
|
|||
|
||||
ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
__func__, ISL29028_REG_TEST1_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
__func__, ISL29028_REG_TEST2_MODE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
|
||||
__func__, ISL29028_REG_CONFIGURE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "setting the proximity, err = %d\n",
|
||||
ret);
|
||||
dev_err(dev, "setting the proximity, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = isl29028_set_als_scale(chip, chip->lux_scale);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev,
|
||||
"setting als scale failed, err = %d\n", ret);
|
||||
dev_err(dev, "setting als scale failed, err = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -496,19 +500,19 @@ static int isl29028_probe(struct i2c_client *client,
|
|||
chip = iio_priv(indio_dev);
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
chip->dev = &client->dev;
|
||||
mutex_init(&chip->lock);
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
ret = PTR_ERR(chip->regmap);
|
||||
dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
|
||||
dev_err(&client->dev, "regmap initialization failed: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = isl29028_chip_init(chip);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "chip initialization failed: %d\n", ret);
|
||||
dev_err(&client->dev, "chip initialization failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -520,7 +524,8 @@ static int isl29028_probe(struct i2c_client *client,
|
|||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "iio registration fails with error %d\n",
|
||||
dev_err(&client->dev,
|
||||
"iio registration fails with error %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ade7758_write_waveform_type(struct device *dev, unsigned type)
|
||||
static int ade7758_write_waveform_type(struct device *dev, unsigned int type)
|
||||
{
|
||||
int ret;
|
||||
u8 reg;
|
||||
|
@ -85,7 +85,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
|
|||
**/
|
||||
static int ade7758_ring_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
unsigned channel;
|
||||
unsigned int channel;
|
||||
|
||||
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
|
||||
return -EINVAL;
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#define _AD2S1210_H
|
||||
|
||||
struct ad2s1210_platform_data {
|
||||
unsigned sample;
|
||||
unsigned a[2];
|
||||
unsigned res[2];
|
||||
bool gpioin;
|
||||
unsigned int sample;
|
||||
unsigned int a[2];
|
||||
unsigned int res[2];
|
||||
bool gpioin;
|
||||
};
|
||||
#endif /* _AD2S1210_H */
|
||||
|
|
|
@ -55,12 +55,12 @@ static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
|
|||
};
|
||||
|
||||
struct bfin_tmr_state {
|
||||
struct iio_trigger *trig;
|
||||
struct bfin_timer *t;
|
||||
unsigned timer_num;
|
||||
bool output_enable;
|
||||
unsigned int duty;
|
||||
int irq;
|
||||
struct iio_trigger *trig;
|
||||
struct bfin_timer *t;
|
||||
unsigned int timer_num;
|
||||
bool output_enable;
|
||||
unsigned int duty;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
|
||||
|
|
|
@ -83,10 +83,12 @@ struct iio_buffer_access_funcs {
|
|||
* @access: [DRIVER] buffer access functions associated with the
|
||||
* implementation.
|
||||
* @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
|
||||
* @buffer_group: [INTERN] attributes of the buffer group
|
||||
* @scan_el_group: [DRIVER] attribute group for those attributes not
|
||||
* created from the iio_chan_info array.
|
||||
* @pollq: [INTERN] wait queue to allow for polling on the buffer.
|
||||
* @stufftoread: [INTERN] flag to indicate new data.
|
||||
* @attrs: [INTERN] standard attributes of the buffer
|
||||
* @demux_list: [INTERN] list of operations required to demux the scan.
|
||||
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
|
||||
* @buffer_list: [INTERN] entry in the devices list of current buffers.
|
||||
|
|
|
@ -527,6 +527,8 @@ void iio_device_unregister(struct iio_dev *indio_dev);
|
|||
int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev);
|
||||
void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev);
|
||||
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
|
||||
int iio_device_claim_direct_mode(struct iio_dev *indio_dev);
|
||||
void iio_device_release_direct_mode(struct iio_dev *indio_dev);
|
||||
|
||||
extern struct bus_type iio_bus_type;
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ enum iio_chan_type {
|
|||
IIO_CONCENTRATION,
|
||||
IIO_RESISTANCE,
|
||||
IIO_PH,
|
||||
IIO_UVINDEX,
|
||||
};
|
||||
|
||||
enum iio_modifier {
|
||||
|
@ -77,6 +78,7 @@ enum iio_modifier {
|
|||
IIO_MOD_Q,
|
||||
IIO_MOD_CO2,
|
||||
IIO_MOD_VOC,
|
||||
IIO_MOD_LIGHT_UV,
|
||||
};
|
||||
|
||||
enum iio_event_type {
|
||||
|
|
|
@ -304,7 +304,19 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
/* Verify the trigger exists */
|
||||
/* Look for this "-devN" trigger */
|
||||
trig_num = find_type_by_name(trigger_name, "trigger");
|
||||
if (trig_num < 0) {
|
||||
/* OK try the simpler "-trigger" suffix instead */
|
||||
free(trigger_name);
|
||||
ret = asprintf(&trigger_name,
|
||||
"%s-trigger", device_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_dev_dir_name;
|
||||
}
|
||||
}
|
||||
|
||||
trig_num = find_type_by_name(trigger_name, "trigger");
|
||||
if (trig_num < 0) {
|
||||
fprintf(stderr, "Failed to find the trigger %s\n",
|
||||
|
|
|
@ -53,6 +53,10 @@ static const char * const iio_chan_type_name_spec[] = {
|
|||
[IIO_ENERGY] = "energy",
|
||||
[IIO_DISTANCE] = "distance",
|
||||
[IIO_VELOCITY] = "velocity",
|
||||
[IIO_CONCENTRATION] = "concentration",
|
||||
[IIO_RESISTANCE] = "resistance",
|
||||
[IIO_PH] = "ph",
|
||||
[IIO_UVINDEX] = "uvindex",
|
||||
};
|
||||
|
||||
static const char * const iio_ev_type_text[] = {
|
||||
|
@ -90,6 +94,7 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_LIGHT_RED] = "red",
|
||||
[IIO_MOD_LIGHT_GREEN] = "green",
|
||||
[IIO_MOD_LIGHT_BLUE] = "blue",
|
||||
[IIO_MOD_LIGHT_UV] = "uv",
|
||||
[IIO_MOD_QUATERNION] = "quaternion",
|
||||
[IIO_MOD_TEMP_AMBIENT] = "ambient",
|
||||
[IIO_MOD_TEMP_OBJECT] = "object",
|
||||
|
@ -102,6 +107,10 @@ static const char * const iio_modifier_names[] = {
|
|||
[IIO_MOD_WALKING] = "walking",
|
||||
[IIO_MOD_STILL] = "still",
|
||||
[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
|
||||
[IIO_MOD_I] = "i",
|
||||
[IIO_MOD_Q] = "q",
|
||||
[IIO_MOD_CO2] = "co2",
|
||||
[IIO_MOD_VOC] = "voc",
|
||||
};
|
||||
|
||||
static bool event_is_known(struct iio_event_data *event)
|
||||
|
@ -136,6 +145,10 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_ENERGY:
|
||||
case IIO_DISTANCE:
|
||||
case IIO_VELOCITY:
|
||||
case IIO_CONCENTRATION:
|
||||
case IIO_RESISTANCE:
|
||||
case IIO_PH:
|
||||
case IIO_UVINDEX:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
@ -162,6 +175,7 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_MOD_LIGHT_RED:
|
||||
case IIO_MOD_LIGHT_GREEN:
|
||||
case IIO_MOD_LIGHT_BLUE:
|
||||
case IIO_MOD_LIGHT_UV:
|
||||
case IIO_MOD_QUATERNION:
|
||||
case IIO_MOD_TEMP_AMBIENT:
|
||||
case IIO_MOD_TEMP_OBJECT:
|
||||
|
@ -174,6 +188,10 @@ static bool event_is_known(struct iio_event_data *event)
|
|||
case IIO_MOD_WALKING:
|
||||
case IIO_MOD_STILL:
|
||||
case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z:
|
||||
case IIO_MOD_I:
|
||||
case IIO_MOD_Q:
|
||||
case IIO_MOD_CO2:
|
||||
case IIO_MOD_VOC:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue