diff options
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r-- | drivers/iio/imu/adis_buffer.c | 2 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 284 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 86 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 22 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 47 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 12 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 52 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/Kconfig | 3 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 2 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 10 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 7 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 5 | ||||
-rw-r--r-- | drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 5 |
13 files changed, 318 insertions, 219 deletions
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 36607d52fee0..76643c5571aa 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -38,7 +38,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, if (!adis->xfer) return -ENOMEM; - adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL); + adis->buffer = kcalloc(indio_dev->scan_bytes, 2, GFP_KERNEL); if (!adis->buffer) return -ENOMEM; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 7d64be353403..f9c0624505a2 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -24,6 +24,7 @@ #include <linux/spinlock.h> #include <linux/iio/iio.h> #include <linux/acpi.h> +#include <linux/platform_device.h> #include "inv_mpu_iio.h" /* @@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6500 = { .raw_accl = INV_MPU6050_REG_RAW_ACCEL, .temperature = INV_MPU6050_REG_TEMPERATURE, .int_enable = INV_MPU6050_REG_INT_ENABLE, + .int_status = INV_MPU6050_REG_INT_STATUS, .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, @@ -86,6 +88,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = { .gyro_fifo_enable = false, .accl_fifo_enable = false, .accl_fs = INV_MPU6050_FS_02G, + .user_ctrl = 0, }; /* Indexed by enum inv_devices */ @@ -121,6 +124,12 @@ static const struct inv_mpu6050_hw hw_info[] = { .config = &chip_config_6050, }, { + .whoami = INV_MPU9255_WHOAMI_VALUE, + .name = "MPU9255", + .reg = ®_set_6500, + .config = &chip_config_6050, + }, + { .whoami = INV_ICM20608_WHOAMI_VALUE, .name = "ICM20608", .reg = ®_set_6500, @@ -168,7 +177,7 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) return result; if (en) { - /* Wait for output stabilize */ + /* Wait for output to stabilize */ msleep(INV_MPU6050_TEMP_UP_TIME); if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { /* switch internal clock to PLL */ @@ -185,26 +194,29 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) { - int result = 0; + int result; if (power_on) { - if (!st->powerup_count) + if (!st->powerup_count) { result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); - if (!result) - st->powerup_count++; + if (result) + return result; + usleep_range(INV_MPU6050_REG_UP_TIME_MIN, + INV_MPU6050_REG_UP_TIME_MAX); + } + st->powerup_count++; } else { - st->powerup_count--; - if (!st->powerup_count) + if (st->powerup_count == 1) { result = regmap_write(st->map, st->reg->pwr_mgmt_1, INV_MPU6050_BIT_SLEEP); + if (result) + return result; + } + st->powerup_count--; } - if (result) - return result; - - if (power_on) - usleep_range(INV_MPU6050_REG_UP_TIME_MIN, - INV_MPU6050_REG_UP_TIME_MAX); + dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n", + power_on, st->powerup_count); return 0; } @@ -262,26 +274,33 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); result = regmap_write(st->map, st->reg->gyro_config, d); if (result) - return result; + goto error_power_off; result = inv_mpu6050_set_lpf_regs(st, INV_MPU6050_FILTER_20HZ); if (result) - return result; + goto error_power_off; d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) - return result; + goto error_power_off; d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); result = regmap_write(st->map, st->reg->accl_config, d); if (result) + goto error_power_off; + + result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); + if (result) return result; memcpy(&st->chip_config, hw_info[st->chip_type].config, sizeof(struct inv_mpu6050_chip_config)); - result = inv_mpu6050_set_power_itg(st, false); + return inv_mpu6050_set_power_itg(st, false); + +error_power_off: + inv_mpu6050_set_power_itg(st, false); return result; } @@ -314,6 +333,65 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, return IIO_VAL_INT; } +static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + int ret; + + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + + switch (chan->type) { + case IIO_ANGL_VEL: + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_power_off; + ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, + chan->channel2, val); + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_power_off; + break; + case IIO_ACCEL: + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_power_off; + ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, + chan->channel2, val); + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_power_off; + break; + case IIO_TEMP: + /* wait for stablization */ + msleep(INV_MPU6050_SENSOR_UP_TIME); + ret = inv_mpu6050_sensor_show(st, st->reg->temperature, + IIO_MOD_X, val); + break; + default: + ret = -EINVAL; + break; + } + + result = inv_mpu6050_set_power_itg(st, false); + if (result) + goto error_power_off; + + return ret; + +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; +} + static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -324,63 +402,14 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - { - int result; - - ret = IIO_VAL_INT; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; mutex_lock(&st->lock); - result = iio_device_claim_direct_mode(indio_dev); - if (result) - goto error_read_raw_unlock; - result = inv_mpu6050_set_power_itg(st, true); - if (result) - goto error_read_raw_release; - switch (chan->type) { - case IIO_ANGL_VEL: - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw_power_off; - ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, - chan->channel2, val); - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); - if (result) - goto error_read_raw_power_off; - break; - case IIO_ACCEL: - result = inv_mpu6050_switch_engine(st, true, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw_power_off; - ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, - chan->channel2, val); - result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); - if (result) - goto error_read_raw_power_off; - break; - case IIO_TEMP: - /* wait for stablization */ - msleep(INV_MPU6050_SENSOR_UP_TIME); - ret = inv_mpu6050_sensor_show(st, st->reg->temperature, - IIO_MOD_X, val); - break; - default: - ret = -EINVAL; - break; - } -error_read_raw_power_off: - result |= inv_mpu6050_set_power_itg(st, false); -error_read_raw_release: - iio_device_release_direct_mode(indio_dev); -error_read_raw_unlock: + ret = inv_mpu6050_read_channel_data(indio_dev, chan, val); mutex_unlock(&st->lock); - if (result) - return result; - + iio_device_release_direct_mode(indio_dev); return ret; - } case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: @@ -502,17 +531,18 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, struct inv_mpu6050_state *st = iio_priv(indio_dev); int result; - mutex_lock(&st->lock); /* * we should only update scale when the chip is disabled, i.e. * not running */ result = iio_device_claim_direct_mode(indio_dev); if (result) - goto error_write_raw_unlock; + return result; + + mutex_lock(&st->lock); result = inv_mpu6050_set_power_itg(st, true); if (result) - goto error_write_raw_release; + goto error_write_raw_unlock; switch (mask) { case IIO_CHAN_INFO_SCALE: @@ -551,10 +581,9 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, } result |= inv_mpu6050_set_power_itg(st, false); -error_write_raw_release: - iio_device_release_direct_mode(indio_dev); error_write_raw_unlock: mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); return result; } @@ -613,17 +642,18 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, fifo_rate > INV_MPU6050_MAX_FIFO_RATE) return -EINVAL; + result = iio_device_claim_direct_mode(indio_dev); + if (result) + return result; + mutex_lock(&st->lock); if (fifo_rate == st->chip_config.fifo_rate) { result = 0; goto fifo_rate_fail_unlock; } - result = iio_device_claim_direct_mode(indio_dev); - if (result) - goto fifo_rate_fail_unlock; result = inv_mpu6050_set_power_itg(st, true); if (result) - goto fifo_rate_fail_release; + goto fifo_rate_fail_unlock; d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; result = regmap_write(st->map, st->reg->sample_rate_div, d); @@ -637,10 +667,9 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, fifo_rate_fail_power_off: result |= inv_mpu6050_set_power_itg(st, false); -fifo_rate_fail_release: - iio_device_release_direct_mode(indio_dev); fifo_rate_fail_unlock: mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); if (result) return result; @@ -769,7 +798,14 @@ static const struct iio_chan_spec inv_mpu_channels[] = { INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), }; -/* constant IIO attribute */ +/* + * The user can choose any frequency between INV_MPU6050_MIN_FIFO_RATE and + * INV_MPU6050_MAX_FIFO_RATE, but only these frequencies are matched by the + * low-pass filter. Specifically, each of these sampling rates are about twice + * the bandwidth of a corresponding low-pass filter, which should eliminate + * aliasing following the Nyquist principle. By picking a frequency different + * from these, the user risks aliasing effects. + */ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); static IIO_CONST_ATTR(in_anglvel_scale_available, "0.000133090 0.000266181 0.000532362 0.001064724"); @@ -850,14 +886,11 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) msleep(INV_MPU6050_POWER_UP_TIME); /* - * toggle power state. After reset, the sleep bit could be on - * or off depending on the OTP settings. Toggling power would + * Turn power on. After reset, the sleep bit could be on + * or off depending on the OTP settings. Turning power on * make it in a definite state as well as making the hardware * state align with the software state */ - result = inv_mpu6050_set_power_itg(st, false); - if (result) - return result; result = inv_mpu6050_set_power_itg(st, true); if (result) return result; @@ -865,13 +898,17 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_power_off; result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_power_off; - return 0; + return inv_mpu6050_set_power_itg(st, false); + +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; } int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, @@ -882,6 +919,8 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, struct inv_mpu6050_platform_data *pdata; struct device *dev = regmap_get_device(regmap); int result; + struct irq_data *desc; + int irq_type; indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) @@ -913,20 +952,43 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, st->plat_data = *pdata; } + desc = irq_get_irq_data(irq); + if (!desc) { + dev_err(dev, "Could not find IRQ %d\n", irq); + return -EINVAL; + } + + irq_type = irqd_get_trigger_type(desc); + if (irq_type == IRQF_TRIGGER_RISING) + st->irq_mask = INV_MPU6050_ACTIVE_HIGH; + else if (irq_type == IRQF_TRIGGER_FALLING) + st->irq_mask = INV_MPU6050_ACTIVE_LOW; + else if (irq_type == IRQF_TRIGGER_HIGH) + st->irq_mask = INV_MPU6050_ACTIVE_HIGH | + INV_MPU6050_LATCH_INT_EN; + else if (irq_type == IRQF_TRIGGER_LOW) + st->irq_mask = INV_MPU6050_ACTIVE_LOW | + INV_MPU6050_LATCH_INT_EN; + else { + dev_err(dev, "Invalid interrupt type 0x%x specified\n", + irq_type); + return -EINVAL; + } + /* power is turned on inside check chip type*/ result = inv_check_and_setup_chip(st); if (result) return result; - if (inv_mpu_bus_setup) - inv_mpu_bus_setup(indio_dev); - result = inv_mpu6050_init_config(indio_dev); if (result) { dev_err(dev, "Could not initialize device.\n"); return result; } + if (inv_mpu_bus_setup) + inv_mpu_bus_setup(indio_dev); + dev_set_drvdata(dev, indio_dev); indio_dev->dev.parent = dev; /* name will be NULL when enumerated via ACPI */ @@ -940,50 +1002,32 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, indio_dev->info = &mpu_info; indio_dev->modes = INDIO_BUFFER_TRIGGERED; - result = iio_triggered_buffer_setup(indio_dev, - inv_mpu6050_irq_handler, - inv_mpu6050_read_fifo, - NULL); + result = devm_iio_triggered_buffer_setup(dev, indio_dev, + inv_mpu6050_irq_handler, + inv_mpu6050_read_fifo, + NULL); if (result) { dev_err(dev, "configure buffer fail %d\n", result); return result; } - result = inv_mpu6050_probe_trigger(indio_dev); + result = inv_mpu6050_probe_trigger(indio_dev, irq_type); if (result) { dev_err(dev, "trigger probe fail %d\n", result); - goto out_unreg_ring; + return result; } INIT_KFIFO(st->timestamps); spin_lock_init(&st->time_stamp_lock); - result = iio_device_register(indio_dev); + result = devm_iio_device_register(dev, indio_dev); if (result) { dev_err(dev, "IIO register fail %d\n", result); - goto out_remove_trigger; + return result; } return 0; - -out_remove_trigger: - inv_mpu6050_remove_trigger(st); -out_unreg_ring: - iio_triggered_buffer_cleanup(indio_dev); - return result; } EXPORT_SYMBOL_GPL(inv_mpu_core_probe); -int inv_mpu_core_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - - iio_device_unregister(indio_dev); - inv_mpu6050_remove_trigger(iio_priv(indio_dev)); - iio_triggered_buffer_cleanup(indio_dev); - - return 0; -} -EXPORT_SYMBOL_GPL(inv_mpu_core_remove); - #ifdef CONFIG_PM_SLEEP static int inv_mpu_resume(struct device *dev) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index fcd7a92b6cf8..495409d56207 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -29,25 +29,18 @@ static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id) { struct iio_dev *indio_dev = i2c_mux_priv(muxc); struct inv_mpu6050_state *st = iio_priv(indio_dev); - int ret = 0; + int ret; - /* Use the same mutex which was used everywhere to protect power-op */ mutex_lock(&st->lock); - if (!st->powerup_count) { - ret = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); - if (ret) - goto write_error; - usleep_range(INV_MPU6050_REG_UP_TIME_MIN, - INV_MPU6050_REG_UP_TIME_MAX); - } - if (!ret) { - st->powerup_count++; - ret = regmap_write(st->map, st->reg->int_pin_cfg, - INV_MPU6050_INT_PIN_CFG | - INV_MPU6050_BIT_BYPASS_EN); - } -write_error: + ret = inv_mpu6050_set_power_itg(st, true); + if (ret) + goto error_unlock; + + ret = regmap_write(st->map, st->reg->int_pin_cfg, + st->irq_mask | INV_MPU6050_BIT_BYPASS_EN); + +error_unlock: mutex_unlock(&st->lock); return ret; @@ -59,12 +52,11 @@ static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id) struct inv_mpu6050_state *st = iio_priv(indio_dev); mutex_lock(&st->lock); - /* It doesn't really mattter, if any of the calls fails */ - regmap_write(st->map, st->reg->int_pin_cfg, INV_MPU6050_INT_PIN_CFG); - st->powerup_count--; - if (!st->powerup_count) - regmap_write(st->map, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_SLEEP); + + /* It doesn't really matter if any of the calls fail */ + regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); + inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&st->lock); return 0; @@ -133,29 +125,32 @@ static int inv_mpu_probe(struct i2c_client *client, return result; st = iio_priv(dev_get_drvdata(&client->dev)); - st->muxc = i2c_mux_alloc(client->adapter, &client->dev, - 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, - inv_mpu6050_select_bypass, - inv_mpu6050_deselect_bypass); - if (!st->muxc) { - result = -ENOMEM; - goto out_unreg_device; + switch (st->chip_type) { + case INV_ICM20608: + /* no i2c auxiliary bus on the chip */ + break; + default: + /* declare i2c auxiliary bus */ + st->muxc = i2c_mux_alloc(client->adapter, &client->dev, + 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, + inv_mpu6050_select_bypass, + inv_mpu6050_deselect_bypass); + if (!st->muxc) + return -ENOMEM; + st->muxc->priv = dev_get_drvdata(&client->dev); + result = i2c_mux_add_adapter(st->muxc, 0, 0, 0); + if (result) + return result; + result = inv_mpu_acpi_create_mux_client(client); + if (result) + goto out_del_mux; + break; } - st->muxc->priv = dev_get_drvdata(&client->dev); - result = i2c_mux_add_adapter(st->muxc, 0, 0, 0); - if (result) - goto out_unreg_device; - - result = inv_mpu_acpi_create_mux_client(client); - if (result) - goto out_del_mux; return 0; out_del_mux: i2c_mux_del_adapters(st->muxc); -out_unreg_device: - inv_mpu_core_remove(&client->dev); return result; } @@ -164,10 +159,12 @@ static int inv_mpu_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct inv_mpu6050_state *st = iio_priv(indio_dev); - inv_mpu_acpi_delete_mux_client(client); - i2c_mux_del_adapters(st->muxc); + if (st->muxc) { + inv_mpu_acpi_delete_mux_client(client); + i2c_mux_del_adapters(st->muxc); + } - return inv_mpu_core_remove(&client->dev); + return 0; } /* @@ -179,6 +176,7 @@ static const struct i2c_device_id inv_mpu_id[] = { {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, {"mpu9250", INV_MPU9250}, + {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, {} }; @@ -203,6 +201,10 @@ static const struct of_device_id inv_of_match[] = { .data = (void *)INV_MPU9250 }, { + .compatible = "invensense,mpu9255", + .data = (void *)INV_MPU9255 + }, + { .compatible = "invensense,icm20608", .data = (void *)INV_ICM20608 }, diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 065794162d65..c54da777945d 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -40,6 +40,7 @@ * @raw_accl: Address of first accel register. * @temperature: temperature register * @int_enable: Interrupt enable register. + * @int_status: Interrupt status register. * @pwr_mgmt_1: Controls chip's power state and clock source. * @pwr_mgmt_2: Controls power state of individual sensors. * @int_pin_cfg; Controls interrupt pin configuration. @@ -60,6 +61,7 @@ struct inv_mpu6050_reg_map { u8 raw_accl; u8 temperature; u8 int_enable; + u8 int_status; u8 pwr_mgmt_1; u8 pwr_mgmt_2; u8 int_pin_cfg; @@ -74,6 +76,7 @@ enum inv_devices { INV_MPU6000, INV_MPU9150, INV_MPU9250, + INV_MPU9255, INV_ICM20608, INV_NUM_PARTS }; @@ -94,6 +97,7 @@ struct inv_mpu6050_chip_config { unsigned int accl_fifo_enable:1; unsigned int gyro_fifo_enable:1; u16 fifo_rate; + u8 user_ctrl; }; /** @@ -125,6 +129,7 @@ struct inv_mpu6050_hw { * @timestamps: kfifo queue to store time stamp. * @map regmap pointer. * @irq interrupt number. + * @irq_mask the int_pin_cfg mask to configure interrupt type. */ struct inv_mpu6050_state { #define TIMESTAMP_FIFO_SIZE 16 @@ -143,6 +148,8 @@ struct inv_mpu6050_state { DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); struct regmap *map; int irq; + u8 irq_mask; + unsigned skip_samples; }; /*register and associated bit definition*/ @@ -166,6 +173,9 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_TEMPERATURE 0x41 #define INV_MPU6050_REG_RAW_GYRO 0x43 +#define INV_MPU6050_REG_INT_STATUS 0x3A +#define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01 + #define INV_MPU6050_REG_USER_CTRL 0x6A #define INV_MPU6050_BIT_FIFO_RST 0x04 #define INV_MPU6050_BIT_DMP_RST 0x08 @@ -215,8 +225,12 @@ struct inv_mpu6050_state { #define INV_MPU6050_OUTPUT_DATA_SIZE 24 #define INV_MPU6050_REG_INT_PIN_CFG 0x37 +#define INV_MPU6050_ACTIVE_HIGH 0x00 +#define INV_MPU6050_ACTIVE_LOW 0x80 +/* enable level triggering */ +#define INV_MPU6050_LATCH_INT_EN 0x20 #define INV_MPU6050_BIT_BYPASS_EN 0x2 -#define INV_MPU6050_INT_PIN_CFG 0 + /* init parameters */ #define INV_MPU6050_INIT_FIFO_RATE 50 @@ -232,6 +246,7 @@ struct inv_mpu6050_state { #define INV_MPU6500_WHOAMI_VALUE 0x70 #define INV_MPU9150_WHOAMI_VALUE 0x68 #define INV_MPU9250_WHOAMI_VALUE 0x71 +#define INV_MPU9255_WHOAMI_VALUE 0x73 #define INV_ICM20608_WHOAMI_VALUE 0xAF /* scan element definition */ @@ -287,8 +302,7 @@ enum inv_mpu6050_clock_sel_e { irqreturn_t inv_mpu6050_irq_handler(int irq, void *p); irqreturn_t inv_mpu6050_read_fifo(int irq, void *p); -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev); -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st); +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type); int inv_reset_fifo(struct iio_dev *indio_dev); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); @@ -297,6 +311,4 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client); void inv_mpu_acpi_delete_mux_client(struct i2c_client *client); int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type); -int inv_mpu_core_remove(struct device *dev); -int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); extern const struct dev_pm_ops inv_mpu_pmops; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index ff81c6aa009d..1795418438e4 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -51,13 +51,14 @@ int inv_reset_fifo(struct iio_dev *indio_dev) if (result) goto reset_fifo_fail; /* disable fifo reading */ - result = regmap_write(st->map, st->reg->user_ctrl, 0); + result = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (result) goto reset_fifo_fail; /* reset FIFO*/ - result = regmap_write(st->map, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_RST); + d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST; + result = regmap_write(st->map, st->reg->user_ctrl, d); if (result) goto reset_fifo_fail; @@ -72,9 +73,9 @@ int inv_reset_fifo(struct iio_dev *indio_dev) if (result) return result; } - /* enable FIFO reading and I2C master interface*/ - result = regmap_write(st->map, st->reg->user_ctrl, - INV_MPU6050_BIT_FIFO_EN); + /* enable FIFO reading */ + d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_EN; + result = regmap_write(st->map, st->reg->user_ctrl, d); if (result) goto reset_fifo_fail; /* enable sensor output to FIFO */ @@ -127,8 +128,23 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; u16 fifo_count; s64 timestamp; + int int_status; mutex_lock(&st->lock); + + /* ack interrupt and check status */ + result = regmap_read(st->map, st->reg->int_status, &int_status); + if (result) { + dev_err(regmap_get_device(st->map), + "failed to ack interrupt\n"); + goto flush_fifo; + } + if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT)) { + dev_warn(regmap_get_device(st->map), + "spurious interrupt with status 0x%x\n", int_status); + goto end_session; + } + if (!(st->chip_config.accl_fifo_enable | st->chip_config.gyro_fifo_enable)) goto end_session; @@ -140,7 +156,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; /* - * read fifo_count register to know how many bytes inside FIFO + * read fifo_count register to know how many bytes are inside the FIFO * right now */ result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data, @@ -150,7 +166,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) fifo_count = be16_to_cpup((__be16 *)(&data[0])); if (fifo_count < bytes_per_datum) goto end_session; - /* fifo count can't be odd number, if it is odd, reset fifo*/ + /* fifo count can't be an odd number. If it is odd, reset the FIFO. */ if (fifo_count & 1) goto flush_fifo; if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) @@ -159,7 +175,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (kfifo_len(&st->timestamps) > fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) goto flush_fifo; - while (fifo_count >= bytes_per_datum) { + do { result = regmap_bulk_read(st->map, st->reg->fifo_r_w, data, bytes_per_datum); if (result) @@ -170,12 +186,15 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (result == 0) timestamp = 0; - result = iio_push_to_buffers_with_timestamp(indio_dev, data, - timestamp); - if (result) - goto flush_fifo; + /* skip first samples if needed */ + if (st->skip_samples) + st->skip_samples--; + else + iio_push_to_buffers_with_timestamp(indio_dev, data, + timestamp); + fifo_count -= bytes_per_datum; - } + } while (fifo_count >= bytes_per_datum); end_session: mutex_unlock(&st->lock); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 74506e5ac0db..227f50afff22 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -31,8 +31,9 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev) if (ret) return ret; - ret = regmap_write(st->map, INV_MPU6050_REG_USER_CTRL, - INV_MPU6050_BIT_I2C_IF_DIS); + st->chip_config.user_ctrl |= INV_MPU6050_BIT_I2C_IF_DIS; + ret = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (ret) { inv_mpu6050_set_power_itg(st, false); return ret; @@ -69,11 +70,6 @@ static int inv_mpu_probe(struct spi_device *spi) inv_mpu_i2c_disable, chip_type); } -static int inv_mpu_remove(struct spi_device *spi) -{ - return inv_mpu_core_remove(&spi->dev); -} - /* * device id table is used to identify what device can be * supported by this driver @@ -83,6 +79,7 @@ static const struct spi_device_id inv_mpu_id[] = { {"mpu6500", INV_MPU6500}, {"mpu9150", INV_MPU9150}, {"mpu9250", INV_MPU9250}, + {"mpu9255", INV_MPU9255}, {"icm20608", INV_ICM20608}, {} }; @@ -97,7 +94,6 @@ MODULE_DEVICE_TABLE(acpi, inv_acpi_match); static struct spi_driver inv_mpu_driver = { .probe = inv_mpu_probe, - .remove = inv_mpu_remove, .id_table = inv_mpu_id, .driver = { .acpi_match_table = ACPI_PTR(inv_acpi_match), diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index f963f9fc98c0..6c3e1652a687 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -49,49 +49,66 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) if (result) return result; inv_scan_query(indio_dev); + st->skip_samples = 0; if (st->chip_config.gyro_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_power_off; + /* gyro first sample is out of specs, skip it */ + st->skip_samples = 1; } if (st->chip_config.accl_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_gyro_off; } result = inv_reset_fifo(indio_dev); if (result) - return result; + goto error_accl_off; } else { result = regmap_write(st->map, st->reg->fifo_en, 0); if (result) - return result; + goto error_accl_off; result = regmap_write(st->map, st->reg->int_enable, 0); if (result) - return result; + goto error_accl_off; - result = regmap_write(st->map, st->reg->user_ctrl, 0); + result = regmap_write(st->map, st->reg->user_ctrl, + st->chip_config.user_ctrl); if (result) - return result; + goto error_accl_off; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); + INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) - return result; + goto error_accl_off; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); + INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) - return result; + goto error_gyro_off; + result = inv_mpu6050_set_power_itg(st, false); if (result) - return result; + goto error_power_off; } return 0; + +error_accl_off: + if (st->chip_config.accl_fifo_enable) + inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); +error_gyro_off: + if (st->chip_config.gyro_fifo_enable) + inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); +error_power_off: + inv_mpu6050_set_power_itg(st, false); + return result; } /** @@ -117,7 +134,7 @@ static const struct iio_trigger_ops inv_mpu_trigger_ops = { .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, }; -int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type) { int ret; struct inv_mpu6050_state *st = iio_priv(indio_dev); @@ -131,7 +148,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) ret = devm_request_irq(&indio_dev->dev, st->irq, &iio_trigger_generic_data_rdy_poll, - IRQF_TRIGGER_RISING, + irq_type, "inv_mpu", st->trig); if (ret) @@ -141,7 +158,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) st->trig->ops = &inv_mpu_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); - ret = iio_trigger_register(st->trig); + ret = devm_iio_trigger_register(&indio_dev->dev, st->trig); if (ret) return ret; @@ -149,8 +166,3 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) return 0; } - -void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st) -{ - iio_trigger_unregister(st->trig); -} diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 14f2eb6e9fb7..ccc817e17eb8 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -8,7 +8,8 @@ config IIO_ST_LSM6DSX select IIO_ST_LSM6DSX_SPI if (SPI_MASTER) help Say yes here to build support for STMicroelectronics LSM6DSx imu - sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm + sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, + ism330dlc To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index a3cc7cd97026..edcd838037cd 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -18,12 +18,14 @@ #define ST_LSM6DS3H_DEV_NAME "lsm6ds3h" #define ST_LSM6DSL_DEV_NAME "lsm6dsl" #define ST_LSM6DSM_DEV_NAME "lsm6dsm" +#define ST_ISM330DLC_DEV_NAME "ism330dlc" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, ST_LSM6DS3H_ID, ST_LSM6DSL_ID, ST_LSM6DSM_ID, + ST_ISM330DLC_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 1045e025e92b..4994f920a836 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -1,10 +1,10 @@ /* * STMicroelectronics st_lsm6dsx FIFO buffer library driver * - * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM: The FIFO buffer can be configured - * to store data from gyroscope and accelerometer. Samples are queued - * without any tag according to a specific pattern based on 'FIFO data sets' - * (6 bytes each): + * LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be + * configured to store data from gyroscope and accelerometer. Samples are + * queued without any tag according to a specific pattern based on + * 'FIFO data sets' (6 bytes each): * - 1st data set is reserved for gyroscope data * - 2nd data set is reserved for accelerometer data * The FIFO pattern changes depending on the ODRs and decimation factors @@ -276,7 +276,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data, #define ST_LSM6DSX_IIO_BUFF_SIZE (ALIGN(ST_LSM6DSX_SAMPLE_SIZE, \ sizeof(s64)) + sizeof(s64)) /** - * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DS3H-LSM6DSL-LSM6DSM read FIFO routine + * st_lsm6dsx_read_fifo() - hw FIFO read routine * @hw: Pointer to instance of struct st_lsm6dsx_hw. * * Read samples from the hw FIFO and push them to IIO buffers. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 8656d72ef4ee..aebbe0ddd8d8 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -17,7 +17,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 8KB * - * - LSM6DS3H/LSM6DSL/LSM6DSM: + * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 @@ -252,6 +252,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .id = { [0] = ST_LSM6DSL_ID, [1] = ST_LSM6DSM_ID, + [2] = ST_ISM330DLC_ID, }, .decimator = { [ST_LSM6DSX_ID_ACC] = { @@ -266,11 +267,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fifo_ops = { .fifo_th = { .addr = 0x06, - .mask = GENMASK(11, 0), + .mask = GENMASK(10, 0), }, .fifo_diff = { .addr = 0x3a, - .mask = GENMASK(11, 0), + .mask = GENMASK(10, 0), }, .th_wl = 3, /* 1LSB = 2B */ }, diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 41525dd2aab7..377c4e9997da 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, }, + { + .compatible = "st,ism330dlc", + .data = (void *)ST_ISM330DLC_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -66,6 +70,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, + { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 2c8135834479..fec5c6ce7eb7 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -57,6 +57,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dsm", .data = (void *)ST_LSM6DSM_ID, }, + { + .compatible = "st,ism330dlc", + .data = (void *)ST_ISM330DLC_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -66,6 +70,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3H_DEV_NAME, ST_LSM6DS3H_ID }, { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID }, { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID }, + { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); |