summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio12
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-meas-spec8
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/accel/Kconfig14
-rw-r--r--drivers/iio/accel/Makefile4
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c (renamed from drivers/iio/accel/bmc150-accel.c)407
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c102
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c91
-rw-r--r--drivers/iio/accel/bmc150-accel.h20
-rw-r--r--drivers/iio/accel/kxcjk-1013.c34
-rw-r--r--drivers/iio/accel/mma9553.c29
-rw-r--r--drivers/iio/accel/stk8312.c30
-rw-r--r--drivers/iio/accel/stk8ba50.c30
-rw-r--r--drivers/iio/adc/ad799x.c1
-rw-r--r--drivers/iio/adc/max1363.c1
-rw-r--r--drivers/iio/chemical/vz89x.c23
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/ms_sensors/Kconfig6
-rw-r--r--drivers/iio/common/ms_sensors/Makefile5
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.c652
-rw-r--r--drivers/iio/common/ms_sensors/ms_sensors_i2c.h66
-rw-r--r--drivers/iio/dac/ad5504.c1
-rw-r--r--drivers/iio/dac/m62332.c63
-rw-r--r--drivers/iio/humidity/Kconfig13
-rw-r--r--drivers/iio/humidity/Makefile1
-rw-r--r--drivers/iio/humidity/hdc100x.c5
-rw-r--r--drivers/iio/humidity/htu21.c253
-rw-r--r--drivers/iio/imu/kmx61.c28
-rw-r--r--drivers/iio/light/apds9960.c6
-rw-r--r--drivers/iio/light/stk3310.c35
-rw-r--r--drivers/iio/magnetometer/bmc150_magn.c29
-rw-r--r--drivers/iio/potentiometer/Kconfig20
-rw-r--r--drivers/iio/potentiometer/Makefile6
-rw-r--r--drivers/iio/potentiometer/mcp4531.c231
-rw-r--r--drivers/iio/pressure/Kconfig13
-rw-r--r--drivers/iio/pressure/Makefile1
-rw-r--r--drivers/iio/pressure/ms5637.c190
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c1
-rw-r--r--drivers/iio/proximity/sx9500.c9
-rw-r--r--drivers/iio/temperature/Kconfig22
-rw-r--r--drivers/iio/temperature/Makefile2
-rw-r--r--drivers/iio/temperature/mlx90614.c14
-rw-r--r--drivers/iio/temperature/tsys01.c230
-rw-r--r--drivers/iio/temperature/tsys02d.c191
-rw-r--r--drivers/staging/iio/cdc/ad7746.c20
48 files changed, 2389 insertions, 540 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 8ce14c8..0439c2a 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -1474,8 +1474,20 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_resistance_raw
What: /sys/bus/iio/devices/iio:deviceX/in_resistanceX_raw
+What: /sys/bus/iio/devices/iio:deviceX/out_resistance_raw
+What: /sys/bus/iio/devices/iio:deviceX/out_resistanceX_raw
KernelVersion: 4.3
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no offset etc.) resistance reading that can be processed
into an ohm value.
+
+What: /sys/bus/iio/devices/iio:deviceX/heater_enable
+KernelVersion: 4.1.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ '1' (enable) or '0' (disable) specifying the enable
+ of heater function. Same reading values apply
+ This ABI is especially applicable for humidity sensors
+ to heatup the device and get rid of any condensation
+ in some humidity environment
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-meas-spec b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
new file mode 100644
index 0000000..1a6265e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-meas-spec
@@ -0,0 +1,8 @@
+What: /sys/bus/iio/devices/iio:deviceX/battery_low
+KernelVersion: 4.1.0
+Contact: linux-iio@vger.kernel.org
+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
diff --git a/MAINTAINERS b/MAINTAINERS
index cbdbdb6..56215b0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6682,6 +6682,12 @@ W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
+MCP4531 MICROCHIP DIGITAL POTENTIOMETER DRIVER
+M: Peter Rosin <peda@axentia.se>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: drivers/iio/potentiometer/mcp4531.c
+
MEDIA DRIVERS FOR RENESAS - VSP1
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 119c94d..66792e7 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -60,6 +60,7 @@ source "drivers/iio/orientation/Kconfig"
if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
endif #IIO_TRIGGER
+source "drivers/iio/potentiometer/Kconfig"
source "drivers/iio/pressure/Kconfig"
source "drivers/iio/proximity/Kconfig"
source "drivers/iio/temperature/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index e210055..aeca726 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -23,6 +23,7 @@ obj-y += imu/
obj-y += light/
obj-y += magnetometer/
obj-y += orientation/
+obj-y += potentiometer/
obj-y += pressure/
obj-y += proximity/
obj-y += temperature/
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8172ae5..969428d 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -19,19 +19,27 @@ config BMA180
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
- depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+ select REGMAP
+ select BMC150_ACCEL_I2C if I2C
+ select BMC150_ACCEL_SPI if SPI
help
Say yes here to build support for the following Bosch accelerometers:
BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280.
- Currently this only supports the device via an i2c interface.
-
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing accelerometer part, which has
its own address and register map.
+config BMC150_ACCEL_I2C
+ tristate
+ select REGMAP_I2C
+
+config BMC150_ACCEL_SPI
+ tristate
+ select REGMAP_SPI
+
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 020dda0..7925f16 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -4,7 +4,9 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_BMA180) += bma180.o
-obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o
+obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
+obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
+obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel-core.c
index 0104cde..2d33f1e 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -35,10 +35,12 @@
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include <linux/regmap.h>
+
+#include "bmc150-accel.h"
#define BMC150_ACCEL_DRV_NAME "bmc150_accel"
#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event"
-#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int"
#define BMC150_ACCEL_REG_CHIP_ID 0x00
@@ -185,7 +187,9 @@ enum bmc150_accel_trigger_id {
};
struct bmc150_accel_data {
- struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
+ int irq;
struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS];
atomic_t active_intr;
struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS];
@@ -242,6 +246,12 @@ static const struct {
{500000, BMC150_ACCEL_SLEEP_500_MS},
{1000000, BMC150_ACCEL_SLEEP_1_SEC} };
+static const struct regmap_config bmc150_i2c_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f,
+};
+
static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
enum bmc150_power_modes mode,
int dur_us)
@@ -269,12 +279,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data,
lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT;
lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT);
- dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits);
+ dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits);
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n");
+ dev_err(data->dev, "Error writing reg_pmu_lpw\n");
return ret;
}
@@ -290,8 +299,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) {
if (bmc150_accel_samp_freq_table[i].val == val &&
bmc150_accel_samp_freq_table[i].val2 == val2) {
- ret = i2c_smbus_write_byte_data(
- data->client,
+ ret = regmap_write(data->regmap,
BMC150_ACCEL_REG_PMU_BW,
bmc150_accel_samp_freq_table[i].bw_bits);
if (ret < 0)
@@ -308,30 +316,23 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val,
static int bmc150_accel_update_slope(struct bmc150_accel_data *data)
{
- int ret, val;
+ int ret;
- ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6,
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6,
data->slope_thres);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_6\n");
- return ret;
- }
-
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_5\n");
+ dev_err(data->dev, "Error writing reg_int_6\n");
return ret;
}
- val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur;
- ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5,
- val);
+ ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5,
+ BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur);
if (ret < 0) {
- dev_err(&data->client->dev, "Error write reg_int_5\n");
+ dev_err(data->dev, "Error updating reg_int_5\n");
return ret;
}
- dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres,
+ dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres,
data->slope_dur);
return ret;
@@ -380,17 +381,17 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on)
int ret;
if (on) {
- ret = pm_runtime_get_sync(&data->client->dev);
+ ret = pm_runtime_get_sync(data->dev);
} else {
- pm_runtime_mark_last_busy(&data->client->dev);
- ret = pm_runtime_put_autosuspend(&data->client->dev);
+ pm_runtime_mark_last_busy(data->dev);
+ ret = pm_runtime_put_autosuspend(data->dev);
}
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Failed: bmc150_accel_set_power_state for %d\n", on);
if (on)
- pm_runtime_put_noidle(&data->client->dev);
+ pm_runtime_put_noidle(data->dev);
return ret;
}
@@ -470,38 +471,18 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i,
return ret;
/* map the interrupt to the appropriate pins */
- ret = i2c_smbus_read_byte_data(data->client, info->map_reg);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_map\n");
- goto out_fix_power_state;
- }
- if (state)
- ret |= info->map_bitmask;
- else
- ret &= ~info->map_bitmask;
-
- ret = i2c_smbus_write_byte_data(data->client, info->map_reg,
- ret);
+ ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask,
+ (state ? info->map_bitmask : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_map\n");
+ dev_err(data->dev, "Error updating reg_int_map\n");
goto out_fix_power_state;
}
/* enable/disable the interrupt */
- ret = i2c_smbus_read_byte_data(data->client, info->en_reg);
- if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_en\n");
- goto out_fix_power_state;
- }
-
- if (state)
- ret |= info->en_bitmask;
- else
- ret &= ~info->en_bitmask;
-
- ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret);
+ ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask,
+ (state ? info->en_bitmask : 0));
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_en\n");
+ dev_err(data->dev, "Error updating reg_int_en\n");
goto out_fix_power_state;
}
@@ -523,12 +504,11 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) {
if (data->chip_info->scale_table[i].scale == val) {
- ret = i2c_smbus_write_byte_data(
- data->client,
+ ret = regmap_write(data->regmap,
BMC150_ACCEL_REG_PMU_RANGE,
data->chip_info->scale_table[i].reg_range);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing pmu_range\n");
return ret;
}
@@ -544,16 +524,17 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val)
static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val)
{
int ret;
+ unsigned int value;
mutex_lock(&data->mutex);
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_temp\n");
+ dev_err(data->dev, "Error reading reg_temp\n");
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret, 7);
+ *val = sign_extend32(value, 7);
mutex_unlock(&data->mutex);
@@ -566,6 +547,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
{
int ret;
int axis = chan->scan_index;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
ret = bmc150_accel_set_power_state(data, true);
@@ -574,15 +556,15 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data,
return ret;
}
- ret = i2c_smbus_read_word_data(data->client,
- BMC150_ACCEL_AXIS_TO_REG(axis));
+ ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis),
+ &raw_val, 2);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading axis %d\n", axis);
+ dev_err(data->dev, "Error reading axis %d\n", axis);
bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
- *val = sign_extend32(ret >> chan->scan_type.shift,
+ *val = sign_extend32(raw_val >> chan->scan_type.shift,
chan->scan_type.realbits - 1);
ret = bmc150_accel_set_power_state(data, false);
mutex_unlock(&data->mutex);
@@ -846,52 +828,34 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val)
* We must read at least one full frame in one burst, otherwise the rest of the
* frame data is discarded.
*/
-static int bmc150_accel_fifo_transfer(const struct i2c_client *client,
+static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data,
char *buffer, int samples)
{
int sample_length = 3 * 2;
- u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA;
- int ret = -EIO;
-
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
- .flags = 0,
- .buf = &reg_fifo_data,
- .len = sizeof(reg_fifo_data),
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .buf = (u8 *)buffer,
- .len = samples * sample_length,
- }
- };
+ int ret;
+ int total_length = samples * sample_length;
+ int i;
+ size_t step = regmap_get_raw_read_max(data->regmap);
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret != 2)
- ret = -EIO;
- else
- ret = 0;
- } else {
- int i, step = I2C_SMBUS_BLOCK_MAX / sample_length;
-
- for (i = 0; i < samples * sample_length; i += step) {
- ret = i2c_smbus_read_i2c_block_data(client,
- reg_fifo_data, step,
- &buffer[i]);
- if (ret != step) {
- ret = -EIO;
- break;
- }
+ if (!step || step > total_length)
+ step = total_length;
+ else if (step < total_length)
+ step = sample_length;
- ret = 0;
- }
+ /*
+ * Seems we have a bus with size limitation so we have to execute
+ * multiple reads
+ */
+ for (i = 0; i < total_length; i += step) {
+ ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA,
+ &buffer[i], step);
+ if (ret)
+ break;
}
if (ret)
- dev_err(&client->dev, "Error transferring data from fifo\n");
+ dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n",
+ step);
return ret;
}
@@ -905,15 +869,15 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3];
int64_t tstamp;
uint64_t sample_period;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client,
- BMC150_ACCEL_REG_FIFO_STATUS);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_fifo_status\n");
+ dev_err(data->dev, "Error reading reg_fifo_status\n");
return ret;
}
- count = ret & 0x7F;
+ count = val & 0x7F;
if (!count)
return 0;
@@ -952,7 +916,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
if (samples && count > samples)
count = samples;
- ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count);
+ ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
if (ret)
return ret;
@@ -1052,15 +1016,6 @@ static const struct iio_chan_spec bmc150_accel_channels[] =
static const struct iio_chan_spec bma280_accel_channels[] =
BMC150_ACCEL_CHANNELS(14);
-enum {
- bmc150,
- bmi055,
- bma255,
- bma250e,
- bma222e,
- bma280,
-};
-
static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = {
[bmc150] = {
.name = "BMC150A",
@@ -1155,17 +1110,19 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct bmc150_accel_data *data = iio_priv(indio_dev);
int bit, ret, i = 0;
+ unsigned int raw_val;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
- ret = i2c_smbus_read_word_data(data->client,
- BMC150_ACCEL_AXIS_TO_REG(bit));
+ ret = regmap_bulk_read(data->regmap,
+ BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val,
+ 2);
if (ret < 0) {
mutex_unlock(&data->mutex);
goto err_read;
}
- data->buffer[i++] = ret;
+ data->buffer[i++] = raw_val;
}
mutex_unlock(&data->mutex);
@@ -1189,13 +1146,12 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig)
mutex_lock(&data->mutex);
/* clear any latched interrupt */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
mutex_unlock(&data->mutex);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
@@ -1249,20 +1205,20 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
struct bmc150_accel_data *data = iio_priv(indio_dev);
int dir;
int ret;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client,
- BMC150_ACCEL_REG_INT_STATUS_2);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error reading reg_int_status_2\n");
+ dev_err(data->dev, "Error reading reg_int_status_2\n");
return ret;
}
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN)
dir = IIO_EV_DIR_FALLING;
else
dir = IIO_EV_DIR_RISING;
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_X)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1271,7 +1227,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
dir),
data->timestamp);
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1280,7 +1236,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev)
dir),
data->timestamp);
- if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z)
+ if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z)
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL,
0,
@@ -1315,13 +1271,11 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private)
}
if (ack) {
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret)
- dev_err(&data->client->dev,
- "Error writing reg_int_rst_latch\n");
+ dev_err(data->dev, "Error writing reg_int_rst_latch\n");
ret = IRQ_HANDLED;
} else {
@@ -1360,32 +1314,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private)
return IRQ_NONE;
}
-static int bmc150_accel_gpio_probe(struct i2c_client *client,
- struct bmc150_accel_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "Failed: gpio get index\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const struct {
int intr;
const char *name;
@@ -1423,7 +1351,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) {
struct bmc150_accel_trigger *t = &data->triggers[i];
- t->indio_trig = devm_iio_trigger_alloc(&data->client->dev,
+ t->indio_trig = devm_iio_trigger_alloc(data->dev,
bmc150_accel_triggers[i].name,
indio_dev->name,
indio_dev->id);
@@ -1432,7 +1360,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev,
break;
}
- t->indio_trig->dev.parent = &data->client->dev;
+ t->indio_trig->dev.parent = data->dev;
t->indio_trig->ops = &bmc150_accel_trigger_ops;
t->intr = bmc150_accel_triggers[i].intr;
t->data = data;
@@ -1459,20 +1387,19 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1;
int ret;
- ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode);
+ ret = regmap_write(data->regmap, reg, data->fifo_mode);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_fifo_config1\n");
+ dev_err(data->dev, "Error writing reg_fifo_config1\n");
return ret;
}
if (!data->fifo_mode)
return 0;
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_FIFO_CONFIG0,
- data->watermark);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0,
+ data->watermark);
if (ret < 0)
- dev_err(&data->client->dev, "Error writing reg_fifo_config0\n");
+ dev_err(data->dev, "Error writing reg_fifo_config0\n");
return ret;
}
@@ -1557,23 +1484,25 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
{
int ret, i;
+ unsigned int val;
- ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID);
+ ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val);
if (ret < 0) {
- dev_err(&data->client->dev, "Error: Reading chip id\n");
+ dev_err(data->dev,
+ "Error: Reading chip id\n");
return ret;
}
- dev_dbg(&data->client->dev, "Chip Id %x\n", ret);
+ dev_dbg(data->dev, "Chip Id %x\n", val);
for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) {
- if (bmc150_accel_chip_info_tbl[i].chip_id == ret) {
+ if (bmc150_accel_chip_info_tbl[i].chip_id == val) {
data->chip_info = &bmc150_accel_chip_info_tbl[i];
break;
}
}
if (!data->chip_info) {
- dev_err(&data->client->dev, "Unsupported chip %x\n", ret);
+ dev_err(data->dev, "Invalid chip %x\n", val);
return -ENODEV;
}
@@ -1587,11 +1516,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return ret;
/* Set Default Range */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_PMU_RANGE,
- BMC150_ACCEL_DEF_RANGE_4G);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE,
+ BMC150_ACCEL_DEF_RANGE_4G);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_pmu_range\n");
+ dev_err(data->dev,
+ "Error writing reg_pmu_range\n");
return ret;
}
@@ -1605,12 +1534,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return ret;
/* Set default as latched interrupts */
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_INT |
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_INT |
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev,
+ dev_err(data->dev,
"Error writing reg_int_rst_latch\n");
return ret;
}
@@ -1618,24 +1546,23 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data)
return 0;
}
-static int bmc150_accel_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name, bool block_supported)
{
struct bmc150_accel_data *data;
struct iio_dev *indio_dev;
int ret;
- const char *name = NULL;
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
- data->client = client;
+ dev_set_drvdata(dev, indio_dev);
+ data->dev = dev;
+ data->irq = irq;
- if (id)
- name = id->name;
+ data->regmap = regmap;
ret = bmc150_accel_chip_init(data);
if (ret < 0)
@@ -1643,7 +1570,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
mutex_init(&data->mutex);
- indio_dev->dev.parent = &client->dev;
+ indio_dev->dev.parent = dev;
indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = name ? name : data->chip_info->name;
@@ -1655,16 +1582,13 @@ static int bmc150_accel_probe(struct i2c_client *client,
bmc150_accel_trigger_handler,
&bmc150_accel_buffer_ops);
if (ret < 0) {
- dev_err(&client->dev, "Failed: iio triggered buffer setup\n");
+ dev_err(data->dev, "Failed: iio triggered buffer setup\n");
return ret;
}
- if (client->irq < 0)
- client->irq = bmc150_accel_gpio_probe(client, data);
-
- if (client->irq > 0) {
+ if (data->irq > 0) {
ret = devm_request_threaded_irq(
- &client->dev, client->irq,
+ data->dev, data->irq,
bmc150_accel_irq_handler,
bmc150_accel_irq_thread_handler,
IRQF_TRIGGER_RISING,
@@ -1679,11 +1603,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
* want to use latch mode when we can to prevent interrupt
* flooding.
*/
- ret = i2c_smbus_write_byte_data(data->client,
- BMC150_ACCEL_REG_INT_RST_LATCH,
- BMC150_ACCEL_INT_MODE_LATCH_RESET);
+ ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH,
+ BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
- dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
+ dev_err(data->dev, "Error writing reg_int_rst_latch\n");
goto err_buffer_cleanup;
}
@@ -1693,9 +1616,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
if (ret)
goto err_buffer_cleanup;
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
- i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ if (block_supported) {
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
indio_dev->info = &bmc150_accel_info_fifo;
indio_dev->buffer->attrs = bmc150_accel_fifo_attributes;
@@ -1704,18 +1625,17 @@ static int bmc150_accel_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret < 0) {
- dev_err(&client->dev, "Unable to register iio device\n");
+ dev_err(dev, "Unable to register iio device\n");
goto err_trigger_unregister;
}
- ret = pm_runtime_set_active(&client->dev);
+ ret = pm_runtime_set_active(dev);
if (ret)
goto err_iio_unregister;
- pm_runtime_enable(&client->dev);
- pm_runtime_set_autosuspend_delay(&client->dev,
- BMC150_AUTO_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
return 0;
@@ -1728,15 +1648,16 @@ err_buffer_cleanup:
return ret;
}
+EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
-static int bmc150_accel_remove(struct i2c_client *client)
+int bmc150_accel_core_remove(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
- pm_runtime_disable(&client->dev);
- pm_runtime_set_suspended(&client->dev);
- pm_runtime_put_noidle(&client->dev);
+ pm_runtime_disable(data->dev);
+ pm_runtime_set_suspended(data->dev);
+ pm_runtime_put_noidle(data->dev);
iio_device_unregister(indio_dev);
@@ -1750,11 +1671,12 @@ static int bmc150_accel_remove(struct i2c_client *client)
return 0;
}
+EXPORT_SYMBOL_GPL(bmc150_accel_core_remove);
#ifdef CONFIG_PM_SLEEP
static int bmc150_accel_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1766,7 +1688,7 @@ static int bmc150_accel_suspend(struct device *dev)
static int bmc150_accel_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
@@ -1782,11 +1704,11 @@ static int bmc150_accel_resume(struct device *dev)
#ifdef CONFIG_PM
static int bmc150_accel_runtime_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
- dev_dbg(&data->client->dev, __func__);
+ dev_dbg(data->dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0);
if (ret < 0)
return -EAGAIN;
@@ -1796,12 +1718,12 @@ static int bmc150_accel_runtime_suspend(struct device *dev)
static int bmc150_accel_runtime_resume(struct device *dev)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
int ret;
int sleep_val;
- dev_dbg(&data->client->dev, __func__);
+ dev_dbg(data->dev, __func__);
ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0);
if (ret < 0)
@@ -1820,47 +1742,12 @@ static int bmc150_accel_runtime_resume(struct device *dev)
}
#endif
-static const struct dev_pm_ops bmc150_accel_pm_ops = {
+const struct dev_pm_ops bmc150_accel_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume)
SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend,
bmc150_accel_runtime_resume, NULL)
};
-
-static const struct acpi_device_id bmc150_accel_acpi_match[] = {
- {"BSBA0150", bmc150},
- {"BMC150A", bmc150},
- {"BMI055A", bmi055},
- {"BMA0255", bma255},
- {"BMA250E", bma250e},
- {"BMA222E", bma222e},
- {"BMA0280", bma280},
- { },
-};
-MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
-
-static const struct i2c_device_id bmc150_accel_id[] = {
- {"bmc150_accel", bmc150},
- {"bmi055_accel", bmi055},
- {"bma255", bma255},
- {"bma250e", bma250e},
- {"bma222e", bma222e},
- {"bma280", bma280},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
-
-static struct i2c_driver bmc150_accel_driver = {
- .driver = {
- .name = BMC150_ACCEL_DRV_NAME,
- .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
- .pm = &bmc150_accel_pm_ops,
- },
- .probe = bmc150_accel_probe,
- .remove = bmc150_accel_remove,
- .id_table = bmc150_accel_id,
-};
-module_i2c_driver(bmc150_accel_driver);
+EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
new file mode 100644
index 0000000..b41404b
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -0,0 +1,102 @@
+/*
+ * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips:
+ * - BMC150
+ * - BMI055
+ * - BMA255
+ * - BMA250E
+ * - BMA222E
+ * - BMA280
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+
+#include "bmc150-accel.h"
+
+static const struct regmap_config bmc150_i2c_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int bmc150_accel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap *regmap;
+ const char *name = NULL;
+ bool block_supported =
+ i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
+ i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK);
+
+ regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Failed to initialize i2c regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ if (id)
+ name = id->name;
+
+ return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name,
+ block_supported);
+}
+
+static int bmc150_accel_remove(struct i2c_client *client)
+{
+ return bmc150_accel_core_remove(&client->dev);
+}
+
+static const struct acpi_device_id bmc150_accel_acpi_match[] = {
+ {"BSBA0150", bmc150},
+ {"BMC150A", bmc150},
+ {"BMI055A", bmi055},
+ {"BMA0255", bma255},
+ {"BMA250E", bma250e},
+ {"BMA222E", bma222e},
+ {"BMA0280", bma280},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
+
+static const struct i2c_device_id bmc150_accel_id[] = {
+ {"bmc150_accel", bmc150},
+ {"bmi055_accel", bmi055},
+ {"bma255", bma255},
+ {"bma250e", bma250e},
+ {"bma222e", bma222e},
+ {"bma280", bma280},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
+
+static struct i2c_driver bmc150_accel_driver = {
+ .driver = {
+ .name = "bmc150_accel_i2c",
+ .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .pm = &bmc150_accel_pm_ops,
+ },
+ .probe = bmc150_accel_probe,
+ .remove = bmc150_accel_remove,
+ .id_table = bmc150_accel_id,
+};
+module_i2c_driver(bmc150_accel_driver);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 I2C accelerometer driver");
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
new file mode 100644
index 0000000..16b66f2
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -0,0 +1,91 @@
+/*
+ * 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip
+ * Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "bmc150-accel.h"
+
+static const struct regmap_config bmc150_spi_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x3f,
+};
+
+static int bmc150_accel_probe(struct spi_device *spi)
+{
+ struct regmap *regmap;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Failed to initialize spi regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name,
+ true);
+}
+
+static int bmc150_accel_remove(struct spi_device *spi)
+{
+ return bmc150_accel_core_remove(&spi->dev);
+}
+
+static const struct acpi_device_id bmc150_accel_acpi_match[] = {
+ {"BSBA0150", bmc150},
+ {"BMC150A", bmc150},
+ {"BMI055A", bmi055},
+ {"BMA0255", bma255},
+ {"BMA250E", bma250e},
+ {"BMA222E", bma222e},
+ {"BMA0280", bma280},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
+
+static const struct spi_device_id bmc150_accel_id[] = {
+ {"bmc150_accel", bmc150},
+ {"bmi055_accel", bmi055},
+ {"bma255", bma255},
+ {"bma250e", bma250e},
+ {"bma222e", bma222e},
+ {"bma280", bma280},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, bmc150_accel_id);
+
+static struct spi_driver bmc150_accel_driver = {
+ .driver = {
+ .name = "bmc150_accel_spi",
+ .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
+ .pm = &bmc150_accel_pm_ops,
+ },
+ .probe = bmc150_accel_probe,
+ .remove = bmc150_accel_remove,
+ .id_table = bmc150_accel_id,
+};
+module_spi_driver(bmc150_accel_driver);
+
+MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("BMC150 SPI accelerometer driver");
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
new file mode 100644
index 0000000..ba03359
--- /dev/null
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -0,0 +1,20 @@
+#ifndef _BMC150_ACCEL_H_
+#define _BMC150_ACCEL_H_
+
+struct regmap;
+
+enum {
+ bmc150,
+ bmi055,
+ bma255,
+ bma250e,
+ bma222e,
+ bma280,
+};
+
+int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
+ const char *name, bool block_supported);
+int bmc150_accel_core_remove(struct device *dev);
+extern const struct dev_pm_ops bmc150_accel_pm_ops;
+
+#endif /* _BMC150_ACCEL_H_ */
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 3292bc0..18c1b06 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev,
return dev_name(dev);
}
-static int kxcjk1013_gpio_probe(struct i2c_client *client,
- struct kxcjk1013_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- if (data->is_smo8500_device)
- return -ENOTSUPP;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int kxcjk1013_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &kxcjk1013_info;
- if (client->irq < 0)
- client->irq = kxcjk1013_gpio_probe(client, data);
-
- if (client->irq > 0) {
+ if (client->irq > 0 && !data->is_smo8500_device) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kxcjk1013_data_rdy_trig_poll,
kxcjk1013_event_handler,
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
index 771858c..9408ef3 100644
--- a/drivers/iio/accel/mma9553.c
+++ b/drivers/iio/accel/mma9553.c
@@ -26,7 +26,6 @@
#define MMA9553_DRV_NAME "mma9553"
#define MMA9553_IRQ_NAME "mma9553_event"
-#define MMA9553_GPIO_NAME "mma9553_int"
/* Pedometer configuration registers (R/W) */
#define MMA9553_REG_CONF_SLEEPMIN 0x00
@@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private)
return IRQ_HANDLED;
}
-static int mma9553_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready GPIO interrupt pin */
- gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "ACPI GPIO get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const char *mma9553_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
@@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mma9553_info;
- if (client->irq < 0)
- client->irq = mma9553_gpio_probe(client);
-
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
mma9553_irq_handler,
diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c
index c764af2..85fe7f7 100644
--- a/drivers/iio/accel/stk8312.c
+++ b/drivers/iio/accel/stk8312.c
@@ -50,7 +50,6 @@
#define STK8312_ALL_CHANNEL_SIZE 3
#define STK8312_DRIVER_NAME "stk8312"
-#define STK8312_GPIO "stk8312_gpio"
#define STK8312_IRQ_NAME "stk8312_event"
/*
@@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = {
.postdisable = stk8312_buffer_postdisable,
};
-static int stk8312_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int stk8312_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0)
- client->irq = stk8312_gpio_probe(client);
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8312_data_rdy_trig_poll,
NULL,
diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c
index 80f77d8..5709d9e 100644
--- a/drivers/iio/accel/stk8ba50.c
+++ b/drivers/iio/accel/stk8ba50.c
@@ -45,7 +45,6 @@
#define STK8BA50_ALL_CHANNEL_SIZE 6
#define STK8BA50_DRIVER_NAME "stk8ba50"
-#define STK8BA50_GPIO "stk8ba50_gpio"
#define STK8BA50_IRQ_NAME "stk8ba50_event"
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
@@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = {
.postdisable = stk8ba50_buffer_postdisable,
};
-static int stk8ba50_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static int stk8ba50_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client,
goto err_power_off;
}
- if (client->irq < 0)
- client->irq = stk8ba50_gpio_probe(client);
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk8ba50_data_rdy_trig_poll,
NULL,
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index b99de00..01d7158 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -528,7 +528,6 @@ static struct attribute *ad799x_event_attributes[] = {
static struct attribute_group ad799x_event_attrs_group = {
.attrs = ad799x_event_attributes,
- .name = "events",
};
static const struct iio_info ad7991_info = {
diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c
index 1b3b74b..929508e 100644
--- a/drivers/iio/adc/max1363.c
+++ b/drivers/iio/adc/max1363.c
@@ -1007,7 +1007,6 @@ static struct attribute *max1363_event_attributes[] = {
static struct attribute_group max1363_event_attribute_group = {
.attrs = max1363_event_attributes,
- .name = "events",
};
static int max1363_update_scan_mode(struct iio_dev *indio_dev,
diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c
index b454200..11e59a5 100644
--- a/drivers/iio/chemical/vz89x.c
+++ b/drivers/iio/chemical/vz89x.c
@@ -85,6 +85,21 @@ static const struct attribute_group vz89x_attrs_group = {
.attrs = vz89x_attributes,
};
+/*
+ * Chipset sometime updates in the middle of a reading causing it to reset the
+ * data pointer, and causing invalid reading of previous data.
+ * We can check for this by reading MSB of the resistance reading that is
+ * always zero, and by also confirming the VOC_short isn't zero.
+ */
+
+static int vz89x_measurement_is_valid(struct vz89x_data *data)
+{
+ if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
+ return 1;
+
+ return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
+}
+
static int vz89x_get_measurement(struct vz89x_data *data)
{
int ret;
@@ -106,6 +121,10 @@ static int vz89x_get_measurement(struct vz89x_data *data)
data->buffer[i] = ret;
}
+ ret = vz89x_measurement_is_valid(data);
+ if (ret)
+ return -EAGAIN;
+
data->last_update = jiffies;
return 0;
@@ -113,9 +132,9 @@ static int vz89x_get_measurement(struct vz89x_data *data)
static int vz89x_get_resistance_reading(struct vz89x_data *data)
{
- u8 *buf = &data->buffer[VZ89X_VOC_TVOC_IDX];
+ u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
- return buf[0] | (buf[1] << 8) | (buf[2] << 16);
+ return buf[0] | (buf[1] << 8);
}
static int vz89x_read_raw(struct iio_dev *indio_dev,
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 790f106..26a6026 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,5 +3,6 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/ms_sensors/Kconfig"
source "drivers/iio/common/ssp_sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index b1e4d9c..585da6a 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,5 +8,6 @@
# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
+obj-y += ms_sensors/
obj-y += ssp_sensors/
obj-y += st_sensors/
diff --git a/drivers/iio/common/ms_sensors/Kconfig b/drivers/iio/common/ms_sensors/Kconfig
new file mode 100644
index 0000000..b28a92b
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Kconfig
@@ -0,0 +1,6 @@
+#
+# Measurements Specialties sensors common library
+#
+
+config IIO_MS_SENSORS_I2C
+ tristate
diff --git a/drivers/iio/common/ms_sensors/Makefile b/drivers/iio/common/ms_sensors/Makefile
new file mode 100644
index 0000000..7846428
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Measurement Specialties sensor common modules.
+#
+
+obj-$(CONFIG_IIO_MS_SENSORS_I2C) += ms_sensors_i2c.o
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.c b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
new file mode 100644
index 0000000..669dc7c
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.c
@@ -0,0 +1,652 @@
+/*
+ * Measurements Specialties driver common i2c functions
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+
+#include "ms_sensors_i2c.h"
+
+/* Conversion times in us */
+static const u16 ms_sensors_ht_t_conversion_time[] = { 50000, 25000,
+ 13000, 7000 };
+static const u16 ms_sensors_ht_h_conversion_time[] = { 16000, 3000,
+ 5000, 8000 };
+static const u16 ms_sensors_tp_conversion_time[] = { 500, 1100, 2100,
+ 4100, 8220, 16440 };
+
+#define MS_SENSORS_SERIAL_READ_MSB 0xFA0F
+#define MS_SENSORS_SERIAL_READ_LSB 0xFCC9
+#define MS_SENSORS_CONFIG_REG_WRITE 0xE6
+#define MS_SENSORS_CONFIG_REG_READ 0xE7
+#define MS_SENSORS_HT_T_CONVERSION_START 0xF3
+#define MS_SENSORS_HT_H_CONVERSION_START 0xF5
+
+#define MS_SENSORS_TP_PROM_READ 0xA0
+#define MS_SENSORS_TP_T_CONVERSION_START 0x50
+#define MS_SENSORS_TP_P_CONVERSION_START 0x40
+#define MS_SENSORS_TP_ADC_READ 0x00
+
+#define MS_SENSORS_NO_READ_CMD 0xFF
+
+/**
+ * ms_sensors_reset() - Reset function
+ * @cli: pointer to device client
+ * @cmd: reset cmd. Depends on device in use
+ * @delay: usleep minimal delay after reset command is issued
+ *
+ * Generic I2C reset function for Measurement Specialties devices.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay)
+{
+ int ret;
+ struct i2c_client *client = cli;
+
+ ret = i2c_smbus_write_byte(client, cmd);
+ if (ret) {
+ dev_err(&client->dev, "Failed to reset device\n");
+ return ret;
+ }
+ usleep_range(delay, delay + 1000);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_reset);
+
+/**
+ * ms_sensors_read_prom_word() - PROM word read function
+ * @cli: pointer to device client
+ * @cmd: PROM read cmd. Depends on device and prom id
+ * @word: pointer to word destination value
+ *
+ * Generic i2c prom word read function for Measurement Specialties devices.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word)
+{
+ int ret;
+ struct i2c_client *client = (struct i2c_client *)cli;
+
+ ret = i2c_smbus_read_word_swapped(client, cmd);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read prom word\n");
+ return ret;
+ }
+ *word = ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_prom_word);
+
+/**
+ * ms_sensors_convert_and_read() - ADC conversion & read function
+ * @cli: pointer to device client
+ * @conv: ADC conversion command. Depends on device in use
+ * @rd: ADC read command. Depends on device in use
+ * @delay: usleep minimal delay after conversion command is issued
+ * @adc: pointer to ADC destination value
+ *
+ * Generic ADC conversion & read function for Measurement Specialties
+ * devices.
+ * The function will issue conversion command, sleep appopriate delay, and
+ * issue command to read ADC.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc)
+{
+ int ret;
+ __be32 buf = 0;
+ struct i2c_client *client = (struct i2c_client *)cli;
+
+ /* Trigger conversion */
+ ret = i2c_smbus_write_byte(client, conv);
+ if (ret)
+ goto err;
+ usleep_range(delay, delay + 1000);
+
+ /* Retrieve ADC value */
+ if (rd != MS_SENSORS_NO_READ_CMD)
+ ret = i2c_smbus_read_i2c_block_data(client, rd, 3, (u8 *)&buf);
+ else
+ ret = i2c_master_recv(client, (u8 *)&buf, 3);
+ if (ret < 0)
+ goto err;
+
+ dev_dbg(&client->dev, "ADC raw value : %x\n", be32_to_cpu(buf) >> 8);
+ *adc = be32_to_cpu(buf) >> 8;
+
+ return 0;
+err:
+ dev_err(&client->dev, "Unable to make sensor adc conversion\n");
+ return ret;
+}
+EXPORT_SYMBOL(ms_sensors_convert_and_read);
+
+/**
+ * ms_sensors_crc_valid() - CRC check function
+ * @value: input and CRC compare value
+ *
+ * Cyclic Redundancy Check function used in TSYS02D, HTU21, MS8607.
+ * This function performs a x^8 + x^5 + x^4 + 1 polynomial CRC.
+ * The argument contains CRC value in LSB byte while the bytes 1 and 2
+ * are used for CRC computation.
+ *
+ * Return: 1 if CRC is valid, 0 otherwise.
+ */
+static bool ms_sensors_crc_valid(u32 value)
+{
+ u32 polynom = 0x988000; /* x^8 + x^5 + x^4 + 1 */
+ u32 msb = 0x800000;
+ u32 mask = 0xFF8000;
+ u32 result = value & 0xFFFF00;
+ u8 crc = value & 0xFF;
+
+ while (msb != 0x80) {
+ if (result & msb)
+ result = ((result ^ polynom) & mask)
+ | (result & ~mask);
+ msb >>= 1;
+ mask >>= 1;
+ polynom >>= 1;
+ }
+
+ return result == crc;
+}
+
+/**
+ * ms_sensors_read_serial() - Serial number read function
+ * @cli: pointer to i2c client
+ * @sn: pointer to 64-bits destination value
+ *
+ * Generic i2c serial number read function for Measurement Specialties devices.
+ * This function is used for TSYS02d, HTU21, MS8607 chipset.
+ * Refer to datasheet:
+ * http://www.meas-spec.com/downloads/HTU2X_Serial_Number_Reading.pdf
+ *
+ * Sensor raw MSB serial number format is the following :
+ * [ SNB3, CRC, SNB2, CRC, SNB1, CRC, SNB0, CRC]
+ * Sensor raw LSB serial number format is the following :
+ * [ X, X, SNC1, SNC0, CRC, SNA1, SNA0, CRC]
+ * The resulting serial number is following :
+ * [ SNA1, SNA0, SNB3, SNB2, SNB1, SNB0, SNC1, SNC0]
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_serial(struct i2c_client *client, u64 *sn)
+{
+ u8 i;
+ __be64 rcv_buf = 0;
+ u64 rcv_val;
+ __be16 send_buf;
+ int ret;
+
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 2,
+ .buf = (__u8 *)&send_buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .buf = (__u8 *)&rcv_buf,
+ },
+ };
+
+ /* Read MSB part of serial number */
+ send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_MSB);
+ msg[1].len = 8;
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read device serial number");
+ return ret;
+ }
+
+ rcv_val = be64_to_cpu(rcv_buf);
+ dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
+
+ for (i = 0; i < 64; i += 16) {
+ if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFF))
+ return -ENODEV;
+ }
+
+ *sn = (((rcv_val >> 32) & 0xFF000000) |
+ ((rcv_val >> 24) & 0x00FF0000) |
+ ((rcv_val >> 16) & 0x0000FF00) |
+ ((rcv_val >> 8) & 0x000000FF)) << 16;
+
+ /* Read LSB part of serial number */
+ send_buf = cpu_to_be16(MS_SENSORS_SERIAL_READ_LSB);
+ msg[1].len = 6;
+ rcv_buf = 0;
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read device serial number");
+ return ret;
+ }
+
+ rcv_val = be64_to_cpu(rcv_buf) >> 16;
+ dev_dbg(&client->dev, "Serial MSB raw : %llx\n", rcv_val);
+
+ for (i = 0; i < 48; i += 24) {
+ if (!ms_sensors_crc_valid((rcv_val >> i) & 0xFFFFFF))
+ return -ENODEV;
+ }
+
+ *sn |= (rcv_val & 0xFFFF00) << 40 | (rcv_val >> 32);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_serial);
+
+static int ms_sensors_read_config_reg(struct i2c_client *client,
+ u8 *config_reg)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte(client, MS_SENSORS_CONFIG_REG_READ);
+ if (ret) {
+ dev_err(&client->dev, "Unable to read config register");
+ return ret;
+ }
+
+ ret = i2c_master_recv(client, config_reg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to read config register");
+ return ret;
+ }
+ dev_dbg(&client->dev, "Config register :%x\n", *config_reg);
+
+ return 0;
+}
+
+/**
+ * ms_sensors_write_resolution() - Set resolution function
+ * @dev_data: pointer to temperature/humidity device data
+ * @i: resolution index to set
+ *
+ * This function will program the appropriate resolution based on the index
+ * provided when user space will set samp_freq channel.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data,
+ u8 i)
+{
+ u8 config_reg;
+ int ret;
+
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ if (ret)
+ return ret;
+
+ config_reg &= 0x7E;
+ config_reg |= ((i & 1) << 7) + ((i & 2) >> 1);
+
+ return i2c_smbus_write_byte_data(dev_data->client,
+ MS_SENSORS_CONFIG_REG_WRITE,
+ config_reg);
+}
+EXPORT_SYMBOL(ms_sensors_write_resolution);
+
+/**
+ * ms_sensors_show_battery_low() - Show device battery low indicator
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer to write result
+ *
+ * This function will read battery indicator value in the device and
+ * return 1 if the device voltage is below 2.25V.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data,
+ char *buf)
+{
+ int ret;
+ u8 config_reg;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", (config_reg & 0x40) >> 6);
+}
+EXPORT_SYMBOL(ms_sensors_show_battery_low);
+
+/**
+ * ms_sensors_show_heater() - Show device heater
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer to write result
+ *
+ * This function will read heater enable value in the device and
+ * return 1 if the heater is enabled.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: length of sprintf on success, negative errno otherwise.
+ */
+ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data,
+ char *buf)
+{
+ u8 config_reg;
+ int ret;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", (config_reg & 0x4) >> 2);
+}
+EXPORT_SYMBOL(ms_sensors_show_heater);
+
+/**
+ * ms_sensors_write_heater() - Write device heater
+ * @dev_data: pointer to temperature/humidity device data
+ * @buf: pointer to char buffer from user space
+ * @len: length of buf
+ *
+ * This function will write 1 or 0 value in the device
+ * to enable or disable heater.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: length of buffer, negative errno otherwise.
+ */
+ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
+ const char *buf, size_t len)
+{
+ u8 val, config_reg;
+ int ret;
+
+ ret = kstrtou8(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val > 1)
+ return -EINVAL;
+
+ mutex_lock(&dev_data->lock);
+ ret = ms_sensors_read_config_reg(dev_data->client, &config_reg);
+ if (ret) {
+ mutex_unlock(&dev_data->lock);
+ return ret;
+ }
+
+ config_reg &= 0xFB;
+ config_reg |= val << 2;
+
+ ret = i2c_smbus_write_byte_data(dev_data->client,
+ MS_SENSORS_CONFIG_REG_WRITE,
+ config_reg);
+ mutex_unlock(&dev_data->lock);
+ if (ret) {
+ dev_err(&dev_data->client->dev, "Unable to write config register\n");
+ return ret;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL(ms_sensors_write_heater);
+
+/**
+ * ms_sensors_ht_read_temperature() - Read temperature
+ * @dev_data: pointer to temperature/humidity device data
+ * @temperature:pointer to temperature destination value
+ *
+ * This function will get temperature ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * This function is used for TSYS02D, HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
+ s32 *temperature)
+{
+ int ret;
+ u32 adc;
+ u16 delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_ht_t_conversion_time[dev_data->res_index];
+ ret = ms_sensors_convert_and_read(dev_data->client,
+ MS_SENSORS_HT_T_CONVERSION_START,
+ MS_SENSORS_NO_READ_CMD,
+ delay, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ if (!ms_sensors_crc_valid(adc)) {
+ dev_err(&dev_data->client->dev,
+ "Temperature read crc check error\n");
+ return -ENODEV;
+ }
+
+ /* Temperature algorithm */
+ *temperature = (((s64)(adc >> 8) * 175720) >> 16) - 46850;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_ht_read_temperature);
+
+/**
+ * ms_sensors_ht_read_humidity() - Read humidity
+ * @dev_data: pointer to temperature/humidity device data
+ * @humidity: pointer to humidity destination value
+ *
+ * This function will get humidity ADC value from the device,
+ * check the CRC and compute the temperature value.
+ * This function is used for HTU21 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
+ u32 *humidity)
+{
+ int ret;
+ u32 adc;
+ u16 delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_ht_h_conversion_time[dev_data->res_index];
+ ret = ms_sensors_convert_and_read(dev_data->client,
+ MS_SENSORS_HT_H_CONVERSION_START,
+ MS_SENSORS_NO_READ_CMD,
+ delay, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ if (!ms_sensors_crc_valid(adc)) {
+ dev_err(&dev_data->client->dev,
+ "Humidity read crc check error\n");
+ return -ENODEV;
+ }
+
+ /* Humidity algorithm */
+ *humidity = (((s32)(adc >> 8) * 12500) >> 16) * 10 - 6000;
+ if (*humidity >= 100000)
+ *humidity = 100000;
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_ht_read_humidity);
+
+/**
+ * ms_sensors_tp_crc_valid() - CRC check function for
+ * Temperature and pressure devices.
+ * This function is only used when reading PROM coefficients
+ *
+ * @prom: pointer to PROM coefficients array
+ * @len: length of PROM coefficients array
+ *
+ * Return: True if CRC is ok.
+ */
+static bool ms_sensors_tp_crc_valid(u16 *prom, u8 len)
+{
+ unsigned int cnt, n_bit;
+ u16 n_rem = 0x0000, crc_read = prom[0], crc = (*prom & 0xF000) >> 12;
+
+ prom[len - 1] = 0;
+ prom[0] &= 0x0FFF; /* Clear the CRC computation part */
+
+ for (cnt = 0; cnt < len * 2; cnt++) {
+ if (cnt % 2 == 1)
+ n_rem ^= prom[cnt >> 1] & 0x00FF;
+ else
+ n_rem ^= prom[cnt >> 1] >> 8;
+
+ for (n_bit = 8; n_bit > 0; n_bit--) {
+ if (n_rem & 0x8000)
+ n_rem = (n_rem << 1) ^ 0x3000;
+ else
+ n_rem <<= 1;
+ }
+ }
+ n_rem >>= 12;
+ prom[0] = crc_read;
+
+ return n_rem == crc;
+}
+
+/**
+ * ms_sensors_tp_read_prom() - prom coeff read function
+ * @dev_data: pointer to temperature/pressure device data
+ *
+ * This function will read prom coefficients and check CRC.
+ * This function is used for MS5637 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data)
+{
+ int i, ret;
+
+ for (i = 0; i < MS_SENSORS_TP_PROM_WORDS_NB; i++) {
+ ret = ms_sensors_read_prom_word(
+ dev_data->client,
+ MS_SENSORS_TP_PROM_READ + (i << 1),
+ &dev_data->prom[i]);
+
+ if (ret)
+ return ret;
+ }
+
+ if (!ms_sensors_tp_crc_valid(dev_data->prom,
+ MS_SENSORS_TP_PROM_WORDS_NB + 1)) {
+ dev_err(&dev_data->client->dev,
+ "Calibration coefficients crc check error\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_tp_read_prom);
+
+/**
+ * ms_sensors_read_temp_and_pressure() - read temp and pressure
+ * @dev_data: pointer to temperature/pressure device data
+ * @temperature:pointer to temperature destination value
+ * @pressure: pointer to pressure destination value
+ *
+ * This function will read ADC and compute pressure and temperature value.
+ * This function is used for MS5637 and MS8607 chipsets.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+ int *temperature,
+ unsigned int *pressure)
+{
+ int ret;
+ u32 t_adc, p_adc;
+ s32 dt, temp;
+ s64 off, sens, t2, off2, sens2;
+ u16 *prom = dev_data->prom, delay;
+
+ mutex_lock(&dev_data->lock);
+ delay = ms_sensors_tp_conversion_time[dev_data->res_index];
+
+ ret = ms_sensors_convert_and_read(
+ dev_data->client,
+ MS_SENSORS_TP_T_CONVERSION_START +
+ dev_data->res_index * 2,
+ MS_SENSORS_TP_ADC_READ,
+ delay, &t_adc);
+ if (ret) {
+ mutex_unlock(&dev_data->lock);
+ return ret;
+ }
+
+ ret = ms_sensors_convert_and_read(
+ dev_data->client,
+ MS_SENSORS_TP_P_CONVERSION_START +
+ dev_data->res_index * 2,
+ MS_SENSORS_TP_ADC_READ,
+ delay, &p_adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ dt = (s32)t_adc - (prom[5] << 8);
+
+ /* Actual temperature = 2000 + dT * TEMPSENS */
+ temp = 2000 + (((s64)dt * prom[6]) >> 23);
+
+ /* Second order temperature compensation */
+ if (temp < 2000) {
+ s64 tmp = (s64)temp - 2000;
+
+ t2 = (3 * ((s64)dt * (s64)dt)) >> 33;
+ off2 = (61 * tmp * tmp) >> 4;
+ sens2 = (29 * tmp * tmp) >> 4;
+
+ if (temp < -1500) {
+ s64 tmp = (s64)temp + 1500;
+
+ off2 += 17 * tmp * tmp;
+ sens2 += 9 * tmp * tmp;
+ }
+ } else {
+ t2 = (5 * ((s64)dt * (s64)dt)) >> 38;
+ off2 = 0;
+ sens2 = 0;
+ }
+
+ /* OFF = OFF_T1 + TCO * dT */
+ off = (((s64)prom[2]) << 17) + ((((s64)prom[4]) * (s64)dt) >> 6);
+ off -= off2;
+
+ /* Sensitivity at actual temperature = SENS_T1 + TCS * dT */
+ sens = (((s64)prom[1]) << 16) + (((s64)prom[3] * dt) >> 7);
+ sens -= sens2;
+
+ /* Temperature compensated pressure = D1 * SENS - OFF */
+ *temperature = (temp - t2) * 10;
+ *pressure = (u32)(((((s64)p_adc * sens) >> 21) - off) >> 15);
+
+ return 0;
+}
+EXPORT_SYMBOL(ms_sensors_read_temp_and_pressure);
+
+MODULE_DESCRIPTION("Measurement-Specialties common i2c driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/iio/common/ms_sensors/ms_sensors_i2c.h b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
new file mode 100644
index 0000000..7b614ad
--- /dev/null
+++ b/drivers/iio/common/ms_sensors/ms_sensors_i2c.h
@@ -0,0 +1,66 @@
+/*
+ * Measurements Specialties common sensor driver
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * 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.
+ */
+
+#ifndef _MS_SENSORS_I2C_H
+#define _MS_SENSORS_I2C_H
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+#define MS_SENSORS_TP_PROM_WORDS_NB 7
+
+/**
+ * struct ms_ht_dev - Humidity/Temperature sensor device structure
+ * @client: i2c client
+ * @lock: lock protecting the i2c conversion
+ * @res_index: index to selected sensor resolution
+ */
+struct ms_ht_dev {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 res_index;
+};
+
+/**
+ * struct ms_tp_dev - Temperature/Pressure sensor device structure
+ * @client: i2c client
+ * @lock: lock protecting the i2c conversion
+ * @prom: array of PROM coefficients used for conversion. Added element
+ * for CRC computation
+ * @res_index: index to selected sensor resolution
+ */
+struct ms_tp_dev {
+ struct i2c_client *client;
+ struct mutex lock;
+ u16 prom[MS_SENSORS_TP_PROM_WORDS_NB + 1];
+ u8 res_index;
+};
+
+int ms_sensors_reset(void *cli, u8 cmd, unsigned int delay);
+int ms_sensors_read_prom_word(void *cli, int cmd, u16 *word);
+int ms_sensors_convert_and_read(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc);
+int ms_sensors_read_serial(struct i2c_client *client, u64 *sn);
+ssize_t ms_sensors_show_serial(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_write_resolution(struct ms_ht_dev *dev_data, u8 i);
+ssize_t ms_sensors_show_battery_low(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_show_heater(struct ms_ht_dev *dev_data, char *buf);
+ssize_t ms_sensors_write_heater(struct ms_ht_dev *dev_data,
+ const char *buf, size_t len);
+int ms_sensors_ht_read_temperature(struct ms_ht_dev *dev_data,
+ s32 *temperature);
+int ms_sensors_ht_read_humidity(struct ms_ht_dev *dev_data,
+ u32 *humidity);
+int ms_sensors_tp_read_prom(struct ms_tp_dev *dev_data);
+int ms_sensors_read_temp_and_pressure(struct ms_tp_dev *dev_data,
+ int *temperature,
+ unsigned int *pressure);
+
+#endif /* _MS_SENSORS_I2C_H */
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
index 581ec14..e6e9756 100644
--- a/drivers/iio/dac/ad5504.c
+++ b/drivers/iio/dac/ad5504.c
@@ -214,7 +214,6 @@ static struct attribute *ad5504_ev_attributes[] = {
static struct attribute_group ad5504_ev_attribute_group = {
.attrs = ad5504_ev_attributes,
- .name = "events",
};
static irqreturn_t ad5504_event_handler(int irq, void *private)
diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c
index c23d7fa..76e8b04 100644
--- a/drivers/iio/dac/m62332.c
+++ b/drivers/iio/dac/m62332.c
@@ -31,7 +31,6 @@
struct m62332_data {
struct i2c_client *client;
- u16 vref_mv;
struct regulator *vcc;
struct mutex mutex;
u8 raw[M62332_CHANNELS];
@@ -40,8 +39,7 @@ struct m62332_data {
#endif
};
-static int m62332_set_value(struct iio_dev *indio_dev,
- u8 val, int channel)
+static int m62332_set_value(struct iio_dev *indio_dev, u8 val, int channel)
{
struct m62332_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
@@ -62,8 +60,8 @@ static int m62332_set_value(struct iio_dev *indio_dev,
goto out;
}
- res = i2c_master_send(client, outbuf, 2);
- if (res >= 0 && res != 2)
+ res = i2c_master_send(client, outbuf, ARRAY_SIZE(outbuf));
+ if (res >= 0 && res != ARRAY_SIZE(outbuf))
res = -EIO;
if (res < 0)
goto out;
@@ -87,46 +85,52 @@ static int m62332_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
- long m)
+ long mask)
{
struct m62332_data *data = iio_priv(indio_dev);
+ int ret;
- switch (m) {
+ switch (mask) {
case IIO_CHAN_INFO_SCALE:
/* Corresponds to Vref / 2^(bits) */
- *val = data->vref_mv;
+ ret = regulator_get_voltage(data->vcc);
+ if (ret < 0)
+ return ret;
+
+ *val = ret / 1000; /* mV */
*val2 = 8;
+
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_RAW:
*val = data->raw[chan->channel];
+
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = 1;
+
return IIO_VAL_INT;
default:
break;
}
+
return -EINVAL;
}
static int m62332_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan, int val, int val2, long mask)
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
{
- int ret;
-
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val > 255)
return -EINVAL;
- ret = m62332_set_value(indio_dev, val, chan->channel);
- break;
+ return m62332_set_value(indio_dev, val, chan->channel);
default:
- ret = -EINVAL;
break;
}
- return ret;
+ return -EINVAL;
}
#ifdef CONFIG_PM_SLEEP
@@ -173,15 +177,15 @@ static const struct iio_info m62332_info = {
.driver_module = THIS_MODULE,
};
-#define M62332_CHANNEL(chan) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .output = 1, \
- .channel = (chan), \
- .datasheet_name = "CH" #chan, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE) | \
- BIT(IIO_CHAN_INFO_OFFSET), \
+#define M62332_CHANNEL(chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (chan), \
+ .datasheet_name = "CH" #chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
@@ -199,6 +203,7 @@ static int m62332_probe(struct i2c_client *client,
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
+
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
@@ -212,16 +217,11 @@ static int m62332_probe(struct i2c_client *client,
/* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
- indio_dev->num_channels = M62332_CHANNELS;
+ indio_dev->num_channels = ARRAY_SIZE(m62332_channels);
indio_dev->channels = m62332_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &m62332_info;
- ret = regulator_get_voltage(data->vcc);
- if (ret < 0)
- return ret;
- data->vref_mv = ret / 1000; /* mV */
-
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
return ret;
@@ -234,6 +234,7 @@ static int m62332_probe(struct i2c_client *client,
err:
iio_map_array_unregister(indio_dev);
+
return ret;
}
@@ -243,6 +244,8 @@ static int m62332_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
+ m62332_set_value(indio_dev, 0, 0);
+ m62332_set_value(indio_dev, 0, 1);
return 0;
}
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 353ee9a..6a23698 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -22,6 +22,19 @@ config HDC100X
To compile this driver as a module, choose M here: the module
will be called hdc100x.
+config HTU21
+ tristate "Measurement Specialties HTU21 humidity & temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ HTU21 humidity and temperature sensor.
+ This driver is also used for MS8607 temperature, pressure & humidity
+ sensor
+
+ This driver can also be built as a module. If so, the module will
+ be called htu21.
+
config SI7005
tristate "SI7005 relative humidity and temperature sensor"
depends on I2C
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
index 3e62c0a..c9f089a 100644
--- a/drivers/iio/humidity/Makefile
+++ b/drivers/iio/humidity/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_DHT11) += dht11.o
obj-$(CONFIG_HDC100X) += hdc100x.o
+obj-$(CONFIG_HTU21) += htu21.o
obj-$(CONFIG_SI7005) += si7005.o
obj-$(CONFIG_SI7020) += si7020.o
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index 2824578..a7f61e88 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -221,8 +221,9 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_OFFSET:
- *val = -40;
- return IIO_VAL_INT;
+ *val = -3971;
+ *val2 = 879096;
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
new file mode 100644
index 0000000..d1636a7
--- /dev/null
+++ b/drivers/iio/humidity/htu21.c
@@ -0,0 +1,253 @@
+/*
+ * htu21.c - Support for Measurement-Specialties
+ * htu21 temperature & humidity sensor
+ * and humidity part of MS8607 sensor
+ *
+ * Copyright (c) 2014 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/HTU21D.pdf
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define HTU21_RESET 0xFE
+
+enum {
+ HTU21,
+ MS8607
+};
+
+static const int htu21_samp_freq[4] = { 20, 40, 70, 120 };
+/* String copy of the above const for readability purpose */
+static const char htu21_show_samp_freq[] = "20 40 70 120";
+
+static int htu21_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret, temperature;
+ unsigned int humidity;
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = ms_sensors_ht_read_temperature(dev_data,
+ &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ case IIO_HUMIDITYRELATIVE: /* in milli %RH */
+ ret = ms_sensors_ht_read_humidity(dev_data,
+ &humidity);
+ if (ret)
+ return ret;
+ *val = humidity;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = htu21_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int htu21_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+ int i, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(htu21_samp_freq);
+ while (i-- > 0)
+ if (val == htu21_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ mutex_lock(&dev_data->lock);
+ dev_data->res_index = i;
+ ret = ms_sensors_write_resolution(dev_data, i);
+ mutex_unlock(&dev_data->lock);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec htu21_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+/*
+ * Meas Spec recommendation is to not read temperature
+ * on this driver part for MS8607
+ */
+static const struct iio_chan_spec ms8607_channels[] = {
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static ssize_t htu21_show_battery_low(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_battery_low(dev_data, buf);
+}
+
+static ssize_t htu21_show_heater(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_heater(dev_data, buf);
+}
+
+static ssize_t htu21_write_heater(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_write_heater(dev_data, buf, len);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(htu21_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+ htu21_show_battery_low, NULL, 0);
+static IIO_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR,
+ htu21_show_heater, htu21_write_heater, 0);
+
+static struct attribute *htu21_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_battery_low.dev_attr.attr,
+ &iio_dev_attr_heater_enable.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group htu21_attribute_group = {
+ .attrs = htu21_attributes,
+};
+
+static const struct iio_info htu21_info = {
+ .read_raw = htu21_read_raw,
+ .write_raw = htu21_write_raw,
+ .attrs = &htu21_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int htu21_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_ht_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+ u64 serial_number;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 0;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &htu21_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ if (id->driver_data == MS8607) {
+ indio_dev->channels = ms8607_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ms8607_channels);
+ } else {
+ indio_dev->channels = htu21_channels;
+ indio_dev->num_channels = ARRAY_SIZE(htu21_channels);
+ }
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, HTU21_RESET, 15000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_read_serial(client, &serial_number);
+ if (ret)
+ return ret;
+ dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id htu21_id[] = {
+ {"htu21", HTU21},
+ {"ms8607-humidity", MS8607},
+ {}
+};
+
+static struct i2c_driver htu21_driver = {
+ .probe = htu21_probe,
+ .id_table = htu21_id,
+ .driver = {
+ .name = "htu21",
+ },
+};
+
+module_i2c_driver(htu21_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties htu21 temperature and humidity driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
index 82cdf50..dbf5e99 100644
--- a/drivers/iio/imu/kmx61.c
+++ b/drivers/iio/imu/kmx61.c
@@ -27,7 +27,6 @@
#include <linux/iio/trigger_consumer.h>
#define KMX61_DRV_NAME "kmx61"
-#define KMX61_GPIO_NAME "kmx61_int"
#define KMX61_IRQ_NAME "kmx61_event"
#define KMX61_REG_WHO_AM_I 0x00
@@ -1243,30 +1242,6 @@ static const char *kmx61_match_acpi_device(struct device *dev)
return dev_name(dev);
}
-static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
- return ret;
-}
-
static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
const struct iio_info *info,
const struct iio_chan_spec *chan,
@@ -1360,9 +1335,6 @@ static int kmx61_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0)
- client->irq = kmx61_gpio_probe(client, data);
-
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
kmx61_data_rdy_trig_poll,
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index bf80ce4..7d269ef 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -472,7 +472,7 @@ static int apds9960_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct apds9960_data *data = iio_priv(indio_dev);
- u16 buf;
+ __le16 buf;
int ret = -EINVAL;
if (data->gesture_mode_running)
@@ -613,7 +613,7 @@ static int apds9960_read_event(struct iio_dev *indio_dev,
int *val, int *val2)
{
u8 reg;
- u16 buf;
+ __le16 buf;
int ret = 0;
struct apds9960_data *data = iio_priv(indio_dev);
@@ -649,7 +649,7 @@ static int apds9960_write_event(struct iio_dev *indio_dev,
int val, int val2)
{
u8 reg;
- u16 buf;
+ __le16 buf;
int ret = 0;
struct apds9960_data *data = iio_priv(indio_dev);
diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c
index 013b217..42d334b 100644
--- a/drivers/iio/light/stk3310.c
+++ b/drivers/iio/light/stk3310.c
@@ -47,7 +47,6 @@
#define STK3310_DRIVER_NAME "stk3310"
#define STK3310_REGMAP_NAME "stk3310_regmap"
#define STK3310_EVENT "stk3310_event"
-#define STK3310_GPIO "stk3310_gpio"
#define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1"
@@ -477,30 +476,6 @@ static int stk3310_init(struct iio_dev *indio_dev)
return ret;
}
-static int stk3310_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* gpio interrupt pin */
- gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "acpi gpio get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
@@ -624,15 +599,7 @@ static int stk3310_probe(struct i2c_client *client,
if (ret < 0)
return ret;
- if (client->irq < 0) {
- client->irq = stk3310_gpio_probe(client);
- if (client->irq < 0) {
- ret = client->irq;
- goto err_standby;
- }
- }
-
- if (client->irq >= 0) {
+ if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk3310_irq_handler,
stk3310_irq_event_handler,
diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c
index d8e614c..1615b23 100644
--- a/drivers/iio/magnetometer/bmc150_magn.c
+++ b/drivers/iio/magnetometer/bmc150_magn.c
@@ -37,7 +37,6 @@
#define BMC150_MAGN_DRV_NAME "bmc150_magn"
#define BMC150_MAGN_IRQ_NAME "bmc150_magn_event"
-#define BMC150_MAGN_GPIO_INT "interrupt"
#define BMC150_MAGN_REG_CHIP_ID 0x40
#define BMC150_MAGN_CHIP_ID_VAL 0x32
@@ -833,31 +832,6 @@ static const struct iio_buffer_setup_ops bmc150_magn_buffer_setup_ops = {
.postdisable = bmc150_magn_buffer_postdisable,
};
-static int bmc150_magn_gpio_probe(struct i2c_client *client)
-{
- struct device *dev;
- struct gpio_desc *gpio;
- int ret;
-
- if (!client)
- return -EINVAL;
-
- dev = &client->dev;
-
- /* data ready GPIO interrupt pin */
- gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN);
- if (IS_ERR(gpio)) {
- dev_err(dev, "ACPI GPIO get index failed\n");
- return PTR_ERR(gpio);
- }
-
- ret = gpiod_to_irq(gpio);
-
- dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
-
- return ret;
-}
-
static const char *bmc150_magn_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
@@ -911,9 +885,6 @@ static int bmc150_magn_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_magn_info;
- if (client->irq <= 0)
- client->irq = bmc150_magn_gpio_probe(client);
-
if (client->irq > 0) {
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig
new file mode 100644
index 0000000..fd75db7
--- /dev/null
+++ b/drivers/iio/potentiometer/Kconfig
@@ -0,0 +1,20 @@
+#
+# Potentiometer drivers
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Digital potentiometers"
+
+config MCP4531
+ tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver"
+ depends on I2C
+ help
+ Say yes here to build support for the Microchip
+ MCP4531, MCP4532, MCP4551, MCP4552,
+ MCP4631, MCP4632, MCP4651, MCP4652
+ digital potentiomenter chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mcp4531.
+
+endmenu
diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile
new file mode 100644
index 0000000..8afe492
--- /dev/null
+++ b/drivers/iio/potentiometer/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for industrial I/O potentiometer drivers
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_MCP4531) += mcp4531.o
diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c
new file mode 100644
index 0000000..a3f6687
--- /dev/null
+++ b/drivers/iio/potentiometer/mcp4531.c
@@ -0,0 +1,231 @@
+/*
+ * Industrial I/O driver for Microchip digital potentiometers
+ * Copyright (c) 2015 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Datasheet: http://www.microchip.com/downloads/en/DeviceDoc/22096b.pdf
+ *
+ * DEVID #Wipers #Positions Resistor Opts (kOhm) i2c address
+ * mcp4531 1 129 5, 10, 50, 100 010111x
+ * mcp4532 1 129 5, 10, 50, 100 01011xx
+ * mcp4551 1 257 5, 10, 50, 100 010111x
+ * mcp4552 1 257 5, 10, 50, 100 01011xx
+ * mcp4631 2 129 5, 10, 50, 100 0101xxx
+ * mcp4632 2 129 5, 10, 50, 100 01011xx
+ * mcp4651 2 257 5, 10, 50, 100 0101xxx
+ * mcp4652 2 257 5, 10, 50, 100 01011xx
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+
+struct mcp4531_cfg {
+ int wipers;
+ int max_pos;
+ int kohms;
+};
+
+enum mcp4531_type {
+ MCP453x_502,
+ MCP453x_103,
+ MCP453x_503,
+ MCP453x_104,
+ MCP455x_502,
+ MCP455x_103,
+ MCP455x_503,
+ MCP455x_104,
+ MCP463x_502,
+ MCP463x_103,
+ MCP463x_503,
+ MCP463x_104,
+ MCP465x_502,
+ MCP465x_103,
+ MCP465x_503,
+ MCP465x_104,
+};
+
+static const struct mcp4531_cfg mcp4531_cfg[] = {
+ [MCP453x_502] = { .wipers = 1, .max_pos = 128, .kohms = 5, },
+ [MCP453x_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
+ [MCP453x_503] = { .wipers = 1, .max_pos = 128, .kohms = 50, },
+ [MCP453x_104] = { .wipers = 1, .max_pos = 128, .kohms = 100, },
+ [MCP455x_502] = { .wipers = 1, .max_pos = 256, .kohms = 5, },
+ [MCP455x_103] = { .wipers = 1, .max_pos = 256, .kohms = 10, },
+ [MCP455x_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
+ [MCP455x_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+ [MCP463x_502] = { .wipers = 2, .max_pos = 128, .kohms = 5, },
+ [MCP463x_103] = { .wipers = 2, .max_pos = 128, .kohms = 10, },
+ [MCP463x_503] = { .wipers = 2, .max_pos = 128, .kohms = 50, },
+ [MCP463x_104] = { .wipers = 2, .max_pos = 128, .kohms = 100, },
+ [MCP465x_502] = { .wipers = 2, .max_pos = 256, .kohms = 5, },
+ [MCP465x_103] = { .wipers = 2, .max_pos = 256, .kohms = 10, },
+ [MCP465x_503] = { .wipers = 2, .max_pos = 256, .kohms = 50, },
+ [MCP465x_104] = { .wipers = 2, .max_pos = 256, .kohms = 100, },
+};
+
+#define MCP4531_WRITE (0 << 2)
+#define MCP4531_INCR (1 << 2)
+#define MCP4531_DECR (2 << 2)
+#define MCP4531_READ (3 << 2)
+
+#define MCP4531_WIPER_SHIFT (4)
+
+struct mcp4531_data {
+ struct i2c_client *client;
+ unsigned long devid;
+};
+
+#define MCP4531_CHANNEL(ch) { \
+ .type = IIO_RESISTANCE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = (ch), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec mcp4531_channels[] = {
+ MCP4531_CHANNEL(0),
+ MCP4531_CHANNEL(1),
+};
+
+static int mcp4531_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+ s32 ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = i2c_smbus_read_word_swapped(data->client,
+ MCP4531_READ | address);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000 * mcp4531_cfg[data->devid].kohms;
+ *val2 = mcp4531_cfg[data->devid].max_pos;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static int mcp4531_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mcp4531_data *data = iio_priv(indio_dev);
+ int address = chan->channel << MCP4531_WIPER_SHIFT;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (val > mcp4531_cfg[data->devid].max_pos || val < 0)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i2c_smbus_write_byte_data(data->client,
+ MCP4531_WRITE | address | (val >> 8),
+ val & 0xff);
+}
+
+static const struct iio_info mcp4531_info = {
+ .read_raw = mcp4531_read_raw,
+ .write_raw = mcp4531_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int mcp4531_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ unsigned long devid = id->driver_data;
+ struct mcp4531_data *data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_err(dev, "SMBUS Word Data not supported\n");
+ return -EIO;
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->devid = devid;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &mcp4531_info;
+ indio_dev->channels = mcp4531_channels;
+ indio_dev->num_channels = mcp4531_cfg[devid].wipers;
+ indio_dev->name = client->name;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id mcp4531_id[] = {
+ { "mcp4531-502", MCP453x_502 },
+ { "mcp4531-103", MCP453x_103 },
+ { "mcp4531-503", MCP453x_503 },
+ { "mcp4531-104", MCP453x_104 },
+ { "mcp4532-502", MCP453x_502 },
+ { "mcp4532-103", MCP453x_103 },
+ { "mcp4532-503", MCP453x_503 },
+ { "mcp4532-104", MCP453x_104 },
+ { "mcp4551-502", MCP455x_502 },
+ { "mcp4551-103", MCP455x_103 },
+ { "mcp4551-503", MCP455x_503 },
+ { "mcp4551-104", MCP455x_104 },
+ { "mcp4552-502", MCP455x_502 },
+ { "mcp4552-103", MCP455x_103 },
+ { "mcp4552-503", MCP455x_503 },
+ { "mcp4552-104", MCP455x_104 },
+ { "mcp4631-502", MCP463x_502 },
+ { "mcp4631-103", MCP463x_103 },
+ { "mcp4631-503", MCP463x_503 },
+ { "mcp4631-104", MCP463x_104 },
+ { "mcp4632-502", MCP463x_502 },
+ { "mcp4632-103", MCP463x_103 },
+ { "mcp4632-503", MCP463x_503 },
+ { "mcp4632-104", MCP463x_104 },
+ { "mcp4651-502", MCP465x_502 },
+ { "mcp4651-103", MCP465x_103 },
+ { "mcp4651-503", MCP465x_503 },
+ { "mcp4651-104", MCP465x_104 },
+ { "mcp4652-502", MCP465x_502 },
+ { "mcp4652-103", MCP465x_103 },
+ { "mcp4652-503", MCP465x_503 },
+ { "mcp4652-104", MCP465x_104 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp4531_id);
+
+static struct i2c_driver mcp4531_driver = {
+ .driver = {
+ .name = "mcp4531",
+ },
+ .probe = mcp4531_probe,
+ .id_table = mcp4531_id,
+};
+
+module_i2c_driver(mcp4531_driver);
+
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_DESCRIPTION("MCP4531 digital potentiometer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 4745179..6f2e7c9 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -79,6 +79,19 @@ config MS5611_SPI
To compile this driver as a module, choose M here: the module will
be called ms5611_spi.
+config MS5637
+ tristate "Measurement Specialties MS5637 pressure & temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ MS5637 pressure and temperature sensor.
+ This driver is also used for MS8607 temperature, pressure & humidity
+ sensor
+
+ This driver can also be built as a module. If so, the module will
+ be called ms5637.
+
config IIO_ST_PRESS
tristate "STMicroelectronics pressure sensor Driver"
depends on (I2C || SPI_MASTER) && SYSFS
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index a4f98f8..46571c96 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o
obj-$(CONFIG_MS5611) += ms5611_core.o
obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o
obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o
+obj-$(CONFIG_MS5637) += ms5637.o
obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o
st_pressure-y := st_pressure_core.o
st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o
diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c
new file mode 100644
index 0000000..e8d0e0d
--- /dev/null
+++ b/drivers/iio/pressure/ms5637.c
@@ -0,0 +1,190 @@
+/*
+ * ms5637.c - Support for Measurement-Specialties ms5637 and ms8607
+ * pressure & temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x76)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS5637-02BA03.pdf
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/MS8607-02BA01.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/mutex.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 };
+/* String copy of the above const for readability purpose */
+static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30";
+
+static int ms5637_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ int temperature;
+ unsigned int pressure;
+ struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = ms_sensors_read_temp_and_pressure(dev_data,
+ &temperature,
+ &pressure);
+ if (ret)
+ return ret;
+
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ case IIO_PRESSURE: /* in kPa */
+ *val = pressure / 1000;
+ *val2 = (pressure % 1000) * 1000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = ms5637_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ms5637_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_tp_dev *dev_data = iio_priv(indio_dev);
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(ms5637_samp_freq);
+ while (i-- > 0)
+ if (val == ms5637_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ dev_data->res_index = i;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec ms5637_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq);
+
+static struct attribute *ms5637_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ms5637_attribute_group = {
+ .attrs = ms5637_attributes,
+};
+
+static const struct iio_info ms5637_info = {
+ .read_raw = ms5637_read_raw,
+ .write_raw = ms5637_write_raw,
+ .attrs = &ms5637_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int ms5637_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_tp_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 5;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &ms5637_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ms5637_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ms5637_channels);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, 0x1E, 3000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_tp_read_prom(dev_data);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ms5637_id[] = {
+ {"ms5637", 0},
+ {"ms8607-temppressure", 1},
+ {}
+};
+
+static struct i2c_driver ms5637_driver = {
+ .probe = ms5637_probe,
+ .id_table = ms5637_id,
+ .driver = {
+ .name = "ms5637"
+ },
+};
+
+module_i2c_driver(ms5637_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 185a7ab..961f9f99 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -271,6 +271,7 @@ static const struct of_device_id lidar_dt_ids[] = {
{ .compatible = "pulsedlight,lidar-lite-v2" },
{ }
};
+MODULE_DEVICE_TABLE(of, lidar_dt_ids);
static struct i2c_driver lidar_driver = {
.driver = {
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
index 3d756bd..66cd09a 100644
--- a/drivers/iio/proximity/sx9500.c
+++ b/drivers/iio/proximity/sx9500.c
@@ -868,21 +868,12 @@ static void sx9500_gpio_probe(struct i2c_client *client,
struct sx9500_data *data)
{
struct device *dev;
- struct gpio_desc *gpio;
if (!client)
return;
dev = &client->dev;
- if (client->irq <= 0) {
- gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN);
- if (IS_ERR(gpio))
- dev_err(dev, "gpio get irq failed\n");
- else
- client->irq = gpiod_to_irq(gpio);
- }
-
data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET,
0, GPIOD_OUT_HIGH);
if (IS_ERR(data->gpiod_rst)) {
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index 21feaa4..c4664e5 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -23,4 +23,26 @@ config TMP006
This driver can also be built as a module. If so, the module will
be called tmp006.
+config TSYS01
+ tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ TSYS01 I2C temperature sensor.
+
+ This driver can also be built as a module. If so, the module will
+ be called tsys01.
+
+config TSYS02D
+ tristate "Measurement Specialties TSYS02D temperature sensor"
+ depends on I2C
+ select IIO_MS_SENSORS_I2C
+ help
+ If you say yes here you get support for the Measurement Specialties
+ TSYS02D temperature sensor.
+
+ This driver can also be built as a module. If so, the module will
+ be called tsys02d.
+
endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 40710a8..02bc79d 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -4,3 +4,5 @@
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
+obj-$(CONFIG_TSYS01) += tsys01.o
+obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c
index 3fd3ba4..a570c2e 100644
--- a/drivers/iio/temperature/mlx90614.c
+++ b/drivers/iio/temperature/mlx90614.c
@@ -72,6 +72,7 @@
#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */
#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */
#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */
+#define MLX90614_CONST_FIR 0x7 /* Fixed value for FIR part of low pass filter */
struct mlx90614_data {
struct i2c_client *client;
@@ -156,15 +157,16 @@ static inline s32 mlx90614_iir_search(const struct i2c_client *client,
* changes
*/
ret = i2c_smbus_read_word_data(client, MLX90614_CONFIG);
- if (ret > 0)
+ if (ret < 0)
return ret;
+ ret &= ~MLX90614_CONFIG_FIR_MASK;
+ ret |= MLX90614_CONST_FIR << MLX90614_CONFIG_FIR_SHIFT;
+ ret &= ~MLX90614_CONFIG_IIR_MASK;
+ ret |= i << MLX90614_CONFIG_IIR_SHIFT;
+
/* Write changed values */
- ret = mlx90614_write_word(client, MLX90614_CONFIG,
- (i << MLX90614_CONFIG_IIR_SHIFT) |
- (((u16) ((0x7 << MLX90614_CONFIG_FIR_SHIFT) |
- ((u16) ret & (~((u16) MLX90614_CONFIG_FIR_MASK))))) &
- (~(u16) MLX90614_CONFIG_IIR_MASK)));
+ ret = mlx90614_write_word(client, MLX90614_CONFIG, ret);
return ret;
}
diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c
new file mode 100644
index 0000000..05c1206
--- /dev/null
+++ b/drivers/iio/temperature/tsys01.c
@@ -0,0 +1,230 @@
+/*
+ * tsys01.c - Support for Measurement-Specialties tsys01 temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/TSYS01_Digital_Temperature_Sensor.pdf
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+/* TSYS01 Commands */
+#define TSYS01_RESET 0x1E
+#define TSYS01_CONVERSION_START 0x48
+#define TSYS01_ADC_READ 0x00
+#define TSYS01_PROM_READ 0xA0
+
+#define TSYS01_PROM_WORDS_NB 8
+
+struct tsys01_dev {
+ void *client;
+ struct mutex lock; /* lock during conversion */
+
+ int (*reset)(void *cli, u8 cmd, unsigned int delay);
+ int (*convert_and_read)(void *cli, u8 conv, u8 rd,
+ unsigned int delay, u32 *adc);
+ int (*read_prom_word)(void *cli, int cmd, u16 *word);
+
+ u16 prom[TSYS01_PROM_WORDS_NB];
+};
+
+/* Multiplication coefficients for temperature computation */
+static const int coeff_mul[] = { -1500000, 1000000, -2000000,
+ 4000000, -2000000 };
+
+static int tsys01_read_temperature(struct iio_dev *indio_dev,
+ s32 *temperature)
+{
+ int ret, i;
+ u32 adc;
+ s64 temp = 0;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+ mutex_lock(&dev_data->lock);
+ ret = dev_data->convert_and_read(dev_data->client,
+ TSYS01_CONVERSION_START,
+ TSYS01_ADC_READ, 9000, &adc);
+ mutex_unlock(&dev_data->lock);
+ if (ret)
+ return ret;
+
+ adc >>= 8;
+
+ /* Temperature algorithm */
+ for (i = 4; i > 0; i--) {
+ temp += coeff_mul[i] *
+ (s64)dev_data->prom[5 - i];
+ temp *= (s64)adc;
+ temp = div64_s64(temp, 100000);
+ }
+ temp *= 10;
+ temp += coeff_mul[0] * (s64)dev_data->prom[5];
+ temp = div64_s64(temp, 100000);
+
+ *temperature = temp;
+
+ return 0;
+}
+
+static int tsys01_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ s32 temperature;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = tsys01_read_temperature(indio_dev, &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tsys01_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ }
+};
+
+static const struct iio_info tsys01_info = {
+ .read_raw = tsys01_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static bool tsys01_crc_valid(u16 *n_prom)
+{
+ u8 cnt;
+ u8 sum = 0;
+
+ for (cnt = 0; cnt < TSYS01_PROM_WORDS_NB; cnt++)
+ sum += ((n_prom[0] >> 8) + (n_prom[0] & 0xFF));
+
+ return (sum == 0);
+}
+
+static int tsys01_read_prom(struct iio_dev *indio_dev)
+{
+ int i, ret;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+ char buf[7 * TSYS01_PROM_WORDS_NB + 1];
+ char *ptr = buf;
+
+ for (i = 0; i < TSYS01_PROM_WORDS_NB; i++) {
+ ret = dev_data->read_prom_word(dev_data->client,
+ TSYS01_PROM_READ + (i << 1),
+ &dev_data->prom[i]);
+ if (ret)
+ return ret;
+
+ ret = sprintf(ptr, "0x%04x ", dev_data->prom[i]);
+ ptr += ret;
+ }
+
+ if (!tsys01_crc_valid(dev_data->prom)) {
+ dev_err(&indio_dev->dev, "prom crc check error\n");
+ return -ENODEV;
+ }
+ *ptr = 0;
+ dev_info(&indio_dev->dev, "PROM coefficients : %s\n", buf);
+
+ return 0;
+}
+
+static int tsys01_probe(struct iio_dev *indio_dev, struct device *dev)
+{
+ int ret;
+ struct tsys01_dev *dev_data = iio_priv(indio_dev);
+
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &tsys01_info;
+ indio_dev->name = dev->driver->name;
+ indio_dev->dev.parent = dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = tsys01_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsys01_channels);
+
+ ret = dev_data->reset(dev_data->client, TSYS01_RESET, 3000);
+ if (ret)
+ return ret;
+
+ ret = tsys01_read_prom(indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int tsys01_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tsys01_dev *dev_data;
+ struct iio_dev *indio_dev;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->reset = ms_sensors_reset;
+ dev_data->read_prom_word = ms_sensors_read_prom_word;
+ dev_data->convert_and_read = ms_sensors_convert_and_read;
+
+ i2c_set_clientdata(client, indio_dev);
+
+ return tsys01_probe(indio_dev, &client->dev);
+}
+
+static const struct i2c_device_id tsys01_id[] = {
+ {"tsys01", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tsys01_id);
+
+static struct i2c_driver tsys01_driver = {
+ .probe = tsys01_i2c_probe,
+ .id_table = tsys01_id,
+ .driver = {
+ .name = "tsys01",
+ },
+};
+
+module_i2c_driver(tsys01_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys01 temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/temperature/tsys02d.c b/drivers/iio/temperature/tsys02d.c
new file mode 100644
index 0000000..4c1fbd5
--- /dev/null
+++ b/drivers/iio/temperature/tsys02d.c
@@ -0,0 +1,191 @@
+/*
+ * tsys02d.c - Support for Measurement-Specialties tsys02d temperature sensor
+ *
+ * Copyright (c) 2015 Measurement-Specialties
+ *
+ * Licensed under the GPL-2.
+ *
+ * (7-bit I2C slave address 0x40)
+ *
+ * Datasheet:
+ * http://www.meas-spec.com/downloads/Digital_Sensor_TSYS02D.pdf
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "../common/ms_sensors/ms_sensors_i2c.h"
+
+#define TSYS02D_RESET 0xFE
+
+static const int tsys02d_samp_freq[4] = { 20, 40, 70, 140 };
+/* String copy of the above const for readability purpose */
+static const char tsys02d_show_samp_freq[] = "20 40 70 140";
+
+static int tsys02d_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ s32 temperature;
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->type) {
+ case IIO_TEMP: /* in milli °C */
+ ret = ms_sensors_ht_read_temperature(dev_data,
+ &temperature);
+ if (ret)
+ return ret;
+ *val = temperature;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = tsys02d_samp_freq[dev_data->res_index];
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tsys02d_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+ int i, ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ i = ARRAY_SIZE(tsys02d_samp_freq);
+ while (i-- > 0)
+ if (val == tsys02d_samp_freq[i])
+ break;
+ if (i < 0)
+ return -EINVAL;
+ mutex_lock(&dev_data->lock);
+ dev_data->res_index = i;
+ ret = ms_sensors_write_resolution(dev_data, i);
+ mutex_unlock(&dev_data->lock);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec tsys02d_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static ssize_t tsys02_read_battery_low(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ms_ht_dev *dev_data = iio_priv(indio_dev);
+
+ return ms_sensors_show_battery_low(dev_data, buf);
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(tsys02d_show_samp_freq);
+static IIO_DEVICE_ATTR(battery_low, S_IRUGO,
+ tsys02_read_battery_low, NULL, 0);
+
+static struct attribute *tsys02d_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_battery_low.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group tsys02d_attribute_group = {
+ .attrs = tsys02d_attributes,
+};
+
+static const struct iio_info tsys02d_info = {
+ .read_raw = tsys02d_read_raw,
+ .write_raw = tsys02d_write_raw,
+ .attrs = &tsys02d_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int tsys02d_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ms_ht_dev *dev_data;
+ struct iio_dev *indio_dev;
+ int ret;
+ u64 serial_number;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+ dev_err(&client->dev,
+ "Adapter does not support some i2c transaction\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_data = iio_priv(indio_dev);
+ dev_data->client = client;
+ dev_data->res_index = 0;
+ mutex_init(&dev_data->lock);
+
+ indio_dev->info = &tsys02d_info;
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = tsys02d_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tsys02d_channels);
+
+ i2c_set_clientdata(client, indio_dev);
+
+ ret = ms_sensors_reset(client, TSYS02D_RESET, 15000);
+ if (ret)
+ return ret;
+
+ ret = ms_sensors_read_serial(client, &serial_number);
+ if (ret)
+ return ret;
+ dev_info(&client->dev, "Serial number : %llx", serial_number);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id tsys02d_id[] = {
+ {"tsys02d", 0},
+ {}
+};
+
+static struct i2c_driver tsys02d_driver = {
+ .probe = tsys02d_probe,
+ .id_table = tsys02d_id,
+ .driver = {
+ .name = "tsys02d",
+ },
+};
+
+module_i2c_driver(tsys02d_driver);
+
+MODULE_DESCRIPTION("Measurement-Specialties tsys02d temperature driver");
+MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
+MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 028b4e8..6cd15e6 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -68,12 +68,12 @@
#define AD7746_VTSETUP_VTCHOP (1 << 0)
/* Excitation Setup Register Bit Designations (AD7746_REG_EXC_SETUP) */
-#define AD7746_EXCSETUP_CLKCTRL (1 << 7)
-#define AD7746_EXCSETUP_EXCON (1 << 6)
-#define AD7746_EXCSETUP_EXCB (1 << 5)
-#define AD7746_EXCSETUP_NEXCB (1 << 4)
-#define AD7746_EXCSETUP_EXCA (1 << 3)
-#define AD7746_EXCSETUP_NEXCA (1 << 2)
+#define AD7746_EXCSETUP_CLKCTRL BIT(7)
+#define AD7746_EXCSETUP_EXCON BIT(6)
+#define AD7746_EXCSETUP_EXCB BIT(5)
+#define AD7746_EXCSETUP_NEXCB BIT(4)
+#define AD7746_EXCSETUP_EXCA BIT(3)
+#define AD7746_EXCSETUP_NEXCA BIT(2)
#define AD7746_EXCSETUP_EXCLVL(x) (((x) & 0x3) << 0)
/* Config Register Bit Designations (AD7746_REG_CFG) */
@@ -528,7 +528,8 @@ static int ad7746_write_raw(struct iio_dev *indio_dev,
goto out;
}
- /* CAPDAC Scale = 21pF_typ / 127
+ /*
+ * CAPDAC Scale = 21pF_typ / 127
* CIN Scale = 8.192pF / 2^24
* Offset Scale = CAPDAC Scale / CIN Scale = 338646
*/
@@ -600,7 +601,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
switch (chan->type) {
case IIO_TEMP:
- /* temperature in milli degrees Celsius
+ /*
+ * temperature in milli degrees Celsius
* T = ((*val / 2048) - 4096) * 1000
*/
*val = (*val * 125) / 256;
@@ -753,8 +755,6 @@ static int ad7746_probe(struct i2c_client *client,
if (ret)
return ret;
- dev_info(&client->dev, "%s capacitive sensor registered\n", id->name);
-
return 0;
}
OpenPOWER on IntegriCloud