Commit edf5e794 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.12c' of...

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 *
parents a2e99e97 2ccc1503
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>;
};
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>;
};
* 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 = <&ltc2497_reg>;
};
...@@ -4,6 +4,7 @@ Required properties: ...@@ -4,6 +4,7 @@ Required properties:
- compatible: should be "rockchip,<name>-saradc" or "rockchip,rk3066-tsadc" - compatible: should be "rockchip,<name>-saradc" or "rockchip,rk3066-tsadc"
- "rockchip,saradc": for rk3188, rk3288 - "rockchip,saradc": for rk3188, rk3288
- "rockchip,rk3066-tsadc": for rk3036 - "rockchip,rk3066-tsadc": for rk3036
- "rockchip,rk3328-saradc", "rockchip,rk3399-saradc": for rk3328
- "rockchip,rk3399-saradc": for rk3399 - "rockchip,rk3399-saradc": for rk3399
- reg: physical base address of the controller and length of memory mapped - 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 ...@@ -3,14 +3,21 @@ InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
http://www.invensense.com/mems/gyro/mpu6050.html http://www.invensense.com/mems/gyro/mpu6050.html
Required properties: 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 - reg : the I2C address of the sensor
- interrupt-parent : should be the phandle for the interrupt controller - interrupt-parent : should be the phandle for the interrupt controller
- interrupts : interrupt mapping for GPIO IRQ - interrupts : interrupt mapping for GPIO IRQ
Optional properties: Optional properties:
- mount-matrix: an optional 3x3 mounting rotation matrix - 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: Example:
mpu6050@68 { mpu6050@68 {
...@@ -28,3 +35,19 @@ Example: ...@@ -28,3 +35,19 @@ Example:
"0", /* y2 */ "0", /* y2 */
"0.984807753012208"; /* z2 */ "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>;
};
};
};
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/ ...@@ -813,6 +813,7 @@ W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers W: http://ez.analog.com/community/linux-device-drivers
S: Supported S: Supported
F: drivers/iio/*/ad* F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc2497*
X: drivers/iio/*/adjd* X: drivers/iio/*/adjd*
F: drivers/staging/iio/*/ad* F: drivers/staging/iio/*/ad*
F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c F: drivers/staging/iio/trigger/iio-trig-bfin-timer.c
......
...@@ -130,6 +130,17 @@ config AD799X ...@@ -130,6 +130,17 @@ config AD799X
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called ad799x. 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 config AT91_ADC
tristate "Atmel AT91 ADC" tristate "Atmel AT91 ADC"
depends on ARCH_AT91 depends on ARCH_AT91
...@@ -195,6 +206,17 @@ config CC10001_ADC ...@@ -195,6 +206,17 @@ config CC10001_ADC
This driver can also be built as a module. If so, the module will be This driver can also be built as a module. If so, the module will be
called cc10001_adc. 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 config DA9150_GPADC
tristate "Dialog DA9150 GPADC driver support" tristate "Dialog DA9150 GPADC driver support"
depends on MFD_DA9150 depends on MFD_DA9150
...@@ -326,6 +348,16 @@ config LTC2485 ...@@ -326,6 +348,16 @@ config LTC2485
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called ltc2485. 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 config MAX1027
tristate "Maxim max1027 ADC driver" tristate "Maxim max1027 ADC driver"
depends on SPI depends on SPI
...@@ -563,6 +595,7 @@ config SUN4I_GPADC ...@@ -563,6 +595,7 @@ config SUN4I_GPADC
tristate "Support for the Allwinner SoCs GPADC" tristate "Support for the Allwinner SoCs GPADC"
depends on IIO depends on IIO
depends on MFD_SUN4I_GPADC depends on MFD_SUN4I_GPADC
depends on THERMAL || !THERMAL_OF
help help
Say yes here to build support for Allwinner (A10, A13 and A31) SoCs 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 GPADC. This ADC provides 4 channels which can be used as an ADC or as
......
...@@ -14,12 +14,14 @@ obj-$(CONFIG_AD7791) += ad7791.o ...@@ -14,12 +14,14 @@ obj-$(CONFIG_AD7791) += ad7791.o
obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
obj-$(CONFIG_CC10001_ADC) += cc10001_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_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
...@@ -32,6 +34,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o ...@@ -32,6 +34,7 @@ obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2497) += ltc2497.o
obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MAX1363) += max1363.o
......
...@@ -520,7 +520,7 @@ static struct attribute *ad799x_event_attributes[] = { ...@@ -520,7 +520,7 @@ static struct attribute *ad799x_event_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group ad799x_event_attrs_group = { static const struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes, .attrs = ad799x_event_attributes,
}; };
......
/*
* 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");
/*
* Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
*
* Rewritten for Linux IIO framework with some code based on
* earlier driver found in the Motorola Linux kernel:
*
* Copyright (C) 2009-2010 Motorola, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/iio/buffer.h>
#include <linux/iio/driver.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/mfd/motorola-cpcap.h>
/* Register CPCAP_REG_ADCC1 bits */
#define CPCAP_BIT_ADEN_AUTO_CLR BIT(15) /* Currently unused */
#define CPCAP_BIT_CAL_MODE BIT(14) /* Set with BIT_RAND0 */
#define CPCAP_BIT_ADC_CLK_SEL1 BIT(13) /* Currently unused */
#define CPCAP_BIT_ADC_CLK_SEL0 BIT(12) /* Currently unused */
#define CPCAP_BIT_ATOX BIT(11)
#define CPCAP_BIT_ATO3 BIT(10)
#define CPCAP_BIT_ATO2 BIT(9)
#define CPCAP_BIT_ATO1 BIT(8)
#define CPCAP_BIT_ATO0 BIT(7)
#define CPCAP_BIT_ADA2 BIT(6)
#define CPCAP_BIT_ADA1 BIT(5)
#define CPCAP_BIT_ADA0 BIT(4)
#define CPCAP_BIT_AD_SEL1 BIT(3) /* Set for bank1 */
#define CPCAP_BIT_RAND1 BIT(2) /* Set for channel 16 & 17 */
#define CPCAP_BIT_RAND0 BIT(1) /* Set with CAL_MODE */
#define CPCAP_BIT_ADEN BIT(0) /* Currently unused */
/* Register CPCAP_REG_ADCC2 bits */
#define CPCAP_BIT_CAL_FACTOR_ENABLE BIT(15) /* Currently unused */
#define CPCAP_BIT_BATDETB_EN BIT(14) /* Currently unused */
#define CPCAP_BIT_ADTRIG_ONESHOT BIT(13) /* Set for !TIMING_IMM */
#define CPCAP_BIT_ASC BIT(12) /* Set for TIMING_IMM */
#define CPCAP_BIT_ATOX_PS_FACTOR BIT(11)
#define CPCAP_BIT_ADC_PS_FACTOR1 BIT(10)
#define CPCAP_BIT_ADC_PS_FACTOR0 BIT(9)
#define CPCAP_BIT_AD4_SELECT BIT(8) /* Currently unused */
#define CPCAP_BIT_ADC_BUSY BIT(7) /* Currently unused */
#define CPCAP_BIT_THERMBIAS_EN BIT(6) /* Currently unused */
#define CPCAP_BIT_ADTRIG_DIS BIT(5) /* Disable interrupt */
#define CPCAP_BIT_LIADC BIT(4) /* Currently unused */
#define CPCAP_BIT_TS_REFEN BIT(3) /* Currently unused */
#define CPCAP_BIT_TS_M2 BIT(2) /* Currently unused */
#define CPCAP_BIT_TS_M1 BIT(1) /* Currently unused */
#define CPCAP_BIT_TS_M0 BIT(0) /* Currently unused */
#define CPCAP_MAX_TEMP_LVL 27
#define CPCAP_FOUR_POINT_TWO_ADC 801
#define ST_ADC_CAL_CHRGI_HIGH_THRESHOLD 530
#define ST_ADC_CAL_CHRGI_LOW_THRESHOLD 494
#define ST_ADC_CAL_BATTI_HIGH_THRESHOLD 530
#define ST_ADC_CAL_BATTI_LOW_THRESHOLD 494
#define ST_ADC_CALIBRATE_DIFF_THRESHOLD 3
#define CPCAP_ADC_MAX_RETRIES 5 /* Calibration and quirk */
/**
* struct cpcap_adc_ato - timing settings for cpcap adc
*
* Unfortunately no cpcap documentation available, please document when
* using these.
*/
struct cpcap_adc_ato {
unsigned short ato_in;
unsigned short atox_in;
unsigned short adc_ps_factor_in;
unsigned short atox_ps_factor_in;
unsigned short ato_out;
unsigned short atox_out;
unsigned short adc_ps_factor_out;
unsigned short atox_ps_factor_out;
};
/**
* struct cpcap-adc - cpcap adc device driver data
* @reg: cpcap regmap
* @dev: struct device
* @vendor: cpcap vendor
* @irq: interrupt
* @lock: mutex
* @ato: request timings
* @wq_data_avail: work queue
* @done: work done
*/
struct cpcap_adc {
struct regmap *reg;
struct device *dev;
u16 vendor;
int irq;
struct mutex lock; /* ADC register access lock */
const struct cpcap_adc_ato *ato;
wait_queue_head_t wq_data_avail;
bool done;
};
/**
* enum cpcap_adc_channel - cpcap adc channels
*/
enum cpcap_adc_channel {
/* Bank0 channels */
CPCAP_ADC_AD0_BATTDETB, /* Battery detection */
CPCAP_ADC_BATTP, /* Battery voltage */
CPCAP_ADC_VBUS, /* USB VBUS voltage */
CPCAP_ADC_AD3, /* Battery temperature when charging */
CPCAP_ADC_BPLUS_AD4, /* Another battery or system voltage */
CPCAP_ADC_CHG_ISENSE, /* Calibrated charge current */
CPCAP_ADC_BATTI, /* Calibrated system current */
CPCAP_ADC_USB_ID, /* USB OTG ID, unused on droid 4? */
/* Bank1 channels */
CPCAP_ADC_AD8, /* Seems unused */
CPCAP_ADC_AD9, /* Seems unused */
CPCAP_ADC_LICELL, /* Maybe system voltage? Always 3V */
CPCAP_ADC_HV_BATTP, /* Another battery detection? */
CPCAP_ADC_TSX1_AD12, /* Seems unused, for touchscreen? */
CPCAP_ADC_TSX2_AD13, /* Seems unused, for touchscreen? */
CPCAP_ADC_TSY1_AD14, /* Seems unused, for touchscreen? */
CPCAP_ADC_TSY2_AD15, /* Seems unused, for touchscreen? */
/* Remuxed channels using bank0 entries */
CPCAP_ADC_BATTP_PI16, /* Alternative mux mode for BATTP */
CPCAP_ADC_BATTI_PI17, /* Alternative mux mode for BATTI */
CPCAP_ADC_CHANNEL_NUM,
};
/**
* enum cpcap_adc_timing - cpcap adc timing options
*
* CPCAP_ADC_TIMING_IMM seems to be immediate with no timings.
* Please document when using.
*/
enum cpcap_adc_timing {
CPCAP_ADC_TIMING_IMM,
CPCAP_ADC_TIMING_IN,
CPCAP_ADC_TIMING_OUT,
};
/**
* struct cpcap_adc_phasing_tbl - cpcap phasing table
* @offset: offset in the phasing table
* @multiplier: multiplier in the phasing table
* @divider: divider in the phasing table
* @min: minimum value
* @max: maximum value
*/
struct cpcap_adc_phasing_tbl {
short offset;
unsigned short multiplier;
unsigned short divider;
short min;
short max;
};
/**
* struct cpcap_adc_conversion_tbl - cpcap conversion table
* @conv_type: conversion type
* @align_offset: align offset
* @conv_offset: conversion offset
* @cal_offset: calibration offset
* @multiplier: conversion multiplier
* @divider: conversion divider
*/
struct cpcap_adc_conversion_tbl {
enum iio_chan_info_enum conv_type;
int align_offset;
int conv_offset;
int cal_offset;
int multiplier;
int divider;
};
/**
* struct cpcap_adc_request - cpcap adc request
* @channel: request channel
* @phase_tbl: channel phasing table
* @conv_tbl: channel conversion table
* @bank_index: channel index within the bank
* @timing: timing settings
* @result: result
*/
struct cpcap_adc_request {
int channel;
const struct cpcap_adc_phasing_tbl *phase_tbl;
const struct cpcap_adc_conversion_tbl *conv_tbl;
int bank_index;
enum cpcap_adc_timing timing;
int result;
};
/* Phasing table for channels. Note that channels 16 & 17 use BATTP and BATTI */
static const struct cpcap_adc_phasing_tbl bank_phasing[] = {
/* Bank0 */
[CPCAP_ADC_AD0_BATTDETB] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_BATTP] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_VBUS] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_AD3] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_BPLUS_AD4] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_CHG_ISENSE] = {0, 0x80, 0x80, -512, 511},
[CPCAP_ADC_BATTI] = {0, 0x80, 0x80, -512, 511},
[CPCAP_ADC_USB_ID] = {0, 0x80, 0x80, 0, 1023},
/* Bank1 */
[CPCAP_ADC_AD8] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_AD9] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_LICELL] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_HV_BATTP] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_TSX1_AD12] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_TSX2_AD13] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_TSY1_AD14] = {0, 0x80, 0x80, 0, 1023},
[CPCAP_ADC_TSY2_AD15] = {0, 0x80, 0x80, 0, 1023},
};
/*
* Conversion table for channels. Updated during init based on calibration.
* Here too channels 16 & 17 use BATTP and BATTI.
*/
static struct cpcap_adc_conversion_tbl bank_conversion[] = {
/* Bank0 */
[CPCAP_ADC_AD0_BATTDETB] = {
IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_BATTP] = {
IIO_CHAN_INFO_PROCESSED, 0, 2400, 0, 2300, 1023,
},
[CPCAP_ADC_VBUS] = {
IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 10000, 1023,
},
[CPCAP_ADC_AD3] = {
IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_BPLUS_AD4] = {
IIO_CHAN_INFO_PROCESSED, 0, 2400, 0, 2300, 1023,
},
[CPCAP_ADC_CHG_ISENSE] = {
IIO_CHAN_INFO_PROCESSED, -512, 2, 0, 5000, 1023,
},
[CPCAP_ADC_BATTI] = {
IIO_CHAN_INFO_PROCESSED, -512, 2, 0, 5000, 1023,
},
[CPCAP_ADC_USB_ID] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
/* Bank1 */
[CPCAP_ADC_AD8] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_AD9] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_LICELL] = {
IIO_CHAN_INFO_PROCESSED, 0, 0, 0, 3400, 1023,
},
[CPCAP_ADC_HV_BATTP] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_TSX1_AD12] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_TSX2_AD13] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_TSY1_AD14] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
[CPCAP_ADC_TSY2_AD15] = {
IIO_CHAN_INFO_RAW, 0, 0, 0, 1, 1,
},
};
/*
* Temperature lookup table of register values to milliCelcius.
* REVISIT: Check the duplicate 0x3ff entry in a freezer
*/
static const int temp_map[CPCAP_MAX_TEMP_LVL][2] = {
{ 0x03ff, -40000 },
{ 0x03ff, -35000 },
{ 0x03ef, -30000 },
{ 0x03b2, -25000 },
{ 0x036c, -20000 },
{ 0x0320, -15000 },
{ 0x02d0, -10000 },
{ 0x027f, -5000 },
{ 0x022f, 0 },
{ 0x01e4, 5000 },
{ 0x019f, 10000 },
{ 0x0161, 15000 },
{ 0x012b, 20000 },
{ 0x00fc, 25000 },
{ 0x00d4, 30000 },
{ 0x00b2, 35000 },
{ 0x0095, 40000 },
{ 0x007d, 45000 },
{ 0x0069, 50000 },
{ 0x0059, 55000 },
{ 0x004b, 60000 },
{ 0x003f, 65000 },
{ 0x0036, 70000 },
{ 0x002e, 75000 },
{ 0x0027, 80000 },
{ 0x0022, 85000 },
{ 0x001d, 90000 },
};
#define CPCAP_CHAN(_type, _index, _address, _datasheet_name) { \
.type = (_type), \
.address = (_address), \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 10, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
.datasheet_name = (_datasheet_name), \
}
/*
* The datasheet names are from Motorola mapphone Linux kernel except
* for the last two which might be uncalibrated charge voltage and
* current.
*/
static const struct iio_chan_spec cpcap_adc_channels[] = {
/* Bank0 */
CPCAP_CHAN(IIO_TEMP, 0, CPCAP_REG_ADCD0, "battdetb"),
CPCAP_CHAN(IIO_VOLTAGE, 1, CPCAP_REG_ADCD1, "battp"),
CPCAP_CHAN(IIO_VOLTAGE, 2, CPCAP_REG_ADCD2, "vbus"),
CPCAP_CHAN(IIO_TEMP, 3, CPCAP_REG_ADCD3, "ad3"),
CPCAP_CHAN(IIO_VOLTAGE, 4, CPCAP_REG_ADCD4, "ad4"),
CPCAP_CHAN(IIO_CURRENT, 5, CPCAP_REG_ADCD5, "chg_isense"),
CPCAP_CHAN(IIO_CURRENT, 6, CPCAP_REG_ADCD6, "batti"),
CPCAP_CHAN(IIO_VOLTAGE, 7, CPCAP_REG_ADCD7, "usb_id"),
/* Bank1 */
CPCAP_CHAN(IIO_CURRENT, 8, CPCAP_REG_ADCD0, "ad8"),
CPCAP_CHAN(IIO_VOLTAGE, 9, CPCAP_REG_ADCD1, "ad9"),
CPCAP_CHAN(IIO_VOLTAGE, 10, CPCAP_REG_ADCD2, "licell"),
CPCAP_CHAN(IIO_VOLTAGE, 11, CPCAP_REG_ADCD3, "hv_battp"),
CPCAP_CHAN(IIO_VOLTAGE, 12, CPCAP_REG_ADCD4, "tsx1_ad12"),
CPCAP_CHAN(IIO_VOLTAGE, 13, CPCAP_REG_ADCD5, "tsx2_ad13"),
CPCAP_CHAN(IIO_VOLTAGE, 14, CPCAP_REG_ADCD6, "tsy1_ad14"),
CPCAP_CHAN(IIO_VOLTAGE, 15, CPCAP_REG_ADCD7, "tsy2_ad15"),
/* There are two registers with multiplexed functionality */
CPCAP_CHAN(IIO_VOLTAGE, 16, CPCAP_REG_ADCD0, "chg_vsense"),
CPCAP_CHAN(IIO_CURRENT, 17, CPCAP_REG_ADCD1, "batti2"),
};
static irqreturn_t cpcap_adc_irq_thread(int irq, void *data)
{
struct iio_dev *indio_dev = data;
struct cpcap_adc *ddata = iio_priv(indio_dev);
int error;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return IRQ_NONE;
ddata->done = true;
wake_up_interruptible(&ddata->wq_data_avail);
return IRQ_HANDLED;
}
/* ADC calibration functions */
static void cpcap_adc_setup_calibrate(struct cpcap_adc *ddata,
enum cpcap_adc_channel chan)
{
unsigned int value = 0;
unsigned long timeout = jiffies + msecs_to_jiffies(3000);
int error;
if ((chan != CPCAP_ADC_CHG_ISENSE) &&
(chan != CPCAP_ADC_BATTI))
return;
value |= CPCAP_BIT_CAL_MODE | CPCAP_BIT_RAND0;
value |= ((chan << 4) &
(CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 | CPCAP_BIT_ADA0));
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
CPCAP_BIT_CAL_MODE | CPCAP_BIT_ATOX |
CPCAP_BIT_ATO3 | CPCAP_BIT_ATO2 |
CPCAP_BIT_ATO1 | CPCAP_BIT_ATO0 |
CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 |
CPCAP_BIT_ADA0 | CPCAP_BIT_AD_SEL1 |
CPCAP_BIT_RAND1 | CPCAP_BIT_RAND0,
value);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ATOX_PS_FACTOR |
CPCAP_BIT_ADC_PS_FACTOR1 |
CPCAP_BIT_ADC_PS_FACTOR0,
0);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ASC,
CPCAP_BIT_ASC);
if (error)
return;
do {
schedule_timeout_uninterruptible(1);
error = regmap_read(ddata->reg, CPCAP_REG_ADCC2, &value);
if (error)
return;
} while ((value & CPCAP_BIT_ASC) && time_before(jiffies, timeout));
if (value & CPCAP_BIT_ASC)
dev_err(ddata->dev,
"Timeout waiting for calibration to complete\n");
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
CPCAP_BIT_CAL_MODE, 0);
if (error)
return;
}
static int cpcap_adc_calibrate_one(struct cpcap_adc *ddata,
int channel,
u16 calibration_register,
int lower_threshold,
int upper_threshold)
{
unsigned int calibration_data[2];
unsigned short cal_data_diff;
int i, error;
for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) {
calibration_data[0] = 0;
calibration_data[1] = 0;
cal_data_diff = 0;
cpcap_adc_setup_calibrate(ddata, channel);
error = regmap_read(ddata->reg, calibration_register,
&calibration_data[0]);
if (error)
return error;
cpcap_adc_setup_calibrate(ddata, channel);
error = regmap_read(ddata->reg, calibration_register,
&calibration_data[1]);
if (error)
return error;
if (calibration_data[0] > calibration_data[1])
cal_data_diff =
calibration_data[0] - calibration_data[1];
else
cal_data_diff =
calibration_data[1] - calibration_data[0];
if (((calibration_data[1] >= lower_threshold) &&
(calibration_data[1] <= upper_threshold) &&
(cal_data_diff <= ST_ADC_CALIBRATE_DIFF_THRESHOLD)) ||
(ddata->vendor == CPCAP_VENDOR_TI)) {
bank_conversion[channel].cal_offset =
((short)calibration_data[1] * -1) + 512;
dev_dbg(ddata->dev, "ch%i calibration complete: %i\n",
channel, bank_conversion[channel].cal_offset);
break;
}
usleep_range(5000, 10000);
}
return 0;
}
static int cpcap_adc_calibrate(struct cpcap_adc *ddata)
{
int error;
error = cpcap_adc_calibrate_one(ddata, CPCAP_ADC_CHG_ISENSE,
CPCAP_REG_ADCAL1,
ST_ADC_CAL_CHRGI_LOW_THRESHOLD,
ST_ADC_CAL_CHRGI_HIGH_THRESHOLD);
if (error)
return error;
error = cpcap_adc_calibrate_one(ddata, CPCAP_ADC_BATTI,
CPCAP_REG_ADCAL2,
ST_ADC_CAL_BATTI_LOW_THRESHOLD,
ST_ADC_CAL_BATTI_HIGH_THRESHOLD);
if (error)
return error;
return 0;
}
/* ADC setup, read and scale functions */
static void cpcap_adc_setup_bank(struct cpcap_adc *ddata,
struct cpcap_adc_request *req)
{
const struct cpcap_adc_ato *ato = ddata->ato;
unsigned short value1 = 0;
unsigned short value2 = 0;
int error;
if (!ato)
return;
switch (req->channel) {
case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
value1 |= CPCAP_BIT_AD_SEL1;
break;
case CPCAP_ADC_BATTP_PI16 ... CPCAP_ADC_BATTI_PI17:
value1 |= CPCAP_BIT_RAND1;
default:
break;
}
switch (req->timing) {
case CPCAP_ADC_TIMING_IN:
value1 |= ato->ato_in;
value1 |= ato->atox_in;
value2 |= ato->adc_ps_factor_in;
value2 |= ato->atox_ps_factor_in;
break;
case CPCAP_ADC_TIMING_OUT:
value1 |= ato->ato_out;
value1 |= ato->atox_out;
value2 |= ato->adc_ps_factor_out;
value2 |= ato->atox_ps_factor_out;
break;
case CPCAP_ADC_TIMING_IMM:
default:
break;
}
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC1,
CPCAP_BIT_CAL_MODE | CPCAP_BIT_ATOX |
CPCAP_BIT_ATO3 | CPCAP_BIT_ATO2 |
CPCAP_BIT_ATO1 | CPCAP_BIT_ATO0 |
CPCAP_BIT_ADA2 | CPCAP_BIT_ADA1 |
CPCAP_BIT_ADA0 | CPCAP_BIT_AD_SEL1 |
CPCAP_BIT_RAND1 | CPCAP_BIT_RAND0,
value1);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ATOX_PS_FACTOR |
CPCAP_BIT_ADC_PS_FACTOR1 |
CPCAP_BIT_ADC_PS_FACTOR0,
value2);
if (error)
return;
if (req->timing == CPCAP_ADC_TIMING_IMM) {
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ASC,
CPCAP_BIT_ASC);
if (error)
return;
} else {
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_ONESHOT,
CPCAP_BIT_ADTRIG_ONESHOT);
if (error)
return;
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS, 0);
if (error)
return;
}
}
/*
* Occasionally the ADC does not seem to start and there will be no
* interrupt. Let's re-init interrupt to prevent the ADC from hanging
* for the next request. It is unclear why this happens, but the next
* request will usually work after doing this.
*/
static void cpcap_adc_quirk_reset_lost_irq(struct cpcap_adc *ddata)
{
int error;
dev_info(ddata->dev, "lost ADC irq, attempting to reinit\n");
disable_irq(ddata->irq);
error = regmap_update_bits(ddata->reg, CPCAP_REG_ADCC2,
CPCAP_BIT_ADTRIG_DIS,
CPCAP_BIT_ADTRIG_DIS);
if (error)
dev_warn(ddata->dev, "%s reset failed: %i\n",
__func__, error);
enable_irq(ddata->irq);
}
static int cpcap_adc_start_bank(struct cpcap_adc *ddata,
struct cpcap_adc_request *req)
{
int i, error;
req->timing = CPCAP_ADC_TIMING_IMM;
ddata->done = false;
for (i = 0; i < CPCAP_ADC_MAX_RETRIES; i++) {
cpcap_adc_setup_bank(ddata, req);
error = wait_event_interruptible_timeout(ddata->wq_data_avail,
ddata->done,
msecs_to_jiffies(50));
if (error > 0)
return 0;
if (error == 0) {
cpcap_adc_quirk_reset_lost_irq(ddata);
error = -ETIMEDOUT;
continue;
}
if (error < 0)
return error;
}
return error;
}
static void cpcap_adc_phase(struct cpcap_adc_request *req)
{
const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl;
const struct cpcap_adc_phasing_tbl *phase_tbl = req->phase_tbl;
int index = req->channel;
/* Remuxed channels 16 and 17 use BATTP and BATTI entries */
switch (req->channel) {
case CPCAP_ADC_BATTP:
case CPCAP_ADC_BATTP_PI16:
index = req->bank_index;
req->result -= phase_tbl[index].offset;
req->result -= CPCAP_FOUR_POINT_TWO_ADC;
req->result *= phase_tbl[index].multiplier;
if (phase_tbl[index].divider == 0)
return;
req->result /= phase_tbl[index].divider;
req->result += CPCAP_FOUR_POINT_TWO_ADC;
break;
case CPCAP_ADC_BATTI_PI17:
index = req->bank_index;
/* fallthrough */
default:
req->result += conv_tbl[index].cal_offset;
req->result += conv_tbl[index].align_offset;
req->result *= phase_tbl[index].multiplier;
if (phase_tbl[index].divider == 0)
return;
req->result /= phase_tbl[index].divider;
req->result += phase_tbl[index].offset;
break;
}
if (req->result < phase_tbl[index].min)
req->result = phase_tbl[index].min;
else if (req->result > phase_tbl[index].max)
req->result = phase_tbl[index].max;
}
/* Looks up temperatures in a table and calculates averages if needed */
static int cpcap_adc_table_to_millicelcius(unsigned short value)
{
int i, result = 0, alpha;
if (value <= temp_map[CPCAP_MAX_TEMP_LVL - 1][0])
return temp_map[CPCAP_MAX_TEMP_LVL - 1][1];
if (value >= temp_map[0][0])
return temp_map[0][1];
for (i = 0; i < CPCAP_MAX_TEMP_LVL - 1; i++) {
if ((value <= temp_map[i][0]) &&
(value >= temp_map[i + 1][0])) {
if (value == temp_map[i][0]) {
result = temp_map[i][1];
} else if (value == temp_map[i + 1][0]) {
result = temp_map[i + 1][1];
} else {
alpha = ((value - temp_map[i][0]) * 1000) /
(temp_map[i + 1][0] - temp_map[i][0]);
result = temp_map[i][1] +
((alpha * (temp_map[i + 1][1] -
temp_map[i][1])) / 1000);
}
break;
}
}
return result;
}
static void cpcap_adc_convert(struct cpcap_adc_request *req)
{
const struct cpcap_adc_conversion_tbl *conv_tbl = req->conv_tbl;
int index = req->channel;
/* Remuxed channels 16 and 17 use BATTP and BATTI entries */
switch (req->channel) {
case CPCAP_ADC_BATTP_PI16:
index = CPCAP_ADC_BATTP;
break;
case CPCAP_ADC_BATTI_PI17:
index = CPCAP_ADC_BATTI;
break;
default:
break;
}
/* No conversion for raw channels */
if (conv_tbl[index].conv_type == IIO_CHAN_INFO_RAW)
return;
/* Temperatures use a lookup table instead of conversion table */
if ((req->channel == CPCAP_ADC_AD0_BATTDETB) ||
(req->channel == CPCAP_ADC_AD3)) {
req->result =
cpcap_adc_table_to_millicelcius(req->result);
return;
}
/* All processed channels use a conversion table */
req->result *= conv_tbl[index].multiplier;
if (conv_tbl[index].divider == 0)
return;
req->result /= conv_tbl[index].divider;
req->result += conv_tbl[index].conv_offset;
}
/*
* REVISIT: Check if timed sampling can use multiple channels at the
* same time. If not, replace channel_mask with just channel.
*/
static int cpcap_adc_read_bank_scaled(struct cpcap_adc *ddata,
struct cpcap_adc_request *req)
{
int calibration_data, error, addr;
if (ddata->vendor == CPCAP_VENDOR_TI) {
error = regmap_read(ddata->reg, CPCAP_REG_ADCAL1,
&calibration_data);
if (error)
return error;
bank_conversion[CPCAP_ADC_CHG_ISENSE].cal_offset =
((short)calibration_data * -1) + 512;
error = regmap_read(ddata->reg, CPCAP_REG_ADCAL2,
&calibration_data);
if (error)
return error;
bank_conversion[CPCAP_ADC_BATTI].cal_offset =
((short)calibration_data * -1) + 512;
}
addr = CPCAP_REG_ADCD0 + req->bank_index * 4;
error = regmap_read(ddata->reg, addr, &req->result);
if (error)
return error;
req->result &= 0x3ff;
cpcap_adc_phase(req);
cpcap_adc_convert(req);
return 0;
}
static int cpcap_adc_init_request(struct cpcap_adc_request *req,
int channel)
{
req->channel = channel;
req->phase_tbl = bank_phasing;
req->conv_tbl = bank_conversion;
switch (channel) {
case CPCAP_ADC_AD0_BATTDETB ... CPCAP_ADC_USB_ID:
req->bank_index = channel;
break;
case CPCAP_ADC_AD8 ... CPCAP_ADC_TSY2_AD15:
req->bank_index = channel - 8;
break;
case CPCAP_ADC_BATTP_PI16:
req->bank_index = CPCAP_ADC_BATTP;
break;
case CPCAP_ADC_BATTI_PI17:
req->bank_index = CPCAP_ADC_BATTI;
break;
default:
return -EINVAL;
}
return 0;
}
static int cpcap_adc_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct cpcap_adc *ddata = iio_priv(indio_dev);
struct cpcap_adc_request req;
int error;
error = cpcap_adc_init_request(&req, chan->channel);
if (error)
return error;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&ddata->lock);
error = cpcap_adc_start_bank(ddata, &req);
if (error)
goto err_unlock;
error = regmap_read(ddata->reg, chan->address, val);
if (error)
goto err_unlock;
mutex_unlock(&ddata->lock);
break;
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&ddata->lock);
error = cpcap_adc_start_bank(ddata, &req);
if (error)
goto err_unlock;
error = cpcap_adc_read_bank_scaled(ddata, &req);
if (error)
goto err_unlock;
mutex_unlock(&ddata->lock);
*val = req.result;
break;
default:
return -EINVAL;
}
return IIO_VAL_INT;
err_unlock:
mutex_unlock(&ddata->lock);
dev_err(ddata->dev, "error reading ADC: %i\n", error);
return error;
}
static const struct iio_info cpcap_adc_info = {
.read_raw = &cpcap_adc_read,
.driver_module = THIS_MODULE,
};
/*
* Configuration for Motorola mapphone series such as droid 4.
* Copied from the Motorola mapphone kernel tree.
*/
static const struct cpcap_adc_ato mapphone_adc = {
.ato_in = 0x0480,
.atox_in = 0,
.adc_ps_factor_in = 0x0200,
.atox_ps_factor_in = 0,
.ato_out = 0,
.atox_out = 0,
.adc_ps_factor_out = 0,
.atox_ps_factor_out = 0,
};
static const struct of_device_id cpcap_adc_id_table[] = {
{
.compatible = "motorola,cpcap-adc",
},
{
.compatible = "motorola,mapphone-cpcap-adc",
.data = &mapphone_adc,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cpcap_adc_id_table);
static int cpcap_adc_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct cpcap_adc *ddata;
struct iio_dev *indio_dev;
int error;
match = of_match_device(of_match_ptr(cpcap_adc_id_table),
&pdev->dev);
if (!match)
return -EINVAL;
if (!match->data) {
dev_err(&pdev->dev, "no configuration data found\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*ddata));
if (!indio_dev) {
dev_err(&pdev->dev, "failed to allocate iio device\n");
return -ENOMEM;
}
ddata = iio_priv(indio_dev);
ddata->ato = match->data;
ddata->dev = &pdev->dev;
mutex_init(&ddata->lock);
init_waitqueue_head(&ddata->wq_data_avail);
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->dev.parent = &pdev->dev;
indio_dev->dev.of_node = pdev->dev.of_node;
indio_dev->channels = cpcap_adc_channels;
indio_dev->num_channels = ARRAY_SIZE(cpcap_adc_channels);
indio_dev->name = dev_name(&pdev->dev);
indio_dev->info = &cpcap_adc_info;
ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
if (!ddata->reg)
return -ENODEV;
error = cpcap_get_vendor(ddata->dev, ddata->reg, &ddata->vendor);
if (error)
return error;
platform_set_drvdata(pdev, indio_dev);
ddata->irq = platform_get_irq_byname(pdev, "adcdone");
if (!ddata->irq)
return -ENODEV;
error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL,
cpcap_adc_irq_thread,
IRQF_TRIGGER_NONE,
"cpcap-adc", indio_dev);
if (error) {
dev_err(&pdev->dev, "could not get irq: %i\n",
error);
return error;
}
error = cpcap_adc_calibrate(ddata);
if (error)
return error;
dev_info(&pdev->dev, "CPCAP ADC device probed\n");
return devm_iio_device_register(&pdev->dev, indio_dev);
}
static struct platform_driver cpcap_adc_driver = {
.driver = {
.name = "cpcap_adc",
.of_match_table = of_match_ptr(cpcap_adc_id_table),
},
.probe = cpcap_adc_probe,
};
module_platform_driver(cpcap_adc_driver);
MODULE_ALIAS("platform:cpcap_adc");
MODULE_DESCRIPTION("CPCAP ADC driver");
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com");
MODULE_LICENSE("GPL v2");
...@@ -579,7 +579,7 @@ static int exynos_read_s3c64xx_ts(struct iio_dev *indio_dev, int *x, int *y) ...@@ -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) 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; u32 mask = info->data->mask;
/* Read value */ /* Read value */
......
...@@ -369,7 +369,7 @@ static struct attribute *hx711_attributes[] = { ...@@ -369,7 +369,7 @@ static struct attribute *hx711_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group hx711_attribute_group = { static const struct attribute_group hx711_attribute_group = {
.attrs = hx711_attributes, .attrs = hx711_attributes,
}; };
......
...@@ -365,7 +365,7 @@ static int imx7d_adc_read_data(struct imx7d_adc *info) ...@@ -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) 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; int status;
status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS); status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS);
......
/*
* 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 = &ltc2497_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) ...@@ -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) 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 iio_dev *indio_dev = pf->indio_dev;
struct max1027_state *st = iio_priv(indio_dev); struct max1027_state *st = iio_priv(indio_dev);
......
...@@ -124,8 +124,8 @@ static int max11100_probe(struct spi_device *spi) ...@@ -124,8 +124,8 @@ static int max11100_probe(struct spi_device *spi)
indio_dev->name = "max11100"; indio_dev->name = "max11100";
indio_dev->info = &max11100_info; indio_dev->info = &max11100_info;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = max11100_channels, indio_dev->channels = max11100_channels;
indio_dev->num_channels = ARRAY_SIZE(max11100_channels), indio_dev->num_channels = ARRAY_SIZE(max11100_channels);
state->vref_reg = devm_regulator_get(&spi->dev, "vref"); state->vref_reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(state->vref_reg)) if (IS_ERR(state->vref_reg))
......
...@@ -1007,7 +1007,7 @@ static struct attribute *max1363_event_attributes[] = { ...@@ -1007,7 +1007,7 @@ static struct attribute *max1363_event_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group max1363_event_attribute_group = { static const struct attribute_group max1363_event_attribute_group = {
.attrs = max1363_event_attributes, .attrs = max1363_event_attributes,
}; };
......
...@@ -166,6 +166,8 @@ ...@@ -166,6 +166,8 @@
#define MESON_SAR_ADC_MAX_FIFO_SIZE 32 #define MESON_SAR_ADC_MAX_FIFO_SIZE 32
#define MESON_SAR_ADC_TIMEOUT 100 /* ms */ #define MESON_SAR_ADC_TIMEOUT 100 /* ms */
/* for use with IIO_VAL_INT_PLUS_MICRO */
#define MILLION 1000000
#define MESON_SAR_ADC_CHAN(_chan) { \ #define MESON_SAR_ADC_CHAN(_chan) { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
...@@ -173,7 +175,9 @@ ...@@ -173,7 +175,9 @@
.channel = _chan, \ .channel = _chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_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, \ .datasheet_name = "SAR_ADC_CH"#_chan, \
} }
...@@ -233,6 +237,8 @@ struct meson_sar_adc_priv { ...@@ -233,6 +237,8 @@ struct meson_sar_adc_priv {
struct clk *adc_div_clk; struct clk *adc_div_clk;
struct clk_divider clk_div; struct clk_divider clk_div;
struct completion done; struct completion done;
int calibbias;
int calibscale;
}; };
static const struct regmap_config meson_sar_adc_regmap_config = { 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) ...@@ -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); 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) static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
{ {
struct meson_sar_adc_priv *priv = iio_priv(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, ...@@ -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 = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval);
fifo_val &= GENMASK(priv->data->resolution - 1, 0); fifo_val &= GENMASK(priv->data->resolution - 1, 0);
*val = fifo_val; *val = meson_sar_adc_calib_val(indio_dev, fifo_val);
return 0; return 0;
} }
...@@ -527,6 +544,15 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, ...@@ -527,6 +544,15 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
*val2 = priv->data->resolution; *val2 = priv->data->resolution;
return IIO_VAL_FRACTIONAL_LOG2; 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: default:
return -EINVAL; return -EINVAL;
} }
...@@ -762,6 +788,47 @@ static irqreturn_t meson_sar_adc_irq(int irq, void *data) ...@@ -762,6 +788,47 @@ static irqreturn_t meson_sar_adc_irq(int irq, void *data)
return IRQ_HANDLED; 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 = { static const struct iio_info meson_sar_adc_iio_info = {
.read_raw = meson_sar_adc_iio_info_read_raw, .read_raw = meson_sar_adc_iio_info_read_raw,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
...@@ -901,6 +968,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev) ...@@ -901,6 +968,8 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
return PTR_ERR(priv->vref); return PTR_ERR(priv->vref);
} }
priv->calibscale = MILLION;
ret = meson_sar_adc_init(indio_dev); ret = meson_sar_adc_init(indio_dev);
if (ret) if (ret)
goto err; goto err;
...@@ -909,6 +978,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev) ...@@ -909,6 +978,10 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err; goto err;
ret = meson_sar_adc_calib(indio_dev);
if (ret)
dev_warn(&pdev->dev, "calibration failed\n");
platform_set_drvdata(pdev, indio_dev); platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev); ret = iio_device_register(indio_dev);
......
...@@ -109,7 +109,7 @@ static int rockchip_saradc_read_raw(struct iio_dev *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) 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 */ /* Read value */
info->last_val = readl_relaxed(info->regs + SARADC_DATA); info->last_val = readl_relaxed(info->regs + SARADC_DATA);
......
...@@ -382,7 +382,7 @@ static int sun4i_gpadc_runtime_resume(struct device *dev) ...@@ -382,7 +382,7 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
static int sun4i_gpadc_get_temp(void *data, int *temp) 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; int val, scale, offset;
if (sun4i_gpadc_temp_read(info->indio_dev, &val)) if (sun4i_gpadc_temp_read(info->indio_dev, &val))
......
...@@ -584,7 +584,7 @@ static int vf610_adc_read_data(struct vf610_adc *info) ...@@ -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) 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); struct vf610_adc *info = iio_priv(indio_dev);
int coco; int coco;
......
...@@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client, ...@@ -163,7 +163,7 @@ static int ams_iaqcore_probe(struct i2c_client *client,
mutex_init(&data->lock); mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev; 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->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
......
...@@ -393,7 +393,7 @@ static int vz89x_probe(struct i2c_client *client, ...@@ -393,7 +393,7 @@ static int vz89x_probe(struct i2c_client *client,
mutex_init(&data->lock); mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev; 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->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
......
...@@ -267,31 +267,12 @@ static int cros_ec_sensors_probe(struct platform_device *pdev) ...@@ -267,31 +267,12 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
else else
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
ret = iio_triggered_buffer_setup(indio_dev, NULL, ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
cros_ec_sensors_capture, NULL); cros_ec_sensors_capture, NULL);
if (ret) if (ret)
return ret; return ret;
ret = iio_device_register(indio_dev); return devm_iio_device_register(dev, 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;
} }
static const struct platform_device_id cros_ec_sensors_ids[] = { static const struct platform_device_id cros_ec_sensors_ids[] = {
...@@ -313,7 +294,6 @@ static struct platform_driver cros_ec_sensors_platform_driver = { ...@@ -313,7 +294,6 @@ static struct platform_driver cros_ec_sensors_platform_driver = {
.name = "cros-ec-sensors", .name = "cros-ec-sensors",
}, },
.probe = cros_ec_sensors_probe, .probe = cros_ec_sensors_probe,
.remove = cros_ec_sensors_remove,
.id_table = cros_ec_sensors_ids, .id_table = cros_ec_sensors_ids,
}; };
module_platform_driver(cros_ec_sensors_platform_driver); module_platform_driver(cros_ec_sensors_platform_driver);
......
...@@ -38,6 +38,12 @@ static struct { ...@@ -38,6 +38,12 @@ static struct {
{HID_USAGE_SENSOR_ACCEL_3D, {HID_USAGE_SENSOR_ACCEL_3D,
HID_USAGE_SENSOR_UNITS_G, 9, 806650000}, 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, 0, 0, 17453293},
{HID_USAGE_SENSOR_GYRO_3D, {HID_USAGE_SENSOR_GYRO_3D,
HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0}, HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND, 1, 0},
...@@ -65,6 +71,8 @@ static struct { ...@@ -65,6 +71,8 @@ static struct {
{HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0}, {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0},
{HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 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) static int pow_10(unsigned power)
......
...@@ -74,7 +74,7 @@ EXPORT_SYMBOL(ms_sensors_reset); ...@@ -74,7 +74,7 @@ EXPORT_SYMBOL(ms_sensors_reset);
int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word) int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
{ {
int ret; int ret;
struct i2c_client *client = (struct i2c_client *)cli; struct i2c_client *client = cli;
ret = i2c_smbus_read_word_swapped(client, cmd); ret = i2c_smbus_read_word_swapped(client, cmd);
if (ret < 0) { if (ret < 0) {
...@@ -107,7 +107,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd, ...@@ -107,7 +107,7 @@ int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
{ {
int ret; int ret;
__be32 buf = 0; __be32 buf = 0;
struct i2c_client *client = (struct i2c_client *)cli; struct i2c_client *client = cli;
/* Trigger conversion */ /* Trigger conversion */
ret = i2c_smbus_write_byte(client, conv); ret = i2c_smbus_write_byte(client, conv);
......
...@@ -212,7 +212,7 @@ static struct attribute *ad5504_ev_attributes[] = { ...@@ -212,7 +212,7 @@ static struct attribute *ad5504_ev_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group ad5504_ev_attribute_group = { static const struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes, .attrs = ad5504_ev_attributes,
}; };
...@@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) ...@@ -223,7 +223,7 @@ static irqreturn_t ad5504_event_handler(int irq, void *private)
0, 0,
IIO_EV_TYPE_THRESH, IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING), IIO_EV_DIR_RISING),
iio_get_time_ns((struct iio_dev *)private)); iio_get_time_ns(private));
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -36,6 +36,20 @@ config HDC100X ...@@ -36,6 +36,20 @@ config HDC100X
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called hdc100x. 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 config HTS221
tristate "STMicroelectronics HTS221 sensor Driver" tristate "STMicroelectronics HTS221 sensor Driver"
depends on (I2C || SPI) depends on (I2C || SPI)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-$(CONFIG_AM2315) += am2315.o obj-$(CONFIG_AM2315) += am2315.o
obj-$(CONFIG_DHT11) += dht11.o obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o obj-$(CONFIG_HDC100X) += hdc100x.o
obj-$(CONFIG_HID_SENSOR_HUMIDITY) += hid-sensor-humidity.o
hts221-y := hts221_core.o \ hts221-y := hts221_core.o \
hts221_buffer.o hts221_buffer.o
...@@ -15,3 +16,5 @@ obj-$(CONFIG_HTS221_SPI) += hts221_spi.o ...@@ -15,3 +16,5 @@ obj-$(CONFIG_HTS221_SPI) += hts221_spi.o
obj-$(CONFIG_HTU21) += htu21.o obj-$(CONFIG_HTU21) += htu21.o
obj-$(CONFIG_SI7005) += si7005.o obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o obj-$(CONFIG_SI7020) += si7020.o
ccflags-y += -I$(srctree)/drivers/iio/common/hid-sensors
...@@ -79,7 +79,7 @@ static struct attribute *hdc100x_attributes[] = { ...@@ -79,7 +79,7 @@ static struct attribute *hdc100x_attributes[] = {
NULL NULL
}; };
static struct attribute_group hdc100x_attribute_group = { static const struct attribute_group hdc100x_attribute_group = {
.attrs = hdc100x_attributes, .attrs = hdc100x_attributes,
}; };
......
/*
* 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 = { ...@@ -41,7 +41,7 @@ static const struct iio_trigger_ops hts221_trigger_ops = {
static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) 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; u8 status;
int err; int err;
......
...@@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = { ...@@ -113,6 +113,12 @@ static const struct inv_mpu6050_hw hw_info[] = {
.reg = &reg_set_6050, .reg = &reg_set_6050,
.config = &chip_config_6050, .config = &chip_config_6050,
}, },
{
.whoami = INV_MPU9250_WHOAMI_VALUE,
.name = "MPU9250",
.reg = &reg_set_6500,
.config = &chip_config_6050,
},
{ {
.whoami = INV_ICM20608_WHOAMI_VALUE, .whoami = INV_ICM20608_WHOAMI_VALUE,
.name = "ICM20608", .name = "ICM20608",
......
...@@ -178,6 +178,7 @@ static const struct i2c_device_id inv_mpu_id[] = { ...@@ -178,6 +178,7 @@ static const struct i2c_device_id inv_mpu_id[] = {
{"mpu6050", INV_MPU6050}, {"mpu6050", INV_MPU6050},
{"mpu6500", INV_MPU6500}, {"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150}, {"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"icm20608", INV_ICM20608}, {"icm20608", INV_ICM20608},
{} {}
}; };
...@@ -197,6 +198,10 @@ static const struct of_device_id inv_of_match[] = { ...@@ -197,6 +198,10 @@ static const struct of_device_id inv_of_match[] = {
.compatible = "invensense,mpu9150", .compatible = "invensense,mpu9150",
.data = (void *)INV_MPU9150 .data = (void *)INV_MPU9150
}, },
{
.compatible = "invensense,mpu9250",
.data = (void *)INV_MPU9250
},
{ {
.compatible = "invensense,icm20608", .compatible = "invensense,icm20608",
.data = (void *)INV_ICM20608 .data = (void *)INV_ICM20608
......
...@@ -70,6 +70,7 @@ enum inv_devices { ...@@ -70,6 +70,7 @@ enum inv_devices {
INV_MPU6500, INV_MPU6500,
INV_MPU6000, INV_MPU6000,
INV_MPU9150, INV_MPU9150,
INV_MPU9250,
INV_ICM20608, INV_ICM20608,
INV_NUM_PARTS INV_NUM_PARTS
}; };
...@@ -226,6 +227,7 @@ struct inv_mpu6050_state { ...@@ -226,6 +227,7 @@ struct inv_mpu6050_state {
#define INV_MPU6050_WHOAMI_VALUE 0x68 #define INV_MPU6050_WHOAMI_VALUE 0x68
#define INV_MPU6500_WHOAMI_VALUE 0x70 #define INV_MPU6500_WHOAMI_VALUE 0x70
#define INV_MPU9150_WHOAMI_VALUE 0x68 #define INV_MPU9150_WHOAMI_VALUE 0x68
#define INV_MPU9250_WHOAMI_VALUE 0x71
#define INV_ICM20608_WHOAMI_VALUE 0xAF #define INV_ICM20608_WHOAMI_VALUE 0xAF
/* scan element definition */ /* scan element definition */
......
...@@ -82,6 +82,7 @@ static const struct spi_device_id inv_mpu_id[] = { ...@@ -82,6 +82,7 @@ static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000}, {"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500}, {"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150}, {"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"icm20608", INV_ICM20608}, {"icm20608", INV_ICM20608},
{} {}
}; };
......
...@@ -364,7 +364,7 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable) ...@@ -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) 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; struct st_lsm6dsx_sensor *sensor;
int i; int i;
...@@ -388,7 +388,7 @@ static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) ...@@ -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) 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; int count;
mutex_lock(&hw->fifo_lock); mutex_lock(&hw->fifo_lock);
......
...@@ -308,32 +308,40 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, ...@@ -308,32 +308,40 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
return 0; 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;
int i, err;
u8 val;
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; 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; break;
if (i == ST_LSM6DSX_ODR_LIST_SIZE) if (i == ST_LSM6DSX_ODR_LIST_SIZE)
return -EINVAL; return -EINVAL;
val = st_lsm6dsx_odr_table[id].odr_avl[i].val; *val = st_lsm6dsx_odr_table[sensor->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;
sensor->odr = odr; sensor->odr = odr;
return 0; 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 st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
{ {
int err; int err;
...@@ -436,9 +444,12 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, ...@@ -436,9 +444,12 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
err = st_lsm6dsx_set_full_scale(sensor, val2); err = st_lsm6dsx_set_full_scale(sensor, val2);
break; break;
case IIO_CHAN_INFO_SAMP_FREQ: case IIO_CHAN_INFO_SAMP_FREQ: {
err = st_lsm6dsx_set_odr(sensor, val); u8 data;
err = st_lsm6dsx_check_odr(sensor, val, &data);
break; break;
}
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
......
...@@ -405,4 +405,14 @@ config VEML6070 ...@@ -405,4 +405,14 @@ config VEML6070
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called veml6070. 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 endmenu
...@@ -38,3 +38,4 @@ obj-$(CONFIG_TSL4531) += tsl4531.o ...@@ -38,3 +38,4 @@ obj-$(CONFIG_TSL4531) += tsl4531.o
obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VEML6070) += veml6070.o obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VL6180) += vl6180.o
...@@ -343,7 +343,7 @@ static struct attribute *apds9960_attributes[] = { ...@@ -343,7 +343,7 @@ static struct attribute *apds9960_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group apds9960_attribute_group = { static const struct attribute_group apds9960_attribute_group = {
.attrs = apds9960_attributes, .attrs = apds9960_attributes,
}; };
......
...@@ -212,7 +212,7 @@ static struct attribute *bh1750_attributes[] = { ...@@ -212,7 +212,7 @@ static struct attribute *bh1750_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group bh1750_attribute_group = { static const struct attribute_group bh1750_attribute_group = {
.attrs = bh1750_attributes, .attrs = bh1750_attributes,
}; };
......
...@@ -690,7 +690,7 @@ static struct attribute *lm3533_als_event_attributes[] = { ...@@ -690,7 +690,7 @@ static struct attribute *lm3533_als_event_attributes[] = {
NULL 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 .attrs = lm3533_als_event_attributes
}; };
...@@ -714,7 +714,7 @@ static struct attribute *lm3533_als_attributes[] = { ...@@ -714,7 +714,7 @@ static struct attribute *lm3533_als_attributes[] = {
NULL NULL
}; };
static struct attribute_group lm3533_als_attribute_group = { static const struct attribute_group lm3533_als_attribute_group = {
.attrs = lm3533_als_attributes .attrs = lm3533_als_attributes
}; };
......
/*
* 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) ...@@ -751,7 +751,7 @@ static void zpa2326_suspend(struct iio_dev *indio_dev)
*/ */
static irqreturn_t zpa2326_handle_irq(int irq, void *data) 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)) { if (iio_buffer_enabled(indio_dev)) {
/* Timestamping needed for buffered sampling only. */ /* Timestamping needed for buffered sampling only. */
...@@ -790,7 +790,7 @@ static irqreturn_t zpa2326_handle_irq(int irq, void *data) ...@@ -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) 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); struct zpa2326_private *priv = iio_priv(indio_dev);
unsigned int val; unsigned int val;
bool cont; bool cont;
......
...@@ -155,7 +155,7 @@ static struct attribute *as3935_attributes[] = { ...@@ -155,7 +155,7 @@ static struct attribute *as3935_attributes[] = {
NULL, NULL,
}; };
static struct attribute_group as3935_attribute_group = { static const struct attribute_group as3935_attribute_group = {
.attrs = as3935_attributes, .attrs = as3935_attributes,
}; };
......
...@@ -203,17 +203,14 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, ...@@ -203,17 +203,14 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
bits = 14; bits = 14;
mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->scan_index]; addr = adis16203_addresses[chan->scan_index];
ret = adis_read_reg_16(st, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret) {
mutex_unlock(&indio_dev->mlock);
return ret; return ret;
} }
val16 &= (1 << bits) - 1; val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16; *val = val16;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT; return IIO_VAL_INT;
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -255,9 +255,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -255,9 +255,8 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
} }
addr = adis16209_addresses[chan->scan_index][0]; addr = adis16209_addresses[chan->scan_index][0];
ret = adis_read_reg_16(st, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret)
return ret; return ret;
}
val16 &= (1 << bits) - 1; val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16; *val = val16;
......
...@@ -290,9 +290,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -290,9 +290,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
bits = 10; bits = 10;
addr = adis16240_addresses[chan->scan_index][0]; addr = adis16240_addresses[chan->scan_index][0];
ret = adis_read_reg_16(st, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret)
return ret; return ret;
}
val16 &= (1 << bits) - 1; val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16; *val = val16;
...@@ -301,9 +300,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -301,9 +300,8 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
bits = 10; bits = 10;
addr = adis16240_addresses[chan->scan_index][1]; addr = adis16240_addresses[chan->scan_index][1];
ret = adis_read_reg_16(st, addr, &val16); ret = adis_read_reg_16(st, addr, &val16);
if (ret) { if (ret)
return ret; return ret;
}
val16 &= (1 << bits) - 1; val16 &= (1 << bits) - 1;
val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
*val = val16; *val = val16;
......
...@@ -560,7 +560,7 @@ static int ad7280_attr_init(struct ad7280_state *st) ...@@ -560,7 +560,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
st->iio_attr[cnt].address = st->iio_attr[cnt].address =
AD7280A_DEVADDR(dev) << 8 | ch; AD7280A_DEVADDR(dev) << 8 | ch;
st->iio_attr[cnt].dev_attr.attr.mode = st->iio_attr[cnt].dev_attr.attr.mode =
S_IWUSR | S_IRUGO; 0644;
st->iio_attr[cnt].dev_attr.show = st->iio_attr[cnt].dev_attr.show =
ad7280_show_balance_sw; ad7280_show_balance_sw;
st->iio_attr[cnt].dev_attr.store = st->iio_attr[cnt].dev_attr.store =
...@@ -577,7 +577,7 @@ static int ad7280_attr_init(struct ad7280_state *st) ...@@ -577,7 +577,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
AD7280A_DEVADDR(dev) << 8 | AD7280A_DEVADDR(dev) << 8 |
(AD7280A_CB1_TIMER + ch); (AD7280A_CB1_TIMER + ch);
st->iio_attr[cnt].dev_attr.attr.mode = st->iio_attr[cnt].dev_attr.attr.mode =
S_IWUSR | S_IRUGO; 0644;
st->iio_attr[cnt].dev_attr.show = st->iio_attr[cnt].dev_attr.show =
ad7280_show_balance_timer; ad7280_show_balance_timer;
st->iio_attr[cnt].dev_attr.store = st->iio_attr[cnt].dev_attr.store =
...@@ -746,26 +746,26 @@ static irqreturn_t ad7280_event_handler(int irq, void *private) ...@@ -746,26 +746,26 @@ static irqreturn_t ad7280_event_handler(int irq, void *private)
static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value, static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value,
in_voltage-voltage_thresh_low_value, in_voltage-voltage_thresh_low_value,
S_IRUGO | S_IWUSR, 0644,
ad7280_read_channel_config, ad7280_read_channel_config,
ad7280_write_channel_config, ad7280_write_channel_config,
AD7280A_CELL_UNDERVOLTAGE); AD7280A_CELL_UNDERVOLTAGE);
static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value, static IIO_DEVICE_ATTR_NAMED(in_thresh_high_value,
in_voltage-voltage_thresh_high_value, in_voltage-voltage_thresh_high_value,
S_IRUGO | S_IWUSR, 0644,
ad7280_read_channel_config, ad7280_read_channel_config,
ad7280_write_channel_config, ad7280_write_channel_config,
AD7280A_CELL_OVERVOLTAGE); AD7280A_CELL_OVERVOLTAGE);
static IIO_DEVICE_ATTR(in_temp_thresh_low_value, static IIO_DEVICE_ATTR(in_temp_thresh_low_value,
S_IRUGO | S_IWUSR, 0644,
ad7280_read_channel_config, ad7280_read_channel_config,
ad7280_write_channel_config, ad7280_write_channel_config,
AD7280A_AUX_ADC_UNDERVOLTAGE); AD7280A_AUX_ADC_UNDERVOLTAGE);
static IIO_DEVICE_ATTR(in_temp_thresh_high_value, static IIO_DEVICE_ATTR(in_temp_thresh_high_value,
S_IRUGO | S_IWUSR, 0644,
ad7280_read_channel_config, ad7280_read_channel_config,
ad7280_write_channel_config, ad7280_write_channel_config,
AD7280A_AUX_ADC_OVERVOLTAGE); AD7280A_AUX_ADC_OVERVOLTAGE);
......
...@@ -208,7 +208,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ...@@ -208,7 +208,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
ret = -EINVAL; ret = -EINVAL;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(scale_avail); i++) for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
if (val2 == scale_avail[i][1]) { if (val2 == scale_avail[i][1]) {
gpiod_set_value(st->gpio_range, i); gpiod_set_value(st->gpio_range, i);
...@@ -217,7 +217,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ...@@ -217,7 +217,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
ret = 0; ret = 0;
break; break;
} }
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return ret; return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO: case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
...@@ -231,11 +231,11 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, ...@@ -231,11 +231,11 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
values[1] = (ret >> 1) & 1; values[1] = (ret >> 1) & 1;
values[2] = (ret >> 2) & 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, gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc,
values); values);
st->oversampling = val; st->oversampling = val;
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->lock);
return 0; return 0;
default: default:
...@@ -413,6 +413,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, ...@@ -413,6 +413,7 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
st->dev = dev; st->dev = dev;
mutex_init(&st->lock);
st->bops = bops; st->bops = bops;
st->base_address = base_address; st->base_address = base_address;
/* tied to logic low, analog input range is +/- 5V */ /* tied to logic low, analog input range is +/- 5V */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
* @name: identification string for chip * @name: identification string for chip
* @channels: channel specification * @channels: channel specification
* @num_channels: number of channels * @num_channels: number of channels
* @lock protect sensor state
*/ */
struct ad7606_chip_info { struct ad7606_chip_info {
...@@ -23,6 +24,7 @@ struct ad7606_chip_info { ...@@ -23,6 +24,7 @@ struct ad7606_chip_info {
/** /**
* struct ad7606_state - driver instance specific data * struct ad7606_state - driver instance specific data
* @lock protect sensor state
*/ */
struct ad7606_state { struct ad7606_state {
...@@ -37,6 +39,7 @@ struct ad7606_state { ...@@ -37,6 +39,7 @@ struct ad7606_state {
bool done; bool done;
void __iomem *base_address; void __iomem *base_address;
struct mutex lock; /* protect sensor state */
struct gpio_desc *gpio_convst; struct gpio_desc *gpio_convst;
struct gpio_desc *gpio_reset; struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_range; struct gpio_desc *gpio_range;
......
...@@ -244,7 +244,6 @@ static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip, ...@@ -244,7 +244,6 @@ static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
chip->config1 = config1; chip->config1 = config1;
return ret; return ret;
} }
static ssize_t adt7316_store_enabled(struct device *dev, static ssize_t adt7316_store_enabled(struct device *dev,
...@@ -434,7 +433,6 @@ static ssize_t adt7316_store_ad_channel(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 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK);
} }
config2 |= data; config2 |= data;
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2); ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
...@@ -725,7 +723,6 @@ static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644, ...@@ -725,7 +723,6 @@ static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644,
adt7316_store_AIN_internal_Vref, adt7316_store_AIN_internal_Vref,
0); 0);
static ssize_t adt7316_show_enable_prop_DACA(struct device *dev, static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
...@@ -925,7 +922,6 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev, ...@@ -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, static IIO_DEVICE_ATTR(all_DAC_update_modes, 0444,
adt7316_show_all_DAC_update_modes, NULL, 0); adt7316_show_all_DAC_update_modes, NULL, 0);
static ssize_t adt7316_store_update_DAC(struct device *dev, static ssize_t adt7316_store_update_DAC(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, const char *buf,
...@@ -1867,6 +1863,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev, ...@@ -1867,6 +1863,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev,
return len; return len;
} }
static inline ssize_t adt7316_show_ad_bound(struct device *dev, static inline ssize_t adt7316_show_ad_bound(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
......
...@@ -232,7 +232,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev, ...@@ -232,7 +232,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
if (ret < 0) if (ret < 0)
goto error_ret; goto error_ret;
cfg = ret & ~((0x03 << 5) | (0x1 << 7)); cfg = ret & ~((0x03 << 5) | BIT(7));
switch (type) { switch (type) {
case IIO_EV_TYPE_MAG_ADAPTIVE: case IIO_EV_TYPE_MAG_ADAPTIVE:
......
...@@ -244,6 +244,7 @@ static int ad7152_write_raw_samp_freq(struct device *dev, int val) ...@@ -244,6 +244,7 @@ static int ad7152_write_raw_samp_freq(struct device *dev, int val)
return ret; return ret;
} }
static int ad7152_write_raw(struct iio_dev *indio_dev, static int ad7152_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, struct iio_chan_spec const *chan,
int val, int val,
......
...@@ -45,10 +45,10 @@ ...@@ -45,10 +45,10 @@
#define AD7746_STATUS_RDYCAP BIT(0) #define AD7746_STATUS_RDYCAP BIT(0)
/* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */ /* Capacitive Channel Setup Register Bit Designations (AD7746_REG_CAP_SETUP) */
#define AD7746_CAPSETUP_CAPEN (1 << 7) #define AD7746_CAPSETUP_CAPEN BIT(7)
#define AD7746_CAPSETUP_CIN2 (1 << 6) /* AD7746 only */ #define AD7746_CAPSETUP_CIN2 BIT(6) /* AD7746 only */
#define AD7746_CAPSETUP_CAPDIFF (1 << 5) #define AD7746_CAPSETUP_CAPDIFF BIT(5)
#define AD7746_CAPSETUP_CACHOP (1 << 0) #define AD7746_CAPSETUP_CACHOP BIT(0)
/* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */ /* Voltage/Temperature Setup Register Bit Designations (AD7746_REG_VT_SETUP) */
#define AD7746_VTSETUP_VTEN (1 << 7) #define AD7746_VTSETUP_VTEN (1 << 7)
...@@ -56,9 +56,9 @@ ...@@ -56,9 +56,9 @@
#define AD7746_VTSETUP_VTMD_EXT_TEMP (1 << 5) #define AD7746_VTSETUP_VTMD_EXT_TEMP (1 << 5)
#define AD7746_VTSETUP_VTMD_VDD_MON (2 << 5) #define AD7746_VTSETUP_VTMD_VDD_MON (2 << 5)
#define AD7746_VTSETUP_VTMD_EXT_VIN (3 << 5) #define AD7746_VTSETUP_VTMD_EXT_VIN (3 << 5)
#define AD7746_VTSETUP_EXTREF (1 << 4) #define AD7746_VTSETUP_EXTREF BIT(4)
#define AD7746_VTSETUP_VTSHORT (1 << 1) #define AD7746_VTSETUP_VTSHORT BIT(1)
#define AD7746_VTSETUP_VTCHOP (1 << 0) #define AD7746_VTSETUP_VTCHOP BIT(0)
/* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */ /* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
#define AD7746_EXCSETUP_CLKCTRL BIT(7) #define AD7746_EXCSETUP_CLKCTRL BIT(7)
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
#define AD7746_CONF_MODE_GAIN_CAL (6 << 0) #define AD7746_CONF_MODE_GAIN_CAL (6 << 0)
/* CAPDAC Register Bit Designations (AD7746_REG_CAPDACx) */ /* 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) #define AD7746_CAPDAC_DACP(x) ((x) & 0x7F)
/* /*
......
...@@ -250,22 +250,22 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr, ...@@ -250,22 +250,22 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr,
* see dds.h for further information * 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, 0, 0200, NULL, ad9832_write, AD9832_FREQ0HM);
static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM); static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9832_write, AD9832_FREQ1HM);
static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM); static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9832_write, AD9832_FREQ_SYM);
static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ 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, 0, 0200, 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, 1, 0200, 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, 2, 0200, NULL, ad9832_write, AD9832_PHASE2H);
static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H); static IIO_DEV_ATTR_PHASE(0, 3, 0200, NULL, ad9832_write, AD9832_PHASE3H);
static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL,
ad9832_write, AD9832_PHASE_SYM); ad9832_write, AD9832_PHASE_SYM);
static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ 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); 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); ad9832_write, AD9832_OUTPUT_EN);
static struct attribute *ad9832_attributes[] = { static struct attribute *ad9832_attributes[] = {
......
...@@ -40,25 +40,20 @@ struct adis16060_state { ...@@ -40,25 +40,20 @@ struct adis16060_state {
static struct iio_dev *adis16060_iio_dev; 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; int ret;
struct adis16060_state *st = iio_priv(indio_dev); struct adis16060_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock); 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); ret = spi_write(st->us_w, st->buf, 3);
mutex_unlock(&st->buf_lock);
if (ret < 0) {
mutex_unlock(&st->buf_lock);
return ret; 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);
ret = spi_read(st->us_r, st->buf, 3); ret = spi_read(st->us_r, st->buf, 3);
...@@ -86,17 +81,11 @@ static int adis16060_read_raw(struct iio_dev *indio_dev, ...@@ -86,17 +81,11 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */ ret = adis16060_spi_write_then_read(indio_dev,
mutex_lock(&indio_dev->mlock); chan->address, &tval);
ret = adis16060_spi_write(indio_dev, chan->address);
if (ret < 0)
goto out_unlock;
ret = adis16060_spi_read(indio_dev, &tval);
if (ret < 0) if (ret < 0)
goto out_unlock; return ret;
mutex_unlock(&indio_dev->mlock);
*val = tval; *val = tval;
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
...@@ -110,10 +99,6 @@ static int adis16060_read_raw(struct iio_dev *indio_dev, ...@@ -110,10 +99,6 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
} }
return -EINVAL; return -EINVAL;
out_unlock:
mutex_unlock(&indio_dev->mlock);
return ret;
} }
static const struct iio_info adis16060_info = { static const struct iio_info adis16060_info = {
......
...@@ -854,7 +854,7 @@ void tsl2x7x_prox_calculate(int *data, int length, ...@@ -854,7 +854,7 @@ void tsl2x7x_prox_calculate(int *data, int length,
tmp = data[i] - statP->mean; tmp = data[i] - statP->mean;
sample_sum += tmp * tmp; 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[] = { ...@@ -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] = { [ALS] = {
.attrs = tsl2X7X_ALS_event_attrs, .attrs = tsl2X7X_ALS_event_attrs,
.name = "events", .name = "events",
......
...@@ -6,18 +6,17 @@ ...@@ -6,18 +6,17 @@
* Licensed under the GPL-2 or later. * Licensed under the GPL-2 or later.
*/ */
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include "meter.h" #include "meter.h"
...@@ -97,7 +96,7 @@ ...@@ -97,7 +96,7 @@
/** /**
* struct ade7754_state - device instance specific data * struct ade7754_state - device instance specific data
* @us: actual spi_device * @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 * @tx: transmit buffer
* @rx: receive buffer * @rx: receive buffer
**/ **/
...@@ -108,17 +107,25 @@ struct ade7754_state { ...@@ -108,17 +107,25 @@ struct ade7754_state {
u8 rx[ADE7754_MAX_RX]; u8 rx[ADE7754_MAX_RX];
}; };
static int ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val) /* Unlocked version of ade7754_spi_write_reg_8 function */
static int __ade7754_spi_write_reg_8(struct device *dev, u8 reg_address, u8 val)
{ {
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev); struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7754_WRITE_REG(reg_address); st->tx[0] = ADE7754_WRITE_REG(reg_address);
st->tx[1] = val; 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;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
ret = spi_write(st->us, st->tx, 2); mutex_lock(&st->buf_lock);
ret = __ade7754_spi_write_reg_8(dev, reg_address, val);
mutex_unlock(&st->buf_lock); mutex_unlock(&st->buf_lock);
return ret; return ret;
...@@ -513,7 +520,7 @@ static ssize_t ade7754_write_frequency(struct device *dev, ...@@ -513,7 +520,7 @@ static ssize_t ade7754_write_frequency(struct device *dev,
if (!val) if (!val)
return -EINVAL; return -EINVAL;
mutex_lock(&indio_dev->mlock); mutex_lock(&st->buf_lock);
t = 26000 / val; t = 26000 / val;
if (t > 0) if (t > 0)
...@@ -531,10 +538,10 @@ static ssize_t ade7754_write_frequency(struct device *dev, ...@@ -531,10 +538,10 @@ static ssize_t ade7754_write_frequency(struct device *dev,
reg &= ~(3 << 3); reg &= ~(3 << 3);
reg |= t << 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: out:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&st->buf_lock);
return ret ? ret : len; return ret ? ret : len;
} }
......
...@@ -49,6 +49,10 @@ ...@@ -49,6 +49,10 @@
#define HID_USAGE_SENSOR_TEMPERATURE 0x200033 #define HID_USAGE_SENSOR_TEMPERATURE 0x200033
#define HID_USAGE_SENSOR_DATA_ENVIRONMENTAL_TEMPERATURE 0x200434 #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) */ /* Gyro 3D: (200076) */
#define HID_USAGE_SENSOR_GYRO_3D 0x200076 #define HID_USAGE_SENSOR_GYRO_3D 0x200076
#define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456 #define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment