From 22b46c45fb9be8ec1fcb4d9b74810e6a20ff67cc Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2014 22:57:00 +0100 Subject: [PATCH 01/35] iio:gyro:bmg160 Gyro Sensor driver This change implements support for BMG160 Gyro sensor. Although chip has several advanced features, this change implements minimum set required for using gyro sensor. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/Kconfig | 11 + drivers/iio/gyro/Makefile | 1 + drivers/iio/gyro/bmg160.c | 1211 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1223 insertions(+) create mode 100644 drivers/iio/gyro/bmg160.c diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index ac2d69e34c8c..d630ae987d0b 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -50,6 +50,17 @@ config ADXRS450 This driver can also be built as a module. If so, the module will be called adxrs450. +config BMG160 + tristate "BOSCH BMG160 Gyro Sensor" + depends on I2C + select IIO_TRIGGERED_BUFFER if IIO_BUFFER + help + Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor + driver. + + This driver can also be built as a module. If so, the module + will be called bmg160. + config HID_SENSOR_GYRO_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile index 2f2752a4ea83..36a38776f739 100644 --- a/drivers/iio/gyro/Makefile +++ b/drivers/iio/gyro/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ADIS16130) += adis16130.o obj-$(CONFIG_ADIS16136) += adis16136.o obj-$(CONFIG_ADIS16260) += adis16260.o obj-$(CONFIG_ADXRS450) += adxrs450.o +obj-$(CONFIG_BMG160) += bmg160.o obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c new file mode 100644 index 000000000000..80f92a65e020 --- /dev/null +++ b/drivers/iio/gyro/bmg160.c @@ -0,0 +1,1211 @@ +/* + * BMG160 Gyro Sensor driver + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BMG160_DRV_NAME "bmg160" +#define BMG160_IRQ_NAME "bmg160_event" +#define BMG160_GPIO_NAME "gpio_int" + +#define BMG160_REG_CHIP_ID 0x00 +#define BMG160_CHIP_ID_VAL 0x0F + +#define BMG160_REG_PMU_LPW 0x11 +#define BMG160_MODE_NORMAL 0x00 +#define BMG160_MODE_DEEP_SUSPEND 0x20 +#define BMG160_MODE_SUSPEND 0x80 + +#define BMG160_REG_RANGE 0x0F + +#define BMG160_RANGE_2000DPS 0 +#define BMG160_RANGE_1000DPS 1 +#define BMG160_RANGE_500DPS 2 +#define BMG160_RANGE_250DPS 3 +#define BMG160_RANGE_125DPS 4 + +#define BMG160_REG_PMU_BW 0x10 +#define BMG160_NO_FILTER 0 +#define BMG160_DEF_BW 100 + +#define BMG160_REG_INT_MAP_0 0x17 +#define BMG160_INT_MAP_0_BIT_ANY BIT(1) + +#define BMG160_REG_INT_MAP_1 0x18 +#define BMG160_INT_MAP_1_BIT_NEW_DATA BIT(0) + +#define BMG160_REG_INT_RST_LATCH 0x21 +#define BMG160_INT_MODE_LATCH_RESET 0x80 +#define BMG160_INT_MODE_LATCH_INT 0x0F +#define BMG160_INT_MODE_NON_LATCH_INT 0x00 + +#define BMG160_REG_INT_EN_0 0x15 +#define BMG160_DATA_ENABLE_INT BIT(7) + +#define BMG160_REG_XOUT_L 0x02 +#define BMG160_AXIS_TO_REG(axis) (BMG160_REG_XOUT_L + (axis * 2)) + +#define BMG160_REG_SLOPE_THRES 0x1B +#define BMG160_SLOPE_THRES_MASK 0x0F + +#define BMG160_REG_MOTION_INTR 0x1C +#define BMG160_INT_MOTION_X BIT(0) +#define BMG160_INT_MOTION_Y BIT(1) +#define BMG160_INT_MOTION_Z BIT(2) +#define BMG160_ANY_DUR_MASK 0x30 +#define BMG160_ANY_DUR_SHIFT 4 + +#define BMG160_REG_INT_STATUS_2 0x0B +#define BMG160_ANY_MOTION_MASK 0x07 + +#define BMG160_REG_TEMP 0x08 +#define BMG160_TEMP_CENTER_VAL 23 + +#define BMG160_MAX_STARTUP_TIME_MS 80 + +#define BMG160_AUTO_SUSPEND_DELAY_MS 2000 + +struct bmg160_data { + struct i2c_client *client; + struct iio_trigger *dready_trig; + struct iio_trigger *motion_trig; + struct mutex mutex; + s16 buffer[8]; + u8 bw_bits; + u32 dps_range; + int ev_enable_state; + int slope_thres; + bool dready_trigger_on; + bool motion_trigger_on; + int64_t timestamp; +}; + +enum bmg160_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +static const struct { + int val; + int bw_bits; +} bmg160_samp_freq_table[] = { {100, 0x07}, + {200, 0x06}, + {400, 0x03}, + {1000, 0x02}, + {2000, 0x01} }; + +static const struct { + int scale; + int dps_range; +} bmg160_scale_table[] = { { 1065, BMG160_RANGE_2000DPS}, + { 532, BMG160_RANGE_1000DPS}, + { 266, BMG160_RANGE_500DPS}, + { 133, BMG160_RANGE_250DPS}, + { 66, BMG160_RANGE_125DPS} }; + +static int bmg160_set_mode(struct bmg160_data *data, u8 mode) +{ + int ret; + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_PMU_LPW, mode); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); + return ret; + } + + return 0; +} + +static int bmg160_convert_freq_to_bit(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { + if (bmg160_samp_freq_table[i].val == val) + return bmg160_samp_freq_table[i].bw_bits; + } + + return -EINVAL; +} + +static int bmg160_set_bw(struct bmg160_data *data, int val) +{ + int ret; + int bw_bits; + + bw_bits = bmg160_convert_freq_to_bit(val); + if (bw_bits < 0) + return bw_bits; + + ret = i2c_smbus_write_byte_data(data->client, BMG160_REG_PMU_BW, + bw_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_bw\n"); + return ret; + } + + data->bw_bits = bw_bits; + + return 0; +} + +static int bmg160_chip_init(struct bmg160_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_chip_id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != BMG160_CHIP_ID_VAL) { + dev_err(&data->client->dev, "invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmg160_set_mode(data, BMG160_MODE_NORMAL); + if (ret < 0) + return ret; + + /* Wait upto 500 ms to be ready after changing mode */ + usleep_range(500, 1000); + + /* Set Bandwidth */ + ret = bmg160_set_bw(data, BMG160_DEF_BW); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_RANGE, + BMG160_RANGE_500DPS); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_range\n"); + return ret; + } + data->dps_range = BMG160_RANGE_500DPS; + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_SLOPE_THRES); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_slope_thres\n"); + return ret; + } + data->slope_thres = ret; + + /* Set default interrupt mode */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_motion_intr\n"); + return ret; + } + + return 0; +} + +static int bmg160_set_power_state(struct bmg160_data *data, bool on) +{ + int ret; + + if (on) + ret = pm_runtime_get_sync(&data->client->dev); + else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + + if (ret < 0) { + dev_err(&data->client->dev, + "Failed: bmg160_set_power_state for %d\n", on); + return ret; + } + + return 0; +} + +static int bmg160_setup_any_motion_interrupt(struct bmg160_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT_MAP0 mapping */ + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_0); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map0\n"); + return ret; + } + if (status) + ret |= BMG160_INT_MAP_0_BIT_ANY; + else + ret &= ~BMG160_INT_MAP_0_BIT_ANY; + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_MAP_0, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map0\n"); + return ret; + } + + /* Enable/Disable slope interrupts */ + if (status) { + /* Update slope thres */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_SLOPE_THRES, + data->slope_thres); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_slope_thres\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_MOTION_INTR, + BMG160_INT_MOTION_X | + BMG160_INT_MOTION_Y | + BMG160_INT_MOTION_Z); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_motion_intr\n"); + return ret; + } + + /* + * New data interrupt is always non-latched, + * which will have higher priority, so no need + * to set latched mode, we will be flooded anyway with INTR + */ + if (!data->dready_trigger_on) { + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_rst_latch\n"); + return ret; + } + } + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_EN_0, + BMG160_DATA_ENABLE_INT); + + } else + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_EN_0, + 0); + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en0\n"); + return ret; + } + + return 0; +} + +static int bmg160_setup_new_data_interrupt(struct bmg160_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT_MAP1 mapping */ + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_MAP_1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map1\n"); + return ret; + } + + if (status) + ret |= BMG160_INT_MAP_1_BIT_NEW_DATA; + else + ret &= ~BMG160_INT_MAP_1_BIT_NEW_DATA; + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_MAP_1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map1\n"); + return ret; + } + + if (status) { + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_NON_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_EN_0, + BMG160_DATA_ENABLE_INT); + + } else { + /* Restore interrupt mode */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_EN_0, + 0); + } + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en0\n"); + return ret; + } + + return 0; +} + +static int bmg160_get_bw(struct bmg160_data *data, int *val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { + if (bmg160_samp_freq_table[i].bw_bits == data->bw_bits) { + *val = bmg160_samp_freq_table[i].val; + return IIO_VAL_INT; + } + } + + return -EINVAL; +} + +static int bmg160_set_scale(struct bmg160_data *data, int val) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) { + if (bmg160_scale_table[i].scale == val) { + ret = i2c_smbus_write_byte_data( + data->client, + BMG160_REG_RANGE, + bmg160_scale_table[i].dps_range); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_range\n"); + return ret; + } + data->dps_range = bmg160_scale_table[i].dps_range; + return 0; + } + } + + return -EINVAL; +} + +static int bmg160_get_temp(struct bmg160_data *data, int *val) +{ + int ret; + + mutex_lock(&data->mutex); + ret = bmg160_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_TEMP); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_temp\n"); + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + + *val = sign_extend32(ret, 7); + ret = bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + return IIO_VAL_INT; +} + +static int bmg160_get_axis(struct bmg160_data *data, int axis, int *val) +{ + int ret; + + mutex_lock(&data->mutex); + ret = bmg160_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = i2c_smbus_read_word_data(data->client, BMG160_AXIS_TO_REG(axis)); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading axis %d\n", axis); + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + + *val = sign_extend32(ret, 15); + ret = bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + return IIO_VAL_INT; +} + +static int bmg160_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + return bmg160_get_temp(data, val); + case IIO_ANGL_VEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + else + return bmg160_get_axis(data, chan->scan_index, + val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = BMG160_TEMP_CENTER_VAL; + return IIO_VAL_INT; + } else + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + *val = 0; + switch (chan->type) { + case IIO_TEMP: + *val2 = 500000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ANGL_VEL: + { + int i; + + for (i = 0; i < ARRAY_SIZE(bmg160_scale_table); ++i) { + if (bmg160_scale_table[i].dps_range == + data->dps_range) { + *val2 = bmg160_scale_table[i].scale; + return IIO_VAL_INT_PLUS_MICRO; + } + } + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + *val2 = 0; + mutex_lock(&data->mutex); + ret = bmg160_get_bw(data, val); + mutex_unlock(&data->mutex); + return ret; + default: + return -EINVAL; + } +} + +static int bmg160_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + /* + * Section 4.2 of spec + * In suspend mode, the only supported operations are reading + * registers as well as writing to the (0x14) softreset + * register. Since we will be in suspend mode by default, change + * mode to power on for other writes. + */ + ret = bmg160_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_bw(data, val); + if (ret < 0) { + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + /* Refer to comments above for the suspend mode ops */ + ret = bmg160_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_scale(data, val2); + if (ret < 0) { + bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + ret = bmg160_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int bmg160_read_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct bmg160_data *data = iio_priv(indio_dev); + + *val2 = 0; + switch (info) { + case IIO_EV_INFO_VALUE: + *val = data->slope_thres & BMG160_SLOPE_THRES_MASK; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int bmg160_write_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct bmg160_data *data = iio_priv(indio_dev); + + switch (info) { + case IIO_EV_INFO_VALUE: + if (data->ev_enable_state) + return -EBUSY; + data->slope_thres &= ~BMG160_SLOPE_THRES_MASK; + data->slope_thres |= (val & BMG160_SLOPE_THRES_MASK); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bmg160_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + + struct bmg160_data *data = iio_priv(indio_dev); + + return data->ev_enable_state; +} + +static int bmg160_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + if (state && data->ev_enable_state) + return 0; + + mutex_lock(&data->mutex); + + if (!state && data->motion_trigger_on) { + data->ev_enable_state = 0; + mutex_unlock(&data->mutex); + return 0; + } + /* + * We will expect the enable and disable to do operation in + * in reverse order. This will happen here anyway as our + * resume operation uses sync mode runtime pm calls, the + * suspend operation will be delayed by autosuspend delay + * So the disable operation will still happen in reverse of + * enable operation. When runtime pm is disabled the mode + * is always on so sequence doesn't matter + */ + ret = bmg160_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = bmg160_setup_any_motion_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + data->ev_enable_state = state; + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmg160_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct bmg160_data *data = iio_priv(indio_dev); + + if (data->dready_trig != trig && data->motion_trig != trig) + return -EINVAL; + + return 0; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000"); + +static IIO_CONST_ATTR(in_anglvel_scale_available, + "0.001065 0.000532 0.000266 0.000133 0.000066"); + +static struct attribute *bmg160_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_anglvel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmg160_attrs_group = { + .attrs = bmg160_attributes, +}; + +static const struct iio_event_spec bmg160_event = { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING, + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) +}; + +#define BMG160_CHANNEL(_axis) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ + .event_spec = &bmg160_event, \ + .num_event_specs = 1 \ +} + +static const struct iio_chan_spec bmg160_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = -1, + }, + BMG160_CHANNEL(X), + BMG160_CHANNEL(Y), + BMG160_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_info bmg160_info = { + .attrs = &bmg160_attrs_group, + .read_raw = bmg160_read_raw, + .write_raw = bmg160_write_raw, + .read_event_value = bmg160_read_event, + .write_event_value = bmg160_write_event, + .write_event_config = bmg160_write_event_config, + .read_event_config = bmg160_read_event_config, + .validate_trigger = bmg160_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t bmg160_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmg160_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + for_each_set_bit(bit, indio_dev->buffer->scan_mask, + indio_dev->masklength) { + ret = i2c_smbus_read_word_data(data->client, + BMG160_AXIS_TO_REG(bit)); + if (ret < 0) { + mutex_unlock(&data->mutex); + goto err; + } + data->buffer[i++] = ret; + } + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + data->timestamp); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int bmg160_trig_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + /* new data interrupts don't need ack */ + if (data->dready_trigger_on) + return 0; + + /* Set latched mode interrupt and clear any latched interrupt */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmg160_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + + if (!state && data->ev_enable_state && data->motion_trigger_on) { + data->motion_trigger_on = false; + mutex_unlock(&data->mutex); + return 0; + } + + /* + * Refer to comment in bmg160_write_event_config for + * enable/disable operation order + */ + ret = bmg160_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + ret = bmg160_setup_any_motion_interrupt(data, state); + else + ret = bmg160_setup_new_data_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + data->motion_trigger_on = state; + else + data->dready_trigger_on = state; + + mutex_unlock(&data->mutex); + + return 0; +} + +static const struct iio_trigger_ops bmg160_trigger_ops = { + .set_trigger_state = bmg160_data_rdy_trigger_set_state, + .try_reenable = bmg160_trig_try_reen, + .owner = THIS_MODULE, +}; + +static irqreturn_t bmg160_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + int dir; + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_STATUS_2); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_status2\n"); + goto ack_intr_status; + } + + if (ret & 0x08) + dir = IIO_EV_DIR_RISING; + else + dir = IIO_EV_DIR_FALLING; + + if (ret & BMG160_ANY_MOTION_MASK) + iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, + 0, + IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + +ack_intr_status: + if (!data->dready_trigger_on) { + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) + dev_err(&data->client->dev, + "Error writing reg_rst_latch\n"); + } + + return IRQ_HANDLED; +} + +static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmg160_data *data = iio_priv(indio_dev); + + data->timestamp = iio_get_time_ns(); + + if (data->dready_trigger_on) + iio_trigger_poll(data->dready_trig); + else if (data->motion_trigger_on) + iio_trigger_poll(data->motion_trig); + + if (data->ev_enable_state) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; + +} + +static int bmg160_acpi_gpio_probe(struct i2c_client *client, + struct bmg160_data *data) +{ + const struct acpi_device_id *id; + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + if (!ACPI_HANDLE(dev)) + return -ENODEV; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0); + if (IS_ERR(gpio)) { + dev_err(dev, "acpi gpio get index failed\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_direction_input(gpio); + if (ret) + return ret; + + ret = gpiod_to_irq(gpio); + + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + +static int bmg160_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bmg160_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + ret = bmg160_chip_init(data); + if (ret < 0) + return ret; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = bmg160_channels; + indio_dev->num_channels = ARRAY_SIZE(bmg160_channels); + indio_dev->name = BMG160_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmg160_info; + + if (client->irq <= 0) + client->irq = bmg160_acpi_gpio_probe(client, data); + + if (client->irq > 0) { + ret = devm_request_threaded_irq(&client->dev, + client->irq, + bmg160_data_rdy_trig_poll, + bmg160_event_handler, + IRQF_TRIGGER_RISING, + BMG160_IRQ_NAME, + indio_dev); + if (ret) + return ret; + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) + return -ENOMEM; + + data->motion_trig = devm_iio_trigger_alloc(&client->dev, + "%s-any-motion-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->motion_trig) + return -ENOMEM; + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &bmg160_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + ret = iio_trigger_register(data->dready_trig); + if (ret) + return ret; + + data->motion_trig->dev.parent = &client->dev; + data->motion_trig->ops = &bmg160_trigger_ops; + iio_trigger_set_drvdata(data->motion_trig, indio_dev); + ret = iio_trigger_register(data->motion_trig); + if (ret) { + data->motion_trig = NULL; + goto err_trigger_unregister; + } + + ret = iio_triggered_buffer_setup(indio_dev, + NULL, + bmg160_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "iio triggered buffer setup failed\n"); + goto err_trigger_unregister; + } + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "unable to register iio device\n"); + goto err_buffer_cleanup; + } + + ret = pm_runtime_set_active(&client->dev); + if (ret) + goto err_iio_unregister; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + BMG160_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return 0; + +err_iio_unregister: + iio_device_unregister(indio_dev); +err_buffer_cleanup: + if (data->dready_trig) + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + if (data->motion_trig) + iio_trigger_unregister(data->motion_trig); + + return ret; +} + +static int bmg160_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bmg160_data *data = iio_priv(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + iio_device_unregister(indio_dev); + + if (data->dready_trig) { + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->dready_trig); + iio_trigger_unregister(data->motion_trig); + } + + mutex_lock(&data->mutex); + bmg160_set_mode(data, BMG160_MODE_DEEP_SUSPEND); + mutex_unlock(&data->mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bmg160_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmg160_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + bmg160_set_mode(data, BMG160_MODE_SUSPEND); + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmg160_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmg160_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) + bmg160_set_mode(data, BMG160_MODE_NORMAL); + mutex_unlock(&data->mutex); + + return 0; +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int bmg160_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmg160_data *data = iio_priv(indio_dev); + + return bmg160_set_mode(data, BMG160_MODE_SUSPEND); +} + +static int bmg160_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmg160_data *data = iio_priv(indio_dev); + int ret; + + ret = bmg160_set_mode(data, BMG160_MODE_NORMAL); + if (ret < 0) + return ret; + + msleep_interruptible(BMG160_MAX_STARTUP_TIME_MS); + + return 0; +} +#endif + +static const struct dev_pm_ops bmg160_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bmg160_suspend, bmg160_resume) + SET_RUNTIME_PM_OPS(bmg160_runtime_suspend, + bmg160_runtime_resume, NULL) +}; + +static const struct acpi_device_id bmg160_acpi_match[] = { + {"BMG0160", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); + +static const struct i2c_device_id bmg160_id[] = { + {"bmg160", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmg160_id); + +static struct i2c_driver bmg160_driver = { + .driver = { + .name = BMG160_DRV_NAME, + .acpi_match_table = ACPI_PTR(bmg160_acpi_match), + .pm = &bmg160_pm_ops, + }, + .probe = bmg160_probe, + .remove = bmg160_remove, + .id_table = bmg160_id, +}; +module_i2c_driver(bmg160_driver); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMG160 Gyro driver"); From ca45d02db82867cf703af5253474689a37f36ca0 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 8 May 2014 22:57:00 +0100 Subject: [PATCH 02/35] iio:gyro:bmg160 documentation Added any-motion trigger documentation. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 b/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 new file mode 100644 index 000000000000..e98209c9155e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 @@ -0,0 +1,7 @@ +What: /sys/bus/iio/devices/triggerX/name = "bmg160-any-motion-devX" +KernelVersion: 3.17 +Contact: linux-iio@vger.kernel.org +Description: + The BMG160 gyro kernel module provides an additional trigger, + which sets driver in a mode, where data is pushed to the buffer + only when there is any motion. From b5faca4b59ab604cd3ff367683a96c330b78d25f Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Fri, 22 Aug 2014 08:35:00 +0100 Subject: [PATCH 03/35] io: accel: kxcjk1013: Remove redundant assignment data->range is already set by kxcjk1013_set_range. Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 57c515bf0fd2..ae7429385f92 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -239,9 +239,6 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - data->range = KXCJK1013_RANGE_4G; - - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); From b4b491c0832ef90a7a5070e5975bc8427f2049ca Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 22 Aug 2014 20:01:00 +0100 Subject: [PATCH 04/35] iio: accel: kxcjk-1013: Support thresholds This chip has a motion detect capability. Using IIO events to specify thresholds and pushing events. In addition a new trigger of type any-motion is added, which pushes data to buffer only when there is any movement. Change list: Comments addressed for Re: [PATCH 5/6] iio: accel: kxcjk-1013: Support thresholds Date: 07/20/2014 - Both motion detect and data ready can be enabled together - Sending RISING/FALLING events based on int status - Separate interrupt configuration for data ready and motion detect Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 499 +++++++++++++++++++++++++++++---- 1 file changed, 448 insertions(+), 51 deletions(-) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index ae7429385f92..647a4cfb2ae7 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -75,16 +76,30 @@ #define KXCJK1013_SLEEP_DELAY_MS 2000 +#define KXCJK1013_REG_INT_SRC2_BIT_ZP BIT(0) +#define KXCJK1013_REG_INT_SRC2_BIT_ZN BIT(1) +#define KXCJK1013_REG_INT_SRC2_BIT_YP BIT(2) +#define KXCJK1013_REG_INT_SRC2_BIT_YN BIT(3) +#define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4) +#define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5) + +#define KXCJK1013_DEFAULT_WAKE_THRES 1 + struct kxcjk1013_data { struct i2c_client *client; - struct iio_trigger *trig; - bool trig_mode; + struct iio_trigger *dready_trig; + struct iio_trigger *motion_trig; struct mutex mutex; s16 buffer[8]; u8 odr_bits; u8 range; + int wake_thres; + int wake_dur; bool active_high_intr; - bool trigger_on; + bool dready_trigger_on; + int ev_enable_state; + bool motion_trigger_on; + int64_t timestamp; }; enum kxcjk1013_axis { @@ -131,6 +146,23 @@ static const struct { {19163, 1, 0}, {38326, 0, 1} }; +static const struct { + int val; + int val2; + int odr_bits; +} wake_odr_data_rate_table[] = { {0, 781000, 0x00}, + {1, 563000, 0x01}, + {3, 125000, 0x02}, + {6, 250000, 0x03}, + {12, 500000, 0x04}, + {25, 0, 0x05}, + {50, 0, 0x06}, + {100, 0, 0x06}, + {200, 0, 0x06}, + {400, 0, 0x06}, + {800, 0, 0x06}, + {1600, 0, 0x06} }; + static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { @@ -270,6 +302,8 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; + data->wake_thres = KXCJK1013_DEFAULT_WAKE_THRES; + return 0; } @@ -304,8 +338,96 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) return 0; } -static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, - bool status) +static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_WAKE_TIMER, + data->wake_dur); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_wake_timer\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_WAKE_THRES, + data->wake_thres); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_wake_thres\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, + bool status) +{ + int ret; + enum kxcjk1013_mode store_mode; + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; + + /* This is requirement by spec to change state to STANDBY */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = kxcjk1013_chip_update_thresholds(data); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEN; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; +} + +static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, + bool status) { int ret; enum kxcjk1013_mode store_mode; @@ -378,6 +500,20 @@ static int kxcjk1013_convert_freq_to_bit(int val, int val2) return -EINVAL; } +static int kxcjk1013_convert_wake_odr_to_bit(int val, int val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wake_odr_data_rate_table); ++i) { + if (wake_odr_data_rate_table[i].val == val && + wake_odr_data_rate_table[i].val2 == val2) { + return wake_odr_data_rate_table[i].odr_bits; + } + } + + return -EINVAL; +} + static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) { int ret; @@ -406,6 +542,17 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_bits; + odr_bits = kxcjk1013_convert_wake_odr_to_bit(val, val2); + if (odr_bits < 0) + return odr_bits; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2, + odr_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl2\n"); + return ret; + } + if (store_mode == OPERATION) { ret = kxcjk1013_set_mode(data, OPERATION); if (ret < 0) @@ -557,12 +704,120 @@ static int kxcjk1013_write_raw(struct iio_dev *indio_dev, return ret; } +static int kxcjk1013_read_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + + *val2 = 0; + switch (info) { + case IIO_EV_INFO_VALUE: + *val = data->wake_thres; + break; + case IIO_EV_INFO_PERIOD: + *val = data->wake_dur; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int kxcjk1013_write_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + + if (data->ev_enable_state) + return -EBUSY; + + switch (info) { + case IIO_EV_INFO_VALUE: + data->wake_thres = val; + break; + case IIO_EV_INFO_PERIOD: + data->wake_dur = val; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int kxcjk1013_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + + struct kxcjk1013_data *data = iio_priv(indio_dev); + + return data->ev_enable_state; +} + +static int kxcjk1013_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + if (state && data->ev_enable_state) + return 0; + + mutex_lock(&data->mutex); + + if (!state && data->motion_trigger_on) { + data->ev_enable_state = 0; + mutex_unlock(&data->mutex); + return 0; + } + + /* + * We will expect the enable and disable to do operation in + * in reverse order. This will happen here anyway as our + * resume operation uses sync mode runtime pm calls, the + * suspend operation will be delayed by autosuspend delay + * So the disable operation will still happen in reverse of + * enable operation. When runtime pm is disabled the mode + * is always on so sequence doesn't matter + */ + ret = kxcjk1013_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = kxcjk1013_setup_any_motion_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + data->ev_enable_state = state; + mutex_unlock(&data->mutex); + + return 0; +} + static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) { struct kxcjk1013_data *data = iio_priv(indio_dev); - if (data->trig != trig) + if (data->dready_trig != trig && data->motion_trig != trig) return -EINVAL; return 0; @@ -583,6 +838,14 @@ static const struct attribute_group kxcjk1013_attrs_group = { .attrs = kxcjk1013_attributes, }; +static const struct iio_event_spec kxcjk1013_event = { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) +}; + #define KXCJK1013_CHANNEL(_axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ @@ -598,6 +861,8 @@ static const struct attribute_group kxcjk1013_attrs_group = { .shift = 4, \ .endianness = IIO_CPU, \ }, \ + .event_spec = &kxcjk1013_event, \ + .num_event_specs = 1 \ } static const struct iio_chan_spec kxcjk1013_channels[] = { @@ -611,6 +876,10 @@ static const struct iio_info kxcjk1013_info = { .attrs = &kxcjk1013_attrs_group, .read_raw = kxcjk1013_read_raw, .write_raw = kxcjk1013_write_raw, + .read_event_value = kxcjk1013_read_event, + .write_event_value = kxcjk1013_write_event, + .write_event_config = kxcjk1013_write_event_config, + .read_event_config = kxcjk1013_read_event_config, .validate_trigger = kxcjk1013_validate_trigger, .driver_module = THIS_MODULE, }; @@ -636,7 +905,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) mutex_unlock(&data->mutex); iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - pf->timestamp); + data->timestamp); err: iio_trigger_notify_done(indio_dev->trig); @@ -665,19 +934,32 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; - if (state && data->trigger_on) - return 0; - mutex_lock(&data->mutex); - ret = kxcjk1013_chip_setup_interrupt(data, state); - if (!ret) { - ret = kxcjk1013_set_power_state(data, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } + + if (!state && data->ev_enable_state && data->motion_trigger_on) { + data->motion_trigger_on = false; + mutex_unlock(&data->mutex); + return 0; } - data->trigger_on = state; + + ret = kxcjk1013_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + ret = kxcjk1013_setup_any_motion_interrupt(data, state); + else + ret = kxcjk1013_setup_new_data_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + data->motion_trigger_on = state; + else + data->dready_trigger_on = state; + mutex_unlock(&data->mutex); return 0; @@ -689,6 +971,109 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = { .owner = THIS_MODULE, }; +static irqreturn_t kxcjk1013_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_src1\n"); + goto ack_intr; + } + + if (ret & 0x02) { + ret = i2c_smbus_read_byte_data(data->client, + KXCJK1013_REG_INT_SRC2); + if (ret < 0) { + dev_err(&data->client->dev, + "Error reading reg_int_src2\n"); + goto ack_intr; + } + + if (ret & KXCJK1013_REG_INT_SRC2_BIT_XN) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + data->timestamp); + if (ret & KXCJK1013_REG_INT_SRC2_BIT_XP) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + data->timestamp); + + + if (ret & KXCJK1013_REG_INT_SRC2_BIT_YN) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + data->timestamp); + if (ret & KXCJK1013_REG_INT_SRC2_BIT_YP) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + data->timestamp); + + if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZN) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + data->timestamp); + if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZP) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + data->timestamp); + } + +ack_intr: + if (data->dready_trigger_on) + return IRQ_HANDLED; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL); + if (ret < 0) + dev_err(&data->client->dev, "Error reading reg_int_rel\n"); + + return IRQ_HANDLED; +} + +static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct kxcjk1013_data *data = iio_priv(indio_dev); + + data->timestamp = iio_get_time_ns(); + + if (data->dready_trigger_on) + iio_trigger_poll(data->dready_trig); + else if (data->motion_trigger_on) + iio_trigger_poll(data->motion_trig); + + if (data->ev_enable_state) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; +} + static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, struct kxcjk1013_data *data) { @@ -731,7 +1116,6 @@ static int kxcjk1013_probe(struct i2c_client *client, { struct kxcjk1013_data *data; struct iio_dev *indio_dev; - struct iio_trigger *trig = NULL; struct kxcjk_1013_platform_data *pdata; int ret; @@ -766,33 +1150,46 @@ static int kxcjk1013_probe(struct i2c_client *client, client->irq = kxcjk1013_acpi_gpio_probe(client, data); if (client->irq >= 0) { - trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); - if (!trig) + ret = devm_request_threaded_irq(&client->dev, client->irq, + kxcjk1013_data_rdy_trig_poll, + kxcjk1013_event_handler, + IRQF_TRIGGER_RISING, + KXCJK1013_IRQ_NAME, + indio_dev); + if (ret) + return ret; + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) return -ENOMEM; - data->trig_mode = true; + data->motion_trig = devm_iio_trigger_alloc(&client->dev, + "%s-any-motion-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->motion_trig) + return -ENOMEM; - ret = devm_request_irq(&client->dev, client->irq, - iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - KXCJK1013_IRQ_NAME, - trig); - if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - goto err_trigger_free; - } - - trig->dev.parent = &client->dev; - trig->ops = &kxcjk1013_trigger_ops; - iio_trigger_set_drvdata(trig, indio_dev); - data->trig = trig; - indio_dev->trig = trig; + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + indio_dev->trig = data->dready_trig; iio_trigger_get(indio_dev->trig); - - ret = iio_trigger_register(trig); + ret = iio_trigger_register(data->dready_trig); if (ret) - goto err_trigger_free; + return ret; + + data->motion_trig->dev.parent = &client->dev; + data->motion_trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(data->motion_trig, indio_dev); + ret = iio_trigger_register(data->motion_trig); + if (ret) { + data->motion_trig = NULL; + goto err_trigger_unregister; + } ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, @@ -825,14 +1222,13 @@ static int kxcjk1013_probe(struct i2c_client *client, err_iio_unregister: iio_device_unregister(indio_dev); err_buffer_cleanup: - if (data->trig_mode) + if (data->dready_trig) iio_triggered_buffer_cleanup(indio_dev); err_trigger_unregister: - if (data->trig_mode) - iio_trigger_unregister(trig); -err_trigger_free: - if (data->trig_mode) - iio_trigger_free(trig); + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + if (data->motion_trig) + iio_trigger_unregister(data->motion_trig); return ret; } @@ -848,10 +1244,10 @@ static int kxcjk1013_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - if (data->trig_mode) { + if (data->dready_trig) { iio_triggered_buffer_cleanup(indio_dev); - iio_trigger_unregister(data->trig); - iio_trigger_free(data->trig); + iio_trigger_unregister(data->dready_trig); + iio_trigger_unregister(data->motion_trig); } mutex_lock(&data->mutex); @@ -883,7 +1279,8 @@ static int kxcjk1013_resume(struct device *dev) mutex_lock(&data->mutex); /* Check, if the suspend occured while active */ - if (data->trigger_on) + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) ret = kxcjk1013_set_mode(data, OPERATION); mutex_unlock(&data->mutex); From 81816affeacfa360bfefabba774774e95f3dcc12 Mon Sep 17 00:00:00 2001 From: Sanjeev Sharma Date: Wed, 20 Aug 2014 10:32:00 +0100 Subject: [PATCH 05/35] iio: remove .owner field for driver using module_platform_driver This patch removes the .owner field for drivers which use the platform_driver_register api because this is overriden in _platform_driver_register. Signed-off-by: Sanjeev Sharma Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 1 - drivers/iio/adc/exynos_adc.c | 1 - drivers/iio/adc/lp8788_adc.c | 1 - drivers/iio/adc/ti_am335x_adc.c | 1 - drivers/iio/adc/twl4030-madc.c | 1 - drivers/iio/adc/twl6030-gpadc.c | 1 - drivers/iio/adc/vf610_adc.c | 1 - drivers/iio/adc/viperboard_adc.c | 1 - drivers/iio/gyro/hid-sensor-gyro-3d.c | 1 - drivers/iio/humidity/dht11.c | 1 - drivers/iio/light/hid-sensor-als.c | 1 - drivers/iio/light/hid-sensor-prox.c | 1 - drivers/iio/light/lm3533-als.c | 1 - drivers/iio/magnetometer/hid-sensor-magn-3d.c | 1 - drivers/iio/orientation/hid-sensor-incl-3d.c | 1 - drivers/iio/orientation/hid-sensor-rotation.c | 1 - drivers/iio/pressure/hid-sensor-press.c | 1 - drivers/iio/trigger/iio-trig-interrupt.c | 1 - 18 files changed, 18 deletions(-) diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 54e464e4bb72..d5d95317003a 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -419,7 +419,6 @@ static struct platform_driver hid_accel_3d_platform_driver = { .id_table = hid_accel_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_accel_3d_probe, .remove = hid_accel_3d_remove, diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index c59012d2d06f..43620fd4c66a 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -723,7 +723,6 @@ static struct platform_driver exynos_adc_driver = { .remove = exynos_adc_remove, .driver = { .name = "exynos-adc", - .owner = THIS_MODULE, .of_match_table = exynos_adc_match, .pm = &exynos_adc_pm_ops, }, diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c index 5c8c91595f47..152cfc8e1c7b 100644 --- a/drivers/iio/adc/lp8788_adc.c +++ b/drivers/iio/adc/lp8788_adc.c @@ -244,7 +244,6 @@ static struct platform_driver lp8788_adc_driver = { .remove = lp8788_adc_remove, .driver = { .name = LP8788_DEV_ADC, - .owner = THIS_MODULE, }, }; module_platform_driver(lp8788_adc_driver); diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index d5dc4c6ce86c..b730864731e8 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -545,7 +545,6 @@ MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); static struct platform_driver tiadc_driver = { .driver = { .name = "TI-am335x-adc", - .owner = THIS_MODULE, .pm = TIADC_PM_OPS, .of_match_table = ti_adc_dt_ids, }, diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index eb86786e698e..94c5f05b4bc1 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -883,7 +883,6 @@ static struct platform_driver twl4030_madc_driver = { .remove = twl4030_madc_remove, .driver = { .name = "twl4030_madc", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(twl_madc_of_match), }, }; diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 15282f148b3b..89d8aa1d2818 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -994,7 +994,6 @@ static struct platform_driver twl6030_gpadc_driver = { .remove = twl6030_gpadc_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &twl6030_gpadc_pm_ops, .of_match_table = of_twl6030_match_tbl, }, diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 44799eb5930e..4a10ae97dbf2 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -698,7 +698,6 @@ static struct platform_driver vf610_adc_driver = { .remove = vf610_adc_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = vf610_adc_match, .pm = &vf610_adc_pm_ops, }, diff --git a/drivers/iio/adc/viperboard_adc.c b/drivers/iio/adc/viperboard_adc.c index 9acf6b6d705b..3be2e35721cc 100644 --- a/drivers/iio/adc/viperboard_adc.c +++ b/drivers/iio/adc/viperboard_adc.c @@ -145,7 +145,6 @@ static int vprbrd_adc_probe(struct platform_device *pdev) static struct platform_driver vprbrd_adc_driver = { .driver = { .name = "viperboard-adc", - .owner = THIS_MODULE, }, .probe = vprbrd_adc_probe, }; diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index fa034a3dad78..a3ea1e8785d7 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -416,7 +416,6 @@ static struct platform_driver hid_gyro_3d_platform_driver = { .id_table = hid_gyro_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_gyro_3d_probe, .remove = hid_gyro_3d_remove, diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index d8771f546bf2..623c145d8a97 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -281,7 +281,6 @@ static int dht11_probe(struct platform_device *pdev) static struct platform_driver dht11_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = dht11_dt_ids, }, .probe = dht11_probe, diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index 96e71e103ea7..a5283d75c096 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -381,7 +381,6 @@ static struct platform_driver hid_als_platform_driver = { .id_table = hid_als_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_als_probe, .remove = hid_als_remove, diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index 412bae86d6ae..f5a514698fd8 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -373,7 +373,6 @@ static struct platform_driver hid_prox_platform_driver = { .id_table = hid_prox_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_prox_probe, .remove = hid_prox_remove, diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index c1aadc6b865a..ae3c71bdd6c6 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -915,7 +915,6 @@ static int lm3533_als_remove(struct platform_device *pdev) static struct platform_driver lm3533_als_driver = { .driver = { .name = "lm3533-als", - .owner = THIS_MODULE, }, .probe = lm3533_als_probe, .remove = lm3533_als_remove, diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 1e717c71c244..6294575d2777 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -530,7 +530,6 @@ static struct platform_driver hid_magn_3d_platform_driver = { .id_table = hid_magn_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_magn_3d_probe, .remove = hid_magn_3d_remove, diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 2478f6c2ef25..1ff181bbbcef 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -437,7 +437,6 @@ static struct platform_driver hid_incl_3d_platform_driver = { .id_table = hid_incl_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_incl_3d_probe, .remove = hid_incl_3d_remove, diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index dccf848e8b0f..4afb6c79ccbc 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -334,7 +334,6 @@ static struct platform_driver hid_dev_rot_platform_driver = { .id_table = hid_dev_rot_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_dev_rot_probe, .remove = hid_dev_rot_remove, diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 2c0d2a4fed8c..764928682df2 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -382,7 +382,6 @@ static struct platform_driver hid_press_platform_driver = { .id_table = hid_press_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_press_probe, .remove = hid_press_remove, diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 7a149a7822bc..572bc6f02ca8 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -109,7 +109,6 @@ static struct platform_driver iio_interrupt_trigger_driver = { .remove = iio_interrupt_trigger_remove, .driver = { .name = "iio_interrupt_trigger", - .owner = THIS_MODULE, }, }; From 63d1157dedd79e37bbc3f68f6a9886c5eeb99c27 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 29 Aug 2014 04:56:00 +0100 Subject: [PATCH 06/35] iio: imu: inv_mpu6050: Remove casting the return value which is a void pointer Casting the return value which is a void pointer is redundant. The conversion from void pointer to any other pointer type is guaranteed by the C programming language. Signed-off-by: Jingoo Han Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 0c6517c94a9d..b75519deac1a 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -673,8 +673,7 @@ static int inv_mpu_probe(struct i2c_client *client, st = iio_priv(indio_dev); st->client = client; - pdata = (struct inv_mpu6050_platform_data - *)dev_get_platdata(&client->dev); + pdata = dev_get_platdata(&client->dev); if (pdata) st->plat_data = *pdata; /* power is turned on inside check chip type*/ From dd8f17a120d00e93b5f76d5904f5ea31934f0a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Tue, 26 Aug 2014 23:40:00 +0100 Subject: [PATCH 07/35] iio: adc: rockchip_saradc: remove unused variable in probe The rate variable in the probe function of the saradc is a remnant of a previous patch iteration. It is unused and thus produces a compile time warning. Therefore remove it. Signed-off-by: Heiko Stuebner Signed-off-by: Jonathan Cameron --- drivers/iio/adc/rockchip_saradc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 1fad9647cef4..e074a0b03f28 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -141,7 +141,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) struct resource *mem; int ret; int irq; - u32 rate; if (!np) return -ENODEV; From 3068ab202e637d5e46831a2276c3849d97655192 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 27 Aug 2014 09:31:00 +0100 Subject: [PATCH 08/35] iio: adc: at91: make the function handle_adc_eoc_trigger() static The handle_adc_eoc_trigger() in only used in at91_adc.c. So make it static. Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 772e869c280e..7807e0ef5b29 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -266,7 +266,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) } /* Handler for classic adc channel eoc trigger */ -void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) +static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); From 3c8bf223469b4db4d63e1dd8bdbde5ffb32d0cba Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 28 Aug 2014 14:14:00 +0100 Subject: [PATCH 09/35] iio: sensors-core: st: Check st_sensors_set_drdy_int_pin()'s return value Value from st_sensors_set_drdy_int_pin() is assigned to err here, but that stored value is not used before it is overwritten. To fix this we're enforcing a check on st_sensors_set_drdy_int_pin()'s return value and if it's an error, we're returning right away. Cc: jic23@kernel.org Cc: linux-iio@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8a4ec00a91a0..24cfe4e044f9 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -306,8 +306,11 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, if (of_pdata) pdata = of_pdata; - if (pdata) + if (pdata) { err = st_sensors_set_drdy_int_pin(indio_dev, pdata); + if (err < 0) + return err; + } err = st_sensors_set_enable(indio_dev, false); if (err < 0) From 5b4b5b9c6851418268cd0d5949942ba262106938 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Fri, 29 Aug 2014 15:26:00 +0100 Subject: [PATCH 10/35] staging: iio: light: isl29018: fix typo isl29108 was used, instead of isl29018. Signed-off-by: Laurentiu Palcu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 86cc8f9fef06..63c70be2d709 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -447,7 +447,7 @@ static struct attribute *isl29018_attributes[] = { NULL }; -static const struct attribute_group isl29108_group = { +static const struct attribute_group isl29018_group = { .attrs = isl29018_attributes, }; @@ -510,8 +510,8 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return 0; } -static const struct iio_info isl29108_info = { - .attrs = &isl29108_group, +static const struct iio_info isl29018_info = { + .attrs = &isl29018_group, .driver_module = THIS_MODULE, .read_raw = &isl29018_read_raw, .write_raw = &isl29018_write_raw, @@ -579,7 +579,7 @@ static int isl29018_probe(struct i2c_client *client, if (err) return err; - indio_dev->info = &isl29108_info; + indio_dev->info = &isl29018_info; indio_dev->channels = isl29018_channels; indio_dev->num_channels = ARRAY_SIZE(isl29018_channels); indio_dev->name = id->name; From 609acefa46090fbe814aa5dbfec79338b49cf784 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Fri, 29 Aug 2014 15:26:00 +0100 Subject: [PATCH 11/35] staging: iio: light: isl29018: add support for isl29023 and isl29035 Intersil chips ISL29018, ISL29023 and ISL29035 are very similar. They're all ambience light sensors. The ISL29018, however, is also a proximity sensor. The registers are similar too: -------------+----------+---------- AVAILABLE IN | ADDR REG | NAME 290xx | | -------------+----------+---------- 18/23/35| 00h| COMMANDI 18/23/35| 01h| COMMANDII (B4-7 are used only in 29018 for proximity) 18/23/35| 02h| DATALSB 18/23/35| 03h| DATAMSB 18/23/35| 04h| INT_LT_LSB 18/23/35| 05h| INT_LT_MSB 18/23/35| 06h| INT_HT_LSB 18/23/35| 07h| INT_HT_MSB 18/23| 08h| TEST 35| 0Fh| ID -------------+----------+----------- So, this patch will add support for ISL29023 and ISL29035 to the existing isl29018 driver. Since these 2 chips don't have proximity detection, the proximity sysfs attribute is not needed. Also, for ISL29035, since it has an ID register, make use of it in order to properly detect the chip and clear the brownout bit. Signed-off-by: Laurentiu Palcu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 163 +++++++++++++++++++++++---- 1 file changed, 141 insertions(+), 22 deletions(-) diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 63c70be2d709..b50f126f3908 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -1,5 +1,5 @@ /* - * A iio driver for the light sensor ISL 29018. + * A iio driver for the light sensor ISL 29018/29023/29035. * * IIO driver for monitoring ambient light intensity in luxi, proximity * sensing and infrared sensing. @@ -58,10 +58,18 @@ #define ISL29018_TEST_SHIFT 0 #define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) +#define ISL29035_REG_DEVICE_ID 0x0F +#define ISL29035_DEVICE_ID_SHIFT 0x03 +#define ISL29035_DEVICE_ID_MASK (0x7 << ISL29035_DEVICE_ID_SHIFT) +#define ISL29035_DEVICE_ID 0x5 +#define ISL29035_BOUT_SHIFT 0x07 +#define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) + struct isl29018_chip { struct device *dev; struct regmap *regmap; struct mutex lock; + int type; unsigned int lux_scale; unsigned int lux_uscale; unsigned int range; @@ -407,23 +415,35 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, return ret; } +#define ISL29018_LIGHT_CHANNEL { \ + .type = IIO_LIGHT, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ +} + +#define ISL29018_IR_CHANNEL { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .channel2 = IIO_MOD_LIGHT_IR, \ +} + +#define ISL29018_PROXIMITY_CHANNEL { \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +} + static const struct iio_chan_spec isl29018_channels[] = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, { - .type = IIO_INTENSITY, - .modified = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .channel2 = IIO_MOD_LIGHT_IR, - }, { - /* Unindexed in current ABI. But perhaps it should be. */ - .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - } + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, + ISL29018_PROXIMITY_CHANNEL, +}; + +static const struct iio_chan_spec isl29023_channels[] = { + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, }; static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); @@ -447,16 +467,63 @@ static struct attribute *isl29018_attributes[] = { NULL }; +static struct attribute *isl29023_attributes[] = { + ISL29018_DEV_ATTR(range), + ISL29018_CONST_ATTR(range_available), + ISL29018_DEV_ATTR(adc_resolution), + ISL29018_CONST_ATTR(adc_resolution_available), + NULL +}; + static const struct attribute_group isl29018_group = { .attrs = isl29018_attributes, }; +static const struct attribute_group isl29023_group = { + .attrs = isl29023_attributes, +}; + +static int isl29035_detect(struct isl29018_chip *chip) +{ + int status; + unsigned int id; + + status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); + if (status < 0) { + dev_err(chip->dev, + "Error reading ID register with error %d\n", + status); + return status; + } + + id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; + + if (id != ISL29035_DEVICE_ID) + return -ENODEV; + + /* clear out brownout bit */ + return regmap_update_bits(chip->regmap, ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK, 0); +} + +enum { + isl29018, + isl29023, + isl29035, +}; + static int isl29018_chip_init(struct isl29018_chip *chip) { int status; unsigned int new_adc_bit; unsigned int new_range; + if (chip->type == isl29035) { + status = isl29035_detect(chip); + if (status < 0) + return status; + } + /* Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD @@ -517,6 +584,13 @@ static const struct iio_info isl29018_info = { .write_raw = &isl29018_write_raw, }; +static const struct iio_info isl29023_info = { + .attrs = &isl29023_group, + .driver_module = THIS_MODULE, + .read_raw = &isl29018_read_raw, + .write_raw = &isl29018_write_raw, +}; + static bool is_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -524,6 +598,7 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg) case ISL29018_REG_ADD_DATA_MSB: case ISL29018_REG_ADD_COMMAND1: case ISL29018_REG_TEST: + case ISL29035_REG_DEVICE_ID: return true; default: return false; @@ -543,6 +618,44 @@ static const struct regmap_config isl29018_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +/* isl29035_regmap_config: regmap configuration for ISL29035 */ +static const struct regmap_config isl29035_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = ISL29035_REG_DEVICE_ID, + .num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1, + .cache_type = REGCACHE_RBTREE, +}; + +struct chip_info { + const struct iio_chan_spec *channels; + int num_channels; + const struct iio_info *indio_info; + const struct regmap_config *regmap_cfg; +}; + +static const struct chip_info chip_info_tbl[] = { + [isl29018] = { + .channels = isl29018_channels, + .num_channels = ARRAY_SIZE(isl29018_channels), + .indio_info = &isl29018_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29023] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29035] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29035_regmap_config, + }, +}; + static int isl29018_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -562,13 +675,15 @@ static int isl29018_probe(struct i2c_client *client, mutex_init(&chip->lock); + chip->type = id->driver_data; chip->lux_scale = 1; chip->lux_uscale = 0; chip->range = 1000; chip->adc_bit = 16; chip->suspended = false; - chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config); + chip->regmap = devm_regmap_init_i2c(client, + chip_info_tbl[id->driver_data].regmap_cfg); if (IS_ERR(chip->regmap)) { err = PTR_ERR(chip->regmap); dev_err(chip->dev, "regmap initialization failed: %d\n", err); @@ -579,9 +694,9 @@ static int isl29018_probe(struct i2c_client *client, if (err) return err; - indio_dev->info = &isl29018_info; - indio_dev->channels = isl29018_channels; - indio_dev->num_channels = ARRAY_SIZE(isl29018_channels); + indio_dev->info = chip_info_tbl[id->driver_data].indio_info; + indio_dev->channels = chip_info_tbl[id->driver_data].channels; + indio_dev->num_channels = chip_info_tbl[id->driver_data].num_channels; indio_dev->name = id->name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; @@ -633,7 +748,9 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); #endif static const struct i2c_device_id isl29018_id[] = { - {"isl29018", 0}, + {"isl29018", isl29018}, + {"isl29023", isl29023}, + {"isl29035", isl29035}, {} }; @@ -641,6 +758,8 @@ MODULE_DEVICE_TABLE(i2c, isl29018_id); static const struct of_device_id isl29018_of_match[] = { { .compatible = "isil,isl29018", }, + { .compatible = "isil,isl29023", }, + { .compatible = "isil,isl29035", }, { }, }; MODULE_DEVICE_TABLE(of, isl29018_of_match); From 823615e2de6880de3c8e681333147a09719f6fdb Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Fri, 29 Aug 2014 09:38:00 +0100 Subject: [PATCH 12/35] iio: accel: BMC150: fix scale value for 16G According to documentation ([1] - page 27), the range for 16G is 7.81mg/LSB. Converted to SI, this is: 7.81 * 10^-3 * 9.80665 m/s^2 / LSB = 0.0765899365 m/s^2 / LSB [1] http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf Signed-off-by: Laurentiu Palcu Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 23ae33496214..ccb6cf83f5f5 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -173,7 +173,7 @@ static const struct { } bmc150_accel_scale_table[] = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, {19122, BMC150_ACCEL_DEF_RANGE_4G}, {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {77057, BMC150_ACCEL_DEF_RANGE_16G} }; + {76590, BMC150_ACCEL_DEF_RANGE_16G} }; static const struct { int sleep_dur; From b31b05cf629574d47b324bb52128ed1b199faccd Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Fri, 29 Aug 2014 09:38:00 +0100 Subject: [PATCH 13/35] iio: accel: BMC150: fix issues when CONFIG_PM_RUNTIME is not set When CONFIG_PM_RUNTIME is not set, the following issues are seen: * warning message at compilation time: warning: 'bmc150_accel_get_startup_times' defined but not used [-Wunused-function] * bmc150_accel_set_power_state() will always fail and reading the accelerometer data is impossible; This occurs because of the call to pm_runtime_put_autosuspend calls __pm_runtime_suspend which returns -ENOSYS. This commit fixes these. Signed-off-by: Laurentiu Palcu Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index ccb6cf83f5f5..0e6566adca24 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -499,6 +499,7 @@ static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, return -EINVAL; } +#ifdef CONFIG_PM_RUNTIME static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) { int i; @@ -529,6 +530,12 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) return 0; } +#else +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + return 0; +} +#endif static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { From 5aa89392fad217fae7df361dc812a27d5177d980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20St=C3=BCbner?= Date: Wed, 23 Jul 2014 22:24:00 +0100 Subject: [PATCH 14/35] dt-bindings: document Rockchip saradc This add the necessary binding documentation for the saradc found in all recent processors from Rockchip. Signed-off-by: Heiko Stuebner Signed-off-by: Jonathan Cameron --- .../bindings/iio/adc/rockchip-saradc.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt new file mode 100644 index 000000000000..5d3ec1df226d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt @@ -0,0 +1,24 @@ +Rockchip Successive Approximation Register (SAR) A/D Converter bindings + +Required properties: +- compatible: Should be "rockchip,saradc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Shall be "saradc" for the converter-clock, and "apb_pclk" for + the peripheral clock. +- vref-supply: The regulator supply ADC reference voltage. +- #io-channel-cells: Should be 1, see ../iio-bindings.txt + +Example: + saradc: saradc@2006c000 { + compatible = "rockchip,saradc"; + reg = <0x2006c000 0x100>; + interrupts = ; + clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + #io-channel-cells = <1>; + vref-supply = <&vcc18>; + }; From ca801795b17b13a105b5209cf451abac3a6529ff Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 19 Aug 2014 16:25:00 +0100 Subject: [PATCH 15/35] iio: accel: kxcjk-1013: add support for kxcj9-1008 This patch adds support for KXCJ9-1008 3-axis acceleromenter sensor. KXCJ9-1008 uses the same register definitions as KXCJK-1013. The specification for KXCJ9-1008 can be downloaded from: http://www.kionix.com/sites/default/files/KXCJ9-1008%20Specifications%20Rev%205.pdf Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 2 +- drivers/iio/accel/kxcjk-1013.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 5704d6bc2267..01b857e2fcbd 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -97,7 +97,7 @@ config KXCJK1013 select IIO_TRIGGERED_BUFFER help Say Y here if you want to build a driver for the Kionix KXCJK-1013 - triaxial acceleration sensor. + triaxial acceleration sensor. This driver also supports KXCJ9-1008. To compile this driver as a module, choose M here: the module will be called kxcjk-1013. diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 647a4cfb2ae7..736231d5f636 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1326,12 +1326,14 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { static const struct acpi_device_id kx_acpi_match[] = { {"KXCJ1013", 0}, + {"KXCJ1008", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, kx_acpi_match); static const struct i2c_device_id kxcjk1013_id[] = { {"kxcjk1013", 0}, + {"kxcj91008", 0}, {} }; From af14afd2abef9e01761ec6eb79dd7c0833a243f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Brinkmann?= Date: Sun, 31 Aug 2014 07:57:00 +0100 Subject: [PATCH 16/35] staging: ad7606_core: Fix checkpatch warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the checkpatch complaint regarding unnecessary line continuation. WARNING: Avoid unnecessary line continuations #143: FILE: ad7606_core.c:143: Signed-off-by: Sören Brinkmann Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7606_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index f0f05f195d2c..bf2c8013134c 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -140,7 +140,7 @@ static ssize_t ad7606_store_range(struct device *dev, return count; } -static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, \ +static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, ad7606_show_range, ad7606_store_range, 0); static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); From f007d7f1431ca9bc184782e704a7da460385d335 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Thu, 9 Oct 2014 07:57:00 +0100 Subject: [PATCH 17/35] iio: Add Dyna-Image AL3320A ambient light sensor driver Minimal implementation. This driver provides raw illuminance readings. This is based on drivers/hwmon/al3320.c (*) driver from msm tree written by Tsechih Lin * https://android.googlesource.com/kernel/msm.git Signed-off-by: Daniel Baluta Reviewed-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 ++ drivers/iio/light/Makefile | 1 + drivers/iio/light/al3320a.c | 232 ++++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/iio/light/al3320a.c diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index bf05ca5b0a57..5bea821adcae 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -17,6 +17,16 @@ config ADJD_S311 This driver can also be built as a module. If so, the module will be called adjd_s311. +config AL3320A + tristate "AL3320A ambient light sensor" + depends on I2C + help + Say Y here if you want to build a driver for the Dyna Image AL3320A + ambient light sensor. + + To compile this driver as a module, choose M here: the + module will be called al3320a. + config APDS9300 tristate "APDS9300 ambient light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 8b8c09f9c1f8..47877a36cc12 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADJD_S311) += adjd_s311.o +obj-$(CONFIG_AL3320A) += al3320a.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_CM32181) += cm32181.o obj-$(CONFIG_CM36651) += cm36651.o diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c new file mode 100644 index 000000000000..6aac6513fd41 --- /dev/null +++ b/drivers/iio/light/al3320a.c @@ -0,0 +1,232 @@ +/* + * AL3320A - Dyna Image Ambient Light Sensor + * + * Copyright (c) 2014, Intel Corporation. + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for AL3320A (7-bit I2C slave address 0x1C). + * + * TODO: interrupt support, thresholds + * + */ + +#include +#include +#include + +#include +#include + +#define AL3320A_DRV_NAME "al3320a" + +#define AL3320A_REG_CONFIG 0x00 +#define AL3320A_REG_STATUS 0x01 +#define AL3320A_REG_INT 0x02 +#define AL3320A_REG_WAIT 0x06 +#define AL3320A_REG_CONFIG_RANGE 0x07 +#define AL3320A_REG_PERSIST 0x08 +#define AL3320A_REG_MEAN_TIME 0x09 +#define AL3320A_REG_ADUMMY 0x0A +#define AL3320A_REG_DATA_LOW 0x22 + +#define AL3320A_REG_LOW_THRESH_LOW 0x30 +#define AL3320A_REG_LOW_THRESH_HIGH 0x31 +#define AL3320A_REG_HIGH_THRESH_LOW 0x32 +#define AL3320A_REG_HIGH_THRESH_HIGH 0x33 + +#define AL3320A_CONFIG_DISABLE 0x00 +#define AL3320A_CONFIG_ENABLE 0x01 + +#define AL3320A_GAIN_SHIFT 1 +#define AL3320A_GAIN_MASK (BIT(2) | BIT(1)) + +/* chip params default values */ +#define AL3320A_DEFAULT_MEAN_TIME 4 +#define AL3320A_DEFAULT_WAIT_TIME 0 /* no waiting */ + +#define AL3320A_SCALE_AVAILABLE "0.512 0.128 0.032 0.01" + +enum al3320a_range { + AL3320A_RANGE_1, /* 33.28 Klx */ + AL3320A_RANGE_2, /* 8.32 Klx */ + AL3320A_RANGE_3, /* 2.08 Klx */ + AL3320A_RANGE_4 /* 0.65 Klx */ +}; + +static const int al3320a_scales[][2] = { + {0, 512000}, {0, 128000}, {0, 32000}, {0, 10000} +}; + +struct al3320a_data { + struct i2c_client *client; +}; + +static const struct iio_chan_spec al3320a_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static IIO_CONST_ATTR(in_illuminance_scale_available, AL3320A_SCALE_AVAILABLE); + +static struct attribute *al3320a_attributes[] = { + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group al3320a_attribute_group = { + .attrs = al3320a_attributes, +}; + +static int al3320a_init(struct al3320a_data *data) +{ + int ret; + + /* power on */ + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG, + AL3320A_CONFIG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE, + AL3320A_RANGE_3 << AL3320A_GAIN_SHIFT); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME, + AL3320A_DEFAULT_MEAN_TIME); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT, + AL3320A_DEFAULT_WAIT_TIME); + if (ret < 0) + return ret; + + return 0; +} + +static int al3320a_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct al3320a_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * ALS ADC value is stored in two adjacent registers: + * - low byte of output is stored at AL3320A_REG_DATA_LOW + * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1 + */ + ret = i2c_smbus_read_word_data(data->client, + AL3320A_REG_DATA_LOW); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = i2c_smbus_read_byte_data(data->client, + AL3320A_REG_CONFIG_RANGE); + if (ret < 0) + return ret; + + ret = (ret & AL3320A_GAIN_MASK) >> AL3320A_GAIN_SHIFT; + *val = al3320a_scales[ret][0]; + *val2 = al3320a_scales[ret][1]; + + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int al3320a_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct al3320a_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + for (i = 0; i < ARRAY_SIZE(al3320a_scales); i++) { + if (val == al3320a_scales[i][0] && + val2 == al3320a_scales[i][1]) + return i2c_smbus_write_byte_data(data->client, + AL3320A_REG_CONFIG_RANGE, + i << AL3320A_GAIN_SHIFT); + } + break; + } + return -EINVAL; +} + +static const struct iio_info al3320a_info = { + .driver_module = THIS_MODULE, + .read_raw = al3320a_read_raw, + .write_raw = al3320a_write_raw, + .attrs = &al3320a_attribute_group, +}; + +static int al3320a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct al3320a_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &al3320a_info; + indio_dev->name = AL3320A_DRV_NAME; + indio_dev->channels = al3320a_channels; + indio_dev->num_channels = ARRAY_SIZE(al3320a_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = al3320a_init(data); + if (ret < 0) { + dev_err(&client->dev, "al3320a chip init failed\n"); + return ret; + } + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int al3320a_remove(struct i2c_client *client) +{ + return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG, + AL3320A_CONFIG_DISABLE); +} + +static const struct i2c_device_id al3320a_id[] = { + {"al3320a", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, al3320a_id); + +static struct i2c_driver al3320a_driver = { + .driver = { + .name = AL3320A_DRV_NAME, + }, + .probe = al3320a_probe, + .remove = al3320a_remove, + .id_table = al3320a_id, +}; + +module_i2c_driver(al3320a_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("AL3320A Ambient Light Sensor driver"); +MODULE_LICENSE("GPL v2"); From dc4ecaf21c4a0c060f2728d31bf492ceb2c8daaf Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Thu, 9 Jan 2014 10:20:00 +0000 Subject: [PATCH 18/35] staging: iio: light: isl29018: add ACPI support Add support for enumerating the device through ACPI. Signed-off-by: Laurentiu Palcu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/light/isl29018.c | 46 ++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index b50f126f3908..65a35daead32 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -30,6 +30,7 @@ #include #include #include +#include #define CONVERSION_TIME_MS 100 @@ -656,12 +657,28 @@ static const struct chip_info chip_info_tbl[] = { }, }; +static const char *isl29018_match_acpi_device(struct device *dev, int *data) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return NULL; + + *data = (int) id->driver_data; + + return dev_name(dev); +} + static int isl29018_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct isl29018_chip *chip; struct iio_dev *indio_dev; int err; + const char *name = NULL; + int dev_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (indio_dev == NULL) { @@ -673,9 +690,17 @@ static int isl29018_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); chip->dev = &client->dev; + if (id) { + name = id->name; + dev_id = id->driver_data; + } + + if (ACPI_HANDLE(&client->dev)) + name = isl29018_match_acpi_device(&client->dev, &dev_id); + mutex_init(&chip->lock); - chip->type = id->driver_data; + chip->type = dev_id; chip->lux_scale = 1; chip->lux_uscale = 0; chip->range = 1000; @@ -683,7 +708,7 @@ static int isl29018_probe(struct i2c_client *client, chip->suspended = false; chip->regmap = devm_regmap_init_i2c(client, - chip_info_tbl[id->driver_data].regmap_cfg); + chip_info_tbl[dev_id].regmap_cfg); if (IS_ERR(chip->regmap)) { err = PTR_ERR(chip->regmap); dev_err(chip->dev, "regmap initialization failed: %d\n", err); @@ -694,10 +719,10 @@ static int isl29018_probe(struct i2c_client *client, if (err) return err; - indio_dev->info = chip_info_tbl[id->driver_data].indio_info; - indio_dev->channels = chip_info_tbl[id->driver_data].channels; - indio_dev->num_channels = chip_info_tbl[id->driver_data].num_channels; - indio_dev->name = id->name; + indio_dev->info = chip_info_tbl[dev_id].indio_info; + indio_dev->channels = chip_info_tbl[dev_id].channels; + indio_dev->num_channels = chip_info_tbl[dev_id].num_channels; + indio_dev->name = name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; err = devm_iio_device_register(&client->dev, indio_dev); @@ -747,6 +772,14 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); #define ISL29018_PM_OPS NULL #endif +static const struct acpi_device_id isl29018_acpi_match[] = { + {"ISL29018", isl29018}, + {"ISL29023", isl29023}, + {"ISL29035", isl29035}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); + static const struct i2c_device_id isl29018_id[] = { {"isl29018", isl29018}, {"isl29023", isl29023}, @@ -768,6 +801,7 @@ static struct i2c_driver isl29018_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "isl29018", + .acpi_match_table = ACPI_PTR(isl29018_acpi_match), .pm = ISL29018_PM_OPS, .owner = THIS_MODULE, .of_match_table = isl29018_of_match, From 8ecbb3c3c712d9c859586886d621e3b6175da972 Mon Sep 17 00:00:00 2001 From: Laurentiu Palcu Date: Sun, 9 Feb 2014 10:30:00 +0000 Subject: [PATCH 19/35] iio: accel: BMC150: add support for other Bosch chips The following chips are either similar or have only the resolution different. Hence, change this driver to support these chips too: BMI055 - combo chip (accelerometer part is identical to BMC150's) BMA255 - identical to BMC150's accelerometer BMA222E - 8 bit resolution BMA250E - 10 bit resolution BMA280 - 14 bit resolution Additionally: * add bmc150_accel_match_acpi_device() function to check that the device has been enumerated through ACPI; * rename bmc150_accel_acpi_gpio_probe() to bmc150_accel_gpio_probe() since the ACPI matching has been moved to the new function. Also, this will allow for the GPIO matching to be done against a device tree too, not only ACPI tree; * rename bmc150_scale_info struct member 'range' to 'reg_range' to be consistent with the naming convention used elsewhere in the driver and declare it u8, instead of int; * change CONFIG description to list all supported chips; Signed-off-by: Laurentiu Palcu Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 4 +- drivers/iio/accel/bmc150-accel.c | 234 +++++++++++++++++++++++-------- 2 files changed, 178 insertions(+), 60 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 01b857e2fcbd..01a2151677a9 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -23,7 +23,9 @@ config BMC150_ACCEL select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for the Bosch BMC150 accelerometer. + 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. diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 0e6566adca24..22c096ce39ad 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -1,5 +1,12 @@ /* - * BMC150 3-axis accelerometer driver + * 3-axis accelerometer driver supporting following 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 @@ -34,7 +41,6 @@ #define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" #define BMC150_ACCEL_REG_CHIP_ID 0x00 -#define BMC150_ACCEL_CHIP_ID_VAL 0xFA #define BMC150_ACCEL_REG_INT_STATUS_2 0x0B #define BMC150_ACCEL_ANY_MOTION_MASK 0x07 @@ -126,6 +132,18 @@ enum bmc150_power_modes { BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, }; +struct bmc150_scale_info { + int scale; + u8 reg_range; +}; + +struct bmc150_accel_chip_info { + u8 chip_id; + const struct iio_chan_spec *channels; + int num_channels; + const struct bmc150_scale_info scale_table[4]; +}; + struct bmc150_accel_data { struct i2c_client *client; struct iio_trigger *dready_trig; @@ -140,6 +158,7 @@ struct bmc150_accel_data { bool dready_trigger_on; bool motion_trigger_on; int64_t timestamp; + const struct bmc150_accel_chip_info *chip_info; }; static const struct { @@ -167,17 +186,9 @@ static const struct { {0x0E, 1}, {0x0F, 1} }; -static const struct { - int scale; - int range; -} bmc150_accel_scale_table[] = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, - {19122, BMC150_ACCEL_DEF_RANGE_4G}, - {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {76590, BMC150_ACCEL_DEF_RANGE_16G} }; - static const struct { int sleep_dur; - int reg_value; + u8 reg_value; } bmc150_accel_sleep_value_table[] = { {0, 0}, {500, BMC150_ACCEL_SLEEP_500_MICRO}, {1000, BMC150_ACCEL_SLEEP_1_MS}, @@ -267,7 +278,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) } dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != BMC150_ACCEL_CHIP_ID_VAL) { + if (ret != data->chip_info->chip_id) { dev_err(&data->client->dev, "Invalid chip %x\n", ret); return -ENODEV; } @@ -541,19 +552,19 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { int ret, i; - for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); ++i) { - if (bmc150_accel_scale_table[i].scale == 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, - BMC150_ACCEL_REG_PMU_RANGE, - bmc150_accel_scale_table[i].range); + data->client, + BMC150_ACCEL_REG_PMU_RANGE, + data->chip_info->scale_table[i].reg_range); if (ret < 0) { dev_err(&data->client->dev, "Error writing pmu_range\n"); return ret; } - data->range = bmc150_accel_scale_table[i].range; + data->range = data->chip_info->scale_table[i].reg_range; return 0; } } @@ -580,10 +591,12 @@ static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) return IIO_VAL_INT; } -static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis, +static int bmc150_accel_get_axis(struct bmc150_accel_data *data, + struct iio_chan_spec const *chan, int *val) { int ret; + int axis = chan->scan_index; mutex_lock(&data->mutex); ret = bmc150_accel_set_power_state(data, true); @@ -600,7 +613,8 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis, mutex_unlock(&data->mutex); return ret; } - *val = sign_extend32(ret >> 4, 11); + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); ret = bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); if (ret < 0) @@ -625,9 +639,7 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev, if (iio_buffer_enabled(indio_dev)) return -EBUSY; else - return bmc150_accel_get_axis(data, - chan->scan_index, - val); + return bmc150_accel_get_axis(data, chan, val); default: return -EINVAL; } @@ -646,13 +658,13 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev, case IIO_ACCEL: { int i; + const struct bmc150_scale_info *si; + int st_size = ARRAY_SIZE(data->chip_info->scale_table); - for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); - ++i) { - if (bmc150_accel_scale_table[i].range == - data->range) { - *val2 = - bmc150_accel_scale_table[i].scale; + for (i = 0; i < st_size; ++i) { + si = &data->chip_info->scale_table[i]; + if (si->reg_range == data->range) { + *val2 = si->scale; return IIO_VAL_INT_PLUS_MICRO; } } @@ -840,7 +852,7 @@ static const struct iio_event_spec bmc150_accel_event = { BIT(IIO_EV_INFO_PERIOD) }; -#define BMC150_ACCEL_CHANNEL(_axis) { \ +#define BMC150_ACCEL_CHANNEL(_axis, bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ @@ -850,26 +862,101 @@ static const struct iio_event_spec bmc150_accel_event = { .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = (bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (bits), \ }, \ .event_spec = &bmc150_accel_event, \ .num_event_specs = 1 \ } -static const struct iio_chan_spec bmc150_accel_channels[] = { - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - .scan_index = -1, +#define BMC150_ACCEL_CHANNELS(bits) { \ + { \ + .type = IIO_TEMP, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = -1, \ + }, \ + BMC150_ACCEL_CHANNEL(X, bits), \ + BMC150_ACCEL_CHANNEL(Y, bits), \ + BMC150_ACCEL_CHANNEL(Z, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(3), \ +} + +static const struct iio_chan_spec bma222e_accel_channels[] = + BMC150_ACCEL_CHANNELS(8); +static const struct iio_chan_spec bma250e_accel_channels[] = + BMC150_ACCEL_CHANNELS(10); +static const struct iio_chan_spec bmc150_accel_channels[] = + BMC150_ACCEL_CHANNELS(12); +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] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bmi055] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma255] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma250e] = { + .chip_id = 0xF9, + .channels = bma250e_accel_channels, + .num_channels = ARRAY_SIZE(bma250e_accel_channels), + .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G}, + {76590, BMC150_ACCEL_DEF_RANGE_4G}, + {153277, BMC150_ACCEL_DEF_RANGE_8G}, + {306457, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma222e] = { + .chip_id = 0xF8, + .channels = bma222e_accel_channels, + .num_channels = ARRAY_SIZE(bma222e_accel_channels), + .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G}, + {306457, BMC150_ACCEL_DEF_RANGE_4G}, + {612915, BMC150_ACCEL_DEF_RANGE_8G}, + {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma280] = { + .chip_id = 0xFB, + .channels = bma280_accel_channels, + .num_channels = ARRAY_SIZE(bma280_accel_channels), + .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G}, + {4785, BMC150_ACCEL_DEF_RANGE_4G}, + {9581, BMC150_ACCEL_DEF_RANGE_8G}, + {19152, BMC150_ACCEL_DEF_RANGE_16G} }, }, - BMC150_ACCEL_CHANNEL(X), - BMC150_ACCEL_CHANNEL(Y), - BMC150_ACCEL_CHANNEL(Z), - IIO_CHAN_SOFT_TIMESTAMP(3), }; static const struct iio_info bmc150_accel_info = { @@ -1040,10 +1127,23 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client, - struct bmc150_accel_data *data) +static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) { const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return NULL; + + *data = (int) id->driver_data; + + return dev_name(dev); +} + +static int bmc150_accel_gpio_probe(struct i2c_client *client, + struct bmc150_accel_data *data) +{ struct device *dev; struct gpio_desc *gpio; int ret; @@ -1052,17 +1152,11 @@ static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client, return -EINVAL; dev = &client->dev; - if (!ACPI_HANDLE(dev)) - return -ENODEV; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; /* data ready gpio interrupt pin */ gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0); if (IS_ERR(gpio)) { - dev_err(dev, "Failed: acpi gpio get index\n"); + dev_err(dev, "Failed: gpio get index\n"); return PTR_ERR(gpio); } @@ -1083,6 +1177,8 @@ static int bmc150_accel_probe(struct i2c_client *client, struct bmc150_accel_data *data; struct iio_dev *indio_dev; int ret; + const char *name = NULL; + int chip_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1092,6 +1188,16 @@ static int bmc150_accel_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; + if (id) { + name = id->name; + chip_id = id->driver_data; + } + + if (ACPI_HANDLE(&client->dev)) + name = bmc150_accel_match_acpi_device(&client->dev, &chip_id); + + data->chip_info = &bmc150_accel_chip_info_tbl[chip_id]; + ret = bmc150_accel_chip_init(data); if (ret < 0) return ret; @@ -1099,14 +1205,14 @@ static int bmc150_accel_probe(struct i2c_client *client, mutex_init(&data->mutex); indio_dev->dev.parent = &client->dev; - indio_dev->channels = bmc150_accel_channels; - indio_dev->num_channels = ARRAY_SIZE(bmc150_accel_channels); - indio_dev->name = BMC150_ACCEL_DRV_NAME; + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; if (client->irq < 0) - client->irq = bmc150_accel_acpi_gpio_probe(client, data); + client->irq = bmc150_accel_gpio_probe(client, data); if (client->irq >= 0) { ret = devm_request_threaded_irq( @@ -1284,14 +1390,24 @@ static const struct dev_pm_ops bmc150_accel_pm_ops = { }; static const struct acpi_device_id bmc150_accel_acpi_match[] = { - {"BSBA0150", 0}, - {"BMC150A", 0}, + {"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", 0}, + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, {} }; From c68613777517e538ace751e4e738e238eb216f86 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sun, 9 Mar 2014 08:33:00 +0000 Subject: [PATCH 20/35] iio: accel: kxcjk-1013: add support for kxtj2-1009 This patch adds support for KXTJ2-1009 3-axis acceleromenter sensor. KXTJ2-1009 uses the same register definitions as KXCJK-1013. The specification for KXTJ2-1009 can be downloaded from: http://www.kionix.com/sites/default/files/KXTJ2-1009%20Specifications%20Rev%204.pdf Reviewed-by: Srinivas Pandruvada Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 3 +- drivers/iio/accel/kxcjk-1013.c | 111 ++++++++++++++++++++++++++------- 2 files changed, 92 insertions(+), 22 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 01a2151677a9..f71efc8d3f3e 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -99,7 +99,8 @@ config KXCJK1013 select IIO_TRIGGERED_BUFFER help Say Y here if you want to build a driver for the Kionix KXCJK-1013 - triaxial acceleration sensor. This driver also supports KXCJ9-1008. + triaxial acceleration sensor. This driver also supports KXCJ9-1008 + and KXTJ2-1009. To compile this driver as a module, choose M here: the module will be called kxcjk-1013. diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 736231d5f636..615fce236d59 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -85,6 +85,13 @@ #define KXCJK1013_DEFAULT_WAKE_THRES 1 +enum kx_chipset { + KXCJK1013, + KXCJ91008, + KXTJ21009, + KX_MAX_CHIPS /* this must be last */ +}; + struct kxcjk1013_data { struct i2c_client *client; struct iio_trigger *dready_trig; @@ -100,6 +107,7 @@ struct kxcjk1013_data { int ev_enable_state; bool motion_trigger_on; int64_t timestamp; + enum kx_chipset chipset; }; enum kxcjk1013_axis { @@ -133,10 +141,53 @@ static const struct { static const struct { int odr_bits; int usec; -} odr_start_up_times[] = { {0x08, 100000}, {0x09, 100000}, {0x0A, 100000}, - {0x0B, 100000}, { 0, 80000}, {0x01, 41000}, - {0x02, 21000}, {0x03, 11000}, {0x04, 6400}, - {0x05, 3900}, {0x06, 2700}, {0x07, 2100} }; +} odr_start_up_times[KX_MAX_CHIPS][12] = { + /* KXCJK-1013 */ + { + {0x08, 100000}, + {0x09, 100000}, + {0x0A, 100000}, + {0x0B, 100000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6400}, + {0x05, 3900}, + {0x06, 2700}, + {0x07, 2100}, + }, + /* KXCJ9-1008 */ + { + {0x08, 100000}, + {0x09, 100000}, + {0x0A, 100000}, + {0x0B, 100000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6400}, + {0x05, 3900}, + {0x06, 2700}, + {0x07, 2100}, + }, + /* KXCTJ2-1009 */ + { + {0x08, 1240000}, + {0x09, 621000}, + {0x0A, 309000}, + {0x0B, 151000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6000}, + {0x05, 4000}, + {0x06, 3000}, + {0x07, 2000}, + }, +}; static const struct { u16 scale; @@ -310,10 +361,11 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) { int i; + int idx = data->chipset; - for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) { - if (odr_start_up_times[i].odr_bits == data->odr_bits) - return odr_start_up_times[i].usec; + for (i = 0; i < ARRAY_SIZE(odr_start_up_times[idx]); ++i) { + if (odr_start_up_times[idx][i].odr_bits == data->odr_bits) + return odr_start_up_times[idx][i].usec; } return KXCJK1013_MAX_STARTUP_TIME_US; @@ -1074,10 +1126,21 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, - struct kxcjk1013_data *data) +static const char *kxcjk1013_match_acpi_device(struct device *dev, + enum kx_chipset *chipset) { const struct acpi_device_id *id; + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + *chipset = (enum kx_chipset)id->driver_data; + + 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; @@ -1086,12 +1149,6 @@ static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, return -EINVAL; dev = &client->dev; - if (!ACPI_HANDLE(dev)) - return -ENODEV; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; /* data ready gpio interrupt pin */ gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0); @@ -1117,6 +1174,7 @@ static int kxcjk1013_probe(struct i2c_client *client, struct kxcjk1013_data *data; struct iio_dev *indio_dev; struct kxcjk_1013_platform_data *pdata; + const char *name; int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); @@ -1133,6 +1191,15 @@ static int kxcjk1013_probe(struct i2c_client *client, else data->active_high_intr = true; /* default polarity */ + if (id) { + data->chipset = (enum kx_chipset)(id->driver_data); + name = id->name; + } else if (ACPI_HANDLE(&client->dev)) { + name = kxcjk1013_match_acpi_device(&client->dev, + &data->chipset); + } else + return -ENODEV; + ret = kxcjk1013_chip_init(data); if (ret < 0) return ret; @@ -1142,12 +1209,12 @@ static int kxcjk1013_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->channels = kxcjk1013_channels; indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels); - indio_dev->name = KXCJK1013_DRV_NAME; + indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &kxcjk1013_info; if (client->irq < 0) - client->irq = kxcjk1013_acpi_gpio_probe(client, data); + client->irq = kxcjk1013_gpio_probe(client, data); if (client->irq >= 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, @@ -1325,15 +1392,17 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { }; static const struct acpi_device_id kx_acpi_match[] = { - {"KXCJ1013", 0}, - {"KXCJ1008", 0}, + {"KXCJ1013", KXCJK1013}, + {"KXCJ1008", KXCJ91008}, + {"KXTJ1009", KXTJ21009}, { }, }; MODULE_DEVICE_TABLE(acpi, kx_acpi_match); static const struct i2c_device_id kxcjk1013_id[] = { - {"kxcjk1013", 0}, - {"kxcj91008", 0}, + {"kxcjk1013", KXCJK1013}, + {"kxcj91008", KXCJ91008}, + {"kxtj21009", KXTJ21009}, {} }; From ef1c6b23355b70356ca18c0d4c39b25dfbd7be02 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Sat, 9 Aug 2014 15:05:00 +0100 Subject: [PATCH 21/35] iio: gyro: bmg160: only set power state if PM_RUNTIME is defined When CONFIG_PM_RUNTIME is not defined and bmg160 tries to power off the device, bmg160_set_power_state will call pm_runtime_put_autosuspend, which is not implemented (wil return -ENOSYS). Only call bmg160_set_power_state when CONFIG_PM_RUNTIME is defined. Signed-off-by: Irina Tirdea Acked-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/bmg160.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c index 80f92a65e020..99acf361aa53 100644 --- a/drivers/iio/gyro/bmg160.c +++ b/drivers/iio/gyro/bmg160.c @@ -237,6 +237,7 @@ static int bmg160_chip_init(struct bmg160_data *data) static int bmg160_set_power_state(struct bmg160_data *data, bool on) { +#ifdef CONFIG_PM_RUNTIME int ret; if (on) @@ -251,6 +252,7 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on) "Failed: bmg160_set_power_state for %d\n", on); return ret; } +#endif return 0; } From 48edc3748142ad393c6ee2bfcc1eb256e9f88b38 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Sat, 9 Aug 2014 15:18:00 +0100 Subject: [PATCH 22/35] iio: magn: ak8975: fix unnecessary casting between char* and const char* Use const char* instead of casting const char* to char*. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8975.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index a2357921d761..bf5ef077e791 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -477,8 +477,8 @@ static const struct acpi_device_id ak_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, ak_acpi_match); -static char *ak8975_match_acpi_device(struct device *dev, - enum asahi_compass_chipset *chipset) +static const char *ak8975_match_acpi_device(struct device *dev, + enum asahi_compass_chipset *chipset) { const struct acpi_device_id *id; @@ -487,7 +487,7 @@ static char *ak8975_match_acpi_device(struct device *dev, return NULL; *chipset = (int)id->driver_data; - return (char *)dev_name(dev); + return dev_name(dev); } static int ak8975_probe(struct i2c_client *client, @@ -497,7 +497,7 @@ static int ak8975_probe(struct i2c_client *client, struct iio_dev *indio_dev; int eoc_gpio; int err; - char *name = NULL; + const char *name = NULL; /* Grab and set up the supplied GPIO. */ if (client->dev.platform_data) @@ -539,7 +539,7 @@ static int ak8975_probe(struct i2c_client *client, if (id) { data->chipset = (enum asahi_compass_chipset)(id->driver_data); - name = (char *) id->name; + name = id->name; } else if (ACPI_HANDLE(&client->dev)) name = ak8975_match_acpi_device(&client->dev, &data->chipset); else From c9bf2373da2144dec511503cebf5f8a63b0dcff3 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sun, 9 Mar 2014 16:13:00 +0000 Subject: [PATCH 23/35] iio: accel: kxcjk-1013: Fix defined but unused warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed when compiling with CONFIG_PM_RUNTIME not set: kxcjk-1013.c: warning: ‘kxcjk1013_get_startup_times’ defined but not used [-Wunused-function] Introduced by commit 124e1b1d (iio: accel: kxcjk-1013: support runtime pm). Signed-off-by: Daniel Baluta Reviewed-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 615fce236d59..98909a9e284e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -358,6 +358,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return 0; } +#ifdef CONFIG_PM_RUNTIME static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) { int i; @@ -370,6 +371,7 @@ static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) return KXCJK1013_MAX_STARTUP_TIME_US; } +#endif static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) { From 3a0888edcffd9406f1cbbe240f4533e35db67e81 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Sun, 9 Feb 2014 11:59:00 +0000 Subject: [PATCH 24/35] iio: gyro: bmi055 gyro sensor driver Add support for the BMI055 gyroscope sensor. BMI055 is a package consisting of an acceleration sensor and a gyroscope. This patch adds support for the gyroscope only. Spec downloaded from: http://ae-bst.resource.bosch.com/media/products/dokumente/bmi055/BST-BMI055-DS000-06.pdf The BMI055 gyroscope uses the same register definition as BMG160, but does not specify a temp register. However, the temp register seems to be working in the same way as for BMG160, so this patch does not remove the temp channel for BMI055. Signed-off-by: Irina Tirdea Reviewed-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/Kconfig | 2 +- drivers/iio/gyro/bmg160.c | 39 +++++++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index d630ae987d0b..b3d0e94f72eb 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -56,7 +56,7 @@ config BMG160 select IIO_TRIGGERED_BUFFER if IIO_BUFFER help Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor - driver. + driver. This driver also supports BMI055 gyroscope. This driver can also be built as a module. If so, the module will be called bmg160. diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c index 99acf361aa53..1f967e0d688e 100644 --- a/drivers/iio/gyro/bmg160.c +++ b/drivers/iio/gyro/bmg160.c @@ -949,10 +949,10 @@ static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private) } -static int bmg160_acpi_gpio_probe(struct i2c_client *client, - struct bmg160_data *data) +static int bmg160_gpio_probe(struct i2c_client *client, + struct bmg160_data *data) + { - const struct acpi_device_id *id; struct device *dev; struct gpio_desc *gpio; int ret; @@ -961,12 +961,6 @@ static int bmg160_acpi_gpio_probe(struct i2c_client *client, return -EINVAL; dev = &client->dev; - if (!ACPI_HANDLE(dev)) - return -ENODEV; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; /* data ready gpio interrupt pin */ gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0); @@ -986,12 +980,24 @@ static int bmg160_acpi_gpio_probe(struct i2c_client *client, return ret; } +static const char *bmg160_match_acpi_device(struct device *dev) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + + return dev_name(dev); +} + static int bmg160_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bmg160_data *data; struct iio_dev *indio_dev; int ret; + const char *name = NULL; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1007,15 +1013,21 @@ static int bmg160_probe(struct i2c_client *client, mutex_init(&data->mutex); + if (id) + name = id->name; + + if (ACPI_HANDLE(&client->dev)) + name = bmg160_match_acpi_device(&client->dev); + indio_dev->dev.parent = &client->dev; indio_dev->channels = bmg160_channels; indio_dev->num_channels = ARRAY_SIZE(bmg160_channels); - indio_dev->name = BMG160_DRV_NAME; + indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmg160_info; if (client->irq <= 0) - client->irq = bmg160_acpi_gpio_probe(client, data); + client->irq = bmg160_gpio_probe(client, data); if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, @@ -1185,12 +1197,15 @@ static const struct dev_pm_ops bmg160_pm_ops = { static const struct acpi_device_id bmg160_acpi_match[] = { {"BMG0160", 0}, - { }, + {"BMI055B", 0}, + {}, }; + MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); static const struct i2c_device_id bmg160_id[] = { {"bmg160", 0}, + {"bmi055_gyro", 0}, {} }; From 16ed8692fa487c0a1569edd0e210357c087e1cc5 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 25/35] iio:bma180: Enable use of device without IRQ Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 58 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index a077cc86421b..f5e26fb697a3 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -529,7 +529,6 @@ static int bma180_probe(struct i2c_client *client, { struct bma180_data *data; struct iio_dev *indio_dev; - struct iio_trigger *trig; int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); @@ -553,30 +552,32 @@ static int bma180_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bma180_info; - trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, indio_dev->id); - if (!trig) { - ret = -ENOMEM; - goto err_chip_disable; + if (client->irq > 0) { + data->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + indio_dev->id); + if (!data->trig) { + ret = -ENOMEM; + goto err_chip_disable; + } + + ret = devm_request_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, + BMA180_IRQ_NAME, data->trig); + if (ret) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto err_trigger_free; + } + + data->trig->dev.parent = &client->dev; + data->trig->ops = &bma180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + indio_dev->trig = data->trig; + + ret = iio_trigger_register(data->trig); + if (ret) + goto err_trigger_free; } - ret = devm_request_irq(&client->dev, client->irq, - iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, BMA180_IRQ_NAME, trig); - if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - goto err_trigger_free; - } - - trig->dev.parent = &client->dev; - trig->ops = &bma180_trigger_ops; - iio_trigger_set_drvdata(trig, indio_dev); - data->trig = trig; - indio_dev->trig = trig; - - ret = iio_trigger_register(trig); - if (ret) - goto err_trigger_free; - ret = iio_triggered_buffer_setup(indio_dev, NULL, bma180_trigger_handler, NULL); if (ret < 0) { @@ -595,9 +596,10 @@ static int bma180_probe(struct i2c_client *client, err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); err_trigger_unregister: - iio_trigger_unregister(trig); + if (data->trig) + iio_trigger_unregister(data->trig); err_trigger_free: - iio_trigger_free(trig); + iio_trigger_free(data->trig); err_chip_disable: bma180_chip_disable(data); @@ -611,8 +613,10 @@ static int bma180_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); - iio_trigger_unregister(data->trig); - iio_trigger_free(data->trig); + if (data->trig) { + iio_trigger_unregister(data->trig); + iio_trigger_free(data->trig); + } mutex_lock(&data->mutex); bma180_chip_disable(data); From cab767d54daf775bc40322e9f8d4393b0c91a447 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 26/35] iio:bma180: Prefix remaining tables and functions with bma18_ and minor cleanups Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index f5e26fb697a3..d7f34b465759 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -49,7 +49,7 @@ #define BMA180_SMP_SKIP BIT(0) /* Bit masks for registers bit fields */ -#define BMA180_RANGE 0x0e /* Range of measured accel values*/ +#define BMA180_RANGE 0x0e /* Range of measured accel values */ #define BMA180_BW 0xf0 /* Accel bandwidth */ #define BMA180_MODE_CONFIG 0x03 /* Config operation modes */ @@ -93,8 +93,8 @@ enum bma180_axis { AXIS_Z, }; -static int bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ -static int scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 }; +static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ +static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 }; static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis) { @@ -107,7 +107,7 @@ static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis) ret = i2c_smbus_read_word_data(data->client, reg); if (ret < 0) dev_err(&data->client->dev, - "failed to read accel_%c registers\n", 'x' + axis); + "failed to read accel_%c register\n", 'x' + axis); return ret; } @@ -185,8 +185,8 @@ static int bma180_set_bw(struct bma180_data *data, int val) if (data->sleep_state) return -EBUSY; - for (i = 0; i < ARRAY_SIZE(bw_table); ++i) { - if (bw_table[i] == val) { + for (i = 0; i < ARRAY_SIZE(bma180_bw_table); ++i) { + if (bma180_bw_table[i] == val) { ret = bma180_set_bits(data, BMA180_BW_TCS, BMA180_BW, i); if (ret) { @@ -209,8 +209,8 @@ static int bma180_set_scale(struct bma180_data *data, int val) if (data->sleep_state) return -EBUSY; - for (i = 0; i < ARRAY_SIZE(scale_table); ++i) - if (scale_table[i] == val) { + for (i = 0; i < ARRAY_SIZE(bma180_scale_table); ++i) + if (bma180_scale_table[i] == val) { ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_RANGE, i); if (ret) { From 9a70b147da1a3cbeb3fc6434b5c13ea938e28017 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 27/35] iio:bma180: Rename BMA_180 to BMA180_ Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index d7f34b465759..284598d7cc94 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -56,7 +56,7 @@ /* We have to write this value in reset register to do soft reset */ #define BMA180_RESET_VAL 0xb6 -#define BMA_180_ID_REG_VAL 0x03 +#define BMA180_ID_REG_VAL 0x03 /* Chip power modes */ #define BMA180_LOW_NOISE 0x00 @@ -258,7 +258,7 @@ static int bma180_chip_init(struct bma180_data *data) if (ret < 0) goto err; - if (ret != BMA_180_ID_REG_VAL) { + if (ret != BMA180_ID_REG_VAL) { ret = -ENODEV; goto err; } From c7c69e8540895be5d09bf023f1b48db3cab7a78b Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 28/35] iio:bma180: Use bool instead of int for state Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 284598d7cc94..aa7566fc031f 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -62,11 +62,8 @@ #define BMA180_LOW_NOISE 0x00 #define BMA180_LOW_POWER 0x03 -#define BMA180_LOW_NOISE_STR "low_noise" -#define BMA180_LOW_POWER_STR "low_power" - /* Defaults values */ -#define BMA180_DEF_PMODE 0 +#define BMA180_DEF_PMODE false #define BMA180_DEF_BW 20 #define BMA180_DEF_SCALE 2452 @@ -80,10 +77,10 @@ struct bma180_data { struct i2c_client *client; struct iio_trigger *trig; struct mutex mutex; - int sleep_state; + bool sleep_state; int scale; int bw; - int pmode; + bool pmode; char *buff; }; @@ -133,7 +130,7 @@ static int bma180_reset_intr(struct bma180_data *data) return ret; } -static int bma180_set_new_data_intr_state(struct bma180_data *data, int state) +static int bma180_set_new_data_intr_state(struct bma180_data *data, bool state) { u8 reg_val = state ? BMA180_NEW_DATA_INT : 0x00; int ret = i2c_smbus_write_byte_data(data->client, BMA180_CTRL_REG3, @@ -153,7 +150,7 @@ err: return ret; } -static int bma180_set_sleep_state(struct bma180_data *data, int state) +static int bma180_set_sleep_state(struct bma180_data *data, bool state) { int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_SLEEP, state); @@ -167,7 +164,7 @@ static int bma180_set_sleep_state(struct bma180_data *data, int state) return 0; } -static int bma180_set_ee_writing_state(struct bma180_data *data, int state) +static int bma180_set_ee_writing_state(struct bma180_data *data, bool state) { int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_EE_W, state); @@ -225,7 +222,7 @@ static int bma180_set_scale(struct bma180_data *data, int val) return -EINVAL; } -static int bma180_set_pmode(struct bma180_data *data, int mode) +static int bma180_set_pmode(struct bma180_data *data, bool mode) { u8 reg_val = mode ? BMA180_LOW_POWER : BMA180_LOW_NOISE; int ret = bma180_set_bits(data, BMA180_TCO_Z, BMA180_MODE_CONFIG, @@ -275,10 +272,10 @@ static int bma180_chip_init(struct bma180_data *data) ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1); if (ret) goto err; - ret = bma180_set_ee_writing_state(data, 1); + ret = bma180_set_ee_writing_state(data, true); if (ret) goto err; - ret = bma180_set_new_data_intr_state(data, 0); + ret = bma180_set_new_data_intr_state(data, false); if (ret) goto err; ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_SMP_SKIP, 1); @@ -303,11 +300,11 @@ err: static void bma180_chip_disable(struct bma180_data *data) { - if (bma180_set_new_data_intr_state(data, 0)) + if (bma180_set_new_data_intr_state(data, false)) goto err; - if (bma180_set_ee_writing_state(data, 0)) + if (bma180_set_ee_writing_state(data, false)) goto err; - if (bma180_set_sleep_state(data, 1)) + if (bma180_set_sleep_state(data, true)) goto err; return; @@ -410,10 +407,7 @@ static const struct iio_info bma180_info = { .driver_module = THIS_MODULE, }; -static const char * const bma180_power_modes[] = { - BMA180_LOW_NOISE_STR, - BMA180_LOW_POWER_STR, -}; +static const char * const bma180_power_modes[] = { "low_noise", "low_power" }; static int bma180_get_power_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) @@ -633,7 +627,7 @@ static int bma180_suspend(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = bma180_set_sleep_state(data, 1); + ret = bma180_set_sleep_state(data, true); mutex_unlock(&data->mutex); return ret; @@ -646,7 +640,7 @@ static int bma180_resume(struct device *dev) int ret; mutex_lock(&data->mutex); - ret = bma180_set_sleep_state(data, 0); + ret = bma180_set_sleep_state(data, false); mutex_unlock(&data->mutex); return ret; From b81fbab7f567aaa12aba6532681b426f3e130e11 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 29/35] iio:bma180: Expose temperature channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 8-bit signed; 0 LSB @ 24 °C, 0.5 °C per LSB Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 80 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index aa7566fc031f..91260a071fe9 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -29,6 +29,7 @@ /* Register set */ #define BMA180_CHIP_ID 0x00 /* Need to distinguish BMA180 from other */ #define BMA180_ACC_X_LSB 0x02 /* First of 6 registers of accel data */ +#define BMA180_TEMP 0x08 #define BMA180_CTRL_REG0 0x0d #define BMA180_RESET 0x10 #define BMA180_BW_TCS 0x20 @@ -84,27 +85,37 @@ struct bma180_data { char *buff; }; -enum bma180_axis { +enum bma180_chan { AXIS_X, AXIS_Y, AXIS_Z, + TEMP }; static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 }; -static int bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis) +static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan) { - u8 reg = BMA180_ACC_X_LSB + axis * 2; int ret; if (data->sleep_state) return -EBUSY; - ret = i2c_smbus_read_word_data(data->client, reg); - if (ret < 0) - dev_err(&data->client->dev, - "failed to read accel_%c register\n", 'x' + axis); + switch (chan) { + case TEMP: + ret = i2c_smbus_read_byte_data(data->client, BMA180_TEMP); + if (ret < 0) + dev_err(&data->client->dev, "failed to read temp register\n"); + break; + default: + ret = i2c_smbus_read_word_data(data->client, + BMA180_ACC_X_LSB + chan * 2); + if (ret < 0) + dev_err(&data->client->dev, + "failed to read accel_%c register\n", + 'x' + chan); + } return ret; } @@ -337,22 +348,35 @@ static int bma180_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: mutex_lock(&data->mutex); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = bma180_get_acc_reg(data, chan->scan_index); + if (iio_buffer_enabled(indio_dev)) { + mutex_unlock(&data->mutex); + return -EBUSY; + } + ret = bma180_get_data_reg(data, chan->scan_index); mutex_unlock(&data->mutex); if (ret < 0) return ret; - *val = (s16)ret >> chan->scan_type.shift; + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: *val = data->bw; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - *val = 0; - *val2 = data->scale; - return IIO_VAL_INT_PLUS_MICRO; + switch (chan->type) { + case IIO_ACCEL: + *val = 0; + *val2 = data->scale; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = 500; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = 48; /* 0 LSB @ 24 degree C */ + return IIO_VAL_INT; default: return -EINVAL; } @@ -443,7 +467,7 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { { }, }; -#define BMA180_CHANNEL(_axis) { \ +#define BMA180_ACC_CHANNEL(_axis) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ @@ -460,11 +484,24 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { .ext_info = bma180_ext_info, \ } +#define BMA180_TEMP_CHANNEL { \ + .type = IIO_TEMP, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = TEMP, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 8, \ + .storagebits = 16, \ + }, \ +} + static const struct iio_chan_spec bma180_channels[] = { - BMA180_CHANNEL(X), - BMA180_CHANNEL(Y), - BMA180_CHANNEL(Z), - IIO_CHAN_SOFT_TIMESTAMP(3), + BMA180_ACC_CHANNEL(X), + BMA180_ACC_CHANNEL(Y), + BMA180_ACC_CHANNEL(Z), + BMA180_TEMP_CHANNEL, + IIO_CHAN_SOFT_TIMESTAMP(4), }; static irqreturn_t bma180_trigger_handler(int irq, void *p) @@ -479,13 +516,14 @@ static irqreturn_t bma180_trigger_handler(int irq, void *p) for_each_set_bit(bit, indio_dev->buffer->scan_mask, indio_dev->masklength) { - ret = bma180_get_acc_reg(data, bit); + ret = bma180_get_data_reg(data, bit); if (ret < 0) { mutex_unlock(&data->mutex); goto err; } ((s16 *)data->buff)[i++] = ret; } + mutex_unlock(&data->mutex); iio_push_to_buffers_with_timestamp(indio_dev, data->buff, time_ns); From b9a6a237ffc99f63fd96f3ad11b3c5c532d211f8 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 30/35] iio:bma180: Drop _update_scan_mode() statically allocate maximum size Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 91260a071fe9..583831898247 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -82,7 +82,7 @@ struct bma180_data { int scale; int bw; bool pmode; - char *buff; + u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */ }; enum bma180_chan { @@ -408,26 +408,10 @@ static int bma180_write_raw(struct iio_dev *indio_dev, } } -static int bma180_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) -{ - struct bma180_data *data = iio_priv(indio_dev); - - if (data->buff) - devm_kfree(&indio_dev->dev, data->buff); - data->buff = devm_kzalloc(&indio_dev->dev, - indio_dev->scan_bytes, GFP_KERNEL); - if (!data->buff) - return -ENOMEM; - - return 0; -} - static const struct iio_info bma180_info = { .attrs = &bma180_attrs_group, .read_raw = bma180_read_raw, .write_raw = bma180_write_raw, - .update_scan_mode = bma180_update_scan_mode, .driver_module = THIS_MODULE, }; From 1b9030f5a0ac7c71bc733af3c9c1064204fc0258 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 31/35] iio:bma180: Introduce part_info to differentiate further chip variants Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 43 +++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 583831898247..5df5991294df 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -26,6 +26,19 @@ #define BMA180_DRV_NAME "bma180" #define BMA180_IRQ_NAME "bma180_event" +enum { + BMA180, +}; + +struct bma180_part_info { + const struct iio_chan_spec *channels; + unsigned num_channels; + const int *scale_table; + unsigned num_scales; + const int *bw_table; + unsigned num_bw; +}; + /* Register set */ #define BMA180_CHIP_ID 0x00 /* Need to distinguish BMA180 from other */ #define BMA180_ACC_X_LSB 0x02 /* First of 6 registers of accel data */ @@ -77,6 +90,7 @@ struct bma180_data { struct i2c_client *client; struct iio_trigger *trig; + const struct bma180_part_info *part_info; struct mutex mutex; bool sleep_state; int scale; @@ -193,8 +207,8 @@ static int bma180_set_bw(struct bma180_data *data, int val) if (data->sleep_state) return -EBUSY; - for (i = 0; i < ARRAY_SIZE(bma180_bw_table); ++i) { - if (bma180_bw_table[i] == val) { + for (i = 0; i < data->part_info->num_bw; ++i) { + if (data->part_info->bw_table[i] == val) { ret = bma180_set_bits(data, BMA180_BW_TCS, BMA180_BW, i); if (ret) { @@ -217,8 +231,8 @@ static int bma180_set_scale(struct bma180_data *data, int val) if (data->sleep_state) return -EBUSY; - for (i = 0; i < ARRAY_SIZE(bma180_scale_table); ++i) - if (bma180_scale_table[i] == val) { + for (i = 0; i < data->part_info->num_scales; ++i) + if (data->part_info->scale_table[i] == val) { ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_RANGE, i); if (ret) { @@ -488,6 +502,14 @@ static const struct iio_chan_spec bma180_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; +static const struct bma180_part_info bma180_part_info[] = { + [BMA180] = { + bma180_channels, ARRAY_SIZE(bma180_channels), + bma180_scale_table, ARRAY_SIZE(bma180_scale_table), + bma180_bw_table, ARRAY_SIZE(bma180_bw_table), + }, +}; + static irqreturn_t bma180_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -554,6 +576,7 @@ static int bma180_probe(struct i2c_client *client, data = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); data->client = client; + data->part_info = &bma180_part_info[id->driver_data]; ret = bma180_chip_init(data); if (ret < 0) @@ -562,8 +585,8 @@ static int bma180_probe(struct i2c_client *client, mutex_init(&data->mutex); indio_dev->dev.parent = &client->dev; - indio_dev->channels = bma180_channels; - indio_dev->num_channels = ARRAY_SIZE(bma180_channels); + indio_dev->channels = data->part_info->channels; + indio_dev->num_channels = data->part_info->num_channels; indio_dev->name = BMA180_DRV_NAME; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bma180_info; @@ -674,12 +697,12 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); #define BMA180_PM_OPS NULL #endif -static struct i2c_device_id bma180_id[] = { - { BMA180_DRV_NAME, 0 }, +static struct i2c_device_id bma180_ids[] = { + { BMA180_DRV_NAME, BMA180 }, { } }; -MODULE_DEVICE_TABLE(i2c, bma180_id); +MODULE_DEVICE_TABLE(i2c, bma180_ids); static struct i2c_driver bma180_driver = { .driver = { @@ -689,7 +712,7 @@ static struct i2c_driver bma180_driver = { }, .probe = bma180_probe, .remove = bma180_remove, - .id_table = bma180_id, + .id_table = bma180_ids, }; module_i2c_driver(bma180_driver); From c1949ec18e50e1e23f3045a7c3836c289f553bb8 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 32/35] iio:bma180: Introduce part-specific _config() and disable() code move part of bma180_init() to bma180_config() (split initialization and configuration code); configuration is heavily chip-specific Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 5df5991294df..933645547f82 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -30,6 +30,8 @@ enum { BMA180, }; +struct bma180_data; + struct bma180_part_info { const struct iio_chan_spec *channels; unsigned num_channels; @@ -37,6 +39,8 @@ struct bma180_part_info { unsigned num_scales; const int *bw_table; unsigned num_bw; + int (*chip_config)(struct bma180_data *data); + void (*chip_disable)(struct bma180_data *data); }; /* Register set */ @@ -279,21 +283,28 @@ static int bma180_chip_init(struct bma180_data *data) int ret = i2c_smbus_read_byte_data(data->client, BMA180_CHIP_ID); if (ret < 0) - goto err; - if (ret != BMA180_ID_REG_VAL) { - ret = -ENODEV; - goto err; - } + return ret; + if (ret != BMA180_ID_REG_VAL) + return -ENODEV; ret = bma180_soft_reset(data); if (ret) - goto err; + return ret; /* * No serial transaction should occur within minimum 10 us * after soft_reset command */ msleep(20); + return 0; +} + +static int bma180_chip_config(struct bma180_data *data) +{ + int ret = bma180_chip_init(data); + + if (ret) + goto err; ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1); if (ret) goto err; @@ -319,7 +330,7 @@ static int bma180_chip_init(struct bma180_data *data) return 0; err: - dev_err(&data->client->dev, "failed to init the chip\n"); + dev_err(&data->client->dev, "failed to config the chip\n"); return ret; } @@ -507,6 +518,8 @@ static const struct bma180_part_info bma180_part_info[] = { bma180_channels, ARRAY_SIZE(bma180_channels), bma180_scale_table, ARRAY_SIZE(bma180_scale_table), bma180_bw_table, ARRAY_SIZE(bma180_bw_table), + bma180_chip_config, + bma180_chip_disable, }, }; @@ -578,7 +591,7 @@ static int bma180_probe(struct i2c_client *client, data->client = client; data->part_info = &bma180_part_info[id->driver_data]; - ret = bma180_chip_init(data); + ret = data->part_info->chip_config(data); if (ret < 0) goto err_chip_disable; @@ -640,7 +653,7 @@ err_trigger_unregister: err_trigger_free: iio_trigger_free(data->trig); err_chip_disable: - bma180_chip_disable(data); + data->part_info->chip_disable(data); return ret; } @@ -658,7 +671,7 @@ static int bma180_remove(struct i2c_client *client) } mutex_lock(&data->mutex); - bma180_chip_disable(data); + data->part_info->chip_disable(data); mutex_unlock(&data->mutex); return 0; From 6377aa496a0bc40af4f66574c813bb9a807a7e3a Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 33/35] iio:bma180: Prepare for accelerometer channels with different resolutions allow to specify channels resolution and compute shift assuming 16-bit registers and MSB allocation Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 933645547f82..f4d280456dd7 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -476,7 +476,7 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { { }, }; -#define BMA180_ACC_CHANNEL(_axis) { \ +#define BMA180_ACC_CHANNEL(_axis, _bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ @@ -486,9 +486,9 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ - .realbits = 14, \ + .realbits = _bits, \ .storagebits = 16, \ - .shift = 2, \ + .shift = 16 - _bits, \ }, \ .ext_info = bma180_ext_info, \ } @@ -506,9 +506,9 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { } static const struct iio_chan_spec bma180_channels[] = { - BMA180_ACC_CHANNEL(X), - BMA180_ACC_CHANNEL(Y), - BMA180_ACC_CHANNEL(Z), + BMA180_ACC_CHANNEL(X, 14), + BMA180_ACC_CHANNEL(Y, 14), + BMA180_ACC_CHANNEL(Z, 14), BMA180_TEMP_CHANNEL, IIO_CHAN_SOFT_TIMESTAMP(4), }; From 402a324e6103c234f73564a3a611766414b6325b Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 34/35] iio:bma180: Implement _available sysfs attribute dynamically makes it easier to add more chip variants and removes redundancy: scales and frequencies are now stated just once Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bma180.c | 54 ++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index f4d280456dd7..a543cffb4ec3 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -85,12 +85,6 @@ struct bma180_part_info { #define BMA180_DEF_BW 20 #define BMA180_DEF_SCALE 2452 -/* Available values for sysfs */ -#define BMA180_FLP_FREQ_AVAILABLE \ - "10 20 40 75 150 300" -#define BMA180_SCALE_AVAILABLE \ - "0.001275 0.001863 0.002452 0.003727 0.004903 0.009709 0.019417" - struct bma180_data { struct i2c_client *client; struct iio_trigger *trig; @@ -349,13 +343,51 @@ err: dev_err(&data->client->dev, "failed to disable the chip\n"); } -static IIO_CONST_ATTR(in_accel_filter_low_pass_3db_frequency_available, - BMA180_FLP_FREQ_AVAILABLE); -static IIO_CONST_ATTR(in_accel_scale_available, BMA180_SCALE_AVAILABLE); +static ssize_t bma180_show_avail(char *buf, const int *vals, unsigned n, + bool micros) +{ + size_t len = 0; + int i; + + for (i = 0; i < n; i++) { + if (!vals[i]) + continue; + len += scnprintf(buf + len, PAGE_SIZE - len, + micros ? "0.%06d " : "%d ", vals[i]); + } + buf[len - 1] = '\n'; + + return len; +} + +static ssize_t bma180_show_filter_freq_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bma180_data *data = iio_priv(dev_to_iio_dev(dev)); + + return bma180_show_avail(buf, data->part_info->bw_table, + data->part_info->num_bw, false); +} + +static ssize_t bma180_show_scale_avail(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bma180_data *data = iio_priv(dev_to_iio_dev(dev)); + + return bma180_show_avail(buf, data->part_info->scale_table, + data->part_info->num_scales, true); +} + +static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available, + S_IRUGO, bma180_show_filter_freq_avail, NULL, 0); + +static IIO_DEVICE_ATTR(in_accel_scale_available, + S_IRUGO, bma180_show_scale_avail, NULL, 0); static struct attribute *bma180_attributes[] = { - &iio_const_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr, - &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available. + dev_attr.attr, + &iio_dev_attr_in_accel_scale_available.dev_attr.attr, NULL, }; From 2017cff24cc08b145bff7256dd6b0ef99e7e8a01 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Tue, 19 Aug 2014 23:43:00 +0100 Subject: [PATCH 35/35] iio:bma180: Add BMA250 chip support the BMA250 has only 10-bit resolution; while the data readout registers have identical layout, the configuration is completely different compared to the BMA180 datasheet: http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/BST-BMA250-DS002-05.pdf Signed-off-by: Peter Meerwald Cc: Oleksandr Kravchenko Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 6 +- drivers/iio/accel/bma180.c | 158 +++++++++++++++++++++++++++++-------- 2 files changed, 129 insertions(+), 35 deletions(-) diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index f71efc8d3f3e..9b9be8725e9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -6,13 +6,13 @@ menu "Accelerometers" config BMA180 - tristate "Bosch BMA180 3-Axis Accelerometer Driver" + tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say Y here if you want to build a driver for the Bosch BMA180 - triaxial acceleration sensor. + Say Y here if you want to build a driver for the Bosch BMA180 or + BMA250 triaxial acceleration sensor. To compile this driver as a module, choose M here: the module will be called bma180. diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index a543cffb4ec3..6ef19641457c 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -3,9 +3,15 @@ * * Copyright 2013 Oleksandr Kravchenko * + * Support for BMA250 (c) Peter Meerwald + * * This file is subject to the terms and conditions of version 2 of * the GNU General Public License. See the file COPYING in the main * directory of this archive for more details. + * + * SPI is not supported by driver + * BMA180: 7-bit I2C slave address 0x40 or 0x41 + * BMA250: 7-bit I2C slave address 0x18 or 0x19 */ #include @@ -28,6 +34,7 @@ enum { BMA180, + BMA250, }; struct bma180_data; @@ -39,6 +46,15 @@ struct bma180_part_info { unsigned num_scales; const int *bw_table; unsigned num_bw; + + u8 int_reset_reg, int_reset_mask; + u8 sleep_reg, sleep_mask; + u8 bw_reg, bw_mask; + u8 scale_reg, scale_mask; + u8 power_reg, power_mask, lowpower_val; + u8 int_enable_reg, int_enable_mask; + u8 softreset_reg; + int (*chip_config)(struct bma180_data *data); void (*chip_disable)(struct bma180_data *data); }; @@ -77,13 +93,23 @@ struct bma180_part_info { #define BMA180_ID_REG_VAL 0x03 /* Chip power modes */ -#define BMA180_LOW_NOISE 0x00 #define BMA180_LOW_POWER 0x03 -/* Defaults values */ -#define BMA180_DEF_PMODE false -#define BMA180_DEF_BW 20 -#define BMA180_DEF_SCALE 2452 +#define BMA250_RANGE_REG 0x0f +#define BMA250_BW_REG 0x10 +#define BMA250_POWER_REG 0x11 +#define BMA250_RESET_REG 0x14 +#define BMA250_INT_ENABLE_REG 0x17 +#define BMA250_INT_MAP_REG 0x1a +#define BMA250_INT_RESET_REG 0x21 + +#define BMA250_RANGE_MASK GENMASK(3, 0) /* Range of accel values */ +#define BMA250_BW_MASK GENMASK(4, 0) /* Accel bandwidth */ +#define BMA250_SUSPEND_MASK BIT(7) /* chip will sleep */ +#define BMA250_LOWPOWER_MASK BIT(6) +#define BMA250_DATA_INTEN_MASK BIT(4) +#define BMA250_INT1_DATA_MASK BIT(0) +#define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */ struct bma180_data { struct i2c_client *client; @@ -107,6 +133,10 @@ enum bma180_chan { static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */ static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 }; +static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */ +static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0, + 0, 0, 306458 }; + static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan) { int ret; @@ -145,7 +175,8 @@ static int bma180_set_bits(struct bma180_data *data, u8 reg, u8 mask, u8 val) static int bma180_reset_intr(struct bma180_data *data) { - int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_RESET_INT, 1); + int ret = bma180_set_bits(data, data->part_info->int_reset_reg, + data->part_info->int_reset_mask, 1); if (ret) dev_err(&data->client->dev, "failed to reset interrupt\n"); @@ -155,10 +186,8 @@ static int bma180_reset_intr(struct bma180_data *data) static int bma180_set_new_data_intr_state(struct bma180_data *data, bool state) { - u8 reg_val = state ? BMA180_NEW_DATA_INT : 0x00; - int ret = i2c_smbus_write_byte_data(data->client, BMA180_CTRL_REG3, - reg_val); - + int ret = bma180_set_bits(data, data->part_info->int_enable_reg, + data->part_info->int_enable_mask, state); if (ret) goto err; ret = bma180_reset_intr(data); @@ -175,7 +204,8 @@ err: static int bma180_set_sleep_state(struct bma180_data *data, bool state) { - int ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_SLEEP, state); + int ret = bma180_set_bits(data, data->part_info->sleep_reg, + data->part_info->sleep_mask, state); if (ret) { dev_err(&data->client->dev, @@ -207,8 +237,8 @@ static int bma180_set_bw(struct bma180_data *data, int val) for (i = 0; i < data->part_info->num_bw; ++i) { if (data->part_info->bw_table[i] == val) { - ret = bma180_set_bits(data, - BMA180_BW_TCS, BMA180_BW, i); + ret = bma180_set_bits(data, data->part_info->bw_reg, + data->part_info->bw_mask, i); if (ret) { dev_err(&data->client->dev, "failed to set bandwidth\n"); @@ -231,8 +261,8 @@ static int bma180_set_scale(struct bma180_data *data, int val) for (i = 0; i < data->part_info->num_scales; ++i) if (data->part_info->scale_table[i] == val) { - ret = bma180_set_bits(data, - BMA180_OFFSET_LSB1, BMA180_RANGE, i); + ret = bma180_set_bits(data, data->part_info->scale_reg, + data->part_info->scale_mask, i); if (ret) { dev_err(&data->client->dev, "failed to set scale\n"); @@ -247,9 +277,9 @@ static int bma180_set_scale(struct bma180_data *data, int val) static int bma180_set_pmode(struct bma180_data *data, bool mode) { - u8 reg_val = mode ? BMA180_LOW_POWER : BMA180_LOW_NOISE; - int ret = bma180_set_bits(data, BMA180_TCO_Z, BMA180_MODE_CONFIG, - reg_val); + u8 reg_val = mode ? data->part_info->lowpower_val : 0; + int ret = bma180_set_bits(data, data->part_info->power_reg, + data->part_info->power_mask, reg_val); if (ret) { dev_err(&data->client->dev, "failed to set power mode\n"); @@ -263,7 +293,7 @@ static int bma180_set_pmode(struct bma180_data *data, bool mode) static int bma180_soft_reset(struct bma180_data *data) { int ret = i2c_smbus_write_byte_data(data->client, - BMA180_RESET, BMA180_RESET_VAL); + data->part_info->softreset_reg, BMA180_RESET_VAL); if (ret) dev_err(&data->client->dev, "failed to reset the chip\n"); @@ -290,7 +320,11 @@ static int bma180_chip_init(struct bma180_data *data) */ msleep(20); - return 0; + ret = bma180_set_new_data_intr_state(data, false); + if (ret) + return ret; + + return bma180_set_pmode(data, false); } static int bma180_chip_config(struct bma180_data *data) @@ -303,21 +337,39 @@ static int bma180_chip_config(struct bma180_data *data) if (ret) goto err; ret = bma180_set_ee_writing_state(data, true); - if (ret) - goto err; - ret = bma180_set_new_data_intr_state(data, false); if (ret) goto err; ret = bma180_set_bits(data, BMA180_OFFSET_LSB1, BMA180_SMP_SKIP, 1); if (ret) goto err; - ret = bma180_set_pmode(data, BMA180_DEF_PMODE); + ret = bma180_set_bw(data, 20); /* 20 Hz */ if (ret) goto err; - ret = bma180_set_bw(data, BMA180_DEF_BW); + ret = bma180_set_scale(data, 2452); /* 2 G */ if (ret) goto err; - ret = bma180_set_scale(data, BMA180_DEF_SCALE); + + return 0; + +err: + dev_err(&data->client->dev, "failed to config the chip\n"); + return ret; +} + +static int bma250_chip_config(struct bma180_data *data) +{ + int ret = bma180_chip_init(data); + + if (ret) + goto err; + ret = bma180_set_bw(data, 16); /* 16 Hz */ + if (ret) + goto err; + ret = bma180_set_scale(data, 38344); /* 2 G */ + if (ret) + goto err; + ret = bma180_set_bits(data, BMA250_INT_MAP_REG, + BMA250_INT1_DATA_MASK, 1); if (ret) goto err; @@ -343,6 +395,19 @@ err: dev_err(&data->client->dev, "failed to disable the chip\n"); } +static void bma250_chip_disable(struct bma180_data *data) +{ + if (bma180_set_new_data_intr_state(data, false)) + goto err; + if (bma180_set_sleep_state(data, true)) + goto err; + + return; + +err: + dev_err(&data->client->dev, "failed to disable the chip\n"); +} + static ssize_t bma180_show_avail(char *buf, const int *vals, unsigned n, bool micros) { @@ -545,14 +610,43 @@ static const struct iio_chan_spec bma180_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(4), }; +static const struct iio_chan_spec bma250_channels[] = { + BMA180_ACC_CHANNEL(X, 10), + BMA180_ACC_CHANNEL(Y, 10), + BMA180_ACC_CHANNEL(Z, 10), + BMA180_TEMP_CHANNEL, + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + static const struct bma180_part_info bma180_part_info[] = { [BMA180] = { bma180_channels, ARRAY_SIZE(bma180_channels), bma180_scale_table, ARRAY_SIZE(bma180_scale_table), bma180_bw_table, ARRAY_SIZE(bma180_bw_table), + BMA180_CTRL_REG0, BMA180_RESET_INT, + BMA180_CTRL_REG0, BMA180_SLEEP, + BMA180_BW_TCS, BMA180_BW, + BMA180_OFFSET_LSB1, BMA180_RANGE, + BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER, + BMA180_CTRL_REG3, BMA180_NEW_DATA_INT, + BMA180_RESET, bma180_chip_config, bma180_chip_disable, }, + [BMA250] = { + bma250_channels, ARRAY_SIZE(bma250_channels), + bma250_scale_table, ARRAY_SIZE(bma250_scale_table), + bma250_bw_table, ARRAY_SIZE(bma250_bw_table), + BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK, + BMA250_POWER_REG, BMA250_SUSPEND_MASK, + BMA250_BW_REG, BMA250_BW_MASK, + BMA250_RANGE_REG, BMA250_RANGE_MASK, + BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1, + BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK, + BMA250_RESET_REG, + bma250_chip_config, + bma250_chip_disable, + }, }; static irqreturn_t bma180_trigger_handler(int irq, void *p) @@ -628,11 +722,10 @@ static int bma180_probe(struct i2c_client *client, goto err_chip_disable; mutex_init(&data->mutex); - indio_dev->dev.parent = &client->dev; indio_dev->channels = data->part_info->channels; indio_dev->num_channels = data->part_info->num_channels; - indio_dev->name = BMA180_DRV_NAME; + indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bma180_info; @@ -646,7 +739,7 @@ static int bma180_probe(struct i2c_client *client, ret = devm_request_irq(&client->dev, client->irq, iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, - BMA180_IRQ_NAME, data->trig); + "bma180_event", data->trig); if (ret) { dev_err(&client->dev, "unable to request IRQ\n"); goto err_trigger_free; @@ -743,7 +836,8 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume); #endif static struct i2c_device_id bma180_ids[] = { - { BMA180_DRV_NAME, BMA180 }, + { "bma180", BMA180 }, + { "bma250", BMA250 }, { } }; @@ -751,7 +845,7 @@ MODULE_DEVICE_TABLE(i2c, bma180_ids); static struct i2c_driver bma180_driver = { .driver = { - .name = BMA180_DRV_NAME, + .name = "bma180", .owner = THIS_MODULE, .pm = BMA180_PM_OPS, }, @@ -764,5 +858,5 @@ module_i2c_driver(bma180_driver); MODULE_AUTHOR("Kravchenko Oleksandr "); MODULE_AUTHOR("Texas Instruments, Inc."); -MODULE_DESCRIPTION("Bosch BMA180 triaxial acceleration sensor"); +MODULE_DESCRIPTION("Bosch BMA180/BMA250 triaxial acceleration sensor"); MODULE_LICENSE("GPL");