diff options
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 = ®_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; } |