From 9a043b0bf286e189ab49410c66170c86d59563c5 Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Fri, 21 Apr 2017 22:58:36 +0200 Subject: iio: pressure: Fix name of BME280 part in Kconfig Bosch BME280 is a combined pressure and humidity sensor Signed-off-by: Peter Meerwald-Stadler Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 5d16b252ab6b..eaa7cfcb4c2a 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -23,7 +23,7 @@ config BMP280 select BMP280_SPI if (SPI_MASTER) help Say yes here to build support for Bosch Sensortec BMP180 and BMP280 - pressure and temperature sensors. Also supports the BE280 with + pressure and temperature sensors. Also supports the BME280 with an additional humidity sensor channel. To compile this driver as a module, choose M here: the core module -- cgit v1.2.3 From c773f70015f6f07f4abe93b486da7f53fde6e878 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Thu, 20 Apr 2017 23:01:57 +0200 Subject: iio: inkern: fix a static checker error Avoid this smatch error: drivers/iio/inkern.c:751 iio_read_avail_channel_raw() error: double unlock 'mutex:&chan->indio_dev->info_exist_lock' Fixes: 00c5f80c2fad ("iio: inkern: add helpers to query available values from channels") Signed-off-by: Peter Rosin Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 7a13535dc3e9..a3941bade6a7 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan, err_unlock: mutex_unlock(&chan->indio_dev->info_exist_lock); - if (ret >= 0 && type != IIO_VAL_INT) { + if (ret >= 0 && type != IIO_VAL_INT) /* raw values are assumed to be IIO_VAL_INT */ ret = -EINVAL; - goto err_unlock; - } return ret; } -- cgit v1.2.3 From d6d0014c6b1989f9571eb06c1641de9946c3c980 Mon Sep 17 00:00:00 2001 From: Paolo Cretaro Date: Tue, 25 Apr 2017 15:00:50 +0200 Subject: staging: iio: tsl2x7x: Replace deprecated macros (S_IRUGO, S_IWUSR) Use octal digits as suggested by checkpatch instead of deprecated macros. Signed-off-by: Paolo Cretaro Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2x7x_core.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index af3910bc1b4f..8121a5188638 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -1498,34 +1498,34 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, return 0; } -static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(power_state, 0644, tsl2x7x_power_state_show, tsl2x7x_power_state_store); -static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO, +static DEVICE_ATTR(in_proximity0_calibscale_available, 0444, tsl2x7x_prox_gain_available_show, NULL); -static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO, +static DEVICE_ATTR(in_illuminance0_calibscale_available, 0444, tsl2x7x_gain_available_show, NULL); -static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(in_illuminance0_integration_time, 0644, tsl2x7x_als_time_show, tsl2x7x_als_time_store); -static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(in_illuminance0_target_input, 0644, tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); -static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL, +static DEVICE_ATTR(in_illuminance0_calibrate, 0200, NULL, tsl2x7x_do_calibrate); -static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL, +static DEVICE_ATTR(in_proximity0_calibrate, 0200, NULL, tsl2x7x_do_prox_calibrate); -static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(in_illuminance0_lux_table, 0644, tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); -static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(in_intensity0_thresh_period, 0644, tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); -static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(in_proximity0_thresh_period, 0644, tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store); /* Use the default register values to identify the Taos device */ -- cgit v1.2.3 From e4ff6c1b41d66e929e18a9afaa7d7d5788ff3da8 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 24 Apr 2017 21:34:33 -0400 Subject: staging: iio: isl29028: correct proximity sleep times The sysfs attribute in_proximity_sampling_frequency_available currently shows the values 1 3 5 10 13 20 83 100. These values are supposed to correspond to the sleep values 800 400 200 100 75 50 12.5 0 (all in ms). When passing in a sampling frequency of 3, it actually uses a sleep time of 200ms instead of the expected 400ms value. This patch changes the value shown by this sysfs attribute to use fixed-point numbers so that the correct sampling frequency is shown to the user. This patch also changes the code that updates the proximity sampling frequency to only allow values that are shown in the _available sysfs attribute. The original code showed the value 83 that corresponds to the sleep time 12 ms. The data sheet actually lists 12.5 ms as the sleep time, so the proximity frequency was updated to 80. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29028.c | 70 +++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c index 5375e7a81205..aeb50825acef 100644 --- a/drivers/staging/iio/light/isl29028.c +++ b/drivers/staging/iio/light/isl29028.c @@ -64,8 +64,25 @@ #define ISL29028_POWER_OFF_DELAY_MS 2000 -static const unsigned int isl29028_prox_sleep_time[] = {800, 400, 200, 100, 75, - 50, 12, 0}; +struct isl29028_prox_data { + int sampling_int; + int sampling_fract; + int sleep_time; +}; + +static const struct isl29028_prox_data isl29028_prox_data[] = { + { 1, 250000, 800 }, + { 2, 500000, 400 }, + { 5, 0, 200 }, + { 10, 0, 100 }, + { 13, 300000, 75 }, + { 20, 0, 50 }, + { 80, 0, 13 }, /* + * Note: Data sheet lists 12.5 ms sleep time. + * Round up a half millisecond for msleep(). + */ + { 100, 0, 0 } +}; enum isl29028_als_ir_mode { ISL29028_MODE_NONE = 0, @@ -76,32 +93,37 @@ enum isl29028_als_ir_mode { struct isl29028_chip { struct mutex lock; struct regmap *regmap; - unsigned int prox_sampling; + int prox_sampling_int; + int prox_sampling_frac; bool enable_prox; int lux_scale; enum isl29028_als_ir_mode als_ir_mode; }; -static int isl29028_find_prox_sleep_time_index(int sampling) +static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract) { - unsigned int period = DIV_ROUND_UP(1000, sampling); int i; - for (i = 0; i < ARRAY_SIZE(isl29028_prox_sleep_time); ++i) { - if (period >= isl29028_prox_sleep_time[i]) - break; + for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) { + if (isl29028_prox_data[i].sampling_int == sampling_int && + isl29028_prox_data[i].sampling_fract == sampling_fract) + return i; } - return i; + return -EINVAL; } static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, - unsigned int sampling) + int sampling_int, int sampling_fract) { struct device *dev = regmap_get_device(chip->regmap); int sleep_index, ret; - sleep_index = isl29028_find_prox_sleep_time_index(sampling); + sleep_index = isl29028_find_prox_sleep_index(sampling_int, + sampling_fract); + if (sleep_index < 0) + return sleep_index; + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, ISL29028_CONF_PROX_SLP_MASK, sleep_index << ISL29028_CONF_PROX_SLP_SH); @@ -112,16 +134,18 @@ static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, return ret; } - chip->prox_sampling = sampling; + chip->prox_sampling_int = sampling_int; + chip->prox_sampling_frac = sampling_fract; return ret; } static int isl29028_enable_proximity(struct isl29028_chip *chip) { - int sleep_index, ret; + int prox_index, ret; - ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling); + ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int, + chip->prox_sampling_frac); if (ret < 0) return ret; @@ -132,8 +156,12 @@ static int isl29028_enable_proximity(struct isl29028_chip *chip) return ret; /* Wait for conversion to be complete for first sample */ - sleep_index = isl29028_find_prox_sleep_time_index(chip->prox_sampling); - msleep(isl29028_prox_sleep_time[sleep_index]); + prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int, + chip->prox_sampling_frac); + if (prox_index < 0) + return prox_index; + + msleep(isl29028_prox_data[prox_index].sleep_time); return 0; } @@ -361,7 +389,7 @@ static int isl29028_write_raw(struct iio_dev *indio_dev, break; } - ret = isl29028_set_proxim_sampling(chip, val); + ret = isl29028_set_proxim_sampling(chip, val, val2); break; case IIO_LIGHT: if (mask != IIO_CHAN_INFO_SCALE) { @@ -439,7 +467,8 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, if (chan->type != IIO_PROXIMITY) break; - *val = chip->prox_sampling; + *val = chip->prox_sampling_int; + *val2 = chip->prox_sampling_frac; ret = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: @@ -472,7 +501,7 @@ static int isl29028_read_raw(struct iio_dev *indio_dev, } static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, - "1 3 5 10 13 20 83 100"); + "1.25 2.5 5 10 13.3 20 80 100"); static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000"); #define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) @@ -571,7 +600,8 @@ static int isl29028_probe(struct i2c_client *client, } chip->enable_prox = false; - chip->prox_sampling = 20; + chip->prox_sampling_int = 20; + chip->prox_sampling_frac = 0; chip->lux_scale = 2000; ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0); -- cgit v1.2.3 From 105c3de1eb414d17e7b9db116f076026d2767ef6 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Mon, 24 Apr 2017 21:34:34 -0400 Subject: staging: iio: isl29028: move out of staging Move ISL29028 ALS / Proximity Sensor out of staging and into mainline. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 + drivers/iio/light/Makefile | 1 + drivers/iio/light/isl29028.c | 723 +++++++++++++++++++++++++++++++++++ drivers/staging/iio/light/Kconfig | 10 - drivers/staging/iio/light/Makefile | 1 - drivers/staging/iio/light/isl29028.c | 723 ----------------------------------- 6 files changed, 734 insertions(+), 734 deletions(-) create mode 100644 drivers/iio/light/isl29028.c delete mode 100644 drivers/staging/iio/light/isl29028.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 33e755d8d825..2356ed9285df 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -172,6 +172,16 @@ config SENSORS_ISL29018 in lux, proximity infrared sensing and normal infrared sensing. Data from sensor is accessible via sysfs. +config SENSORS_ISL29028 + tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" + depends on I2C + select REGMAP_I2C + help + Provides driver for the Intersil's ISL29028 device. + This driver supports the sysfs interface to get the ALS, IR intensity, + Proximity value via iio. The ISL29028 provides the concurrent sensing + of ambient light and proximity. + config ISL29125 tristate "Intersil ISL29125 digital color light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 681363c2b298..fa32fa459e2e 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o +obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c new file mode 100644 index 000000000000..aeb50825acef --- /dev/null +++ b/drivers/iio/light/isl29028.c @@ -0,0 +1,723 @@ +/* + * IIO driver for the light sensor ISL29028. + * ISL29028 is Concurrent Ambient Light and Proximity Sensor + * + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2017 Brian Masney + * + * 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. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ISL29028_CONV_TIME_MS 100 + +#define ISL29028_REG_CONFIGURE 0x01 + +#define ISL29028_CONF_ALS_IR_MODE_ALS 0 +#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0) +#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0) + +#define ISL29028_CONF_ALS_RANGE_LOW_LUX 0 +#define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1) +#define ISL29028_CONF_ALS_RANGE_MASK BIT(1) + +#define ISL29028_CONF_ALS_DIS 0 +#define ISL29028_CONF_ALS_EN BIT(2) +#define ISL29028_CONF_ALS_EN_MASK BIT(2) + +#define ISL29028_CONF_PROX_SLP_SH 4 +#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH) + +#define ISL29028_CONF_PROX_EN BIT(7) +#define ISL29028_CONF_PROX_EN_MASK BIT(7) + +#define ISL29028_REG_INTERRUPT 0x02 + +#define ISL29028_REG_PROX_DATA 0x08 +#define ISL29028_REG_ALSIR_L 0x09 +#define ISL29028_REG_ALSIR_U 0x0A + +#define ISL29028_REG_TEST1_MODE 0x0E +#define ISL29028_REG_TEST2_MODE 0x0F + +#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1) + +#define ISL29028_POWER_OFF_DELAY_MS 2000 + +struct isl29028_prox_data { + int sampling_int; + int sampling_fract; + int sleep_time; +}; + +static const struct isl29028_prox_data isl29028_prox_data[] = { + { 1, 250000, 800 }, + { 2, 500000, 400 }, + { 5, 0, 200 }, + { 10, 0, 100 }, + { 13, 300000, 75 }, + { 20, 0, 50 }, + { 80, 0, 13 }, /* + * Note: Data sheet lists 12.5 ms sleep time. + * Round up a half millisecond for msleep(). + */ + { 100, 0, 0 } +}; + +enum isl29028_als_ir_mode { + ISL29028_MODE_NONE = 0, + ISL29028_MODE_ALS, + ISL29028_MODE_IR, +}; + +struct isl29028_chip { + struct mutex lock; + struct regmap *regmap; + int prox_sampling_int; + int prox_sampling_frac; + bool enable_prox; + int lux_scale; + enum isl29028_als_ir_mode als_ir_mode; +}; + +static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) { + if (isl29028_prox_data[i].sampling_int == sampling_int && + isl29028_prox_data[i].sampling_fract == sampling_fract) + return i; + } + + return -EINVAL; +} + +static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, + int sampling_int, int sampling_fract) +{ + struct device *dev = regmap_get_device(chip->regmap); + int sleep_index, ret; + + sleep_index = isl29028_find_prox_sleep_index(sampling_int, + sampling_fract); + if (sleep_index < 0) + return sleep_index; + + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_PROX_SLP_MASK, + sleep_index << ISL29028_CONF_PROX_SLP_SH); + + if (ret < 0) { + dev_err(dev, "%s(): Error %d setting the proximity sampling\n", + __func__, ret); + return ret; + } + + chip->prox_sampling_int = sampling_int; + chip->prox_sampling_frac = sampling_fract; + + return ret; +} + +static int isl29028_enable_proximity(struct isl29028_chip *chip) +{ + int prox_index, ret; + + ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int, + chip->prox_sampling_frac); + if (ret < 0) + return ret; + + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_PROX_EN_MASK, + ISL29028_CONF_PROX_EN); + if (ret < 0) + return ret; + + /* Wait for conversion to be complete for first sample */ + prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int, + chip->prox_sampling_frac); + if (prox_index < 0) + return prox_index; + + msleep(isl29028_prox_data[prox_index].sleep_time); + + return 0; +} + +static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale) +{ + struct device *dev = regmap_get_device(chip->regmap); + int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX : + ISL29028_CONF_ALS_RANGE_LOW_LUX; + int ret; + + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_RANGE_MASK, val); + if (ret < 0) { + dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__, + ret); + return ret; + } + + chip->lux_scale = lux_scale; + + return ret; +} + +static int isl29028_set_als_ir_mode(struct isl29028_chip *chip, + enum isl29028_als_ir_mode mode) +{ + int ret; + + if (chip->als_ir_mode == mode) + return 0; + + ret = isl29028_set_als_scale(chip, chip->lux_scale); + if (ret < 0) + return ret; + + switch (mode) { + case ISL29028_MODE_ALS: + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_IR_MODE_MASK, + ISL29028_CONF_ALS_IR_MODE_ALS); + if (ret < 0) + return ret; + + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_RANGE_MASK, + ISL29028_CONF_ALS_RANGE_HIGH_LUX); + break; + case ISL29028_MODE_IR: + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_IR_MODE_MASK, + ISL29028_CONF_ALS_IR_MODE_IR); + break; + case ISL29028_MODE_NONE: + return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_EN_MASK, + ISL29028_CONF_ALS_DIS); + } + + if (ret < 0) + return ret; + + /* Enable the ALS/IR */ + ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, + ISL29028_CONF_ALS_EN_MASK, + ISL29028_CONF_ALS_EN); + if (ret < 0) + return ret; + + /* Need to wait for conversion time if ALS/IR mode enabled */ + msleep(ISL29028_CONV_TIME_MS); + + chip->als_ir_mode = mode; + + return 0; +} + +static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir) +{ + struct device *dev = regmap_get_device(chip->regmap); + unsigned int lsb; + unsigned int msb; + int ret; + + ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb); + if (ret < 0) { + dev_err(dev, + "%s(): Error %d reading register ALSIR_L\n", + __func__, ret); + return ret; + } + + ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb); + if (ret < 0) { + dev_err(dev, + "%s(): Error %d reading register ALSIR_U\n", + __func__, ret); + return ret; + } + + *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF); + + return 0; +} + +static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox) +{ + struct device *dev = regmap_get_device(chip->regmap); + unsigned int data; + int ret; + + if (!chip->enable_prox) { + ret = isl29028_enable_proximity(chip); + if (ret < 0) + return ret; + + chip->enable_prox = true; + } + + ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data); + if (ret < 0) { + dev_err(dev, "%s(): Error %d reading register PROX_DATA\n", + __func__, ret); + return ret; + } + + *prox = data; + + return 0; +} + +static int isl29028_als_get(struct isl29028_chip *chip, int *als_data) +{ + struct device *dev = regmap_get_device(chip->regmap); + int ret; + int als_ir_data; + + ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS); + if (ret < 0) { + dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__, + ret); + return ret; + } + + ret = isl29028_read_als_ir(chip, &als_ir_data); + if (ret < 0) + return ret; + + /* + * convert als data count to lux. + * if lux_scale = 125, lux = count * 0.031 + * if lux_scale = 2000, lux = count * 0.49 + */ + if (chip->lux_scale == 125) + als_ir_data = (als_ir_data * 31) / 1000; + else + als_ir_data = (als_ir_data * 49) / 100; + + *als_data = als_ir_data; + + return 0; +} + +static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) +{ + struct device *dev = regmap_get_device(chip->regmap); + int ret; + + ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR); + if (ret < 0) { + dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__, + ret); + return ret; + } + + return isl29028_read_als_ir(chip, ir_data); +} + +static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) +{ + struct device *dev = regmap_get_device(chip->regmap); + int ret; + + if (on) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) + pm_runtime_put_noidle(dev); + } else { + pm_runtime_mark_last_busy(dev); + ret = pm_runtime_put_autosuspend(dev); + } + + return ret; +} + +/* Channel IO */ +static int isl29028_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct isl29028_chip *chip = iio_priv(indio_dev); + struct device *dev = regmap_get_device(chip->regmap); + int ret; + + ret = isl29028_set_pm_runtime_busy(chip, true); + if (ret < 0) + return ret; + + mutex_lock(&chip->lock); + + ret = -EINVAL; + switch (chan->type) { + case IIO_PROXIMITY: + if (mask != IIO_CHAN_INFO_SAMP_FREQ) { + dev_err(dev, + "%s(): proximity: Mask value 0x%08lx is not supported\n", + __func__, mask); + break; + } + + if (val < 1 || val > 100) { + dev_err(dev, + "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n", + __func__, val); + break; + } + + ret = isl29028_set_proxim_sampling(chip, val, val2); + break; + case IIO_LIGHT: + if (mask != IIO_CHAN_INFO_SCALE) { + dev_err(dev, + "%s(): light: Mask value 0x%08lx is not supported\n", + __func__, mask); + break; + } + + if (val != 125 && val != 2000) { + dev_err(dev, + "%s(): light: Lux scale %d is not in the set {125, 2000}\n", + __func__, val); + break; + } + + ret = isl29028_set_als_scale(chip, val); + break; + default: + dev_err(dev, "%s(): Unsupported channel type %x\n", + __func__, chan->type); + break; + } + + mutex_unlock(&chip->lock); + + if (ret < 0) + return ret; + + ret = isl29028_set_pm_runtime_busy(chip, false); + if (ret < 0) + return ret; + + return ret; +} + +static int isl29028_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct isl29028_chip *chip = iio_priv(indio_dev); + struct device *dev = regmap_get_device(chip->regmap); + int ret, pm_ret; + + ret = isl29028_set_pm_runtime_busy(chip, true); + if (ret < 0) + return ret; + + mutex_lock(&chip->lock); + + ret = -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + ret = isl29028_als_get(chip, val); + break; + case IIO_INTENSITY: + ret = isl29028_ir_get(chip, val); + break; + case IIO_PROXIMITY: + ret = isl29028_read_proxim(chip, val); + break; + default: + break; + } + + if (ret < 0) + break; + + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (chan->type != IIO_PROXIMITY) + break; + + *val = chip->prox_sampling_int; + *val2 = chip->prox_sampling_frac; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_LIGHT) + break; + *val = chip->lux_scale; + ret = IIO_VAL_INT; + break; + default: + dev_err(dev, "%s(): mask value 0x%08lx is not supported\n", + __func__, mask); + break; + } + + mutex_unlock(&chip->lock); + + if (ret < 0) + return ret; + + /** + * Preserve the ret variable if the call to + * isl29028_set_pm_runtime_busy() is successful so the reading + * (if applicable) is returned to user space. + */ + pm_ret = isl29028_set_pm_runtime_busy(chip, false); + if (pm_ret < 0) + return pm_ret; + + return ret; +} + +static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, + "1.25 2.5 5 10 13.3 20 80 100"); +static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000"); + +#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) +static struct attribute *isl29028_attributes[] = { + ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available), + ISL29028_CONST_ATTR(in_illuminance_scale_available), + NULL, +}; + +static const struct attribute_group isl29108_group = { + .attrs = isl29028_attributes, +}; + +static const struct iio_chan_spec isl29028_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_SCALE), + }, { + .type = IIO_INTENSITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + } +}; + +static const struct iio_info isl29028_info = { + .attrs = &isl29108_group, + .driver_module = THIS_MODULE, + .read_raw = isl29028_read_raw, + .write_raw = isl29028_write_raw, +}; + +static int isl29028_clear_configure_reg(struct isl29028_chip *chip) +{ + struct device *dev = regmap_get_device(chip->regmap); + int ret; + + ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0); + if (ret < 0) + dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n", + __func__, ret); + + chip->als_ir_mode = ISL29028_MODE_NONE; + chip->enable_prox = false; + + return ret; +} + +static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ISL29028_REG_INTERRUPT: + case ISL29028_REG_PROX_DATA: + case ISL29028_REG_ALSIR_L: + case ISL29028_REG_ALSIR_U: + return true; + default: + return false; + } +} + +static const struct regmap_config isl29028_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = isl29028_is_volatile_reg, + .max_register = ISL29028_NUM_REGS - 1, + .num_reg_defaults_raw = ISL29028_NUM_REGS, + .cache_type = REGCACHE_RBTREE, +}; + +static int isl29028_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct isl29028_chip *chip; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + + i2c_set_clientdata(client, indio_dev); + mutex_init(&chip->lock); + + chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(&client->dev, "%s: Error %d initializing regmap\n", + __func__, ret); + return ret; + } + + chip->enable_prox = false; + chip->prox_sampling_int = 20; + chip->prox_sampling_frac = 0; + chip->lux_scale = 2000; + + ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0); + if (ret < 0) { + dev_err(&client->dev, + "%s(): Error %d writing to TEST1_MODE register\n", + __func__, ret); + return ret; + } + + ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0); + if (ret < 0) { + dev_err(&client->dev, + "%s(): Error %d writing to TEST2_MODE register\n", + __func__, ret); + return ret; + } + + ret = isl29028_clear_configure_reg(chip); + if (ret < 0) + return ret; + + indio_dev->info = &isl29028_info; + indio_dev->channels = isl29028_channels; + indio_dev->num_channels = ARRAY_SIZE(isl29028_channels); + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + ISL29028_POWER_OFF_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); + if (ret < 0) { + dev_err(&client->dev, + "%s(): iio registration failed with error %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int isl29028_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct isl29028_chip *chip = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + return isl29028_clear_configure_reg(chip); +} + +static int __maybe_unused isl29028_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct isl29028_chip *chip = iio_priv(indio_dev); + int ret; + + mutex_lock(&chip->lock); + + ret = isl29028_clear_configure_reg(chip); + + mutex_unlock(&chip->lock); + + return ret; +} + +static int __maybe_unused isl29028_resume(struct device *dev) +{ + /** + * The specific component (ALS/IR or proximity) will enable itself as + * needed the next time that the user requests a reading. This is done + * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity(). + */ + return 0; +} + +static const struct dev_pm_ops isl29028_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL) +}; + +static const struct i2c_device_id isl29028_id[] = { + {"isl29028", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, isl29028_id); + +static const struct of_device_id isl29028_of_match[] = { + { .compatible = "isl,isl29028", }, /* for backward compat., don't use */ + { .compatible = "isil,isl29028", }, + { }, +}; +MODULE_DEVICE_TABLE(of, isl29028_of_match); + +static struct i2c_driver isl29028_driver = { + .driver = { + .name = "isl29028", + .pm = &isl29028_pm_ops, + .of_match_table = isl29028_of_match, + }, + .probe = isl29028_probe, + .remove = isl29028_remove, + .id_table = isl29028_id, +}; + +module_i2c_driver(isl29028_driver); + +MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Laxman Dewangan "); diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 4fbf6298c0f3..aacb0ae58c0e 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -3,16 +3,6 @@ # menu "Light sensors" -config SENSORS_ISL29028 - tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" - depends on I2C - select REGMAP_I2C - help - Provides driver for the Intersil's ISL29028 device. - This driver supports the sysfs interface to get the ALS, IR intensity, - Proximity value via iio. The ISL29028 provides the concurrent sensing - of ambient light and proximity. - config TSL2x7x tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" depends on I2C diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index f8693e9fdc94..10286c3ee6fe 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,5 +2,4 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c deleted file mode 100644 index aeb50825acef..000000000000 --- a/drivers/staging/iio/light/isl29028.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * IIO driver for the light sensor ISL29028. - * ISL29028 is Concurrent Ambient Light and Proximity Sensor - * - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * Copyright (c) 2016-2017 Brian Masney - * - * 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. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ISL29028_CONV_TIME_MS 100 - -#define ISL29028_REG_CONFIGURE 0x01 - -#define ISL29028_CONF_ALS_IR_MODE_ALS 0 -#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0) -#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0) - -#define ISL29028_CONF_ALS_RANGE_LOW_LUX 0 -#define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1) -#define ISL29028_CONF_ALS_RANGE_MASK BIT(1) - -#define ISL29028_CONF_ALS_DIS 0 -#define ISL29028_CONF_ALS_EN BIT(2) -#define ISL29028_CONF_ALS_EN_MASK BIT(2) - -#define ISL29028_CONF_PROX_SLP_SH 4 -#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH) - -#define ISL29028_CONF_PROX_EN BIT(7) -#define ISL29028_CONF_PROX_EN_MASK BIT(7) - -#define ISL29028_REG_INTERRUPT 0x02 - -#define ISL29028_REG_PROX_DATA 0x08 -#define ISL29028_REG_ALSIR_L 0x09 -#define ISL29028_REG_ALSIR_U 0x0A - -#define ISL29028_REG_TEST1_MODE 0x0E -#define ISL29028_REG_TEST2_MODE 0x0F - -#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1) - -#define ISL29028_POWER_OFF_DELAY_MS 2000 - -struct isl29028_prox_data { - int sampling_int; - int sampling_fract; - int sleep_time; -}; - -static const struct isl29028_prox_data isl29028_prox_data[] = { - { 1, 250000, 800 }, - { 2, 500000, 400 }, - { 5, 0, 200 }, - { 10, 0, 100 }, - { 13, 300000, 75 }, - { 20, 0, 50 }, - { 80, 0, 13 }, /* - * Note: Data sheet lists 12.5 ms sleep time. - * Round up a half millisecond for msleep(). - */ - { 100, 0, 0 } -}; - -enum isl29028_als_ir_mode { - ISL29028_MODE_NONE = 0, - ISL29028_MODE_ALS, - ISL29028_MODE_IR, -}; - -struct isl29028_chip { - struct mutex lock; - struct regmap *regmap; - int prox_sampling_int; - int prox_sampling_frac; - bool enable_prox; - int lux_scale; - enum isl29028_als_ir_mode als_ir_mode; -}; - -static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) { - if (isl29028_prox_data[i].sampling_int == sampling_int && - isl29028_prox_data[i].sampling_fract == sampling_fract) - return i; - } - - return -EINVAL; -} - -static int isl29028_set_proxim_sampling(struct isl29028_chip *chip, - int sampling_int, int sampling_fract) -{ - struct device *dev = regmap_get_device(chip->regmap); - int sleep_index, ret; - - sleep_index = isl29028_find_prox_sleep_index(sampling_int, - sampling_fract); - if (sleep_index < 0) - return sleep_index; - - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_PROX_SLP_MASK, - sleep_index << ISL29028_CONF_PROX_SLP_SH); - - if (ret < 0) { - dev_err(dev, "%s(): Error %d setting the proximity sampling\n", - __func__, ret); - return ret; - } - - chip->prox_sampling_int = sampling_int; - chip->prox_sampling_frac = sampling_fract; - - return ret; -} - -static int isl29028_enable_proximity(struct isl29028_chip *chip) -{ - int prox_index, ret; - - ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int, - chip->prox_sampling_frac); - if (ret < 0) - return ret; - - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_PROX_EN_MASK, - ISL29028_CONF_PROX_EN); - if (ret < 0) - return ret; - - /* Wait for conversion to be complete for first sample */ - prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int, - chip->prox_sampling_frac); - if (prox_index < 0) - return prox_index; - - msleep(isl29028_prox_data[prox_index].sleep_time); - - return 0; -} - -static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale) -{ - struct device *dev = regmap_get_device(chip->regmap); - int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX : - ISL29028_CONF_ALS_RANGE_LOW_LUX; - int ret; - - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_RANGE_MASK, val); - if (ret < 0) { - dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__, - ret); - return ret; - } - - chip->lux_scale = lux_scale; - - return ret; -} - -static int isl29028_set_als_ir_mode(struct isl29028_chip *chip, - enum isl29028_als_ir_mode mode) -{ - int ret; - - if (chip->als_ir_mode == mode) - return 0; - - ret = isl29028_set_als_scale(chip, chip->lux_scale); - if (ret < 0) - return ret; - - switch (mode) { - case ISL29028_MODE_ALS: - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_IR_MODE_MASK, - ISL29028_CONF_ALS_IR_MODE_ALS); - if (ret < 0) - return ret; - - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_RANGE_MASK, - ISL29028_CONF_ALS_RANGE_HIGH_LUX); - break; - case ISL29028_MODE_IR: - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_IR_MODE_MASK, - ISL29028_CONF_ALS_IR_MODE_IR); - break; - case ISL29028_MODE_NONE: - return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_EN_MASK, - ISL29028_CONF_ALS_DIS); - } - - if (ret < 0) - return ret; - - /* Enable the ALS/IR */ - ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE, - ISL29028_CONF_ALS_EN_MASK, - ISL29028_CONF_ALS_EN); - if (ret < 0) - return ret; - - /* Need to wait for conversion time if ALS/IR mode enabled */ - msleep(ISL29028_CONV_TIME_MS); - - chip->als_ir_mode = mode; - - return 0; -} - -static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir) -{ - struct device *dev = regmap_get_device(chip->regmap); - unsigned int lsb; - unsigned int msb; - int ret; - - ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb); - if (ret < 0) { - dev_err(dev, - "%s(): Error %d reading register ALSIR_L\n", - __func__, ret); - return ret; - } - - ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb); - if (ret < 0) { - dev_err(dev, - "%s(): Error %d reading register ALSIR_U\n", - __func__, ret); - return ret; - } - - *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF); - - return 0; -} - -static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox) -{ - struct device *dev = regmap_get_device(chip->regmap); - unsigned int data; - int ret; - - if (!chip->enable_prox) { - ret = isl29028_enable_proximity(chip); - if (ret < 0) - return ret; - - chip->enable_prox = true; - } - - ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data); - if (ret < 0) { - dev_err(dev, "%s(): Error %d reading register PROX_DATA\n", - __func__, ret); - return ret; - } - - *prox = data; - - return 0; -} - -static int isl29028_als_get(struct isl29028_chip *chip, int *als_data) -{ - struct device *dev = regmap_get_device(chip->regmap); - int ret; - int als_ir_data; - - ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS); - if (ret < 0) { - dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__, - ret); - return ret; - } - - ret = isl29028_read_als_ir(chip, &als_ir_data); - if (ret < 0) - return ret; - - /* - * convert als data count to lux. - * if lux_scale = 125, lux = count * 0.031 - * if lux_scale = 2000, lux = count * 0.49 - */ - if (chip->lux_scale == 125) - als_ir_data = (als_ir_data * 31) / 1000; - else - als_ir_data = (als_ir_data * 49) / 100; - - *als_data = als_ir_data; - - return 0; -} - -static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data) -{ - struct device *dev = regmap_get_device(chip->regmap); - int ret; - - ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR); - if (ret < 0) { - dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__, - ret); - return ret; - } - - return isl29028_read_als_ir(chip, ir_data); -} - -static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on) -{ - struct device *dev = regmap_get_device(chip->regmap); - int ret; - - if (on) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) - pm_runtime_put_noidle(dev); - } else { - pm_runtime_mark_last_busy(dev); - ret = pm_runtime_put_autosuspend(dev); - } - - return ret; -} - -/* Channel IO */ -static int isl29028_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct isl29028_chip *chip = iio_priv(indio_dev); - struct device *dev = regmap_get_device(chip->regmap); - int ret; - - ret = isl29028_set_pm_runtime_busy(chip, true); - if (ret < 0) - return ret; - - mutex_lock(&chip->lock); - - ret = -EINVAL; - switch (chan->type) { - case IIO_PROXIMITY: - if (mask != IIO_CHAN_INFO_SAMP_FREQ) { - dev_err(dev, - "%s(): proximity: Mask value 0x%08lx is not supported\n", - __func__, mask); - break; - } - - if (val < 1 || val > 100) { - dev_err(dev, - "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n", - __func__, val); - break; - } - - ret = isl29028_set_proxim_sampling(chip, val, val2); - break; - case IIO_LIGHT: - if (mask != IIO_CHAN_INFO_SCALE) { - dev_err(dev, - "%s(): light: Mask value 0x%08lx is not supported\n", - __func__, mask); - break; - } - - if (val != 125 && val != 2000) { - dev_err(dev, - "%s(): light: Lux scale %d is not in the set {125, 2000}\n", - __func__, val); - break; - } - - ret = isl29028_set_als_scale(chip, val); - break; - default: - dev_err(dev, "%s(): Unsupported channel type %x\n", - __func__, chan->type); - break; - } - - mutex_unlock(&chip->lock); - - if (ret < 0) - return ret; - - ret = isl29028_set_pm_runtime_busy(chip, false); - if (ret < 0) - return ret; - - return ret; -} - -static int isl29028_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct isl29028_chip *chip = iio_priv(indio_dev); - struct device *dev = regmap_get_device(chip->regmap); - int ret, pm_ret; - - ret = isl29028_set_pm_runtime_busy(chip, true); - if (ret < 0) - return ret; - - mutex_lock(&chip->lock); - - ret = -EINVAL; - switch (mask) { - case IIO_CHAN_INFO_RAW: - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_LIGHT: - ret = isl29028_als_get(chip, val); - break; - case IIO_INTENSITY: - ret = isl29028_ir_get(chip, val); - break; - case IIO_PROXIMITY: - ret = isl29028_read_proxim(chip, val); - break; - default: - break; - } - - if (ret < 0) - break; - - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_SAMP_FREQ: - if (chan->type != IIO_PROXIMITY) - break; - - *val = chip->prox_sampling_int; - *val2 = chip->prox_sampling_frac; - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_SCALE: - if (chan->type != IIO_LIGHT) - break; - *val = chip->lux_scale; - ret = IIO_VAL_INT; - break; - default: - dev_err(dev, "%s(): mask value 0x%08lx is not supported\n", - __func__, mask); - break; - } - - mutex_unlock(&chip->lock); - - if (ret < 0) - return ret; - - /** - * Preserve the ret variable if the call to - * isl29028_set_pm_runtime_busy() is successful so the reading - * (if applicable) is returned to user space. - */ - pm_ret = isl29028_set_pm_runtime_busy(chip, false); - if (pm_ret < 0) - return pm_ret; - - return ret; -} - -static IIO_CONST_ATTR(in_proximity_sampling_frequency_available, - "1.25 2.5 5 10 13.3 20 80 100"); -static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000"); - -#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) -static struct attribute *isl29028_attributes[] = { - ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available), - ISL29028_CONST_ATTR(in_illuminance_scale_available), - NULL, -}; - -static const struct attribute_group isl29108_group = { - .attrs = isl29028_attributes, -}; - -static const struct iio_chan_spec isl29028_channels[] = { - { - .type = IIO_LIGHT, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_SCALE), - }, { - .type = IIO_INTENSITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SAMP_FREQ), - } -}; - -static const struct iio_info isl29028_info = { - .attrs = &isl29108_group, - .driver_module = THIS_MODULE, - .read_raw = isl29028_read_raw, - .write_raw = isl29028_write_raw, -}; - -static int isl29028_clear_configure_reg(struct isl29028_chip *chip) -{ - struct device *dev = regmap_get_device(chip->regmap); - int ret; - - ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0); - if (ret < 0) - dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n", - __func__, ret); - - chip->als_ir_mode = ISL29028_MODE_NONE; - chip->enable_prox = false; - - return ret; -} - -static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg) -{ - switch (reg) { - case ISL29028_REG_INTERRUPT: - case ISL29028_REG_PROX_DATA: - case ISL29028_REG_ALSIR_L: - case ISL29028_REG_ALSIR_U: - return true; - default: - return false; - } -} - -static const struct regmap_config isl29028_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .volatile_reg = isl29028_is_volatile_reg, - .max_register = ISL29028_NUM_REGS - 1, - .num_reg_defaults_raw = ISL29028_NUM_REGS, - .cache_type = REGCACHE_RBTREE, -}; - -static int isl29028_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct isl29028_chip *chip; - struct iio_dev *indio_dev; - int ret; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - - chip = iio_priv(indio_dev); - - i2c_set_clientdata(client, indio_dev); - mutex_init(&chip->lock); - - chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config); - if (IS_ERR(chip->regmap)) { - ret = PTR_ERR(chip->regmap); - dev_err(&client->dev, "%s: Error %d initializing regmap\n", - __func__, ret); - return ret; - } - - chip->enable_prox = false; - chip->prox_sampling_int = 20; - chip->prox_sampling_frac = 0; - chip->lux_scale = 2000; - - ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0); - if (ret < 0) { - dev_err(&client->dev, - "%s(): Error %d writing to TEST1_MODE register\n", - __func__, ret); - return ret; - } - - ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0); - if (ret < 0) { - dev_err(&client->dev, - "%s(): Error %d writing to TEST2_MODE register\n", - __func__, ret); - return ret; - } - - ret = isl29028_clear_configure_reg(chip); - if (ret < 0) - return ret; - - indio_dev->info = &isl29028_info; - indio_dev->channels = isl29028_channels; - indio_dev->num_channels = ARRAY_SIZE(isl29028_channels); - indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, - ISL29028_POWER_OFF_DELAY_MS); - pm_runtime_use_autosuspend(&client->dev); - - ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); - if (ret < 0) { - dev_err(&client->dev, - "%s(): iio registration failed with error %d\n", - __func__, ret); - return ret; - } - - return 0; -} - -static int isl29028_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct isl29028_chip *chip = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); - - return isl29028_clear_configure_reg(chip); -} - -static int __maybe_unused isl29028_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct isl29028_chip *chip = iio_priv(indio_dev); - int ret; - - mutex_lock(&chip->lock); - - ret = isl29028_clear_configure_reg(chip); - - mutex_unlock(&chip->lock); - - return ret; -} - -static int __maybe_unused isl29028_resume(struct device *dev) -{ - /** - * The specific component (ALS/IR or proximity) will enable itself as - * needed the next time that the user requests a reading. This is done - * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity(). - */ - return 0; -} - -static const struct dev_pm_ops isl29028_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL) -}; - -static const struct i2c_device_id isl29028_id[] = { - {"isl29028", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, isl29028_id); - -static const struct of_device_id isl29028_of_match[] = { - { .compatible = "isl,isl29028", }, /* for backward compat., don't use */ - { .compatible = "isil,isl29028", }, - { }, -}; -MODULE_DEVICE_TABLE(of, isl29028_of_match); - -static struct i2c_driver isl29028_driver = { - .driver = { - .name = "isl29028", - .pm = &isl29028_pm_ops, - .of_match_table = isl29028_of_match, - }, - .probe = isl29028_probe, - .remove = isl29028_remove, - .id_table = isl29028_id, -}; - -module_i2c_driver(isl29028_driver); - -MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Laxman Dewangan "); -- cgit v1.2.3 From 7383d44b84c94aaca4bf695a6bd8a69f2295ef1a Mon Sep 17 00:00:00 2001 From: Shrirang Bagul Date: Wed, 19 Apr 2017 22:05:00 +0800 Subject: iio: st_pressure: st_accel: Initialise sensor platform data properly This patch fixes the sensor platform data initialisation for st_pressure and st_accel device drivers. Without this patch, the driver fails to register the sensors when the user removes and re-loads the driver. 1. Unload the kernel modules for st_pressure $ sudo rmmod st_pressure_i2c $ sudo rmmod st_pressure 2. Re-load the driver $ sudo insmod st_pressure $ sudo insmod st_pressure_i2c Signed-off-by: Jonathan Cameron Acked-by: Linus Walleij --- drivers/iio/accel/st_accel_core.c | 7 ++++--- drivers/iio/pressure/st_pressure_core.c | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 784670e2736b..07d1489cd457 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -710,6 +710,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata = + (struct st_sensors_platform_data *)adata->dev->platform_data; int irq = adata->get_irq_data_ready(indio_dev); int err; @@ -736,9 +738,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev) &adata->sensor_settings->fs.fs_avl[0]; adata->odr = adata->sensor_settings->odr.odr_avl[0].hz; - if (!adata->dev->platform_data) - adata->dev->platform_data = - (struct st_sensors_platform_data *)&default_accel_pdata; + if (!pdata) + pdata = (struct st_sensors_platform_data *)&default_accel_pdata; err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); if (err < 0) diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index fd0edca0e656..aa61ec15c139 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -568,6 +568,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = { int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata = + (struct st_sensors_platform_data *)press_data->dev->platform_data; int irq = press_data->get_irq_data_ready(indio_dev); int err; @@ -603,10 +605,8 @@ int st_press_common_probe(struct iio_dev *indio_dev) press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; /* Some devices don't support a data ready pin. */ - if (!press_data->dev->platform_data && - press_data->sensor_settings->drdy_irq.addr) - press_data->dev->platform_data = - (struct st_sensors_platform_data *)&default_press_pdata; + if (!pdata && press_data->sensor_settings->drdy_irq.addr) + pdata = (struct st_sensors_platform_data *)&default_press_pdata; err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); if (err < 0) -- cgit v1.2.3 From 1a732f4211145b4f6cc47f14cdd9f51a31d7e147 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 20 Apr 2017 17:43:10 +0200 Subject: iio: adc: rcar-gyroadc: Derive interface clock speed from fck clock The "if" interface clock speed is actually derived from the "fck" block clock, as in the hardware they are the same clock. Drop the incorrect second "if" clock and get the clock speed from "fck". Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Cc: linux-renesas-soc@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rcar-gyroadc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/adc/rcar-gyroadc.c b/drivers/iio/adc/rcar-gyroadc.c index 018ed360e717..27a318164619 100644 --- a/drivers/iio/adc/rcar-gyroadc.c +++ b/drivers/iio/adc/rcar-gyroadc.c @@ -73,7 +73,7 @@ enum rcar_gyroadc_model { struct rcar_gyroadc { struct device *dev; void __iomem *regs; - struct clk *iclk; + struct clk *clk; struct regulator *vref[8]; unsigned int num_channels; enum rcar_gyroadc_model model; @@ -83,7 +83,7 @@ struct rcar_gyroadc { static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv) { - const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000; + const unsigned long clk_mhz = clk_get_rate(priv->clk) / 1000000; const unsigned long clk_mul = (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5; unsigned long clk_len = clk_mhz * clk_mul; @@ -510,9 +510,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); - priv->iclk = devm_clk_get(dev, "if"); - if (IS_ERR(priv->iclk)) { - ret = PTR_ERR(priv->iclk); + priv->clk = devm_clk_get(dev, "fck"); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret); return ret; @@ -536,7 +536,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev) indio_dev->info = &rcar_gyroadc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = clk_prepare_enable(priv->iclk); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(dev, "Could not prepare or enable the IF clock.\n"); goto err_clk_if_enable; @@ -565,7 +565,7 @@ err_iio_device_register: pm_runtime_put_sync(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - clk_disable_unprepare(priv->iclk); + clk_disable_unprepare(priv->clk); err_clk_if_enable: rcar_gyroadc_deinit_supplies(indio_dev); @@ -584,7 +584,7 @@ static int rcar_gyroadc_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); - clk_disable_unprepare(priv->iclk); + clk_disable_unprepare(priv->clk); rcar_gyroadc_deinit_supplies(indio_dev); return 0; -- cgit v1.2.3 From 80a49fd8244e810380adeacca10712c7a867d709 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 20 Apr 2017 17:42:16 +0200 Subject: iio: adc: rcar-gyroadc: Drop if clock from Renesas GyroADC bindings The "if" interface clock speed is actually derived from the "fck" block clock, as in the hardware they are the same clock. Drop the incorrect second "if" clock and retain only the "fck" clock. Signed-off-by: Marek Vasut Reviewed-by: Geert Uytterhoeven Cc: Rob Herring Cc: linux-renesas-soc@vger.kernel.org To: devicetree@vger.kernel.org Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt index f5b0adae6010..2a62908a774a 100644 --- a/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt +++ b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt @@ -16,8 +16,7 @@ Required properties: - clocks: References to all the clocks specified in the clock-names property as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt. -- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block - clock, the "if" is the interface clock. +- clock-names: Shall contain "fck". The "fck" is the GyroADC block clock. - power-domains: Must contain a reference to the PM domain, if available. - #address-cells: Should be <1> (setting for the subnodes) for all ADCs except for "fujitsu,mb88101a". Should be <0> (setting for @@ -75,8 +74,8 @@ Example: adc@e6e54000 { compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc"; reg = <0 0xe6e54000 0 64>; - clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>; - clock-names = "fck", "if"; + clocks = <&mstp9_clks R8A7791_CLK_GYROADC>; + clock-names = "fck"; power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; pinctrl-0 = <&adc_pins>; -- cgit v1.2.3 From 1016d56765740e02a613346f22a35c0ae7bccac4 Mon Sep 17 00:00:00 2001 From: Orson Zhai Date: Tue, 25 Apr 2017 09:16:56 +0800 Subject: iio: core: Fix suspicious sizeof usage Pointer size is variours in different system, say 32bit for 4 and 64bit for 8. The 'sizeof(infomask)' may lead to wrong bit numbers. Signed-off-by: Orson Zhai Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 3ff91e02fee3..795f53c4d75d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1089,7 +1089,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, { int i, ret, attrcount = 0; - for_each_set_bit(i, infomask, sizeof(infomask)*8) { + for_each_set_bit(i, infomask, sizeof(*infomask)*8) { if (i >= ARRAY_SIZE(iio_chan_info_postfix)) return -EINVAL; ret = __iio_add_chan_devattr(iio_chan_info_postfix[i], @@ -1118,7 +1118,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev, int i, ret, attrcount = 0; char *avail_postfix; - for_each_set_bit(i, infomask, sizeof(infomask) * 8) { + for_each_set_bit(i, infomask, sizeof(*infomask) * 8) { avail_postfix = kasprintf(GFP_KERNEL, "%s_available", iio_chan_info_postfix[i]); -- cgit v1.2.3 From c36662193b4e2e37e0e2084ca34585478526fa88 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Fri, 21 Apr 2017 18:01:25 +0530 Subject: tools/iio: Use include/uapi with __EXPORTED_HEADERS__ Use the local uapi headers to keep in sync with "recently" added enum values like IIO_UVINDEX. Build tested using: $ make -C tools/iio $ make -C /tools iio $ make -C /tools/iio This follows a strategy similar to that used by tools/hv, tools/net and tools/leds among others. Cc: Randy Dunlap Cc: Jonathan Cameron Signed-off-by: Sekhar Nori Signed-off-by: Jonathan Cameron --- tools/iio/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 5446d625e17d..8f08e03a9a5e 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -1,5 +1,5 @@ CC = $(CROSS_COMPILE)gcc -CFLAGS += -Wall -g -D_GNU_SOURCE +CFLAGS += -Wall -g -D_GNU_SOURCE -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include BINDIR=usr/bin INSTALL_PROGRAM=install -m 755 -p -- cgit v1.2.3 From c894acc7bf400d039bf740420b22f0b71b7fb504 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 19 Apr 2017 15:35:48 +0100 Subject: iio: hid-sensor: fix return of -EINVAL on invalid values in ret or value Ensure that when an invalid value in ret or value is found -EINVAL is returned. A previous commit broke the way the return error is being returned and instead caused the return code in ret to be re-assigned rather than be returned. Fixes: 5d9854eaea776 ("iio: hid-sensor: Store restore poll and hysteresis on S3") Signed-off-by: Colin Ian King Signed-off-by: Jonathan Cameron --- drivers/iio/common/hid-sensors/hid-sensor-attributes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 1c0874cdf665..aeb09a85d7a8 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -230,7 +230,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, st->poll.index, sizeof(value), &value); if (ret < 0 || value < 0) - ret = -EINVAL; + return -EINVAL; ret = sensor_hub_get_feature(st->hsdev, st->poll.report_id, @@ -283,7 +283,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, st->sensitivity.index, sizeof(value), &value); if (ret < 0 || value < 0) - ret = -EINVAL; + return -EINVAL; ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, -- cgit v1.2.3 From d532e5b2bc4724b3c493c1be58e3f1686c1e4fe7 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 26 Apr 2017 22:30:00 -0700 Subject: iio: proximity: as3935: move storm out of range check Move out of storm check to apply to IIO_CHAN_INFO_RAW so the reported results are constant between the former and the IIO_CHAN_INFO_PROCESSED Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/as3935.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index ddf9bee89f77..aa0d0be1a608 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -176,13 +176,13 @@ static int as3935_read_raw(struct iio_dev *indio_dev, if (ret) return ret; - if (m == IIO_CHAN_INFO_RAW) - return IIO_VAL_INT; - /* storm out of range */ if (*val == AS3935_DATA_MASK) return -EINVAL; + if (m == IIO_CHAN_INFO_RAW) + return IIO_VAL_INT; + if (m == IIO_CHAN_INFO_PROCESSED) *val *= 1000; break; -- cgit v1.2.3 From e530cc8408770e6451e4d5c5e8a2a45132689cc1 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 28 Apr 2017 17:55:58 +0200 Subject: iio: isl29028: add isl29030 support isl29030 is basically the same chip. The only difference is the chip's first pin. For isl29028 its named ADDR0 and can be used to change the chip's i2c address. For isl29030 on the other hand that pin is named Ials and is an analog current output proportional to ALS/IR. This change is irrelevant for the Linux driver. This has been tested on Motorola Droid 4. Signed-off-by: Sebastian Reichel Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 + drivers/iio/light/isl29028.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index ad10fbe61562..010e2ac43f62 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -55,6 +55,7 @@ gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor +isil,isl29030 Intersil ISL29030 Ambient Light and Proximity Sensor maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c index aeb50825acef..3d09c1fc4dad 100644 --- a/drivers/iio/light/isl29028.c +++ b/drivers/iio/light/isl29028.c @@ -16,6 +16,10 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * + * Datasheets: + * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29028.pdf + * - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29030.pdf */ #include @@ -694,6 +698,7 @@ static const struct dev_pm_ops isl29028_pm_ops = { static const struct i2c_device_id isl29028_id[] = { {"isl29028", 0}, + {"isl29030", 0}, {} }; MODULE_DEVICE_TABLE(i2c, isl29028_id); @@ -701,6 +706,7 @@ MODULE_DEVICE_TABLE(i2c, isl29028_id); static const struct of_device_id isl29028_of_match[] = { { .compatible = "isl,isl29028", }, /* for backward compat., don't use */ { .compatible = "isil,isl29028", }, + { .compatible = "isil,isl29030", }, { }, }; MODULE_DEVICE_TABLE(of, isl29028_of_match); -- cgit v1.2.3 From 535de397b28a3e24bf93da19dc9581936e420eea Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 Apr 2017 22:31:55 +0200 Subject: iio: imu: st_lsm6dsx: modify st_lsm6dsx_flush_fifo and st_lsm6dsx_set_fifo_mode scope Remove static qualifier from st_lsm6dsx_flush_fifo() and st_lsm6dsx_set_fifo_mode() in order to use them in system sleep pm support Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 3 +++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 4839db7b9690..7778520f28d4 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -144,5 +144,8 @@ int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask, u8 val); int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark); +int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw); +int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, + enum st_lsm6dsx_fifo_mode fifo_mode); #endif /* ST_LSM6DSX_H */ diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index c8e5cfd0ef0b..b19a62d8c884 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -130,8 +130,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw) return 0; } -static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, - enum st_lsm6dsx_fifo_mode fifo_mode) +int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw, + enum st_lsm6dsx_fifo_mode fifo_mode) { u8 data; int err; @@ -303,7 +303,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) return read_len; } -static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) +int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) { int err; -- cgit v1.2.3 From d3f770582aeb11db9d8b433d6ee23bdfab3422a2 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 27 Apr 2017 22:31:56 +0200 Subject: iio: imu: st_lsm6dsx: add system power management support Add system sleep power management support to st_lsm6dsx driver. In particular during suspend phase each sensor is disabled and hw fifo is configured in bypass in order to avoid subsequent I/O operations. The patch has been tested on HiKey board device Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 ++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 54 ++++++++++++++++++++++++++++ drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 1 + drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 1 + 4 files changed, 58 insertions(+) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 7778520f28d4..46352c7bff43 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -135,6 +135,8 @@ struct st_lsm6dsx_hw { #endif /* CONFIG_SPI_MASTER */ }; +extern const struct dev_pm_ops st_lsm6dsx_pm_ops; + int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, const struct st_lsm6dsx_transfer_function *tf_ops); int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 462a27b70453..1b53848cdfd8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -731,6 +732,59 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, } EXPORT_SYMBOL(st_lsm6dsx_probe); +#ifdef CONFIG_PM +static int st_lsm6dsx_suspend(struct device *dev) +{ + struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); + struct st_lsm6dsx_sensor *sensor; + int i, err = 0; + + for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { + sensor = iio_priv(hw->iio_devs[i]); + if (!(hw->enable_mask & BIT(sensor->id))) + continue; + + err = st_lsm6dsx_write_with_mask(hw, + st_lsm6dsx_odr_table[sensor->id].reg.addr, + st_lsm6dsx_odr_table[sensor->id].reg.mask, 0); + if (err < 0) + return err; + } + + if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) + err = st_lsm6dsx_flush_fifo(hw); + + return err; +} + +static int st_lsm6dsx_resume(struct device *dev) +{ + struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); + struct st_lsm6dsx_sensor *sensor; + int i, err = 0; + + for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { + sensor = iio_priv(hw->iio_devs[i]); + if (!(hw->enable_mask & BIT(sensor->id))) + continue; + + err = st_lsm6dsx_set_odr(sensor, sensor->odr); + if (err < 0) + return err; + } + + if (hw->enable_mask) + err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); + + return err; +} +#endif /* CONFIG_PM */ + +const struct dev_pm_ops st_lsm6dsx_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) +}; +EXPORT_SYMBOL(st_lsm6dsx_pm_ops); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_AUTHOR("Denis Ciocca "); MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 09a51cfb9b5e..305fec712ab0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -98,6 +98,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); static struct i2c_driver st_lsm6dsx_driver = { .driver = { .name = "st_lsm6dsx_i2c", + .pm = &st_lsm6dsx_pm_ops, .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match), }, .probe = st_lsm6dsx_i2c_probe, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index f765a5058488..95472f153ad2 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); static struct spi_driver st_lsm6dsx_driver = { .driver = { .name = "st_lsm6dsx_spi", + .pm = &st_lsm6dsx_pm_ops, .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match), }, .probe = st_lsm6dsx_spi_probe, -- cgit v1.2.3 From 2451c5dda4d0bc65c1d72fa8d06f3db2ad6f4311 Mon Sep 17 00:00:00 2001 From: Quentin Swain Date: Sun, 30 Apr 2017 19:16:58 -0400 Subject: iio: ad9834 convert symbolic permissions to octal Remove checkpatch warnings by converting symbolic S_IRUGO and S_IWUSR permissions to octal Signed-off-by: Quentin Swain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/frequency/ad9834.c | 22 +++++++++++----------- drivers/staging/iio/frequency/dds.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index af108e96b3ec..995acdd7c942 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -292,7 +292,7 @@ ssize_t ad9834_show_out0_wavetype_available(struct device *dev, return sprintf(buf, "%s\n", str); } -static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO, +static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, 0444, ad9834_show_out0_wavetype_available, NULL, 0); static @@ -312,27 +312,27 @@ ssize_t ad9834_show_out1_wavetype_available(struct device *dev, return sprintf(buf, "%s\n", str); } -static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO, +static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444, ad9834_show_out1_wavetype_available, NULL, 0); /** * see dds.h for further information */ -static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0); -static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1); -static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL); +static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9834_write, AD9834_REG_FREQ0); +static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9834_write, AD9834_REG_FREQ1); +static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL); static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ -static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0); -static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1); -static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL); +static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0); +static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1); +static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL); 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, ad9834_write, AD9834_PIN_SW); -static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET); -static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL, +static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL, ad9834_write, AD9834_RESET); +static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, 0200, NULL, ad9834_write, AD9834_OPBITEN); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h index fe53e7324c94..d6ccd99c14d7 100644 --- a/drivers/staging/iio/frequency/dds.h +++ b/drivers/staging/iio/frequency/dds.h @@ -101,7 +101,7 @@ #define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\ - S_IWUSR, NULL, _store, _addr) + 0200, NULL, _store, _addr) /** * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available -- cgit v1.2.3 From 3e8eae90790af430bb6d92dbd830f6b5653bc17b Mon Sep 17 00:00:00 2001 From: Quentin Swain Date: Sun, 30 Apr 2017 19:16:59 -0400 Subject: iio: ade7753 Convert: symbolic permissions to octal Convert S_IRUGO and S_IWUSR macros to octal permissions to resolve warnings reported by checkpatch.pl Signed-off-by: Quentin Swain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7753.c | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index b71fbd313778..c0f258c53d3f 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -298,92 +298,92 @@ static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY); static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY); static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY); static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY); -static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CFDEN(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_CFDEN); -static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CFNUM(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_CFNUM); static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM); -static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_PHCAL(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_PHCAL); -static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APOS(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_APOS); -static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAGCYC(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_SAGCYC); -static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAGLVL(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_SAGLVL); -static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_LINECYC(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_LINECYC); -static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_WDIV(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_WDIV); -static IIO_DEV_ATTR_IRMS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IRMS(0644, ade7753_read_24bit, NULL, ADE7753_IRMS); -static IIO_DEV_ATTR_VRMS(S_IRUGO, +static IIO_DEV_ATTR_VRMS(0444, ade7753_read_24bit, NULL, ADE7753_VRMS); -static IIO_DEV_ATTR_IRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IRMSOS(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_IRMSOS); -static IIO_DEV_ATTR_VRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VRMSOS(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_VRMSOS); -static IIO_DEV_ATTR_WGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_WGAIN(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_WGAIN); -static IIO_DEV_ATTR_VAGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VAGAIN(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_VAGAIN); -static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_PGA_GAIN(0644, ade7753_read_16bit, ade7753_write_16bit, ADE7753_GAIN); -static IIO_DEV_ATTR_IPKLVL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IPKLVL(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_IPKLVL); -static IIO_DEV_ATTR_VPKLVL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VPKLVL(0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_VPKLVL); -static IIO_DEV_ATTR_IPEAK(S_IRUGO, +static IIO_DEV_ATTR_IPEAK(0444, ade7753_read_24bit, NULL, ADE7753_IPEAK); -static IIO_DEV_ATTR_VPEAK(S_IRUGO, +static IIO_DEV_ATTR_VPEAK(0444, ade7753_read_24bit, NULL, ADE7753_VPEAK); -static IIO_DEV_ATTR_VPERIOD(S_IRUGO, +static IIO_DEV_ATTR_VPERIOD(0444, ade7753_read_16bit, NULL, ADE7753_PERIOD); -static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CH_OFF(1, 0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_CH1OS); -static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CH_OFF(2, 0644, ade7753_read_8bit, ade7753_write_8bit, ADE7753_CH2OS); @@ -514,7 +514,7 @@ static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit); static IIO_CONST_ATTR(in_temp_offset, "-25 C"); static IIO_CONST_ATTR(in_temp_scale, "0.67 C"); -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAMP_FREQ(0644, ade7753_read_frequency, ade7753_write_frequency); -- cgit v1.2.3 From 37cbe596e24a606463e052405d6ff585141331b7 Mon Sep 17 00:00:00 2001 From: Quentin Swain Date: Sun, 30 Apr 2017 19:17:00 -0400 Subject: iio: ade7754: Convert symbolic permissions to octal Convert symbolic S_IRUGO and S_IWUSR macros to octal permissions to resolve warnings reported by checkpatch.pl Signed-off-by: Quentin Swain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7754.c | 56 ++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 32dc50341746..be0df3fe4230 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -316,111 +316,111 @@ static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY); static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY); static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY); static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY); -static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VPEAK(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_VPEAK); -static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IPEAK(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_VPEAK); -static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APHCAL(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_APHCAL); -static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BPHCAL(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_BPHCAL); -static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CPHCAL(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_CPHCAL); -static IIO_DEV_ATTR_AAPOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AAPOS(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_AAPOS); -static IIO_DEV_ATTR_BAPOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BAPOS(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_BAPOS); -static IIO_DEV_ATTR_CAPOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CAPOS(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CAPOS); -static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_WDIV(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_WDIV); -static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VADIV(0644, ade7754_read_8bit, ade7754_write_8bit, ADE7754_VADIV); -static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CFNUM(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CFNUM); -static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CFDEN(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CFDEN); -static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_AAPGAIN); -static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_BAPGAIN); -static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(0644, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CAPGAIN); -static IIO_DEV_ATTR_AIRMS(S_IRUGO, +static IIO_DEV_ATTR_AIRMS(0444, ade7754_read_24bit, NULL, ADE7754_AIRMS); -static IIO_DEV_ATTR_BIRMS(S_IRUGO, +static IIO_DEV_ATTR_BIRMS(0444, ade7754_read_24bit, NULL, ADE7754_BIRMS); -static IIO_DEV_ATTR_CIRMS(S_IRUGO, +static IIO_DEV_ATTR_CIRMS(0444, ade7754_read_24bit, NULL, ADE7754_CIRMS); -static IIO_DEV_ATTR_AVRMS(S_IRUGO, +static IIO_DEV_ATTR_AVRMS(0444, ade7754_read_24bit, NULL, ADE7754_AVRMS); -static IIO_DEV_ATTR_BVRMS(S_IRUGO, +static IIO_DEV_ATTR_BVRMS(0444, ade7754_read_24bit, NULL, ADE7754_BVRMS); -static IIO_DEV_ATTR_CVRMS(S_IRUGO, +static IIO_DEV_ATTR_CVRMS(0444, ade7754_read_24bit, NULL, ADE7754_CVRMS); -static IIO_DEV_ATTR_AIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_AIRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_AIRMSOS); -static IIO_DEV_ATTR_BIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_BIRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_BIRMSOS); -static IIO_DEV_ATTR_CIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_CIRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CIRMSOS); -static IIO_DEV_ATTR_AVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_AVRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_AVRMSOS); -static IIO_DEV_ATTR_BVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_BVRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_BVRMSOS); -static IIO_DEV_ATTR_CVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_CVRMSOS(0444, ade7754_read_16bit, ade7754_write_16bit, ADE7754_CVRMSOS); @@ -549,7 +549,7 @@ static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit); static IIO_CONST_ATTR(in_temp_offset, "129 C"); static IIO_CONST_ATTR(in_temp_scale, "4 C"); -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAMP_FREQ(0644, ade7754_read_frequency, ade7754_write_frequency); -- cgit v1.2.3 From 78425b3290397686d888b16d43013142a62bc268 Mon Sep 17 00:00:00 2001 From: Quentin Swain Date: Sun, 30 Apr 2017 19:17:01 -0400 Subject: iio: ade7758: Convert symbolic permissions to octal Convert symbolic S_IRUGO and S_IWUSR macros to octal permissions to fix warnings reported by checkpatch.pl Signed-off-by: Quentin Swain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7758_core.c | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 99c89e606c8d..40498af4dc46 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -301,103 +301,103 @@ static int ade7758_reset(struct device *dev) return ret; } -static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VPEAK(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_VPEAK); -static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IPEAK(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_VPEAK); -static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APHCAL(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_APHCAL); -static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BPHCAL(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_BPHCAL); -static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CPHCAL(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_CPHCAL); -static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_WDIV(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_WDIV); -static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VADIV(0644, ade7758_read_8bit, ade7758_write_8bit, ADE7758_VADIV); -static IIO_DEV_ATTR_AIRMS(S_IRUGO, +static IIO_DEV_ATTR_AIRMS(0444, ade7758_read_24bit, NULL, ADE7758_AIRMS); -static IIO_DEV_ATTR_BIRMS(S_IRUGO, +static IIO_DEV_ATTR_BIRMS(0444, ade7758_read_24bit, NULL, ADE7758_BIRMS); -static IIO_DEV_ATTR_CIRMS(S_IRUGO, +static IIO_DEV_ATTR_CIRMS(0444, ade7758_read_24bit, NULL, ADE7758_CIRMS); -static IIO_DEV_ATTR_AVRMS(S_IRUGO, +static IIO_DEV_ATTR_AVRMS(0444, ade7758_read_24bit, NULL, ADE7758_AVRMS); -static IIO_DEV_ATTR_BVRMS(S_IRUGO, +static IIO_DEV_ATTR_BVRMS(0444, ade7758_read_24bit, NULL, ADE7758_BVRMS); -static IIO_DEV_ATTR_CVRMS(S_IRUGO, +static IIO_DEV_ATTR_CVRMS(0444, ade7758_read_24bit, NULL, ADE7758_CVRMS); -static IIO_DEV_ATTR_AIRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AIRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_AIRMSOS); -static IIO_DEV_ATTR_BIRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BIRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_BIRMSOS); -static IIO_DEV_ATTR_CIRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CIRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_CIRMSOS); -static IIO_DEV_ATTR_AVRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AVRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_AVRMSOS); -static IIO_DEV_ATTR_BVRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BVRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_BVRMSOS); -static IIO_DEV_ATTR_CVRMSOS(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CVRMSOS(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_CVRMSOS); -static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AIGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_AIGAIN); -static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BIGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_BIGAIN); -static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CIGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_CIGAIN); -static IIO_DEV_ATTR_AVRMSGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AVRMSGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_AVRMSGAIN); -static IIO_DEV_ATTR_BVRMSGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BVRMSGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_BVRMSGAIN); -static IIO_DEV_ATTR_CVRMSGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CVRMSGAIN(0644, ade7758_read_16bit, ade7758_write_16bit, ADE7758_CVRMSGAIN); -- cgit v1.2.3 From b46c39a09838bb87d412a6ad7427ea58bf99ae02 Mon Sep 17 00:00:00 2001 From: Quentin Swain Date: Sun, 30 Apr 2017 19:17:02 -0400 Subject: iio: ade7854: Convert symbolic permissions to octal Convert symbolic S_IRUGO and S_IWUSR macros to octal to fix warnings reported by checkpatch.pl Signed-off-by: Quentin Swain Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7854.c | 88 ++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c index c6cffc11b0ba..70612da64a8b 100644 --- a/drivers/staging/iio/meter/ade7854.c +++ b/drivers/staging/iio/meter/ade7854.c @@ -186,127 +186,127 @@ static int ade7854_reset(struct device *dev) return st->write_reg_16(dev, ADE7854_CONFIG, val); } -static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AIGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AIGAIN); -static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BIGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BIGAIN); -static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CIGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CIGAIN); -static IIO_DEV_ATTR_NIGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_NIGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_NIGAIN); -static IIO_DEV_ATTR_AVGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_AVGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AVGAIN); -static IIO_DEV_ATTR_BVGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BVGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BVGAIN); -static IIO_DEV_ATTR_CVGAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CVGAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CVGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AVAGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BVAGAIN); -static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CVAGAIN); -static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AWATTOS); -static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BWATTOS); -static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CWATTOS); -static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CVARGAIN); -static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_AVAROS); -static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_BVAROS); -static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(0644, ade7854_read_24bit, ade7854_write_24bit, ADE7854_CVAROS); -static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_VPEAK(0644, ade7854_read_32bit, ade7854_write_32bit, ADE7854_VPEAK); -static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_IPEAK(0644, ade7854_read_32bit, ade7854_write_32bit, ADE7854_VPEAK); -static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_APHCAL(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_APHCAL); -static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_BPHCAL(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_BPHCAL); -static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CPHCAL(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CPHCAL); -static IIO_DEV_ATTR_CF1DEN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CF1DEN(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CF1DEN); -static IIO_DEV_ATTR_CF2DEN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CF2DEN(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CF2DEN); -static IIO_DEV_ATTR_CF3DEN(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CF3DEN(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CF3DEN); -static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_LINECYC(0644, ade7854_read_16bit, ade7854_write_16bit, ADE7854_LINECYC); -static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_SAGCYC(0644, ade7854_read_8bit, ade7854_write_8bit, ADE7854_SAGCYC); -static IIO_DEV_ATTR_CFCYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_CFCYC(0644, ade7854_read_8bit, ade7854_write_8bit, ADE7854_CFCYC); -static IIO_DEV_ATTR_PEAKCYC(S_IWUSR | S_IRUGO, +static IIO_DEV_ATTR_PEAKCYC(0644, ade7854_read_8bit, ade7854_write_8bit, ADE7854_PEAKCYC); @@ -318,55 +318,55 @@ static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit, ADE7854_ANGLE1); static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit, ADE7854_ANGLE2); -static IIO_DEV_ATTR_AIRMS(S_IRUGO, +static IIO_DEV_ATTR_AIRMS(0444, ade7854_read_24bit, NULL, ADE7854_AIRMS); -static IIO_DEV_ATTR_BIRMS(S_IRUGO, +static IIO_DEV_ATTR_BIRMS(0444, ade7854_read_24bit, NULL, ADE7854_BIRMS); -static IIO_DEV_ATTR_CIRMS(S_IRUGO, +static IIO_DEV_ATTR_CIRMS(0444, ade7854_read_24bit, NULL, ADE7854_CIRMS); -static IIO_DEV_ATTR_NIRMS(S_IRUGO, +static IIO_DEV_ATTR_NIRMS(0444, ade7854_read_24bit, NULL, ADE7854_NIRMS); -static IIO_DEV_ATTR_AVRMS(S_IRUGO, +static IIO_DEV_ATTR_AVRMS(0444, ade7854_read_24bit, NULL, ADE7854_AVRMS); -static IIO_DEV_ATTR_BVRMS(S_IRUGO, +static IIO_DEV_ATTR_BVRMS(0444, ade7854_read_24bit, NULL, ADE7854_BVRMS); -static IIO_DEV_ATTR_CVRMS(S_IRUGO, +static IIO_DEV_ATTR_CVRMS(0444, ade7854_read_24bit, NULL, ADE7854_CVRMS); -static IIO_DEV_ATTR_AIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_AIRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_AIRMSOS); -static IIO_DEV_ATTR_BIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_BIRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_BIRMSOS); -static IIO_DEV_ATTR_CIRMSOS(S_IRUGO, +static IIO_DEV_ATTR_CIRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CIRMSOS); -static IIO_DEV_ATTR_AVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_AVRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_AVRMSOS); -static IIO_DEV_ATTR_BVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_BVRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_BVRMSOS); -static IIO_DEV_ATTR_CVRMSOS(S_IRUGO, +static IIO_DEV_ATTR_CVRMSOS(0444, ade7854_read_16bit, ade7854_write_16bit, ADE7854_CVRMSOS); -- cgit v1.2.3 From 9ff88edc5e7bad08bdd79a20f14533a5cf44b865 Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Sun, 7 May 2017 18:24:24 +0800 Subject: iio: hid-sensor-rotation: Add relative orientation sensor hid support Relative orientation(AG) sensor is a 6dof orientation sensor, it depends on acceleration and gyroscope sensor data. It gives a quaternion describing the orientation of the device relative to an initial orientation. It is a standard HID sensor. More information can be found in: http://www.usb.org/developers/hidpage/HUTRR59_-_Usages_for_Wearables.pdf Relative orientation(AG) sensor and dev rotation sensor have same channels and share channel usage id. So the most of the code for relative orientation sensor can be reused. Signed-off-by: Song Hongyan Reviewed-by: Andy Shevchenko Reviewed-by: Xu Even Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-rotation.c | 28 +++++++++++++++++++-------- include/linux/hid-sensor-ids.h | 1 + 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index a97e802ca523..4d953c26325f 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -218,7 +218,7 @@ static int dev_rot_parse_report(struct platform_device *pdev, static int hid_dev_rot_probe(struct platform_device *pdev) { int ret; - static char *name = "dev_rotation"; + static char *name; struct iio_dev *indio_dev; struct dev_rot_state *rot_state; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; @@ -234,8 +234,18 @@ static int hid_dev_rot_probe(struct platform_device *pdev) rot_state->common_attributes.hsdev = hsdev; rot_state->common_attributes.pdev = pdev; - ret = hid_sensor_parse_common_attributes(hsdev, - HID_USAGE_SENSOR_DEVICE_ORIENTATION, + switch (hsdev->usage) { + case HID_USAGE_SENSOR_DEVICE_ORIENTATION: + name = "dev_rotation"; + break; + case HID_USAGE_SENSOR_RELATIVE_ORIENTATION: + name = "relative_orientation"; + break; + default: + return -EINVAL; + } + + ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage, &rot_state->common_attributes); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); @@ -252,8 +262,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev) ret = dev_rot_parse_report(pdev, hsdev, (struct iio_chan_spec *)indio_dev->channels, - HID_USAGE_SENSOR_DEVICE_ORIENTATION, - rot_state); + hsdev->usage, rot_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); return ret; @@ -288,8 +297,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev) rot_state->callbacks.send_event = dev_rot_proc_event; rot_state->callbacks.capture_sample = dev_rot_capture_sample; rot_state->callbacks.pdev = pdev; - ret = sensor_hub_register_callback(hsdev, - HID_USAGE_SENSOR_DEVICE_ORIENTATION, + ret = sensor_hub_register_callback(hsdev, hsdev->usage, &rot_state->callbacks); if (ret) { dev_err(&pdev->dev, "callback reg failed\n"); @@ -314,7 +322,7 @@ static int hid_dev_rot_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct dev_rot_state *rot_state = iio_priv(indio_dev); - sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_DEVICE_ORIENTATION); + sensor_hub_remove_callback(hsdev, hsdev->usage); iio_device_unregister(indio_dev); hid_sensor_remove_trigger(&rot_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); @@ -327,6 +335,10 @@ static const struct platform_device_id hid_dev_rot_ids[] = { /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ .name = "HID-SENSOR-20008a", }, + { + /* Relative orientation(AG) sensor */ + .name = "HID-SENSOR-20008e", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 761f86242473..b5469e878e99 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -90,6 +90,7 @@ #define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481 #define HID_USAGE_SENSOR_DEVICE_ORIENTATION 0x20008A +#define HID_USAGE_SENSOR_RELATIVE_ORIENTATION 0x20008E #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 -- cgit v1.2.3 From 00907c7a3282053dd4782e02c3101809608e7ea7 Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Sun, 7 May 2017 18:24:25 +0800 Subject: iio: hid-sensor-rotation: Add geomagnetic orientation sensor hid support. Geomagnetic orientation(AM) sensor is one kind of orientation 6dof sensor. It gives the device rotation in respect to the earth center and the magnetic north. The sensor is implemented through use of an accelerometer and magnetometer do not use gyroscope. It is a standard HID sensor. More information can be found in: http://www.usb.org/developers/hidpage/HUTRR59_-_Usages_for_Wearables.pdf Geomagnetic orientation(AM) sensor and dev rotation sensor have same channel and share channel usage id. So the most of the code for relative orientation sensor can be reused. Signed-off-by: Song Hongyan Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-rotation.c | 7 +++++++ include/linux/hid-sensor-ids.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 4d953c26325f..60d3517a78af 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -241,6 +241,9 @@ static int hid_dev_rot_probe(struct platform_device *pdev) case HID_USAGE_SENSOR_RELATIVE_ORIENTATION: name = "relative_orientation"; break; + case HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION: + name = "geomagnetic_orientation"; + break; default: return -EINVAL; } @@ -339,6 +342,10 @@ static const struct platform_device_id hid_dev_rot_ids[] = { /* Relative orientation(AG) sensor */ .name = "HID-SENSOR-20008e", }, + { + /* Geomagnetic orientation(AM) sensor */ + .name = "HID-SENSOR-2000c1", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index b5469e878e99..5af62c7e49f3 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -91,6 +91,7 @@ #define HID_USAGE_SENSOR_DEVICE_ORIENTATION 0x20008A #define HID_USAGE_SENSOR_RELATIVE_ORIENTATION 0x20008E +#define HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION 0x2000C1 #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 -- cgit v1.2.3 From a78587d338d084037b0ea6687508f207d8dec2fb Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Sun, 7 May 2017 18:24:26 +0800 Subject: iio: hid-sensor-rotation: Add "scale" and "offset" properties parse support Add orientation sensor "scale" and "offset" parse support. These two properties are needed for exponent data conversion. Signed-off-by: Song Hongyan Reviewed-by: Andy Shevchenko Reviewed-by: Xu Even Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- .../iio/common/hid-sensors/hid-sensor-attributes.c | 6 ++++++ drivers/iio/orientation/hid-sensor-rotation.c | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index aeb09a85d7a8..0e05f6d1e761 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -69,6 +69,12 @@ static struct { {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND, 1000000, 0}, + {HID_USAGE_SENSOR_DEVICE_ORIENTATION, 0, 1, 0}, + + {HID_USAGE_SENSOR_RELATIVE_ORIENTATION, 0, 1, 0}, + + {HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION, 0, 1, 0}, + {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0}, {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0}, diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 60d3517a78af..e9fa86c87db5 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -31,6 +31,10 @@ struct dev_rot_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info quaternion; u32 sampled_vals[4]; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; /* Channel definitions */ @@ -41,6 +45,8 @@ static const struct iio_chan_spec dev_rot_channels[] = { .channel2 = IIO_MOD_QUATERNION, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_HYSTERESIS) } }; @@ -80,6 +86,15 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev, } else ret_type = -EINVAL; break; + case IIO_CHAN_INFO_SCALE: + vals[0] = rot_state->scale_pre_decml; + vals[1] = rot_state->scale_post_decml; + return rot_state->scale_precision; + + case IIO_CHAN_INFO_OFFSET: + *vals = rot_state->value_offset; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: ret_type = hid_sensor_read_samp_freq_value( &rot_state->common_attributes, &vals[0], &vals[1]); @@ -199,6 +214,11 @@ static int dev_rot_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "dev_rot: attrib size %d\n", st->quaternion.size); + st->scale_precision = hid_sensor_format_scale( + hsdev->usage, + &st->quaternion, + &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, -- cgit v1.2.3 From c1c2de37c7bef8d335ad9483fd560311b9aa45de Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 6 May 2017 15:49:27 +0200 Subject: iio: adc: meson-saradc: mark all meson_sar_adc_data static and const These are only passed as of_device_id.data and never modified. Thus we can mark them as static const, just like the of_device_id instances where they are used. Signed-off-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index dd4190b50df6..2f6fec995264 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -834,17 +834,17 @@ static const struct iio_info meson_sar_adc_iio_info = { .driver_module = THIS_MODULE, }; -struct meson_sar_adc_data meson_sar_adc_gxbb_data = { +static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { .resolution = 10, .name = "meson-gxbb-saradc", }; -struct meson_sar_adc_data meson_sar_adc_gxl_data = { +static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { .resolution = 12, .name = "meson-gxl-saradc", }; -struct meson_sar_adc_data meson_sar_adc_gxm_data = { +static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { .resolution = 12, .name = "meson-gxm-saradc", }; -- cgit v1.2.3 From 400fd3a13310a7128d86ff99ec121c915f8f10bc Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 6 May 2017 15:49:28 +0200 Subject: dt-bindings: iio: adc: add Meson8 and Meson8b support The Amlogic Meson SAR ADC driver can be used on Meson8 and Meson8b (probably on earlier SoC generations as well, but I don't have any hardware available for testing that). Add a separate compatible for Meson8 and Meson8b because it does not need any of the BL30 magic (unlike the GX SoCs). Signed-off-by: Martin Blumenstingl Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt index 047189192aec..f413e82c8b83 100644 --- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -2,6 +2,8 @@ Required properties: - compatible: depending on the SoC this should be one of: + - "amlogic,meson8-saradc" for Meson8 + - "amlogic,meson8b-saradc" for Meson8b - "amlogic,meson-gxbb-saradc" for GXBB - "amlogic,meson-gxl-saradc" for GXL - "amlogic,meson-gxm-saradc" for GXM -- cgit v1.2.3 From 6c76ed31cd05add11f89d017a8de956935083d3b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 6 May 2017 15:49:29 +0200 Subject: iio: adc: meson-saradc: add Meson8b SoC compatibility Meson GX SoCs however use some magic bits to prevent simultaneous (= conflicting, because only consumer should use the FIFO buffer with the ADC results) usage by the Linux kernel and the bootloader (the BL30 bootloader uses the SAR ADC to read the CPU temperature). This patch changes guards all BL30 functionality so it is skipped on SoCs which don't have it. Since the hardware itself doesn't know whether BL30 is available the internal meson_sar_adc_data is extended so this information can be provided per of_device_id.data inside the driver. Additionally the clocks "adc_clk" and "adc_sel" are not provided by the clock-controller itself. "adc_sel" is not available at all. "adc_clk" is provided by the SAR ADC IP block itself on Meson8b (and earlier). This is already supported by the meson_saradc driver. Finally this introduces new of_device_ids for the Meson8 and Meson8b SoCs so the driver can be wired up in the corresponding DT. Signed-off-by: Martin Blumenstingl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/meson_saradc.c | 80 +++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 2f6fec995264..81cd39a57fe3 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -220,6 +220,7 @@ enum meson_sar_adc_chan7_mux_sel { }; struct meson_sar_adc_data { + bool has_bl30_integration; unsigned int resolution; const char *name; }; @@ -437,19 +438,24 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev) mutex_lock(&indio_dev->mlock); - /* prevent BL30 from using the SAR ADC while we are using it */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY); - - /* wait until BL30 releases it's lock (so we can use the SAR ADC) */ - do { - udelay(1); - regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); - } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); - - if (timeout < 0) - return -ETIMEDOUT; + if (priv->data->has_bl30_integration) { + /* prevent BL30 from using the SAR ADC while we are using it */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); + + /* + * wait until BL30 releases it's lock (so we can use the SAR + * ADC) + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + } return 0; } @@ -458,9 +464,10 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev) { struct meson_sar_adc_priv *priv = iio_priv(indio_dev); - /* allow BL30 to use the SAR ADC again */ - regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, - MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + if (priv->data->has_bl30_integration) + /* allow BL30 to use the SAR ADC again */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); mutex_unlock(&indio_dev->mlock); } @@ -614,14 +621,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev) */ meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); - /* - * leave sampling delay and the input clocks as configured by BL30 to - * make sure BL30 gets the values it expects when reading the - * temperature sensor. - */ - regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); - if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) - return 0; + if (priv->data->has_bl30_integration) { + /* + * leave sampling delay and the input clocks as configured by + * BL30 to make sure BL30 gets the values it expects when + * reading the temperature sensor. + */ + regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); + if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) + return 0; + } meson_sar_adc_stop_sample_engine(indio_dev); @@ -834,22 +843,45 @@ static const struct iio_info meson_sar_adc_iio_info = { .driver_module = THIS_MODULE, }; +static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { + .has_bl30_integration = false, + .resolution = 10, + .name = "meson-meson8-saradc", +}; + +static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { + .has_bl30_integration = false, + .resolution = 10, + .name = "meson-meson8b-saradc", +}; + static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { + .has_bl30_integration = true, .resolution = 10, .name = "meson-gxbb-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { + .has_bl30_integration = true, .resolution = 12, .name = "meson-gxl-saradc", }; static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { + .has_bl30_integration = true, .resolution = 12, .name = "meson-gxm-saradc", }; static const struct of_device_id meson_sar_adc_of_match[] = { + { + .compatible = "amlogic,meson8-saradc", + .data = &meson_sar_adc_meson8_data, + }, + { + .compatible = "amlogic,meson8b-saradc", + .data = &meson_sar_adc_meson8b_data, + }, { .compatible = "amlogic,meson-gxbb-saradc", .data = &meson_sar_adc_gxbb_data, -- cgit v1.2.3 From 535fba29b3e1afef4ba201b3c69a6992583ec0bd Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 5 May 2017 18:28:28 -0700 Subject: iio: temperature: maxim_thermocouple: add MAX31856 part MAX31856 is register equivalent to the MAX31855 but suppports J, N, R, S, T, E and B type thermocouples in addition to K-type. Data conversion for the various types happens transparently to the driver via probe type detection, and a LUT on the sensor. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 557214202eff..d70e2e53d6a7 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -267,6 +267,7 @@ static int maxim_thermocouple_remove(struct spi_device *spi) static const struct spi_device_id maxim_thermocouple_id[] = { {"max6675", MAX6675}, {"max31855", MAX31855}, + {"max31856", MAX31855}, {}, }; MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id); -- cgit v1.2.3 From 38a67ffd44fc013437f83e96612c5210499ba02a Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 4 May 2017 20:38:22 -0400 Subject: staging: iio: tsl2x7x: rename driver for consistency with other IIO light drivers This patch renames the tsl2x7x_core.c file to tsl2x7x.c so that the naming convention is consistent with other IIO light drivers outside of staging. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/Makefile | 2 +- drivers/staging/iio/light/tsl2x7x.c | 2063 ++++++++++++++++++++++++++++++ drivers/staging/iio/light/tsl2x7x_core.c | 2063 ------------------------------ 3 files changed, 2064 insertions(+), 2064 deletions(-) create mode 100644 drivers/staging/iio/light/tsl2x7x.c delete mode 100644 drivers/staging/iio/light/tsl2x7x_core.c diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 10286c3ee6fe..ab8dc3a3d10b 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -2,4 +2,4 @@ # Makefile for industrial I/O Light sensors # -obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o +obj-$(CONFIG_TSL2x7x) += tsl2x7x.o diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c new file mode 100644 index 000000000000..8121a5188638 --- /dev/null +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -0,0 +1,2063 @@ +/* + * Device driver for monitoring ambient light intensity in (lux) + * and proximity detection (prox) within the TAOS TSL2X7X family of devices. + * + * Copyright (c) 2012, TAOS Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tsl2x7x.h" + +/* Cal defs*/ +#define PROX_STAT_CAL 0 +#define PROX_STAT_SAMP 1 +#define MAX_SAMPLES_CAL 200 + +/* TSL2X7X Device ID */ +#define TRITON_ID 0x00 +#define SWORDFISH_ID 0x30 +#define HALIBUT_ID 0x20 + +/* Lux calculation constants */ +#define TSL2X7X_LUX_CALC_OVER_FLOW 65535 + +/* TAOS Register definitions - note: + * depending on device, some of these register are not used and the + * register address is benign. + */ +/* 2X7X register offsets */ +#define TSL2X7X_MAX_CONFIG_REG 16 + +/* Device Registers and Masks */ +#define TSL2X7X_CNTRL 0x00 +#define TSL2X7X_ALS_TIME 0X01 +#define TSL2X7X_PRX_TIME 0x02 +#define TSL2X7X_WAIT_TIME 0x03 +#define TSL2X7X_ALS_MINTHRESHLO 0X04 +#define TSL2X7X_ALS_MINTHRESHHI 0X05 +#define TSL2X7X_ALS_MAXTHRESHLO 0X06 +#define TSL2X7X_ALS_MAXTHRESHHI 0X07 +#define TSL2X7X_PRX_MINTHRESHLO 0X08 +#define TSL2X7X_PRX_MINTHRESHHI 0X09 +#define TSL2X7X_PRX_MAXTHRESHLO 0X0A +#define TSL2X7X_PRX_MAXTHRESHHI 0X0B +#define TSL2X7X_PERSISTENCE 0x0C +#define TSL2X7X_PRX_CONFIG 0x0D +#define TSL2X7X_PRX_COUNT 0x0E +#define TSL2X7X_GAIN 0x0F +#define TSL2X7X_NOTUSED 0x10 +#define TSL2X7X_REVID 0x11 +#define TSL2X7X_CHIPID 0x12 +#define TSL2X7X_STATUS 0x13 +#define TSL2X7X_ALS_CHAN0LO 0x14 +#define TSL2X7X_ALS_CHAN0HI 0x15 +#define TSL2X7X_ALS_CHAN1LO 0x16 +#define TSL2X7X_ALS_CHAN1HI 0x17 +#define TSL2X7X_PRX_LO 0x18 +#define TSL2X7X_PRX_HI 0x19 + +/* tsl2X7X cmd reg masks */ +#define TSL2X7X_CMD_REG 0x80 +#define TSL2X7X_CMD_SPL_FN 0x60 + +#define TSL2X7X_CMD_PROX_INT_CLR 0X05 +#define TSL2X7X_CMD_ALS_INT_CLR 0x06 +#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07 + +/* tsl2X7X cntrl reg masks */ +#define TSL2X7X_CNTL_ADC_ENBL 0x02 +#define TSL2X7X_CNTL_PWR_ON 0x01 + +/* tsl2X7X status reg masks */ +#define TSL2X7X_STA_ADC_VALID 0x01 +#define TSL2X7X_STA_PRX_VALID 0x02 +#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\ + TSL2X7X_STA_PRX_VALID) +#define TSL2X7X_STA_ALS_INTR 0x10 +#define TSL2X7X_STA_PRX_INTR 0x20 + +/* tsl2X7X cntrl reg masks */ +#define TSL2X7X_CNTL_REG_CLEAR 0x00 +#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20 +#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10 +#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08 +#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04 +#define TSL2X7X_CNTL_PWRON 0x01 +#define TSL2X7X_CNTL_ALSPON_ENBL 0x03 +#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13 +#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F +#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F + +/*Prox diode to use */ +#define TSL2X7X_DIODE0 0x10 +#define TSL2X7X_DIODE1 0x20 +#define TSL2X7X_DIODE_BOTH 0x30 + +/* LED Power */ +#define TSL2X7X_mA100 0x00 +#define TSL2X7X_mA50 0x40 +#define TSL2X7X_mA25 0x80 +#define TSL2X7X_mA13 0xD0 +#define TSL2X7X_MAX_TIMER_CNT (0xFF) + +#define TSL2X7X_MIN_ITIME 3 + +/* TAOS txx2x7x Device family members */ +enum { + tsl2571, + tsl2671, + tmd2671, + tsl2771, + tmd2771, + tsl2572, + tsl2672, + tmd2672, + tsl2772, + tmd2772 +}; + +enum { + TSL2X7X_CHIP_UNKNOWN = 0, + TSL2X7X_CHIP_WORKING = 1, + TSL2X7X_CHIP_SUSPENDED = 2 +}; + +struct tsl2x7x_parse_result { + int integer; + int fract; +}; + +/* Per-device data */ +struct tsl2x7x_als_info { + u16 als_ch0; + u16 als_ch1; + u16 lux; +}; + +struct tsl2x7x_prox_stat { + int min; + int max; + int mean; + unsigned long stddev; +}; + +struct tsl2x7x_chip_info { + int chan_table_elements; + struct iio_chan_spec channel[4]; + const struct iio_info *info; +}; + +struct tsl2X7X_chip { + kernel_ulong_t id; + struct mutex prox_mutex; + struct mutex als_mutex; + struct i2c_client *client; + u16 prox_data; + struct tsl2x7x_als_info als_cur_info; + struct tsl2x7x_settings tsl2x7x_settings; + struct tsl2X7X_platform_data *pdata; + int als_time_scale; + int als_saturation; + int tsl2x7x_chip_status; + u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG]; + const struct tsl2x7x_chip_info *chip_info; + const struct iio_info *info; + s64 event_timestamp; + /* + * This structure is intentionally large to accommodate + * updates via sysfs. + * Sized to 9 = max 8 segments + 1 termination segment + */ + struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE]; +}; + +/* Different devices require different coefficents */ +static const struct tsl2x7x_lux tsl2x71_lux_table[] = { + { 14461, 611, 1211 }, + { 18540, 352, 623 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tmd2x71_lux_table[] = { + { 11635, 115, 256 }, + { 15536, 87, 179 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tsl2x72_lux_table[] = { + { 14013, 466, 917 }, + { 18222, 310, 552 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux tmd2x72_lux_table[] = { + { 13218, 130, 262 }, + { 17592, 92, 169 }, + { 0, 0, 0 }, +}; + +static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { + [tsl2571] = tsl2x71_lux_table, + [tsl2671] = tsl2x71_lux_table, + [tmd2671] = tmd2x71_lux_table, + [tsl2771] = tsl2x71_lux_table, + [tmd2771] = tmd2x71_lux_table, + [tsl2572] = tsl2x72_lux_table, + [tsl2672] = tsl2x72_lux_table, + [tmd2672] = tmd2x72_lux_table, + [tsl2772] = tsl2x72_lux_table, + [tmd2772] = tmd2x72_lux_table, +}; + +static const struct tsl2x7x_settings tsl2x7x_default_settings = { + .als_time = 219, /* 101 ms */ + .als_gain = 0, + .prx_time = 254, /* 5.4 ms */ + .prox_gain = 1, + .wait_time = 245, + .prox_config = 0, + .als_gain_trim = 1000, + .als_cal_target = 150, + .als_thresh_low = 200, + .als_thresh_high = 256, + .persistence = 255, + .interrupts_en = 0, + .prox_thres_low = 0, + .prox_thres_high = 512, + .prox_max_samples_cal = 30, + .prox_pulse_count = 8 +}; + +static const s16 tsl2X7X_als_gainadj[] = { + 1, + 8, + 16, + 120 +}; + +static const s16 tsl2X7X_prx_gainadj[] = { + 1, + 2, + 4, + 8 +}; + +/* Channel variations */ +enum { + ALS, + PRX, + ALSPRX, + PRX2, + ALSPRX2, +}; + +static const u8 device_channel_config[] = { + ALS, + PRX, + PRX, + ALSPRX, + ALSPRX, + ALS, + PRX2, + PRX2, + ALSPRX2, + ALSPRX2 +}; + +/** + * tsl2x7x_i2c_read() - Read a byte from a register. + * @client: i2c client + * @reg: device register to read from + * @*val: pointer to location to store register contents. + * + */ +static int +tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val) +{ + int ret; + + /* select register to write */ + ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); + if (ret < 0) { + dev_err(&client->dev, "failed to write register %x\n", reg); + return ret; + } + + /* read the data */ + ret = i2c_smbus_read_byte(client); + if (ret >= 0) + *val = (u8)ret; + else + dev_err(&client->dev, "failed to read register %x\n", reg); + + return ret; +} + +/** + * tsl2x7x_get_lux() - Reads and calculates current lux value. + * @indio_dev: pointer to IIO device + * + * The raw ch0 and ch1 values of the ambient light sensed in the last + * integration cycle are read from the device. + * Time scale factor array values are adjusted based on the integration time. + * The raw values are multiplied by a scale factor, and device gain is obtained + * using gain index. Limit checks are done next, then the ratio of a multiple + * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[] + * is then scanned to find the first ratio value that is just above the ratio + * we just calculated. The ch0 and ch1 multiplier constants in the array are + * then used along with the time scale factor array values, to calculate the + * lux. + */ +static int tsl2x7x_get_lux(struct iio_dev *indio_dev) +{ + u16 ch0, ch1; /* separated ch0/ch1 data from device */ + u32 lux; /* raw lux calculated from device data */ + u64 lux64; + u32 ratio; + u8 buf[4]; + struct tsl2x7x_lux *p; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int i, ret; + u32 ch0lux = 0; + u32 ch1lux = 0; + + if (mutex_trylock(&chip->als_mutex) == 0) + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ + + if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { + /* device is not enabled */ + dev_err(&chip->client->dev, "%s: device is not enabled\n", + __func__); + ret = -EBUSY; + goto out_unlock; + } + + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: Failed to read STATUS Reg\n", __func__); + goto out_unlock; + } + /* is data new & valid */ + if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) { + dev_err(&chip->client->dev, + "%s: data not valid yet\n", __func__); + ret = chip->als_cur_info.lux; /* return LAST VALUE */ + goto out_unlock; + } + + for (i = 0; i < 4; i++) { + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | + (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]); + if (ret < 0) { + dev_err(&chip->client->dev, + "failed to read. err=%x\n", ret); + goto out_unlock; + } + } + + /* clear any existing interrupt status */ + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | + TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_ALS_INT_CLR)); + if (ret < 0) { + dev_err(&chip->client->dev, + "i2c_write_command failed - err = %d\n", ret); + goto out_unlock; /* have no data, so return failure */ + } + + /* extract ALS/lux data */ + ch0 = le16_to_cpup((const __le16 *)&buf[0]); + ch1 = le16_to_cpup((const __le16 *)&buf[2]); + + chip->als_cur_info.als_ch0 = ch0; + chip->als_cur_info.als_ch1 = ch1; + + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) { + lux = TSL2X7X_LUX_CALC_OVER_FLOW; + goto return_max; + } + + if (!ch0) { + /* have no data, so return LAST VALUE */ + ret = chip->als_cur_info.lux; + goto out_unlock; + } + /* calculate ratio */ + ratio = (ch1 << 15) / ch0; + /* convert to unscaled lux using the pointer to the table */ + p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; + while (p->ratio != 0 && p->ratio < ratio) + p++; + + if (p->ratio == 0) { + lux = 0; + } else { + ch0lux = DIV_ROUND_UP(ch0 * p->ch0, + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); + ch1lux = DIV_ROUND_UP(ch1 * p->ch1, + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); + lux = ch0lux - ch1lux; + } + + /* note: lux is 31 bit max at this point */ + if (ch1lux > ch0lux) { + dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n"); + ret = chip->als_cur_info.lux; + goto out_unlock; + } + + /* adjust for active time scale */ + if (chip->als_time_scale == 0) + lux = 0; + else + lux = (lux + (chip->als_time_scale >> 1)) / + chip->als_time_scale; + + /* adjust for active gain scale + * The tsl2x7x_device_lux tables have a factor of 256 built-in. + * User-specified gain provides a multiplier. + * Apply user-specified gain before shifting right to retain precision. + * Use 64 bits to avoid overflow on multiplication. + * Then go back to 32 bits before division to avoid using div_u64(). + */ + + lux64 = lux; + lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim; + lux64 >>= 8; + lux = lux64; + lux = (lux + 500) / 1000; + + if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */ + lux = TSL2X7X_LUX_CALC_OVER_FLOW; + + /* Update the structure with the latest lux. */ +return_max: + chip->als_cur_info.lux = lux; + ret = lux; + +out_unlock: + mutex_unlock(&chip->als_mutex); + + return ret; +} + +/** + * tsl2x7x_get_prox() - Reads proximity data registers and updates + * chip->prox_data. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2x7x_get_prox(struct iio_dev *indio_dev) +{ + int i; + int ret; + u8 status; + u8 chdata[2]; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (mutex_trylock(&chip->prox_mutex) == 0) { + dev_err(&chip->client->dev, + "%s: Can't get prox mutex\n", __func__); + return -EBUSY; + } + + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status); + if (ret < 0) { + dev_err(&chip->client->dev, "i2c err=%d\n", ret); + goto prox_poll_err; + } + + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + if (!(status & TSL2X7X_STA_ADC_VALID)) + goto prox_poll_err; + break; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + if (!(status & TSL2X7X_STA_PRX_VALID)) + goto prox_poll_err; + break; + } + + for (i = 0; i < 2; i++) { + ret = tsl2x7x_i2c_read(chip->client, + (TSL2X7X_CMD_REG | + (TSL2X7X_PRX_LO + i)), &chdata[i]); + if (ret < 0) + goto prox_poll_err; + } + + chip->prox_data = + le16_to_cpup((const __le16 *)&chdata[0]); + +prox_poll_err: + + mutex_unlock(&chip->prox_mutex); + + return chip->prox_data; +} + +/** + * tsl2x7x_defaults() - Populates the device nominal operating parameters + * with those provided by a 'platform' data struct or + * with prefined defaults. + * + * @chip: pointer to device structure. + */ +static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) +{ + /* If Operational settings defined elsewhere.. */ + if (chip->pdata && chip->pdata->platform_default_settings) + memcpy(&chip->tsl2x7x_settings, + chip->pdata->platform_default_settings, + sizeof(tsl2x7x_default_settings)); + else + memcpy(&chip->tsl2x7x_settings, + &tsl2x7x_default_settings, + sizeof(tsl2x7x_default_settings)); + + /* Load up the proper lux table. */ + if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0) + memcpy(chip->tsl2x7x_device_lux, + chip->pdata->platform_lux_table, + sizeof(chip->pdata->platform_lux_table)); + else + memcpy(chip->tsl2x7x_device_lux, + (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id], + MAX_DEFAULT_TABLE_BYTES); +} + +/** + * tsl2x7x_als_calibrate() - Obtain single reading and calculate + * the als_gain_trim. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 reg_val; + int gain_trim_val; + int ret; + int lux_val; + + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&chip->client->dev, + "failed to write CNTRL register, ret=%d\n", ret); + return ret; + } + + reg_val = i2c_smbus_read_byte(chip->client); + if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) + != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { + dev_err(&chip->client->dev, + "%s: failed: ADC not enabled\n", __func__); + return -1; + } + + ret = i2c_smbus_write_byte(chip->client, + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&chip->client->dev, + "failed to write ctrl reg: ret=%d\n", ret); + return ret; + } + + reg_val = i2c_smbus_read_byte(chip->client); + if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { + dev_err(&chip->client->dev, + "%s: failed: STATUS - ADC not valid.\n", __func__); + return -ENODATA; + } + + lux_val = tsl2x7x_get_lux(indio_dev); + if (lux_val < 0) { + dev_err(&chip->client->dev, + "%s: failed to get lux\n", __func__); + return lux_val; + } + + gain_trim_val = ((chip->tsl2x7x_settings.als_cal_target) + * chip->tsl2x7x_settings.als_gain_trim) / lux_val; + if ((gain_trim_val < 250) || (gain_trim_val > 4000)) + return -ERANGE; + + chip->tsl2x7x_settings.als_gain_trim = gain_trim_val; + dev_info(&chip->client->dev, + "%s als_calibrate completed\n", chip->client->name); + + return (int)gain_trim_val; +} + +static int tsl2x7x_chip_on(struct iio_dev *indio_dev) +{ + int i; + int ret = 0; + u8 *dev_reg; + u8 utmp; + int als_count; + int als_time; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 reg_val = 0; + + if (chip->pdata && chip->pdata->power_on) + chip->pdata->power_on(indio_dev); + + /* Non calculated parameters */ + chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = + chip->tsl2x7x_settings.prx_time; + chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = + chip->tsl2x7x_settings.wait_time; + chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = + chip->tsl2x7x_settings.prox_config; + + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = + (chip->tsl2x7x_settings.als_thresh_low) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] = + (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] = + (chip->tsl2x7x_settings.als_thresh_high) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = + (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = + chip->tsl2x7x_settings.persistence; + + chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = + chip->tsl2x7x_settings.prox_pulse_count; + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = + (chip->tsl2x7x_settings.prox_thres_low) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] = + (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = + (chip->tsl2x7x_settings.prox_thres_high) & 0xFF; + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] = + (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF; + + /* and make sure we're not already on */ + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { + /* if forcing a register update - turn off, then on */ + dev_info(&chip->client->dev, "device is already enabled\n"); + return -EINVAL; + } + + /* determine als integration register */ + als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270; + if (!als_count) + als_count = 1; /* ensure at least one cycle */ + + /* convert back to time (encompasses overrides) */ + als_time = (als_count * 27 + 5) / 10; + chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; + + /* Set the gain based on tsl2x7x_settings struct */ + chip->tsl2x7x_config[TSL2X7X_GAIN] = + chip->tsl2x7x_settings.als_gain | + (TSL2X7X_mA100 | TSL2X7X_DIODE1) + | ((chip->tsl2x7x_settings.prox_gain) << 2); + + /* set chip struct re scaling and saturation */ + chip->als_saturation = als_count * 922; /* 90% of full scale */ + chip->als_time_scale = (als_time + 25) / 50; + + /* + * TSL2X7X Specific power-on / adc enable sequence + * Power on the device 1st. + */ + utmp = TSL2X7X_CNTL_PWR_ON; + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed on CNTRL reg.\n", __func__); + return ret; + } + + /* + * Use the following shadow copy for our delay before enabling ADC. + * Write all the registers. + */ + for (i = 0, dev_reg = chip->tsl2x7x_config; + i < TSL2X7X_MAX_CONFIG_REG; i++) { + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG + i, + *dev_reg++); + if (ret < 0) { + dev_err(&chip->client->dev, + "failed on write to reg %d.\n", i); + return ret; + } + } + + mdelay(3); /* Power-on settling time */ + + /* + * NOW enable the ADC + * initialize the desired mode of operation + */ + utmp = TSL2X7X_CNTL_PWR_ON | + TSL2X7X_CNTL_ADC_ENBL | + TSL2X7X_CNTL_PROX_DET_ENBL; + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed on 2nd CTRL reg.\n", __func__); + return ret; + } + + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; + + if (chip->tsl2x7x_settings.interrupts_en != 0) { + dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); + + reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL; + if ((chip->tsl2x7x_settings.interrupts_en == 0x20) || + (chip->tsl2x7x_settings.interrupts_en == 0x30)) + reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL; + + reg_val |= chip->tsl2x7x_settings.interrupts_en; + ret = i2c_smbus_write_byte_data(chip->client, + (TSL2X7X_CMD_REG | + TSL2X7X_CNTRL), reg_val); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed in tsl2x7x_IOCTL_INT_SET.\n", + __func__); + + /* Clear out any initial interrupts */ + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | + TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: Failed to clear Int status\n", + __func__); + return ret; + } + } + + return ret; +} + +static int tsl2x7x_chip_off(struct iio_dev *indio_dev) +{ + int ret; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + /* turn device off */ + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; + + ret = i2c_smbus_write_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); + + if (chip->pdata && chip->pdata->power_off) + chip->pdata->power_off(chip->client); + + return ret; +} + +/** + * tsl2x7x_invoke_change + * @indio_dev: pointer to IIO device + * + * Obtain and lock both ALS and PROX resources, + * determine and save device state (On/Off), + * cycle device to implement updated parameter, + * put device back into proper state, and unlock + * resource. + */ +static +int tsl2x7x_invoke_change(struct iio_dev *indio_dev) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int device_status = chip->tsl2x7x_chip_status; + + mutex_lock(&chip->als_mutex); + mutex_lock(&chip->prox_mutex); + + if (device_status == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + tsl2x7x_chip_on(indio_dev); + + if (device_status != TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + mutex_unlock(&chip->prox_mutex); + mutex_unlock(&chip->als_mutex); + + return 0; +} + +static +void tsl2x7x_prox_calculate(int *data, int length, + struct tsl2x7x_prox_stat *statP) +{ + int i; + int sample_sum; + int tmp; + + if (!length) + length = 1; + + sample_sum = 0; + statP->min = INT_MAX; + statP->max = INT_MIN; + for (i = 0; i < length; i++) { + sample_sum += data[i]; + statP->min = min(statP->min, data[i]); + statP->max = max(statP->max, data[i]); + } + + statP->mean = sample_sum / length; + sample_sum = 0; + for (i = 0; i < length; i++) { + tmp = data[i] - statP->mean; + sample_sum += tmp * tmp; + } + statP->stddev = int_sqrt((long)sample_sum / length); +} + +/** + * tsl2x7x_prox_cal() - Calculates std. and sets thresholds. + * @indio_dev: pointer to IIO device + * + * Calculates a standard deviation based on the samples, + * and sets the threshold accordingly. + */ +static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) +{ + int prox_history[MAX_SAMPLES_CAL + 1]; + int i; + struct tsl2x7x_prox_stat prox_stat_data[2]; + struct tsl2x7x_prox_stat *calP; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + u8 tmp_irq_settings; + u8 current_state = chip->tsl2x7x_chip_status; + + if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) { + dev_err(&chip->client->dev, + "max prox samples cal is too big: %d\n", + chip->tsl2x7x_settings.prox_max_samples_cal); + chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL; + } + + /* have to stop to change settings */ + tsl2x7x_chip_off(indio_dev); + + /* Enable proximity detection save just in case prox not wanted yet*/ + tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en; + chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL; + + /*turn on device if not already on*/ + tsl2x7x_chip_on(indio_dev); + + /*gather the samples*/ + for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) { + mdelay(15); + tsl2x7x_get_prox(indio_dev); + prox_history[i] = chip->prox_data; + dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", + i, chip->prox_data); + } + + tsl2x7x_chip_off(indio_dev); + calP = &prox_stat_data[PROX_STAT_CAL]; + tsl2x7x_prox_calculate(prox_history, + chip->tsl2x7x_settings.prox_max_samples_cal, + calP); + chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean; + + dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", + calP->min, calP->mean, calP->max); + dev_info(&chip->client->dev, + "%s proximity threshold set to %d\n", + chip->client->name, chip->tsl2x7x_settings.prox_thres_high); + + /* back to the way they were */ + chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings; + if (current_state == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_on(indio_dev); +} + +static ssize_t tsl2x7x_power_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); +} + +static ssize_t tsl2x7x_power_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_chip_on(indio_dev); + else + tsl2x7x_chip_off(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_gain_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); + } + + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); +} + +static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); +} + +static ssize_t tsl2x7x_als_time_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z; + + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + y /= 1000; + z %= 1000; + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_als_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + int ret; + + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; + + result.fract /= 3; + chip->tsl2x7x_settings.als_time = + TSL2X7X_MAX_TIMER_CNT - (u8)result.fract; + + dev_info(&chip->client->dev, "%s: als time = %d", + __func__, chip->tsl2x7x_settings.als_time); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static IIO_CONST_ATTR(in_illuminance0_integration_time_available, + ".00272 - .696"); + +static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", + chip->tsl2x7x_settings.als_cal_target); +} + +static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value) + chip->tsl2x7x_settings.als_cal_target = value; + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +/* persistence settings */ +static ssize_t tsl2x7x_als_persistence_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z, filter_delay; + + /* Determine integration time */ + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F); + y = filter_delay / 1000; + z = filter_delay % 1000; + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_als_persistence_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + int y, z, filter_delay; + int ret; + + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; + + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + + filter_delay = + DIV_ROUND_UP((result.integer * 1000) + result.fract, z); + + chip->tsl2x7x_settings.persistence &= 0xF0; + chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F); + + dev_info(&chip->client->dev, "%s: als persistence = %d", + __func__, filter_delay); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static ssize_t tsl2x7x_prox_persistence_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int y, z, filter_delay; + + /* Determine integration time */ + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4); + y = filter_delay / 1000; + z = filter_delay % 1000; + + return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); +} + +static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + struct tsl2x7x_parse_result result; + int y, z, filter_delay; + int ret; + + ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); + if (ret) + return ret; + + y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; + z = y * TSL2X7X_MIN_ITIME; + + filter_delay = + DIV_ROUND_UP((result.integer * 1000) + result.fract, z); + + chip->tsl2x7x_settings.persistence &= 0x0F; + chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0); + + dev_info(&chip->client->dev, "%s: prox persistence = %d", + __func__, filter_delay); + + tsl2x7x_invoke_change(indio_dev); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static ssize_t tsl2x7x_do_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_als_calibrate(indio_dev); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_luxtable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int i = 0; + int offset = 0; + + while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) { + offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,", + chip->tsl2x7x_device_lux[i].ratio, + chip->tsl2x7x_device_lux[i].ch0, + chip->tsl2x7x_device_lux[i].ch1); + if (chip->tsl2x7x_device_lux[i].ratio == 0) { + /* + * We just printed the first "0" entry. + * Now get rid of the extra "," and break. + */ + offset--; + break; + } + i++; + } + + offset += snprintf(buf + offset, PAGE_SIZE, "\n"); + return offset; +} + +static ssize_t tsl2x7x_luxtable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1]; + int n; + + get_options(buf, ARRAY_SIZE(value), value); + + /* We now have an array of ints starting at value[1], and + * enumerated by value[0]. + * We expect each group of three ints is one table entry, + * and the last table entry is all 0. + */ + n = value[0]; + if ((n % 3) || n < 6 || + n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); + return -EINVAL; + } + + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); + return -EINVAL; + } + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) + tsl2x7x_chip_off(indio_dev); + + /* Zero out the table */ + memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); + memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4)); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + + if (strtobool(buf, &value)) + return -EINVAL; + + if (value) + tsl2x7x_prox_cal(indio_dev); + + tsl2x7x_invoke_change(indio_dev); + + return len; +} + +static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret; + + if (chan->type == IIO_INTENSITY) + ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10); + else + ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20); + + return ret; +} + +static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int val) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (chan->type == IIO_INTENSITY) { + if (val) + chip->tsl2x7x_settings.interrupts_en |= 0x10; + else + chip->tsl2x7x_settings.interrupts_en &= 0x20; + } else { + if (val) + chip->tsl2x7x_settings.interrupts_en |= 0x20; + else + chip->tsl2x7x_settings.interrupts_en &= 0x10; + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.als_thresh_high = val; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.als_thresh_low = val; + break; + default: + return -EINVAL; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->tsl2x7x_settings.prox_thres_high = val; + break; + case IIO_EV_DIR_FALLING: + chip->tsl2x7x_settings.prox_thres_low = val; + break; + default: + return -EINVAL; + } + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.als_thresh_high; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.als_thresh_low; + break; + default: + return -EINVAL; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->tsl2x7x_settings.prox_thres_high; + break; + case IIO_EV_DIR_FALLING: + *val = chip->tsl2x7x_settings.prox_thres_low; + break; + default: + return -EINVAL; + } + } + + return IIO_VAL_INT; +} + +static int tsl2x7x_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + int ret = -EINVAL; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + tsl2x7x_get_lux(indio_dev); + *val = chip->als_cur_info.lux; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_INTENSITY: + tsl2x7x_get_lux(indio_dev); + if (chan->channel == 0) + *val = chip->als_cur_info.als_ch0; + else + *val = chip->als_cur_info.als_ch1; + ret = IIO_VAL_INT; + break; + case IIO_PROXIMITY: + tsl2x7x_get_prox(indio_dev); + *val = chip->prox_data; + ret = IIO_VAL_INT; + break; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_LIGHT) + *val = + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]; + else + *val = + tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain]; + ret = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_CALIBBIAS: + *val = chip->tsl2x7x_settings.als_gain_trim; + ret = IIO_VAL_INT; + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static int tsl2x7x_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_INTENSITY) { + switch (val) { + case 1: + chip->tsl2x7x_settings.als_gain = 0; + break; + case 8: + chip->tsl2x7x_settings.als_gain = 1; + break; + case 16: + chip->tsl2x7x_settings.als_gain = 2; + break; + case 120: + switch (chip->id) { + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + return -EINVAL; + } + chip->tsl2x7x_settings.als_gain = 3; + break; + case 128: + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + return -EINVAL; + } + chip->tsl2x7x_settings.als_gain = 3; + break; + default: + return -EINVAL; + } + } else { + switch (val) { + case 1: + chip->tsl2x7x_settings.prox_gain = 0; + break; + case 2: + chip->tsl2x7x_settings.prox_gain = 1; + break; + case 4: + chip->tsl2x7x_settings.prox_gain = 2; + break; + case 8: + chip->tsl2x7x_settings.prox_gain = 3; + break; + default: + return -EINVAL; + } + } + break; + case IIO_CHAN_INFO_CALIBBIAS: + chip->tsl2x7x_settings.als_gain_trim = val; + break; + + default: + return -EINVAL; + } + + tsl2x7x_invoke_change(indio_dev); + + return 0; +} + +static DEVICE_ATTR(power_state, 0644, + tsl2x7x_power_state_show, tsl2x7x_power_state_store); + +static DEVICE_ATTR(in_proximity0_calibscale_available, 0444, + tsl2x7x_prox_gain_available_show, NULL); + +static DEVICE_ATTR(in_illuminance0_calibscale_available, 0444, + tsl2x7x_gain_available_show, NULL); + +static DEVICE_ATTR(in_illuminance0_integration_time, 0644, + tsl2x7x_als_time_show, tsl2x7x_als_time_store); + +static DEVICE_ATTR(in_illuminance0_target_input, 0644, + tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); + +static DEVICE_ATTR(in_illuminance0_calibrate, 0200, NULL, + tsl2x7x_do_calibrate); + +static DEVICE_ATTR(in_proximity0_calibrate, 0200, NULL, + tsl2x7x_do_prox_calibrate); + +static DEVICE_ATTR(in_illuminance0_lux_table, 0644, + tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); + +static DEVICE_ATTR(in_intensity0_thresh_period, 0644, + tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); + +static DEVICE_ATTR(in_proximity0_thresh_period, 0644, + tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store); + +/* Use the default register values to identify the Taos device */ +static int tsl2x7x_device_id(unsigned char *id, int target) +{ + switch (target) { + case tsl2571: + case tsl2671: + case tsl2771: + return (*id & 0xf0) == TRITON_ID; + case tmd2671: + case tmd2771: + return (*id & 0xf0) == HALIBUT_ID; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + return (*id & 0xf0) == SWORDFISH_ID; + } + + return -EINVAL; +} + +static irqreturn_t tsl2x7x_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(indio_dev); + int ret; + u8 value; + + value = i2c_smbus_read_byte_data(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_STATUS); + + /* What type of interrupt do we need to process */ + if (value & TSL2X7X_STA_PRX_INTR) { + tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + + if (value & TSL2X7X_STA_ALS_INTR) { + tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */ + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + /* Clear interrupt now that we have handled it. */ + ret = i2c_smbus_write_byte(chip->client, + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | + TSL2X7X_CMD_PROXALS_INT_CLR); + if (ret < 0) + dev_err(&chip->client->dev, + "Failed to clear irq from event handler. err = %d\n", + ret); + + return IRQ_HANDLED; +} + +static struct attribute *tsl2x7x_ALS_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + NULL +}; + +static struct attribute *tsl2x7x_PRX_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2x7x_PRX2_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_proximity0_calibrate.attr, + &dev_attr_in_proximity0_calibscale_available.attr, + NULL +}; + +static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = { + &dev_attr_power_state.attr, + &dev_attr_in_illuminance0_calibscale_available.attr, + &dev_attr_in_illuminance0_integration_time.attr, + &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + &dev_attr_in_proximity0_calibrate.attr, + &dev_attr_in_proximity0_calibscale_available.attr, + NULL +}; + +static struct attribute *tsl2X7X_ALS_event_attrs[] = { + &dev_attr_in_intensity0_thresh_period.attr, + NULL, +}; + +static struct attribute *tsl2X7X_PRX_event_attrs[] = { + &dev_attr_in_proximity0_thresh_period.attr, + NULL, +}; + +static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = { + &dev_attr_in_intensity0_thresh_period.attr, + &dev_attr_in_proximity0_thresh_period.attr, + NULL, +}; + +static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = { + [ALS] = { + .attrs = tsl2x7x_ALS_device_attrs, + }, + [PRX] = { + .attrs = tsl2x7x_PRX_device_attrs, + }, + [ALSPRX] = { + .attrs = tsl2x7x_ALSPRX_device_attrs, + }, + [PRX2] = { + .attrs = tsl2x7x_PRX2_device_attrs, + }, + [ALSPRX2] = { + .attrs = tsl2x7x_ALSPRX2_device_attrs, + }, +}; + +static const struct attribute_group tsl2X7X_event_attr_group_tbl[] = { + [ALS] = { + .attrs = tsl2X7X_ALS_event_attrs, + .name = "events", + }, + [PRX] = { + .attrs = tsl2X7X_PRX_event_attrs, + .name = "events", + }, + [ALSPRX] = { + .attrs = tsl2X7X_ALSPRX_event_attrs, + .name = "events", + }, +}; + +static const struct iio_info tsl2X7X_device_info[] = { + [ALS] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALS], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [PRX] = { + .attrs = &tsl2X7X_device_attr_group_tbl[PRX], + .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [ALSPRX] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [PRX2] = { + .attrs = &tsl2X7X_device_attr_group_tbl[PRX2], + .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, + [ALSPRX2] = { + .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2], + .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], + .driver_module = THIS_MODULE, + .read_raw = &tsl2x7x_read_raw, + .write_raw = &tsl2x7x_write_raw, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, + }, +}; + +static const struct iio_event_spec tsl2x7x_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { + [ALS] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + }, + }, + .chan_table_elements = 3, + .info = &tsl2X7X_device_info[ALS], + }, + [PRX] = { + .channel = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX], + }, + [ALSPRX] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX], + }, + [PRX2] = { + .channel = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, + }, + .chan_table_elements = 1, + .info = &tsl2X7X_device_info[PRX2], + }, + [ALSPRX2] = { + .channel = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2x7x_events, + .num_event_specs = ARRAY_SIZE(tsl2x7x_events), + }, + }, + .chan_table_elements = 4, + .info = &tsl2X7X_device_info[ALSPRX2], + }, +}; + +static int tsl2x7x_probe(struct i2c_client *clientp, + const struct i2c_device_id *id) +{ + int ret; + unsigned char device_id; + struct iio_dev *indio_dev; + struct tsl2X7X_chip *chip; + + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + chip->client = clientp; + i2c_set_clientdata(clientp, indio_dev); + + ret = tsl2x7x_i2c_read(chip->client, + TSL2X7X_CHIPID, &device_id); + if (ret < 0) + return ret; + + if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || + (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { + dev_info(&chip->client->dev, + "%s: i2c device found does not match expected id\n", + __func__); + return -EINVAL; + } + + ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); + if (ret < 0) { + dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n", + ret); + return ret; + } + + /* + * ALS and PROX functions can be invoked via user space poll + * or H/W interrupt. If busy return last sample. + */ + mutex_init(&chip->als_mutex); + mutex_init(&chip->prox_mutex); + + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN; + chip->pdata = dev_get_platdata(&clientp->dev); + chip->id = id->driver_data; + chip->chip_info = + &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]]; + + indio_dev->info = chip->chip_info->info; + indio_dev->dev.parent = &clientp->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = chip->client->name; + indio_dev->channels = chip->chip_info->channel; + indio_dev->num_channels = chip->chip_info->chan_table_elements; + + if (clientp->irq) { + ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, + NULL, + &tsl2x7x_event_handler, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "TSL2X7X_event", + indio_dev); + if (ret) { + dev_err(&clientp->dev, + "%s: irq request failed", __func__); + return ret; + } + } + + /* Load up the defaults */ + tsl2x7x_defaults(chip); + /* Make sure the chip is on */ + tsl2x7x_chip_on(indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&clientp->dev, + "%s: iio registration failed\n", __func__); + return ret; + } + + dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); + + return 0; +} + +static int tsl2x7x_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = 0; + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { + ret = tsl2x7x_chip_off(indio_dev); + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; + } + + if (chip->pdata && chip->pdata->platform_power) { + pm_message_t pmm = {PM_EVENT_SUSPEND}; + + chip->pdata->platform_power(dev, pmm); + } + + return ret; +} + +static int tsl2x7x_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2X7X_chip *chip = iio_priv(indio_dev); + int ret = 0; + + if (chip->pdata && chip->pdata->platform_power) { + pm_message_t pmm = {PM_EVENT_RESUME}; + + chip->pdata->platform_power(dev, pmm); + } + + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) + ret = tsl2x7x_chip_on(indio_dev); + + return ret; +} + +static int tsl2x7x_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + tsl2x7x_chip_off(indio_dev); + + iio_device_unregister(indio_dev); + + return 0; +} + +static struct i2c_device_id tsl2x7x_idtable[] = { + { "tsl2571", tsl2571 }, + { "tsl2671", tsl2671 }, + { "tmd2671", tmd2671 }, + { "tsl2771", tsl2771 }, + { "tmd2771", tmd2771 }, + { "tsl2572", tsl2572 }, + { "tsl2672", tsl2672 }, + { "tmd2672", tmd2672 }, + { "tsl2772", tsl2772 }, + { "tmd2772", tmd2772 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); + +static const struct dev_pm_ops tsl2x7x_pm_ops = { + .suspend = tsl2x7x_suspend, + .resume = tsl2x7x_resume, +}; + +/* Driver definition */ +static struct i2c_driver tsl2x7x_driver = { + .driver = { + .name = "tsl2x7x", + .pm = &tsl2x7x_pm_ops, + }, + .id_table = tsl2x7x_idtable, + .probe = tsl2x7x_probe, + .remove = tsl2x7x_remove, +}; + +module_i2c_driver(tsl2x7x_driver); + +MODULE_AUTHOR("J. August Brenner"); +MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c deleted file mode 100644 index 8121a5188638..000000000000 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ /dev/null @@ -1,2063 +0,0 @@ -/* - * Device driver for monitoring ambient light intensity in (lux) - * and proximity detection (prox) within the TAOS TSL2X7X family of devices. - * - * Copyright (c) 2012, TAOS Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tsl2x7x.h" - -/* Cal defs*/ -#define PROX_STAT_CAL 0 -#define PROX_STAT_SAMP 1 -#define MAX_SAMPLES_CAL 200 - -/* TSL2X7X Device ID */ -#define TRITON_ID 0x00 -#define SWORDFISH_ID 0x30 -#define HALIBUT_ID 0x20 - -/* Lux calculation constants */ -#define TSL2X7X_LUX_CALC_OVER_FLOW 65535 - -/* TAOS Register definitions - note: - * depending on device, some of these register are not used and the - * register address is benign. - */ -/* 2X7X register offsets */ -#define TSL2X7X_MAX_CONFIG_REG 16 - -/* Device Registers and Masks */ -#define TSL2X7X_CNTRL 0x00 -#define TSL2X7X_ALS_TIME 0X01 -#define TSL2X7X_PRX_TIME 0x02 -#define TSL2X7X_WAIT_TIME 0x03 -#define TSL2X7X_ALS_MINTHRESHLO 0X04 -#define TSL2X7X_ALS_MINTHRESHHI 0X05 -#define TSL2X7X_ALS_MAXTHRESHLO 0X06 -#define TSL2X7X_ALS_MAXTHRESHHI 0X07 -#define TSL2X7X_PRX_MINTHRESHLO 0X08 -#define TSL2X7X_PRX_MINTHRESHHI 0X09 -#define TSL2X7X_PRX_MAXTHRESHLO 0X0A -#define TSL2X7X_PRX_MAXTHRESHHI 0X0B -#define TSL2X7X_PERSISTENCE 0x0C -#define TSL2X7X_PRX_CONFIG 0x0D -#define TSL2X7X_PRX_COUNT 0x0E -#define TSL2X7X_GAIN 0x0F -#define TSL2X7X_NOTUSED 0x10 -#define TSL2X7X_REVID 0x11 -#define TSL2X7X_CHIPID 0x12 -#define TSL2X7X_STATUS 0x13 -#define TSL2X7X_ALS_CHAN0LO 0x14 -#define TSL2X7X_ALS_CHAN0HI 0x15 -#define TSL2X7X_ALS_CHAN1LO 0x16 -#define TSL2X7X_ALS_CHAN1HI 0x17 -#define TSL2X7X_PRX_LO 0x18 -#define TSL2X7X_PRX_HI 0x19 - -/* tsl2X7X cmd reg masks */ -#define TSL2X7X_CMD_REG 0x80 -#define TSL2X7X_CMD_SPL_FN 0x60 - -#define TSL2X7X_CMD_PROX_INT_CLR 0X05 -#define TSL2X7X_CMD_ALS_INT_CLR 0x06 -#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07 - -/* tsl2X7X cntrl reg masks */ -#define TSL2X7X_CNTL_ADC_ENBL 0x02 -#define TSL2X7X_CNTL_PWR_ON 0x01 - -/* tsl2X7X status reg masks */ -#define TSL2X7X_STA_ADC_VALID 0x01 -#define TSL2X7X_STA_PRX_VALID 0x02 -#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\ - TSL2X7X_STA_PRX_VALID) -#define TSL2X7X_STA_ALS_INTR 0x10 -#define TSL2X7X_STA_PRX_INTR 0x20 - -/* tsl2X7X cntrl reg masks */ -#define TSL2X7X_CNTL_REG_CLEAR 0x00 -#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20 -#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10 -#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08 -#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04 -#define TSL2X7X_CNTL_PWRON 0x01 -#define TSL2X7X_CNTL_ALSPON_ENBL 0x03 -#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13 -#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F -#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F - -/*Prox diode to use */ -#define TSL2X7X_DIODE0 0x10 -#define TSL2X7X_DIODE1 0x20 -#define TSL2X7X_DIODE_BOTH 0x30 - -/* LED Power */ -#define TSL2X7X_mA100 0x00 -#define TSL2X7X_mA50 0x40 -#define TSL2X7X_mA25 0x80 -#define TSL2X7X_mA13 0xD0 -#define TSL2X7X_MAX_TIMER_CNT (0xFF) - -#define TSL2X7X_MIN_ITIME 3 - -/* TAOS txx2x7x Device family members */ -enum { - tsl2571, - tsl2671, - tmd2671, - tsl2771, - tmd2771, - tsl2572, - tsl2672, - tmd2672, - tsl2772, - tmd2772 -}; - -enum { - TSL2X7X_CHIP_UNKNOWN = 0, - TSL2X7X_CHIP_WORKING = 1, - TSL2X7X_CHIP_SUSPENDED = 2 -}; - -struct tsl2x7x_parse_result { - int integer; - int fract; -}; - -/* Per-device data */ -struct tsl2x7x_als_info { - u16 als_ch0; - u16 als_ch1; - u16 lux; -}; - -struct tsl2x7x_prox_stat { - int min; - int max; - int mean; - unsigned long stddev; -}; - -struct tsl2x7x_chip_info { - int chan_table_elements; - struct iio_chan_spec channel[4]; - const struct iio_info *info; -}; - -struct tsl2X7X_chip { - kernel_ulong_t id; - struct mutex prox_mutex; - struct mutex als_mutex; - struct i2c_client *client; - u16 prox_data; - struct tsl2x7x_als_info als_cur_info; - struct tsl2x7x_settings tsl2x7x_settings; - struct tsl2X7X_platform_data *pdata; - int als_time_scale; - int als_saturation; - int tsl2x7x_chip_status; - u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG]; - const struct tsl2x7x_chip_info *chip_info; - const struct iio_info *info; - s64 event_timestamp; - /* - * This structure is intentionally large to accommodate - * updates via sysfs. - * Sized to 9 = max 8 segments + 1 termination segment - */ - struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE]; -}; - -/* Different devices require different coefficents */ -static const struct tsl2x7x_lux tsl2x71_lux_table[] = { - { 14461, 611, 1211 }, - { 18540, 352, 623 }, - { 0, 0, 0 }, -}; - -static const struct tsl2x7x_lux tmd2x71_lux_table[] = { - { 11635, 115, 256 }, - { 15536, 87, 179 }, - { 0, 0, 0 }, -}; - -static const struct tsl2x7x_lux tsl2x72_lux_table[] = { - { 14013, 466, 917 }, - { 18222, 310, 552 }, - { 0, 0, 0 }, -}; - -static const struct tsl2x7x_lux tmd2x72_lux_table[] = { - { 13218, 130, 262 }, - { 17592, 92, 169 }, - { 0, 0, 0 }, -}; - -static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { - [tsl2571] = tsl2x71_lux_table, - [tsl2671] = tsl2x71_lux_table, - [tmd2671] = tmd2x71_lux_table, - [tsl2771] = tsl2x71_lux_table, - [tmd2771] = tmd2x71_lux_table, - [tsl2572] = tsl2x72_lux_table, - [tsl2672] = tsl2x72_lux_table, - [tmd2672] = tmd2x72_lux_table, - [tsl2772] = tsl2x72_lux_table, - [tmd2772] = tmd2x72_lux_table, -}; - -static const struct tsl2x7x_settings tsl2x7x_default_settings = { - .als_time = 219, /* 101 ms */ - .als_gain = 0, - .prx_time = 254, /* 5.4 ms */ - .prox_gain = 1, - .wait_time = 245, - .prox_config = 0, - .als_gain_trim = 1000, - .als_cal_target = 150, - .als_thresh_low = 200, - .als_thresh_high = 256, - .persistence = 255, - .interrupts_en = 0, - .prox_thres_low = 0, - .prox_thres_high = 512, - .prox_max_samples_cal = 30, - .prox_pulse_count = 8 -}; - -static const s16 tsl2X7X_als_gainadj[] = { - 1, - 8, - 16, - 120 -}; - -static const s16 tsl2X7X_prx_gainadj[] = { - 1, - 2, - 4, - 8 -}; - -/* Channel variations */ -enum { - ALS, - PRX, - ALSPRX, - PRX2, - ALSPRX2, -}; - -static const u8 device_channel_config[] = { - ALS, - PRX, - PRX, - ALSPRX, - ALSPRX, - ALS, - PRX2, - PRX2, - ALSPRX2, - ALSPRX2 -}; - -/** - * tsl2x7x_i2c_read() - Read a byte from a register. - * @client: i2c client - * @reg: device register to read from - * @*val: pointer to location to store register contents. - * - */ -static int -tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - - /* select register to write */ - ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); - if (ret < 0) { - dev_err(&client->dev, "failed to write register %x\n", reg); - return ret; - } - - /* read the data */ - ret = i2c_smbus_read_byte(client); - if (ret >= 0) - *val = (u8)ret; - else - dev_err(&client->dev, "failed to read register %x\n", reg); - - return ret; -} - -/** - * tsl2x7x_get_lux() - Reads and calculates current lux value. - * @indio_dev: pointer to IIO device - * - * The raw ch0 and ch1 values of the ambient light sensed in the last - * integration cycle are read from the device. - * Time scale factor array values are adjusted based on the integration time. - * The raw values are multiplied by a scale factor, and device gain is obtained - * using gain index. Limit checks are done next, then the ratio of a multiple - * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[] - * is then scanned to find the first ratio value that is just above the ratio - * we just calculated. The ch0 and ch1 multiplier constants in the array are - * then used along with the time scale factor array values, to calculate the - * lux. - */ -static int tsl2x7x_get_lux(struct iio_dev *indio_dev) -{ - u16 ch0, ch1; /* separated ch0/ch1 data from device */ - u32 lux; /* raw lux calculated from device data */ - u64 lux64; - u32 ratio; - u8 buf[4]; - struct tsl2x7x_lux *p; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int i, ret; - u32 ch0lux = 0; - u32 ch1lux = 0; - - if (mutex_trylock(&chip->als_mutex) == 0) - return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ - - if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { - /* device is not enabled */ - dev_err(&chip->client->dev, "%s: device is not enabled\n", - __func__); - ret = -EBUSY; - goto out_unlock; - } - - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: Failed to read STATUS Reg\n", __func__); - goto out_unlock; - } - /* is data new & valid */ - if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) { - dev_err(&chip->client->dev, - "%s: data not valid yet\n", __func__); - ret = chip->als_cur_info.lux; /* return LAST VALUE */ - goto out_unlock; - } - - for (i = 0; i < 4; i++) { - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | - (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]); - if (ret < 0) { - dev_err(&chip->client->dev, - "failed to read. err=%x\n", ret); - goto out_unlock; - } - } - - /* clear any existing interrupt status */ - ret = i2c_smbus_write_byte(chip->client, - (TSL2X7X_CMD_REG | - TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_ALS_INT_CLR)); - if (ret < 0) { - dev_err(&chip->client->dev, - "i2c_write_command failed - err = %d\n", ret); - goto out_unlock; /* have no data, so return failure */ - } - - /* extract ALS/lux data */ - ch0 = le16_to_cpup((const __le16 *)&buf[0]); - ch1 = le16_to_cpup((const __le16 *)&buf[2]); - - chip->als_cur_info.als_ch0 = ch0; - chip->als_cur_info.als_ch1 = ch1; - - if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) { - lux = TSL2X7X_LUX_CALC_OVER_FLOW; - goto return_max; - } - - if (!ch0) { - /* have no data, so return LAST VALUE */ - ret = chip->als_cur_info.lux; - goto out_unlock; - } - /* calculate ratio */ - ratio = (ch1 << 15) / ch0; - /* convert to unscaled lux using the pointer to the table */ - p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; - while (p->ratio != 0 && p->ratio < ratio) - p++; - - if (p->ratio == 0) { - lux = 0; - } else { - ch0lux = DIV_ROUND_UP(ch0 * p->ch0, - tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); - ch1lux = DIV_ROUND_UP(ch1 * p->ch1, - tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]); - lux = ch0lux - ch1lux; - } - - /* note: lux is 31 bit max at this point */ - if (ch1lux > ch0lux) { - dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n"); - ret = chip->als_cur_info.lux; - goto out_unlock; - } - - /* adjust for active time scale */ - if (chip->als_time_scale == 0) - lux = 0; - else - lux = (lux + (chip->als_time_scale >> 1)) / - chip->als_time_scale; - - /* adjust for active gain scale - * The tsl2x7x_device_lux tables have a factor of 256 built-in. - * User-specified gain provides a multiplier. - * Apply user-specified gain before shifting right to retain precision. - * Use 64 bits to avoid overflow on multiplication. - * Then go back to 32 bits before division to avoid using div_u64(). - */ - - lux64 = lux; - lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim; - lux64 >>= 8; - lux = lux64; - lux = (lux + 500) / 1000; - - if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */ - lux = TSL2X7X_LUX_CALC_OVER_FLOW; - - /* Update the structure with the latest lux. */ -return_max: - chip->als_cur_info.lux = lux; - ret = lux; - -out_unlock: - mutex_unlock(&chip->als_mutex); - - return ret; -} - -/** - * tsl2x7x_get_prox() - Reads proximity data registers and updates - * chip->prox_data. - * - * @indio_dev: pointer to IIO device - */ -static int tsl2x7x_get_prox(struct iio_dev *indio_dev) -{ - int i; - int ret; - u8 status; - u8 chdata[2]; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - if (mutex_trylock(&chip->prox_mutex) == 0) { - dev_err(&chip->client->dev, - "%s: Can't get prox mutex\n", __func__); - return -EBUSY; - } - - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status); - if (ret < 0) { - dev_err(&chip->client->dev, "i2c err=%d\n", ret); - goto prox_poll_err; - } - - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - if (!(status & TSL2X7X_STA_ADC_VALID)) - goto prox_poll_err; - break; - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - if (!(status & TSL2X7X_STA_PRX_VALID)) - goto prox_poll_err; - break; - } - - for (i = 0; i < 2; i++) { - ret = tsl2x7x_i2c_read(chip->client, - (TSL2X7X_CMD_REG | - (TSL2X7X_PRX_LO + i)), &chdata[i]); - if (ret < 0) - goto prox_poll_err; - } - - chip->prox_data = - le16_to_cpup((const __le16 *)&chdata[0]); - -prox_poll_err: - - mutex_unlock(&chip->prox_mutex); - - return chip->prox_data; -} - -/** - * tsl2x7x_defaults() - Populates the device nominal operating parameters - * with those provided by a 'platform' data struct or - * with prefined defaults. - * - * @chip: pointer to device structure. - */ -static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) -{ - /* If Operational settings defined elsewhere.. */ - if (chip->pdata && chip->pdata->platform_default_settings) - memcpy(&chip->tsl2x7x_settings, - chip->pdata->platform_default_settings, - sizeof(tsl2x7x_default_settings)); - else - memcpy(&chip->tsl2x7x_settings, - &tsl2x7x_default_settings, - sizeof(tsl2x7x_default_settings)); - - /* Load up the proper lux table. */ - if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0) - memcpy(chip->tsl2x7x_device_lux, - chip->pdata->platform_lux_table, - sizeof(chip->pdata->platform_lux_table)); - else - memcpy(chip->tsl2x7x_device_lux, - (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id], - MAX_DEFAULT_TABLE_BYTES); -} - -/** - * tsl2x7x_als_calibrate() - Obtain single reading and calculate - * the als_gain_trim. - * - * @indio_dev: pointer to IIO device - */ -static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 reg_val; - int gain_trim_val; - int ret; - int lux_val; - - ret = i2c_smbus_write_byte(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); - if (ret < 0) { - dev_err(&chip->client->dev, - "failed to write CNTRL register, ret=%d\n", ret); - return ret; - } - - reg_val = i2c_smbus_read_byte(chip->client); - if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) - != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { - dev_err(&chip->client->dev, - "%s: failed: ADC not enabled\n", __func__); - return -1; - } - - ret = i2c_smbus_write_byte(chip->client, - (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); - if (ret < 0) { - dev_err(&chip->client->dev, - "failed to write ctrl reg: ret=%d\n", ret); - return ret; - } - - reg_val = i2c_smbus_read_byte(chip->client); - if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { - dev_err(&chip->client->dev, - "%s: failed: STATUS - ADC not valid.\n", __func__); - return -ENODATA; - } - - lux_val = tsl2x7x_get_lux(indio_dev); - if (lux_val < 0) { - dev_err(&chip->client->dev, - "%s: failed to get lux\n", __func__); - return lux_val; - } - - gain_trim_val = ((chip->tsl2x7x_settings.als_cal_target) - * chip->tsl2x7x_settings.als_gain_trim) / lux_val; - if ((gain_trim_val < 250) || (gain_trim_val > 4000)) - return -ERANGE; - - chip->tsl2x7x_settings.als_gain_trim = gain_trim_val; - dev_info(&chip->client->dev, - "%s als_calibrate completed\n", chip->client->name); - - return (int)gain_trim_val; -} - -static int tsl2x7x_chip_on(struct iio_dev *indio_dev) -{ - int i; - int ret = 0; - u8 *dev_reg; - u8 utmp; - int als_count; - int als_time; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 reg_val = 0; - - if (chip->pdata && chip->pdata->power_on) - chip->pdata->power_on(indio_dev); - - /* Non calculated parameters */ - chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = - chip->tsl2x7x_settings.prx_time; - chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = - chip->tsl2x7x_settings.wait_time; - chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = - chip->tsl2x7x_settings.prox_config; - - chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = - (chip->tsl2x7x_settings.als_thresh_low) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] = - (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] = - (chip->tsl2x7x_settings.als_thresh_high) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = - (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = - chip->tsl2x7x_settings.persistence; - - chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = - chip->tsl2x7x_settings.prox_pulse_count; - chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = - (chip->tsl2x7x_settings.prox_thres_low) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] = - (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = - (chip->tsl2x7x_settings.prox_thres_high) & 0xFF; - chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] = - (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF; - - /* and make sure we're not already on */ - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { - /* if forcing a register update - turn off, then on */ - dev_info(&chip->client->dev, "device is already enabled\n"); - return -EINVAL; - } - - /* determine als integration register */ - als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270; - if (!als_count) - als_count = 1; /* ensure at least one cycle */ - - /* convert back to time (encompasses overrides) */ - als_time = (als_count * 27 + 5) / 10; - chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; - - /* Set the gain based on tsl2x7x_settings struct */ - chip->tsl2x7x_config[TSL2X7X_GAIN] = - chip->tsl2x7x_settings.als_gain | - (TSL2X7X_mA100 | TSL2X7X_DIODE1) - | ((chip->tsl2x7x_settings.prox_gain) << 2); - - /* set chip struct re scaling and saturation */ - chip->als_saturation = als_count * 922; /* 90% of full scale */ - chip->als_time_scale = (als_time + 25) / 50; - - /* - * TSL2X7X Specific power-on / adc enable sequence - * Power on the device 1st. - */ - utmp = TSL2X7X_CNTL_PWR_ON; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed on CNTRL reg.\n", __func__); - return ret; - } - - /* - * Use the following shadow copy for our delay before enabling ADC. - * Write all the registers. - */ - for (i = 0, dev_reg = chip->tsl2x7x_config; - i < TSL2X7X_MAX_CONFIG_REG; i++) { - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG + i, - *dev_reg++); - if (ret < 0) { - dev_err(&chip->client->dev, - "failed on write to reg %d.\n", i); - return ret; - } - } - - mdelay(3); /* Power-on settling time */ - - /* - * NOW enable the ADC - * initialize the desired mode of operation - */ - utmp = TSL2X7X_CNTL_PWR_ON | - TSL2X7X_CNTL_ADC_ENBL | - TSL2X7X_CNTL_PROX_DET_ENBL; - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed on 2nd CTRL reg.\n", __func__); - return ret; - } - - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; - - if (chip->tsl2x7x_settings.interrupts_en != 0) { - dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); - - reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL; - if ((chip->tsl2x7x_settings.interrupts_en == 0x20) || - (chip->tsl2x7x_settings.interrupts_en == 0x30)) - reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL; - - reg_val |= chip->tsl2x7x_settings.interrupts_en; - ret = i2c_smbus_write_byte_data(chip->client, - (TSL2X7X_CMD_REG | - TSL2X7X_CNTRL), reg_val); - if (ret < 0) - dev_err(&chip->client->dev, - "%s: failed in tsl2x7x_IOCTL_INT_SET.\n", - __func__); - - /* Clear out any initial interrupts */ - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | - TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_PROXALS_INT_CLR); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: Failed to clear Int status\n", - __func__); - return ret; - } - } - - return ret; -} - -static int tsl2x7x_chip_off(struct iio_dev *indio_dev) -{ - int ret; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - /* turn device off */ - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; - - ret = i2c_smbus_write_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); - - if (chip->pdata && chip->pdata->power_off) - chip->pdata->power_off(chip->client); - - return ret; -} - -/** - * tsl2x7x_invoke_change - * @indio_dev: pointer to IIO device - * - * Obtain and lock both ALS and PROX resources, - * determine and save device state (On/Off), - * cycle device to implement updated parameter, - * put device back into proper state, and unlock - * resource. - */ -static -int tsl2x7x_invoke_change(struct iio_dev *indio_dev) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int device_status = chip->tsl2x7x_chip_status; - - mutex_lock(&chip->als_mutex); - mutex_lock(&chip->prox_mutex); - - if (device_status == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); - - tsl2x7x_chip_on(indio_dev); - - if (device_status != TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); - - mutex_unlock(&chip->prox_mutex); - mutex_unlock(&chip->als_mutex); - - return 0; -} - -static -void tsl2x7x_prox_calculate(int *data, int length, - struct tsl2x7x_prox_stat *statP) -{ - int i; - int sample_sum; - int tmp; - - if (!length) - length = 1; - - sample_sum = 0; - statP->min = INT_MAX; - statP->max = INT_MIN; - for (i = 0; i < length; i++) { - sample_sum += data[i]; - statP->min = min(statP->min, data[i]); - statP->max = max(statP->max, data[i]); - } - - statP->mean = sample_sum / length; - sample_sum = 0; - for (i = 0; i < length; i++) { - tmp = data[i] - statP->mean; - sample_sum += tmp * tmp; - } - statP->stddev = int_sqrt((long)sample_sum / length); -} - -/** - * tsl2x7x_prox_cal() - Calculates std. and sets thresholds. - * @indio_dev: pointer to IIO device - * - * Calculates a standard deviation based on the samples, - * and sets the threshold accordingly. - */ -static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) -{ - int prox_history[MAX_SAMPLES_CAL + 1]; - int i; - struct tsl2x7x_prox_stat prox_stat_data[2]; - struct tsl2x7x_prox_stat *calP; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - u8 tmp_irq_settings; - u8 current_state = chip->tsl2x7x_chip_status; - - if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) { - dev_err(&chip->client->dev, - "max prox samples cal is too big: %d\n", - chip->tsl2x7x_settings.prox_max_samples_cal); - chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL; - } - - /* have to stop to change settings */ - tsl2x7x_chip_off(indio_dev); - - /* Enable proximity detection save just in case prox not wanted yet*/ - tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en; - chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL; - - /*turn on device if not already on*/ - tsl2x7x_chip_on(indio_dev); - - /*gather the samples*/ - for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) { - mdelay(15); - tsl2x7x_get_prox(indio_dev); - prox_history[i] = chip->prox_data; - dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", - i, chip->prox_data); - } - - tsl2x7x_chip_off(indio_dev); - calP = &prox_stat_data[PROX_STAT_CAL]; - tsl2x7x_prox_calculate(prox_history, - chip->tsl2x7x_settings.prox_max_samples_cal, - calP); - chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean; - - dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", - calP->min, calP->mean, calP->max); - dev_info(&chip->client->dev, - "%s proximity threshold set to %d\n", - chip->client->name, chip->tsl2x7x_settings.prox_thres_high); - - /* back to the way they were */ - chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings; - if (current_state == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_on(indio_dev); -} - -static ssize_t tsl2x7x_power_state_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); -} - -static ssize_t tsl2x7x_power_state_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - - if (strtobool(buf, &value)) - return -EINVAL; - - if (value) - tsl2x7x_chip_on(indio_dev); - else - tsl2x7x_chip_off(indio_dev); - - return len; -} - -static ssize_t tsl2x7x_gain_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); - } - - return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); -} - -static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); -} - -static ssize_t tsl2x7x_als_time_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - int y, z; - - y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; - z = y * TSL2X7X_MIN_ITIME; - y /= 1000; - z %= 1000; - - return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); -} - -static ssize_t tsl2x7x_als_time_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - struct tsl2x7x_parse_result result; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); - if (ret) - return ret; - - result.fract /= 3; - chip->tsl2x7x_settings.als_time = - TSL2X7X_MAX_TIMER_CNT - (u8)result.fract; - - dev_info(&chip->client->dev, "%s: als time = %d", - __func__, chip->tsl2x7x_settings.als_time); - - tsl2x7x_invoke_change(indio_dev); - - return IIO_VAL_INT_PLUS_MICRO; -} - -static IIO_CONST_ATTR(in_illuminance0_integration_time_available, - ".00272 - .696"); - -static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - return snprintf(buf, PAGE_SIZE, "%d\n", - chip->tsl2x7x_settings.als_cal_target); -} - -static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - unsigned long value; - - if (kstrtoul(buf, 0, &value)) - return -EINVAL; - - if (value) - chip->tsl2x7x_settings.als_cal_target = value; - - tsl2x7x_invoke_change(indio_dev); - - return len; -} - -/* persistence settings */ -static ssize_t tsl2x7x_als_persistence_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - int y, z, filter_delay; - - /* Determine integration time */ - y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; - z = y * TSL2X7X_MIN_ITIME; - filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F); - y = filter_delay / 1000; - z = filter_delay % 1000; - - return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); -} - -static ssize_t tsl2x7x_als_persistence_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - struct tsl2x7x_parse_result result; - int y, z, filter_delay; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); - if (ret) - return ret; - - y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1; - z = y * TSL2X7X_MIN_ITIME; - - filter_delay = - DIV_ROUND_UP((result.integer * 1000) + result.fract, z); - - chip->tsl2x7x_settings.persistence &= 0xF0; - chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F); - - dev_info(&chip->client->dev, "%s: als persistence = %d", - __func__, filter_delay); - - tsl2x7x_invoke_change(indio_dev); - - return IIO_VAL_INT_PLUS_MICRO; -} - -static ssize_t tsl2x7x_prox_persistence_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - int y, z, filter_delay; - - /* Determine integration time */ - y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; - z = y * TSL2X7X_MIN_ITIME; - filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4); - y = filter_delay / 1000; - z = filter_delay % 1000; - - return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); -} - -static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - struct tsl2x7x_parse_result result; - int y, z, filter_delay; - int ret; - - ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract); - if (ret) - return ret; - - y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1; - z = y * TSL2X7X_MIN_ITIME; - - filter_delay = - DIV_ROUND_UP((result.integer * 1000) + result.fract, z); - - chip->tsl2x7x_settings.persistence &= 0x0F; - chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0); - - dev_info(&chip->client->dev, "%s: prox persistence = %d", - __func__, filter_delay); - - tsl2x7x_invoke_change(indio_dev); - - return IIO_VAL_INT_PLUS_MICRO; -} - -static ssize_t tsl2x7x_do_calibrate(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - - if (strtobool(buf, &value)) - return -EINVAL; - - if (value) - tsl2x7x_als_calibrate(indio_dev); - - tsl2x7x_invoke_change(indio_dev); - - return len; -} - -static ssize_t tsl2x7x_luxtable_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev)); - int i = 0; - int offset = 0; - - while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) { - offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,", - chip->tsl2x7x_device_lux[i].ratio, - chip->tsl2x7x_device_lux[i].ch0, - chip->tsl2x7x_device_lux[i].ch1); - if (chip->tsl2x7x_device_lux[i].ratio == 0) { - /* - * We just printed the first "0" entry. - * Now get rid of the extra "," and break. - */ - offset--; - break; - } - i++; - } - - offset += snprintf(buf + offset, PAGE_SIZE, "\n"); - return offset; -} - -static ssize_t tsl2x7x_luxtable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1]; - int n; - - get_options(buf, ARRAY_SIZE(value), value); - - /* We now have an array of ints starting at value[1], and - * enumerated by value[0]. - * We expect each group of three ints is one table entry, - * and the last table entry is all 0. - */ - n = value[0]; - if ((n % 3) || n < 6 || - n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { - dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); - return -EINVAL; - } - - if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { - dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); - return -EINVAL; - } - - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) - tsl2x7x_chip_off(indio_dev); - - /* Zero out the table */ - memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); - memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4)); - - tsl2x7x_invoke_change(indio_dev); - - return len; -} - -static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - - if (strtobool(buf, &value)) - return -EINVAL; - - if (value) - tsl2x7x_prox_cal(indio_dev); - - tsl2x7x_invoke_change(indio_dev); - - return len; -} - -static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret; - - if (chan->type == IIO_INTENSITY) - ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10); - else - ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20); - - return ret; -} - -static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int val) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - if (chan->type == IIO_INTENSITY) { - if (val) - chip->tsl2x7x_settings.interrupts_en |= 0x10; - else - chip->tsl2x7x_settings.interrupts_en &= 0x20; - } else { - if (val) - chip->tsl2x7x_settings.interrupts_en |= 0x20; - else - chip->tsl2x7x_settings.interrupts_en &= 0x10; - } - - tsl2x7x_invoke_change(indio_dev); - - return 0; -} - -static int tsl2x7x_write_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->tsl2x7x_settings.als_thresh_high = val; - break; - case IIO_EV_DIR_FALLING: - chip->tsl2x7x_settings.als_thresh_low = val; - break; - default: - return -EINVAL; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->tsl2x7x_settings.prox_thres_high = val; - break; - case IIO_EV_DIR_FALLING: - chip->tsl2x7x_settings.prox_thres_low = val; - break; - default: - return -EINVAL; - } - } - - tsl2x7x_invoke_change(indio_dev); - - return 0; -} - -static int tsl2x7x_read_thresh(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->tsl2x7x_settings.als_thresh_high; - break; - case IIO_EV_DIR_FALLING: - *val = chip->tsl2x7x_settings.als_thresh_low; - break; - default: - return -EINVAL; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->tsl2x7x_settings.prox_thres_high; - break; - case IIO_EV_DIR_FALLING: - *val = chip->tsl2x7x_settings.prox_thres_low; - break; - default: - return -EINVAL; - } - } - - return IIO_VAL_INT; -} - -static int tsl2x7x_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - int ret = -EINVAL; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_LIGHT: - tsl2x7x_get_lux(indio_dev); - *val = chip->als_cur_info.lux; - ret = IIO_VAL_INT; - break; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_RAW: - switch (chan->type) { - case IIO_INTENSITY: - tsl2x7x_get_lux(indio_dev); - if (chan->channel == 0) - *val = chip->als_cur_info.als_ch0; - else - *val = chip->als_cur_info.als_ch1; - ret = IIO_VAL_INT; - break; - case IIO_PROXIMITY: - tsl2x7x_get_prox(indio_dev); - *val = chip->prox_data; - ret = IIO_VAL_INT; - break; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_LIGHT) - *val = - tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]; - else - *val = - tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain]; - ret = IIO_VAL_INT; - break; - case IIO_CHAN_INFO_CALIBBIAS: - *val = chip->tsl2x7x_settings.als_gain_trim; - ret = IIO_VAL_INT; - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static int tsl2x7x_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_INTENSITY) { - switch (val) { - case 1: - chip->tsl2x7x_settings.als_gain = 0; - break; - case 8: - chip->tsl2x7x_settings.als_gain = 1; - break; - case 16: - chip->tsl2x7x_settings.als_gain = 2; - break; - case 120: - switch (chip->id) { - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - return -EINVAL; - } - chip->tsl2x7x_settings.als_gain = 3; - break; - case 128: - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - return -EINVAL; - } - chip->tsl2x7x_settings.als_gain = 3; - break; - default: - return -EINVAL; - } - } else { - switch (val) { - case 1: - chip->tsl2x7x_settings.prox_gain = 0; - break; - case 2: - chip->tsl2x7x_settings.prox_gain = 1; - break; - case 4: - chip->tsl2x7x_settings.prox_gain = 2; - break; - case 8: - chip->tsl2x7x_settings.prox_gain = 3; - break; - default: - return -EINVAL; - } - } - break; - case IIO_CHAN_INFO_CALIBBIAS: - chip->tsl2x7x_settings.als_gain_trim = val; - break; - - default: - return -EINVAL; - } - - tsl2x7x_invoke_change(indio_dev); - - return 0; -} - -static DEVICE_ATTR(power_state, 0644, - tsl2x7x_power_state_show, tsl2x7x_power_state_store); - -static DEVICE_ATTR(in_proximity0_calibscale_available, 0444, - tsl2x7x_prox_gain_available_show, NULL); - -static DEVICE_ATTR(in_illuminance0_calibscale_available, 0444, - tsl2x7x_gain_available_show, NULL); - -static DEVICE_ATTR(in_illuminance0_integration_time, 0644, - tsl2x7x_als_time_show, tsl2x7x_als_time_store); - -static DEVICE_ATTR(in_illuminance0_target_input, 0644, - tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); - -static DEVICE_ATTR(in_illuminance0_calibrate, 0200, NULL, - tsl2x7x_do_calibrate); - -static DEVICE_ATTR(in_proximity0_calibrate, 0200, NULL, - tsl2x7x_do_prox_calibrate); - -static DEVICE_ATTR(in_illuminance0_lux_table, 0644, - tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); - -static DEVICE_ATTR(in_intensity0_thresh_period, 0644, - tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); - -static DEVICE_ATTR(in_proximity0_thresh_period, 0644, - tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store); - -/* Use the default register values to identify the Taos device */ -static int tsl2x7x_device_id(unsigned char *id, int target) -{ - switch (target) { - case tsl2571: - case tsl2671: - case tsl2771: - return (*id & 0xf0) == TRITON_ID; - case tmd2671: - case tmd2771: - return (*id & 0xf0) == HALIBUT_ID; - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - return (*id & 0xf0) == SWORDFISH_ID; - } - - return -EINVAL; -} - -static irqreturn_t tsl2x7x_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(indio_dev); - int ret; - u8 value; - - value = i2c_smbus_read_byte_data(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_STATUS); - - /* What type of interrupt do we need to process */ - if (value & TSL2X7X_STA_PRX_INTR) { - tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */ - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_EITHER), - timestamp); - } - - if (value & TSL2X7X_STA_ALS_INTR) { - tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */ - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_EITHER), - timestamp); - } - /* Clear interrupt now that we have handled it. */ - ret = i2c_smbus_write_byte(chip->client, - TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | - TSL2X7X_CMD_PROXALS_INT_CLR); - if (ret < 0) - dev_err(&chip->client->dev, - "Failed to clear irq from event handler. err = %d\n", - ret); - - return IRQ_HANDLED; -} - -static struct attribute *tsl2x7x_ALS_device_attrs[] = { - &dev_attr_power_state.attr, - &dev_attr_in_illuminance0_calibscale_available.attr, - &dev_attr_in_illuminance0_integration_time.attr, - &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - NULL -}; - -static struct attribute *tsl2x7x_PRX_device_attrs[] = { - &dev_attr_power_state.attr, - &dev_attr_in_proximity0_calibrate.attr, - NULL -}; - -static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = { - &dev_attr_power_state.attr, - &dev_attr_in_illuminance0_calibscale_available.attr, - &dev_attr_in_illuminance0_integration_time.attr, - &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - &dev_attr_in_proximity0_calibrate.attr, - NULL -}; - -static struct attribute *tsl2x7x_PRX2_device_attrs[] = { - &dev_attr_power_state.attr, - &dev_attr_in_proximity0_calibrate.attr, - &dev_attr_in_proximity0_calibscale_available.attr, - NULL -}; - -static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = { - &dev_attr_power_state.attr, - &dev_attr_in_illuminance0_calibscale_available.attr, - &dev_attr_in_illuminance0_integration_time.attr, - &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr, - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - &dev_attr_in_proximity0_calibrate.attr, - &dev_attr_in_proximity0_calibscale_available.attr, - NULL -}; - -static struct attribute *tsl2X7X_ALS_event_attrs[] = { - &dev_attr_in_intensity0_thresh_period.attr, - NULL, -}; - -static struct attribute *tsl2X7X_PRX_event_attrs[] = { - &dev_attr_in_proximity0_thresh_period.attr, - NULL, -}; - -static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = { - &dev_attr_in_intensity0_thresh_period.attr, - &dev_attr_in_proximity0_thresh_period.attr, - NULL, -}; - -static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = { - [ALS] = { - .attrs = tsl2x7x_ALS_device_attrs, - }, - [PRX] = { - .attrs = tsl2x7x_PRX_device_attrs, - }, - [ALSPRX] = { - .attrs = tsl2x7x_ALSPRX_device_attrs, - }, - [PRX2] = { - .attrs = tsl2x7x_PRX2_device_attrs, - }, - [ALSPRX2] = { - .attrs = tsl2x7x_ALSPRX2_device_attrs, - }, -}; - -static const struct attribute_group tsl2X7X_event_attr_group_tbl[] = { - [ALS] = { - .attrs = tsl2X7X_ALS_event_attrs, - .name = "events", - }, - [PRX] = { - .attrs = tsl2X7X_PRX_event_attrs, - .name = "events", - }, - [ALSPRX] = { - .attrs = tsl2X7X_ALSPRX_event_attrs, - .name = "events", - }, -}; - -static const struct iio_info tsl2X7X_device_info[] = { - [ALS] = { - .attrs = &tsl2X7X_device_attr_group_tbl[ALS], - .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS], - .driver_module = THIS_MODULE, - .read_raw = &tsl2x7x_read_raw, - .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, - }, - [PRX] = { - .attrs = &tsl2X7X_device_attr_group_tbl[PRX], - .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], - .driver_module = THIS_MODULE, - .read_raw = &tsl2x7x_read_raw, - .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, - }, - [ALSPRX] = { - .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX], - .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], - .driver_module = THIS_MODULE, - .read_raw = &tsl2x7x_read_raw, - .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, - }, - [PRX2] = { - .attrs = &tsl2X7X_device_attr_group_tbl[PRX2], - .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX], - .driver_module = THIS_MODULE, - .read_raw = &tsl2x7x_read_raw, - .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, - }, - [ALSPRX2] = { - .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2], - .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX], - .driver_module = THIS_MODULE, - .read_raw = &tsl2x7x_read_raw, - .write_raw = &tsl2x7x_write_raw, - .read_event_value = &tsl2x7x_read_thresh, - .write_event_value = &tsl2x7x_write_thresh, - .read_event_config = &tsl2x7x_read_interrupt_config, - .write_event_config = &tsl2x7x_write_interrupt_config, - }, -}; - -static const struct iio_event_spec tsl2x7x_events[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE), - }, -}; - -static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = { - [ALS] = { - .channel = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - }, - }, - .chan_table_elements = 3, - .info = &tsl2X7X_device_info[ALS], - }, - [PRX] = { - .channel = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, - }, - .chan_table_elements = 1, - .info = &tsl2X7X_device_info[PRX], - }, - [ALSPRX] = { - .channel = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, - }, - .chan_table_elements = 4, - .info = &tsl2X7X_device_info[ALSPRX], - }, - [PRX2] = { - .channel = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, - }, - .chan_table_elements = 1, - .info = &tsl2X7X_device_info[PRX2], - }, - [ALSPRX2] = { - .channel = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2x7x_events, - .num_event_specs = ARRAY_SIZE(tsl2x7x_events), - }, - }, - .chan_table_elements = 4, - .info = &tsl2X7X_device_info[ALSPRX2], - }, -}; - -static int tsl2x7x_probe(struct i2c_client *clientp, - const struct i2c_device_id *id) -{ - int ret; - unsigned char device_id; - struct iio_dev *indio_dev; - struct tsl2X7X_chip *chip; - - indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - - chip = iio_priv(indio_dev); - chip->client = clientp; - i2c_set_clientdata(clientp, indio_dev); - - ret = tsl2x7x_i2c_read(chip->client, - TSL2X7X_CHIPID, &device_id); - if (ret < 0) - return ret; - - if ((!tsl2x7x_device_id(&device_id, id->driver_data)) || - (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) { - dev_info(&chip->client->dev, - "%s: i2c device found does not match expected id\n", - __func__); - return -EINVAL; - } - - ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); - if (ret < 0) { - dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n", - ret); - return ret; - } - - /* - * ALS and PROX functions can be invoked via user space poll - * or H/W interrupt. If busy return last sample. - */ - mutex_init(&chip->als_mutex); - mutex_init(&chip->prox_mutex); - - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN; - chip->pdata = dev_get_platdata(&clientp->dev); - chip->id = id->driver_data; - chip->chip_info = - &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]]; - - indio_dev->info = chip->chip_info->info; - indio_dev->dev.parent = &clientp->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = chip->client->name; - indio_dev->channels = chip->chip_info->channel; - indio_dev->num_channels = chip->chip_info->chan_table_elements; - - if (clientp->irq) { - ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, - NULL, - &tsl2x7x_event_handler, - IRQF_TRIGGER_RISING | - IRQF_ONESHOT, - "TSL2X7X_event", - indio_dev); - if (ret) { - dev_err(&clientp->dev, - "%s: irq request failed", __func__); - return ret; - } - } - - /* Load up the defaults */ - tsl2x7x_defaults(chip); - /* Make sure the chip is on */ - tsl2x7x_chip_on(indio_dev); - - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(&clientp->dev, - "%s: iio registration failed\n", __func__); - return ret; - } - - dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); - - return 0; -} - -static int tsl2x7x_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret = 0; - - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { - ret = tsl2x7x_chip_off(indio_dev); - chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; - } - - if (chip->pdata && chip->pdata->platform_power) { - pm_message_t pmm = {PM_EVENT_SUSPEND}; - - chip->pdata->platform_power(dev, pmm); - } - - return ret; -} - -static int tsl2x7x_resume(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct tsl2X7X_chip *chip = iio_priv(indio_dev); - int ret = 0; - - if (chip->pdata && chip->pdata->platform_power) { - pm_message_t pmm = {PM_EVENT_RESUME}; - - chip->pdata->platform_power(dev, pmm); - } - - if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) - ret = tsl2x7x_chip_on(indio_dev); - - return ret; -} - -static int tsl2x7x_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - tsl2x7x_chip_off(indio_dev); - - iio_device_unregister(indio_dev); - - return 0; -} - -static struct i2c_device_id tsl2x7x_idtable[] = { - { "tsl2571", tsl2571 }, - { "tsl2671", tsl2671 }, - { "tmd2671", tmd2671 }, - { "tsl2771", tsl2771 }, - { "tmd2771", tmd2771 }, - { "tsl2572", tsl2572 }, - { "tsl2672", tsl2672 }, - { "tmd2672", tmd2672 }, - { "tsl2772", tsl2772 }, - { "tmd2772", tmd2772 }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); - -static const struct dev_pm_ops tsl2x7x_pm_ops = { - .suspend = tsl2x7x_suspend, - .resume = tsl2x7x_resume, -}; - -/* Driver definition */ -static struct i2c_driver tsl2x7x_driver = { - .driver = { - .name = "tsl2x7x", - .pm = &tsl2x7x_pm_ops, - }, - .id_table = tsl2x7x_idtable, - .probe = tsl2x7x_probe, - .remove = tsl2x7x_remove, -}; - -module_i2c_driver(tsl2x7x_driver); - -MODULE_AUTHOR("J. August Brenner"); -MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8d043004838daff5e75aa6705380e02dd17544d0 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Thu, 4 May 2017 22:38:31 +0200 Subject: tsl2x7x: remove paragraph about writing to the FSF's mailing address Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL. Signed-off-by: Enric Balletbo i Serra Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2x7x.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c index 8121a5188638..a912e9ec87f2 100644 --- a/drivers/staging/iio/light/tsl2x7x.c +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -13,10 +13,6 @@ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include -- cgit v1.2.3 From 40f4b1f031a71dcf111f64a3c20ee0361b96d862 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 4 May 2017 22:10:52 +0200 Subject: iio: hid-sensor-accel-3d: Drop unnecessary static Drop static on a local variable, when the variable is initialized before use, on every possible execution path through the function. The static has no benefit, and dropping it reduces the code size. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @bad exists@ position p; identifier x; type T; @@ static T x@p; ... x = <+...x...+> @@ identifier x; expression e; type T; position p != bad.p; @@ -static T x@p; ... when != x when strict ?x = e; // The change in code size is indicates by the following output from the size command. before: text data bss dec hex filename 3879 512 8 4399 112f drivers/iio/accel/hid-sensor-accel-3d.o after: text data bss dec hex filename 3863 512 0 4375 1117 drivers/iio/accel/hid-sensor-accel-3d.o Signed-off-by: Julia Lawall Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 43a6cb078193..2238a26aba63 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -347,7 +347,7 @@ static int accel_3d_parse_report(struct platform_device *pdev, static int hid_accel_3d_probe(struct platform_device *pdev) { int ret = 0; - static const char *name; + const char *name; struct iio_dev *indio_dev; struct accel_3d_state *accel_state; const struct iio_chan_spec *channel_spec; -- cgit v1.2.3 From de01d65795647e66b29bf1400c2b5c39998a47d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Mon, 1 May 2017 13:19:41 +0200 Subject: iio: Documentation: sysfs-bus-iio-meas-spec: Remove (partially) duplicate line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stefan Brüns Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-meas-spec | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec index 1a6265e92e2f..6d47e548eee5 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec +++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec @@ -5,4 +5,3 @@ Description: Reading returns either '1' or '0'. '1' means that the battery level supplied to sensor is below 2.25V. This ABI is available for tsys02d, htu21, ms8607 - This ABI is available for htu21, ms8607 -- cgit v1.2.3 From ac23d64defcdce0dad93e10ac7f202430f713729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Mon, 1 May 2017 13:19:42 +0200 Subject: iio: adc: Fix bad GENMASK use, typos, whitespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 7906dd52c5a0 ("iio: ina2xx: Fix whitespace and re-order code") changed the register number of the MASK_ENABLE register from 0x06 to the value equivalent GENMASK(2,1), although its no mask. Also fix a typo (INA2_6_6 instead of INA2_2_6), and use the datasheet name ("Mask/Enable") for the register number define. Fix bad indentation for channel attributes. Signed-off-by: Stefan Brüns Acked-by: Andrew F. Davis Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index db9838230257..6b588ac3130c 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -42,8 +42,8 @@ #define INA2XX_CURRENT 0x04 /* readonly */ #define INA2XX_CALIBRATION 0x05 -#define INA226_ALERT_MASK GENMASK(2, 1) -#define INA266_CVRF BIT(3) +#define INA226_MASK_ENABLE 0x06 +#define INA226_CVRF BIT(3) #define INA2XX_MAX_REGISTERS 8 @@ -417,8 +417,8 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev, .address = (_address), \ .indexed = 1, \ .channel = (_index), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ - | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ .scan_index = (_index), \ @@ -481,12 +481,12 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) */ if (!chip->allow_async_readout) do { - ret = regmap_read(chip->regmap, INA226_ALERT_MASK, + ret = regmap_read(chip->regmap, INA226_MASK_ENABLE, &alert); if (ret < 0) return ret; - alert &= INA266_CVRF; + alert &= INA226_CVRF; } while (!alert); /* -- cgit v1.2.3 From f80ac400ee762bba3a420a4a537ce6ae7854b657 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Thu, 4 May 2017 15:13:20 +0300 Subject: iio: tools: generic_buffer: increase trigger length Increased trigger length to 64 in order to cope with trigger names like fc030000.adc-dev0-external-rising Signed-off-by: Eugen Hristev Signed-off-by: Jonathan Cameron --- tools/iio/iio_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index 780f2014f8fa..8b379da26e35 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -13,7 +13,7 @@ #include /* Made up value to limit allocation sizes */ -#define IIO_MAX_NAME_LENGTH 30 +#define IIO_MAX_NAME_LENGTH 64 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" #define FORMAT_TYPE_FILE "%s_type" -- cgit v1.2.3 From 6fb34812c2a2a4cdcdad4452b9634892812fa97b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 2 May 2017 14:33:45 +0200 Subject: iio: stm32 trigger: Add support for TRGO2 triggers Add support for TRGO2 trigger that can be found on STM32F7. Add additional master modes supported by TRGO2. Register additional "tim[1/8]_trgo2" triggers for timer1 & timer8. Detect TRGO2 timer capability (master mode selection 2). Signed-off-by: Fabrice Gasnier Acked-by: Benjamin Gaignard Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-timer-stm32 | 48 +++++++++ drivers/iio/trigger/stm32-timer-trigger.c | 113 ++++++++++++++++++--- include/linux/iio/timer/stm32-timer-trigger.h | 2 + include/linux/mfd/stm32-timers.h | 2 + 4 files changed, 151 insertions(+), 14 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 index 230020e06677..deb015935683 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 @@ -16,6 +16,54 @@ Description: - "OC2REF" : OC2REF signal is used as trigger output. - "OC3REF" : OC3REF signal is used as trigger output. - "OC4REF" : OC4REF signal is used as trigger output. + Additional modes (on TRGO2 only): + - "OC5REF" : OC5REF signal is used as trigger output. + - "OC6REF" : OC6REF signal is used as trigger output. + - "compare_pulse_OC4REF": + OC4REF rising or falling edges generate pulses. + - "compare_pulse_OC6REF": + OC6REF rising or falling edges generate pulses. + - "compare_pulse_OC4REF_r_or_OC6REF_r": + OC4REF or OC6REF rising edges generate pulses. + - "compare_pulse_OC4REF_r_or_OC6REF_f": + OC4REF rising or OC6REF falling edges generate pulses. + - "compare_pulse_OC5REF_r_or_OC6REF_r": + OC5REF or OC6REF rising edges generate pulses. + - "compare_pulse_OC5REF_r_or_OC6REF_f": + OC5REF rising or OC6REF falling edges generate pulses. + + +-----------+ +-------------+ +---------+ + | Prescaler +-> | Counter | +-> | Master | TRGO(2) + +-----------+ +--+--------+-+ |-> | Control +--> + | | || +---------+ + +--v--------+-+ OCxREF || +---------+ + | Chx compare +----------> | Output | ChX + +-----------+-+ | | Control +--> + . | | +---------+ + . | | . + +-----------v-+ OC6REF | . + | Ch6 compare +---------+> + +-------------+ + + Example with: "compare_pulse_OC4REF_r_or_OC6REF_r": + + X + X X + X . . X + X . . X + X . . X + count X . . . . X + . . . . + . . . . + +---------------+ + OC4REF | . . | + +-+ . . +-+ + . +---+ . + OC6REF . | | . + +-------+ +-------+ + +-+ +-+ + TRGO2 | | | | + +-+ +---+ +---------+ What: /sys/bus/iio/devices/triggerX/master_mode KernelVersion: 4.11 diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 25248d644e7c..0797f2fe584f 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -14,19 +14,19 @@ #include #include -#define MAX_TRIGGERS 6 +#define MAX_TRIGGERS 7 #define MAX_VALIDS 5 /* List the triggers created by each timer */ static const void *triggers_table[][MAX_TRIGGERS] = { - { TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, + { TIM1_TRGO, TIM1_TRGO2, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, { TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,}, { TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,}, { TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,}, { TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,}, { TIM6_TRGO,}, { TIM7_TRGO,}, - { TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, + { TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, { TIM9_TRGO, TIM9_CH1, TIM9_CH2,}, { }, /* timer 10 */ { }, /* timer 11 */ @@ -56,9 +56,16 @@ struct stm32_timer_trigger { u32 max_arr; const void *triggers; const void *valids; + bool has_trgo2; }; +static bool stm32_timer_is_trgo2_name(const char *name) +{ + return !!strstr(name, "trgo2"); +} + static int stm32_timer_start(struct stm32_timer_trigger *priv, + struct iio_trigger *trig, unsigned int frequency) { unsigned long long prd, div; @@ -102,7 +109,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); /* Force master mode to update mode */ - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20); + if (stm32_timer_is_trgo2_name(trig->name)) + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, + 0x2 << TIM_CR2_MMS2_SHIFT); + else + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, + 0x2 << TIM_CR2_MMS_SHIFT); /* Make sure that registers are updated */ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); @@ -150,7 +162,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev, if (freq == 0) { stm32_timer_stop(priv); } else { - ret = stm32_timer_start(priv, freq); + ret = stm32_timer_start(priv, trig, freq); if (ret) return ret; } @@ -183,6 +195,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(0660, stm32_tt_read_frequency, stm32_tt_store_frequency); +#define MASTER_MODE_MAX 7 +#define MASTER_MODE2_MAX 15 + static char *master_mode_table[] = { "reset", "enable", @@ -191,7 +206,16 @@ static char *master_mode_table[] = { "OC1REF", "OC2REF", "OC3REF", - "OC4REF" + "OC4REF", + /* Master mode selection 2 only */ + "OC5REF", + "OC6REF", + "compare_pulse_OC4REF", + "compare_pulse_OC6REF", + "compare_pulse_OC4REF_r_or_OC6REF_r", + "compare_pulse_OC4REF_r_or_OC6REF_f", + "compare_pulse_OC5REF_r_or_OC6REF_r", + "compare_pulse_OC5REF_r_or_OC6REF_f", }; static ssize_t stm32_tt_show_master_mode(struct device *dev, @@ -199,10 +223,15 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev, char *buf) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); + struct iio_trigger *trig = to_iio_trigger(dev); u32 cr2; regmap_read(priv->regmap, TIM_CR2, &cr2); - cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; + + if (stm32_timer_is_trgo2_name(trig->name)) + cr2 = (cr2 & TIM_CR2_MMS2) >> TIM_CR2_MMS2_SHIFT; + else + cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]); } @@ -212,13 +241,25 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, const char *buf, size_t len) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); + struct iio_trigger *trig = to_iio_trigger(dev); + u32 mask, shift, master_mode_max; int i; - for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) { + if (stm32_timer_is_trgo2_name(trig->name)) { + mask = TIM_CR2_MMS2; + shift = TIM_CR2_MMS2_SHIFT; + master_mode_max = MASTER_MODE2_MAX; + } else { + mask = TIM_CR2_MMS; + shift = TIM_CR2_MMS_SHIFT; + master_mode_max = MASTER_MODE_MAX; + } + + for (i = 0; i <= master_mode_max; i++) { if (!strncmp(master_mode_table[i], buf, strlen(master_mode_table[i]))) { - regmap_update_bits(priv->regmap, TIM_CR2, - TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT); + regmap_update_bits(priv->regmap, TIM_CR2, mask, + i << shift); /* Make sure that registers are updated */ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); @@ -229,8 +270,31 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, return -EINVAL; } -static IIO_CONST_ATTR(master_mode_available, - "reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF"); +static ssize_t stm32_tt_show_master_mode_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_trigger *trig = to_iio_trigger(dev); + unsigned int i, master_mode_max; + size_t len = 0; + + if (stm32_timer_is_trgo2_name(trig->name)) + master_mode_max = MASTER_MODE2_MAX; + else + master_mode_max = MASTER_MODE_MAX; + + for (i = 0; i <= master_mode_max; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%s ", master_mode_table[i]); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR(master_mode_available, 0444, + stm32_tt_show_master_mode_avail, NULL, 0); static IIO_DEVICE_ATTR(master_mode, 0660, stm32_tt_show_master_mode, @@ -240,7 +304,7 @@ static IIO_DEVICE_ATTR(master_mode, 0660, static struct attribute *stm32_trigger_attrs[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_master_mode.dev_attr.attr, - &iio_const_attr_master_mode_available.dev_attr.attr, + &iio_dev_attr_master_mode_available.dev_attr.attr, NULL, }; @@ -264,6 +328,12 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) while (cur && *cur) { struct iio_trigger *trig; + bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur); + + if (cur_is_trgo2 && !priv->has_trgo2) { + cur++; + continue; + } trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur); if (!trig) @@ -277,7 +347,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) * should only be available on trgo trigger which * is always the first in the list. */ - if (cur == priv->triggers) + if (cur == priv->triggers || cur_is_trgo2) trig->dev.groups = stm32_trigger_attr_groups; iio_trigger_set_drvdata(trig, priv); @@ -584,6 +654,20 @@ bool is_stm32_timer_trigger(struct iio_trigger *trig) } EXPORT_SYMBOL(is_stm32_timer_trigger); +static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) +{ + u32 val; + + /* + * Master mode selection 2 bits can only be written and read back when + * timer supports it. + */ + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2); + regmap_read(priv->regmap, TIM_CR2, &val); + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + priv->has_trgo2 = !!val; +} + static int stm32_timer_trigger_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -614,6 +698,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) priv->max_arr = ddata->max_arr; priv->triggers = triggers_table[index]; priv->valids = valids_table[index]; + stm32_timer_detect_trgo2(priv); ret = stm32_setup_iio_triggers(priv); if (ret) diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h index 55535aef2e6c..fa7d786ed99e 100644 --- a/include/linux/iio/timer/stm32-timer-trigger.h +++ b/include/linux/iio/timer/stm32-timer-trigger.h @@ -10,6 +10,7 @@ #define _STM32_TIMER_TRIGGER_H_ #define TIM1_TRGO "tim1_trgo" +#define TIM1_TRGO2 "tim1_trgo2" #define TIM1_CH1 "tim1_ch1" #define TIM1_CH2 "tim1_ch2" #define TIM1_CH3 "tim1_ch3" @@ -44,6 +45,7 @@ #define TIM7_TRGO "tim7_trgo" #define TIM8_TRGO "tim8_trgo" +#define TIM8_TRGO2 "tim8_trgo2" #define TIM8_CH1 "tim8_ch1" #define TIM8_CH2 "tim8_ch2" #define TIM8_CH3 "tim8_ch3" diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index 4a0abbc10ef6..ce7346e7f77a 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -34,6 +34,7 @@ #define TIM_CR1_DIR BIT(4) /* Counter Direction */ #define TIM_CR1_ARPE BIT(7) /* Auto-reload Preload Ena */ #define TIM_CR2_MMS (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */ +#define TIM_CR2_MMS2 GENMASK(23, 20) /* Master mode selection 2 */ #define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */ #define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */ #define TIM_DIER_UIE BIT(0) /* Update interrupt */ @@ -60,6 +61,7 @@ #define MAX_TIM_PSC 0xFFFF #define TIM_CR2_MMS_SHIFT 4 +#define TIM_CR2_MMS2_SHIFT 20 #define TIM_SMCR_TS_SHIFT 4 #define TIM_BDTR_BKF_MASK 0xF #define TIM_BDTR_BKF_SHIFT 16 -- cgit v1.2.3 From e7215fe4d51e69c9d2608ad0c409d48e844d0adc Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 14 May 2017 10:43:55 +0200 Subject: iio: pressure: zpa2326: report interrupted case as failure If the timeout-case prints a warning message then probably the interrupted case should also. Further, wait_for_completion_interruptible_timeout() returns long not int. Fixes: commit 03b262f2bbf4 ("iio:pressure: initial zpa2326 barometer support") Signed-off-by: Nicholas Mc Guire Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/zpa2326.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index e58a0ad07477..c92a95f9f52c 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -867,12 +867,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, { int ret; unsigned int val; + long timeout; zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt"); - ret = wait_for_completion_interruptible_timeout( + timeout = wait_for_completion_interruptible_timeout( &private->data_ready, ZPA2326_CONVERSION_JIFFIES); - if (ret > 0) + if (timeout > 0) /* * Interrupt handler completed before timeout: return operation * status. @@ -882,13 +883,16 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, /* Clear all interrupts just to be sure. */ regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val); - if (!ret) + if (!timeout) { /* Timed out. */ + zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)", + timeout); ret = -ETIME; - - if (ret != -ERESTARTSYS) - zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)", - ret); + } else if (timeout < 0) { + zpa2326_warn(indio_dev, + "wait for one shot interrupt cancelled"); + ret = -ERESTARTSYS; + } return ret; } -- cgit v1.2.3 From b2d2d2bfca6832ae61f80c5fbc9e7cdc566d04b4 Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Mon, 8 May 2017 09:26:24 +0200 Subject: iio:ad5064: Add support for ltc2633 and similar devices The Linear Technology LTC2631, LTC2633 and LTC2635 are very similar to the AD5064 device, in particular the LTC2627. This patch adds support for those devices. Only the LTC2633 has been tested, which is the 2-channel variant. The LTC2631 is the 1-channel, and the LTC2635 the 4-channel version. The actual DAC resolution depends on the exact chip type and can be 12, 10 or 8 bits, using the upper bits so this has no effect on the register map. The internal reference is set to 2.5V on "L" versions, and it's 4.096V for "H" versions. Datasheets: LTC2631: http://www.linear.com/docs/26553 LTC2633: http://www.linear.com/docs/39529 LTC2635: http://www.linear.com/docs/28754 Signed-off-by: Mike Looijmans Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 3 +- drivers/iio/dac/ad5064.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index df5abc46cd3f..25bed2d7d2b9 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -13,7 +13,8 @@ config AD5064 AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, - LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to Analog Converter. + LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635 + Digital to Analog Converter. To compile this driver as a module, choose M here: the module will be called ad5064. diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 6803e4a137cd..3f9399c27869 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -2,8 +2,8 @@ * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, * AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, * AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, - * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to analog converters - * driver + * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635 + * Digital to analog converters driver * * Copyright 2011 Analog Devices Inc. * @@ -168,6 +168,24 @@ enum ad5064_type { ID_LTC2626, ID_LTC2627, ID_LTC2629, + ID_LTC2631_L12, + ID_LTC2631_H12, + ID_LTC2631_L10, + ID_LTC2631_H10, + ID_LTC2631_L8, + ID_LTC2631_H8, + ID_LTC2633_L12, + ID_LTC2633_H12, + ID_LTC2633_L10, + ID_LTC2633_H10, + ID_LTC2633_L8, + ID_LTC2633_H8, + ID_LTC2635_L12, + ID_LTC2635_H12, + ID_LTC2635_L10, + ID_LTC2635_H10, + ID_LTC2635_L8, + ID_LTC2635_H8, }; static int ad5064_write(struct ad5064_state *st, unsigned int cmd, @@ -425,6 +443,19 @@ static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info); static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info); static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info); static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info); +#define ltc2631_12_channels ltc2627_channels +static DECLARE_AD5064_CHANNELS(ltc2631_10_channels, 10, 6, ltc2617_ext_info); +static DECLARE_AD5064_CHANNELS(ltc2631_8_channels, 8, 8, ltc2617_ext_info); + +#define LTC2631_INFO(vref, pchannels, nchannels) \ + { \ + .shared_vref = true, \ + .internal_vref = vref, \ + .channels = pchannels, \ + .num_channels = nchannels, \ + .regmap_type = AD5064_REGMAP_LTC, \ + } + static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { [ID_AD5024] = { @@ -724,6 +755,24 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { .num_channels = 4, .regmap_type = AD5064_REGMAP_LTC, }, + [ID_LTC2631_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 1), + [ID_LTC2631_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 1), + [ID_LTC2631_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 1), + [ID_LTC2631_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 1), + [ID_LTC2631_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 1), + [ID_LTC2631_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 1), + [ID_LTC2633_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 2), + [ID_LTC2633_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 2), + [ID_LTC2633_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 2), + [ID_LTC2633_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 2), + [ID_LTC2633_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 2), + [ID_LTC2633_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 2), + [ID_LTC2635_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 4), + [ID_LTC2635_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 4), + [ID_LTC2635_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 4), + [ID_LTC2635_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 4), + [ID_LTC2635_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 4), + [ID_LTC2635_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 4), }; static inline unsigned int ad5064_num_vref(struct ad5064_state *st) @@ -982,6 +1031,24 @@ static const struct i2c_device_id ad5064_i2c_ids[] = { {"ltc2626", ID_LTC2626}, {"ltc2627", ID_LTC2627}, {"ltc2629", ID_LTC2629}, + {"ltc2631-l12", ID_LTC2631_L12}, + {"ltc2631-h12", ID_LTC2631_H12}, + {"ltc2631-l10", ID_LTC2631_L10}, + {"ltc2631-h10", ID_LTC2631_H10}, + {"ltc2631-l8", ID_LTC2631_L8}, + {"ltc2631-h8", ID_LTC2631_H8}, + {"ltc2633-l12", ID_LTC2633_L12}, + {"ltc2633-h12", ID_LTC2633_H12}, + {"ltc2633-l10", ID_LTC2633_L10}, + {"ltc2633-h10", ID_LTC2633_H10}, + {"ltc2633-l8", ID_LTC2633_L8}, + {"ltc2633-h8", ID_LTC2633_H8}, + {"ltc2635-l12", ID_LTC2635_L12}, + {"ltc2635-h12", ID_LTC2635_H12}, + {"ltc2635-l10", ID_LTC2635_L10}, + {"ltc2635-h10", ID_LTC2635_H10}, + {"ltc2635-l8", ID_LTC2635_L8}, + {"ltc2635-h8", ID_LTC2635_H8}, {} }; MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); -- cgit v1.2.3 From 4ae2f37a2f35f72f52e1b51a38558ff28a09ef30 Mon Sep 17 00:00:00 2001 From: Harinath Nampally Date: Tue, 9 May 2017 19:41:53 -0400 Subject: staging: iio: meter: Fix the identations for proper alignments. This patch fixes below checkpatch.pl kind of warnings: CHECK: Alignment should match open parenthesis Signed-off-by: Harinath Nampally Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7753.c | 55 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index c0f258c53d3f..ce26abdeab92 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -107,9 +107,8 @@ static int ade7753_spi_write_reg_8(struct device *dev, return ret; } -static int ade7753_spi_write_reg_16(struct device *dev, - u8 reg_address, - u16 value) +static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address, + u16 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -126,8 +125,8 @@ static int ade7753_spi_write_reg_16(struct device *dev, } static int ade7753_spi_read_reg_8(struct device *dev, - u8 reg_address, - u8 *val) + u8 reg_address, + u8 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); @@ -136,7 +135,7 @@ static int ade7753_spi_read_reg_8(struct device *dev, ret = spi_w8r8(st->us, ADE7753_READ_REG(reg_address)); if (ret < 0) { dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X", - reg_address); + reg_address); return ret; } *val = ret; @@ -145,8 +144,8 @@ static int ade7753_spi_read_reg_8(struct device *dev, } static int ade7753_spi_read_reg_16(struct device *dev, - u8 reg_address, - u16 *val) + u8 reg_address, + u16 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); @@ -165,8 +164,8 @@ static int ade7753_spi_read_reg_16(struct device *dev, } static int ade7753_spi_read_reg_24(struct device *dev, - u8 reg_address, - u32 *val) + u8 reg_address, + u32 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); @@ -189,7 +188,7 @@ static int ade7753_spi_read_reg_24(struct device *dev, ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) { dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X", - reg_address); + reg_address); goto error_ret; } *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2]; @@ -200,8 +199,8 @@ error_ret: } static ssize_t ade7753_read_8bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u8 val; @@ -215,8 +214,8 @@ static ssize_t ade7753_read_8bit(struct device *dev, } static ssize_t ade7753_read_16bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u16 val; @@ -230,8 +229,8 @@ static ssize_t ade7753_read_16bit(struct device *dev, } static ssize_t ade7753_read_24bit(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u32 val; @@ -245,9 +244,9 @@ static ssize_t ade7753_read_24bit(struct device *dev, } static ssize_t ade7753_write_8bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -263,9 +262,9 @@ error_ret: } static ssize_t ade7753_write_16bit(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int ret; @@ -450,8 +449,8 @@ err_ret: } static ssize_t ade7753_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { int ret; u16 t; @@ -468,9 +467,9 @@ static ssize_t ade7753_read_frequency(struct device *dev, } static ssize_t ade7753_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) + struct device_attribute *attr, + const char *buf, + size_t len) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7753_state *st = iio_priv(indio_dev); -- cgit v1.2.3 From f98f3be84ec75e51d822bfe502cacaec3735f795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Lindahl?= Date: Tue, 9 May 2017 18:05:00 +0200 Subject: dt-bindings: iio: adc: add driver for the ti-adc084s021 chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the Texas Instruments ADC084S021 ADC chip. Signed-off-by: MÃ¥rten Lindahl Acked-by: Rob Herring Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/ti-adc084s021.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt new file mode 100644 index 000000000000..4259e50620bc --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt @@ -0,0 +1,19 @@ +* Texas Instruments' ADC084S021 + +Required properties: + - compatible : Must be "ti,adc084s021" + - reg : SPI chip select number for the device + - vref-supply : The regulator supply for ADC reference voltage + - spi-cpol : Per spi-bus bindings + - spi-cpha : Per spi-bus bindings + - spi-max-frequency : Per spi-bus bindings + +Example: +adc@0 { + compatible = "ti,adc084s021"; + reg = <0>; + vref-supply = <&adc_vref>; + spi-cpol; + spi-cpha; + spi-max-frequency = <16000000>; +}; -- cgit v1.2.3 From 3691e5a694491bd54743cfc862cc3859d4be92db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Lindahl?= Date: Tue, 9 May 2017 18:05:01 +0200 Subject: iio: adc: add driver for the ti-adc084s021 chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for the Texas Instruments ADC084S021 ADC chip. Signed-off-by: MÃ¥rten Lindahl Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-adc084s021.c | 275 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 drivers/iio/adc/ti-adc084s021.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 0b8915298bf1..9e08b8afccc6 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -670,6 +670,18 @@ config TI_ADC0832 This driver can also be built as a module. If so, the module will be called ti-adc0832. +config TI_ADC084S021 + tristate "Texas Instruments ADC084S021" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADC084S021 + chips. + + This driver can also be built as a module. If so, the module will be + called ti-adc084s021. + config TI_ADC12138 tristate "Texas Instruments ADC12130/ADC12132/ADC12138" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 56e5fabece4c..ed8e8e220dbb 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o obj-$(CONFIG_STM32_ADC) += stm32-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o +obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c new file mode 100644 index 000000000000..a355121c11a4 --- /dev/null +++ b/drivers/iio/adc/ti-adc084s021.c @@ -0,0 +1,275 @@ +/** + * Copyright (C) 2017 Axis Communications AB + * + * Driver for Texas Instruments' ADC084S021 ADC chip. + * Datasheets can be found here: + * http://www.ti.com/lit/ds/symlink/adc084s021.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC084S021_DRIVER_NAME "adc084s021" + +struct adc084s021 { + struct spi_device *spi; + struct spi_message message; + struct spi_transfer spi_trans; + struct regulator *reg; + struct mutex lock; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache line. + */ + u16 tx_buf[4] ____cacheline_aligned; + __be16 rx_buf[5]; /* First 16-bits are trash */ +}; + +#define ADC084S021_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .channel = (num), \ + .indexed = 1, \ + .scan_index = (num), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 8, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ + } + +static const struct iio_chan_spec adc084s021_channels[] = { + ADC084S021_VOLTAGE_CHANNEL(0), + ADC084S021_VOLTAGE_CHANNEL(1), + ADC084S021_VOLTAGE_CHANNEL(2), + ADC084S021_VOLTAGE_CHANNEL(3), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +/** + * Read an ADC channel and return its value. + * + * @adc: The ADC SPI data. + * @data: Buffer for converted data. + */ +static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data) +{ + int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */ + int ret, i = 0; + u16 *p = data; + + /* Do the transfer */ + ret = spi_sync(adc->spi, &adc->message); + if (ret < 0) + return ret; + + for (; i < n_words; i++) + *(p + i) = adc->rx_buf[i + 1]; + + return ret; +} + +static int adc084s021_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct adc084s021 *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret < 0) + return ret; + + ret = regulator_enable(adc->reg); + if (ret) { + iio_device_release_direct_mode(indio_dev); + return ret; + } + + adc->tx_buf[0] = channel->channel << 3; + ret = adc084s021_adc_conversion(adc, val); + iio_device_release_direct_mode(indio_dev); + regulator_disable(adc->reg); + if (ret < 0) + return ret; + + *val = be16_to_cpu(*val); + *val = (*val >> channel->scan_type.shift) & 0xff; + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_enable(adc->reg); + if (ret) + return ret; + + ret = regulator_get_voltage(adc->reg); + regulator_disable(adc->reg); + if (ret < 0) + return ret; + + *val = ret / 1000; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +/** + * Read enabled ADC channels and push data to the buffer. + * + * @irq: The interrupt number (not used). + * @pollfunc: Pointer to the poll func. + */ +static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc) +{ + struct iio_poll_func *pf = pollfunc; + struct iio_dev *indio_dev = pf->indio_dev; + struct adc084s021 *adc = iio_priv(indio_dev); + __be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */ + + mutex_lock(&adc->lock); + + if (adc084s021_adc_conversion(adc, &data) < 0) + dev_err(&adc->spi->dev, "Failed to read data\n"); + + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); + mutex_unlock(&adc->lock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int adc084s021_buffer_preenable(struct iio_dev *indio_dev) +{ + struct adc084s021 *adc = iio_priv(indio_dev); + int scan_index; + int i = 0; + + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + const struct iio_chan_spec *channel = + &indio_dev->channels[scan_index]; + adc->tx_buf[i++] = channel->channel << 3; + } + adc->spi_trans.len = 2 + (i * sizeof(__be16)); /* Trash + channels */ + + return regulator_enable(adc->reg); +} + +static int adc084s021_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct adc084s021 *adc = iio_priv(indio_dev); + + adc->spi_trans.len = 4; /* Trash + single channel */ + + return regulator_disable(adc->reg); +} + +static const struct iio_info adc084s021_info = { + .read_raw = adc084s021_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct iio_buffer_setup_ops adc084s021_buffer_setup_ops = { + .preenable = adc084s021_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = adc084s021_buffer_postdisable, +}; + +static int adc084s021_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adc084s021 *adc; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) { + dev_err(&spi->dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + adc = iio_priv(indio_dev); + adc->spi = spi; + + /* Connect the SPI device and the iio dev */ + spi_set_drvdata(spi, indio_dev); + + /* Initiate the Industrial I/O device */ + indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &adc084s021_info; + indio_dev->channels = adc084s021_channels; + indio_dev->num_channels = ARRAY_SIZE(adc084s021_channels); + + /* Create SPI transfer for channel reads */ + adc->spi_trans.tx_buf = adc->tx_buf; + adc->spi_trans.rx_buf = adc->rx_buf; + adc->spi_trans.len = 4; /* Trash + single channel */ + spi_message_init_with_transfers(&adc->message, &adc->spi_trans, 1); + + adc->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(adc->reg)) + return PTR_ERR(adc->reg); + + mutex_init(&adc->lock); + + /* Setup triggered buffer with pollfunction */ + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL, + adc084s021_buffer_trigger_handler, + &adc084s021_buffer_setup_ops); + if (ret) { + dev_err(&spi->dev, "Failed to setup triggered buffer\n"); + return ret; + } + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static const struct of_device_id adc084s021_of_match[] = { + { .compatible = "ti,adc084s021", }, + {}, +}; +MODULE_DEVICE_TABLE(of, adc084s021_of_match); + +static const struct spi_device_id adc084s021_id[] = { + { ADC084S021_DRIVER_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, adc084s021_id); + +static struct spi_driver adc084s021_driver = { + .driver = { + .name = ADC084S021_DRIVER_NAME, + .of_match_table = of_match_ptr(adc084s021_of_match), + }, + .probe = adc084s021_probe, + .id_table = adc084s021_id, +}; +module_spi_driver(adc084s021_driver); + +MODULE_AUTHOR("MÃ¥rten Lindahl "); +MODULE_DESCRIPTION("Texas Instruments ADC084S021"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); -- cgit v1.2.3 From b7079eeac5da0d50a89a73969ff390e8cdecec44 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 14 May 2017 17:45:44 +0200 Subject: iio: humidity: hts221: add power management support Add system sleep power management support to hts221 driver Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/humidity/hts221.h | 3 +++ drivers/iio/humidity/hts221_core.c | 54 +++++++++++++++++++++++++++++++++++--- drivers/iio/humidity/hts221_i2c.c | 1 + drivers/iio/humidity/hts221_spi.c | 1 + 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/iio/humidity/hts221.h b/drivers/iio/humidity/hts221.h index c7154665512e..94510266e0a5 100644 --- a/drivers/iio/humidity/hts221.h +++ b/drivers/iio/humidity/hts221.h @@ -57,12 +57,15 @@ struct hts221_hw { struct hts221_sensor sensors[HTS221_SENSOR_MAX]; + bool enabled; u8 odr; const struct hts221_transfer_function *tf; struct hts221_transfer_buffer tb; }; +extern const struct dev_pm_ops hts221_pm_ops; + int hts221_config_drdy(struct hts221_hw *hw, bool enable); int hts221_probe(struct iio_dev *iio_dev); int hts221_power_on(struct hts221_hw *hw); diff --git a/drivers/iio/humidity/hts221_core.c b/drivers/iio/humidity/hts221_core.c index 3f3ef4a1a474..a56da3999e00 100644 --- a/drivers/iio/humidity/hts221_core.c +++ b/drivers/iio/humidity/hts221_core.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "hts221.h" @@ -307,15 +308,30 @@ hts221_sysfs_temp_oversampling_avail(struct device *dev, int hts221_power_on(struct hts221_hw *hw) { - return hts221_update_odr(hw, hw->odr); + int err; + + err = hts221_update_odr(hw, hw->odr); + if (err < 0) + return err; + + hw->enabled = true; + + return 0; } int hts221_power_off(struct hts221_hw *hw) { - u8 data[] = {0x00, 0x00}; + __le16 data = 0; + int err; - return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), - data); + err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), + (u8 *)&data); + if (err < 0) + return err; + + hw->enabled = false; + + return 0; } static int hts221_parse_temp_caldata(struct hts221_hw *hw) @@ -682,6 +698,36 @@ int hts221_probe(struct iio_dev *iio_dev) } EXPORT_SYMBOL(hts221_probe); +static int __maybe_unused hts221_suspend(struct device *dev) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct hts221_hw *hw = iio_priv(iio_dev); + __le16 data = 0; + int err; + + err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data), + (u8 *)&data); + + return err < 0 ? err : 0; +} + +static int __maybe_unused hts221_resume(struct device *dev) +{ + struct iio_dev *iio_dev = dev_get_drvdata(dev); + struct hts221_hw *hw = iio_priv(iio_dev); + int err = 0; + + if (hw->enabled) + err = hts221_update_odr(hw, hw->odr); + + return err; +} + +const struct dev_pm_ops hts221_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(hts221_suspend, hts221_resume) +}; +EXPORT_SYMBOL(hts221_pm_ops); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 8333c0296c0e..f38e4b7e0160 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table); static struct i2c_driver hts221_driver = { .driver = { .name = "hts221_i2c", + .pm = &hts221_pm_ops, .of_match_table = of_match_ptr(hts221_i2c_of_match), .acpi_match_table = ACPI_PTR(hts221_acpi_match), }, diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index 70df5e7150c1..57cbc256771b 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(spi, hts221_spi_id_table); static struct spi_driver hts221_driver = { .driver = { .name = "hts221_spi", + .pm = &hts221_pm_ops, .of_match_table = of_match_ptr(hts221_spi_of_match), }, .probe = hts221_spi_probe, -- cgit v1.2.3 From 371894f5d1a00cd6c03aab0beb9789b474ea46b0 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Tue, 25 Apr 2017 04:06:33 -0400 Subject: iio: tsl2583: add runtime power management support This patch adds runtime power management support to the tsl2583 driver. The device is powered off after two seconds of inactivity. Verified that the driver still functions correctly using a TSL2581 hooked up to a Raspberry Pi 2. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/iio/light/tsl2583.c | 106 +++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/drivers/iio/light/tsl2583.c b/drivers/iio/light/tsl2583.c index a78b6025c465..1679181d2bdd 100644 --- a/drivers/iio/light/tsl2583.c +++ b/drivers/iio/light/tsl2583.c @@ -3,7 +3,7 @@ * within the TAOS tsl258x family of devices (tsl2580, tsl2581, tsl2583). * * Copyright (c) 2011, TAOS Corporation. - * Copyright (c) 2016 Brian Masney + * Copyright (c) 2016-2017 Brian Masney * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include #include #include +#include /* Device Registers and Masks */ #define TSL2583_CNTRL 0x00 @@ -64,6 +65,8 @@ #define TSL2583_CHIP_ID 0x90 #define TSL2583_CHIP_ID_MASK 0xf0 +#define TSL2583_POWER_OFF_DELAY_MS 2000 + /* Per-device data */ struct tsl2583_als_info { u16 als_ch0; @@ -108,7 +111,6 @@ struct tsl2583_chip { struct tsl2583_settings als_settings; int als_time_scale; int als_saturation; - bool suspended; }; struct gainadj { @@ -460,8 +462,6 @@ static int tsl2583_chip_init_and_power_on(struct iio_dev *indio_dev) if (ret < 0) return ret; - chip->suspended = false; - return ret; } @@ -513,11 +513,6 @@ static ssize_t in_illuminance_calibrate_store(struct device *dev, mutex_lock(&chip->als_mutex); - if (chip->suspended) { - ret = -EBUSY; - goto done; - } - ret = tsl2583_als_calibrate(indio_dev); if (ret < 0) goto done; @@ -645,20 +640,36 @@ static const struct iio_chan_spec tsl2583_channels[] = { }, }; +static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on) +{ + int ret; + + if (on) { + ret = pm_runtime_get_sync(&chip->client->dev); + if (ret < 0) + pm_runtime_put_noidle(&chip->client->dev); + } else { + pm_runtime_mark_last_busy(&chip->client->dev); + ret = pm_runtime_put_autosuspend(&chip->client->dev); + } + + return ret; +} + static int tsl2583_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct tsl2583_chip *chip = iio_priv(indio_dev); - int ret = -EINVAL; + int ret, pm_ret; - mutex_lock(&chip->als_mutex); + ret = tsl2583_set_pm_runtime_busy(chip, true); + if (ret < 0) + return ret; - if (chip->suspended) { - ret = -EBUSY; - goto read_done; - } + mutex_lock(&chip->als_mutex); + ret = -EINVAL; switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type == IIO_LIGHT) { @@ -719,6 +730,18 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev, read_done: mutex_unlock(&chip->als_mutex); + if (ret < 0) + return ret; + + /* + * Preserve the ret variable if the call to + * tsl2583_set_pm_runtime_busy() is successful so the reading + * (if applicable) is returned to user space. + */ + pm_ret = tsl2583_set_pm_runtime_busy(chip, false); + if (pm_ret < 0) + return pm_ret; + return ret; } @@ -727,15 +750,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct tsl2583_chip *chip = iio_priv(indio_dev); - int ret = -EINVAL; + int ret; - mutex_lock(&chip->als_mutex); + ret = tsl2583_set_pm_runtime_busy(chip, true); + if (ret < 0) + return ret; - if (chip->suspended) { - ret = -EBUSY; - goto write_done; - } + mutex_lock(&chip->als_mutex); + ret = -EINVAL; switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: if (chan->type == IIO_LIGHT) { @@ -767,9 +790,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev, break; } -write_done: mutex_unlock(&chip->als_mutex); + if (ret < 0) + return ret; + + ret = tsl2583_set_pm_runtime_busy(chip, false); + if (ret < 0) + return ret; + return ret; } @@ -803,7 +832,6 @@ static int tsl2583_probe(struct i2c_client *clientp, i2c_set_clientdata(clientp, indio_dev); mutex_init(&chip->als_mutex); - chip->suspended = true; ret = i2c_smbus_read_byte_data(clientp, TSL2583_CMD_REG | TSL2583_CHIPID); @@ -826,6 +854,11 @@ static int tsl2583_probe(struct i2c_client *clientp, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->name = chip->client->name; + pm_runtime_enable(&clientp->dev); + pm_runtime_set_autosuspend_delay(&clientp->dev, + TSL2583_POWER_OFF_DELAY_MS); + pm_runtime_use_autosuspend(&clientp->dev); + ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev); if (ret) { dev_err(&clientp->dev, "%s: iio registration failed\n", @@ -836,16 +869,25 @@ static int tsl2583_probe(struct i2c_client *clientp, /* Load up the V2 defaults (these are hard coded defaults for now) */ tsl2583_defaults(chip); - /* Make sure the chip is on */ - ret = tsl2583_chip_init_and_power_on(indio_dev); - if (ret < 0) - return ret; - dev_info(&clientp->dev, "Light sensor found.\n"); return 0; } +static int tsl2583_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct tsl2583_chip *chip = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + return tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF); +} + static int __maybe_unused tsl2583_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); @@ -855,7 +897,6 @@ static int __maybe_unused tsl2583_suspend(struct device *dev) mutex_lock(&chip->als_mutex); ret = tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF); - chip->suspended = true; mutex_unlock(&chip->als_mutex); @@ -877,7 +918,11 @@ static int __maybe_unused tsl2583_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(tsl2583_pm_ops, tsl2583_suspend, tsl2583_resume); +static const struct dev_pm_ops tsl2583_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(tsl2583_suspend, tsl2583_resume, NULL) +}; static struct i2c_device_id tsl2583_idtable[] = { { "tsl2580", 0 }, @@ -904,6 +949,7 @@ static struct i2c_driver tsl2583_driver = { }, .id_table = tsl2583_idtable, .probe = tsl2583_probe, + .remove = tsl2583_remove, }; module_i2c_driver(tsl2583_driver); -- cgit v1.2.3 From 138bc7969c24c6cbba28e919c2376ad10a46fc60 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 7 Apr 2017 19:22:06 -0700 Subject: iio: hid-sensor-hub: Implement batch mode HID sensor hubs using Integrated Senor Hub (ISH) has added capability to support batch mode. This allows host processor to go to sleep for extended duration, while the sensor hub is storing samples in its internal buffers. 'Commit f4f4673b7535 ("iio: add support for hardware fifo")' implements feature in IIO core to implement such feature. This feature is used in bmc150-accel-core.c to implement batch mode. This implementation allows software device buffer watermark to be used as a hint to adjust hardware FIFO. But HID sensor hubs don't allow to change internal buffer size of FIFOs. Instead an additional usage id to set "maximum report latency" is defined. This allows host to go to sleep upto this latency period without getting any report. Since there is no ABI to set this latency, a new attribute "hwfifo_timeout" is added so that user mode can specify a latency. This change checks presence of usage id to get/set maximum report latency and if present, it will expose hwfifo_timeout. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 11 +++ .../iio/common/hid-sensors/hid-sensor-attributes.c | 44 ++++++++++++ .../iio/common/hid-sensors/hid-sensor-trigger.c | 80 ++++++++++++++++++++++ include/linux/hid-sensor-hub.h | 5 ++ include/linux/hid-sensor-ids.h | 3 + 5 files changed, 143 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 8c24d0892f61..2db2cdf42d54 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1425,6 +1425,17 @@ Description: guarantees that the hardware fifo is flushed to the device buffer. +What: /sys/bus/iio/devices/iio:device*/buffer/hwfifo_timeout +KernelVersion: 4.12 +Contact: linux-iio@vger.kernel.org +Description: + A read/write property to provide capability to delay reporting of + samples till a timeout is reached. This allows host processors to + sleep, while the sensor is storing samples in its internal fifo. + The maximum timeout in seconds can be specified by setting + hwfifo_timeout.The current delay can be read by reading + hwfifo_timeout. A value of 0 means that there is no timeout. + What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark KernelVersion: 4.2 Contact: linux-iio@vger.kernel.org diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 0e05f6d1e761..f5d4d786e193 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -410,6 +410,48 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, } +static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_common *st) +{ + sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, + usage_id, + HID_USAGE_SENSOR_PROP_REPORT_LATENCY, + &st->report_latency); + + hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n", + st->report_latency.index, st->report_latency.report_id); +} + +int hid_sensor_get_report_latency(struct hid_sensor_common *st) +{ + int ret; + int value; + + ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id, + st->report_latency.index, sizeof(value), + &value); + if (ret < 0) + return ret; + + return value; +} +EXPORT_SYMBOL(hid_sensor_get_report_latency); + +int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms) +{ + return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id, + st->report_latency.index, + sizeof(latency_ms), &latency_ms); +} +EXPORT_SYMBOL(hid_sensor_set_report_latency); + +bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) +{ + return st->report_latency.index > 0 && st->report_latency.report_id > 0; +} +EXPORT_SYMBOL(hid_sensor_batch_mode_supported); + int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, struct hid_sensor_common *st) @@ -451,6 +493,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, } else st->timestamp_ns_scale = 1000000000; + hid_sensor_get_report_latency_info(hsdev, usage_id, st); + hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n", st->poll.index, st->poll.report_id, st->report_state.index, st->report_state.report_id, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 0b5dea050239..16ade0a0327b 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -26,9 +26,84 @@ #include #include #include +#include #include #include "hid-sensor-trigger.h" +static ssize_t _hid_sensor_set_report_latency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int integer, fract, ret; + int latency; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); + if (ret) + return ret; + + latency = integer * 1000 + fract / 1000; + ret = hid_sensor_set_report_latency(attrb, latency); + if (ret < 0) + return len; + + attrb->latency_ms = hid_sensor_get_report_latency(attrb); + + return len; +} + +static ssize_t _hid_sensor_get_report_latency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int latency; + + latency = hid_sensor_get_report_latency(attrb); + if (latency < 0) + return latency; + + return sprintf(buf, "%d.%06u\n", latency / 1000, (latency % 1000) * 1000); +} + +static ssize_t _hid_sensor_get_fifo_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int latency; + + latency = hid_sensor_get_report_latency(attrb); + if (latency < 0) + return latency; + + return sprintf(buf, "%d\n", !!latency); +} + +static IIO_DEVICE_ATTR(hwfifo_timeout, 0644, + _hid_sensor_get_report_latency, + _hid_sensor_set_report_latency, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + _hid_sensor_get_fifo_state, NULL, 0); + +static const struct attribute *hid_sensor_fifo_attributes[] = { + &iio_dev_attr_hwfifo_timeout.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev, + struct hid_sensor_common *st) +{ + if (!hid_sensor_batch_mode_supported(st)) + return; + + iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes); +} + static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) { int state_val; @@ -141,6 +216,9 @@ static void hid_sensor_set_power_work(struct work_struct *work) sizeof(attrb->raw_hystersis), &attrb->raw_hystersis); + if (attrb->latency_ms > 0) + hid_sensor_set_report_latency(attrb, attrb->latency_ms); + _hid_sensor_power_state(attrb, true); } @@ -192,6 +270,8 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, attrb->trigger = trig; indio_dev->trig = iio_trigger_get(trig); + hid_sensor_setup_batch_mode(indio_dev, attrb); + ret = pm_runtime_set_active(&indio_dev->dev); if (ret) goto error_unreg_trigger; diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index f32d7c392c1e..fc7aae64dcde 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -233,12 +233,14 @@ struct hid_sensor_common { atomic_t user_requested_state; int poll_interval; int raw_hystersis; + int latency_ms; struct iio_trigger *trigger; int timestamp_ns_scale; struct hid_sensor_hub_attribute_info poll; struct hid_sensor_hub_attribute_info report_state; struct hid_sensor_hub_attribute_info power_state; struct hid_sensor_hub_attribute_info sensitivity; + struct hid_sensor_hub_attribute_info report_latency; struct work_struct work; }; @@ -276,5 +278,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st); int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st, int64_t raw_value); +bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st); +int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency); +int hid_sensor_get_report_latency(struct hid_sensor_common *st); #endif diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 5af62c7e49f3..76033e0420a7 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -152,6 +152,9 @@ #define HID_USAGE_SENSOR_PROP_REPORT_STATE 0x200316 #define HID_USAGE_SENSOR_PROY_POWER_STATE 0x200319 +/* Batch mode selectors */ +#define HID_USAGE_SENSOR_PROP_REPORT_LATENCY 0x20031B + /* Per data field properties */ #define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 -- cgit v1.2.3 From 14b39dce373191f8fd7a703a643dccf0f97f0323 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 19 May 2017 14:28:53 -0700 Subject: iio: light: isl29018: Only declare ACPI table when ACPI is enabled This fixes the following warning when building with clang: drivers/iio/light/isl29018.c:808:36: error: variable 'isl29018_acpi_match' is not needed and will not be emitted [-Werror,-Wunneeded-internal-declaration] Signed-off-by: Matthias Kaehlcke Reviewed-by: Guenter Roeck Signed-off-by: Jonathan Cameron --- drivers/iio/light/isl29018.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 917dd8b43e72..61f5924b472d 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -807,6 +807,7 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); #define ISL29018_PM_OPS NULL #endif +#ifdef CONFIG_ACPI static const struct acpi_device_id isl29018_acpi_match[] = { {"ISL29018", isl29018}, {"ISL29023", isl29023}, @@ -814,6 +815,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = { {}, }; MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); +#endif static const struct i2c_device_id isl29018_id[] = { {"isl29018", isl29018}, -- cgit v1.2.3 From fa7662e1bddbded1820415907740837baa897721 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:47:59 +0300 Subject: iio: hi8435: add raw access With current event-only driver, it is not possible for user space application to know current senses if they don't change since application starts. Address that by adding raw access to channels. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hi8435.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 678e8c7ea763..cb8e6342eddf 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -105,6 +105,26 @@ static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val) return spi_write(priv->spi, priv->reg_buffer, 3); } +static int hi8435_read_raw(struct iio_dev *idev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct hi8435_priv *priv = iio_priv(idev); + u32 tmp; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp); + if (ret < 0) + return ret; + *val = !!(tmp & BIT(chan->channel)); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + static int hi8435_read_event_config(struct iio_dev *idev, const struct iio_chan_spec *chan, enum iio_event_type type, @@ -333,6 +353,7 @@ static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = num, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .event_spec = hi8435_events, \ .num_event_specs = ARRAY_SIZE(hi8435_events), \ .ext_info = hi8435_ext_info, \ @@ -376,6 +397,7 @@ static const struct iio_chan_spec hi8435_channels[] = { static const struct iio_info hi8435_info = { .driver_module = THIS_MODULE, + .read_raw = hi8435_read_raw, .read_event_config = &hi8435_read_event_config, .write_event_config = hi8435_write_event_config, .read_event_value = &hi8435_read_event_value, -- cgit v1.2.3 From ee19ac340c5fdfd89c6348be4563453c61ab54a9 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:48:00 +0300 Subject: iio: hi8435: avoid garbage event at first enable Currently, driver generates events for channels if new reading differs from previous one. This "previous value" is initialized to zero, which results into event if value is constant-one. Fix that by initializing "previous value" by reading at event enable time. This provides reliable sequence for userspace: - enable event, - AFTER THAT read current value, - AFTER THAT each event will correspond to change. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hi8435.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index cb8e6342eddf..45a92e3e8f2b 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -141,10 +141,21 @@ static int hi8435_write_event_config(struct iio_dev *idev, enum iio_event_direction dir, int state) { struct hi8435_priv *priv = iio_priv(idev); + int ret; + u32 tmp; + + if (state) { + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp); + if (ret < 0) + return ret; + if (tmp & BIT(chan->channel)) + priv->event_prev_val |= BIT(chan->channel); + else + priv->event_prev_val &= ~BIT(chan->channel); - priv->event_scan_mask &= ~BIT(chan->channel); - if (state) priv->event_scan_mask |= BIT(chan->channel); + } else + priv->event_scan_mask &= ~BIT(chan->channel); return 0; } -- cgit v1.2.3 From bd7026992f203d7a0b7e26d53b0b05739454f1df Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:48:01 +0300 Subject: iio: hi8435: make in_voltage_sensing_mode_available visible Possible values of sensing_mode are encoded with strings and actual strings used are not obvious. Provide a hint by enabling in_voltage_sensing_mode_available attribute. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hi8435.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 45a92e3e8f2b..d09cb6ff8044 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -356,6 +356,7 @@ static const struct iio_enum hi8435_sensing_mode = { static const struct iio_chan_spec_ext_info hi8435_ext_info[] = { IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode), + IIO_ENUM_AVAILABLE("sensing_mode", &hi8435_sensing_mode), {}, }; -- cgit v1.2.3 From 61305664a542f874283f74bf0b27ddb31f5045d7 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:48:02 +0300 Subject: iio: hi8435: cleanup reset gpio Reset GPIO is active low. Currently driver uses gpiod_set_value(1) to clean reset, which depends on device tree to contain GPIO_ACTIVE_HIGH - that does not match reality. This fixes driver to use _raw version of gpiod_set_value() to enforce active-low semantics despite of what's written in device tree. Allowing device tree to override that only opens possibility for errors and does not add any value. Additionally, use _cansleep version to make things work with i2c-gpio and other sleeping gpio drivers. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron --- drivers/iio/adc/hi8435.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index d09cb6ff8044..ab59969b7c49 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -476,13 +476,15 @@ static int hi8435_probe(struct spi_device *spi) priv->spi = spi; reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(reset_gpio)) { - /* chip s/w reset if h/w reset failed */ + if (!IS_ERR(reset_gpio)) { + /* need >=100ns low pulse to reset chip */ + gpiod_set_raw_value_cansleep(reset_gpio, 0); + udelay(1); + gpiod_set_raw_value_cansleep(reset_gpio, 1); + } else { + /* s/w reset chip if h/w reset is not available */ hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST); hi8435_writeb(priv, HI8435_CTRL_REG, 0); - } else { - udelay(5); - gpiod_set_value(reset_gpio, 1); } spi_set_drvdata(spi, idev); -- cgit v1.2.3 From 52325ff42a9aa7bdcbcc5461f6eec4c4f93ed944 Mon Sep 17 00:00:00 2001 From: Surender Polsani Date: Fri, 19 May 2017 15:07:12 +0530 Subject: staging: iio: light: Replace symbolic permissions as per coding style Fixed the following checkpatch.pl warnings: octal permissions are more preferable than symbolic permissions Replaced DEVICE_ATTR family macros with DEVICE_ATTR_RW family as suggested by Greg K-H. Changed attributes and function names where ever required to satisfy internal macro definitions like __ATTR__RW(). Signed-off-by: Surender Polsani Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/tsl2x7x.c | 62 ++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c index a912e9ec87f2..146719928fb3 100644 --- a/drivers/staging/iio/light/tsl2x7x.c +++ b/drivers/staging/iio/light/tsl2x7x.c @@ -915,7 +915,7 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) tsl2x7x_chip_on(indio_dev); } -static ssize_t tsl2x7x_power_state_show(struct device *dev, +static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -924,7 +924,7 @@ static ssize_t tsl2x7x_power_state_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); } -static ssize_t tsl2x7x_power_state_store(struct device *dev, +static ssize_t power_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -942,7 +942,7 @@ static ssize_t tsl2x7x_power_state_store(struct device *dev, return len; } -static ssize_t tsl2x7x_gain_available_show(struct device *dev, +static ssize_t in_illuminance0_calibscale_available_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -960,14 +960,14 @@ static ssize_t tsl2x7x_gain_available_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); } -static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, +static ssize_t in_proximity0_calibscale_available_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); } -static ssize_t tsl2x7x_als_time_show(struct device *dev, +static ssize_t in_illuminance0_integration_time_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -982,7 +982,7 @@ static ssize_t tsl2x7x_als_time_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); } -static ssize_t tsl2x7x_als_time_store(struct device *dev, +static ssize_t in_illuminance0_integration_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1010,7 +1010,7 @@ static ssize_t tsl2x7x_als_time_store(struct device *dev, static IIO_CONST_ATTR(in_illuminance0_integration_time_available, ".00272 - .696"); -static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, +static ssize_t in_illuminance0_target_input_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1020,7 +1020,7 @@ static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, chip->tsl2x7x_settings.als_cal_target); } -static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, +static ssize_t in_illuminance0_target_input_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1040,7 +1040,7 @@ static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, } /* persistence settings */ -static ssize_t tsl2x7x_als_persistence_show(struct device *dev, +static ssize_t in_intensity0_thresh_period_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1057,7 +1057,7 @@ static ssize_t tsl2x7x_als_persistence_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); } -static ssize_t tsl2x7x_als_persistence_store(struct device *dev, +static ssize_t in_intensity0_thresh_period_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1088,7 +1088,7 @@ static ssize_t tsl2x7x_als_persistence_store(struct device *dev, return IIO_VAL_INT_PLUS_MICRO; } -static ssize_t tsl2x7x_prox_persistence_show(struct device *dev, +static ssize_t in_proximity0_thresh_period_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1105,7 +1105,7 @@ static ssize_t tsl2x7x_prox_persistence_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z); } -static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, +static ssize_t in_proximity0_thresh_period_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1136,7 +1136,7 @@ static ssize_t tsl2x7x_prox_persistence_store(struct device *dev, return IIO_VAL_INT_PLUS_MICRO; } -static ssize_t tsl2x7x_do_calibrate(struct device *dev, +static ssize_t in_illuminance0_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1154,7 +1154,7 @@ static ssize_t tsl2x7x_do_calibrate(struct device *dev, return len; } -static ssize_t tsl2x7x_luxtable_show(struct device *dev, +static ssize_t in_illuminance0_lux_table_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1182,7 +1182,7 @@ static ssize_t tsl2x7x_luxtable_show(struct device *dev, return offset; } -static ssize_t tsl2x7x_luxtable_store(struct device *dev, +static ssize_t in_illuminance0_lux_table_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1222,7 +1222,7 @@ static ssize_t tsl2x7x_luxtable_store(struct device *dev, return len; } -static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, +static ssize_t in_proximity0_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { @@ -1494,35 +1494,25 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev, return 0; } -static DEVICE_ATTR(power_state, 0644, - tsl2x7x_power_state_show, tsl2x7x_power_state_store); +static DEVICE_ATTR_RW(power_state); -static DEVICE_ATTR(in_proximity0_calibscale_available, 0444, - tsl2x7x_prox_gain_available_show, NULL); +static DEVICE_ATTR_RO(in_proximity0_calibscale_available); -static DEVICE_ATTR(in_illuminance0_calibscale_available, 0444, - tsl2x7x_gain_available_show, NULL); +static DEVICE_ATTR_RO(in_illuminance0_calibscale_available); -static DEVICE_ATTR(in_illuminance0_integration_time, 0644, - tsl2x7x_als_time_show, tsl2x7x_als_time_store); +static DEVICE_ATTR_RW(in_illuminance0_integration_time); -static DEVICE_ATTR(in_illuminance0_target_input, 0644, - tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); +static DEVICE_ATTR_RW(in_illuminance0_target_input); -static DEVICE_ATTR(in_illuminance0_calibrate, 0200, NULL, - tsl2x7x_do_calibrate); +static DEVICE_ATTR_WO(in_illuminance0_calibrate); -static DEVICE_ATTR(in_proximity0_calibrate, 0200, NULL, - tsl2x7x_do_prox_calibrate); +static DEVICE_ATTR_WO(in_proximity0_calibrate); -static DEVICE_ATTR(in_illuminance0_lux_table, 0644, - tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); +static DEVICE_ATTR_RW(in_illuminance0_lux_table); -static DEVICE_ATTR(in_intensity0_thresh_period, 0644, - tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); +static DEVICE_ATTR_RW(in_intensity0_thresh_period); -static DEVICE_ATTR(in_proximity0_thresh_period, 0644, - tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store); +static DEVICE_ATTR_RW(in_proximity0_thresh_period); /* Use the default register values to identify the Taos device */ static int tsl2x7x_device_id(unsigned char *id, int target) -- cgit v1.2.3 From f87fa26177ac4dd5ebcc1e598a90142ecb4973cb Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:49 +0300 Subject: iio: light: rpr0521 disable sensor -bugfix Sensor was marked enabled on each call even if the call was for disabling sensor. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 7de0f397194b..03504f6ecd3b 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -197,7 +197,10 @@ static int rpr0521_als_enable(struct rpr0521_data *data, u8 status) if (ret < 0) return ret; - data->als_dev_en = true; + if (status & RPR0521_MODE_ALS_MASK) + data->als_dev_en = true; + else + data->als_dev_en = false; return 0; } @@ -212,7 +215,10 @@ static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status) if (ret < 0) return ret; - data->pxs_dev_en = true; + if (status & RPR0521_MODE_PXS_MASK) + data->pxs_dev_en = true; + else + data->pxs_dev_en = false; return 0; } -- cgit v1.2.3 From 12d74949133e2450533894ea01ce0c56646ce006 Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:50 +0300 Subject: iio: light: rpr0521 poweroff for probe fails Set sensor measurement off after probe fail in pm_runtime_set_active() or iio_device_register(). Without this change sensor measurement stays on even though probe fails on these calls. This is maybe rare case, but causes constant power drain without any benefits when it happens. Power drain is 20-500uA, typically 180uA. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 03504f6ecd3b..84d8d403e547 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -516,13 +516,26 @@ static int rpr0521_probe(struct i2c_client *client, ret = pm_runtime_set_active(&client->dev); if (ret < 0) - return ret; + goto err_poweroff; pm_runtime_enable(&client->dev); pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(&client->dev); - return iio_device_register(indio_dev); + ret = iio_device_register(indio_dev); + if (ret) + goto err_pm_disable; + + return 0; + +err_pm_disable: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); +err_poweroff: + rpr0521_poweroff(data); + + return ret; } static int rpr0521_remove(struct i2c_client *client) -- cgit v1.2.3 From 484c314b90ae240fb8e6e2924722deb92c756d93 Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:51 +0300 Subject: iio: light: rpr0521 on-off sequence change for CONFIG_PM Refactor _set_power_state(), _resume() and _suspend(). Enable measurement only when needed, not in _init(). System can suspend during measurement and measurement is continued on resume. Pm turns off measurement when both ps and als measurements are disabled for 2 seconds. During off-time the power save is 20-500mA, typically 180mA. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 70 +++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 84d8d403e547..921981978598 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -9,7 +9,7 @@ * * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38). * - * TODO: illuminance channel, PM support, buffer + * TODO: illuminance channel, buffer */ #include @@ -142,9 +142,11 @@ struct rpr0521_data { bool als_dev_en; bool pxs_dev_en; - /* optimize runtime pm ops - enable device only if needed */ + /* optimize runtime pm ops - enable/disable device only if needed */ bool als_ps_need_en; bool pxs_ps_need_en; + bool als_need_dis; + bool pxs_need_dis; struct regmap *regmap; }; @@ -230,40 +232,32 @@ static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status) * @on: state to be set for devices in @device_mask * @device_mask: bitmask specifying for which device we need to update @on state * - * We rely on rpr0521_runtime_resume to enable our @device_mask devices, but - * if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to - * rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable - * bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not - * be called twice. + * Calls for this function must be balanced so that each ON should have matching + * OFF. Otherwise pm usage_count gets out of sync. */ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, u8 device_mask) { #ifdef CONFIG_PM int ret; - u8 update_mask = 0; if (device_mask & RPR0521_MODE_ALS_MASK) { - if (on && !data->als_ps_need_en && data->pxs_dev_en) - update_mask |= RPR0521_MODE_ALS_MASK; - else - data->als_ps_need_en = on; + data->als_ps_need_en = on; + data->als_need_dis = !on; } if (device_mask & RPR0521_MODE_PXS_MASK) { - if (on && !data->pxs_ps_need_en && data->als_dev_en) - update_mask |= RPR0521_MODE_PXS_MASK; - else - data->pxs_ps_need_en = on; - } - - if (update_mask) { - ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL, - update_mask, update_mask); - if (ret < 0) - return ret; + data->pxs_ps_need_en = on; + data->pxs_need_dis = !on; } + /* + * On: _resume() is called only when we are suspended + * Off: _suspend() is called after delay if _resume() is not + * called before that. + * Note: If either measurement is re-enabled before _suspend(), + * both stay enabled until _suspend(). + */ if (on) { ret = pm_runtime_get_sync(&data->client->dev); } else { @@ -279,6 +273,23 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on, return ret; } + + if (on) { + /* If _resume() was not called, enable measurement now. */ + if (data->als_ps_need_en) { + ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); + if (ret) + return ret; + data->als_ps_need_en = false; + } + + if (data->pxs_ps_need_en) { + ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); + if (ret) + return ret; + data->pxs_ps_need_en = false; + } + } #endif return 0; } @@ -425,12 +436,14 @@ static int rpr0521_init(struct rpr0521_data *data) return ret; } +#ifndef CONFIG_PM ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) return ret; ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); if (ret < 0) return ret; +#endif return 0; } @@ -560,9 +573,16 @@ static int rpr0521_runtime_suspend(struct device *dev) struct rpr0521_data *data = iio_priv(indio_dev); int ret; - /* disable channels and sets {als,pxs}_dev_en to false */ mutex_lock(&data->lock); + /* If measurements are enabled, enable them on resume */ + if (!data->als_need_dis) + data->als_ps_need_en = data->als_dev_en; + if (!data->pxs_need_dis) + data->pxs_ps_need_en = data->pxs_dev_en; + + /* disable channels and sets {als,pxs}_dev_en to false */ ret = rpr0521_poweroff(data); + regcache_mark_dirty(data->regmap); mutex_unlock(&data->lock); return ret; @@ -574,6 +594,7 @@ static int rpr0521_runtime_resume(struct device *dev) struct rpr0521_data *data = iio_priv(indio_dev); int ret; + regcache_sync(data->regmap); if (data->als_ps_need_en) { ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) @@ -587,6 +608,7 @@ static int rpr0521_runtime_resume(struct device *dev) return ret; data->pxs_ps_need_en = false; } + msleep(100); //wait for first measurement result return 0; } -- cgit v1.2.3 From ae5916501b8d45b0585171f4e4ada7c64493813b Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:52 +0300 Subject: iio: light: rpr0521 magic number to sizeof() on value read Changed magic number to sizeof() on value read. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 921981978598..38095d79a874 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -356,7 +356,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev, ret = regmap_bulk_read(data->regmap, rpr0521_data_reg[chan->address].address, - &raw_data, 2); + &raw_data, sizeof(raw_data)); if (ret < 0) { rpr0521_set_power_state(data, false, device_mask); mutex_unlock(&data->lock); -- cgit v1.2.3 From 624c389e10a912769f2587f1ce3374f28159f1eb Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:53 +0300 Subject: iio: light: rpr0521 whitespace fixes Just whitespace change, no functional changes. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 38095d79a874..52c559d9e09b 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -371,6 +371,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev, *val = le16_to_cpu(raw_data); return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: mutex_lock(&data->lock); ret = rpr0521_get_gain(data, chan->address, val, val2); @@ -379,6 +380,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev, return ret; return IIO_VAL_INT_PLUS_MICRO; + default: return -EINVAL; } @@ -398,6 +400,7 @@ static int rpr0521_write_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); return ret; + default: return -EINVAL; } -- cgit v1.2.3 From c91a88ef846f65764ebe645324672fe54ec76204 Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:54 +0300 Subject: iio: light: rpr0521 sample_frequency read/write Add sysfs read/write sample frequency. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 117 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 52c559d9e09b..0aac4bc156f6 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -132,6 +132,30 @@ static const struct rpr0521_gain_info { }, }; +struct rpr0521_samp_freq { + int als_hz; + int als_uhz; + int pxs_hz; + int pxs_uhz; +}; + +static const struct rpr0521_samp_freq rpr0521_samp_freq_i[13] = { +/* {ALS, PXS}, W==currently writable option */ + {0, 0, 0, 0}, /* W0000, 0=standby */ + {0, 0, 100, 0}, /* 0001 */ + {0, 0, 25, 0}, /* 0010 */ + {0, 0, 10, 0}, /* 0011 */ + {0, 0, 2, 500000}, /* 0100 */ + {10, 0, 20, 0}, /* 0101 */ + {10, 0, 10, 0}, /* W0110 */ + {10, 0, 2, 500000}, /* 0111 */ + {2, 500000, 20, 0}, /* 1000, measurement 100ms, sleep 300ms */ + {2, 500000, 10, 0}, /* 1001, measurement 100ms, sleep 300ms */ + {2, 500000, 0, 0}, /* 1010, high sensitivity mode */ + {2, 500000, 2, 500000}, /* W1011, high sensitivity mode */ + {20, 0, 20, 0} /* 1100, ALS_data x 0.5, see specification P.18 */ +}; + struct rpr0521_data { struct i2c_client *client; @@ -154,9 +178,16 @@ struct rpr0521_data { static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL); static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL); +/* + * Start with easy freq first, whole table of freq combinations is more + * complicated. + */ +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("2.5 10"); + static struct attribute *rpr0521_attributes[] = { &iio_const_attr_in_intensity_scale_available.dev_attr.attr, &iio_const_attr_in_proximity_scale_available.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -172,6 +203,7 @@ static const struct iio_chan_spec rpr0521_channels[] = { .channel2 = IIO_MOD_LIGHT_BOTH, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_INTENSITY, @@ -180,12 +212,14 @@ static const struct iio_chan_spec rpr0521_channels[] = { .channel2 = IIO_MOD_LIGHT_IR, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, { .type = IIO_PROXIMITY, .address = RPR0521_CHAN_PXS, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } }; @@ -331,6 +365,72 @@ static int rpr0521_set_gain(struct rpr0521_data *data, int chan, idx << rpr0521_gain[chan].shift); } +static int rpr0521_read_samp_freq(struct rpr0521_data *data, + enum iio_chan_type chan_type, + int *val, int *val2) +{ + int reg, ret; + + ret = regmap_read(data->regmap, RPR0521_REG_MODE_CTRL, ®); + if (ret < 0) + return ret; + + reg &= RPR0521_MODE_MEAS_TIME_MASK; + if (reg >= ARRAY_SIZE(rpr0521_samp_freq_i)) + return -EINVAL; + + switch (chan_type) { + case IIO_INTENSITY: + *val = rpr0521_samp_freq_i[reg].als_hz; + *val2 = rpr0521_samp_freq_i[reg].als_uhz; + return 0; + + case IIO_PROXIMITY: + *val = rpr0521_samp_freq_i[reg].pxs_hz; + *val2 = rpr0521_samp_freq_i[reg].pxs_uhz; + return 0; + + default: + return -EINVAL; + } +} + +static int rpr0521_write_samp_freq_common(struct rpr0521_data *data, + enum iio_chan_type chan_type, + int val, int val2) +{ + int i; + + /* + * Ignore channel + * both pxs and als are setup only to same freq because of simplicity + */ + switch (val) { + case 0: + i = 0; + break; + + case 2: + if (val2 != 500000) + return -EINVAL; + + i = 11; + break; + + case 10: + i = 6; + break; + + default: + return -EINVAL; + } + + return regmap_update_bits(data->regmap, + RPR0521_REG_MODE_CTRL, + RPR0521_MODE_MEAS_TIME_MASK, + i); +} + static int rpr0521_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -381,6 +481,15 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->lock); + ret = rpr0521_read_samp_freq(data, chan->type, val, val2); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + return IIO_VAL_INT_PLUS_MICRO; + default: return -EINVAL; } @@ -401,6 +510,14 @@ static int rpr0521_write_raw(struct iio_dev *indio_dev, return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->lock); + ret = rpr0521_write_samp_freq_common(data, chan->type, + val, val2); + mutex_unlock(&data->lock); + + return ret; + default: return -EINVAL; } -- cgit v1.2.3 From 734c442303ad886fb2471d0fae0845f4a8a958e1 Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:55 +0300 Subject: iio: light: rpr0521 proximity offset read/write Add sysfs read/write proximity offset feature. Offset is read/write from sensor registers. Values are proximity raw 10-bit values. After applying offset value, output values will be (measured_raw - offset_value). Output values are unsigned so offset value doesn't make output negative. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 0aac4bc156f6..83b24d1be383 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -30,6 +30,7 @@ #define RPR0521_REG_PXS_DATA 0x44 /* 16-bit, little endian */ #define RPR0521_REG_ALS_DATA0 0x46 /* 16-bit, little endian */ #define RPR0521_REG_ALS_DATA1 0x48 /* 16-bit, little endian */ +#define RPR0521_REG_PS_OFFSET_LSB 0x53 #define RPR0521_REG_ID 0x92 #define RPR0521_MODE_ALS_MASK BIT(7) @@ -218,6 +219,7 @@ static const struct iio_chan_spec rpr0521_channels[] = { .type = IIO_PROXIMITY, .address = RPR0521_CHAN_PXS, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), } @@ -431,6 +433,40 @@ static int rpr0521_write_samp_freq_common(struct rpr0521_data *data, i); } +static int rpr0521_read_ps_offset(struct rpr0521_data *data, int *offset) +{ + int ret; + __le16 buffer; + + ret = regmap_bulk_read(data->regmap, + RPR0521_REG_PS_OFFSET_LSB, &buffer, sizeof(buffer)); + + if (ret < 0) { + dev_err(&data->client->dev, "Failed to read PS OFFSET register\n"); + return ret; + } + *offset = le16_to_cpu(buffer); + + return ret; +} + +static int rpr0521_write_ps_offset(struct rpr0521_data *data, int offset) +{ + int ret; + __le16 buffer; + + buffer = cpu_to_le16(offset & 0x3ff); + ret = regmap_raw_write(data->regmap, + RPR0521_REG_PS_OFFSET_LSB, &buffer, sizeof(buffer)); + + if (ret < 0) { + dev_err(&data->client->dev, "Failed to write PS OFFSET register\n"); + return ret; + } + + return ret; +} + static int rpr0521_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) @@ -490,6 +526,15 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + mutex_lock(&data->lock); + ret = rpr0521_read_ps_offset(data, val); + mutex_unlock(&data->lock); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + default: return -EINVAL; } @@ -518,6 +563,13 @@ static int rpr0521_write_raw(struct iio_dev *indio_dev, return ret; + case IIO_CHAN_INFO_OFFSET: + mutex_lock(&data->lock); + ret = rpr0521_write_ps_offset(data, val); + mutex_unlock(&data->lock); + + return ret; + default: return -EINVAL; } -- cgit v1.2.3 From 9ece370b02f912bedff217b53f6f8cfbef0e93eb Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:56 +0300 Subject: iio: light: rpr0521 channel numbers reordered Move proximity channel from last to first in structs to avoid confusion later with buffered triggers. Proximity data output is first in rpr0521 register map. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/rpr0521.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 83b24d1be383..9d0c2e859bb2 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -78,9 +78,9 @@ static const struct rpr0521_gain rpr0521_pxs_gain[3] = { }; enum rpr0521_channel { + RPR0521_CHAN_PXS, RPR0521_CHAN_ALS_DATA0, RPR0521_CHAN_ALS_DATA1, - RPR0521_CHAN_PXS, }; struct rpr0521_reg_desc { @@ -89,6 +89,10 @@ struct rpr0521_reg_desc { }; static const struct rpr0521_reg_desc rpr0521_data_reg[] = { + [RPR0521_CHAN_PXS] = { + .address = RPR0521_REG_PXS_DATA, + .device_mask = RPR0521_MODE_PXS_MASK, + }, [RPR0521_CHAN_ALS_DATA0] = { .address = RPR0521_REG_ALS_DATA0, .device_mask = RPR0521_MODE_ALS_MASK, @@ -97,10 +101,6 @@ static const struct rpr0521_reg_desc rpr0521_data_reg[] = { .address = RPR0521_REG_ALS_DATA1, .device_mask = RPR0521_MODE_ALS_MASK, }, - [RPR0521_CHAN_PXS] = { - .address = RPR0521_REG_PXS_DATA, - .device_mask = RPR0521_MODE_PXS_MASK, - }, }; static const struct rpr0521_gain_info { @@ -110,6 +110,13 @@ static const struct rpr0521_gain_info { const struct rpr0521_gain *gain; int size; } rpr0521_gain[] = { + [RPR0521_CHAN_PXS] = { + .reg = RPR0521_REG_PXS_CTRL, + .mask = RPR0521_PXS_GAIN_MASK, + .shift = RPR0521_PXS_GAIN_SHIFT, + .gain = rpr0521_pxs_gain, + .size = ARRAY_SIZE(rpr0521_pxs_gain), + }, [RPR0521_CHAN_ALS_DATA0] = { .reg = RPR0521_REG_ALS_CTRL, .mask = RPR0521_ALS_DATA0_GAIN_MASK, @@ -124,13 +131,6 @@ static const struct rpr0521_gain_info { .gain = rpr0521_als_gain, .size = ARRAY_SIZE(rpr0521_als_gain), }, - [RPR0521_CHAN_PXS] = { - .reg = RPR0521_REG_PXS_CTRL, - .mask = RPR0521_PXS_GAIN_MASK, - .shift = RPR0521_PXS_GAIN_SHIFT, - .gain = rpr0521_pxs_gain, - .size = ARRAY_SIZE(rpr0521_pxs_gain), - }, }; struct rpr0521_samp_freq { @@ -197,6 +197,14 @@ static const struct attribute_group rpr0521_attribute_group = { }; static const struct iio_chan_spec rpr0521_channels[] = { + { + .type = IIO_PROXIMITY, + .address = RPR0521_CHAN_PXS, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), + }, { .type = IIO_INTENSITY, .modified = 1, @@ -215,14 +223,6 @@ static const struct iio_chan_spec rpr0521_channels[] = { BIT(IIO_CHAN_INFO_SCALE), .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), }, - { - .type = IIO_PROXIMITY, - .address = RPR0521_CHAN_PXS, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_OFFSET) | - BIT(IIO_CHAN_INFO_SCALE), - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), - } }; static int rpr0521_als_enable(struct rpr0521_data *data, u8 status) -- cgit v1.2.3 From f1320b09517bceb261fed887fe261d6cbab2094e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 May 2017 14:51:58 +0200 Subject: iio: accel: bma180: Add support for BMA250E The BMA250E adds a new fifo mode and is fully backwards compatible with the BMA250, but with a different chip-id. This commit adds support for it by adjusting the chip-id check and otherwise treating it as a regular BMA250. Signed-off-by: Hans de Goede Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index efc67739c28f..3d6694821a96 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -36,6 +36,7 @@ enum chip_ids { BMA180, BMA250, + BMA250E, }; struct bma180_data; @@ -55,6 +56,7 @@ struct bma180_part_info { u8 power_reg, power_mask, lowpower_val; u8 int_enable_reg, int_enable_mask; u8 softreset_reg; + u8 chip_id; int (*chip_config)(struct bma180_data *data); void (*chip_disable)(struct bma180_data *data); @@ -112,6 +114,8 @@ struct bma180_part_info { #define BMA250_INT1_DATA_MASK BIT(0) #define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */ +#define BMA250E_CHIP_ID 0xf9 + struct bma180_data { struct i2c_client *client; struct iio_trigger *trig; @@ -309,7 +313,7 @@ static int bma180_chip_init(struct bma180_data *data) if (ret < 0) return ret; - if (ret != BMA180_ID_REG_VAL) + if (ret != data->part_info->chip_id) return -ENODEV; ret = bma180_soft_reset(data); @@ -632,6 +636,7 @@ static const struct bma180_part_info bma180_part_info[] = { BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER, BMA180_CTRL_REG3, BMA180_NEW_DATA_INT, BMA180_RESET, + BMA180_CHIP_ID, bma180_chip_config, bma180_chip_disable, }, @@ -646,6 +651,22 @@ static const struct bma180_part_info bma180_part_info[] = { BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1, BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK, BMA250_RESET_REG, + BMA180_CHIP_ID, + bma250_chip_config, + bma250_chip_disable, + }, + [BMA250E] = { + bma250_channels, ARRAY_SIZE(bma250_channels), + bma250_scale_table, ARRAY_SIZE(bma250_scale_table), + bma250_bw_table, ARRAY_SIZE(bma250_bw_table), + BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK, + BMA250_POWER_REG, BMA250_SUSPEND_MASK, + BMA250_BW_REG, BMA250_BW_MASK, + BMA250_RANGE_REG, BMA250_RANGE_MASK, + BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1, + BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK, + BMA250_RESET_REG, + BMA250E_CHIP_ID, bma250_chip_config, bma250_chip_disable, }, @@ -845,6 +866,7 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); static struct i2c_device_id bma180_ids[] = { { "bma180", BMA180 }, { "bma250", BMA250 }, + { "bma250e", BMA250E }, { } }; -- cgit v1.2.3 From 5333e88661f2079d5ca8b94690ac920976300de3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 16 May 2017 14:51:59 +0200 Subject: iio: accel: bma180: Add ACPI enumeration support for BMA250E Some x86 tablets use the BMA250E accelerometer, add support for this. Signed-off-by: Hans de Goede Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 3d6694821a96..17b7953f2502 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -14,6 +14,7 @@ * BMA250: 7-bit I2C slave address 0x18 or 0x19 */ +#include #include #include #include @@ -727,6 +728,8 @@ static const struct iio_trigger_ops bma180_trigger_ops = { static int bma180_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + const struct acpi_device_id *acpi_id; struct bma180_data *data; struct iio_dev *indio_dev; enum chip_ids chip; @@ -739,10 +742,17 @@ static int bma180_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; - if (client->dev.of_node) + if (dev->of_node) { chip = (enum chip_ids)of_device_get_match_data(&client->dev); - else + } else if (id) { chip = id->driver_data; + } else { + acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!acpi_id) + return -ENODEV; + + chip = acpi_id->driver_data; + } data->part_info = &bma180_part_info[chip]; ret = data->part_info->chip_config(data); @@ -863,6 +873,12 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); #define BMA180_PM_OPS NULL #endif +static const struct acpi_device_id bma180_acpi_match[] = { + { "BMA250E", BMA250E }, + { } +}; +MODULE_DEVICE_TABLE(acpi, bma180_acpi_match); + static struct i2c_device_id bma180_ids[] = { { "bma180", BMA180 }, { "bma250", BMA250 }, @@ -888,6 +904,7 @@ MODULE_DEVICE_TABLE(of, bma180_of_match); static struct i2c_driver bma180_driver = { .driver = { .name = "bma180", + .acpi_match_table = ACPI_PTR(bma180_acpi_match), .pm = BMA180_PM_OPS, .of_match_table = bma180_of_match, }, -- cgit v1.2.3 From 3cec48501748644ce2e17eb976d3201a753e5aae Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 19 May 2017 22:11:36 +0200 Subject: iio: imu: st_lsm6dsx: substitute ifdef CONFIG_PM with __maybe_unused macro Get rid of #ifdef CONFIG_PM by adding __maybe_unused macro to st_lsm6dsx_suspend and st_lsm6dsx_resume function declarations Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron --- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 1b53848cdfd8..b485540da89e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -732,8 +732,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, } EXPORT_SYMBOL(st_lsm6dsx_probe); -#ifdef CONFIG_PM -static int st_lsm6dsx_suspend(struct device *dev) +static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) { struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); struct st_lsm6dsx_sensor *sensor; @@ -757,7 +756,7 @@ static int st_lsm6dsx_suspend(struct device *dev) return err; } -static int st_lsm6dsx_resume(struct device *dev) +static int __maybe_unused st_lsm6dsx_resume(struct device *dev) { struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); struct st_lsm6dsx_sensor *sensor; @@ -778,7 +777,6 @@ static int st_lsm6dsx_resume(struct device *dev) return err; } -#endif /* CONFIG_PM */ const struct dev_pm_ops st_lsm6dsx_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) -- cgit v1.2.3 From 7e87d11c9bda75816ced8d0895e8d24e5c52833a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 17 May 2017 17:28:17 +0200 Subject: iio: adc: Add support for TI ADC108S102 and ADC128S102 This is an upstream port of an IIO driver for the TI ADC108S102 and ADC128S102. The former can be found on the Intel Galileo Gen2 and the Siemens SIMATIC IOT2000. For those boards, ACPI-based enumeration is included. Due to the lack of regulators under ACPI, we hard-code the voltage provided to the VA pin of the ADC to 5 V, the value used on Galileo and IOT2000. For DT usage, the regulator "vref-supply" provides this information. Note that DT usage has not been tested. Original author: Bogdan Pricop Ported from Intel Galileo Gen2 BSP to Intel Yocto kernel: Todor Minchev . Signed-off-by: Jan Kiszka Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/ti-adc108s102.txt | 18 ++ drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-adc108s102.c | 348 +++++++++++++++++++++ 4 files changed, 379 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt create mode 100644 drivers/iio/adc/ti-adc108s102.c diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt new file mode 100644 index 000000000000..bbbbb4a9f58f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt @@ -0,0 +1,18 @@ +* Texas Instruments' ADC108S102 and ADC128S102 ADC chip + +Required properties: + - compatible: Should be "ti,adc108s102" + - reg: spi chip select number for the device + - vref-supply: The regulator supply for ADC reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,adc108s102"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9e08b8afccc6..2f2632991e0e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -694,6 +694,18 @@ config TI_ADC12138 This driver can also be built as a module. If so, the module will be called ti-adc12138. +config TI_ADC108S102 + tristate "Texas Instruments ADC108S102 and ADC128S102 driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Texas Instruments ADC108S102 and + ADC128S102 ADC. + + To compile this driver as a module, choose M here: the module will + be called ti-adc108s102. + config TI_ADC128S052 tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ed8e8e220dbb..9fb51e6f49cb 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o +obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c new file mode 100644 index 000000000000..de4e5ac98c6e --- /dev/null +++ b/drivers/iio/adc/ti-adc108s102.c @@ -0,0 +1,348 @@ +/* + * TI ADC108S102 SPI ADC driver + * + * Copyright (c) 2013-2015 Intel Corporation. + * Copyright (c) 2017 Siemens AG + * + * 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. + * + * This IIO device driver is designed to work with the following + * analog to digital converters from Texas Instruments: + * ADC108S102 + * ADC128S102 + * The communication with ADC chip is via the SPI bus (mode 3). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * In case of ACPI, we use the hard-wired 5000 mV of the Galileo and IOT2000 + * boards as default for the reference pin VA. Device tree users encode that + * via the vref-supply regulator. + */ +#define ADC108S102_VA_MV_ACPI_DEFAULT 5000 + +/* + * Defining the ADC resolution being 12 bits, we can use the same driver for + * both ADC108S102 (10 bits resolution) and ADC128S102 (12 bits resolution) + * chips. The ADC108S102 effectively returns a 12-bit result with the 2 + * least-significant bits unset. + */ +#define ADC108S102_BITS 12 +#define ADC108S102_MAX_CHANNELS 8 + +/* + * 16-bit SPI command format: + * [15:14] Ignored + * [13:11] 3-bit channel address + * [10:0] Ignored + */ +#define ADC108S102_CMD(ch) ((u16)(ch) << 11) + +/* + * 16-bit SPI response format: + * [15:12] Zeros + * [11:0] 12-bit ADC sample (for ADC108S102, [1:0] will always be 0). + */ +#define ADC108S102_RES_DATA(res) ((u16)res & GENMASK(11, 0)) + +struct adc108s102_state { + struct spi_device *spi; + struct regulator *reg; + u32 va_millivolt; + /* SPI transfer used by triggered buffer handler*/ + struct spi_transfer ring_xfer; + /* SPI transfer used by direct scan */ + struct spi_transfer scan_single_xfer; + /* SPI message used by ring_xfer SPI transfer */ + struct spi_message ring_msg; + /* SPI message used by scan_single_xfer SPI transfer */ + struct spi_message scan_single_msg; + + /* + * SPI message buffers: + * tx_buf: |C0|C1|C2|C3|C4|C5|C6|C7|XX| + * rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt| + * + * tx_buf: 8 channel read commands, plus 1 dummy command + * rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp + */ + __be16 rx_buf[13] ____cacheline_aligned; + __be16 tx_buf[9] ____cacheline_aligned; +}; + +#define ADC108S102_V_CHAN(index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = ADC108S102_BITS, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec adc108s102_channels[] = { + ADC108S102_V_CHAN(0), + ADC108S102_V_CHAN(1), + ADC108S102_V_CHAN(2), + ADC108S102_V_CHAN(3), + ADC108S102_V_CHAN(4), + ADC108S102_V_CHAN(5), + ADC108S102_V_CHAN(6), + ADC108S102_V_CHAN(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +static int adc108s102_update_scan_mode(struct iio_dev *indio_dev, + unsigned long const *active_scan_mask) +{ + struct adc108s102_state *st = iio_priv(indio_dev); + unsigned int bit, cmds; + + /* + * Fill in the first x shorts of tx_buf with the number of channels + * enabled for sampling by the triggered buffer. + */ + cmds = 0; + for_each_set_bit(bit, active_scan_mask, ADC108S102_MAX_CHANNELS) + st->tx_buf[cmds++] = cpu_to_be16(ADC108S102_CMD(bit)); + + /* One dummy command added, to clock in the last response */ + st->tx_buf[cmds++] = 0x00; + + /* build SPI ring message */ + st->ring_xfer.tx_buf = &st->tx_buf[0]; + st->ring_xfer.rx_buf = &st->rx_buf[0]; + st->ring_xfer.len = cmds * sizeof(st->tx_buf[0]); + + spi_message_init_with_transfers(&st->ring_msg, &st->ring_xfer, 1); + + return 0; +} + +static irqreturn_t adc108s102_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adc108s102_state *st = iio_priv(indio_dev); + int ret; + + ret = spi_sync(st->spi, &st->ring_msg); + if (ret < 0) + goto out_notify; + + /* Skip the dummy response in the first slot */ + iio_push_to_buffers_with_timestamp(indio_dev, + (u8 *)&st->rx_buf[1], + iio_get_time_ns(indio_dev)); + +out_notify: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int adc108s102_scan_direct(struct adc108s102_state *st, unsigned int ch) +{ + int ret; + + st->tx_buf[0] = cpu_to_be16(ADC108S102_CMD(ch)); + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + return ret; + + /* Skip the dummy response in the first slot */ + return be16_to_cpu(st->rx_buf[1]); +} + +static int adc108s102_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct adc108s102_state *st = iio_priv(indio_dev); + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = adc108s102_scan_direct(st, chan->address); + + iio_device_release_direct_mode(indio_dev); + + if (ret < 0) + return ret; + + *val = ADC108S102_RES_DATA(ret); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->type != IIO_VOLTAGE) + break; + + *val = st->va_millivolt; + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_info adc108s102_info = { + .read_raw = &adc108s102_read_raw, + .update_scan_mode = &adc108s102_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static int adc108s102_probe(struct spi_device *spi) +{ + struct adc108s102_state *st; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + if (ACPI_COMPANION(&spi->dev)) { + st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT; + } else { + st->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(st->reg)) + return PTR_ERR(st->reg); + + ret = regulator_enable(st->reg); + if (ret < 0) { + dev_err(&spi->dev, "Cannot enable vref regulator\n"); + return ret; + } + + ret = regulator_get_voltage(st->reg); + if (ret < 0) { + dev_err(&spi->dev, "vref get voltage failed\n"); + return ret; + } + + st->va_millivolt = ret / 1000; + } + + spi_set_drvdata(spi, indio_dev); + st->spi = spi; + + indio_dev->name = spi->modalias; + indio_dev->dev.parent = &spi->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = adc108s102_channels; + indio_dev->num_channels = ARRAY_SIZE(adc108s102_channels); + indio_dev->info = &adc108s102_info; + + /* Setup default message */ + st->scan_single_xfer.tx_buf = st->tx_buf; + st->scan_single_xfer.rx_buf = st->rx_buf; + st->scan_single_xfer.len = 2 * sizeof(st->tx_buf[0]); + + spi_message_init_with_transfers(&st->scan_single_msg, + &st->scan_single_xfer, 1); + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &adc108s102_trigger_handler, NULL); + if (ret) + goto error_disable_reg; + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register IIO device\n"); + goto error_cleanup_triggered_buffer; + } + return 0; + +error_cleanup_triggered_buffer: + iio_triggered_buffer_cleanup(indio_dev); + +error_disable_reg: + regulator_disable(st->reg); + + return ret; +} + +static int adc108s102_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adc108s102_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + + regulator_disable(st->reg); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id adc108s102_of_match[] = { + { .compatible = "ti,adc108s102" }, + { } +}; +MODULE_DEVICE_TABLE(of, adc108s102_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id adc108s102_acpi_ids[] = { + { "INT3495", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids); +#endif + +static const struct spi_device_id adc108s102_id[] = { + { "adc108s102", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, adc108s102_id); + +static struct spi_driver adc108s102_driver = { + .driver = { + .name = "adc108s102", + .of_match_table = of_match_ptr(adc108s102_of_match), + .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids), + }, + .probe = adc108s102_probe, + .remove = adc108s102_remove, + .id_table = adc108s102_id, +}; +module_spi_driver(adc108s102_driver); + +MODULE_AUTHOR("Bogdan Pricop "); +MODULE_DESCRIPTION("Texas Instruments ADC108S102 and ADC128S102 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3