diff options
Diffstat (limited to 'drivers/iio/accel')
-rw-r--r-- | drivers/iio/accel/Kconfig | 33 | ||||
-rw-r--r-- | drivers/iio/accel/Makefile | 6 | ||||
-rw-r--r-- | drivers/iio/accel/bmc150-accel-core.c (renamed from drivers/iio/accel/bmc150-accel.c) | 407 | ||||
-rw-r--r-- | drivers/iio/accel/bmc150-accel-i2c.c | 102 | ||||
-rw-r--r-- | drivers/iio/accel/bmc150-accel-spi.c | 91 | ||||
-rw-r--r-- | drivers/iio/accel/bmc150-accel.h | 20 | ||||
-rw-r--r-- | drivers/iio/accel/kxcjk-1013.c | 34 | ||||
-rw-r--r-- | drivers/iio/accel/mma8452.c | 356 | ||||
-rw-r--r-- | drivers/iio/accel/mma9553.c | 29 | ||||
-rw-r--r-- | drivers/iio/accel/mxc4005.c | 567 | ||||
-rw-r--r-- | drivers/iio/accel/st_accel_core.c | 1 | ||||
-rw-r--r-- | drivers/iio/accel/stk8312.c | 30 | ||||
-rw-r--r-- | drivers/iio/accel/stk8ba50.c | 30 |
13 files changed, 1255 insertions, 451 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index a59047d7657e..969428dd6329 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -19,19 +19,27 @@ config BMA180 config BMC150_ACCEL tristate "Bosch BMC150 Accelerometer Driver" - depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER + select REGMAP + select BMC150_ACCEL_I2C if I2C + select BMC150_ACCEL_SPI if SPI help Say yes here to build support for the following Bosch accelerometers: BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. - Currently this only supports the device via an i2c interface. - This is a combo module with both accelerometer and magnetometer. This driver is only implementing accelerometer part, which has its own address and register map. +config BMC150_ACCEL_I2C + tristate + select REGMAP_I2C + +config BMC150_ACCEL_SPI + tristate + select REGMAP_SPI + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER @@ -100,13 +108,13 @@ config KXCJK1013 be called kxcjk-1013. config MMA8452 - tristate "Freescale MMA8452Q Accelerometer Driver" + tristate "Freescale MMA8452Q and similar Accelerometers Driver" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for the Freescale MMA8452Q 3-axis - accelerometer. + Say yes here to build support for the following Freescale 3-axis + accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC. To compile this driver as a module, choose M here: the module will be called mma8452. @@ -137,6 +145,19 @@ config MMA9553 To compile this driver as a module, choose M here: the module will be called mma9553. +config MXC4005 + tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + help + Say yes here to build support for the Memsic MXC4005XC 3-axis + accelerometer. + + To compile this driver as a module, choose M. The module will be + called mxc4005. + config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index ebd2675b2a02..7925f166e6e9 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,7 +4,9 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o -obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o +obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o +obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o +obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o @@ -14,6 +16,8 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o obj-$(CONFIG_MMA9551) += mma9551.o obj-$(CONFIG_MMA9553) += mma9553.o +obj-$(CONFIG_MXC4005) += mxc4005.o + obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel-core.c index 0104cdef8709..2d33f1e821db 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -35,10 +35,12 @@ #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <linux/regmap.h> + +#include "bmc150-accel.h" #define BMC150_ACCEL_DRV_NAME "bmc150_accel" #define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" -#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" #define BMC150_ACCEL_REG_CHIP_ID 0x00 @@ -185,7 +187,9 @@ enum bmc150_accel_trigger_id { }; struct bmc150_accel_data { - struct i2c_client *client; + struct regmap *regmap; + struct device *dev; + int irq; struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; atomic_t active_intr; struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; @@ -242,6 +246,12 @@ static const struct { {500000, BMC150_ACCEL_SLEEP_500_MS}, {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; +static const struct regmap_config bmc150_i2c_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x3f, +}; + static int bmc150_accel_set_mode(struct bmc150_accel_data *data, enum bmc150_power_modes mode, int dur_us) @@ -269,12 +279,11 @@ static int bmc150_accel_set_mode(struct bmc150_accel_data *data, lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); - dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits); + dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits); - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_LPW, lpw_bits); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); + dev_err(data->dev, "Error writing reg_pmu_lpw\n"); return ret; } @@ -290,8 +299,7 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { if (bmc150_accel_samp_freq_table[i].val == val && bmc150_accel_samp_freq_table[i].val2 == val2) { - ret = i2c_smbus_write_byte_data( - data->client, + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_BW, bmc150_accel_samp_freq_table[i].bw_bits); if (ret < 0) @@ -308,30 +316,23 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, static int bmc150_accel_update_slope(struct bmc150_accel_data *data) { - int ret, val; + int ret; - ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6, + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6, data->slope_thres); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_6\n"); - return ret; - } - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_5\n"); + dev_err(data->dev, "Error writing reg_int_6\n"); return ret; } - val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur; - ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5, - val); + ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5, + BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur); if (ret < 0) { - dev_err(&data->client->dev, "Error write reg_int_5\n"); + dev_err(data->dev, "Error updating reg_int_5\n"); return ret; } - dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres, + dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres, data->slope_dur); return ret; @@ -380,17 +381,17 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) int ret; if (on) { - ret = pm_runtime_get_sync(&data->client->dev); + ret = pm_runtime_get_sync(data->dev); } else { - pm_runtime_mark_last_busy(&data->client->dev); - ret = pm_runtime_put_autosuspend(&data->client->dev); + pm_runtime_mark_last_busy(data->dev); + ret = pm_runtime_put_autosuspend(data->dev); } if (ret < 0) { - dev_err(&data->client->dev, + dev_err(data->dev, "Failed: bmc150_accel_set_power_state for %d\n", on); if (on) - pm_runtime_put_noidle(&data->client->dev); + pm_runtime_put_noidle(data->dev); return ret; } @@ -470,38 +471,18 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, return ret; /* map the interrupt to the appropriate pins */ - ret = i2c_smbus_read_byte_data(data->client, info->map_reg); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_map\n"); - goto out_fix_power_state; - } - if (state) - ret |= info->map_bitmask; - else - ret &= ~info->map_bitmask; - - ret = i2c_smbus_write_byte_data(data->client, info->map_reg, - ret); + ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask, + (state ? info->map_bitmask : 0)); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_map\n"); + dev_err(data->dev, "Error updating reg_int_map\n"); goto out_fix_power_state; } /* enable/disable the interrupt */ - ret = i2c_smbus_read_byte_data(data->client, info->en_reg); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_en\n"); - goto out_fix_power_state; - } - - if (state) - ret |= info->en_bitmask; - else - ret &= ~info->en_bitmask; - - ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret); + ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask, + (state ? info->en_bitmask : 0)); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_en\n"); + dev_err(data->dev, "Error updating reg_int_en\n"); goto out_fix_power_state; } @@ -523,12 +504,11 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { if (data->chip_info->scale_table[i].scale == val) { - ret = i2c_smbus_write_byte_data( - data->client, + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE, data->chip_info->scale_table[i].reg_range); if (ret < 0) { - dev_err(&data->client->dev, + dev_err(data->dev, "Error writing pmu_range\n"); return ret; } @@ -544,16 +524,17 @@ static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) { int ret; + unsigned int value; mutex_lock(&data->mutex); - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP); + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value); if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_temp\n"); + dev_err(data->dev, "Error reading reg_temp\n"); mutex_unlock(&data->mutex); return ret; } - *val = sign_extend32(ret, 7); + *val = sign_extend32(value, 7); mutex_unlock(&data->mutex); @@ -566,6 +547,7 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, { int ret; int axis = chan->scan_index; + unsigned int raw_val; mutex_lock(&data->mutex); ret = bmc150_accel_set_power_state(data, true); @@ -574,15 +556,15 @@ static int bmc150_accel_get_axis(struct bmc150_accel_data *data, return ret; } - ret = i2c_smbus_read_word_data(data->client, - BMC150_ACCEL_AXIS_TO_REG(axis)); + ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis), + &raw_val, 2); if (ret < 0) { - dev_err(&data->client->dev, "Error reading axis %d\n", axis); + dev_err(data->dev, "Error reading axis %d\n", axis); bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; } - *val = sign_extend32(ret >> chan->scan_type.shift, + *val = sign_extend32(raw_val >> chan->scan_type.shift, chan->scan_type.realbits - 1); ret = bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); @@ -846,52 +828,34 @@ static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val) * We must read at least one full frame in one burst, otherwise the rest of the * frame data is discarded. */ -static int bmc150_accel_fifo_transfer(const struct i2c_client *client, +static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data, char *buffer, int samples) { int sample_length = 3 * 2; - u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA; - int ret = -EIO; - - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .flags = 0, - .buf = ®_fifo_data, - .len = sizeof(reg_fifo_data), - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = (u8 *)buffer, - .len = samples * sample_length, - } - }; + int ret; + int total_length = samples * sample_length; + int i; + size_t step = regmap_get_raw_read_max(data->regmap); - ret = i2c_transfer(client->adapter, msg, 2); - if (ret != 2) - ret = -EIO; - else - ret = 0; - } else { - int i, step = I2C_SMBUS_BLOCK_MAX / sample_length; - - for (i = 0; i < samples * sample_length; i += step) { - ret = i2c_smbus_read_i2c_block_data(client, - reg_fifo_data, step, - &buffer[i]); - if (ret != step) { - ret = -EIO; - break; - } + if (!step || step > total_length) + step = total_length; + else if (step < total_length) + step = sample_length; - ret = 0; - } + /* + * Seems we have a bus with size limitation so we have to execute + * multiple reads + */ + for (i = 0; i < total_length; i += step) { + ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, + &buffer[i], step); + if (ret) + break; } if (ret) - dev_err(&client->dev, "Error transferring data from fifo\n"); + dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n", + step); return ret; } @@ -905,15 +869,15 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; int64_t tstamp; uint64_t sample_period; + unsigned int val; - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_FIFO_STATUS); + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val); if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_fifo_status\n"); + dev_err(data->dev, "Error reading reg_fifo_status\n"); return ret; } - count = ret & 0x7F; + count = val & 0x7F; if (!count) return 0; @@ -952,7 +916,7 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, if (samples && count > samples) count = samples; - ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count); + ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count); if (ret) return ret; @@ -1052,15 +1016,6 @@ static const struct iio_chan_spec bmc150_accel_channels[] = static const struct iio_chan_spec bma280_accel_channels[] = BMC150_ACCEL_CHANNELS(14); -enum { - bmc150, - bmi055, - bma255, - bma250e, - bma222e, - bma280, -}; - static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { [bmc150] = { .name = "BMC150A", @@ -1155,17 +1110,19 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct bmc150_accel_data *data = iio_priv(indio_dev); int bit, ret, i = 0; + unsigned int raw_val; mutex_lock(&data->mutex); for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { - ret = i2c_smbus_read_word_data(data->client, - BMC150_ACCEL_AXIS_TO_REG(bit)); + ret = regmap_bulk_read(data->regmap, + BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val, + 2); if (ret < 0) { mutex_unlock(&data->mutex); goto err_read; } - data->buffer[i++] = ret; + data->buffer[i++] = raw_val; } mutex_unlock(&data->mutex); @@ -1189,13 +1146,12 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) mutex_lock(&data->mutex); /* clear any latched interrupt */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); mutex_unlock(&data->mutex); if (ret < 0) { - dev_err(&data->client->dev, + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); return ret; } @@ -1249,20 +1205,20 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) struct bmc150_accel_data *data = iio_priv(indio_dev); int dir; int ret; + unsigned int val; - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_INT_STATUS_2); + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val); if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); + dev_err(data->dev, "Error reading reg_int_status_2\n"); return ret; } - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) + if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) dir = IIO_EV_DIR_FALLING; else dir = IIO_EV_DIR_RISING; - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) + if (val & BMC150_ACCEL_ANY_MOTION_BIT_X) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, @@ -1271,7 +1227,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) dir), data->timestamp); - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, @@ -1280,7 +1236,7 @@ static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) dir), data->timestamp); - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, @@ -1315,13 +1271,11 @@ static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) } if (ack) { - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); if (ret) - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); ret = IRQ_HANDLED; } else { @@ -1360,32 +1314,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) return IRQ_NONE; } -static int bmc150_accel_gpio_probe(struct i2c_client *client, - struct bmc150_accel_data *data) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "Failed: gpio get index\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static const struct { int intr; const char *name; @@ -1423,7 +1351,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { struct bmc150_accel_trigger *t = &data->triggers[i]; - t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, + t->indio_trig = devm_iio_trigger_alloc(data->dev, bmc150_accel_triggers[i].name, indio_dev->name, indio_dev->id); @@ -1432,7 +1360,7 @@ static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, break; } - t->indio_trig->dev.parent = &data->client->dev; + t->indio_trig->dev.parent = data->dev; t->indio_trig->ops = &bmc150_accel_trigger_ops; t->intr = bmc150_accel_triggers[i].intr; t->data = data; @@ -1459,20 +1387,19 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data) u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1; int ret; - ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode); + ret = regmap_write(data->regmap, reg, data->fifo_mode); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_fifo_config1\n"); + dev_err(data->dev, "Error writing reg_fifo_config1\n"); return ret; } if (!data->fifo_mode) return 0; - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_FIFO_CONFIG0, - data->watermark); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0, + data->watermark); if (ret < 0) - dev_err(&data->client->dev, "Error writing reg_fifo_config0\n"); + dev_err(data->dev, "Error writing reg_fifo_config0\n"); return ret; } @@ -1557,23 +1484,25 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { static int bmc150_accel_chip_init(struct bmc150_accel_data *data) { int ret, i; + unsigned int val; - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val); if (ret < 0) { - dev_err(&data->client->dev, "Error: Reading chip id\n"); + dev_err(data->dev, + "Error: Reading chip id\n"); return ret; } - dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + dev_dbg(data->dev, "Chip Id %x\n", val); for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { - if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { + if (bmc150_accel_chip_info_tbl[i].chip_id == val) { data->chip_info = &bmc150_accel_chip_info_tbl[i]; break; } } if (!data->chip_info) { - dev_err(&data->client->dev, "Unsupported chip %x\n", ret); + dev_err(data->dev, "Invalid chip %x\n", val); return -ENODEV; } @@ -1587,11 +1516,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) return ret; /* Set Default Range */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_RANGE, - BMC150_ACCEL_DEF_RANGE_4G); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); + dev_err(data->dev, + "Error writing reg_pmu_range\n"); return ret; } @@ -1605,12 +1534,11 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) return ret; /* Set default as latched interrupts */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); if (ret < 0) { - dev_err(&data->client->dev, + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); return ret; } @@ -1618,24 +1546,23 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) return 0; } -static int bmc150_accel_probe(struct i2c_client *client, - const struct i2c_device_id *id) +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name, bool block_supported) { struct bmc150_accel_data *data; struct iio_dev *indio_dev; int ret; - const char *name = NULL; - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) return -ENOMEM; data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - data->client = client; + dev_set_drvdata(dev, indio_dev); + data->dev = dev; + data->irq = irq; - if (id) - name = id->name; + data->regmap = regmap; ret = bmc150_accel_chip_init(data); if (ret < 0) @@ -1643,7 +1570,7 @@ static int bmc150_accel_probe(struct i2c_client *client, mutex_init(&data->mutex); - indio_dev->dev.parent = &client->dev; + indio_dev->dev.parent = dev; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; indio_dev->name = name ? name : data->chip_info->name; @@ -1655,16 +1582,13 @@ static int bmc150_accel_probe(struct i2c_client *client, bmc150_accel_trigger_handler, &bmc150_accel_buffer_ops); if (ret < 0) { - dev_err(&client->dev, "Failed: iio triggered buffer setup\n"); + dev_err(data->dev, "Failed: iio triggered buffer setup\n"); return ret; } - if (client->irq < 0) - client->irq = bmc150_accel_gpio_probe(client, data); - - if (client->irq > 0) { + if (data->irq > 0) { ret = devm_request_threaded_irq( - &client->dev, client->irq, + data->dev, data->irq, bmc150_accel_irq_handler, bmc150_accel_irq_thread_handler, IRQF_TRIGGER_RISING, @@ -1679,11 +1603,10 @@ static int bmc150_accel_probe(struct i2c_client *client, * want to use latch mode when we can to prevent interrupt * flooding. */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_RESET); + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_RESET); if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n"); + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); goto err_buffer_cleanup; } @@ -1693,9 +1616,7 @@ static int bmc150_accel_probe(struct i2c_client *client, if (ret) goto err_buffer_cleanup; - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + if (block_supported) { indio_dev->modes |= INDIO_BUFFER_SOFTWARE; indio_dev->info = &bmc150_accel_info_fifo; indio_dev->buffer->attrs = bmc150_accel_fifo_attributes; @@ -1704,18 +1625,17 @@ static int bmc150_accel_probe(struct i2c_client *client, ret = iio_device_register(indio_dev); if (ret < 0) { - dev_err(&client->dev, "Unable to register iio device\n"); + dev_err(dev, "Unable to register iio device\n"); goto err_trigger_unregister; } - ret = pm_runtime_set_active(&client->dev); + ret = pm_runtime_set_active(dev); if (ret) goto err_iio_unregister; - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, - BMC150_AUTO_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(&client->dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); return 0; @@ -1728,15 +1648,16 @@ err_buffer_cleanup: return ret; } +EXPORT_SYMBOL_GPL(bmc150_accel_core_probe); -static int bmc150_accel_remove(struct i2c_client *client) +int bmc150_accel_core_remove(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_accel_data *data = iio_priv(indio_dev); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); + pm_runtime_disable(data->dev); + pm_runtime_set_suspended(data->dev); + pm_runtime_put_noidle(data->dev); iio_device_unregister(indio_dev); @@ -1750,11 +1671,12 @@ static int bmc150_accel_remove(struct i2c_client *client) return 0; } +EXPORT_SYMBOL_GPL(bmc150_accel_core_remove); #ifdef CONFIG_PM_SLEEP static int bmc150_accel_suspend(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_accel_data *data = iio_priv(indio_dev); mutex_lock(&data->mutex); @@ -1766,7 +1688,7 @@ static int bmc150_accel_suspend(struct device *dev) static int bmc150_accel_resume(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_accel_data *data = iio_priv(indio_dev); mutex_lock(&data->mutex); @@ -1782,11 +1704,11 @@ static int bmc150_accel_resume(struct device *dev) #ifdef CONFIG_PM static int bmc150_accel_runtime_suspend(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; - dev_dbg(&data->client->dev, __func__); + dev_dbg(data->dev, __func__); ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); if (ret < 0) return -EAGAIN; @@ -1796,12 +1718,12 @@ static int bmc150_accel_runtime_suspend(struct device *dev) static int bmc150_accel_runtime_resume(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; int sleep_val; - dev_dbg(&data->client->dev, __func__); + dev_dbg(data->dev, __func__); ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); if (ret < 0) @@ -1820,47 +1742,12 @@ static int bmc150_accel_runtime_resume(struct device *dev) } #endif -static const struct dev_pm_ops bmc150_accel_pm_ops = { +const struct dev_pm_ops bmc150_accel_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, bmc150_accel_runtime_resume, NULL) }; - -static const struct acpi_device_id bmc150_accel_acpi_match[] = { - {"BSBA0150", bmc150}, - {"BMC150A", bmc150}, - {"BMI055A", bmi055}, - {"BMA0255", bma255}, - {"BMA250E", bma250e}, - {"BMA222E", bma222e}, - {"BMA0280", bma280}, - { }, -}; -MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); - -static const struct i2c_device_id bmc150_accel_id[] = { - {"bmc150_accel", bmc150}, - {"bmi055_accel", bmi055}, - {"bma255", bma255}, - {"bma250e", bma250e}, - {"bma222e", bma222e}, - {"bma280", bma280}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); - -static struct i2c_driver bmc150_accel_driver = { - .driver = { - .name = BMC150_ACCEL_DRV_NAME, - .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), - .pm = &bmc150_accel_pm_ops, - }, - .probe = bmc150_accel_probe, - .remove = bmc150_accel_remove, - .id_table = bmc150_accel_id, -}; -module_i2c_driver(bmc150_accel_driver); +EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c new file mode 100644 index 000000000000..b41404ba32fc --- /dev/null +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -0,0 +1,102 @@ +/* + * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips: + * - BMC150 + * - BMI055 + * - BMA255 + * - BMA250E + * - BMA222E + * - BMA280 + * + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/device.h> +#include <linux/mod_devicetable.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/acpi.h> +#include <linux/regmap.h> + +#include "bmc150-accel.h" + +static const struct regmap_config bmc150_i2c_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int bmc150_accel_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + const char *name = NULL; + bool block_supported = + i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK); + + regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to initialize i2c regmap\n"); + return PTR_ERR(regmap); + } + + if (id) + name = id->name; + + return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, + block_supported); +} + +static int bmc150_accel_remove(struct i2c_client *client) +{ + return bmc150_accel_core_remove(&client->dev); +} + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct i2c_device_id bmc150_accel_id[] = { + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); + +static struct i2c_driver bmc150_accel_driver = { + .driver = { + .name = "bmc150_accel_i2c", + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_i2c_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c new file mode 100644 index 000000000000..16b66f2a7204 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -0,0 +1,91 @@ +/* + * 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip + * Copyright © 2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/acpi.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "bmc150-accel.h" + +static const struct regmap_config bmc150_spi_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x3f, +}; + +static int bmc150_accel_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const struct spi_device_id *id = spi_get_device_id(spi); + + regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); + return PTR_ERR(regmap); + } + + return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name, + true); +} + +static int bmc150_accel_remove(struct spi_device *spi) +{ + return bmc150_accel_core_remove(&spi->dev); +} + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct spi_device_id bmc150_accel_id[] = { + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, + {} +}; +MODULE_DEVICE_TABLE(spi, bmc150_accel_id); + +static struct spi_driver bmc150_accel_driver = { + .driver = { + .name = "bmc150_accel_spi", + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_spi_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h new file mode 100644 index 000000000000..ba0335987f94 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel.h @@ -0,0 +1,20 @@ +#ifndef _BMC150_ACCEL_H_ +#define _BMC150_ACCEL_H_ + +struct regmap; + +enum { + bmc150, + bmi055, + bma255, + bma250e, + bma222e, + bma280, +}; + +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name, bool block_supported); +int bmc150_accel_core_remove(struct device *dev); +extern const struct dev_pm_ops bmc150_accel_pm_ops; + +#endif /* _BMC150_ACCEL_H_ */ diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 3292bc0c1d0e..18c1b06684c1 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, return dev_name(dev); } -static int kxcjk1013_gpio_probe(struct i2c_client *client, - struct kxcjk1013_data *data) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - if (data->is_smo8500_device) - return -ENOTSUPP; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int kxcjk1013_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &kxcjk1013_info; - if (client->irq < 0) - client->irq = kxcjk1013_gpio_probe(client, data); - - if (client->irq > 0) { + if (client->irq > 0 && !data->is_smo8500_device) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index b921d84c1be6..1eccc2dcf14c 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1,6 +1,12 @@ /* - * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer + * mma8452.c - Support for following Freescale 3-axis accelerometers: * + * MMA8452Q (12 bit) + * MMA8453Q (10 bit) + * MMA8652FC (12 bit) + * MMA8653FC (10 bit) + * + * Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com> * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net> * * This file is subject to the terms and conditions of version 2 of @@ -22,10 +28,11 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/events.h> #include <linux/delay.h> +#include <linux/of_device.h> #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) -#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_X 0x01 /* MSB first */ #define MMA8452_OUT_Y 0x03 #define MMA8452_OUT_Z 0x05 #define MMA8452_INT_SRC 0x0c @@ -38,6 +45,16 @@ #define MMA8452_DATA_CFG_HPF_MASK BIT(4) #define MMA8452_HP_FILTER_CUTOFF 0x0f #define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) +#define MMA8452_FF_MT_CFG 0x15 +#define MMA8452_FF_MT_CFG_OAE BIT(6) +#define MMA8452_FF_MT_CFG_ELE BIT(7) +#define MMA8452_FF_MT_SRC 0x16 +#define MMA8452_FF_MT_SRC_XHE BIT(1) +#define MMA8452_FF_MT_SRC_YHE BIT(3) +#define MMA8452_FF_MT_SRC_ZHE BIT(5) +#define MMA8452_FF_MT_THS 0x17 +#define MMA8452_FF_MT_THS_MASK 0x7f +#define MMA8452_FF_MT_COUNT 0x18 #define MMA8452_TRANSIENT_CFG 0x1d #define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) #define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) @@ -65,15 +82,65 @@ #define MMA8452_MAX_REG 0x31 #define MMA8452_INT_DRDY BIT(0) +#define MMA8452_INT_FF_MT BIT(2) #define MMA8452_INT_TRANS BIT(5) #define MMA8452_DEVICE_ID 0x2a +#define MMA8453_DEVICE_ID 0x3a +#define MMA8652_DEVICE_ID 0x4a +#define MMA8653_DEVICE_ID 0x5a struct mma8452_data { struct i2c_client *client; struct mutex lock; u8 ctrl_reg1; u8 data_cfg; + const struct mma_chip_info *chip_info; +}; + +/** + * struct mma_chip_info - chip specific data for Freescale's accelerometers + * @chip_id: WHO_AM_I register's value + * @channels: struct iio_chan_spec matching the device's + * capabilities + * @num_channels: number of channels + * @mma_scales: scale factors for converting register values + * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers + * per mode: m/s^2 and micro m/s^2 + * @ev_cfg: event config register address + * @ev_cfg_ele: latch bit in event config register + * @ev_cfg_chan_shift: number of the bit to enable events in X + * direction; in event config register + * @ev_src: event source register address + * @ev_src_xe: bit in event source register that indicates + * an event in X direction + * @ev_src_ye: bit in event source register that indicates + * an event in Y direction + * @ev_src_ze: bit in event source register that indicates + * an event in Z direction + * @ev_ths: event threshold register address + * @ev_ths_mask: mask for the threshold value + * @ev_count: event count (period) register address + * + * Since not all chips supported by the driver support comparing high pass + * filtered data for events (interrupts), different interrupt sources are + * used for different chips and the relevant registers are included here. + */ +struct mma_chip_info { + u8 chip_id; + const struct iio_chan_spec *channels; + int num_channels; + const int mma_scales[3][2]; + u8 ev_cfg; + u8 ev_cfg_ele; + u8 ev_cfg_chan_shift; + u8 ev_src; + u8 ev_src_xe; + u8 ev_src_ye; + u8 ev_src_ze; + u8 ev_ths; + u8 ev_ths_mask; + u8 ev_count; }; static int mma8452_drdy(struct mma8452_data *data) @@ -143,16 +210,6 @@ static const int mma8452_samp_freq[8][2] = { {6, 250000}, {1, 560000} }; -/* - * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 - * The userspace interface uses m/s^2 and we declare micro units - * So scale factor is given by: - * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 - */ -static const int mma8452_scales[3][2] = { - {0, 9577}, {0, 19154}, {0, 38307} -}; - /* Datasheet table 35 (step time vs sample frequency) */ static const int mma8452_transient_time_step_us[8] = { 1250, @@ -189,8 +246,11 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) { - return mma8452_show_int_plus_micros(buf, mma8452_scales, - ARRAY_SIZE(mma8452_scales)); + struct mma8452_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + + return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, + ARRAY_SIZE(data->chip_info->mma_scales)); } static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, @@ -221,9 +281,8 @@ static int mma8452_get_samp_freq_index(struct mma8452_data *data, static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) { - return mma8452_get_int_plus_micros_index(mma8452_scales, - ARRAY_SIZE(mma8452_scales), - val, val2); + return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, + ARRAY_SIZE(data->chip_info->mma_scales), val, val2); } static int mma8452_get_hp_filter_index(struct mma8452_data *data, @@ -270,14 +329,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, - 11); + *val = sign_extend32(be16_to_cpu( + buffer[chan->scan_index]) >> chan->scan_type.shift, + chan->scan_type.realbits - 1); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; - *val = mma8452_scales[i][0]; - *val2 = mma8452_scales[i][1]; + *val = data->chip_info->mma_scales[i][0]; + *val2 = data->chip_info->mma_scales[i][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -439,17 +499,17 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: ret = i2c_smbus_read_byte_data(data->client, - MMA8452_TRANSIENT_THS); + data->chip_info->ev_ths); if (ret < 0) return ret; - *val = ret & MMA8452_TRANSIENT_THS_MASK; + *val = ret & data->chip_info->ev_ths_mask; return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: ret = i2c_smbus_read_byte_data(data->client, - MMA8452_TRANSIENT_COUNT); + data->chip_info->ev_count); if (ret < 0) return ret; @@ -497,7 +557,8 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) return -EINVAL; - return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); + return mma8452_change_config(data, data->chip_info->ev_ths, + val); case IIO_EV_INFO_PERIOD: steps = (val * USEC_PER_SEC + val2) / @@ -507,7 +568,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (steps < 0 || steps > 0xff) return -EINVAL; - return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, + return mma8452_change_config(data, data->chip_info->ev_count, steps); case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: @@ -538,13 +599,15 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int ret; - ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); + ret = i2c_smbus_read_byte_data(data->client, + data->chip_info->ev_cfg); if (ret < 0) return ret; - return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0; + return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift)); } static int mma8452_write_event_config(struct iio_dev *indio_dev, @@ -554,20 +617,22 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, int state) { struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int val; - val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); + val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg); if (val < 0) return val; if (state) - val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); + val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift); else - val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); + val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift); - val |= MMA8452_TRANSIENT_CFG_ELE; + val |= chip->ev_cfg_ele; + val |= MMA8452_FF_MT_CFG_OAE; - return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val); + return mma8452_change_config(data, chip->ev_cfg, val); } static void mma8452_transient_interrupt(struct iio_dev *indio_dev) @@ -576,25 +641,25 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev) s64 ts = iio_get_time_ns(); int src; - src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); + src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); if (src < 0) return; - if (src & MMA8452_TRANSIENT_SRC_XTRANSE) + if (src & data->chip_info->ev_src_xe) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), ts); - if (src & MMA8452_TRANSIENT_SRC_YTRANSE) + if (src & data->chip_info->ev_src_ye) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), ts); - if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) + if (src & data->chip_info->ev_src_ze) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, IIO_EV_TYPE_MAG, @@ -606,6 +671,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) { struct iio_dev *indio_dev = p; struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int ret = IRQ_NONE; int src; @@ -618,7 +684,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) ret = IRQ_HANDLED; } - if (src & MMA8452_INT_TRANS) { + if ((src & MMA8452_INT_TRANS && + chip->ev_src == MMA8452_TRANSIENT_SRC) || + (src & MMA8452_INT_FF_MT && + chip->ev_src == MMA8452_FF_MT_SRC)) { mma8452_transient_interrupt(indio_dev); ret = IRQ_HANDLED; } @@ -680,6 +749,16 @@ static const struct iio_event_spec mma8452_transient_event[] = { }, }; +static const struct iio_event_spec mma8452_motion_event[] = { + { + .type = IIO_EV_TYPE_MAG, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_PERIOD) + }, +}; + /* * Threshold is configured in fixed 8G/127 steps regardless of * currently selected scale for measurement. @@ -693,10 +772,9 @@ static struct attribute *mma8452_event_attributes[] = { static struct attribute_group mma8452_event_attribute_group = { .attrs = mma8452_event_attributes, - .name = "events", }; -#define MMA8452_CHANNEL(axis, idx) { \ +#define MMA8452_CHANNEL(axis, idx, bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ @@ -708,22 +786,144 @@ static struct attribute_group mma8452_event_attribute_group = { .scan_index = idx, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = (bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (bits), \ .endianness = IIO_BE, \ }, \ .event_spec = mma8452_transient_event, \ .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ } +#define MMA8652_CHANNEL(axis, idx, bits) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 16 - (bits), \ + .endianness = IIO_BE, \ + }, \ + .event_spec = mma8452_motion_event, \ + .num_event_specs = ARRAY_SIZE(mma8452_motion_event), \ +} + static const struct iio_chan_spec mma8452_channels[] = { - MMA8452_CHANNEL(X, 0), - MMA8452_CHANNEL(Y, 1), - MMA8452_CHANNEL(Z, 2), + MMA8452_CHANNEL(X, 0, 12), + MMA8452_CHANNEL(Y, 1, 12), + MMA8452_CHANNEL(Z, 2, 12), IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec mma8453_channels[] = { + MMA8452_CHANNEL(X, 0, 10), + MMA8452_CHANNEL(Y, 1, 10), + MMA8452_CHANNEL(Z, 2, 10), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec mma8652_channels[] = { + MMA8652_CHANNEL(X, 0, 12), + MMA8652_CHANNEL(Y, 1, 12), + MMA8652_CHANNEL(Z, 2, 12), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec mma8653_channels[] = { + MMA8652_CHANNEL(X, 0, 10), + MMA8652_CHANNEL(Y, 1, 10), + MMA8652_CHANNEL(Z, 2, 10), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +enum { + mma8452, + mma8453, + mma8652, + mma8653, +}; + +static const struct mma_chip_info mma_chip_info_table[] = { + [mma8452] = { + .chip_id = MMA8452_DEVICE_ID, + .channels = mma8452_channels, + .num_channels = ARRAY_SIZE(mma8452_channels), + /* + * Hardware has fullscale of -2G, -4G, -8G corresponding to + * raw value -2048 for 12 bit or -512 for 10 bit. + * The userspace interface uses m/s^2 and we declare micro units + * So scale factor for 12 bit here is given by: + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + */ + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, + .ev_cfg = MMA8452_TRANSIENT_CFG, + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, + .ev_cfg_chan_shift = 1, + .ev_src = MMA8452_TRANSIENT_SRC, + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, + .ev_ths = MMA8452_TRANSIENT_THS, + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, + .ev_count = MMA8452_TRANSIENT_COUNT, + }, + [mma8453] = { + .chip_id = MMA8453_DEVICE_ID, + .channels = mma8453_channels, + .num_channels = ARRAY_SIZE(mma8453_channels), + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, + .ev_cfg = MMA8452_TRANSIENT_CFG, + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, + .ev_cfg_chan_shift = 1, + .ev_src = MMA8452_TRANSIENT_SRC, + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, + .ev_ths = MMA8452_TRANSIENT_THS, + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, + .ev_count = MMA8452_TRANSIENT_COUNT, + }, + [mma8652] = { + .chip_id = MMA8652_DEVICE_ID, + .channels = mma8652_channels, + .num_channels = ARRAY_SIZE(mma8652_channels), + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, + .ev_cfg = MMA8452_FF_MT_CFG, + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, + .ev_cfg_chan_shift = 3, + .ev_src = MMA8452_FF_MT_SRC, + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, + .ev_ths = MMA8452_FF_MT_THS, + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, + .ev_count = MMA8452_FF_MT_COUNT, + }, + [mma8653] = { + .chip_id = MMA8653_DEVICE_ID, + .channels = mma8653_channels, + .num_channels = ARRAY_SIZE(mma8653_channels), + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, + .ev_cfg = MMA8452_FF_MT_CFG, + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, + .ev_cfg_chan_shift = 3, + .ev_src = MMA8452_FF_MT_SRC, + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, + .ev_ths = MMA8452_FF_MT_THS, + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, + .ev_count = MMA8452_FF_MT_COUNT, + }, +}; + static struct attribute *mma8452_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_accel_scale_available.dev_attr.attr, @@ -841,18 +1041,28 @@ static int mma8452_reset(struct i2c_client *client) return -ETIMEDOUT; } +static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, + { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, + { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, + { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, + { } +}; +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); + static int mma8452_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mma8452_data *data; struct iio_dev *indio_dev; int ret; + const struct of_device_id *match; - ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); - if (ret < 0) - return ret; - if (ret != MMA8452_DEVICE_ID) + match = of_match_device(mma8452_dt_ids, &client->dev); + if (!match) { + dev_err(&client->dev, "unknown device model\n"); return -ENODEV; + } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -861,14 +1071,33 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); + data->chip_info = match->data; + + ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); + if (ret < 0) + return ret; + + switch (ret) { + case MMA8452_DEVICE_ID: + case MMA8453_DEVICE_ID: + case MMA8652_DEVICE_ID: + case MMA8653_DEVICE_ID: + if (ret == data->chip_info->chip_id) + break; + default: + return -ENODEV; + } + + dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", + match->compatible, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; indio_dev->name = id->name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = mma8452_channels; - indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; indio_dev->available_scan_masks = mma8452_scan_masks; ret = mma8452_reset(client); @@ -892,13 +1121,15 @@ static int mma8452_probe(struct i2c_client *client, if (client->irq) { /* - * Although we enable the transient interrupt source once and - * for all here the transient event detection itself is not - * enabled until userspace asks for it by - * mma8452_write_event_config() + * Although we enable the interrupt sources once and for + * all here the event detection itself is not enabled until + * userspace asks for it by mma8452_write_event_config() */ - int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS; - int enabled_interrupts = MMA8452_INT_TRANS; + int supported_interrupts = MMA8452_INT_DRDY | + MMA8452_INT_TRANS | + MMA8452_INT_FF_MT; + int enabled_interrupts = MMA8452_INT_TRANS | + MMA8452_INT_FF_MT; /* Assume wired to INT1 pin */ ret = i2c_smbus_write_byte_data(client, @@ -987,17 +1218,14 @@ static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); #endif static const struct i2c_device_id mma8452_id[] = { - { "mma8452", 0 }, + { "mma8452", mma8452 }, + { "mma8453", mma8453 }, + { "mma8652", mma8652 }, + { "mma8653", mma8653 }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); -static const struct of_device_id mma8452_dt_ids[] = { - { .compatible = "fsl,mma8452" }, - { } -}; -MODULE_DEVICE_TABLE(of, mma8452_dt_ids); - static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 771858cb67a1..9408ef3add58 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -26,7 +26,6 @@ #define MMA9553_DRV_NAME "mma9553" #define MMA9553_IRQ_NAME "mma9553_event" -#define MMA9553_GPIO_NAME "mma9553_int" /* Pedometer configuration registers (R/W) */ #define MMA9553_REG_CONF_SLEEPMIN 0x00 @@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) return IRQ_HANDLED; } -static int mma9553_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready GPIO interrupt pin */ - gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "ACPI GPIO get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static const char *mma9553_match_acpi_device(struct device *dev) { const struct acpi_device_id *id; @@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mma9553_info; - if (client->irq < 0) - client->irq = mma9553_gpio_probe(client); - if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, mma9553_irq_handler, diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c new file mode 100644 index 000000000000..e72e218c2696 --- /dev/null +++ b/drivers/iio/accel/mxc4005.c @@ -0,0 +1,567 @@ +/* + * 3-axis accelerometer driver for MXC4005XC Memsic sensor + * + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/regmap.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/buffer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> + +#define MXC4005_DRV_NAME "mxc4005" +#define MXC4005_IRQ_NAME "mxc4005_event" +#define MXC4005_REGMAP_NAME "mxc4005_regmap" + +#define MXC4005_REG_XOUT_UPPER 0x03 +#define MXC4005_REG_XOUT_LOWER 0x04 +#define MXC4005_REG_YOUT_UPPER 0x05 +#define MXC4005_REG_YOUT_LOWER 0x06 +#define MXC4005_REG_ZOUT_UPPER 0x07 +#define MXC4005_REG_ZOUT_LOWER 0x08 + +#define MXC4005_REG_INT_MASK1 0x0B +#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 + +#define MXC4005_REG_INT_CLR1 0x01 +#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 + +#define MXC4005_REG_CONTROL 0x0D +#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) +#define MXC4005_CONTROL_FSR_SHIFT 5 + +#define MXC4005_REG_DEVICE_ID 0x0E + +enum mxc4005_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum mxc4005_range { + MXC4005_RANGE_2G, + MXC4005_RANGE_4G, + MXC4005_RANGE_8G, +}; + +struct mxc4005_data { + struct device *dev; + struct mutex mutex; + struct regmap *regmap; + struct iio_trigger *dready_trig; + __be16 buffer[8]; + bool trigger_enabled; +}; + +/* + * MXC4005 can operate in the following ranges: + * +/- 2G, 4G, 8G (the default +/-2G) + * + * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582 + * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164 + * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329 + */ +static const struct { + u8 range; + int scale; +} mxc4005_scale_table[] = { + {MXC4005_RANGE_2G, 9582}, + {MXC4005_RANGE_4G, 19164}, + {MXC4005_RANGE_8G, 38329}, +}; + + +static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329"); + +static struct attribute *mxc4005_attributes[] = { + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group mxc4005_attrs_group = { + .attrs = mxc4005_attributes, +}; + +static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MXC4005_REG_XOUT_UPPER: + case MXC4005_REG_XOUT_LOWER: + case MXC4005_REG_YOUT_UPPER: + case MXC4005_REG_YOUT_LOWER: + case MXC4005_REG_ZOUT_UPPER: + case MXC4005_REG_ZOUT_LOWER: + case MXC4005_REG_DEVICE_ID: + case MXC4005_REG_CONTROL: + return true; + default: + return false; + } +} + +static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MXC4005_REG_INT_CLR1: + case MXC4005_REG_INT_MASK1: + case MXC4005_REG_CONTROL: + return true; + default: + return false; + } +} + +static const struct regmap_config mxc4005_regmap_config = { + .name = MXC4005_REGMAP_NAME, + + .reg_bits = 8, + .val_bits = 8, + + .max_register = MXC4005_REG_DEVICE_ID, + + .readable_reg = mxc4005_is_readable_reg, + .writeable_reg = mxc4005_is_writeable_reg, +}; + +static int mxc4005_read_xyz(struct mxc4005_data *data) +{ + int ret; + + ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, + (u8 *) data->buffer, sizeof(data->buffer)); + if (ret < 0) { + dev_err(data->dev, "failed to read axes\n"); + return ret; + } + + return 0; +} + +static int mxc4005_read_axis(struct mxc4005_data *data, + unsigned int addr) +{ + __be16 reg; + int ret; + + ret = regmap_bulk_read(data->regmap, addr, (u8 *) ®, sizeof(reg)); + if (ret < 0) { + dev_err(data->dev, "failed to read reg %02x\n", addr); + return ret; + } + + return be16_to_cpu(reg); +} + +static int mxc4005_read_scale(struct mxc4005_data *data) +{ + unsigned int reg; + int ret; + int i; + + ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, ®); + if (ret < 0) { + dev_err(data->dev, "failed to read reg_control\n"); + return ret; + } + + i = reg >> MXC4005_CONTROL_FSR_SHIFT; + + if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table)) + return -EINVAL; + + return mxc4005_scale_table[i].scale; +} + +static int mxc4005_set_scale(struct mxc4005_data *data, int val) +{ + unsigned int reg; + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) { + if (mxc4005_scale_table[i].scale == val) { + reg = i << MXC4005_CONTROL_FSR_SHIFT; + ret = regmap_update_bits(data->regmap, + MXC4005_REG_CONTROL, + MXC4005_REG_CONTROL_MASK_FSR, + reg); + if (ret < 0) + dev_err(data->dev, + "failed to write reg_control\n"); + return ret; + } + } + + return -EINVAL; +} + +static int mxc4005_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_ACCEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + ret = mxc4005_read_axis(data, chan->address); + if (ret < 0) + return ret; + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + ret = mxc4005_read_scale(data); + if (ret < 0) + return ret; + + *val = 0; + *val2 = ret; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int mxc4005_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + + return mxc4005_set_scale(data, val2); + default: + return -EINVAL; + } +} + +static const struct iio_info mxc4005_info = { + .driver_module = THIS_MODULE, + .read_raw = mxc4005_read_raw, + .write_raw = mxc4005_write_raw, + .attrs = &mxc4005_attrs_group, +}; + +static const unsigned long mxc4005_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; + +#define MXC4005_CHANNEL(_axis, _addr) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = _addr, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec mxc4005_channels[] = { + MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), + MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), + MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static irqreturn_t mxc4005_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + ret = mxc4005_read_xyz(data); + if (ret < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); + +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int mxc4005_clr_intr(struct mxc4005_data *data) +{ + int ret; + + /* clear interrupt */ + ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, + MXC4005_REG_INT_CLR1_BIT_DRDYC); + if (ret < 0) { + dev_err(data->dev, "failed to write to reg_int_clr1\n"); + return ret; + } + + return 0; +} + +static int mxc4005_set_trigger_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + if (state) { + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, + MXC4005_REG_INT_MASK1_BIT_DRDYE); + } else { + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, + ~MXC4005_REG_INT_MASK1_BIT_DRDYE); + } + + if (ret < 0) { + mutex_unlock(&data->mutex); + dev_err(data->dev, "failed to update reg_int_mask1"); + return ret; + } + + data->trigger_enabled = state; + mutex_unlock(&data->mutex); + + return 0; +} + +static int mxc4005_trigger_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct mxc4005_data *data = iio_priv(indio_dev); + + if (!data->dready_trig) + return 0; + + return mxc4005_clr_intr(data); +} + +static const struct iio_trigger_ops mxc4005_trigger_ops = { + .set_trigger_state = mxc4005_set_trigger_state, + .try_reenable = mxc4005_trigger_try_reen, + .owner = THIS_MODULE, +}; + +static int mxc4005_gpio_probe(struct i2c_client *client, + struct mxc4005_data *data) +{ + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(dev, "failed to get acpi gpio index\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_to_irq(gpio); + + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + +static int mxc4005_chip_init(struct mxc4005_data *data) +{ + int ret; + unsigned int reg; + + ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, ®); + if (ret < 0) { + dev_err(data->dev, "failed to read chip id\n"); + return ret; + } + + dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); + + return 0; +} + +static int mxc4005_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxc4005_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "failed to initialize regmap\n"); + return PTR_ERR(regmap); + } + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->dev = &client->dev; + data->regmap = regmap; + + ret = mxc4005_chip_init(data); + if (ret < 0) { + dev_err(&client->dev, "failed to initialize chip\n"); + return ret; + } + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = mxc4005_channels; + indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); + indio_dev->available_scan_masks = mxc4005_scan_masks; + indio_dev->name = MXC4005_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mxc4005_info; + + ret = iio_triggered_buffer_setup(indio_dev, + iio_pollfunc_store_time, + mxc4005_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "failed to setup iio triggered buffer\n"); + return ret; + } + + if (client->irq < 0) + client->irq = mxc4005_gpio_probe(client, data); + + if (client->irq > 0) { + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) + return -ENOMEM; + + ret = devm_request_threaded_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + MXC4005_IRQ_NAME, + data->dready_trig); + if (ret) { + dev_err(&client->dev, + "failed to init threaded irq\n"); + goto err_buffer_cleanup; + } + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &mxc4005_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(data->dready_trig); + if (ret) { + dev_err(&client->dev, + "failed to register trigger\n"); + goto err_trigger_unregister; + } + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, + "unable to register iio device %d\n", ret); + goto err_buffer_cleanup; + } + + return 0; + +err_trigger_unregister: + iio_trigger_unregister(data->dready_trig); +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} + +static int mxc4005_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mxc4005_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + iio_triggered_buffer_cleanup(indio_dev); + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + + return 0; +} + +static const struct acpi_device_id mxc4005_acpi_match[] = { + {"MXC4005", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); + +static const struct i2c_device_id mxc4005_id[] = { + {"mxc4005", 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mxc4005_id); + +static struct i2c_driver mxc4005_driver = { + .driver = { + .name = MXC4005_DRV_NAME, + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + }, + .probe = mxc4005_probe, + .remove = mxc4005_remove, + .id_table = mxc4005_id, +}; + +module_i2c_driver(mxc4005_driver); + +MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index fb9311110424..197a08b4e2f3 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -612,6 +612,7 @@ static const struct iio_info accel_info = { .attrs = &st_accel_attribute_group, .read_raw = &st_accel_read_raw, .write_raw = &st_accel_write_raw, + .debugfs_reg_access = &st_sensors_debugfs_reg_access, }; #ifdef CONFIG_IIO_TRIGGER diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c764af284c94..85fe7f7247c1 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -50,7 +50,6 @@ #define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" -#define STK8312_GPIO "stk8312_gpio" #define STK8312_IRQ_NAME "stk8312_event" /* @@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = { .postdisable = stk8312_buffer_postdisable, }; -static int stk8312_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int stk8312_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client, if (ret < 0) return ret; - if (client->irq < 0) - client->irq = stk8312_gpio_probe(client); - - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, stk8312_data_rdy_trig_poll, NULL, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 80f77d8704b5..5709d9eb8f34 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -45,7 +45,6 @@ #define STK8BA50_ALL_CHANNEL_SIZE 6 #define STK8BA50_DRIVER_NAME "stk8ba50" -#define STK8BA50_GPIO "stk8ba50_gpio" #define STK8BA50_IRQ_NAME "stk8ba50_event" #define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069" @@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = { .postdisable = stk8ba50_buffer_postdisable, }; -static int stk8ba50_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int stk8ba50_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client, goto err_power_off; } - if (client->irq < 0) - client->irq = stk8ba50_gpio_probe(client); - - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, stk8ba50_data_rdy_trig_poll, NULL, |