mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 17:53:56 +08:00
Third set of new device support, cleanups and features for IIO in the 4.12 cycle
Somewhat dominated in patch numbers of last of the outreachy application window related patches (they are still coming, despite window being closed which is good to see!) Good set of new drivers as well. New device support * ASPEED ADC - new driver * cpcap PMIC ADC - new driver * hid-humidity - driver for HID compatible humidity sensors. * ltc2497 ADC - new driver * mpu6050 - bring bindings up to date and add trivial support for 9250 * rockchip-saradc - update bindings to cover rk3328 * vl6180 light, proximity and time of flight sensor. - new driver Features * meson-saradc - add calibration Cleanup and minor fixes * ad5504 - constify attribute_group structure - drop casting of void * * ad7150 - replace some shifts of 1 by BIT macro usage * ad7152 - blank lines between function definitions * ad7280a - octal permissions. * ad7606 - replace use of core mlock mutex with a local lock * ad7746 - replace some shifts of 1 by BIT macro usage - function parameter alignment - drop some excessive brackets (introduced in last pull request) * ad7753 - white space cleanup * ad7754 - includes in alphabetical order and groupped appropriately. - change from missuse of internal mlock mutex to using the buffer lock to also protect values during frequency update. * ad779x - constify attribute_group structures * ad9832 - octal permissions * adis16060 - remove use of core mlock mutex in favour of adding a local _spi_write_then_read which can use the local buffer protection lock. - fix naming of above function. * adis16203 - remove locking during reads of calibbias that doesn't protect anything not protected elsewhere. * adis16209 - remove unnecessary braces in single statement if * adis16240 - remove unnecessary braces in single statement if * adt7136 - drop excess blank lines and put some in between functions. * ams-iaq - replace comma with semi colon. Not actual bug, just unusual syntax. * apds9960 - constify attribute group structure * as3935 - constify attribute group structure * bm1750 - constify attribute group structure * cros_ec - devm version of triggered buffer setup to simplify code. * exynos - drop casting of void * * hdc100x - constify attribute_group structure * hid-accel - fix wrong scale for newly introduced gravity sensor. * hts221 - drop casting of void * * hx711 - constify attribute_group structure * imx7d_adc - drop casting of void * * lm35333 - constify attribute_group structure * lsm6dsx - drop casting of void * - hold ODR configuration until enabling to avoid a race condition. * max1027 - drop casting of void * * max11100 - fix a comma where semicolon was intended (no actual bug, just odd) * max1363 - constify attribute_group structure * ms sensors - drop casting of void * * rockchip_saradc - drop casting of void * * sun4i-gpadc - fix missing dependency on THERMAL or presence of stubs (issue only introduced in pervious set) - drop casting of void * * tsl2x7x - fix wrong standard deviation calc. Note these aren't actually used for anything at the moment so bug didn't really matter. - constify attribute group structure. * vf610adc - drop casting of void * * vz89x - replace comma with semicolon. Not actual bug, just odd syntax. * zpa2326 - drop casting of void * -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAljhRoIRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0Fohx7Q//ZFhtcXjdZhc38u2LbbKYL68PLK2upREm 2lXOgM7WzRAxWKTk3om2b2Wc289dWclGe5eJp2gpV8HjnoOxiiGFyzZvDOA1mL1E rHBhlytSxOqOGs9ELMfkAWYfTtW28LN4+6bYM7kJ0ItDptxvBEyxh4KLYlkWpYpc LSk26+N29n2ZMeb0yCmwQgkHMWF6kK7bpDhAF530x8hN6vSd8C+OE0G2pb4SaAn6 wNANJ2SUwAq6jS2TzcQfjTjKnIK9/jwRZCWoEr/JL/I7M8kpQGXzIapzNhNyCODL ymuylr/LP82rf3Kp/himx4wxTHQ99GQHhiQedIJTGSjcCSR6mpTtwYfoMJ6rmoDZ t60FC9worLoqTnqIUxaP3yQSqwy/Hj1Kd1IJmiZFJjm4ki8/YxTHbQfFS6OK0s2j lZKN8WYvytZNArdrxMKjNGUt8y3dW1orP31ykNoxN4znhVQTGIoSc5D4Oi2NUTmY MhM97jzLmlOgMVHp5NAkb9iiz0JccobIFQnwjyiyyS3Q6FW4hQeypzoBO+HhZoYz d6+3zK2LAz8+idN8UsiALYtVLII/khhMw0N0/jLiqNW3Ceh4DPdP4BTz8aa8bNNc DpzeFjhHzXqmBvwyvneGaUZIRGM1uNR8FO7+qsjmw1uet7Kfyfs2arL6KfeThox7 nxVGjupwpuo= =YYdq -----END PGP SIGNATURE----- Merge tag 'iio-for-4.12c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Third set of new device support, cleanups and features for IIO in the 4.12 cycle Somewhat dominated in patch numbers of last of the outreachy application window related patches (they are still coming, despite window being closed which is good to see!) Good set of new drivers as well. New device support * ASPEED ADC - new driver * cpcap PMIC ADC - new driver * hid-humidity - driver for HID compatible humidity sensors. * ltc2497 ADC - new driver * mpu6050 - bring bindings up to date and add trivial support for 9250 * rockchip-saradc - update bindings to cover rk3328 * vl6180 light, proximity and time of flight sensor. - new driver Features * meson-saradc - add calibration Cleanup and minor fixes * ad5504 - constify attribute_group structure - drop casting of void * * ad7150 - replace some shifts of 1 by BIT macro usage * ad7152 - blank lines between function definitions * ad7280a - octal permissions. * ad7606 - replace use of core mlock mutex with a local lock * ad7746 - replace some shifts of 1 by BIT macro usage - function parameter alignment - drop some excessive brackets (introduced in last pull request) * ad7753 - white space cleanup * ad7754 - includes in alphabetical order and groupped appropriately. - change from missuse of internal mlock mutex to using the buffer lock to also protect values during frequency update. * ad779x - constify attribute_group structures * ad9832 - octal permissions * adis16060 - remove use of core mlock mutex in favour of adding a local _spi_write_then_read which can use the local buffer protection lock. - fix naming of above function. * adis16203 - remove locking during reads of calibbias that doesn't protect anything not protected elsewhere. * adis16209 - remove unnecessary braces in single statement if * adis16240 - remove unnecessary braces in single statement if * adt7136 - drop excess blank lines and put some in between functions. * ams-iaq - replace comma with semi colon. Not actual bug, just unusual syntax. * apds9960 - constify attribute group structure * as3935 - constify attribute group structure * bm1750 - constify attribute group structure * cros_ec - devm version of triggered buffer setup to simplify code. * exynos - drop casting of void * * hdc100x - constify attribute_group structure * hid-accel - fix wrong scale for newly introduced gravity sensor. * hts221 - drop casting of void * * hx711 - constify attribute_group structure * imx7d_adc - drop casting of void * * lm35333 - constify attribute_group structure * lsm6dsx - drop casting of void * - hold ODR configuration until enabling to avoid a race condition. * max1027 - drop casting of void * * max11100 - fix a comma where semicolon was intended (no actual bug, just odd) * max1363 - constify attribute_group structure * ms sensors - drop casting of void * * rockchip_saradc - drop casting of void * * sun4i-gpadc - fix missing dependency on THERMAL or presence of stubs (issue only introduced in pervious set) - drop casting of void * * tsl2x7x - fix wrong standard deviation calc. Note these aren't actually used for anything at the moment so bug didn't really matter. - constify attribute group structure. * vf610adc - drop casting of void * * vz89x - replace comma with semicolon. Not actual bug, just odd syntax. * zpa2326 - drop casting of void *
This commit is contained in:
commit
edf5e79422
20
Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
Normal file
20
Documentation/devicetree/bindings/iio/adc/aspeed_adc.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Aspeed ADC
|
||||
|
||||
This device is a 10-bit converter for 16 voltage channels. All inputs are
|
||||
single ended.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "aspeed,ast2400-adc" or "aspeed,ast2500-adc"
|
||||
- reg: memory window mapping address and length
|
||||
- clocks: Input clock used to derive the sample clock. Expected to be the
|
||||
SoC's APB clock.
|
||||
- #io-channel-cells: Must be set to <1> to indicate channels are selected
|
||||
by index.
|
||||
|
||||
Example:
|
||||
adc@1e6e9000 {
|
||||
compatible = "aspeed,ast2400-adc";
|
||||
reg = <0x1e6e9000 0xb0>;
|
||||
clocks = <&clk_apb>;
|
||||
#io-channel-cells = <1>;
|
||||
};
|
18
Documentation/devicetree/bindings/iio/adc/cpcap-adc.txt
Normal file
18
Documentation/devicetree/bindings/iio/adc/cpcap-adc.txt
Normal file
@ -0,0 +1,18 @@
|
||||
Motorola CPCAP PMIC ADC binding
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "motorola,cpcap-adc" or "motorola,mapphone-cpcap-adc"
|
||||
- interrupt-parent: The interrupt controller
|
||||
- interrupts: The interrupt number for the ADC device
|
||||
- interrupt-names: Should be "adcdone"
|
||||
- #io-channel-cells: Number of cells in an IIO specifier
|
||||
|
||||
Example:
|
||||
|
||||
cpcap_adc: adc {
|
||||
compatible = "motorola,mapphone-cpcap-adc";
|
||||
interrupt-parent = <&cpcap>;
|
||||
interrupts = <8 IRQ_TYPE_NONE>;
|
||||
interrupt-names = "adcdone";
|
||||
#io-channel-cells = <1>;
|
||||
};
|
13
Documentation/devicetree/bindings/iio/adc/ltc2497.txt
Normal file
13
Documentation/devicetree/bindings/iio/adc/ltc2497.txt
Normal file
@ -0,0 +1,13 @@
|
||||
* Linear Technology / Analog Devices LTC2497 ADC
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "lltc,ltc2497"
|
||||
- reg: Must contain the ADC I2C address
|
||||
- vref-supply: The regulator supply for ADC reference voltage
|
||||
|
||||
Example:
|
||||
ltc2497: adc@76 {
|
||||
compatible = "lltc,ltc2497";
|
||||
reg = <0x76>;
|
||||
vref-supply = <<c2497_reg>;
|
||||
};
|
@ -4,6 +4,7 @@ Required properties:
|
||||
- compatible: should be "rockchip,<name>-saradc" or "rockchip,rk3066-tsadc"
|
||||
- "rockchip,saradc": for rk3188, rk3288
|
||||
- "rockchip,rk3066-tsadc": for rk3036
|
||||
- "rockchip,rk3328-saradc", "rockchip,rk3399-saradc": for rk3328
|
||||
- "rockchip,rk3399-saradc": for rk3399
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
|
@ -3,14 +3,21 @@ InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
|
||||
http://www.invensense.com/mems/gyro/mpu6050.html
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "invensense,mpu6050"
|
||||
- compatible : should be one of
|
||||
"invensense,mpu6050"
|
||||
"invensense,mpu6500"
|
||||
"invensense,mpu9150"
|
||||
"invensense,mpu9250"
|
||||
"invensense,icm20608"
|
||||
- reg : the I2C address of the sensor
|
||||
- interrupt-parent : should be the phandle for the interrupt controller
|
||||
- interrupts : interrupt mapping for GPIO IRQ
|
||||
|
||||
Optional properties:
|
||||
- mount-matrix: an optional 3x3 mounting rotation matrix
|
||||
|
||||
- i2c-gate node. These devices also support an auxiliary i2c bus. This is
|
||||
simple enough to be described using the i2c-gate binding. See
|
||||
i2c/i2c-gate.txt for more details.
|
||||
|
||||
Example:
|
||||
mpu6050@68 {
|
||||
@ -28,3 +35,19 @@ Example:
|
||||
"0", /* y2 */
|
||||
"0.984807753012208"; /* z2 */
|
||||
};
|
||||
|
||||
|
||||
mpu9250@68 {
|
||||
compatible = "invensense,mpu9250";
|
||||
reg = <0x68>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <21 1>;
|
||||
i2c-gate {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ax8975@c {
|
||||
compatible = "ak,ak8975";
|
||||
reg = <0x0c>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
15
Documentation/devicetree/bindings/iio/light/vl6180.txt
Normal file
15
Documentation/devicetree/bindings/iio/light/vl6180.txt
Normal file
@ -0,0 +1,15 @@
|
||||
STMicro VL6180 - ALS, range and proximity sensor
|
||||
|
||||
Link to datasheet: http://www.st.com/resource/en/datasheet/vl6180x.pdf
|
||||
|
||||
Required properties:
|
||||
|
||||
-compatible: should be "st,vl6180"
|
||||
-reg: the I2C address of the sensor
|
||||
|
||||
Example:
|
||||
|
||||
vl6180@29 {
|
||||
compatible = "st,vl6180";
|
||||
reg = <0x29>;
|
||||
};
|
@ -813,6 +813,7 @@ W: http://wiki.analog.com/
|
||||
W: http://ez.analog.com/community/linux-device-drivers
|
||||
S: Supported
|
||||
F: drivers/iio/*/ad*
|
||||
F: drivers/iio/adc/ltc2497*
|
||||
X: drivers/iio/*/adjd*
|
||||
F: drivers/staging/iio/*/ad*
|
||||
F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c
|
||||
|
@ -130,6 +130,17 @@ config AD799X
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ad799x.
|
||||
|
||||
config ASPEED_ADC
|
||||
tristate "Aspeed ADC"
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
If you say yes here you get support for the ADC included in Aspeed
|
||||
BMC SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called aspeed_adc.
|
||||
|
||||
config AT91_ADC
|
||||
tristate "Atmel AT91 ADC"
|
||||
depends on ARCH_AT91
|
||||
@ -195,6 +206,17 @@ config CC10001_ADC
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called cc10001_adc.
|
||||
|
||||
config CPCAP_ADC
|
||||
tristate "Motorola CPCAP PMIC ADC driver"
|
||||
depends on MFD_CPCAP
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Motorola CPCAP PMIC ADC.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called cpcap-adc.
|
||||
|
||||
config DA9150_GPADC
|
||||
tristate "Dialog DA9150 GPADC driver support"
|
||||
depends on MFD_DA9150
|
||||
@ -326,6 +348,16 @@ config LTC2485
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ltc2485.
|
||||
|
||||
config LTC2497
|
||||
tristate "Linear Technology LTC2497 ADC driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Linear Technology LTC2497
|
||||
16-Bit 8-/16-Channel Delta Sigma ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ltc2497.
|
||||
|
||||
config MAX1027
|
||||
tristate "Maxim max1027 ADC driver"
|
||||
depends on SPI
|
||||
@ -563,6 +595,7 @@ config SUN4I_GPADC
|
||||
tristate "Support for the Allwinner SoCs GPADC"
|
||||
depends on IIO
|
||||
depends on MFD_SUN4I_GPADC
|
||||
depends on THERMAL || !THERMAL_OF
|
||||
help
|
||||
Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
|
||||
GPADC. This ADC provides 4 channels which can be used as an ADC or as
|
||||
|
@ -14,12 +14,14 @@ obj-$(CONFIG_AD7791) += ad7791.o
|
||||
obj-$(CONFIG_AD7793) += ad7793.o
|
||||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
|
||||
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
|
||||
obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
|
||||
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
|
||||
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
|
||||
obj-$(CONFIG_CPCAP_ADC) += cpcap-adc.o
|
||||
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
|
||||
obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
@ -32,6 +34,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
|
||||
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
|
||||
obj-$(CONFIG_LTC2485) += ltc2485.o
|
||||
obj-$(CONFIG_LTC2497) += ltc2497.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX11100) += max11100.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
|
@ -520,7 +520,7 @@ static struct attribute *ad799x_event_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ad799x_event_attrs_group = {
|
||||
static const struct attribute_group ad799x_event_attrs_group = {
|
||||
.attrs = ad799x_event_attributes,
|
||||
};
|
||||
|
||||
|
295
drivers/iio/adc/aspeed_adc.c
Normal file
295
drivers/iio/adc/aspeed_adc.c
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Aspeed AST2400/2500 ADC
|
||||
*
|
||||
* Copyright (C) 2017 Google, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/driver.h>
|
||||
|
||||
#define ASPEED_RESOLUTION_BITS 10
|
||||
#define ASPEED_CLOCKS_PER_SAMPLE 12
|
||||
|
||||
#define ASPEED_REG_ENGINE_CONTROL 0x00
|
||||
#define ASPEED_REG_INTERRUPT_CONTROL 0x04
|
||||
#define ASPEED_REG_VGA_DETECT_CONTROL 0x08
|
||||
#define ASPEED_REG_CLOCK_CONTROL 0x0C
|
||||
#define ASPEED_REG_MAX 0xC0
|
||||
|
||||
#define ASPEED_OPERATION_MODE_POWER_DOWN (0x0 << 1)
|
||||
#define ASPEED_OPERATION_MODE_STANDBY (0x1 << 1)
|
||||
#define ASPEED_OPERATION_MODE_NORMAL (0x7 << 1)
|
||||
|
||||
#define ASPEED_ENGINE_ENABLE BIT(0)
|
||||
|
||||
struct aspeed_adc_model_data {
|
||||
const char *model_name;
|
||||
unsigned int min_sampling_rate; // Hz
|
||||
unsigned int max_sampling_rate; // Hz
|
||||
unsigned int vref_voltage; // mV
|
||||
};
|
||||
|
||||
struct aspeed_adc_data {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
spinlock_t clk_lock;
|
||||
struct clk_hw *clk_prescaler;
|
||||
struct clk_hw *clk_scaler;
|
||||
};
|
||||
|
||||
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_idx), \
|
||||
.address = (_data_reg_addr), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
|
||||
ASPEED_CHAN(0, 0x10),
|
||||
ASPEED_CHAN(1, 0x12),
|
||||
ASPEED_CHAN(2, 0x14),
|
||||
ASPEED_CHAN(3, 0x16),
|
||||
ASPEED_CHAN(4, 0x18),
|
||||
ASPEED_CHAN(5, 0x1A),
|
||||
ASPEED_CHAN(6, 0x1C),
|
||||
ASPEED_CHAN(7, 0x1E),
|
||||
ASPEED_CHAN(8, 0x20),
|
||||
ASPEED_CHAN(9, 0x22),
|
||||
ASPEED_CHAN(10, 0x24),
|
||||
ASPEED_CHAN(11, 0x26),
|
||||
ASPEED_CHAN(12, 0x28),
|
||||
ASPEED_CHAN(13, 0x2A),
|
||||
ASPEED_CHAN(14, 0x2C),
|
||||
ASPEED_CHAN(15, 0x2E),
|
||||
};
|
||||
|
||||
static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct aspeed_adc_data *data = iio_priv(indio_dev);
|
||||
const struct aspeed_adc_model_data *model_data =
|
||||
of_device_get_match_data(data->dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
*val = readw(data->base + chan->address);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = model_data->vref_voltage;
|
||||
*val2 = ASPEED_RESOLUTION_BITS;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = clk_get_rate(data->clk_scaler->clk) /
|
||||
ASPEED_CLOCKS_PER_SAMPLE;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct aspeed_adc_data *data = iio_priv(indio_dev);
|
||||
const struct aspeed_adc_model_data *model_data =
|
||||
of_device_get_match_data(data->dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
if (val < model_data->min_sampling_rate ||
|
||||
val > model_data->max_sampling_rate)
|
||||
return -EINVAL;
|
||||
|
||||
clk_set_rate(data->clk_scaler->clk,
|
||||
val * ASPEED_CLOCKS_PER_SAMPLE);
|
||||
return 0;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
/*
|
||||
* Technically, these could be written but the only reasons
|
||||
* for doing so seem better handled in userspace. EPERM is
|
||||
* returned to signal this is a policy choice rather than a
|
||||
* hardware limitation.
|
||||
*/
|
||||
return -EPERM;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int aspeed_adc_reg_access(struct iio_dev *indio_dev,
|
||||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
struct aspeed_adc_data *data = iio_priv(indio_dev);
|
||||
|
||||
if (!readval || reg % 4 || reg > ASPEED_REG_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
*readval = readl(data->base + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_info aspeed_adc_iio_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = aspeed_adc_read_raw,
|
||||
.write_raw = aspeed_adc_write_raw,
|
||||
.debugfs_reg_access = aspeed_adc_reg_access,
|
||||
};
|
||||
|
||||
static int aspeed_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct aspeed_adc_data *data;
|
||||
const struct aspeed_adc_model_data *model_data;
|
||||
struct resource *res;
|
||||
const char *clk_parent_name;
|
||||
int ret;
|
||||
u32 adc_engine_control_reg_val;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
data->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
data->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(data->base))
|
||||
return PTR_ERR(data->base);
|
||||
|
||||
/* Register ADC clock prescaler with source specified by device tree. */
|
||||
spin_lock_init(&data->clk_lock);
|
||||
clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
|
||||
|
||||
data->clk_prescaler = clk_hw_register_divider(
|
||||
&pdev->dev, "prescaler", clk_parent_name, 0,
|
||||
data->base + ASPEED_REG_CLOCK_CONTROL,
|
||||
17, 15, 0, &data->clk_lock);
|
||||
if (IS_ERR(data->clk_prescaler))
|
||||
return PTR_ERR(data->clk_prescaler);
|
||||
|
||||
/*
|
||||
* Register ADC clock scaler downstream from the prescaler. Allow rate
|
||||
* setting to adjust the prescaler as well.
|
||||
*/
|
||||
data->clk_scaler = clk_hw_register_divider(
|
||||
&pdev->dev, "scaler", "prescaler",
|
||||
CLK_SET_RATE_PARENT,
|
||||
data->base + ASPEED_REG_CLOCK_CONTROL,
|
||||
0, 10, 0, &data->clk_lock);
|
||||
if (IS_ERR(data->clk_scaler)) {
|
||||
ret = PTR_ERR(data->clk_scaler);
|
||||
goto scaler_error;
|
||||
}
|
||||
|
||||
/* Start all channels in normal mode. */
|
||||
clk_prepare_enable(data->clk_scaler->clk);
|
||||
adc_engine_control_reg_val = GENMASK(31, 16) |
|
||||
ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
|
||||
writel(adc_engine_control_reg_val,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
|
||||
model_data = of_device_get_match_data(&pdev->dev);
|
||||
indio_dev->name = model_data->model_name;
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &aspeed_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = aspeed_adc_iio_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto iio_register_error;
|
||||
|
||||
return 0;
|
||||
|
||||
iio_register_error:
|
||||
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
clk_disable_unprepare(data->clk_scaler->clk);
|
||||
clk_hw_unregister_divider(data->clk_scaler);
|
||||
|
||||
scaler_error:
|
||||
clk_hw_unregister_divider(data->clk_prescaler);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aspeed_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct aspeed_adc_data *data = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
|
||||
data->base + ASPEED_REG_ENGINE_CONTROL);
|
||||
clk_disable_unprepare(data->clk_scaler->clk);
|
||||
clk_hw_unregister_divider(data->clk_scaler);
|
||||
clk_hw_unregister_divider(data->clk_prescaler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct aspeed_adc_model_data ast2400_model_data = {
|
||||
.model_name = "ast2400-adc",
|
||||
.vref_voltage = 2500, // mV
|
||||
.min_sampling_rate = 10000,
|
||||
.max_sampling_rate = 500000,
|
||||
};
|
||||
|
||||
static const struct aspeed_adc_model_data ast2500_model_data = {
|
||||
.model_name = "ast2500-adc",
|
||||
.vref_voltage = 1800, // mV
|
||||
.min_sampling_rate = 1,
|
||||
.max_sampling_rate = 1000000,
|
||||
};
|
||||
|
||||
static const struct of_device_id aspeed_adc_matches[] = {
|
||||
{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
|
||||
{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
|
||||
|
||||
static struct platform_driver aspeed_adc_driver = {
|
||||
.probe = aspeed_adc_probe,
|
||||
.remove = aspeed_adc_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = aspeed_adc_matches,
|
||||
}
|
||||
};
|
||||
|
||||
module_platform_driver(aspeed_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
|
||||
MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
|
||||
MODULE_LICENSE("GPL");
|
1007
drivers/iio/adc/cpcap-adc.c
Normal file
1007
drivers/iio/adc/cpcap-adc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -579,7 +579,7 @@ static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y)
|
||||
|
||||
static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct exynos_adc *info = (struct exynos_adc *)dev_id;
|
||||
struct exynos_adc *info = dev_id;
|
||||
u32 mask = info->data->mask;
|
||||
|
||||
/* Read value */
|
||||
|
@ -369,7 +369,7 @@ static struct attribute *hx711_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group hx711_attribute_group = {
|
||||
static const struct attribute_group hx711_attribute_group = {
|
||||
.attrs = hx711_attributes,
|
||||
};
|
||||
|
||||
|
@ -365,7 +365,7 @@ static int imx7d_adc_read_data(struct imx7d_adc *info)
|
||||
|
||||
static irqreturn_t imx7d_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct imx7d_adc *info = (struct imx7d_adc *)dev_id;
|
||||
struct imx7d_adc *info = dev_id;
|
||||
int status;
|
||||
|
||||
status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS);
|
||||
|
279
drivers/iio/adc/ltc2497.c
Normal file
279
drivers/iio/adc/ltc2497.c
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* ltc2497.c - Driver for Analog Devices/Linear Technology LTC2497 ADC
|
||||
*
|
||||
* Copyright (C) 2017 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*
|
||||
* Datasheet: http://cds.linear.com/docs/en/datasheet/2497fd.pdf
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define LTC2497_ENABLE 0xA0
|
||||
#define LTC2497_SGL BIT(4)
|
||||
#define LTC2497_DIFF 0
|
||||
#define LTC2497_SIGN BIT(3)
|
||||
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
|
||||
#define LTC2497_CONVERSION_TIME_MS 150ULL
|
||||
|
||||
struct ltc2497_st {
|
||||
struct i2c_client *client;
|
||||
struct regulator *ref;
|
||||
ktime_t time_prev;
|
||||
u8 addr_prev;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) requires the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
__be32 buf ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static int ltc2497_wait_conv(struct ltc2497_st *st)
|
||||
{
|
||||
s64 time_elapsed;
|
||||
|
||||
time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
|
||||
|
||||
if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
|
||||
/* delay if conversion time not passed
|
||||
* since last read or write
|
||||
*/
|
||||
if (msleep_interruptible(
|
||||
LTC2497_CONVERSION_TIME_MS - time_elapsed))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
|
||||
/* We're in automatic mode -
|
||||
* so the last reading is stil not outdated
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ltc2497_read(struct ltc2497_st *st, u8 address, int *val)
|
||||
{
|
||||
struct i2c_client *client = st->client;
|
||||
int ret;
|
||||
|
||||
ret = ltc2497_wait_conv(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret || st->addr_prev != address) {
|
||||
ret = i2c_smbus_write_byte(st->client,
|
||||
LTC2497_ENABLE | address);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
st->addr_prev = address;
|
||||
if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
ret = i2c_master_recv(client, (char *)&st->buf, 3);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "i2c_master_recv failed\n");
|
||||
return ret;
|
||||
}
|
||||
st->time_prev = ktime_get();
|
||||
|
||||
/* convert and shift the result,
|
||||
* and finally convert from offset binary to signed integer
|
||||
*/
|
||||
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2497_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct ltc2497_st *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ltc2497_read(st, chan->address, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = regulator_get_voltage(st->ref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = ret / 1000;
|
||||
*val2 = 17;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#define LTC2497_CHAN(_chan, _addr) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_chan), \
|
||||
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
}
|
||||
|
||||
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
|
||||
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
|
||||
.address = (_addr | _chan), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.differential = 1, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ltc2497_channel[] = {
|
||||
LTC2497_CHAN(0, LTC2497_SGL),
|
||||
LTC2497_CHAN(1, LTC2497_SGL),
|
||||
LTC2497_CHAN(2, LTC2497_SGL),
|
||||
LTC2497_CHAN(3, LTC2497_SGL),
|
||||
LTC2497_CHAN(4, LTC2497_SGL),
|
||||
LTC2497_CHAN(5, LTC2497_SGL),
|
||||
LTC2497_CHAN(6, LTC2497_SGL),
|
||||
LTC2497_CHAN(7, LTC2497_SGL),
|
||||
LTC2497_CHAN(8, LTC2497_SGL),
|
||||
LTC2497_CHAN(9, LTC2497_SGL),
|
||||
LTC2497_CHAN(10, LTC2497_SGL),
|
||||
LTC2497_CHAN(11, LTC2497_SGL),
|
||||
LTC2497_CHAN(12, LTC2497_SGL),
|
||||
LTC2497_CHAN(13, LTC2497_SGL),
|
||||
LTC2497_CHAN(14, LTC2497_SGL),
|
||||
LTC2497_CHAN(15, LTC2497_SGL),
|
||||
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
|
||||
LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
|
||||
LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
|
||||
};
|
||||
|
||||
static const struct iio_info ltc2497_info = {
|
||||
.read_raw = ltc2497_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ltc2497_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct ltc2497_st *st;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
st->client = client;
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->info = <c2497_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ltc2497_channel;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel);
|
||||
|
||||
st->ref = devm_regulator_get(&client->dev, "vref");
|
||||
if (IS_ERR(st->ref))
|
||||
return PTR_ERR(st->ref);
|
||||
|
||||
ret = regulator_enable(st->ref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
|
||||
if (ret < 0)
|
||||
goto err_regulator_disable;
|
||||
|
||||
st->addr_prev = LTC2497_CONFIG_DEFAULT;
|
||||
st->time_prev = ktime_get();
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto err_regulator_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_regulator_disable:
|
||||
regulator_disable(st->ref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc2497_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct ltc2497_st *st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(st->ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc2497_id[] = {
|
||||
{ "ltc2497", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2497_id);
|
||||
|
||||
static const struct of_device_id ltc2497_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2497", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2497_of_match);
|
||||
|
||||
static struct i2c_driver ltc2497_driver = {
|
||||
.driver = {
|
||||
.name = "ltc2497",
|
||||
.of_match_table = of_match_ptr(ltc2497_of_match),
|
||||
},
|
||||
.probe = ltc2497_probe,
|
||||
.remove = ltc2497_remove,
|
||||
.id_table = ltc2497_id,
|
||||
};
|
||||
module_i2c_driver(ltc2497_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
|
||||
MODULE_DESCRIPTION("Linear Technology LTC2497 ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -364,7 +364,7 @@ static int max1027_set_trigger_state(struct iio_trigger *trig, bool state)
|
||||
|
||||
static irqreturn_t max1027_trigger_handler(int irq, void *private)
|
||||
{
|
||||
struct iio_poll_func *pf = (struct iio_poll_func *)private;
|
||||
struct iio_poll_func *pf = private;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct max1027_state *st = iio_priv(indio_dev);
|
||||
|
||||
|
@ -124,8 +124,8 @@ static int max11100_probe(struct spi_device *spi)
|
||||
indio_dev->name = "max11100";
|
||||
indio_dev->info = &max11100_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = max11100_channels,
|
||||
indio_dev->num_channels = ARRAY_SIZE(max11100_channels),
|
||||
indio_dev->channels = max11100_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(max11100_channels);
|
||||
|
||||
state->vref_reg = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(state->vref_reg))
|
||||
|
@ -1007,7 +1007,7 @@ static struct attribute *max1363_event_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group max1363_event_attribute_group = {
|
||||
static const struct attribute_group max1363_event_attribute_group = {
|
||||
.attrs = max1363_event_attributes,
|
||||
};
|
||||
|
||||
|
@ -166,6 +166,8 @@
|
||||
|
||||
#define MESON_SAR_ADC_MAX_FIFO_SIZE 32
|
||||
#define MESON_SAR_ADC_TIMEOUT 100 /* ms */
|
||||
/* for use with IIO_VAL_INT_PLUS_MICRO */
|
||||
#define MILLION 1000000
|
||||
|
||||
#define MESON_SAR_ADC_CHAN(_chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
@ -173,7 +175,9 @@
|
||||
.channel = _chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_AVERAGE_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS) | \
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE), \
|
||||
.datasheet_name = "SAR_ADC_CH"#_chan, \
|
||||
}
|
||||
|
||||
@ -233,6 +237,8 @@ struct meson_sar_adc_priv {
|
||||
struct clk *adc_div_clk;
|
||||
struct clk_divider clk_div;
|
||||
struct completion done;
|
||||
int calibbias;
|
||||
int calibscale;
|
||||
};
|
||||
|
||||
static const struct regmap_config meson_sar_adc_regmap_config = {
|
||||
@ -252,6 +258,17 @@ static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev)
|
||||
return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
|
||||
}
|
||||
|
||||
static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val)
|
||||
{
|
||||
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
|
||||
int tmp;
|
||||
|
||||
/* use val_calib = scale * val_raw + offset calibration function */
|
||||
tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias;
|
||||
|
||||
return clamp(tmp, 0, (1 << priv->data->resolution) - 1);
|
||||
}
|
||||
|
||||
static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
|
||||
@ -302,7 +319,7 @@ static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
|
||||
|
||||
fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval);
|
||||
fifo_val &= GENMASK(priv->data->resolution - 1, 0);
|
||||
*val = fifo_val;
|
||||
*val = meson_sar_adc_calib_val(indio_dev, fifo_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -527,6 +544,15 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
|
||||
*val2 = priv->data->resolution;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
*val = priv->calibbias;
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_CALIBSCALE:
|
||||
*val = priv->calibscale / MILLION;
|
||||
*val2 = priv->calibscale % MILLION;
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -762,6 +788,47 @@ static irqreturn_t meson_sar_adc_irq(int irq, void *data)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int meson_sar_adc_calib(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
|
||||
int ret, nominal0, nominal1, value0, value1;
|
||||
|
||||
/* use points 25% and 75% for calibration */
|
||||
nominal0 = (1 << priv->data->resolution) / 4;
|
||||
nominal1 = (1 << priv->data->resolution) * 3 / 4;
|
||||
|
||||
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4);
|
||||
usleep_range(10, 20);
|
||||
ret = meson_sar_adc_get_sample(indio_dev,
|
||||
&meson_sar_adc_iio_channels[7],
|
||||
MEAN_AVERAGING, EIGHT_SAMPLES, &value0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4);
|
||||
usleep_range(10, 20);
|
||||
ret = meson_sar_adc_get_sample(indio_dev,
|
||||
&meson_sar_adc_iio_channels[7],
|
||||
MEAN_AVERAGING, EIGHT_SAMPLES, &value1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (value1 <= value0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
priv->calibscale = div_s64((nominal1 - nominal0) * (s64)MILLION,
|
||||
value1 - value0);
|
||||
priv->calibbias = nominal0 - div_s64((s64)value0 * priv->calibscale,
|
||||
MILLION);
|
||||
ret = 0;
|
||||
out:
|
||||
meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info meson_sar_adc_iio_info = {
|
||||
.read_raw = meson_sar_adc_iio_info_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
@ -901,6 +968,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(priv->vref);
|
||||
}
|
||||
|
||||
priv->calibscale = MILLION;
|
||||
|
||||
ret = meson_sar_adc_init(indio_dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -909,6 +978,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = meson_sar_adc_calib(indio_dev);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "calibration failed\n");
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
|
@ -109,7 +109,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id;
|
||||
struct rockchip_saradc *info = dev_id;
|
||||
|
||||
/* Read value */
|
||||
info->last_val = readl_relaxed(info->regs + SARADC_DATA);
|
||||
|
@ -382,7 +382,7 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
|
||||
|
||||
static int sun4i_gpadc_get_temp(void *data, int *temp)
|
||||
{
|
||||
struct sun4i_gpadc_iio *info = (struct sun4i_gpadc_iio *)data;
|
||||
struct sun4i_gpadc_iio *info = data;
|
||||
int val, scale, offset;
|
||||
|
||||
if (sun4i_gpadc_temp_read(info->indio_dev, &val))
|
||||
|
@ -584,7 +584,7 @@ static int vf610_adc_read_data(struct vf610_adc *info)
|
||||
|
||||
static irqreturn_t vf610_adc_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct iio_dev *indio_dev = (struct iio_dev *)dev_id;
|
||||
struct iio_dev *indio_dev = dev_id;
|
||||
struct vf610_adc *info = iio_priv(indio_dev);
|
||||
int coco;
|
||||
|
||||
|
@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client,
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &ams_iaqcore_info,
|
||||
indio_dev->info = &ams_iaqcore_info;
|
||||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
|
@ -393,7 +393,7 @@ static int vz89x_probe(struct i2c_client *client,
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &vz89x_info,
|
||||
indio_dev->info = &vz89x_info;
|
||||
indio_dev->name = dev_name(&client->dev);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
|
@ -267,31 +267,12 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
|
||||
else
|
||||
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
|
||||
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
cros_ec_sensors_capture, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_uninit_buffer;
|
||||
|
||||
return 0;
|
||||
|
||||
error_uninit_buffer:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_sensors_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
return 0;
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct platform_device_id cros_ec_sensors_ids[] = {
|
||||
@ -313,7 +294,6 @@ static struct platform_driver cros_ec_sensors_platform_driver = {
|
||||
.name = "cros-ec-sensors",
|
||||
},
|
||||
.probe = cros_ec_sensors_probe,
|
||||
.remove = cros_ec_sensors_remove,
|
||||
.id_table = cros_ec_sensors_ids,
|
||||
};
|
||||
module_platform_driver(cros_ec_sensors_platform_driver);
|
||||
|
@ -38,6 +38,12 @@ static struct {
|
||||
{HID_USAGE_SENSOR_ACCEL_3D,
|
||||
HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
|
||||
|
||||
{HID_USAGE_SENSOR_GRAVITY_VECTOR, 0, 9, 806650000},
|
||||
{HID_USAGE_SENSOR_GRAVITY_VECTOR,
|
||||
HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD, 1, 0},
|
||||
{HID_USAGE_SENSOR_GRAVITY_VECTOR,
|
||||
HID_USAGE_SENSOR_UNITS_G, 9, 806650000},
|
||||
|
||||
{HID_USAGE_SENSOR_GYRO_3D, 0, 0, 17453293},
|
||||
{HID_USAGE_SENSOR_GYRO_3D,
|
||||
HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
|
||||
@ -65,6 +71,8 @@ static struct {
|
||||
|
||||
{HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0},
|
||||
{HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0},
|
||||
|
||||
{HID_USAGE_SENSOR_HUMIDITY, 0, 1000, 0},
|
||||
};
|
||||
|
||||
static int pow_10(unsigned power)
|
||||
|
@ -74,7 +74,7 @@ EXPORT_SYMBOL(ms_sensors_reset);
|
||||
int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_client *client = (struct i2c_client *)cli;
|
||||
struct i2c_client *client = cli;
|
||||
|
||||
ret = i2c_smbus_read_word_swapped(client, cmd);
|
||||
if (ret < 0) {
|
||||
@ -107,7 +107,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
|
||||
{
|
||||
int ret;
|
||||
__be32 buf = 0;
|
||||
struct i2c_client *client = (struct i2c_client *)cli;
|
||||
struct i2c_client *client = cli;
|
||||
|
||||
/* Trigger conversion */
|
||||
ret = i2c_smbus_write_byte(client, conv);
|
||||
|
@ -212,7 +212,7 @@ static struct attribute *ad5504_ev_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ad5504_ev_attribute_group = {
|
||||
static const struct attribute_group ad5504_ev_attribute_group = {
|
||||
.attrs = ad5504_ev_attributes,
|
||||
};
|
||||
|
||||
@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private)
|
||||
0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
iio_get_time_ns((struct iio_dev *)private));
|
||||
iio_get_time_ns(private));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -36,6 +36,20 @@ config HDC100X
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hdc100x.
|
||||
|
||||
config HID_SENSOR_HUMIDITY
|
||||
tristate "HID Environmental humidity sensor"
|
||||
depends on HID_SENSOR_HUB
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select HID_SENSOR_IIO_COMMON
|
||||
select HID_SENSOR_IIO_TRIGGER
|
||||
help
|
||||
Say yes here to build support for the HID SENSOR
|
||||
humidity driver
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called hid-sensor-humidity.
|
||||
|
||||
config HTS221
|
||||
tristate "STMicroelectronics HTS221 sensor Driver"
|
||||
depends on (I2C || SPI)
|
||||
|
@ -5,6 +5,7 @@
|
||||
obj-$(CONFIG_AM2315) += am2315.o
|
||||
obj-$(CONFIG_DHT11) += dht11.o
|
||||
obj-$(CONFIG_HDC100X) += hdc100x.o
|
||||
obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
|
||||
|
||||
hts221-y := hts221_core.o \
|
||||
hts221_buffer.o
|
||||
@ -15,3 +16,5 @@ obj-$(CONFIG_HTS221_SPI) += hts221_spi.o
|
||||
obj-$(CONFIG_HTU21) += htu21.o
|
||||
obj-$(CONFIG_SI7005) += si7005.o
|
||||
obj-$(CONFIG_SI7020) += si7020.o
|
||||
|
||||
ccflags-y += -I$(srctree)/drivers/iio/common/hid-sensors
|
||||
|
@ -79,7 +79,7 @@ static struct attribute *hdc100x_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group hdc100x_attribute_group = {
|
||||
static const struct attribute_group hdc100x_attribute_group = {
|
||||
.attrs = hdc100x_attributes,
|
||||
};
|
||||
|
||||
|
315
drivers/iio/humidity/hid-sensor-humidity.c
Normal file
315
drivers/iio/humidity/hid-sensor-humidity.c
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* HID Sensors Driver
|
||||
* Copyright (c) 2017, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program.
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/hid-sensor-hub.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "hid-sensor-trigger.h"
|
||||
|
||||
struct hid_humidity_state {
|
||||
struct hid_sensor_common common_attributes;
|
||||
struct hid_sensor_hub_attribute_info humidity_attr;
|
||||
s32 humidity_data;
|
||||
int scale_pre_decml;
|
||||
int scale_post_decml;
|
||||
int scale_precision;
|
||||
int value_offset;
|
||||
};
|
||||
|
||||
/* Channel definitions */
|
||||
static const struct iio_chan_spec humidity_channels[] = {
|
||||
{
|
||||
.type = IIO_HUMIDITYRELATIVE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_HYSTERESIS),
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(1)
|
||||
};
|
||||
|
||||
/* Adjust channel real bits based on report descriptor */
|
||||
static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
|
||||
int channel, int size)
|
||||
{
|
||||
channels[channel].scan_type.sign = 's';
|
||||
/* Real storage bits will change based on the report desc. */
|
||||
channels[channel].scan_type.realbits = size * 8;
|
||||
/* Maximum size of a sample to capture is s32 */
|
||||
channels[channel].scan_type.storagebits = sizeof(s32) * 8;
|
||||
}
|
||||
|
||||
static int humidity_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->type != IIO_HUMIDITYRELATIVE)
|
||||
return -EINVAL;
|
||||
hid_sensor_power_state(&humid_st->common_attributes, true);
|
||||
*val = sensor_hub_input_attr_get_raw_value(
|
||||
humid_st->common_attributes.hsdev,
|
||||
HID_USAGE_SENSOR_HUMIDITY,
|
||||
HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
|
||||
humid_st->humidity_attr.report_id,
|
||||
SENSOR_HUB_SYNC);
|
||||
hid_sensor_power_state(&humid_st->common_attributes, false);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = humid_st->scale_pre_decml;
|
||||
*val2 = humid_st->scale_post_decml;
|
||||
|
||||
return humid_st->scale_precision;
|
||||
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
*val = humid_st->value_offset;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return hid_sensor_read_samp_freq_value(
|
||||
&humid_st->common_attributes, val, val2);
|
||||
|
||||
case IIO_CHAN_INFO_HYSTERESIS:
|
||||
return hid_sensor_read_raw_hyst_value(
|
||||
&humid_st->common_attributes, val, val2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int humidity_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return hid_sensor_write_samp_freq_value(
|
||||
&humid_st->common_attributes, val, val2);
|
||||
|
||||
case IIO_CHAN_INFO_HYSTERESIS:
|
||||
return hid_sensor_write_raw_hyst_value(
|
||||
&humid_st->common_attributes, val, val2);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info humidity_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &humidity_read_raw,
|
||||
.write_raw = &humidity_write_raw,
|
||||
};
|
||||
|
||||
/* Callback handler to send event after all samples are received and captured */
|
||||
static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
|
||||
unsigned int usage_id, void *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
|
||||
|
||||
if (atomic_read(&humid_st->common_attributes.data_ready))
|
||||
iio_push_to_buffers_with_timestamp(indio_dev,
|
||||
&humid_st->humidity_data,
|
||||
iio_get_time_ns(indio_dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Capture samples in local storage */
|
||||
static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
|
||||
unsigned int usage_id, size_t raw_len,
|
||||
char *raw_data, void *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
|
||||
|
||||
switch (usage_id) {
|
||||
case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY:
|
||||
humid_st->humidity_data = *(s32 *)raw_data;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse report which is specific to an usage id */
|
||||
static int humidity_parse_report(struct platform_device *pdev,
|
||||
struct hid_sensor_hub_device *hsdev,
|
||||
struct iio_chan_spec *channels,
|
||||
unsigned int usage_id,
|
||||
struct hid_humidity_state *st)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
|
||||
usage_id,
|
||||
HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
|
||||
&st->humidity_attr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
humidity_adjust_channel_bit_mask(channels, 0, st->humidity_attr.size);
|
||||
|
||||
st->scale_precision = hid_sensor_format_scale(
|
||||
HID_USAGE_SENSOR_HUMIDITY,
|
||||
&st->humidity_attr,
|
||||
&st->scale_pre_decml,
|
||||
&st->scale_post_decml);
|
||||
|
||||
/* Set Sensitivity field ids, when there is no individual modifier */
|
||||
if (st->common_attributes.sensitivity.index < 0)
|
||||
sensor_hub_input_get_attribute_info(hsdev,
|
||||
HID_FEATURE_REPORT, usage_id,
|
||||
HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
|
||||
HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
|
||||
&st->common_attributes.sensitivity);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct hid_sensor_hub_callbacks humidity_callbacks = {
|
||||
.send_event = &humidity_proc_event,
|
||||
.capture_sample = &humidity_capture_sample,
|
||||
};
|
||||
|
||||
/* Function to initialize the processing for usage id */
|
||||
static int hid_humidity_probe(struct platform_device *pdev)
|
||||
{
|
||||
static const char *name = "humidity";
|
||||
struct iio_dev *indio_dev;
|
||||
struct hid_humidity_state *humid_st;
|
||||
struct iio_chan_spec *humid_chans;
|
||||
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*humid_st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
humid_st = iio_priv(indio_dev);
|
||||
humid_st->common_attributes.hsdev = hsdev;
|
||||
humid_st->common_attributes.pdev = pdev;
|
||||
|
||||
ret = hid_sensor_parse_common_attributes(hsdev,
|
||||
HID_USAGE_SENSOR_HUMIDITY,
|
||||
&humid_st->common_attributes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
|
||||
sizeof(humidity_channels), GFP_KERNEL);
|
||||
if (!humid_chans)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = humidity_parse_report(pdev, hsdev, humid_chans,
|
||||
HID_USAGE_SENSOR_HUMIDITY, humid_st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->channels = humid_chans;
|
||||
indio_dev->num_channels = ARRAY_SIZE(humidity_channels);
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->info = &humidity_info;
|
||||
indio_dev->name = name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
|
||||
&iio_pollfunc_store_time, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atomic_set(&humid_st->common_attributes.data_ready, 0);
|
||||
ret = hid_sensor_setup_trigger(indio_dev, name,
|
||||
&humid_st->common_attributes);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
humidity_callbacks.pdev = pdev;
|
||||
ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
|
||||
&humidity_callbacks);
|
||||
if (ret)
|
||||
goto error_remove_trigger;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret)
|
||||
goto error_remove_callback;
|
||||
|
||||
return ret;
|
||||
|
||||
error_remove_callback:
|
||||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
|
||||
error_remove_trigger:
|
||||
hid_sensor_remove_trigger(&humid_st->common_attributes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Function to deinitialize the processing for usage id */
|
||||
static int hid_humidity_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
struct hid_humidity_state *humid_st = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
|
||||
hid_sensor_remove_trigger(&humid_st->common_attributes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id hid_humidity_ids[] = {
|
||||
{
|
||||
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
|
||||
.name = "HID-SENSOR-200032",
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, hid_humidity_ids);
|
||||
|
||||
static struct platform_driver hid_humidity_platform_driver = {
|
||||
.id_table = hid_humidity_ids,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.pm = &hid_sensor_pm_ops,
|
||||
},
|
||||
.probe = hid_humidity_probe,
|
||||
.remove = hid_humidity_remove,
|
||||
};
|
||||
module_platform_driver(hid_humidity_platform_driver);
|
||||
|
||||
MODULE_DESCRIPTION("HID Environmental humidity sensor");
|
||||
MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -41,7 +41,7 @@ static const struct iio_trigger_ops hts221_trigger_ops = {
|
||||
|
||||
static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
|
||||
{
|
||||
struct hts221_hw *hw = (struct hts221_hw *)private;
|
||||
struct hts221_hw *hw = private;
|
||||
u8 status;
|
||||
int err;
|
||||
|
||||
|
@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
|
||||
.reg = ®_set_6050,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.whoami = INV_MPU9250_WHOAMI_VALUE,
|
||||
.name = "MPU9250",
|
||||
.reg = ®_set_6500,
|
||||
.config = &chip_config_6050,
|
||||
},
|
||||
{
|
||||
.whoami = INV_ICM20608_WHOAMI_VALUE,
|
||||
.name = "ICM20608",
|
||||
|
@ -178,6 +178,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
|
||||
{"mpu6050", INV_MPU6050},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{"mpu9150", INV_MPU9150},
|
||||
{"mpu9250", INV_MPU9250},
|
||||
{"icm20608", INV_ICM20608},
|
||||
{}
|
||||
};
|
||||
@ -197,6 +198,10 @@ static const struct of_device_id inv_of_match[] = {
|
||||
.compatible = "invensense,mpu9150",
|
||||
.data = (void *)INV_MPU9150
|
||||
},
|
||||
{
|
||||
.compatible = "invensense,mpu9250",
|
||||
.data = (void *)INV_MPU9250
|
||||
},
|
||||
{
|
||||
.compatible = "invensense,icm20608",
|
||||
.data = (void *)INV_ICM20608
|
||||
|
@ -70,6 +70,7 @@ enum inv_devices {
|
||||
INV_MPU6500,
|
||||
INV_MPU6000,
|
||||
INV_MPU9150,
|
||||
INV_MPU9250,
|
||||
INV_ICM20608,
|
||||
INV_NUM_PARTS
|
||||
};
|
||||
@ -226,6 +227,7 @@ struct inv_mpu6050_state {
|
||||
#define INV_MPU6050_WHOAMI_VALUE 0x68
|
||||
#define INV_MPU6500_WHOAMI_VALUE 0x70
|
||||
#define INV_MPU9150_WHOAMI_VALUE 0x68
|
||||
#define INV_MPU9250_WHOAMI_VALUE 0x71
|
||||
#define INV_ICM20608_WHOAMI_VALUE 0xAF
|
||||
|
||||
/* scan element definition */
|
||||
|
@ -82,6 +82,7 @@ static const struct spi_device_id inv_mpu_id[] = {
|
||||
{"mpu6000", INV_MPU6000},
|
||||
{"mpu6500", INV_MPU6500},
|
||||
{"mpu9150", INV_MPU9150},
|
||||
{"mpu9250", INV_MPU9250},
|
||||
{"icm20608", INV_ICM20608},
|
||||
{}
|
||||
};
|
||||
|
@ -364,7 +364,7 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
|
||||
|
||||
static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
|
||||
{
|
||||
struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
|
||||
struct st_lsm6dsx_hw *hw = private;
|
||||
struct st_lsm6dsx_sensor *sensor;
|
||||
int i;
|
||||
|
||||
@ -388,7 +388,7 @@ static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
|
||||
|
||||
static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
|
||||
{
|
||||
struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
|
||||
struct st_lsm6dsx_hw *hw = private;
|
||||
int count;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
|
@ -308,32 +308,40 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
|
||||
static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr,
|
||||
u8 *val)
|
||||
{
|
||||
enum st_lsm6dsx_sensor_id id = sensor->id;
|
||||
int i, err;
|
||||
u8 val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
|
||||
if (st_lsm6dsx_odr_table[id].odr_avl[i].hz == odr)
|
||||
if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr)
|
||||
break;
|
||||
|
||||
if (i == ST_LSM6DSX_ODR_LIST_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
val = st_lsm6dsx_odr_table[id].odr_avl[i].val;
|
||||
err = st_lsm6dsx_write_with_mask(sensor->hw,
|
||||
st_lsm6dsx_odr_table[id].reg.addr,
|
||||
st_lsm6dsx_odr_table[id].reg.mask,
|
||||
val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
|
||||
sensor->odr = odr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
|
||||
{
|
||||
enum st_lsm6dsx_sensor_id id = sensor->id;
|
||||
int err;
|
||||
u8 val;
|
||||
|
||||
err = st_lsm6dsx_check_odr(sensor, odr, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return st_lsm6dsx_write_with_mask(sensor->hw,
|
||||
st_lsm6dsx_odr_table[id].reg.addr,
|
||||
st_lsm6dsx_odr_table[id].reg.mask,
|
||||
val);
|
||||
}
|
||||
|
||||
int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
|
||||
{
|
||||
int err;
|
||||
@ -436,9 +444,12 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
err = st_lsm6dsx_set_full_scale(sensor, val2);
|
||||
break;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
err = st_lsm6dsx_set_odr(sensor, val);
|
||||
case IIO_CHAN_INFO_SAMP_FREQ: {
|
||||
u8 data;
|
||||
|
||||
err = st_lsm6dsx_check_odr(sensor, val, &data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
|
@ -405,4 +405,14 @@ config VEML6070
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called veml6070.
|
||||
|
||||
config VL6180
|
||||
tristate "VL6180 ALS, range and proximity sensor"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you want to build a driver for the STMicroelectronics
|
||||
VL6180 combined ambient light, range and proximity sensor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vl6180.
|
||||
|
||||
endmenu
|
||||
|
@ -38,3 +38,4 @@ obj-$(CONFIG_TSL4531) += tsl4531.o
|
||||
obj-$(CONFIG_US5182D) += us5182d.o
|
||||
obj-$(CONFIG_VCNL4000) += vcnl4000.o
|
||||
obj-$(CONFIG_VEML6070) += veml6070.o
|
||||
obj-$(CONFIG_VL6180) += vl6180.o
|
||||
|
@ -343,7 +343,7 @@ static struct attribute *apds9960_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group apds9960_attribute_group = {
|
||||
static const struct attribute_group apds9960_attribute_group = {
|
||||
.attrs = apds9960_attributes,
|
||||
};
|
||||
|
||||
|
@ -212,7 +212,7 @@ static struct attribute *bh1750_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group bh1750_attribute_group = {
|
||||
static const struct attribute_group bh1750_attribute_group = {
|
||||
.attrs = bh1750_attributes,
|
||||
};
|
||||
|
||||
|
@ -690,7 +690,7 @@ static struct attribute *lm3533_als_event_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group lm3533_als_event_attribute_group = {
|
||||
static const struct attribute_group lm3533_als_event_attribute_group = {
|
||||
.attrs = lm3533_als_event_attributes
|
||||
};
|
||||
|
||||
@ -714,7 +714,7 @@ static struct attribute *lm3533_als_attributes[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group lm3533_als_attribute_group = {
|
||||
static const struct attribute_group lm3533_als_attribute_group = {
|
||||
.attrs = lm3533_als_attributes
|
||||
};
|
||||
|
||||
|
543
drivers/iio/light/vl6180.c
Normal file
543
drivers/iio/light/vl6180.c
Normal file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* vl6180.c - Support for STMicroelectronics VL6180 ALS, range and proximity
|
||||
* sensor
|
||||
*
|
||||
* Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
|
||||
* Copyright 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of version 2 of
|
||||
* the GNU General Public License. See the file COPYING in the main
|
||||
* directory of this archive for more details.
|
||||
*
|
||||
* IIO driver for VL6180 (7-bit I2C slave address 0x29)
|
||||
*
|
||||
* Range: 0 to 100mm
|
||||
* ALS: < 1 Lux up to 100 kLux
|
||||
* IR: 850nm
|
||||
*
|
||||
* TODO: irq, threshold events, continuous mode, hardware buffer
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
#define VL6180_DRV_NAME "vl6180"
|
||||
|
||||
/* Device identification register and value */
|
||||
#define VL6180_MODEL_ID 0x000
|
||||
#define VL6180_MODEL_ID_VAL 0xb4
|
||||
|
||||
/* Configuration registers */
|
||||
#define VL6180_INTR_CONFIG 0x014
|
||||
#define VL6180_INTR_CLEAR 0x015
|
||||
#define VL6180_OUT_OF_RESET 0x016
|
||||
#define VL6180_HOLD 0x017
|
||||
#define VL6180_RANGE_START 0x018
|
||||
#define VL6180_ALS_START 0x038
|
||||
#define VL6180_ALS_GAIN 0x03f
|
||||
#define VL6180_ALS_IT 0x040
|
||||
|
||||
/* Status registers */
|
||||
#define VL6180_RANGE_STATUS 0x04d
|
||||
#define VL6180_ALS_STATUS 0x04e
|
||||
#define VL6180_INTR_STATUS 0x04f
|
||||
|
||||
/* Result value registers */
|
||||
#define VL6180_ALS_VALUE 0x050
|
||||
#define VL6180_RANGE_VALUE 0x062
|
||||
#define VL6180_RANGE_RATE 0x066
|
||||
|
||||
/* bits of the RANGE_START and ALS_START register */
|
||||
#define VL6180_MODE_CONT BIT(1) /* continuous mode */
|
||||
#define VL6180_STARTSTOP BIT(0) /* start measurement, auto-reset */
|
||||
|
||||
/* bits of the INTR_STATUS and INTR_CONFIG register */
|
||||
#define VL6180_ALS_READY BIT(5)
|
||||
#define VL6180_RANGE_READY BIT(2)
|
||||
|
||||
/* bits of the INTR_CLEAR register */
|
||||
#define VL6180_CLEAR_ERROR BIT(2)
|
||||
#define VL6180_CLEAR_ALS BIT(1)
|
||||
#define VL6180_CLEAR_RANGE BIT(0)
|
||||
|
||||
/* bits of the HOLD register */
|
||||
#define VL6180_HOLD_ON BIT(0)
|
||||
|
||||
/* default value for the ALS_IT register */
|
||||
#define VL6180_ALS_IT_100 0x63 /* 100 ms */
|
||||
|
||||
/* values for the ALS_GAIN register */
|
||||
#define VL6180_ALS_GAIN_1 0x46
|
||||
#define VL6180_ALS_GAIN_1_25 0x45
|
||||
#define VL6180_ALS_GAIN_1_67 0x44
|
||||
#define VL6180_ALS_GAIN_2_5 0x43
|
||||
#define VL6180_ALS_GAIN_5 0x42
|
||||
#define VL6180_ALS_GAIN_10 0x41
|
||||
#define VL6180_ALS_GAIN_20 0x40
|
||||
#define VL6180_ALS_GAIN_40 0x47
|
||||
|
||||
struct vl6180_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
|
||||
|
||||
/**
|
||||
* struct vl6180_chan_regs - Registers for accessing channels
|
||||
* @drdy_mask: Data ready bit in status register
|
||||
* @start_reg: Conversion start register
|
||||
* @value_reg: Result value register
|
||||
* @word: Register word length
|
||||
*/
|
||||
struct vl6180_chan_regs {
|
||||
u8 drdy_mask;
|
||||
u16 start_reg, value_reg;
|
||||
bool word;
|
||||
};
|
||||
|
||||
static const struct vl6180_chan_regs vl6180_chan_regs_table[] = {
|
||||
[VL6180_ALS] = {
|
||||
.drdy_mask = VL6180_ALS_READY,
|
||||
.start_reg = VL6180_ALS_START,
|
||||
.value_reg = VL6180_ALS_VALUE,
|
||||
.word = true,
|
||||
},
|
||||
[VL6180_RANGE] = {
|
||||
.drdy_mask = VL6180_RANGE_READY,
|
||||
.start_reg = VL6180_RANGE_START,
|
||||
.value_reg = VL6180_RANGE_VALUE,
|
||||
.word = false,
|
||||
},
|
||||
[VL6180_PROX] = {
|
||||
.drdy_mask = VL6180_RANGE_READY,
|
||||
.start_reg = VL6180_RANGE_START,
|
||||
.value_reg = VL6180_RANGE_RATE,
|
||||
.word = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int vl6180_read(struct i2c_client *client, u16 cmd, void *databuf,
|
||||
u8 len)
|
||||
{
|
||||
__be16 cmdbuf = cpu_to_be16(cmd);
|
||||
struct i2c_msg msgs[2] = {
|
||||
{ .addr = client->addr, .len = sizeof(cmdbuf), .buf = (u8 *) &cmdbuf },
|
||||
{ .addr = client->addr, .len = len, .buf = databuf,
|
||||
.flags = I2C_M_RD } };
|
||||
int ret;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "failed reading register 0x%04x\n", cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vl6180_read_byte(struct i2c_client *client, u16 cmd)
|
||||
{
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
ret = vl6180_read(client, cmd, &data, sizeof(data));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int vl6180_read_word(struct i2c_client *client, u16 cmd)
|
||||
{
|
||||
__be16 data;
|
||||
int ret;
|
||||
|
||||
ret = vl6180_read(client, cmd, &data, sizeof(data));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return be16_to_cpu(data);
|
||||
}
|
||||
|
||||
static int vl6180_write_byte(struct i2c_client *client, u16 cmd, u8 val)
|
||||
{
|
||||
u8 buf[3];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{ .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
|
||||
int ret;
|
||||
|
||||
buf[0] = cmd >> 8;
|
||||
buf[1] = cmd & 0xff;
|
||||
buf[2] = val;
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl6180_write_word(struct i2c_client *client, u16 cmd, u16 val)
|
||||
{
|
||||
__be16 buf[2];
|
||||
struct i2c_msg msgs[1] = {
|
||||
{ .addr = client->addr, .len = sizeof(buf), .buf = (u8 *) &buf } };
|
||||
int ret;
|
||||
|
||||
buf[0] = cpu_to_be16(cmd);
|
||||
buf[1] = cpu_to_be16(val);
|
||||
|
||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "failed writing register 0x%04x\n", cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vl6180_measure(struct vl6180_data *data, int addr)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int tries = 20, ret;
|
||||
u16 value;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
/* Start single shot measurement */
|
||||
ret = vl6180_write_byte(client,
|
||||
vl6180_chan_regs_table[addr].start_reg, VL6180_STARTSTOP);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
while (tries--) {
|
||||
ret = vl6180_read_byte(client, VL6180_INTR_STATUS);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
if (ret & vl6180_chan_regs_table[addr].drdy_mask)
|
||||
break;
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
if (tries < 0) {
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Read result value from appropriate registers */
|
||||
ret = vl6180_chan_regs_table[addr].word ?
|
||||
vl6180_read_word(client, vl6180_chan_regs_table[addr].value_reg) :
|
||||
vl6180_read_byte(client, vl6180_chan_regs_table[addr].value_reg);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
value = ret;
|
||||
|
||||
/* Clear the interrupt flag after data read */
|
||||
ret = vl6180_write_byte(client, VL6180_INTR_CLEAR,
|
||||
VL6180_CLEAR_ERROR | VL6180_CLEAR_ALS | VL6180_CLEAR_RANGE);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
ret = value;
|
||||
|
||||
fail:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec vl6180_channels[] = {
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
.address = VL6180_ALS,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_INT_TIME) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_HARDWAREGAIN),
|
||||
}, {
|
||||
.type = IIO_DISTANCE,
|
||||
.address = VL6180_RANGE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
}, {
|
||||
.type = IIO_PROXIMITY,
|
||||
.address = VL6180_PROX,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Columns 3 & 4 represent the same value in decimal and hex notations.
|
||||
* Kept in order to avoid the datatype conversion while reading the
|
||||
* hardware_gain.
|
||||
*/
|
||||
static const int vl6180_als_gain[8][4] = {
|
||||
{ 1, 0, 70, VL6180_ALS_GAIN_1 },
|
||||
{ 1, 250000, 69, VL6180_ALS_GAIN_1_25 },
|
||||
{ 1, 670000, 68, VL6180_ALS_GAIN_1_67 },
|
||||
{ 2, 500000, 67, VL6180_ALS_GAIN_2_5 },
|
||||
{ 5, 0, 66, VL6180_ALS_GAIN_5 },
|
||||
{ 10, 0, 65, VL6180_ALS_GAIN_10 },
|
||||
{ 20, 0, 64, VL6180_ALS_GAIN_20 },
|
||||
{ 40, 0, 71, VL6180_ALS_GAIN_40 }
|
||||
};
|
||||
|
||||
static int vl6180_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct vl6180_data *data = iio_priv(indio_dev);
|
||||
int ret, i;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = vl6180_measure(data, chan->address);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
ret = vl6180_read_word(data->client, VL6180_ALS_IT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = 0; /* 1 count = 1ms (0 = 1ms) */
|
||||
*val2 = (ret + 1) * 1000; /* convert to seconds */
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_LIGHT:
|
||||
*val = 0; /* one ALS count is 0.32 Lux */
|
||||
*val2 = 320000;
|
||||
break;
|
||||
case IIO_DISTANCE:
|
||||
*val = 0; /* sensor reports mm, scale to meter */
|
||||
*val2 = 1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
ret = vl6180_read_byte(data->client, VL6180_ALS_GAIN);
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
|
||||
if (ret == vl6180_als_gain[i][2]) {
|
||||
*val = vl6180_als_gain[i][0];
|
||||
*val2 = vl6180_als_gain[i][1];
|
||||
}
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static IIO_CONST_ATTR(als_gain_available, "1 1.25 1.67 2.5 5 10 20 40");
|
||||
|
||||
static struct attribute *vl6180_attributes[] = {
|
||||
&iio_const_attr_als_gain_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group vl6180_attribute_group = {
|
||||
.attrs = vl6180_attributes,
|
||||
};
|
||||
|
||||
/* HOLD is needed before updating any config registers */
|
||||
static int vl6180_hold(struct vl6180_data *data, bool hold)
|
||||
{
|
||||
return vl6180_write_byte(data->client, VL6180_HOLD,
|
||||
hold ? VL6180_HOLD_ON : 0);
|
||||
}
|
||||
|
||||
static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
|
||||
if (val == vl6180_als_gain[i][0] &&
|
||||
val2 == vl6180_als_gain[i][1]) {
|
||||
mutex_lock(&data->lock);
|
||||
ret = vl6180_hold(data, true);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
|
||||
vl6180_als_gain[i][3]);
|
||||
fail:
|
||||
vl6180_hold(data, false);
|
||||
mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vl6180_set_it(struct vl6180_data *data, int val2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = vl6180_hold(data, true);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
ret = vl6180_write_word(data->client, VL6180_ALS_IT,
|
||||
(val2 - 500) / 1000); /* write value in ms */
|
||||
fail:
|
||||
vl6180_hold(data, false);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vl6180_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct vl6180_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
if (val != 0 || val2 < 500 || val2 >= 512500)
|
||||
return -EINVAL;
|
||||
|
||||
return vl6180_set_it(data, val2);
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
if (chan->type != IIO_LIGHT)
|
||||
return -EINVAL;
|
||||
|
||||
return vl6180_set_als_gain(data, val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info vl6180_info = {
|
||||
.read_raw = vl6180_read_raw,
|
||||
.write_raw = vl6180_write_raw,
|
||||
.attrs = &vl6180_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int vl6180_init(struct vl6180_data *data)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
ret = vl6180_read_byte(client, VL6180_MODEL_ID);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != VL6180_MODEL_ID_VAL) {
|
||||
dev_err(&client->dev, "invalid model ID %02x\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = vl6180_hold(data, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = vl6180_read_byte(client, VL6180_OUT_OF_RESET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Detect false reset condition here. This bit is always set when the
|
||||
* system comes out of reset.
|
||||
*/
|
||||
if (ret != 0x01)
|
||||
dev_info(&client->dev, "device is not fresh out of reset\n");
|
||||
|
||||
/* Enable ALS and Range ready interrupts */
|
||||
ret = vl6180_write_byte(client, VL6180_INTR_CONFIG,
|
||||
VL6180_ALS_READY | VL6180_RANGE_READY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* ALS integration time: 100ms */
|
||||
ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* ALS gain: 1 */
|
||||
ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = vl6180_write_byte(client, VL6180_OUT_OF_RESET, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return vl6180_hold(data, false);
|
||||
}
|
||||
|
||||
static int vl6180_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct vl6180_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->info = &vl6180_info;
|
||||
indio_dev->channels = vl6180_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(vl6180_channels);
|
||||
indio_dev->name = VL6180_DRV_NAME;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = vl6180_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&client->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id vl6180_of_match[] = {
|
||||
{ .compatible = "st,vl6180", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vl6180_of_match);
|
||||
|
||||
static const struct i2c_device_id vl6180_id[] = {
|
||||
{ "vl6180", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, vl6180_id);
|
||||
|
||||
static struct i2c_driver vl6180_driver = {
|
||||
.driver = {
|
||||
.name = VL6180_DRV_NAME,
|
||||
.of_match_table = of_match_ptr(vl6180_of_match),
|
||||
},
|
||||
.probe = vl6180_probe,
|
||||
.id_table = vl6180_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(vl6180_driver);
|
||||
|
||||
MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
|
||||
MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
|
||||
MODULE_DESCRIPTION("STMicro VL6180 ALS, range and proximity sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -751,7 +751,7 @@ static void zpa2326_suspend(struct iio_dev *indio_dev)
|
||||
*/
|
||||
static irqreturn_t zpa2326_handle_irq(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = (struct iio_dev *)data;
|
||||
struct iio_dev *indio_dev = data;
|
||||
|
||||
if (iio_buffer_enabled(indio_dev)) {
|
||||
/* Timestamping needed for buffered sampling only. */
|
||||
@ -790,7 +790,7 @@ static irqreturn_t zpa2326_handle_irq(int irq, void *data)
|
||||
*/
|
||||
static irqreturn_t zpa2326_handle_threaded_irq(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = (struct iio_dev *)data;
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct zpa2326_private *priv = iio_priv(indio_dev);
|
||||
unsigned int val;
|
||||
bool cont;
|
||||
|
@ -155,7 +155,7 @@ static struct attribute *as3935_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group as3935_attribute_group = {
|
||||
static const struct attribute_group as3935_attribute_group = {
|
||||
.attrs = as3935_attributes,
|
||||
};
|
||||
|
||||
|
@ -203,17 +203,14 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_CALIBBIAS:
|
||||
bits = 14;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
addr = adis16203_addresses[chan->scan_index];
|
||||
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;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -255,9 +255,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
addr = adis16209_addresses[chan->scan_index][0];
|
||||
ret = adis_read_reg_16(st, addr, &val16);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
val16 &= (1 << bits) - 1;
|
||||
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
|
||||
*val = val16;
|
||||
|
@ -290,9 +290,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
|
||||
bits = 10;
|
||||
addr = adis16240_addresses[chan->scan_index][0];
|
||||
ret = adis_read_reg_16(st, addr, &val16);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
val16 &= (1 << bits) - 1;
|
||||
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
|
||||
*val = val16;
|
||||
@ -301,9 +300,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
|
||||
bits = 10;
|
||||
addr = adis16240_addresses[chan->scan_index][1];
|
||||
ret = adis_read_reg_16(st, addr, &val16);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
val16 &= (1 << bits) - 1;
|
||||
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
|
||||
*val = val16;
|
||||
|
@ -560,7 +560,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
|
||||
st->iio_attr[cnt].address =
|
||||
AD7280A_DEVADDR(dev) << 8 | ch;
|
||||
st->iio_attr[cnt].dev_attr.attr.mode =
|
||||
S_IWUSR | S_IRUGO;
|
||||
0644;
|
||||
st->iio_attr[cnt].dev_attr.show =
|
||||
ad7280_show_balance_sw;
|
||||
st->iio_attr[cnt].dev_attr.store =
|
||||
@ -577,7 +577,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
|
||||
AD7280A_DEVADDR(dev) << 8 |
|
||||
(AD7280A_CB1_TIMER + ch);
|
||||
st->iio_attr[cnt].dev_attr.attr.mode =
|
||||
S_IWUSR | S_IRUGO;
|
||||
0644;
|
||||
st->iio_attr[cnt].dev_attr.show =
|
||||
ad7280_show_balance_timer;
|
||||
st->iio_attr[cnt].dev_attr.store =
|
||||
@ -746,26 +746,26 @@ out:
|
||||
|
||||
static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value,
|
||||
in_voltage-voltage_thresh_low_value,
|
||||
S_IRUGO | S_IWUSR,
|
||||
0644,
|
||||
ad7280_read_channel_config,
|
||||
ad7280_write_channel_config,
|
||||
AD7280A_CELL_UNDERVOLTAGE);
|
||||
|
||||
static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value,
|
||||
in_voltage-voltage_thresh_high_value,
|
||||
S_IRUGO | S_IWUSR,
|
||||
0644,
|
||||
ad7280_read_channel_config,
|
||||
ad7280_write_channel_config,
|
||||
AD7280A_CELL_OVERVOLTAGE);
|
||||
|
||||
static IIO_DEVICE_ATTR(in_temp_thresh_low_value,
|
||||
S_IRUGO | S_IWUSR,
|
||||
0644,
|
||||
ad7280_read_channel_config,
|
||||
ad7280_write_channel_config,
|
||||
AD7280A_AUX_ADC_UNDERVOLTAGE);
|
||||
|
||||
static IIO_DEVICE_ATTR(in_temp_thresh_high_value,
|
||||
S_IRUGO | S_IWUSR,
|
||||
0644,
|
||||
ad7280_read_channel_config,
|
||||
ad7280_write_channel_config,
|
||||
AD7280A_AUX_ADC_OVERVOLTAGE);
|
||||
|
@ -208,7 +208,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
ret = -EINVAL;
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
|
||||
if (val2 == scale_avail[i][1]) {
|
||||
gpiod_set_value(st->gpio_range, i);
|
||||
@ -217,7 +217,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
@ -231,11 +231,11 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
|
||||
values[1] = (ret >> 1) & 1;
|
||||
values[2] = (ret >> 2) & 1;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->lock);
|
||||
gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
|
||||
values);
|
||||
st->oversampling = val;
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
@ -413,6 +413,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
st->dev = dev;
|
||||
mutex_init(&st->lock);
|
||||
st->bops = bops;
|
||||
st->base_address = base_address;
|
||||
/* tied to logic low, analog input range is +/- 5V */
|
||||
|
@ -14,6 +14,7 @@
|
||||
* @name: identification string for chip
|
||||
* @channels: channel specification
|
||||
* @num_channels: number of channels
|
||||
* @lock protect sensor state
|
||||
*/
|
||||
|
||||
struct ad7606_chip_info {
|
||||
@ -23,6 +24,7 @@ struct ad7606_chip_info {
|
||||
|
||||
/**
|
||||
* struct ad7606_state - driver instance specific data
|
||||
* @lock protect sensor state
|
||||
*/
|
||||
|
||||
struct ad7606_state {
|
||||
@ -37,6 +39,7 @@ struct ad7606_state {
|
||||
bool done;
|
||||
void __iomem *base_address;
|
||||
|
||||
struct mutex lock; /* protect sensor state */
|
||||
struct gpio_desc *gpio_convst;
|
||||
struct gpio_desc *gpio_reset;
|
||||
struct gpio_desc *gpio_range;
|
||||
|
@ -244,7 +244,6 @@ static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
|
||||
chip->config1 = config1;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t adt7316_store_enabled(struct device *dev,
|
||||
@ -434,7 +433,6 @@ static ssize_t adt7316_store_ad_channel(struct device *dev,
|
||||
config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK);
|
||||
}
|
||||
|
||||
|
||||
config2 |= data;
|
||||
|
||||
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
|
||||
@ -725,7 +723,6 @@ static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644,
|
||||
adt7316_store_AIN_internal_Vref,
|
||||
0);
|
||||
|
||||
|
||||
static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@ -925,7 +922,6 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
|
||||
static IIO_DEVICE_ATTR(all_DAC_update_modes, 0444,
|
||||
adt7316_show_all_DAC_update_modes, NULL, 0);
|
||||
|
||||
|
||||
static ssize_t adt7316_store_update_DAC(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
@ -1867,6 +1863,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev,
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline ssize_t adt7316_show_ad_bound(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
@ -232,7 +232,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
|
||||
cfg = ret & ~((0x03 << 5) | (0x1 << 7));
|
||||
cfg = ret & ~((0x03 << 5) | BIT(7));
|
||||
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
|
@ -244,6 +244,7 @@ static int ad7152_write_raw_samp_freq(struct device *dev, int val)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad7152_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val,
|
||||
|
@ -45,10 +45,10 @@
|
||||
#define AD7746_STATUS_RDYCAP BIT(0)
|
||||
|
||||
/* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */
|
||||
#define AD7746_CAPSETUP_CAPEN (1 << 7)
|
||||
#define AD7746_CAPSETUP_CIN2 (1 << 6) /* AD7746 only */
|
||||
#define AD7746_CAPSETUP_CAPDIFF (1 << 5)
|
||||
#define AD7746_CAPSETUP_CACHOP (1 << 0)
|
||||
#define AD7746_CAPSETUP_CAPEN BIT(7)
|
||||
#define AD7746_CAPSETUP_CIN2 BIT(6) /* AD7746 only */
|
||||
#define AD7746_CAPSETUP_CAPDIFF BIT(5)
|
||||
#define AD7746_CAPSETUP_CACHOP BIT(0)
|
||||
|
||||
/* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */
|
||||
#define AD7746_VTSETUP_VTEN (1 << 7)
|
||||
@ -56,9 +56,9 @@
|
||||
#define AD7746_VTSETUP_VTMD_EXT_TEMP (1 << 5)
|
||||
#define AD7746_VTSETUP_VTMD_VDD_MON (2 << 5)
|
||||
#define AD7746_VTSETUP_VTMD_EXT_VIN (3 << 5)
|
||||
#define AD7746_VTSETUP_EXTREF (1 << 4)
|
||||
#define AD7746_VTSETUP_VTSHORT (1 << 1)
|
||||
#define AD7746_VTSETUP_VTCHOP (1 << 0)
|
||||
#define AD7746_VTSETUP_EXTREF BIT(4)
|
||||
#define AD7746_VTSETUP_VTSHORT BIT(1)
|
||||
#define AD7746_VTSETUP_VTCHOP BIT(0)
|
||||
|
||||
/* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
|
||||
#define AD7746_EXCSETUP_CLKCTRL BIT(7)
|
||||
@ -82,7 +82,7 @@
|
||||
#define AD7746_CONF_MODE_GAIN_CAL (6 << 0)
|
||||
|
||||
/* CAPDAC Register Bit Designations (AD7746_REG_CAPDACx) */
|
||||
#define AD7746_CAPDAC_DACEN (1 << 7)
|
||||
#define AD7746_CAPDAC_DACEN BIT(7)
|
||||
#define AD7746_CAPDAC_DACP(x) ((x) & 0x7F)
|
||||
|
||||
/*
|
||||
@ -547,7 +547,7 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
regval = chip->config | AD7746_CONF_MODE_SINGLE_CONV;
|
||||
ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_CFG,
|
||||
regval);
|
||||
regval);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
|
@ -250,22 +250,22 @@ error_ret:
|
||||
* see dds.h for further information
|
||||
*/
|
||||
|
||||
static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ0HM);
|
||||
static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM);
|
||||
static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM);
|
||||
static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9832_write, AD9832_FREQ0HM);
|
||||
static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9832_write, AD9832_FREQ1HM);
|
||||
static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9832_write, AD9832_FREQ_SYM);
|
||||
static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
|
||||
|
||||
static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_PHASE0H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_PHASE1H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 2, S_IWUSR, NULL, ad9832_write, AD9832_PHASE2H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H);
|
||||
static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL,
|
||||
static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9832_write, AD9832_PHASE0H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9832_write, AD9832_PHASE1H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 2, 0200, NULL, ad9832_write, AD9832_PHASE2H);
|
||||
static IIO_DEV_ATTR_PHASE(0, 3, 0200, NULL, ad9832_write, AD9832_PHASE3H);
|
||||
static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL,
|
||||
ad9832_write, AD9832_PHASE_SYM);
|
||||
static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
|
||||
|
||||
static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
|
||||
static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL,
|
||||
ad9832_write, AD9832_PINCTRL_EN);
|
||||
static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
|
||||
static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL,
|
||||
ad9832_write, AD9832_OUTPUT_EN);
|
||||
|
||||
static struct attribute *ad9832_attributes[] = {
|
||||
|
@ -40,25 +40,20 @@ struct adis16060_state {
|
||||
|
||||
static struct iio_dev *adis16060_iio_dev;
|
||||
|
||||
static int adis16060_spi_write(struct iio_dev *indio_dev, u8 val)
|
||||
static int adis16060_spi_write_then_read(struct iio_dev *indio_dev,
|
||||
u8 conf, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
struct adis16060_state *st = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&st->buf_lock);
|
||||
st->buf[2] = val; /* The last 8 bits clocked in are latched */
|
||||
st->buf[2] = conf; /* The last 8 bits clocked in are latched */
|
||||
ret = spi_write(st->us_w, st->buf, 3);
|
||||
mutex_unlock(&st->buf_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adis16060_spi_read(struct iio_dev *indio_dev, u16 *val)
|
||||
{
|
||||
int ret;
|
||||
struct adis16060_state *st = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&st->buf_lock);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&st->buf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spi_read(st->us_r, st->buf, 3);
|
||||
|
||||
@ -86,17 +81,11 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
/* Take the iio_dev status lock */
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = adis16060_spi_write(indio_dev, chan->address);
|
||||
ret = adis16060_spi_write_then_read(indio_dev,
|
||||
chan->address, &tval);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
return ret;
|
||||
|
||||
ret = adis16060_spi_read(indio_dev, &tval);
|
||||
if (ret < 0)
|
||||
goto out_unlock;
|
||||
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
*val = tval;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
@ -110,10 +99,6 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_info adis16060_info = {
|
||||
|
@ -854,7 +854,7 @@ void tsl2x7x_prox_calculate(int *data, int length,
|
||||
tmp = data[i] - statP->mean;
|
||||
sample_sum += tmp * tmp;
|
||||
}
|
||||
statP->stddev = int_sqrt((long)sample_sum) / length;
|
||||
statP->stddev = int_sqrt((long)sample_sum / length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1676,7 +1676,7 @@ static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
|
||||
static const struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
|
||||
[ALS] = {
|
||||
.attrs = tsl2X7X_ALS_event_attrs,
|
||||
.name = "events",
|
||||
|
@ -83,10 +83,10 @@
|
||||
* @buf_lock: mutex to protect tx and rx
|
||||
**/
|
||||
struct ade7753_state {
|
||||
struct spi_device *us;
|
||||
struct mutex buf_lock;
|
||||
u8 tx[ADE7753_MAX_TX] ____cacheline_aligned;
|
||||
u8 rx[ADE7753_MAX_RX];
|
||||
struct spi_device *us;
|
||||
struct mutex buf_lock;
|
||||
u8 tx[ADE7753_MAX_TX] ____cacheline_aligned;
|
||||
u8 rx[ADE7753_MAX_RX];
|
||||
};
|
||||
|
||||
static int ade7753_spi_write_reg_8(struct device *dev,
|
||||
|
@ -6,18 +6,17 @@
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#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/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.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 "meter.h"
|
||||
@ -97,7 +96,7 @@
|
||||
/**
|
||||
* struct ade7754_state - device instance specific data
|
||||
* @us: actual spi_device
|
||||
* @buf_lock: mutex to protect tx and rx
|
||||
* @buf_lock: mutex to protect tx, rx and write frequency
|
||||
* @tx: transmit buffer
|
||||
* @rx: receive buffer
|
||||
**/
|
||||
@ -108,6 +107,17 @@ struct ade7754_state {
|
||||
u8 rx[ADE7754_MAX_RX];
|
||||
};
|
||||
|
||||
/* Unlocked version of ade7754_spi_write_reg_8 function */
|
||||
static int __ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ade7754_state *st = iio_priv(indio_dev);
|
||||
|
||||
st->tx[0] = ADE7754_WRITE_REG(reg_address);
|
||||
st->tx[1] = val;
|
||||
return spi_write(st->us, st->tx, 2);
|
||||
}
|
||||
|
||||
static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
|
||||
{
|
||||
int ret;
|
||||
@ -115,10 +125,7 @@ static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
|
||||
struct ade7754_state *st = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&st->buf_lock);
|
||||
st->tx[0] = ADE7754_WRITE_REG(reg_address);
|
||||
st->tx[1] = val;
|
||||
|
||||
ret = spi_write(st->us, st->tx, 2);
|
||||
ret = __ade7754_spi_write_reg_8(dev, reg_address, val);
|
||||
mutex_unlock(&st->buf_lock);
|
||||
|
||||
return ret;
|
||||
@ -513,7 +520,7 @@ static ssize_t ade7754_write_frequency(struct device *dev,
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
mutex_lock(&st->buf_lock);
|
||||
|
||||
t = 26000 / val;
|
||||
if (t > 0)
|
||||
@ -531,10 +538,10 @@ static ssize_t ade7754_write_frequency(struct device *dev,
|
||||
reg &= ~(3 << 3);
|
||||
reg |= t << 3;
|
||||
|
||||
ret = ade7754_spi_write_reg_8(dev, ADE7754_WAVMODE, reg);
|
||||
ret = __ade7754_spi_write_reg_8(dev, ADE7754_WAVMODE, reg);
|
||||
|
||||
out:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&st->buf_lock);
|
||||
|
||||
return ret ? ret : len;
|
||||
}
|
||||
|
@ -49,6 +49,10 @@
|
||||
#define HID_USAGE_SENSOR_TEMPERATURE 0x200033
|
||||
#define HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE 0x200434
|
||||
|
||||
/* humidity */
|
||||
#define HID_USAGE_SENSOR_HUMIDITY 0x200032
|
||||
#define HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY 0x200433
|
||||
|
||||
/* Gyro 3D: (200076) */
|
||||
#define HID_USAGE_SENSOR_GYRO_3D 0x200076
|
||||
#define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456
|
||||
|
Loading…
Reference in New Issue
Block a user