diff --git a/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 b/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 new file mode 100644 index 000000000000..e98209c9155e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-gyro-bmg160 @@ -0,0 +1,7 @@ +What: /sys/bus/iio/devices/triggerX/name = "bmg160-any-motion-devX" +KernelVersion: 3.17 +Contact: linux-iio@vger.kernel.org +Description: + The BMG160 gyro kernel module provides an additional trigger, + which sets driver in a mode, where data is pushed to the buffer + only when there is any motion. diff --git a/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt new file mode 100644 index 000000000000..5d3ec1df226d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/rockchip-saradc.txt @@ -0,0 +1,24 @@ +Rockchip Successive Approximation Register (SAR) A/D Converter bindings + +Required properties: +- compatible: Should be "rockchip,saradc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Shall be "saradc" for the converter-clock, and "apb_pclk" for + the peripheral clock. +- vref-supply: The regulator supply ADC reference voltage. +- #io-channel-cells: Should be 1, see ../iio-bindings.txt + +Example: + saradc: saradc@2006c000 { + compatible = "rockchip,saradc"; + reg = <0x2006c000 0x100>; + interrupts = ; + clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + #io-channel-cells = <1>; + vref-supply = <&vcc18>; + }; diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 5704d6bc2267..9b9be8725e9d 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -6,13 +6,13 @@ menu "Accelerometers" config BMA180 - tristate "Bosch BMA180 3-Axis Accelerometer Driver" + tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say Y here if you want to build a driver for the Bosch BMA180 - triaxial acceleration sensor. + Say Y here if you want to build a driver for the Bosch BMA180 or + BMA250 triaxial acceleration sensor. To compile this driver as a module, choose M here: the module will be called bma180. @@ -23,7 +23,9 @@ config BMC150_ACCEL select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for the Bosch BMC150 accelerometer. + Say yes here to build support for the following Bosch accelerometers: + BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. + Currently this only supports the device via an i2c interface. This is a combo module with both accelerometer and magnetometer. @@ -97,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/bma180.c b/drivers/iio/accel/bma180.c index a077cc86421b..6ef19641457c 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -3,9 +3,15 @@ * * Copyright 2013 Oleksandr Kravchenko * + * Support for BMA250 (c) Peter Meerwald + * * This file is subject to the terms and conditions of version 2 of * the GNU General Public License. See the file COPYING in the main * directory of this archive for more details. + * + * SPI is not supported by driver + * BMA180: 7-bit I2C slave address 0x40 or 0x41 + * BMA250: 7-bit I2C slave address 0x18 or 0x19 */ #include @@ -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" +#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 -/* 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_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 bma180_get_acc_reg(struct bma180_data *data, enum bma180_axis axis) +static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */ +static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0, + 0, 0, 306458 }; + +static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan) { - 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 @@ static int bma180_set_new_data_intr_state(struct bma180_data *data, int state) 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,86 @@ 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_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_bits(data, BMA180_CTRL_REG0, BMA180_DIS_WAKE_UP, 1); if (ret) goto err; - ret = bma180_set_ee_writing_state(data, 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); - if (ret) - goto err; - ret = bma180_set_scale(data, BMA180_DEF_SCALE); + ret = bma180_set_scale(data, 2452); /* 2 G */ 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 int bma250_chip_config(struct bma180_data *data) +{ + int ret = bma180_chip_init(data); + + if (ret) + goto err; + ret = bma180_set_bw(data, 16); /* 16 Hz */ + if (ret) + goto err; + ret = bma180_set_scale(data, 38344); /* 2 G */ + if (ret) + goto err; + ret = bma180_set_bits(data, BMA250_INT_MAP_REG, + BMA250_INT1_DATA_MASK, 1); + if (ret) + goto err; + + return 0; + +err: + 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, 1)) + if (bma180_set_sleep_state(data, true)) goto err; return; @@ -316,13 +395,64 @@ static void bma180_chip_disable(struct bma180_data *data) 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 void bma250_chip_disable(struct bma180_data *data) +{ + if (bma180_set_new_data_intr_state(data, false)) + goto err; + if (bma180_set_sleep_state(data, true)) + goto err; + + return; + +err: + dev_err(&data->client->dev, "failed to disable the chip\n"); +} + +static ssize_t bma180_show_avail(char *buf, const int *vals, unsigned n, + bool micros) +{ + 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,44 +715,46 @@ 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_event", data->trig); + if (ret) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto err_trigger_free; + } + + data->trig->dev.parent = &client->dev; + data->trig->ops = &bma180_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + indio_dev->trig = data->trig; + + ret = iio_trigger_register(data->trig); + if (ret) + goto err_trigger_free; } - ret = devm_request_irq(&client->dev, client->irq, - iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, BMA180_IRQ_NAME, trig); - if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - goto err_trigger_free; - } - - trig->dev.parent = &client->dev; - trig->ops = &bma180_trigger_ops; - iio_trigger_set_drvdata(trig, indio_dev); - data->trig = trig; - indio_dev->trig = trig; - - ret = iio_trigger_register(trig); - if (ret) - goto err_trigger_free; - ret = iio_triggered_buffer_setup(indio_dev, NULL, bma180_trigger_handler, NULL); if (ret < 0) { @@ -595,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 "); 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 index 23ae33496214..22c096ce39ad 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -1,5 +1,12 @@ /* - * BMC150 3-axis accelerometer driver + * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: + * - BMC150 + * - BMI055 + * - BMA255 + * - BMA250E + * - BMA222E + * - BMA280 + * * Copyright (c) 2014, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it @@ -34,7 +41,6 @@ #define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" #define BMC150_ACCEL_REG_CHIP_ID 0x00 -#define BMC150_ACCEL_CHIP_ID_VAL 0xFA #define BMC150_ACCEL_REG_INT_STATUS_2 0x0B #define BMC150_ACCEL_ANY_MOTION_MASK 0x07 @@ -126,6 +132,18 @@ enum bmc150_power_modes { BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, }; +struct bmc150_scale_info { + int scale; + u8 reg_range; +}; + +struct bmc150_accel_chip_info { + u8 chip_id; + const struct iio_chan_spec *channels; + int num_channels; + const struct bmc150_scale_info scale_table[4]; +}; + struct bmc150_accel_data { struct i2c_client *client; struct iio_trigger *dready_trig; @@ -140,6 +158,7 @@ struct bmc150_accel_data { bool dready_trigger_on; bool motion_trigger_on; int64_t timestamp; + const struct bmc150_accel_chip_info *chip_info; }; static const struct { @@ -167,17 +186,9 @@ static const struct { {0x0E, 1}, {0x0F, 1} }; -static const struct { - int scale; - int range; -} bmc150_accel_scale_table[] = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, - {19122, BMC150_ACCEL_DEF_RANGE_4G}, - {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {77057, BMC150_ACCEL_DEF_RANGE_16G} }; - static const struct { int sleep_dur; - int reg_value; + u8 reg_value; } bmc150_accel_sleep_value_table[] = { {0, 0}, {500, BMC150_ACCEL_SLEEP_500_MICRO}, {1000, BMC150_ACCEL_SLEEP_1_MS}, @@ -267,7 +278,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) } dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != BMC150_ACCEL_CHIP_ID_VAL) { + if (ret != data->chip_info->chip_id) { dev_err(&data->client->dev, "Invalid chip %x\n", ret); return -ENODEV; } @@ -499,6 +510,7 @@ static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, return -EINVAL; } +#ifdef CONFIG_PM_RUNTIME static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) { int i; @@ -529,24 +541,30 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) return 0; } +#else +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + return 0; +} +#endif static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { int ret, i; - for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); ++i) { - if (bmc150_accel_scale_table[i].scale == val) { + for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { + if (data->chip_info->scale_table[i].scale == val) { ret = i2c_smbus_write_byte_data( - data->client, - BMC150_ACCEL_REG_PMU_RANGE, - bmc150_accel_scale_table[i].range); + data->client, + BMC150_ACCEL_REG_PMU_RANGE, + data->chip_info->scale_table[i].reg_range); if (ret < 0) { dev_err(&data->client->dev, "Error writing pmu_range\n"); return ret; } - data->range = bmc150_accel_scale_table[i].range; + data->range = data->chip_info->scale_table[i].reg_range; return 0; } } @@ -573,10 +591,12 @@ static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) return IIO_VAL_INT; } -static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis, +static int bmc150_accel_get_axis(struct bmc150_accel_data *data, + struct iio_chan_spec const *chan, int *val) { int ret; + int axis = chan->scan_index; mutex_lock(&data->mutex); ret = bmc150_accel_set_power_state(data, true); @@ -593,7 +613,8 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis, mutex_unlock(&data->mutex); return ret; } - *val = sign_extend32(ret >> 4, 11); + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); ret = bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); if (ret < 0) @@ -618,9 +639,7 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev, if (iio_buffer_enabled(indio_dev)) return -EBUSY; else - return bmc150_accel_get_axis(data, - chan->scan_index, - val); + return bmc150_accel_get_axis(data, chan, val); default: return -EINVAL; } @@ -639,13 +658,13 @@ static int bmc150_accel_read_raw(struct iio_dev *indio_dev, case IIO_ACCEL: { int i; + const struct bmc150_scale_info *si; + int st_size = ARRAY_SIZE(data->chip_info->scale_table); - for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); - ++i) { - if (bmc150_accel_scale_table[i].range == - data->range) { - *val2 = - bmc150_accel_scale_table[i].scale; + for (i = 0; i < st_size; ++i) { + si = &data->chip_info->scale_table[i]; + if (si->reg_range == data->range) { + *val2 = si->scale; return IIO_VAL_INT_PLUS_MICRO; } } @@ -833,7 +852,7 @@ static const struct iio_event_spec bmc150_accel_event = { BIT(IIO_EV_INFO_PERIOD) }; -#define BMC150_ACCEL_CHANNEL(_axis) { \ +#define BMC150_ACCEL_CHANNEL(_axis, bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##_axis, \ @@ -843,26 +862,101 @@ static const struct iio_event_spec bmc150_accel_event = { .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = (bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (bits), \ }, \ .event_spec = &bmc150_accel_event, \ .num_event_specs = 1 \ } -static const struct iio_chan_spec bmc150_accel_channels[] = { - { - .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_OFFSET), - .scan_index = -1, +#define BMC150_ACCEL_CHANNELS(bits) { \ + { \ + .type = IIO_TEMP, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = -1, \ + }, \ + BMC150_ACCEL_CHANNEL(X, bits), \ + BMC150_ACCEL_CHANNEL(Y, bits), \ + BMC150_ACCEL_CHANNEL(Z, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(3), \ +} + +static const struct iio_chan_spec bma222e_accel_channels[] = + BMC150_ACCEL_CHANNELS(8); +static const struct iio_chan_spec bma250e_accel_channels[] = + BMC150_ACCEL_CHANNELS(10); +static const struct iio_chan_spec bmc150_accel_channels[] = + BMC150_ACCEL_CHANNELS(12); +static const struct iio_chan_spec bma280_accel_channels[] = + BMC150_ACCEL_CHANNELS(14); + +enum { + bmc150, + bmi055, + bma255, + bma250e, + bma222e, + bma280, +}; + +static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { + [bmc150] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bmi055] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma255] = { + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma250e] = { + .chip_id = 0xF9, + .channels = bma250e_accel_channels, + .num_channels = ARRAY_SIZE(bma250e_accel_channels), + .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G}, + {76590, BMC150_ACCEL_DEF_RANGE_4G}, + {153277, BMC150_ACCEL_DEF_RANGE_8G}, + {306457, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma222e] = { + .chip_id = 0xF8, + .channels = bma222e_accel_channels, + .num_channels = ARRAY_SIZE(bma222e_accel_channels), + .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G}, + {306457, BMC150_ACCEL_DEF_RANGE_4G}, + {612915, BMC150_ACCEL_DEF_RANGE_8G}, + {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma280] = { + .chip_id = 0xFB, + .channels = bma280_accel_channels, + .num_channels = ARRAY_SIZE(bma280_accel_channels), + .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G}, + {4785, BMC150_ACCEL_DEF_RANGE_4G}, + {9581, BMC150_ACCEL_DEF_RANGE_8G}, + {19152, BMC150_ACCEL_DEF_RANGE_16G} }, }, - BMC150_ACCEL_CHANNEL(X), - BMC150_ACCEL_CHANNEL(Y), - BMC150_ACCEL_CHANNEL(Z), - IIO_CHAN_SOFT_TIMESTAMP(3), }; static const struct iio_info bmc150_accel_info = { @@ -1033,10 +1127,23 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private) return IRQ_HANDLED; } -static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client, - struct bmc150_accel_data *data) +static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) { const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return NULL; + + *data = (int) id->driver_data; + + return dev_name(dev); +} + +static int bmc150_accel_gpio_probe(struct i2c_client *client, + struct bmc150_accel_data *data) +{ struct device *dev; struct gpio_desc *gpio; int ret; @@ -1045,17 +1152,11 @@ static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client, return -EINVAL; dev = &client->dev; - if (!ACPI_HANDLE(dev)) - return -ENODEV; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; /* data ready gpio interrupt pin */ gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0); if (IS_ERR(gpio)) { - dev_err(dev, "Failed: acpi gpio get index\n"); + dev_err(dev, "Failed: gpio get index\n"); return PTR_ERR(gpio); } @@ -1076,6 +1177,8 @@ static int bmc150_accel_probe(struct i2c_client *client, struct bmc150_accel_data *data; struct iio_dev *indio_dev; int ret; + const char *name = NULL; + int chip_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1085,6 +1188,16 @@ static int bmc150_accel_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; + if (id) { + name = id->name; + chip_id = id->driver_data; + } + + if (ACPI_HANDLE(&client->dev)) + name = bmc150_accel_match_acpi_device(&client->dev, &chip_id); + + data->chip_info = &bmc150_accel_chip_info_tbl[chip_id]; + ret = bmc150_accel_chip_init(data); if (ret < 0) return ret; @@ -1092,14 +1205,14 @@ static int bmc150_accel_probe(struct i2c_client *client, mutex_init(&data->mutex); indio_dev->dev.parent = &client->dev; - indio_dev->channels = bmc150_accel_channels; - indio_dev->num_channels = ARRAY_SIZE(bmc150_accel_channels); - indio_dev->name = BMC150_ACCEL_DRV_NAME; + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; if (client->irq < 0) - client->irq = bmc150_accel_acpi_gpio_probe(client, data); + client->irq = bmc150_accel_gpio_probe(client, data); if (client->irq >= 0) { ret = devm_request_threaded_irq( @@ -1277,14 +1390,24 @@ static const struct dev_pm_ops bmc150_accel_pm_ops = { }; static const struct acpi_device_id bmc150_accel_acpi_match[] = { - {"BSBA0150", 0}, - {"BMC150A", 0}, + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, { }, }; MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); static const struct i2c_device_id bmc150_accel_id[] = { - {"bmc150_accel", 0}, + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, {} }; 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 57c515bf0fd2..98909a9e284e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -75,16 +76,38 @@ #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]; u8 odr_bits; u8 range; + int wake_thres; + int wake_dur; bool active_high_intr; - bool trigger_on; + bool dready_trigger_on; + int ev_enable_state; + bool motion_trigger_on; + int64_t timestamp; + enum kx_chipset chipset; }; enum kxcjk1013_axis { @@ -118,10 +141,53 @@ static const struct { static const struct { int odr_bits; int usec; -} odr_start_up_times[] = { {0x08, 100000}, {0x09, 100000}, {0x0A, 100000}, - {0x0B, 100000}, { 0, 80000}, {0x01, 41000}, - {0x02, 21000}, {0x03, 11000}, {0x04, 6400}, - {0x05, 3900}, {0x06, 2700}, {0x07, 2100} }; +} odr_start_up_times[KX_MAX_CHIPS][12] = { + /* KXCJK-1013 */ + { + {0x08, 100000}, + {0x09, 100000}, + {0x0A, 100000}, + {0x0B, 100000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6400}, + {0x05, 3900}, + {0x06, 2700}, + {0x07, 2100}, + }, + /* KXCJ9-1008 */ + { + {0x08, 100000}, + {0x09, 100000}, + {0x0A, 100000}, + {0x0B, 100000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6400}, + {0x05, 3900}, + {0x06, 2700}, + {0x07, 2100}, + }, + /* KXCTJ2-1009 */ + { + {0x08, 1240000}, + {0x09, 621000}, + {0x0A, 309000}, + {0x0B, 151000}, + {0, 80000}, + {0x01, 41000}, + {0x02, 21000}, + {0x03, 11000}, + {0x04, 6000}, + {0x05, 4000}, + {0x06, 3000}, + {0x07, 2000}, + }, +}; static const struct { u16 scale; @@ -131,6 +197,23 @@ static const struct { {19163, 1, 0}, {38326, 0, 1} }; +static const struct { + int val; + int val2; + int odr_bits; +} wake_odr_data_rate_table[] = { {0, 781000, 0x00}, + {1, 563000, 0x01}, + {3, 125000, 0x02}, + {6, 250000, 0x03}, + {12, 500000, 0x04}, + {25, 0, 0x05}, + {50, 0, 0x06}, + {100, 0, 0x06}, + {200, 0, 0x06}, + {400, 0, 0x06}, + {800, 0, 0x06}, + {1600, 0, 0x06} }; + static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { @@ -239,9 +322,6 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; - data->range = KXCJK1013_RANGE_4G; - - ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); @@ -273,20 +353,25 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) if (ret < 0) return ret; + data->wake_thres = KXCJK1013_DEFAULT_WAKE_THRES; + return 0; } +#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); ++i) { - if (odr_start_up_times[i].odr_bits == data->odr_bits) - return odr_start_up_times[i].usec; + for (i = 0; i < ARRAY_SIZE(odr_start_up_times[idx]); ++i) { + if (odr_start_up_times[idx][i].odr_bits == data->odr_bits) + return odr_start_up_times[idx][i].usec; } return KXCJK1013_MAX_STARTUP_TIME_US; } +#endif static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) { @@ -307,8 +392,96 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) return 0; } -static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, - bool status) +static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_WAKE_TIMER, + data->wake_dur); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_wake_timer\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_WAKE_THRES, + data->wake_thres); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_wake_thres\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data, + bool status) +{ + int ret; + enum kxcjk1013_mode store_mode; + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; + + /* This is requirement by spec to change state to STANDBY */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = kxcjk1013_chip_update_thresholds(data); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEN; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_WUFE; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; +} + +static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data, + bool status) { int ret; enum kxcjk1013_mode store_mode; @@ -381,6 +554,20 @@ static int kxcjk1013_convert_freq_to_bit(int val, int val2) return -EINVAL; } +static int kxcjk1013_convert_wake_odr_to_bit(int val, int val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wake_odr_data_rate_table); ++i) { + if (wake_odr_data_rate_table[i].val == val && + wake_odr_data_rate_table[i].val2 == val2) { + return wake_odr_data_rate_table[i].odr_bits; + } + } + + return -EINVAL; +} + static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) { int ret; @@ -409,6 +596,17 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_bits; + odr_bits = kxcjk1013_convert_wake_odr_to_bit(val, val2); + if (odr_bits < 0) + return odr_bits; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2, + odr_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl2\n"); + return ret; + } + if (store_mode == OPERATION) { ret = kxcjk1013_set_mode(data, OPERATION); if (ret < 0) @@ -560,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; @@ -586,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, \ @@ -601,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[] = { @@ -614,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, }; @@ -639,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); @@ -668,19 +988,32 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; - if (state && data->trigger_on) - return 0; - mutex_lock(&data->mutex); - ret = kxcjk1013_chip_setup_interrupt(data, state); - if (!ret) { - ret = kxcjk1013_set_power_state(data, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } + + if (!state && data->ev_enable_state && data->motion_trigger_on) { + data->motion_trigger_on = false; + mutex_unlock(&data->mutex); + return 0; } - data->trigger_on = state; + + ret = kxcjk1013_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + ret = kxcjk1013_setup_any_motion_interrupt(data, state); + else + ret = kxcjk1013_setup_new_data_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + data->motion_trigger_on = state; + else + data->dready_trigger_on = state; + mutex_unlock(&data->mutex); return 0; @@ -692,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; @@ -704,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); @@ -734,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)); @@ -752,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; @@ -761,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) + ret = devm_request_threaded_irq(&client->dev, client->irq, + kxcjk1013_data_rdy_trig_poll, + kxcjk1013_event_handler, + IRQF_TRIGGER_RISING, + KXCJK1013_IRQ_NAME, + indio_dev); + if (ret) + return ret; + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) return -ENOMEM; - data->trig_mode = true; + data->motion_trig = devm_iio_trigger_alloc(&client->dev, + "%s-any-motion-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->motion_trig) + return -ENOMEM; - ret = devm_request_irq(&client->dev, client->irq, - iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, - KXCJK1013_IRQ_NAME, - trig); - if (ret) { - dev_err(&client->dev, "unable to request IRQ\n"); - goto err_trigger_free; - } - - trig->dev.parent = &client->dev; - trig->ops = &kxcjk1013_trigger_ops; - iio_trigger_set_drvdata(trig, indio_dev); - data->trig = trig; - indio_dev->trig = trig; + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + indio_dev->trig = data->dready_trig; iio_trigger_get(indio_dev->trig); - - ret = iio_trigger_register(trig); + ret = iio_trigger_register(data->dready_trig); if (ret) - goto err_trigger_free; + return ret; + + data->motion_trig->dev.parent = &client->dev; + data->motion_trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(data->motion_trig, indio_dev); + ret = iio_trigger_register(data->motion_trig); + if (ret) { + data->motion_trig = NULL; + goto err_trigger_unregister; + } ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, @@ -828,14 +1291,13 @@ static int kxcjk1013_probe(struct i2c_client *client, err_iio_unregister: iio_device_unregister(indio_dev); err_buffer_cleanup: - if (data->trig_mode) + if (data->dready_trig) iio_triggered_buffer_cleanup(indio_dev); err_trigger_unregister: - if (data->trig_mode) - iio_trigger_unregister(trig); -err_trigger_free: - if (data->trig_mode) - iio_trigger_free(trig); + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + if (data->motion_trig) + iio_trigger_unregister(data->motion_trig); return ret; } @@ -851,10 +1313,10 @@ static int kxcjk1013_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - if (data->trig_mode) { + if (data->dready_trig) { iio_triggered_buffer_cleanup(indio_dev); - iio_trigger_unregister(data->trig); - iio_trigger_free(data->trig); + iio_trigger_unregister(data->dready_trig); + iio_trigger_unregister(data->motion_trig); } mutex_lock(&data->mutex); @@ -886,7 +1348,8 @@ static int kxcjk1013_resume(struct device *dev) mutex_lock(&data->mutex); /* Check, if the suspend occured while active */ - if (data->trigger_on) + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) ret = kxcjk1013_set_mode(data, OPERATION); mutex_unlock(&data->mutex); @@ -931,13 +1394,17 @@ static const struct dev_pm_ops kxcjk1013_pm_ops = { }; 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}, {} }; diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 772e869c280e..7807e0ef5b29 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -266,7 +266,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) } /* Handler for classic adc channel eoc trigger */ -void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) +static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) { struct at91_adc_state *st = iio_priv(idev); diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index c59012d2d06f..43620fd4c66a 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -723,7 +723,6 @@ static struct platform_driver exynos_adc_driver = { .remove = exynos_adc_remove, .driver = { .name = "exynos-adc", - .owner = THIS_MODULE, .of_match_table = exynos_adc_match, .pm = &exynos_adc_pm_ops, }, diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c index 5c8c91595f47..152cfc8e1c7b 100644 --- a/drivers/iio/adc/lp8788_adc.c +++ b/drivers/iio/adc/lp8788_adc.c @@ -244,7 +244,6 @@ static struct platform_driver lp8788_adc_driver = { .remove = lp8788_adc_remove, .driver = { .name = LP8788_DEV_ADC, - .owner = THIS_MODULE, }, }; module_platform_driver(lp8788_adc_driver); diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c index 1fad9647cef4..e074a0b03f28 100644 --- a/drivers/iio/adc/rockchip_saradc.c +++ b/drivers/iio/adc/rockchip_saradc.c @@ -141,7 +141,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev) struct resource *mem; int ret; int irq; - u32 rate; if (!np) return -ENODEV; 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/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/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BMG160_DRV_NAME "bmg160" +#define BMG160_IRQ_NAME "bmg160_event" +#define BMG160_GPIO_NAME "gpio_int" + +#define BMG160_REG_CHIP_ID 0x00 +#define BMG160_CHIP_ID_VAL 0x0F + +#define BMG160_REG_PMU_LPW 0x11 +#define BMG160_MODE_NORMAL 0x00 +#define BMG160_MODE_DEEP_SUSPEND 0x20 +#define BMG160_MODE_SUSPEND 0x80 + +#define BMG160_REG_RANGE 0x0F + +#define BMG160_RANGE_2000DPS 0 +#define BMG160_RANGE_1000DPS 1 +#define BMG160_RANGE_500DPS 2 +#define BMG160_RANGE_250DPS 3 +#define BMG160_RANGE_125DPS 4 + +#define BMG160_REG_PMU_BW 0x10 +#define BMG160_NO_FILTER 0 +#define BMG160_DEF_BW 100 + +#define BMG160_REG_INT_MAP_0 0x17 +#define BMG160_INT_MAP_0_BIT_ANY BIT(1) + +#define BMG160_REG_INT_MAP_1 0x18 +#define BMG160_INT_MAP_1_BIT_NEW_DATA BIT(0) + +#define BMG160_REG_INT_RST_LATCH 0x21 +#define BMG160_INT_MODE_LATCH_RESET 0x80 +#define BMG160_INT_MODE_LATCH_INT 0x0F +#define BMG160_INT_MODE_NON_LATCH_INT 0x00 + +#define BMG160_REG_INT_EN_0 0x15 +#define BMG160_DATA_ENABLE_INT BIT(7) + +#define BMG160_REG_XOUT_L 0x02 +#define BMG160_AXIS_TO_REG(axis) (BMG160_REG_XOUT_L + (axis * 2)) + +#define BMG160_REG_SLOPE_THRES 0x1B +#define BMG160_SLOPE_THRES_MASK 0x0F + +#define BMG160_REG_MOTION_INTR 0x1C +#define BMG160_INT_MOTION_X BIT(0) +#define BMG160_INT_MOTION_Y BIT(1) +#define BMG160_INT_MOTION_Z BIT(2) +#define BMG160_ANY_DUR_MASK 0x30 +#define BMG160_ANY_DUR_SHIFT 4 + +#define BMG160_REG_INT_STATUS_2 0x0B +#define BMG160_ANY_MOTION_MASK 0x07 + +#define BMG160_REG_TEMP 0x08 +#define BMG160_TEMP_CENTER_VAL 23 + +#define BMG160_MAX_STARTUP_TIME_MS 80 + +#define BMG160_AUTO_SUSPEND_DELAY_MS 2000 + +struct bmg160_data { + struct i2c_client *client; + struct iio_trigger *dready_trig; + struct iio_trigger *motion_trig; + struct mutex mutex; + s16 buffer[8]; + u8 bw_bits; + u32 dps_range; + int ev_enable_state; + int slope_thres; + bool dready_trigger_on; + bool motion_trigger_on; + int64_t timestamp; +}; + +enum bmg160_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +static const struct { + int val; + int bw_bits; +} bmg160_samp_freq_table[] = { {100, 0x07}, + {200, 0x06}, + {400, 0x03}, + {1000, 0x02}, + {2000, 0x01} }; + +static const struct { + int scale; + int dps_range; +} bmg160_scale_table[] = { { 1065, BMG160_RANGE_2000DPS}, + { 532, BMG160_RANGE_1000DPS}, + { 266, BMG160_RANGE_500DPS}, + { 133, BMG160_RANGE_250DPS}, + { 66, BMG160_RANGE_125DPS} }; + +static int bmg160_set_mode(struct bmg160_data *data, u8 mode) +{ + int ret; + + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_PMU_LPW, mode); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); + return ret; + } + + return 0; +} + +static int bmg160_convert_freq_to_bit(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmg160_samp_freq_table); ++i) { + if (bmg160_samp_freq_table[i].val == val) + return bmg160_samp_freq_table[i].bw_bits; + } + + return -EINVAL; +} + +static int bmg160_set_bw(struct bmg160_data *data, int val) +{ + int ret; + int bw_bits; + + bw_bits = bmg160_convert_freq_to_bit(val); + if (bw_bits < 0) + return bw_bits; + + ret = i2c_smbus_write_byte_data(data->client, BMG160_REG_PMU_BW, + bw_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_bw\n"); + return ret; + } + + data->bw_bits = bw_bits; + + return 0; +} + +static int bmg160_chip_init(struct bmg160_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_chip_id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != BMG160_CHIP_ID_VAL) { + dev_err(&data->client->dev, "invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmg160_set_mode(data, BMG160_MODE_NORMAL); + if (ret < 0) + return ret; + + /* Wait upto 500 ms to be ready after changing mode */ + usleep_range(500, 1000); + + /* Set Bandwidth */ + ret = bmg160_set_bw(data, BMG160_DEF_BW); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_RANGE, + BMG160_RANGE_500DPS); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_range\n"); + return ret; + } + data->dps_range = BMG160_RANGE_500DPS; + + ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_SLOPE_THRES); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_slope_thres\n"); + return ret; + } + data->slope_thres = ret; + + /* Set default interrupt mode */ + ret = i2c_smbus_write_byte_data(data->client, + BMG160_REG_INT_RST_LATCH, + BMG160_INT_MODE_LATCH_INT | + BMG160_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_motion_intr\n"); + return ret; + } + + return 0; +} + +static int bmg160_set_power_state(struct bmg160_data *data, bool on) +{ +#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 "); +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/light/Kconfig b/drivers/iio/light/Kconfig index bf05ca5b0a57..5bea821adcae 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -17,6 +17,16 @@ config ADJD_S311 This driver can also be built as a module. If so, the module will be called adjd_s311. +config AL3320A + tristate "AL3320A ambient light sensor" + depends on I2C + help + Say Y here if you want to build a driver for the Dyna Image AL3320A + ambient light sensor. + + To compile this driver as a module, choose M here: the + module will be called al3320a. + config APDS9300 tristate "APDS9300 ambient light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 8b8c09f9c1f8..47877a36cc12 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ADJD_S311) += adjd_s311.o +obj-$(CONFIG_AL3320A) += al3320a.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_CM32181) += cm32181.o obj-$(CONFIG_CM36651) += cm36651.o diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c new file mode 100644 index 000000000000..6aac6513fd41 --- /dev/null +++ b/drivers/iio/light/al3320a.c @@ -0,0 +1,232 @@ +/* + * AL3320A - Dyna Image Ambient Light Sensor + * + * Copyright (c) 2014, Intel Corporation. + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * IIO driver for AL3320A (7-bit I2C slave address 0x1C). + * + * TODO: interrupt support, thresholds + * + */ + +#include +#include +#include + +#include +#include + +#define AL3320A_DRV_NAME "al3320a" + +#define AL3320A_REG_CONFIG 0x00 +#define AL3320A_REG_STATUS 0x01 +#define AL3320A_REG_INT 0x02 +#define AL3320A_REG_WAIT 0x06 +#define AL3320A_REG_CONFIG_RANGE 0x07 +#define AL3320A_REG_PERSIST 0x08 +#define AL3320A_REG_MEAN_TIME 0x09 +#define AL3320A_REG_ADUMMY 0x0A +#define AL3320A_REG_DATA_LOW 0x22 + +#define AL3320A_REG_LOW_THRESH_LOW 0x30 +#define AL3320A_REG_LOW_THRESH_HIGH 0x31 +#define AL3320A_REG_HIGH_THRESH_LOW 0x32 +#define AL3320A_REG_HIGH_THRESH_HIGH 0x33 + +#define AL3320A_CONFIG_DISABLE 0x00 +#define AL3320A_CONFIG_ENABLE 0x01 + +#define AL3320A_GAIN_SHIFT 1 +#define AL3320A_GAIN_MASK (BIT(2) | BIT(1)) + +/* chip params default values */ +#define AL3320A_DEFAULT_MEAN_TIME 4 +#define AL3320A_DEFAULT_WAIT_TIME 0 /* no waiting */ + +#define AL3320A_SCALE_AVAILABLE "0.512 0.128 0.032 0.01" + +enum al3320a_range { + AL3320A_RANGE_1, /* 33.28 Klx */ + AL3320A_RANGE_2, /* 8.32 Klx */ + AL3320A_RANGE_3, /* 2.08 Klx */ + AL3320A_RANGE_4 /* 0.65 Klx */ +}; + +static const int al3320a_scales[][2] = { + {0, 512000}, {0, 128000}, {0, 32000}, {0, 10000} +}; + +struct al3320a_data { + struct i2c_client *client; +}; + +static const struct iio_chan_spec al3320a_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + } +}; + +static IIO_CONST_ATTR(in_illuminance_scale_available, AL3320A_SCALE_AVAILABLE); + +static struct attribute *al3320a_attributes[] = { + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group al3320a_attribute_group = { + .attrs = al3320a_attributes, +}; + +static int al3320a_init(struct al3320a_data *data) +{ + int ret; + + /* power on */ + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG, + AL3320A_CONFIG_ENABLE); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE, + AL3320A_RANGE_3 << AL3320A_GAIN_SHIFT); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_MEAN_TIME, + AL3320A_DEFAULT_MEAN_TIME); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_WAIT, + AL3320A_DEFAULT_WAIT_TIME); + if (ret < 0) + return ret; + + return 0; +} + +static int al3320a_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct al3320a_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * ALS ADC value is stored in two adjacent registers: + * - low byte of output is stored at AL3320A_REG_DATA_LOW + * - high byte of output is stored at AL3320A_REG_DATA_LOW + 1 + */ + ret = i2c_smbus_read_word_data(data->client, + AL3320A_REG_DATA_LOW); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = i2c_smbus_read_byte_data(data->client, + AL3320A_REG_CONFIG_RANGE); + if (ret < 0) + return ret; + + ret = (ret & AL3320A_GAIN_MASK) >> AL3320A_GAIN_SHIFT; + *val = al3320a_scales[ret][0]; + *val2 = al3320a_scales[ret][1]; + + return IIO_VAL_INT_PLUS_MICRO; + } + return -EINVAL; +} + +static int al3320a_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct al3320a_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + for (i = 0; i < ARRAY_SIZE(al3320a_scales); i++) { + if (val == al3320a_scales[i][0] && + val2 == al3320a_scales[i][1]) + return i2c_smbus_write_byte_data(data->client, + AL3320A_REG_CONFIG_RANGE, + i << AL3320A_GAIN_SHIFT); + } + break; + } + return -EINVAL; +} + +static const struct iio_info al3320a_info = { + .driver_module = THIS_MODULE, + .read_raw = al3320a_read_raw, + .write_raw = al3320a_write_raw, + .attrs = &al3320a_attribute_group, +}; + +static int al3320a_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct al3320a_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &al3320a_info; + indio_dev->name = AL3320A_DRV_NAME; + indio_dev->channels = al3320a_channels; + indio_dev->num_channels = ARRAY_SIZE(al3320a_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = al3320a_init(data); + if (ret < 0) { + dev_err(&client->dev, "al3320a chip init failed\n"); + return ret; + } + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int al3320a_remove(struct i2c_client *client) +{ + return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG, + AL3320A_CONFIG_DISABLE); +} + +static const struct i2c_device_id al3320a_id[] = { + {"al3320a", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, al3320a_id); + +static struct i2c_driver al3320a_driver = { + .driver = { + .name = AL3320A_DRV_NAME, + }, + .probe = al3320a_probe, + .remove = al3320a_remove, + .id_table = al3320a_id, +}; + +module_i2c_driver(al3320a_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("AL3320A Ambient Light Sensor driver"); +MODULE_LICENSE("GPL v2"); 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 1e717c71c244..6294575d2777 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -530,7 +530,6 @@ static struct platform_driver hid_magn_3d_platform_driver = { .id_table = hid_magn_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_magn_3d_probe, .remove = hid_magn_3d_remove, diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 2478f6c2ef25..1ff181bbbcef 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -437,7 +437,6 @@ static struct platform_driver hid_incl_3d_platform_driver = { .id_table = hid_incl_3d_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_incl_3d_probe, .remove = hid_incl_3d_remove, diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index dccf848e8b0f..4afb6c79ccbc 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -334,7 +334,6 @@ static struct platform_driver hid_dev_rot_platform_driver = { .id_table = hid_dev_rot_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_dev_rot_probe, .remove = hid_dev_rot_remove, diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 2c0d2a4fed8c..764928682df2 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -382,7 +382,6 @@ static struct platform_driver hid_press_platform_driver = { .id_table = hid_press_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_press_probe, .remove = hid_press_remove, diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 7a149a7822bc..572bc6f02ca8 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -109,7 +109,6 @@ static struct platform_driver iio_interrupt_trigger_driver = { .remove = iio_interrupt_trigger_remove, .driver = { .name = "iio_interrupt_trigger", - .owner = THIS_MODULE, }, }; diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index f0f05f195d2c..bf2c8013134c 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -140,7 +140,7 @@ static ssize_t ad7606_store_range(struct device *dev, return count; } -static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, \ +static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR, ad7606_show_range, ad7606_store_range, 0); static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000"); diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 86cc8f9fef06..65a35daead32 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -1,5 +1,5 @@ /* - * A iio driver for the light sensor ISL 29018. + * A iio driver for the light sensor ISL 29018/29023/29035. * * IIO driver for monitoring ambient light intensity in luxi, proximity * sensing and infrared sensing. @@ -30,6 +30,7 @@ #include #include #include +#include #define CONVERSION_TIME_MS 100 @@ -58,10 +59,18 @@ #define ISL29018_TEST_SHIFT 0 #define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) +#define ISL29035_REG_DEVICE_ID 0x0F +#define ISL29035_DEVICE_ID_SHIFT 0x03 +#define ISL29035_DEVICE_ID_MASK (0x7 << ISL29035_DEVICE_ID_SHIFT) +#define ISL29035_DEVICE_ID 0x5 +#define ISL29035_BOUT_SHIFT 0x07 +#define ISL29035_BOUT_MASK (0x01 << ISL29035_BOUT_SHIFT) + struct isl29018_chip { struct device *dev; struct regmap *regmap; struct mutex lock; + int type; unsigned int lux_scale; unsigned int lux_uscale; unsigned int range; @@ -407,23 +416,35 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, return ret; } +#define ISL29018_LIGHT_CHANNEL { \ + .type = IIO_LIGHT, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ +} + +#define ISL29018_IR_CHANNEL { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .channel2 = IIO_MOD_LIGHT_IR, \ +} + +#define ISL29018_PROXIMITY_CHANNEL { \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +} + static const struct iio_chan_spec isl29018_channels[] = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, { - .type = IIO_INTENSITY, - .modified = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .channel2 = IIO_MOD_LIGHT_IR, - }, { - /* Unindexed in current ABI. But perhaps it should be. */ - .type = IIO_PROXIMITY, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - } + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, + ISL29018_PROXIMITY_CHANNEL, +}; + +static const struct iio_chan_spec isl29023_channels[] = { + ISL29018_LIGHT_CHANNEL, + ISL29018_IR_CHANNEL, }; static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); @@ -447,16 +468,63 @@ static struct attribute *isl29018_attributes[] = { NULL }; -static const struct attribute_group isl29108_group = { +static struct attribute *isl29023_attributes[] = { + ISL29018_DEV_ATTR(range), + ISL29018_CONST_ATTR(range_available), + ISL29018_DEV_ATTR(adc_resolution), + ISL29018_CONST_ATTR(adc_resolution_available), + NULL +}; + +static const struct attribute_group isl29018_group = { .attrs = isl29018_attributes, }; +static const struct attribute_group isl29023_group = { + .attrs = isl29023_attributes, +}; + +static int isl29035_detect(struct isl29018_chip *chip) +{ + int status; + unsigned int id; + + status = regmap_read(chip->regmap, ISL29035_REG_DEVICE_ID, &id); + if (status < 0) { + dev_err(chip->dev, + "Error reading ID register with error %d\n", + status); + return status; + } + + id = (id & ISL29035_DEVICE_ID_MASK) >> ISL29035_DEVICE_ID_SHIFT; + + if (id != ISL29035_DEVICE_ID) + return -ENODEV; + + /* clear out brownout bit */ + return regmap_update_bits(chip->regmap, ISL29035_REG_DEVICE_ID, + ISL29035_BOUT_MASK, 0); +} + +enum { + isl29018, + isl29023, + isl29035, +}; + static int isl29018_chip_init(struct isl29018_chip *chip) { int status; unsigned int new_adc_bit; unsigned int new_range; + if (chip->type == isl29035) { + status = isl29035_detect(chip); + if (status < 0) + return status; + } + /* Code added per Intersil Application Note 1534: * When VDD sinks to approximately 1.8V or below, some of * the part's registers may change their state. When VDD @@ -510,8 +578,15 @@ static int isl29018_chip_init(struct isl29018_chip *chip) return 0; } -static const struct iio_info isl29108_info = { - .attrs = &isl29108_group, +static const struct iio_info isl29018_info = { + .attrs = &isl29018_group, + .driver_module = THIS_MODULE, + .read_raw = &isl29018_read_raw, + .write_raw = &isl29018_write_raw, +}; + +static const struct iio_info isl29023_info = { + .attrs = &isl29023_group, .driver_module = THIS_MODULE, .read_raw = &isl29018_read_raw, .write_raw = &isl29018_write_raw, @@ -524,6 +599,7 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg) case ISL29018_REG_ADD_DATA_MSB: case ISL29018_REG_ADD_COMMAND1: case ISL29018_REG_TEST: + case ISL29035_REG_DEVICE_ID: return true; default: return false; @@ -543,12 +619,66 @@ static const struct regmap_config isl29018_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +/* isl29035_regmap_config: regmap configuration for ISL29035 */ +static const struct regmap_config isl29035_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = is_volatile_reg, + .max_register = ISL29035_REG_DEVICE_ID, + .num_reg_defaults_raw = ISL29035_REG_DEVICE_ID + 1, + .cache_type = REGCACHE_RBTREE, +}; + +struct chip_info { + const struct iio_chan_spec *channels; + int num_channels; + const struct iio_info *indio_info; + const struct regmap_config *regmap_cfg; +}; + +static const struct chip_info chip_info_tbl[] = { + [isl29018] = { + .channels = isl29018_channels, + .num_channels = ARRAY_SIZE(isl29018_channels), + .indio_info = &isl29018_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29023] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29018_regmap_config, + }, + [isl29035] = { + .channels = isl29023_channels, + .num_channels = ARRAY_SIZE(isl29023_channels), + .indio_info = &isl29023_info, + .regmap_cfg = &isl29035_regmap_config, + }, +}; + +static const char *isl29018_match_acpi_device(struct device *dev, int *data) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + + if (!id) + return NULL; + + *data = (int) id->driver_data; + + return dev_name(dev); +} + static int isl29018_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct isl29018_chip *chip; struct iio_dev *indio_dev; int err; + const char *name = NULL; + int dev_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip)); if (indio_dev == NULL) { @@ -560,15 +690,25 @@ static int isl29018_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); chip->dev = &client->dev; + if (id) { + name = id->name; + dev_id = id->driver_data; + } + + if (ACPI_HANDLE(&client->dev)) + name = isl29018_match_acpi_device(&client->dev, &dev_id); + mutex_init(&chip->lock); + chip->type = dev_id; chip->lux_scale = 1; chip->lux_uscale = 0; chip->range = 1000; chip->adc_bit = 16; chip->suspended = false; - chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config); + chip->regmap = devm_regmap_init_i2c(client, + chip_info_tbl[dev_id].regmap_cfg); if (IS_ERR(chip->regmap)) { err = PTR_ERR(chip->regmap); dev_err(chip->dev, "regmap initialization failed: %d\n", err); @@ -579,10 +719,10 @@ static int isl29018_probe(struct i2c_client *client, if (err) return err; - indio_dev->info = &isl29108_info; - indio_dev->channels = isl29018_channels; - indio_dev->num_channels = ARRAY_SIZE(isl29018_channels); - indio_dev->name = id->name; + indio_dev->info = chip_info_tbl[dev_id].indio_info; + indio_dev->channels = chip_info_tbl[dev_id].channels; + indio_dev->num_channels = chip_info_tbl[dev_id].num_channels; + indio_dev->name = name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; err = devm_iio_device_register(&client->dev, indio_dev); @@ -632,8 +772,18 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume); #define ISL29018_PM_OPS NULL #endif +static const struct acpi_device_id isl29018_acpi_match[] = { + {"ISL29018", isl29018}, + {"ISL29023", isl29023}, + {"ISL29035", isl29035}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match); + static const struct i2c_device_id isl29018_id[] = { - {"isl29018", 0}, + {"isl29018", isl29018}, + {"isl29023", isl29023}, + {"isl29035", isl29035}, {} }; @@ -641,6 +791,8 @@ MODULE_DEVICE_TABLE(i2c, isl29018_id); static const struct of_device_id isl29018_of_match[] = { { .compatible = "isil,isl29018", }, + { .compatible = "isil,isl29023", }, + { .compatible = "isil,isl29035", }, { }, }; MODULE_DEVICE_TABLE(of, isl29018_of_match); @@ -649,6 +801,7 @@ static struct i2c_driver isl29018_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "isl29018", + .acpi_match_table = ACPI_PTR(isl29018_acpi_match), .pm = ISL29018_PM_OPS, .owner = THIS_MODULE, .of_match_table = isl29018_of_match,