diff options
Diffstat (limited to 'drivers/iio')
42 files changed, 5142 insertions, 332 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 12addf272a61..9b9be8725e9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -6,17 +6,32 @@ 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. +config BMC150_ACCEL + tristate "Bosch BMC150 Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the following Bosch accelerometers: + BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. + + Currently this only supports the device via an i2c interface. + + This is a combo module with both accelerometer and magnetometer. + This driver is only implementing accelerometer part, which has + its own address and register map. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER @@ -84,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. + 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/Makefile b/drivers/iio/accel/Makefile index 6578ca1a8e09..a593996c6539 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o +obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 19100fddd2ed..f081b007f7d2 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -3,9 +3,15 @@ * * Copyright 2013 Oleksandr Kravchenko <x0199363@ti.com> * + * Support for BMA250 (c) Peter Meerwald <pmeerw@pmeerw.net> + * * 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 <linux/module.h> @@ -26,9 +32,37 @@ #define BMA180_DRV_NAME "bma180" #define BMA180_IRQ_NAME "bma180_event" +enum { + BMA180, + BMA250, +}; + +struct bma180_data; + +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; + + 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); +}; + /* 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 @@ -49,65 +83,81 @@ #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 */ /* 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 #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_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" +#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; struct iio_trigger *trig; + const struct bma180_part_info *part_info; struct mutex mutex; - int sleep_state; + bool sleep_state; int scale; int bw; - int pmode; - char *buff; + bool pmode; + u8 buff[16]; /* 3x 16-bit + 8-bit + padding + timestamp */ }; -enum bma180_axis { +enum bma180_chan { AXIS_X, AXIS_Y, AXIS_Z, + TEMP }; -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 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_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 registers\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; } @@ -125,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"); @@ -133,12 +184,10 @@ 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, - 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); @@ -153,9 +202,10 @@ 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); + int ret = bma180_set_bits(data, data->part_info->sleep_reg, + data->part_info->sleep_mask, state); if (ret) { dev_err(&data->client->dev, @@ -167,7 +217,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); @@ -185,10 +235,10 @@ 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) { - ret = bma180_set_bits(data, - BMA180_BW_TCS, BMA180_BW, i); + for (i = 0; i < data->part_info->num_bw; ++i) { + if (data->part_info->bw_table[i] == val) { + 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"); @@ -209,10 +259,10 @@ 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) { - ret = bma180_set_bits(data, - BMA180_OFFSET_LSB1, BMA180_RANGE, i); + for (i = 0; i < data->part_info->num_scales; ++i) + if (data->part_info->scale_table[i] == val) { + 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"); @@ -225,11 +275,11 @@ 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, - 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"); @@ -243,7 +293,7 @@ static int bma180_set_pmode(struct bma180_data *data, int 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"); @@ -257,57 +307,99 @@ 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 != BMA_180_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); - ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1); + 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) +{ + int ret = bma180_chip_init(data); + if (ret) goto err; - ret = bma180_set_ee_writing_state(data, 1); + ret = bma180_set_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1); if (ret) goto err; - ret = bma180_set_new_data_intr_state(data, 0); + ret = bma180_set_ee_writing_state(data, true); 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; + + 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_scale(data, BMA180_DEF_SCALE); + 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; 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; } 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, true)) + goto err; + + return; + +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, 1)) + if (bma180_set_sleep_state(data, true)) goto err; return; @@ -316,13 +408,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, }; @@ -340,22 +470,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; } @@ -387,33 +530,14 @@ 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, }; -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) @@ -449,7 +573,7 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { { }, }; -#define BMA180_CHANNEL(_axis) { \ +#define BMA180_ACC_CHANNEL(_axis, _bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ @@ -459,18 +583,70 @@ 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, \ } +#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, 14), + BMA180_ACC_CHANNEL(Y, 14), + BMA180_ACC_CHANNEL(Z, 14), + BMA180_TEMP_CHANNEL, + 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) @@ -485,13 +661,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); @@ -529,7 +706,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)); @@ -539,43 +715,45 @@ 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); + ret = data->part_info->chip_config(data); if (ret < 0) goto err_chip_disable; 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->name = BMA180_DRV_NAME; + indio_dev->channels = data->part_info->channels; + indio_dev->num_channels = data->part_info->num_channels; + indio_dev->name = id->name; 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, trig); - if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - goto err_trigger_free; - } + ret = devm_request_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, + "bma180_event", data->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 = iio_trigger_get(trig); + data->trig->dev.parent = &client->dev; + data->trig->ops = &bma180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + indio_dev->trig = iio_trigger_get(trig); - ret = iio_trigger_register(trig); - if (ret) - goto err_trigger_free; + ret = iio_trigger_register(data->trig); + if (ret) + goto err_trigger_free; + } ret = iio_triggered_buffer_setup(indio_dev, NULL, bma180_trigger_handler, NULL); @@ -595,11 +773,12 @@ 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); + data->part_info->chip_disable(data); return ret; } @@ -611,11 +790,13 @@ 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); + data->part_info->chip_disable(data); mutex_unlock(&data->mutex); return 0; @@ -629,7 +810,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; @@ -642,7 +823,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; @@ -654,27 +835,28 @@ 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", BMA180 }, + { "bma250", BMA250 }, { } }; -MODULE_DEVICE_TABLE(i2c, bma180_id); +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, }, .probe = bma180_probe, .remove = bma180_remove, - .id_table = bma180_id, + .id_table = bma180_ids, }; module_i2c_driver(bma180_driver); MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>"); MODULE_AUTHOR("Texas Instruments, Inc."); -MODULE_DESCRIPTION("Bosch BMA180 triaxial acceleration sensor"); +MODULE_DESCRIPTION("Bosch BMA180/BMA250 triaxial acceleration sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c new file mode 100644 index 000000000000..22c096ce39ad --- /dev/null +++ b/drivers/iio/accel/bmc150-accel.c @@ -0,0 +1,1430 @@ +/* + * 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 + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define BMC150_ACCEL_DRV_NAME "bmc150_accel" +#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" +#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" + +#define BMC150_ACCEL_REG_CHIP_ID 0x00 + +#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B +#define BMC150_ACCEL_ANY_MOTION_MASK 0x07 +#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) + +#define BMC150_ACCEL_REG_PMU_LPW 0x11 +#define BMC150_ACCEL_PMU_MODE_MASK 0xE0 +#define BMC150_ACCEL_PMU_MODE_SHIFT 5 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK 0x17 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT 1 + +#define BMC150_ACCEL_REG_PMU_RANGE 0x0F + +#define BMC150_ACCEL_DEF_RANGE_2G 0x03 +#define BMC150_ACCEL_DEF_RANGE_4G 0x05 +#define BMC150_ACCEL_DEF_RANGE_8G 0x08 +#define BMC150_ACCEL_DEF_RANGE_16G 0x0C + +/* Default BW: 125Hz */ +#define BMC150_ACCEL_REG_PMU_BW 0x10 +#define BMC150_ACCEL_DEF_BW 125 + +#define BMC150_ACCEL_REG_INT_MAP_0 0x19 +#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) + +#define BMC150_ACCEL_REG_INT_MAP_1 0x1A +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) + +#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 +#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 +#define BMC150_ACCEL_INT_MODE_LATCH_INT 0x0F +#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT 0x00 + +#define BMC150_ACCEL_REG_INT_EN_0 0x16 +#define BMC150_ACCEL_INT_EN_BIT_SLP_X BIT(0) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Y BIT(1) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2) + +#define BMC150_ACCEL_REG_INT_EN_1 0x17 +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4) + +#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 +#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) + +#define BMC150_ACCEL_REG_INT_5 0x27 +#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 + +#define BMC150_ACCEL_REG_INT_6 0x28 +#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF + +/* Slope duration in terms of number of samples */ +#define BMC150_ACCEL_DEF_SLOPE_DURATION 2 +/* in terms of multiples of g's/LSB, based on range */ +#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 5 + +#define BMC150_ACCEL_REG_XOUT_L 0x02 + +#define BMC150_ACCEL_MAX_STARTUP_TIME_MS 100 + +/* Sleep Duration values */ +#define BMC150_ACCEL_SLEEP_500_MICRO 0x05 +#define BMC150_ACCEL_SLEEP_1_MS 0x06 +#define BMC150_ACCEL_SLEEP_2_MS 0x07 +#define BMC150_ACCEL_SLEEP_4_MS 0x08 +#define BMC150_ACCEL_SLEEP_6_MS 0x09 +#define BMC150_ACCEL_SLEEP_10_MS 0x0A +#define BMC150_ACCEL_SLEEP_25_MS 0x0B +#define BMC150_ACCEL_SLEEP_50_MS 0x0C +#define BMC150_ACCEL_SLEEP_100_MS 0x0D +#define BMC150_ACCEL_SLEEP_500_MS 0x0E +#define BMC150_ACCEL_SLEEP_1_SEC 0x0F + +#define BMC150_ACCEL_REG_TEMP 0x08 +#define BMC150_ACCEL_TEMP_CENTER_VAL 24 + +#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) +#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 + +enum bmc150_accel_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum bmc150_power_modes { + BMC150_ACCEL_SLEEP_MODE_NORMAL, + BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, + BMC150_ACCEL_SLEEP_MODE_LPM, + 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; + struct iio_trigger *motion_trig; + struct mutex mutex; + s16 buffer[8]; + u8 bw_bits; + u32 slope_dur; + u32 slope_thres; + u32 range; + int ev_enable_state; + bool dready_trigger_on; + bool motion_trigger_on; + int64_t timestamp; + const struct bmc150_accel_chip_info *chip_info; +}; + +static const struct { + int val; + int val2; + u8 bw_bits; +} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08}, + {15, 630000, 0x09}, + {31, 250000, 0x0A}, + {62, 500000, 0x0B}, + {125, 0, 0x0C}, + {250, 0, 0x0D}, + {500, 0, 0x0E}, + {1000, 0, 0x0F} }; + +static const struct { + int bw_bits; + int msec; +} bmc150_accel_sample_upd_time[] = { {0x08, 64}, + {0x09, 32}, + {0x0A, 16}, + {0x0B, 8}, + {0x0C, 4}, + {0x0D, 2}, + {0x0E, 1}, + {0x0F, 1} }; + +static const struct { + int sleep_dur; + u8 reg_value; +} bmc150_accel_sleep_value_table[] = { {0, 0}, + {500, BMC150_ACCEL_SLEEP_500_MICRO}, + {1000, BMC150_ACCEL_SLEEP_1_MS}, + {2000, BMC150_ACCEL_SLEEP_2_MS}, + {4000, BMC150_ACCEL_SLEEP_4_MS}, + {6000, BMC150_ACCEL_SLEEP_6_MS}, + {10000, BMC150_ACCEL_SLEEP_10_MS}, + {25000, BMC150_ACCEL_SLEEP_25_MS}, + {50000, BMC150_ACCEL_SLEEP_50_MS}, + {100000, BMC150_ACCEL_SLEEP_100_MS}, + {500000, BMC150_ACCEL_SLEEP_500_MS}, + {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; + + +static int bmc150_accel_set_mode(struct bmc150_accel_data *data, + enum bmc150_power_modes mode, + int dur_us) +{ + int i; + int ret; + u8 lpw_bits; + int dur_val = -1; + + if (dur_us > 0) { + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table); + ++i) { + if (bmc150_accel_sleep_value_table[i].sleep_dur == + dur_us) + dur_val = + bmc150_accel_sleep_value_table[i].reg_value; + } + } else + dur_val = 0; + + if (dur_val < 0) + return -EINVAL; + + lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; + lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); + + dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits); + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_LPW, lpw_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, + int val2) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].val == val && + bmc150_accel_samp_freq_table[i].val2 == val2) { + ret = i2c_smbus_write_byte_data( + data->client, + BMC150_ACCEL_REG_PMU_BW, + bmc150_accel_samp_freq_table[i].bw_bits); + if (ret < 0) + return ret; + + data->bw_bits = + bmc150_accel_samp_freq_table[i].bw_bits; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, + "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != data->chip_info->chip_id) { + dev_err(&data->client->dev, "Invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration */ + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_5\n"); + return ret; + } + data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_5, + data->slope_dur); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_5\n"); + return ret; + } + dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur); + + /* Set default slope thresholds */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_6, + BMC150_ACCEL_DEF_SLOPE_THRESHOLD); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_6\n"); + return ret; + } + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres); + + /* Set default as latched interrupts */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_setup_any_motion_interrupt( + struct bmc150_accel_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT1 mapping */ + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_0); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map_0\n"); + return ret; + } + if (status) + ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; + else + ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_0, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map_0\n"); + return ret; + } + + if (status) { + /* Set slope duration (no of samples) */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_5, + data->slope_dur); + if (ret < 0) { + dev_err(&data->client->dev, "Error write reg_int_5\n"); + return ret; + } + + /* Set slope thresholds */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_6, + data->slope_thres); + if (ret < 0) { + dev_err(&data->client->dev, "Error write reg_int_6\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, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_0, + BMC150_ACCEL_INT_EN_BIT_SLP_X | + BMC150_ACCEL_INT_EN_BIT_SLP_Y | + BMC150_ACCEL_INT_EN_BIT_SLP_Z); + } else + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_0, + 0); + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en_0\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT1 mapping */ + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map_1\n"); + return ret; + } + if (status) + ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA; + else + ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA; + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map_1\n"); + return ret; + } + + if (status) { + /* + * Set non latched mode interrupt and clear any latched + * interrupt + */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_NON_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_1, + BMC150_ACCEL_INT_EN_BIT_DATA_EN); + + } else { + /* Restore default interrupt mode */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_1, + 0); + } + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en_1\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, + int *val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) { + *val = bmc150_accel_samp_freq_table[i].val; + *val2 = bmc150_accel_samp_freq_table[i].val2; + return IIO_VAL_INT_PLUS_MICRO; + } + } + + return -EINVAL; +} + +#ifdef CONFIG_PM_RUNTIME +static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) { + if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits) + return bmc150_accel_sample_upd_time[i].msec; + } + + return BMC150_ACCEL_MAX_STARTUP_TIME_MS; +} + +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + int ret; + + if (on) + ret = pm_runtime_get_sync(&data->client->dev); + 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: bmc150_accel_set_power_state for %d\n", on); + return ret; + } + + 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) +{ + int ret, i; + + 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, + 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 = data->chip_info->scale_table[i].reg_range; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) +{ + int ret; + + mutex_lock(&data->mutex); + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_temp\n"); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret, 7); + + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; +} + +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); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = i2c_smbus_read_word_data(data->client, + BMC150_ACCEL_AXIS_TO_REG(axis)); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading axis %d\n", axis); + bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + ret = bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + return IIO_VAL_INT; +} + +static int bmc150_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + return bmc150_accel_get_temp(data, val); + case IIO_ACCEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + else + return bmc150_accel_get_axis(data, chan, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = BMC150_ACCEL_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_ACCEL: + { + int i; + const struct bmc150_scale_info *si; + int st_size = ARRAY_SIZE(data->chip_info->scale_table); + + 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; + } + } + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_get_bw(data, val, val2); + mutex_unlock(&data->mutex); + return ret; + default: + return -EINVAL; + } +} + +static int bmc150_accel_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_set_bw(data, val, val2); + mutex_unlock(&data->mutex); + break; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = bmc150_accel_set_scale(data, val2); + mutex_unlock(&data->mutex); + return ret; + default: + ret = -EINVAL; + } + + return ret; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + *val2 = 0; + switch (info) { + case IIO_EV_INFO_VALUE: + *val = data->slope_thres; + break; + case IIO_EV_INFO_PERIOD: + *val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + if (data->ev_enable_state) + return -EBUSY; + + switch (info) { + case IIO_EV_INFO_VALUE: + data->slope_thres = val; + break; + case IIO_EV_INFO_PERIOD: + data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK; + data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + return data->ev_enable_state; +} + +static int bmc150_accel_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 bmc150_accel_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 = bmc150_accel_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = bmc150_accel_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 bmc150_accel_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct bmc150_accel_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( + "7.810000 15.630000 31.250000 62.500000 125 250 500 1000"); + +static struct attribute *bmc150_accel_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmc150_accel_attrs_group = { + .attrs = bmc150_accel_attributes, +}; + +static const struct iio_event_spec bmc150_accel_event = { + .type = IIO_EV_TYPE_ROC, + .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 BMC150_ACCEL_CHANNEL(_axis, bits) { \ + .type = IIO_ACCEL, \ + .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 = (bits), \ + .storagebits = 16, \ + .shift = 16 - (bits), \ + }, \ + .event_spec = &bmc150_accel_event, \ + .num_event_specs = 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} }, + }, +}; + +static const struct iio_info bmc150_accel_info = { + .attrs = &bmc150_accel_attrs_group, + .read_raw = bmc150_accel_read_raw, + .write_raw = bmc150_accel_write_raw, + .read_event_value = bmc150_accel_read_event, + .write_event_value = bmc150_accel_write_event, + .write_event_config = bmc150_accel_write_event_config, + .read_event_config = bmc150_accel_read_event_config, + .validate_trigger = bmc150_accel_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmc150_accel_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, + BMC150_ACCEL_AXIS_TO_REG(bit)); + if (ret < 0) { + mutex_unlock(&data->mutex); + goto err_read; + } + data->buffer[i++] = ret; + } + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + data->timestamp); +err_read: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + /* new data interrupts don't need ack */ + if (data->dready_trigger_on) + return 0; + + mutex_lock(&data->mutex); + /* clear any latched interrupt */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + mutex_unlock(&data->mutex); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmc150_accel_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 bmc150_accel_write_event_config for + * enable/disable operation order + */ + ret = bmc150_accel_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + ret = bmc150_accel_setup_any_motion_interrupt(data, state); + else + ret = bmc150_accel_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 ret; +} + +static const struct iio_trigger_ops bmc150_accel_trigger_ops = { + .set_trigger_state = bmc150_accel_data_rdy_trigger_set_state, + .try_reenable = bmc150_accel_trig_try_reen, + .owner = THIS_MODULE, +}; + +static irqreturn_t bmc150_accel_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + int dir; + + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_STATUS_2); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); + goto ack_intr_status; + } + + if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) + dir = IIO_EV_DIR_FALLING; + else + dir = IIO_EV_DIR_RISING; + + if (ret & BMC150_ACCEL_ANY_MOTION_MASK) + iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_EITHER), + data->timestamp); +ack_intr_status: + if (!data->dready_trigger_on) + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + + return IRQ_HANDLED; +} + +static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_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 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; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0); + if (IS_ERR(gpio)) { + dev_err(dev, "Failed: gpio get index\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 bmc150_accel_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + 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) + return -ENOMEM; + + data = iio_priv(indio_dev); + 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; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + 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_gpio_probe(client, data); + + if (client->irq >= 0) { + ret = devm_request_threaded_irq( + &client->dev, client->irq, + bmc150_accel_data_rdy_trig_poll, + bmc150_accel_event_handler, + IRQF_TRIGGER_RISING, + BMC150_ACCEL_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 = &bmc150_accel_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 = &bmc150_accel_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, + bmc150_accel_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "Failed: iio triggered buffer setup\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, + BMC150_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 bmc150_accel_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + 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); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bmc150_accel_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + mutex_unlock(&data->mutex); + + return 0; +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int bmc150_accel_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + dev_dbg(&data->client->dev, __func__); + + return bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); +} + +static int bmc150_accel_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + int sleep_val; + + dev_dbg(&data->client->dev, __func__); + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + sleep_val = bmc150_accel_get_startup_times(data); + if (sleep_val < 20) + usleep_range(sleep_val * 1000, 20000); + else + msleep_interruptible(sleep_val); + + return 0; +} +#endif + +static const struct dev_pm_ops bmc150_accel_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) + SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, + bmc150_accel_runtime_resume, NULL) +}; + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct i2c_device_id bmc150_accel_id[] = { + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); + +static struct i2c_driver bmc150_accel_driver = { + .driver = { + .name = BMC150_ACCEL_DRV_NAME, + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_i2c_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 accelerometer driver"); 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/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 7941cf2d31ee..98909a9e284e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -21,10 +21,13 @@ #include <linux/string.h> #include <linux/acpi.h> #include <linux/gpio/consumer.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> #include <linux/iio/trigger.h> +#include <linux/iio/events.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/accel/kxcjk_1013.h> @@ -71,15 +74,40 @@ #define KXCJK1013_DATA_MASK_12_BIT 0x0FFF #define KXCJK1013_MAX_STARTUP_TIME_US 100000 +#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 + +enum kx_chipset { + KXCJK1013, + KXCJ91008, + KXTJ21009, + KX_MAX_CHIPS /* this must be last */ +}; + 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]; - int power_state; u8 odr_bits; + u8 range; + int wake_thres; + int wake_dur; bool active_high_intr; + bool dready_trigger_on; + int ev_enable_state; + bool motion_trigger_on; + int64_t timestamp; + enum kx_chipset chipset; }; enum kxcjk1013_axis { @@ -93,6 +121,12 @@ enum kxcjk1013_mode { OPERATION, }; +enum kxcjk1013_range { + KXCJK1013_RANGE_2G, + KXCJK1013_RANGE_4G, + KXCJK1013_RANGE_8G, +}; + static const struct { int val; int val2; @@ -107,10 +141,78 @@ 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; + u8 gsel_0; + u8 gsel_1; +} KXCJK1013_scale_table[] = { {9582, 0, 0}, + {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) @@ -138,6 +240,51 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, return 0; } +static int kxcjk1013_get_mode(struct kxcjk1013_data *data, + enum kxcjk1013_mode *mode) +{ + int 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 (ret & KXCJK1013_REG_CTRL1_BIT_PC1) + *mode = OPERATION; + else + *mode = STANDBY; + + return 0; +} + +static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) +{ + int 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; + } + + ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); + ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); + + 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; + } + + data->range = range_index; + + return 0; +} + static int kxcjk1013_chip_init(struct kxcjk1013_data *data) { int ret; @@ -160,10 +307,6 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } - /* Setting range to 4G */ - ret |= KXCJK1013_REG_CTRL1_BIT_GSEL0; - ret &= ~KXCJK1013_REG_CTRL1_BIT_GSEL1; - /* Set 12 bit mode */ ret |= KXCJK1013_REG_CTRL1_BIT_RES; @@ -174,6 +317,11 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } + /* Setting range to 4G */ + ret = kxcjk1013_set_range(data, KXCJK1013_RANGE_4G); + if (ret < 0) + return ret; + 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"); @@ -201,14 +349,147 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + + data->wake_thres = KXCJK1013_DEFAULT_WAKE_THRES; + return 0; } -static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, - bool status) +#ifdef CONFIG_PM_RUNTIME +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[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; +} +#endif + +static int kxcjk1013_set_power_state(struct kxcjk1013_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: kxcjk1013_set_power_state for %d\n", on); + return ret; + } + + return 0; +} + +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; + + 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) @@ -250,7 +531,13 @@ static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, return ret; } - return ret; + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; } static int kxcjk1013_convert_freq_to_bit(int val, int val2) @@ -267,10 +554,29 @@ 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; int odr_bits; + enum kxcjk1013_mode store_mode; + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; odr_bits = kxcjk1013_convert_freq_to_bit(val, val2); if (odr_bits < 0) @@ -290,9 +596,18 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_bits; - /* Check, if the ODR is changed after data enable */ - if (data->power_state) { - /* Set the state back to operation */ + 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) return ret; @@ -331,16 +646,38 @@ static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis) return ret; } -static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) +static int kxcjk1013_set_scale(struct kxcjk1013_data *data, int val) { - int i; + int ret, i; + enum kxcjk1013_mode store_mode; + + + for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) { + if (KXCJK1013_scale_table[i].scale == val) { + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; + + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = kxcjk1013_set_range(data, i); + if (ret < 0) + return ret; - 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; + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret) + return ret; + } + + return 0; + } } - return KXCJK1013_MAX_STARTUP_TIME_US; + return -EINVAL; } static int kxcjk1013_read_raw(struct iio_dev *indio_dev, @@ -356,34 +693,30 @@ static int kxcjk1013_read_raw(struct iio_dev *indio_dev, if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; else { - int sleep_val; - - ret = kxcjk1013_set_mode(data, OPERATION); + ret = kxcjk1013_set_power_state(data, true); if (ret < 0) { mutex_unlock(&data->mutex); return ret; } - ++data->power_state; - sleep_val = kxcjk1013_get_startup_times(data); - if (sleep_val < 20000) - usleep_range(sleep_val, 20000); - else - msleep_interruptible(sleep_val/1000); ret = kxcjk1013_get_acc_reg(data, chan->scan_index); - if (--data->power_state == 0) - kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) { + kxcjk1013_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret >> 4, 11); + ret = kxcjk1013_set_power_state(data, false); } mutex_unlock(&data->mutex); if (ret < 0) return ret; - *val = sign_extend32(ret >> 4, 11); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = 19163; /* range +-4g (4/2047*9.806650) */ + *val2 = KXCJK1013_scale_table[data->range].scale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -410,6 +743,14 @@ static int kxcjk1013_write_raw(struct iio_dev *indio_dev, ret = kxcjk1013_set_odr(data, val, val2); mutex_unlock(&data->mutex); break; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = kxcjk1013_set_scale(data, val2); + mutex_unlock(&data->mutex); + break; default: ret = -EINVAL; } @@ -417,12 +758,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; @@ -431,8 +880,11 @@ static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev, static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600"); +static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019163 0.038326"); + static struct attribute *kxcjk1013_attributes[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, NULL, }; @@ -440,6 +892,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, \ @@ -455,6 +915,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[] = { @@ -468,6 +930,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, }; @@ -493,7 +959,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); @@ -520,20 +986,34 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; mutex_lock(&data->mutex); - if (state) { - kxcjk1013_chip_setup_interrupt(data, true); - kxcjk1013_set_mode(data, OPERATION); - ++data->power_state; - } else { - if (--data->power_state) { - mutex_unlock(&data->mutex); - return 0; - } - kxcjk1013_chip_setup_interrupt(data, false); - kxcjk1013_set_mode(data, STANDBY); + + if (!state && data->ev_enable_state && data->motion_trigger_on) { + data->motion_trigger_on = false; + mutex_unlock(&data->mutex); + return 0; } + + 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; @@ -545,10 +1025,124 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = { .owner = THIS_MODULE, }; -static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, - struct kxcjk1013_data *data) +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 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; @@ -557,12 +1151,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); @@ -587,8 +1175,8 @@ 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; + const char *name; int ret; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); @@ -605,6 +1193,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; @@ -614,41 +1211,54 @@ 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) { - trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, - indio_dev->id); - if (!trig) - return -ENOMEM; + 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->trig_mode = true; + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_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; - } + 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; - 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, @@ -661,23 +1271,33 @@ static int kxcjk1013_probe(struct i2c_client *client, } } - ret = devm_iio_device_register(&client->dev, indio_dev); + 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, + KXCJK1013_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + return 0; +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; } @@ -687,10 +1307,16 @@ static int kxcjk1013_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct kxcjk1013_data *data = iio_priv(indio_dev); - if (data->trig_mode) { + 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->trig); - iio_trigger_free(data->trig); + iio_trigger_unregister(data->dready_trig); + iio_trigger_unregister(data->motion_trig); } mutex_lock(&data->mutex); @@ -705,43 +1331,80 @@ static int kxcjk1013_suspend(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; mutex_lock(&data->mutex); - kxcjk1013_set_mode(data, STANDBY); + ret = kxcjk1013_set_mode(data, STANDBY); mutex_unlock(&data->mutex); - return 0; + return ret; } static int kxcjk1013_resume(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret = 0; mutex_lock(&data->mutex); + /* Check, if the suspend occured while active */ + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) + ret = kxcjk1013_set_mode(data, OPERATION); + mutex_unlock(&data->mutex); - if (data->power_state) - kxcjk1013_set_mode(data, OPERATION); + return ret; +} +#endif - mutex_unlock(&data->mutex); +#ifdef CONFIG_PM_RUNTIME +static int kxcjk1013_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); - return 0; + return kxcjk1013_set_mode(data, STANDBY); } -static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend, kxcjk1013_resume); -#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops) -#else -#define KXCJK1013_PM_OPS NULL +static int kxcjk1013_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + int sleep_val; + + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + + sleep_val = kxcjk1013_get_startup_times(data); + if (sleep_val < 20000) + usleep_range(sleep_val, 20000); + else + msleep_interruptible(sleep_val/1000); + + return 0; +} #endif +static const struct dev_pm_ops kxcjk1013_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) + SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, + kxcjk1013_runtime_resume, NULL) +}; + static const struct acpi_device_id kx_acpi_match[] = { - {"KXCJ1013", 0}, + {"KXCJ1013", KXCJK1013}, + {"KXCJ1008", KXCJ91008}, + {"KXTJ1009", KXTJ21009}, { }, }; MODULE_DEVICE_TABLE(acpi, kx_acpi_match); static const struct i2c_device_id kxcjk1013_id[] = { - {"kxcjk1013", 0}, + {"kxcjk1013", KXCJK1013}, + {"kxcj91008", KXCJ91008}, + {"kxtj21009", KXTJ21009}, {} }; @@ -751,7 +1414,7 @@ static struct i2c_driver kxcjk1013_driver = { .driver = { .name = KXCJK1013_DRV_NAME, .acpi_match_table = ACPI_PTR(kx_acpi_match), - .pm = KXCJK1013_PM_OPS, + .pm = &kxcjk1013_pm_ops, }, .probe = kxcjk1013_probe, .remove = kxcjk1013_remove, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 11b048a59fde..88bdc8f612e2 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -129,7 +129,7 @@ config AT91_ADC config EXYNOS_ADC tristate "Exynos ADC driver support" - depends on ARCH_EXYNOS || (OF && COMPILE_TEST) + depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) help Core support for the ADC block found in the Samsung EXYNOS series of SoCs for drivers such as the touchscreen and hwmon to use to share @@ -206,6 +206,16 @@ config NAU7802 To compile this driver as a module, choose M here: the module will be called nau7802. +config ROCKCHIP_SARADC + tristate "Rockchip SARADC driver" + depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) + help + Say yes here to build support for the SARADC found in SoCs from + Rockchip. + + To compile this driver as a module, choose M here: the + module will be called rockchip_saradc. + config TI_ADC081C tristate "Texas Instruments ADC081C021/027" depends on I2C @@ -216,6 +226,16 @@ config TI_ADC081C This driver can also be built as a module. If so, the module will be called ti-adc081c. +config TI_ADC128S052 + tristate "Texas Instruments ADC128S052" + depends on SPI + help + If you say yes here you get support for Texas Instruments ADC128S052 + chip. + + This driver can also be built as a module. If so, the module will be + called ti-adc128s052. + config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ad81b512aa3d..cb88a6a23b8f 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -22,7 +22,9 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o +obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 7eadaf16adc1..ff61ae55dd3f 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -267,7 +267,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); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index fc9dfc23ecb7..43620fd4c66a 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -40,13 +40,16 @@ #include <linux/iio/machine.h> #include <linux/iio/driver.h> -/* EXYNOS4412/5250 ADC_V1 registers definitions */ +/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ #define ADC_V1_CON(x) ((x) + 0x00) #define ADC_V1_DLY(x) ((x) + 0x08) #define ADC_V1_DATX(x) ((x) + 0x0C) #define ADC_V1_INTCLR(x) ((x) + 0x18) #define ADC_V1_MUX(x) ((x) + 0x1c) +/* S3C2410 ADC registers definitions */ +#define ADC_S3C2410_MUX(x) ((x) + 0x18) + /* Future ADC_V2 registers definitions */ #define ADC_V2_CON1(x) ((x) + 0x00) #define ADC_V2_CON2(x) ((x) + 0x04) @@ -61,6 +64,11 @@ #define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) #define ADC_V1_CON_STANDBY (1u << 2) +/* Bit definitions for S3C2410 ADC */ +#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) +#define ADC_S3C2410_DATX_MASK 0x3FF +#define ADC_S3C2416_CON_RES_SEL (1u << 3) + /* Bit definitions for ADC_V2 */ #define ADC_V2_CON1_SOFT_RESET (1u << 2) @@ -77,6 +85,7 @@ /* Bit definitions common for ADC_V1 and ADC_V2 */ #define ADC_CON_EN_START (1u << 0) +#define ADC_CON_EN_START_MASK (0x3 << 0) #define ADC_DATX_MASK 0xFFF #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) @@ -100,6 +109,8 @@ struct exynos_adc { struct exynos_adc_data { int num_channels; bool needs_sclk; + bool needs_adc_phy; + u32 mask; void (*init_hw)(struct exynos_adc *info); void (*exit_hw)(struct exynos_adc *info); @@ -171,7 +182,8 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info) { u32 con1; - writel(1, info->enable_reg); + if (info->data->needs_adc_phy) + writel(1, info->enable_reg); /* set default prescaler values and Enable prescaler */ con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; @@ -185,7 +197,8 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info) { u32 con; - writel(0, info->enable_reg); + if (info->data->needs_adc_phy) + writel(0, info->enable_reg); con = readl(ADC_V1_CON(info->regs)); con |= ADC_V1_CON_STANDBY; @@ -210,6 +223,8 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info, static const struct exynos_adc_data exynos_adc_v1_data = { .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + .needs_adc_phy = true, .init_hw = exynos_adc_v1_init_hw, .exit_hw = exynos_adc_v1_exit_hw, @@ -217,11 +232,89 @@ static const struct exynos_adc_data exynos_adc_v1_data = { .start_conv = exynos_adc_v1_start_conv, }; +static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + /* Enable 12 bit ADC resolution */ + con1 = readl(ADC_V1_CON(info->regs)); + con1 |= ADC_S3C2416_CON_RES_SEL; + writel(con1, ADC_V1_CON(info->regs)); + + /* Select channel for S3C2416 */ + writel(addr, ADC_S3C2410_MUX(info->regs)); + + con1 = readl(ADC_V1_CON(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c2416_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c2416_start_conv, +}; + +static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + /* Select channel for S3C2433 */ + writel(addr, ADC_S3C2410_MUX(info->regs)); + + con1 = readl(ADC_V1_CON(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c2443_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c2443_start_conv, +}; + +static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + con1 = readl(ADC_V1_CON(info->regs)); + con1 &= ~ADC_S3C2410_CON_SELMUX(0x7); + con1 |= ADC_S3C2410_CON_SELMUX(addr); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c24xx_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c64xx_start_conv, +}; + +static struct exynos_adc_data const exynos_adc_s3c64xx_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .clear_irq = exynos_adc_v1_clear_irq, + .start_conv = exynos_adc_s3c64xx_start_conv, +}; + static void exynos_adc_v2_init_hw(struct exynos_adc *info) { u32 con1, con2; - writel(1, info->enable_reg); + if (info->data->needs_adc_phy) + writel(1, info->enable_reg); con1 = ADC_V2_CON1_SOFT_RESET; writel(con1, ADC_V2_CON1(info->regs)); @@ -238,7 +331,8 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info) { u32 con; - writel(0, info->enable_reg); + if (info->data->needs_adc_phy) + writel(0, info->enable_reg); con = readl(ADC_V2_CON1(info->regs)); con &= ~ADC_CON_EN_START; @@ -266,6 +360,8 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info, static const struct exynos_adc_data exynos_adc_v2_data = { .num_channels = MAX_ADC_V2_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + .needs_adc_phy = true, .init_hw = exynos_adc_v2_init_hw, .exit_hw = exynos_adc_v2_exit_hw, @@ -275,7 +371,9 @@ static const struct exynos_adc_data exynos_adc_v2_data = { static const struct exynos_adc_data exynos3250_adc_data = { .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ .needs_sclk = true, + .needs_adc_phy = true, .init_hw = exynos_adc_v2_init_hw, .exit_hw = exynos_adc_v2_exit_hw, @@ -285,6 +383,21 @@ static const struct exynos_adc_data exynos3250_adc_data = { static const struct of_device_id exynos_adc_match[] = { { + .compatible = "samsung,s3c2410-adc", + .data = &exynos_adc_s3c24xx_data, + }, { + .compatible = "samsung,s3c2416-adc", + .data = &exynos_adc_s3c2416_data, + }, { + .compatible = "samsung,s3c2440-adc", + .data = &exynos_adc_s3c24xx_data, + }, { + .compatible = "samsung,s3c2443-adc", + .data = &exynos_adc_s3c2443_data, + }, { + .compatible = "samsung,s3c6410-adc", + .data = &exynos_adc_s3c64xx_data, + }, { .compatible = "samsung,exynos-adc-v1", .data = &exynos_adc_v1_data, }, { @@ -347,9 +460,10 @@ static int exynos_read_raw(struct iio_dev *indio_dev, static irqreturn_t exynos_adc_isr(int irq, void *dev_id) { struct exynos_adc *info = (struct exynos_adc *)dev_id; + u32 mask = info->data->mask; /* Read value */ - info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; + info->value = readl(ADC_V1_DATX(info->regs)) & mask; /* clear irq */ if (info->data->clear_irq) @@ -442,10 +556,13 @@ static int exynos_adc_probe(struct platform_device *pdev) if (IS_ERR(info->regs)) return PTR_ERR(info->regs); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(info->enable_reg)) - return PTR_ERR(info->enable_reg); + + if (info->data->needs_adc_phy) { + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->enable_reg)) + return PTR_ERR(info->enable_reg); + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -606,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/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c new file mode 100644 index 000000000000..e074a0b03f28 --- /dev/null +++ b/drivers/iio/adc/rockchip_saradc.c @@ -0,0 +1,316 @@ +/* + * Rockchip Successive Approximation Register (SAR) A/D Converter + * Copyright (C) 2014 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/regulator/consumer.h> +#include <linux/iio/iio.h> + +#define SARADC_DATA 0x00 +#define SARADC_DATA_MASK 0x3ff + +#define SARADC_STAS 0x04 +#define SARADC_STAS_BUSY BIT(0) + +#define SARADC_CTRL 0x08 +#define SARADC_CTRL_IRQ_STATUS BIT(6) +#define SARADC_CTRL_IRQ_ENABLE BIT(5) +#define SARADC_CTRL_POWER_CTRL BIT(3) +#define SARADC_CTRL_CHN_MASK 0x7 + +#define SARADC_DLY_PU_SOC 0x0c +#define SARADC_DLY_PU_SOC_MASK 0x3f + +#define SARADC_BITS 10 +#define SARADC_TIMEOUT msecs_to_jiffies(100) + +struct rockchip_saradc { + void __iomem *regs; + struct clk *pclk; + struct clk *clk; + struct completion completion; + struct regulator *vref; + u16 last_val; +}; + +static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rockchip_saradc *info = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + + reinit_completion(&info->completion); + + /* 8 clock periods as delay between power up and start cmd */ + writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); + + /* Select the channel to be used and trigger conversion */ + writel(SARADC_CTRL_POWER_CTRL + | (chan->channel & SARADC_CTRL_CHN_MASK) + | SARADC_CTRL_IRQ_ENABLE, + info->regs + SARADC_CTRL); + + if (!wait_for_completion_timeout(&info->completion, + SARADC_TIMEOUT)) { + writel_relaxed(0, info->regs + SARADC_CTRL); + mutex_unlock(&indio_dev->mlock); + return -ETIMEDOUT; + } + + *val = info->last_val; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(info->vref); + if (ret < 0) { + dev_err(&indio_dev->dev, "failed to get voltage\n"); + return ret; + } + + *val = ret / 1000; + *val2 = SARADC_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) +{ + struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id; + + /* Read value */ + info->last_val = readl_relaxed(info->regs + SARADC_DATA); + info->last_val &= SARADC_DATA_MASK; + + /* Clear irq & power down adc */ + writel_relaxed(0, info->regs + SARADC_CTRL); + + complete(&info->completion); + + return IRQ_HANDLED; +} + +static const struct iio_info rockchip_saradc_iio_info = { + .read_raw = rockchip_saradc_read_raw, + .driver_module = THIS_MODULE, +}; + +#define ADC_CHANNEL(_index, _id) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = _id, \ +} + +static const struct iio_chan_spec rockchip_saradc_iio_channels[] = { + ADC_CHANNEL(0, "adc0"), + ADC_CHANNEL(1, "adc1"), + ADC_CHANNEL(2, "adc2"), +}; + +static int rockchip_saradc_probe(struct platform_device *pdev) +{ + struct rockchip_saradc *info = NULL; + struct device_node *np = pdev->dev.of_node; + struct iio_dev *indio_dev = NULL; + struct resource *mem; + int ret; + int irq; + + if (!np) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + info = iio_priv(indio_dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->regs)) + return PTR_ERR(info->regs); + + init_completion(&info->completion); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, + 0, dev_name(&pdev->dev), info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq %d\n", irq); + return ret; + } + + info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(info->pclk)) { + dev_err(&pdev->dev, "failed to get pclk\n"); + return PTR_ERR(info->pclk); + } + + info->clk = devm_clk_get(&pdev->dev, "saradc"); + if (IS_ERR(info->clk)) { + dev_err(&pdev->dev, "failed to get adc clock\n"); + return PTR_ERR(info->clk); + } + + info->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(info->vref)) { + dev_err(&pdev->dev, "failed to get regulator, %ld\n", + PTR_ERR(info->vref)); + return PTR_ERR(info->vref); + } + + /* + * Use a default of 1MHz for the converter clock. + * This may become user-configurable in the future. + */ + ret = clk_set_rate(info->clk, 1000000); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); + return ret; + } + + ret = regulator_enable(info->vref); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable vref regulator\n"); + return ret; + } + + ret = clk_prepare_enable(info->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable pclk\n"); + goto err_reg_voltage; + } + + ret = clk_prepare_enable(info->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable converter clock\n"); + goto err_pclk; + } + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &rockchip_saradc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->channels = rockchip_saradc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_clk; + + return 0; + +err_clk: + clk_disable_unprepare(info->clk); +err_pclk: + clk_disable_unprepare(info->pclk); +err_reg_voltage: + regulator_disable(info->vref); + return ret; +} + +static int rockchip_saradc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct rockchip_saradc *info = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->pclk); + regulator_disable(info->vref); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rockchip_saradc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rockchip_saradc *info = iio_priv(indio_dev); + + clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->pclk); + regulator_disable(info->vref); + + return 0; +} + +static int rockchip_saradc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rockchip_saradc *info = iio_priv(indio_dev); + int ret; + + ret = regulator_enable(info->vref); + if (ret) + return ret; + + ret = clk_prepare_enable(info->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; + + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, + rockchip_saradc_suspend, rockchip_saradc_resume); + +static const struct of_device_id rockchip_saradc_match[] = { + { .compatible = "rockchip,saradc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_saradc_match); + +static struct platform_driver rockchip_saradc_driver = { + .probe = rockchip_saradc_probe, + .remove = rockchip_saradc_remove, + .driver = { + .name = "rockchip-saradc", + .owner = THIS_MODULE, + .of_match_table = rockchip_saradc_match, + .pm = &rockchip_saradc_pm_ops, + }, +}; + +module_platform_driver(rockchip_saradc_driver); diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c new file mode 100644 index 000000000000..655cb564ec54 --- /dev/null +++ b/drivers/iio/adc/ti-adc128s052.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com> + * + * Driver for Texas Instruments' ADC128S052 ADC chip. + * Datasheet can be found here: + * http://www.ti.com/lit/ds/symlink/adc128s052.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +struct adc128 { + struct spi_device *spi; + + struct regulator *reg; + struct mutex lock; + + u8 buffer[2] ____cacheline_aligned; +}; + +static int adc128_adc_conversion(struct adc128 *adc, u8 channel) +{ + int ret; + + mutex_lock(&adc->lock); + + adc->buffer[0] = channel << 3; + adc->buffer[1] = 0; + + ret = spi_write(adc->spi, &adc->buffer, 2); + if (ret < 0) { + mutex_unlock(&adc->lock); + return ret; + } + + ret = spi_read(adc->spi, &adc->buffer, 2); + + mutex_unlock(&adc->lock); + + if (ret < 0) + return ret; + + return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF); +} + +static int adc128_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct adc128 *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + + ret = adc128_adc_conversion(adc, channel->channel); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + + ret = regulator_get_voltage(adc->reg); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } + +} + +#define ADC128_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (num), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + } + +static const struct iio_chan_spec adc128_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), + ADC128_VOLTAGE_CHANNEL(1), + ADC128_VOLTAGE_CHANNEL(2), + ADC128_VOLTAGE_CHANNEL(3), + ADC128_VOLTAGE_CHANNEL(4), + ADC128_VOLTAGE_CHANNEL(5), + ADC128_VOLTAGE_CHANNEL(6), + ADC128_VOLTAGE_CHANNEL(7), +}; + +static const struct iio_info adc128_info = { + .read_raw = adc128_read_raw, + .driver_module = THIS_MODULE, +}; + +static int adc128_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adc128 *adc; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + + spi_set_drvdata(spi, indio_dev); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &adc128_info; + + indio_dev->channels = adc128_channels; + indio_dev->num_channels = ARRAY_SIZE(adc128_channels); + + adc->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(adc->reg)) + return PTR_ERR(adc->reg); + + ret = regulator_enable(adc->reg); + if (ret < 0) + return ret; + + mutex_init(&adc->lock); + + ret = iio_device_register(indio_dev); + + return ret; +} + +static int adc128_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adc128 *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(adc->reg); + + return 0; +} + +static const struct spi_device_id adc128_id[] = { + { "adc128s052", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, adc128_id); + +static struct spi_driver adc128_driver = { + .driver = { + .name = "adc128s052", + .owner = THIS_MODULE, + }, + .probe = adc128_probe, + .remove = adc128_remove, + .id_table = adc128_id, +}; +module_spi_driver(adc128_driver); + +MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); +MODULE_DESCRIPTION("Texas Instruments ADC128S052"); +MODULE_LICENSE("GPL v2"); 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/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 626b39749767..a221f7329b79 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1201,12 +1201,16 @@ static int xadc_probe(struct platform_device *pdev) goto err_device_free; xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); - if (IS_ERR(xadc->convst_trigger)) + if (IS_ERR(xadc->convst_trigger)) { + ret = PTR_ERR(xadc->convst_trigger); goto err_triggered_buffer_cleanup; + } xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev, "samplerate"); - if (IS_ERR(xadc->samplerate_trigger)) + if (IS_ERR(xadc->samplerate_trigger)) { + ret = PTR_ERR(xadc->samplerate_trigger); goto err_free_convst_trigger; + } } xadc->clk = devm_clk_get(&pdev->dev, NULL); @@ -1322,7 +1326,6 @@ static struct platform_driver xadc_driver = { .remove = xadc_remove, .driver = { .name = "xadc", - .owner = THIS_MODULE, .of_match_table = xadc_of_match_table, }, }; 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) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index f278eff42a4c..2236ea22f98a 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -152,6 +152,14 @@ config MAX517 This driver can also be built as a module. If so, the module will be called max517. +config MAX5821 + tristate "Maxim MAX5821 DAC driver" + depends on I2C + depends on OF + help + Say yes here to build support for Maxim MAX5821 + 10 bits DAC. + config MCP4725 tristate "MCP4725 DAC driver" depends on I2C diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 10107640bb46..52be7e1acf16 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -17,5 +17,6 @@ obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_MAX517) += max517.o +obj-$(CONFIG_MAX5821) += max5821.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4922) += mcp4922.o diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c new file mode 100644 index 000000000000..6e914495b346 --- /dev/null +++ b/drivers/iio/dac/max5821.c @@ -0,0 +1,405 @@ + /* + * iio/dac/max5821.c + * Copyright (C) 2014 Philippe Reynes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +#define MAX5821_MAX_DAC_CHANNELS 2 + +/* command bytes */ +#define MAX5821_LOAD_DAC_A_IN_REG_B 0x00 +#define MAX5821_LOAD_DAC_B_IN_REG_A 0x10 +#define MAX5821_EXTENDED_COMMAND_MODE 0xf0 +#define MAX5821_READ_DAC_A_COMMAND 0xf1 +#define MAX5821_READ_DAC_B_COMMAND 0xf2 + +#define MAX5821_EXTENDED_POWER_UP 0x00 +#define MAX5821_EXTENDED_POWER_DOWN_MODE0 0x01 +#define MAX5821_EXTENDED_POWER_DOWN_MODE1 0x02 +#define MAX5821_EXTENDED_POWER_DOWN_MODE2 0x03 +#define MAX5821_EXTENDED_DAC_A 0x04 +#define MAX5821_EXTENDED_DAC_B 0x08 + +enum max5821_device_ids { + ID_MAX5821, +}; + +struct max5821_data { + struct i2c_client *client; + struct regulator *vref_reg; + unsigned short vref_mv; + bool powerdown[MAX5821_MAX_DAC_CHANNELS]; + u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS]; + struct mutex lock; +}; + +static const char * const max5821_powerdown_modes[] = { + "three_state", + "1kohm_to_gnd", + "100kohm_to_gnd", +}; + +enum { + MAX5821_THREE_STATE, + MAX5821_1KOHM_TO_GND, + MAX5821_100KOHM_TO_GND +}; + +static int max5821_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct max5821_data *st = iio_priv(indio_dev); + + return st->powerdown_mode[chan->channel]; +} + +static int max5821_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct max5821_data *st = iio_priv(indio_dev); + + st->powerdown_mode[chan->channel] = mode; + + return 0; +} + +static const struct iio_enum max5821_powerdown_mode_enum = { + .items = max5821_powerdown_modes, + .num_items = ARRAY_SIZE(max5821_powerdown_modes), + .get = max5821_get_powerdown_mode, + .set = max5821_set_powerdown_mode, +}; + +static ssize_t max5821_read_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct max5821_data *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", st->powerdown[chan->channel]); +} + +static int max5821_sync_powerdown_mode(struct max5821_data *data, + const struct iio_chan_spec *chan) +{ + u8 outbuf[2]; + + outbuf[0] = MAX5821_EXTENDED_COMMAND_MODE; + + if (chan->channel == 0) + outbuf[1] = MAX5821_EXTENDED_DAC_A; + else + outbuf[1] = MAX5821_EXTENDED_DAC_B; + + if (data->powerdown[chan->channel]) + outbuf[1] |= data->powerdown_mode[chan->channel] + 1; + else + outbuf[1] |= MAX5821_EXTENDED_POWER_UP; + + return i2c_master_send(data->client, outbuf, 2); +} + +static ssize_t max5821_write_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct max5821_data *data = iio_priv(indio_dev); + bool powerdown; + int ret; + + ret = strtobool(buf, &powerdown); + if (ret) + return ret; + + data->powerdown[chan->channel] = powerdown; + + ret = max5821_sync_powerdown_mode(data, chan); + if (ret < 0) + return ret; + + return len; +} + +static const struct iio_chan_spec_ext_info max5821_ext_info[] = { + { + .name = "powerdown", + .read = max5821_read_dac_powerdown, + .write = max5821_write_dac_powerdown, + .shared = IIO_SEPARATE, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &max5821_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", &max5821_powerdown_mode_enum), + { }, +}; + +#define MAX5821_CHANNEL(chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = max5821_ext_info, \ +} + +static const struct iio_chan_spec max5821_channels[] = { + MAX5821_CHANNEL(0), + MAX5821_CHANNEL(1) +}; + +static const u8 max5821_read_dac_command[] = { + MAX5821_READ_DAC_A_COMMAND, + MAX5821_READ_DAC_B_COMMAND +}; + +static const u8 max5821_load_dac_command[] = { + MAX5821_LOAD_DAC_A_IN_REG_B, + MAX5821_LOAD_DAC_B_IN_REG_A +}; + +static int max5821_get_value(struct iio_dev *indio_dev, + int *val, int channel) +{ + struct max5821_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + u8 outbuf[1]; + u8 inbuf[2]; + int ret; + + if ((channel != 0) && (channel != 1)) + return -EINVAL; + + outbuf[0] = max5821_read_dac_command[channel]; + + mutex_lock(&data->lock); + + ret = i2c_master_send(client, outbuf, 1); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret != 1) { + mutex_unlock(&data->lock); + return -EIO; + } + + ret = i2c_master_recv(client, inbuf, 2); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret != 2) { + mutex_unlock(&data->lock); + return -EIO; + } + + mutex_unlock(&data->lock); + + *val = ((inbuf[0] & 0x0f) << 6) | (inbuf[1] >> 2); + + return IIO_VAL_INT; +} + +static int max5821_set_value(struct iio_dev *indio_dev, + int val, int channel) +{ + struct max5821_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + u8 outbuf[2]; + int ret; + + if ((val < 0) || (val > 1023)) + return -EINVAL; + + if ((channel != 0) && (channel != 1)) + return -EINVAL; + + outbuf[0] = max5821_load_dac_command[channel]; + outbuf[0] |= val >> 6; + outbuf[1] = (val & 0x3f) << 2; + + ret = i2c_master_send(client, outbuf, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + else + return 0; +} + +static int max5821_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max5821_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return max5821_get_value(indio_dev, val, chan->channel); + case IIO_CHAN_INFO_SCALE: + *val = data->vref_mv; + *val2 = 10; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int max5821_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + if (val2 != 0) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return max5821_set_value(indio_dev, val, chan->channel); + default: + return -EINVAL; + } +} + +#ifdef CONFIG_PM_SLEEP +static int max5821_suspend(struct device *dev) +{ + u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE, + MAX5821_EXTENDED_DAC_A | + MAX5821_EXTENDED_DAC_B | + MAX5821_EXTENDED_POWER_DOWN_MODE2 }; + + return i2c_master_send(to_i2c_client(dev), outbuf, 2); +} + +static int max5821_resume(struct device *dev) +{ + u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE, + MAX5821_EXTENDED_DAC_A | + MAX5821_EXTENDED_DAC_B | + MAX5821_EXTENDED_POWER_UP }; + + return i2c_master_send(to_i2c_client(dev), outbuf, 2); +} + +static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume); +#define MAX5821_PM_OPS (&max5821_pm_ops) +#else +#define MAX5821_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct iio_info max5821_info = { + .read_raw = max5821_read_raw, + .write_raw = max5821_write_raw, + .driver_module = THIS_MODULE, +}; + +static int max5821_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max5821_data *data; + struct iio_dev *indio_dev; + u32 tmp; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + /* max5821 start in powerdown mode 100Kohm to ground */ + for (tmp = 0; tmp < MAX5821_MAX_DAC_CHANNELS; tmp++) { + data->powerdown[tmp] = true; + data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND; + } + + data->vref_reg = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(data->vref_reg)) { + ret = PTR_ERR(data->vref_reg); + dev_err(&client->dev, + "Failed to get vref regulator: %d\n", ret); + goto error_free_reg; + } + + ret = regulator_enable(data->vref_reg); + if (ret) { + dev_err(&client->dev, + "Failed to enable vref regulator: %d\n", ret); + goto error_free_reg; + } + + ret = regulator_get_voltage(data->vref_reg); + if (ret < 0) { + dev_err(&client->dev, + "Failed to get voltage on regulator: %d\n", ret); + goto error_disable_reg; + } + + data->vref_mv = ret / 1000; + + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->num_channels = ARRAY_SIZE(max5821_channels); + indio_dev->channels = max5821_channels; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &max5821_info; + + return iio_device_register(indio_dev); + +error_disable_reg: + regulator_disable(data->vref_reg); + +error_free_reg: + + return ret; +} + +static int max5821_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct max5821_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(data->vref_reg); + + return 0; +} + +static const struct i2c_device_id max5821_id[] = { + { "max5821", ID_MAX5821 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max5821_id); + +static const struct of_device_id max5821_of_match[] = { + { .compatible = "maxim,max5821" }, + { } +}; + +static struct i2c_driver max5821_driver = { + .driver = { + .name = "max5821", + .pm = MAX5821_PM_OPS, + .owner = THIS_MODULE, + }, + .probe = max5821_probe, + .remove = max5821_remove, + .id_table = max5821_id, +}; +module_i2c_driver(max5821_driver); + +MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>"); +MODULE_DESCRIPTION("MAX5821 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index ac2d69e34c8c..b3d0e94f72eb 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 also supports BMI055 gyroscope. + + 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..1f967e0d688e --- /dev/null +++ b/drivers/iio/gyro/bmg160.c @@ -0,0 +1,1228 @@ +/* + * 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 <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/events.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#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) +{ +#ifdef CONFIG_PM_RUNTIME + 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; + } +#endif + + 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_gpio_probe(struct i2c_client *client, + struct bmg160_data *data) + +{ + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, 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 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) + 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); + + 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 = name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmg160_info; + + if (client->irq <= 0) + client->irq = bmg160_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}, + {"BMI055B", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); + +static const struct i2c_device_id bmg160_id[] = { + {"bmg160", 0}, + {"bmi055_gyro", 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 <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMG160 Gyro driver"); 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/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*/ diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 0472ee268271..f971f79103ec 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -942,13 +942,34 @@ int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data) } EXPORT_SYMBOL_GPL(iio_push_to_buffers); +static int iio_buffer_add_demux(struct iio_buffer *buffer, + struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc, + unsigned int length) +{ + + if (*p && (*p)->from + (*p)->length == in_loc && + (*p)->to + (*p)->length == out_loc) { + (*p)->length += length; + } else { + *p = kmalloc(sizeof(**p), GFP_KERNEL); + if (*p == NULL) + return -ENOMEM; + (*p)->from = in_loc; + (*p)->to = out_loc; + (*p)->length = length; + list_add_tail(&(*p)->l, &buffer->demux_list); + } + + return 0; +} + static int iio_buffer_update_demux(struct iio_dev *indio_dev, struct iio_buffer *buffer) { const struct iio_chan_spec *ch; int ret, in_ind = -1, out_ind, length; unsigned in_loc = 0, out_loc = 0; - struct iio_demux_table *p; + struct iio_demux_table *p = NULL; /* Clear out any old demux */ iio_buffer_demux_free(buffer); @@ -979,14 +1000,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, else length = ch->scan_type.storagebits / 8; /* Make sure we are aligned */ - in_loc += length; - if (in_loc % length) - in_loc += length - in_loc % length; - } - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - ret = -ENOMEM; - goto error_clear_mux_table; + in_loc = roundup(in_loc, length) + length; } ch = iio_find_channel_from_si(indio_dev, in_ind); if (ch->scan_type.repeat > 1) @@ -994,24 +1008,16 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ch->scan_type.repeat; else length = ch->scan_type.storagebits / 8; - if (out_loc % length) - out_loc += length - out_loc % length; - if (in_loc % length) - in_loc += length - in_loc % length; - p->from = in_loc; - p->to = out_loc; - p->length = length; - list_add_tail(&p->l, &buffer->demux_list); + out_loc = roundup(out_loc, length); + in_loc = roundup(in_loc, length); + ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); + if (ret) + goto error_clear_mux_table; out_loc += length; in_loc += length; } /* Relies on scan_timestamp being last */ if (buffer->scan_timestamp) { - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - ret = -ENOMEM; - goto error_clear_mux_table; - } ch = iio_find_channel_from_si(indio_dev, indio_dev->scan_index_timestamp); if (ch->scan_type.repeat > 1) @@ -1019,14 +1025,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ch->scan_type.repeat; else length = ch->scan_type.storagebits / 8; - if (out_loc % length) - out_loc += length - out_loc % length; - if (in_loc % length) - in_loc += length - in_loc % length; - p->from = in_loc; - p->to = out_loc; - p->length = length; - list_add_tail(&p->l, &buffer->demux_list); + out_loc = roundup(out_loc, length); + in_loc = roundup(in_loc, length); + ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); + if (ret) + goto error_clear_mux_table; out_loc += length; in_loc += length; } 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 <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#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 <daniel.baluta@intel.com>"); +MODULE_DESCRIPTION("AL3320A Ambient Light Sensor driver"); +MODULE_LICENSE("GPL v2"); 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/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 diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 3ec777a8f64e..6294575d2777 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -246,8 +246,7 @@ static const struct iio_info magn_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); iio_push_to_buffers(indio_dev, data); @@ -263,9 +262,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); if (atomic_read(&magn_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - magn_state->iio_vals, - sizeof(magn_state->iio_vals)); + hid_sensor_push_data(indio_dev, magn_state->iio_vals); return 0; } @@ -533,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, }, }; |