diff options
Diffstat (limited to 'drivers/iio')
30 files changed, 1505 insertions, 111 deletions
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 4a24c2ee81a9..c2229a521ab9 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -94,7 +94,6 @@ error_ret: static int kxsd9_read(struct iio_dev *indio_dev, u8 address) { - struct spi_message msg; int ret; struct kxsd9_state *st = iio_priv(indio_dev); struct spi_transfer xfers[] = { @@ -112,10 +111,7 @@ static int kxsd9_read(struct iio_dev *indio_dev, u8 address) mutex_lock(&st->buf_lock); st->tx[0] = KXSD9_READ(address); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers)); if (ret) return ret; return (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index a235de252a90..e0f5a3ceba5e 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -20,7 +20,7 @@ #include <linux/irq.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> @@ -419,10 +419,15 @@ static const struct iio_info accel_info = { .write_raw = &st_accel_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER static const struct iio_trigger_ops st_accel_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE, }; +#define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops) +#else +#define ST_ACCEL_TRIGGER_OPS NULL +#endif int st_accel_common_probe(struct iio_dev *indio_dev) { @@ -455,7 +460,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) goto st_accel_common_probe_error; err = st_sensors_allocate_trigger(indio_dev, - &st_accel_trigger_ops); + ST_ACCEL_TRIGGER_OPS); if (err < 0) goto st_accel_probe_trigger_error; } diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 90b8ddfb61ed..ffc9d097e484 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_i2c.h> diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index dbd45c08711f..22b35bfea7d2 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_spi.h> diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 08e4feb4f6ee..6c1cfb74bdfc 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -163,6 +163,8 @@ struct max1363_chip_info { * @mask_low: bitmask for enabled low thresholds * @thresh_high: high threshold values * @thresh_low: low threshold values + * @vref: Reference voltage regulator + * @vref_uv: Actual (external or internal) reference voltage */ struct max1363_state { struct i2c_client *client; @@ -182,6 +184,8 @@ struct max1363_state { /* 4x unipolar first then the fours bipolar ones */ s16 thresh_high[8]; s16 thresh_low[8]; + struct regulator *vref; + u32 vref_uv; }; #define MAX1363_MODE_SINGLE(_num, _mask) { \ @@ -393,6 +397,8 @@ static int max1363_read_raw(struct iio_dev *indio_dev, { struct max1363_state *st = iio_priv(indio_dev); int ret; + unsigned long scale_uv; + switch (m) { case IIO_CHAN_INFO_RAW: ret = max1363_read_single_chan(indio_dev, chan, val, m); @@ -400,16 +406,10 @@ static int max1363_read_raw(struct iio_dev *indio_dev, return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - if ((1 << (st->chip_info->bits + 1)) > - st->chip_info->int_vref_mv) { - *val = 0; - *val2 = 500000; - return IIO_VAL_INT_PLUS_MICRO; - } else { - *val = (st->chip_info->int_vref_mv) - >> st->chip_info->bits; - return IIO_VAL_INT; - } + scale_uv = st->vref_uv >> st->chip_info->bits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; } @@ -1390,12 +1390,16 @@ static const struct max1363_chip_info max1363_chip_info_tbl[] = { static int max1363_initial_setup(struct max1363_state *st) { - st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD - | MAX1363_SETUP_POWER_UP_INT_REF - | MAX1363_SETUP_INT_CLOCK + st->setupbyte = MAX1363_SETUP_INT_CLOCK | MAX1363_SETUP_UNIPOLAR | MAX1363_SETUP_NORESET; + if (st->vref) + st->setupbyte |= MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF; + else + st->setupbyte |= MAX1363_SETUP_POWER_UP_INT_REF + | MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT; + /* Set scan mode writes the config anyway so wait until then */ st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte); st->current_mode = &max1363_mode_table[st->chip_info->default_mode]; @@ -1410,8 +1414,9 @@ static int max1363_alloc_scan_masks(struct iio_dev *indio_dev) unsigned long *masks; int i; - masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)* - (st->chip_info->num_modes + 1), GFP_KERNEL); + masks = devm_kzalloc(&indio_dev->dev, + BITS_TO_LONGS(MAX1363_MAX_CHANNELS) * sizeof(long) * + (st->chip_info->num_modes + 1), GFP_KERNEL); if (!masks) return -ENOMEM; @@ -1490,6 +1495,7 @@ static int max1363_probe(struct i2c_client *client, int ret; struct max1363_state *st; struct iio_dev *indio_dev; + struct regulator *vref; indio_dev = iio_device_alloc(sizeof(struct max1363_state)); if (indio_dev == NULL) { @@ -1504,7 +1510,7 @@ static int max1363_probe(struct i2c_client *client, st = iio_priv(indio_dev); - st->reg = regulator_get(&client->dev, "vcc"); + st->reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(st->reg)) { ret = PTR_ERR(st->reg); goto error_unregister_map; @@ -1512,7 +1518,7 @@ static int max1363_probe(struct i2c_client *client, ret = regulator_enable(st->reg); if (ret) - goto error_put_reg; + goto error_unregister_map; /* this is only used for device removal purposes */ i2c_set_clientdata(client, indio_dev); @@ -1520,6 +1526,23 @@ static int max1363_probe(struct i2c_client *client, st->chip_info = &max1363_chip_info_tbl[id->driver_data]; st->client = client; + st->vref_uv = st->chip_info->int_vref_mv * 1000; + vref = devm_regulator_get(&client->dev, "vref"); + if (!IS_ERR(vref)) { + int vref_uv; + + ret = regulator_enable(vref); + if (ret) + goto error_disable_reg; + st->vref = vref; + vref_uv = regulator_get_voltage(vref); + if (vref_uv <= 0) { + ret = -EINVAL; + goto error_disable_reg; + } + st->vref_uv = vref_uv; + } + ret = max1363_alloc_scan_masks(indio_dev); if (ret) goto error_disable_reg; @@ -1533,15 +1556,15 @@ static int max1363_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; ret = max1363_initial_setup(st); if (ret < 0) - goto error_free_available_scan_masks; + goto error_disable_reg; ret = iio_triggered_buffer_setup(indio_dev, NULL, &max1363_trigger_handler, &max1363_buffered_setup_ops); if (ret) - goto error_free_available_scan_masks; + goto error_disable_reg; if (client->irq) { - ret = request_threaded_irq(st->client->irq, + ret = devm_request_threaded_irq(&client->dev, st->client->irq, NULL, &max1363_event_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, @@ -1554,20 +1577,16 @@ static int max1363_probe(struct i2c_client *client, ret = iio_device_register(indio_dev); if (ret < 0) - goto error_free_irq; + goto error_uninit_buffer; return 0; -error_free_irq: - if (client->irq) - free_irq(st->client->irq, indio_dev); + error_uninit_buffer: iio_triggered_buffer_cleanup(indio_dev); -error_free_available_scan_masks: - kfree(indio_dev->available_scan_masks); error_disable_reg: + if (st->vref) + regulator_disable(st->vref); regulator_disable(st->reg); -error_put_reg: - regulator_put(st->reg); error_unregister_map: iio_map_array_unregister(indio_dev); error_free_device: @@ -1582,12 +1601,10 @@ static int max1363_remove(struct i2c_client *client) struct max1363_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - if (client->irq) - free_irq(st->client->irq, indio_dev); iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->available_scan_masks); + if (st->vref) + regulator_disable(st->vref); regulator_disable(st->reg); - regulator_put(st->reg); iio_map_array_unregister(indio_dev); iio_device_free(indio_dev); diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index 54b46fd3aede..92771217f665 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -213,7 +213,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, unsigned int addr) { struct ad5360_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -226,10 +225,6 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) | @@ -237,7 +232,7 @@ static int ad5360_read(struct iio_dev *indio_dev, unsigned int type, AD5360_READBACK_TYPE(type) | AD5360_READBACK_ADDR(addr)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 43be948db83e..6b86a638dad0 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -127,7 +127,6 @@ static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg, static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) { struct ad5421_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -140,15 +139,11 @@ static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 0661829f2773..e5e59749f109 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -85,11 +85,7 @@ static int ad5504_spi_read(struct spi_device *spi, u8 addr) .rx_buf = &val, .len = 2, }; - struct spi_message m; - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - ret = spi_sync(spi, &m); + ret = spi_sync_transfer(spi, &t, 1); if (ret < 0) return ret; diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index ca9609d7a15c..5e554af21703 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -117,18 +117,13 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) .len = 3, }, }; - struct spi_message m; int ret; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | AD5686_ADDR(addr)); st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) return ret; diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 0869bbd27d30..71faabc6b14e 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -153,7 +153,6 @@ static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel, static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) { struct ad5755_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -167,16 +166,12 @@ static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16)); st->data[1].d32 = cpu_to_be32(AD5755_NOOP); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) ret = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index 7f9045e6daa4..5b7acd3a2c77 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -135,7 +135,6 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, unsigned int *val) { struct ad5764_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -148,15 +147,11 @@ static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg, }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - mutex_lock(&indio_dev->mlock); st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret >= 0) *val = be32_to_cpu(st->data[1].d32) & 0xffff; diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 6407b5407ddd..8dfd3da8a07b 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -125,7 +125,6 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) u8 d8[4]; } data[3]; int ret; - struct spi_message msg; struct spi_transfer xfers[] = { { .tx_buf = &data[0].d8[1], @@ -144,10 +143,7 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) AD5791_ADDR(addr)); data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(spi, &msg); + ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); *val = be32_to_cpu(data[2].d32); diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c index 80307473e3a9..1ea132e239ea 100644 --- a/drivers/iio/frequency/ad9523.c +++ b/drivers/iio/frequency/ad9523.c @@ -287,7 +287,6 @@ struct ad9523_state { static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) { struct ad9523_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; /* We encode the register size 1..3 bytes into the register address. @@ -305,15 +304,11 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD9523_READ | AD9523_CNT(AD9523_TRANSF_LEN(addr)) | AD9523_ADDR(addr)); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) dev_err(&indio_dev->dev, "read failed (%d)", ret); else @@ -326,7 +321,6 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr) static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val) { struct ad9523_state *st = iio_priv(indio_dev); - struct spi_message m; int ret; struct spi_transfer t[] = { { @@ -338,16 +332,12 @@ static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val) }, }; - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - st->data[0].d32 = cpu_to_be32(AD9523_WRITE | AD9523_CNT(AD9523_TRANSF_LEN(addr)) | AD9523_ADDR(addr)); st->data[1].d32 = cpu_to_be32(val); - ret = spi_sync(st->spi, &m); + ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t)); if (ret < 0) dev_err(&indio_dev->dev, "write failed (%d)", ret); diff --git a/drivers/iio/gyro/adxrs450.c b/drivers/iio/gyro/adxrs450.c index d9d43831c380..5b79953f7011 100644 --- a/drivers/iio/gyro/adxrs450.c +++ b/drivers/iio/gyro/adxrs450.c @@ -213,7 +213,6 @@ error_ret: static int adxrs450_spi_initial(struct adxrs450_state *st, u32 *val, char chk) { - struct spi_message msg; int ret; u32 tx; struct spi_transfer xfers = { @@ -228,9 +227,7 @@ static int adxrs450_spi_initial(struct adxrs450_state *st, if (chk) tx |= (ADXRS450_CHK | ADXRS450_P); st->tx = cpu_to_be32(tx); - spi_message_init(&msg); - spi_message_add_tail(&xfers, &msg); - ret = spi_sync(st->us, &msg); + ret = spi_sync_transfer(st->us, &xfers, 1); if (ret) { dev_err(&st->us->dev, "Problem while reading initializing data\n"); goto error_ret; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 0a09998276c0..fa9b24219987 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -21,7 +21,7 @@ #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> @@ -287,10 +287,15 @@ static const struct iio_info gyro_info = { .write_raw = &st_gyro_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER static const struct iio_trigger_ops st_gyro_trigger_ops = { .owner = THIS_MODULE, .set_trigger_state = ST_GYRO_TRIGGER_SET_STATE, }; +#define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops) +#else +#define ST_GYRO_TRIGGER_OPS NULL +#endif int st_gyro_common_probe(struct iio_dev *indio_dev) { @@ -323,7 +328,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) goto st_gyro_common_probe_error; err = st_sensors_allocate_trigger(indio_dev, - &st_gyro_trigger_ops); + ST_GYRO_TRIGGER_OPS); if (err < 0) goto st_gyro_probe_trigger_error; } diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index a44b5b4a2013..8a310500573d 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_i2c.h> diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 8b4dcc5eab0c..f3540390eb22 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_spi.h> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 47f66ed9c4ef..4f40a10cb74f 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -36,3 +36,5 @@ config IIO_ADIS_LIB_BUFFER help A set of buffer helper functions for the Analog Devices ADIS* device family. + +source "drivers/iio/imu/inv_mpu6050/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 019b717c5ff1..f2f56ceaed26 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -11,3 +11,5 @@ adis_lib-y += adis.o adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o + +obj-y += inv_mpu6050/ diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig new file mode 100644 index 000000000000..b5cfa3a354cf --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -0,0 +1,13 @@ +# +# inv-mpu6050 drivers for Invensense MPU devices and combos +# + +config INV_MPU6050_IIO + tristate "Invensense MPU6050 devices" + depends on I2C && SYSFS + select IIO_TRIGGERED_BUFFER + help + This driver supports the Invensense MPU6050 devices. + It is a gyroscope/accelerometer combo device. + This driver can be built as a module. The module will be called + inv-mpu6050. diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile new file mode 100644 index 000000000000..3a677c778afb --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Invensense MPU6050 device. +# + +obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o +inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c new file mode 100644 index 000000000000..37ca05b47e4b --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -0,0 +1,795 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/sysfs.h> +#include <linux/jiffies.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kfifo.h> +#include <linux/spinlock.h> +#include "inv_mpu_iio.h" + +/* + * this is the gyro scale translated from dynamic range plus/minus + * {250, 500, 1000, 2000} to rad/s + */ +static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724}; + +/* + * this is the accel scale translated from dynamic range plus/minus + * {2, 4, 8, 16} to m/s^2 + */ +static const int accel_scale[] = {598, 1196, 2392, 4785}; + +static const struct inv_mpu6050_reg_map reg_set_6050 = { + .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, + .lpf = INV_MPU6050_REG_CONFIG, + .user_ctrl = INV_MPU6050_REG_USER_CTRL, + .fifo_en = INV_MPU6050_REG_FIFO_EN, + .gyro_config = INV_MPU6050_REG_GYRO_CONFIG, + .accl_config = INV_MPU6050_REG_ACCEL_CONFIG, + .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H, + .fifo_r_w = INV_MPU6050_REG_FIFO_R_W, + .raw_gyro = INV_MPU6050_REG_RAW_GYRO, + .raw_accl = INV_MPU6050_REG_RAW_ACCEL, + .temperature = INV_MPU6050_REG_TEMPERATURE, + .int_enable = INV_MPU6050_REG_INT_ENABLE, + .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1, + .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2, +}; + +static const struct inv_mpu6050_chip_config chip_config_6050 = { + .fsr = INV_MPU6050_FSR_2000DPS, + .lpf = INV_MPU6050_FILTER_20HZ, + .fifo_rate = INV_MPU6050_INIT_FIFO_RATE, + .gyro_fifo_enable = false, + .accl_fifo_enable = false, + .accl_fs = INV_MPU6050_FS_02G, +}; + +static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = { + { + .num_reg = 117, + .name = "MPU6050", + .reg = ®_set_6050, + .config = &chip_config_6050, + }, +}; + +int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d) +{ + return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d); +} + +int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) +{ + u8 d, mgmt_1; + int result; + + /* switch clock needs to be careful. Only when gyro is on, can + clock source be switched to gyro. Otherwise, it must be set to + internal clock */ + if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->pwr_mgmt_1, 1, &mgmt_1); + if (result != 1) + return result; + + mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK; + } + + if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) { + /* turning off gyro requires switch to internal clock first. + Then turn off gyro engine */ + mgmt_1 |= INV_CLK_INTERNAL; + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, mgmt_1); + if (result) + return result; + } + + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->pwr_mgmt_2, 1, &d); + if (result != 1) + return result; + if (en) + d &= ~mask; + else + d |= mask; + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d); + if (result) + return result; + + if (en) { + /* Wait for output stablize */ + msleep(INV_MPU6050_TEMP_UP_TIME); + if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { + /* switch internal clock to PLL */ + mgmt_1 |= INV_CLK_PLL; + result = inv_mpu6050_write_reg(st, + st->reg->pwr_mgmt_1, mgmt_1); + if (result) + return result; + } + } + + return 0; +} + +int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) +{ + int result; + + if (power_on) + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0); + else + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_SLEEP); + if (result) + return result; + + if (power_on) + msleep(INV_MPU6050_REG_UP_TIME); + + return 0; +} + +/** + * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. + * + * Initial configuration: + * FSR: ± 2000DPS + * DLPF: 20Hz + * FIFO rate: 50Hz + * Clock source: Gyro PLL + */ +static int inv_mpu6050_init_config(struct iio_dev *indio_dev) +{ + int result; + u8 d; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); + if (result) + return result; + + d = INV_MPU6050_FILTER_20HZ; + result = inv_mpu6050_write_reg(st, st->reg->lpf, d); + if (result) + return result; + + d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1; + result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); + if (result) + return result; + + d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); + 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 result; +} + +static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, + int axis, int *val) +{ + int ind, result; + __be16 d; + + ind = (axis - IIO_MOD_X) * 2; + result = i2c_smbus_read_i2c_block_data(st->client, reg + ind, 2, + (u8 *)&d); + if (result != 2) + return -EINVAL; + *val = (short)be16_to_cpup(&d); + + return IIO_VAL_INT; +} + +static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) { + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + { + int ret, result; + + ret = IIO_VAL_INT; + result = 0; + mutex_lock(&indio_dev->mlock); + if (!st->chip_config.enable) { + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto error_read_raw; + } + /* when enable is on, power is already on */ + switch (chan->type) { + case IIO_ANGL_VEL: + if (!st->chip_config.gyro_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_read_raw; + } + ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, + chan->channel2, val); + if (!st->chip_config.gyro_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + goto error_read_raw; + } + break; + case IIO_ACCEL: + if (!st->chip_config.accl_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_read_raw; + } + ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, + chan->channel2, val); + if (!st->chip_config.accl_fifo_enable || + !st->chip_config.enable) { + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + goto error_read_raw; + } + break; + case IIO_TEMP: + /* wait for stablization */ + msleep(INV_MPU6050_SENSOR_UP_TIME); + inv_mpu6050_sensor_show(st, st->reg->temperature, + IIO_MOD_X, val); + break; + default: + ret = -EINVAL; + break; + } +error_read_raw: + if (!st->chip_config.enable) + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + return ret; + } + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + *val = 0; + *val2 = gyro_scale_6050[st->chip_config.fsr]; + + return IIO_VAL_INT_PLUS_NANO; + case IIO_ACCEL: + *val = 0; + *val2 = accel_scale[st->chip_config.accl_fs]; + + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + *val = 0; + *val2 = INV_MPU6050_TEMP_SCALE; + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + *val = INV_MPU6050_TEMP_OFFSET; + + return IIO_VAL_INT; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr) +{ + int result; + u8 d; + + if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM) + return -EINVAL; + if (fsr == st->chip_config.fsr) + return 0; + + d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d); + if (result) + return result; + st->chip_config.fsr = fsr; + + return 0; +} + +static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs) +{ + int result; + u8 d; + + if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM) + return -EINVAL; + if (fs == st->chip_config.accl_fs) + return 0; + + d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); + result = inv_mpu6050_write_reg(st, st->reg->accl_config, d); + if (result) + return result; + st->chip_config.accl_fs = fs; + + return 0; +} + +static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) { + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + + mutex_lock(&indio_dev->mlock); + /* we should only update scale when the chip is disabled, i.e., + not running */ + if (st->chip_config.enable) { + result = -EBUSY; + goto error_write_raw; + } + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto error_write_raw; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_ANGL_VEL: + result = inv_mpu6050_write_fsr(st, val); + break; + case IIO_ACCEL: + result = inv_mpu6050_write_accel_fs(st, val); + break; + default: + result = -EINVAL; + break; + } + break; + default: + result = -EINVAL; + break; + } + +error_write_raw: + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + + return result; +} + +/** + * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. + * + * Based on the Nyquist principle, the sampling rate must + * exceed twice of the bandwidth of the signal, or there + * would be alising. This function basically search for the + * correct low pass parameters based on the fifo rate, e.g, + * sampling frequency. + */ +static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) +{ + const int hz[] = {188, 98, 42, 20, 10, 5}; + const int d[] = {INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ, + INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ, + INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ}; + int i, h, result; + u8 data; + + h = (rate >> 1); + i = 0; + while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) + i++; + data = d[i]; + result = inv_mpu6050_write_reg(st, st->reg->lpf, data); + if (result) + return result; + st->chip_config.lpf = data; + + return 0; +} + +/** + * inv_mpu6050_fifo_rate_store() - Set fifo rate. + */ +static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + s32 fifo_rate; + u8 d; + int result; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + if (kstrtoint(buf, 10, &fifo_rate)) + return -EINVAL; + if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || + fifo_rate > INV_MPU6050_MAX_FIFO_RATE) + return -EINVAL; + if (fifo_rate == st->chip_config.fifo_rate) + return count; + + mutex_lock(&indio_dev->mlock); + if (st->chip_config.enable) { + result = -EBUSY; + goto fifo_rate_fail; + } + result = inv_mpu6050_set_power_itg(st, true); + if (result) + goto fifo_rate_fail; + + d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1; + result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d); + if (result) + goto fifo_rate_fail; + st->chip_config.fifo_rate = fifo_rate; + + result = inv_mpu6050_set_lpf(st, fifo_rate); + if (result) + goto fifo_rate_fail; + +fifo_rate_fail: + result |= inv_mpu6050_set_power_itg(st, false); + mutex_unlock(&indio_dev->mlock); + if (result) + return result; + + return count; +} + +/** + * inv_fifo_rate_show() - Get the current sampling rate. + */ +static ssize_t inv_fifo_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); + + return sprintf(buf, "%d\n", st->chip_config.fifo_rate); +} + +/** + * inv_attr_show() - calling this function will show current + * parameters. + */ +static ssize_t inv_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + s8 *m; + + switch (this_attr->address) { + /* In MPU6050, the two matrix are the same because gyro and accel + are integrated in one chip */ + case ATTR_GYRO_MATRIX: + case ATTR_ACCL_MATRIX: + m = st->plat_data.orientation; + + return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n", + m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); + default: + return -EINVAL; + } +} + +/** + * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense + * MPU6050 device. + * @indio_dev: The IIO device + * @trig: The new trigger + * + * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050 + * device, -EINVAL otherwise. + */ +static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +#define INV_MPU6050_CHAN(_type, _channel2, _index) \ + { \ + .type = _type, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \ + | IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .shift = 0 , \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec inv_mpu_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), + /* + * Note that temperature should only be via polled reading only, + * not the final scan elements output. + */ + { + .type = IIO_TEMP, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT + | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT + | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, + .scan_index = -1, + }, + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), + + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), +}; + +/* constant IIO attribute */ +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); +static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show, + inv_mpu6050_fifo_rate_store); +static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_GYRO_MATRIX); +static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL, + ATTR_ACCL_MATRIX); + +static struct attribute *inv_attributes[] = { + &iio_dev_attr_in_gyro_matrix.dev_attr.attr, + &iio_dev_attr_in_accel_matrix.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group inv_attribute_group = { + .attrs = inv_attributes +}; + +static const struct iio_info mpu_info = { + .driver_module = THIS_MODULE, + .read_raw = &inv_mpu6050_read_raw, + .write_raw = &inv_mpu6050_write_raw, + .attrs = &inv_attribute_group, + .validate_trigger = inv_mpu6050_validate_trigger, +}; + +/** + * inv_check_and_setup_chip() - check and setup chip. + */ +static int inv_check_and_setup_chip(struct inv_mpu6050_state *st, + const struct i2c_device_id *id) +{ + int result; + + st->chip_type = INV_MPU6050; + st->hw = &hw_info[st->chip_type]; + st->reg = hw_info[st->chip_type].reg; + + /* reset to make sure previous state are not there */ + result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_H_RESET); + if (result) + return result; + 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 + 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; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + + return 0; +} + +/** + * inv_mpu_probe() - probe function. + * @client: i2c client. + * @id: i2c device id. + * + * Returns 0 on success, a negative error code otherwise. + */ +static int inv_mpu_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct inv_mpu6050_state *st; + struct iio_dev *indio_dev; + int result; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK | + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { + result = -ENOSYS; + goto out_no_free; + } + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + result = -ENOMEM; + goto out_no_free; + } + st = iio_priv(indio_dev); + st->client = client; + st->plat_data = *(struct inv_mpu6050_platform_data + *)dev_get_platdata(&client->dev); + /* power is turned on inside check chip type*/ + result = inv_check_and_setup_chip(st, id); + if (result) + goto out_free; + + result = inv_mpu6050_init_config(indio_dev); + if (result) { + dev_err(&client->dev, + "Could not initialize device.\n"); + goto out_free; + } + + i2c_set_clientdata(client, indio_dev); + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->channels = inv_mpu_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + + 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); + if (result) { + dev_err(&st->client->dev, "configure buffer fail %d\n", + result); + goto out_free; + } + result = inv_mpu6050_probe_trigger(indio_dev); + if (result) { + dev_err(&st->client->dev, "trigger probe fail %d\n", result); + goto out_unreg_ring; + } + + INIT_KFIFO(st->timestamps); + spin_lock_init(&st->time_stamp_lock); + result = iio_device_register(indio_dev); + if (result) { + dev_err(&st->client->dev, "IIO register fail %d\n", result); + goto out_remove_trigger; + } + + return 0; + +out_remove_trigger: + inv_mpu6050_remove_trigger(st); +out_unreg_ring: + iio_triggered_buffer_cleanup(indio_dev); +out_free: + iio_device_free(indio_dev); +out_no_free: + + return result; +} + +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); + + iio_device_unregister(indio_dev); + inv_mpu6050_remove_trigger(st); + iio_triggered_buffer_cleanup(indio_dev); + iio_device_free(indio_dev); + + return 0; +} +#ifdef CONFIG_PM_SLEEP + +static int inv_mpu_resume(struct device *dev) +{ + return inv_mpu6050_set_power_itg( + iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true); +} + +static int inv_mpu_suspend(struct device *dev) +{ + return inv_mpu6050_set_power_itg( + iio_priv(i2c_get_clientdata(to_i2c_client(dev))), false); +} +static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); + +#define INV_MPU6050_PMOPS (&inv_mpu_pmops) +#else +#define INV_MPU6050_PMOPS NULL +#endif /* CONFIG_PM_SLEEP */ + +/* + * device id table is used to identify what device can be + * supported by this driver + */ +static const struct i2c_device_id inv_mpu_id[] = { + {"mpu6050", INV_MPU6050}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, inv_mpu_id); + +static struct i2c_driver inv_mpu_driver = { + .probe = inv_mpu_probe, + .remove = inv_mpu_remove, + .id_table = inv_mpu_id, + .driver = { + .owner = THIS_MODULE, + .name = "inv-mpu6050", + .pm = INV_MPU6050_PMOPS, + }, +}; + +module_i2c_driver(inv_mpu_driver); + +MODULE_AUTHOR("Invensense Corporation"); +MODULE_DESCRIPTION("Invensense device MPU6050 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h new file mode 100644 index 000000000000..f38395529a44 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -0,0 +1,246 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ +#include <linux/i2c.h> +#include <linux/kfifo.h> +#include <linux/spinlock.h> +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/kfifo_buf.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/platform_data/invensense_mpu6050.h> + +/** + * struct inv_mpu6050_reg_map - Notable registers. + * @sample_rate_div: Divider applied to gyro output rate. + * @lpf: Configures internal low pass filter. + * @user_ctrl: Enables/resets the FIFO. + * @fifo_en: Determines which data will appear in FIFO. + * @gyro_config: gyro config register. + * @accl_config: accel config register + * @fifo_count_h: Upper byte of FIFO count. + * @fifo_r_w: FIFO register. + * @raw_gyro: Address of first gyro register. + * @raw_accl: Address of first accel register. + * @temperature: temperature register + * @int_enable: Interrupt enable register. + * @pwr_mgmt_1: Controls chip's power state and clock source. + * @pwr_mgmt_2: Controls power state of individual sensors. + */ +struct inv_mpu6050_reg_map { + u8 sample_rate_div; + u8 lpf; + u8 user_ctrl; + u8 fifo_en; + u8 gyro_config; + u8 accl_config; + u8 fifo_count_h; + u8 fifo_r_w; + u8 raw_gyro; + u8 raw_accl; + u8 temperature; + u8 int_enable; + u8 pwr_mgmt_1; + u8 pwr_mgmt_2; +}; + +/*device enum */ +enum inv_devices { + INV_MPU6050, + INV_NUM_PARTS +}; + +/** + * struct inv_mpu6050_chip_config - Cached chip configuration data. + * @fsr: Full scale range. + * @lpf: Digital low pass filter frequency. + * @accl_fs: accel full scale range. + * @enable: master enable state. + * @accl_fifo_enable: enable accel data output + * @gyro_fifo_enable: enable gyro data output + * @fifo_rate: FIFO update rate. + */ +struct inv_mpu6050_chip_config { + unsigned int fsr:2; + unsigned int lpf:3; + unsigned int accl_fs:2; + unsigned int enable:1; + unsigned int accl_fifo_enable:1; + unsigned int gyro_fifo_enable:1; + u16 fifo_rate; +}; + +/** + * struct inv_mpu6050_hw - Other important hardware information. + * @num_reg: Number of registers on device. + * @name: name of the chip. + * @reg: register map of the chip. + * @config: configuration of the chip. + */ +struct inv_mpu6050_hw { + u8 num_reg; + u8 *name; + const struct inv_mpu6050_reg_map *reg; + const struct inv_mpu6050_chip_config *config; +}; + +/* + * struct inv_mpu6050_state - Driver state variables. + * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. + * @trig: IIO trigger. + * @chip_config: Cached attribute information. + * @reg: Map of important registers. + * @hw: Other hardware-specific information. + * @chip_type: chip type. + * @time_stamp_lock: spin lock to time stamp. + * @client: i2c client handle. + * @plat_data: platform data. + * @timestamps: kfifo queue to store time stamp. + */ +struct inv_mpu6050_state { +#define TIMESTAMP_FIFO_SIZE 16 + struct iio_trigger *trig; + struct inv_mpu6050_chip_config chip_config; + const struct inv_mpu6050_reg_map *reg; + const struct inv_mpu6050_hw *hw; + enum inv_devices chip_type; + spinlock_t time_stamp_lock; + struct i2c_client *client; + struct inv_mpu6050_platform_data plat_data; + DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); +}; + +/*register and associated bit definition*/ +#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19 +#define INV_MPU6050_REG_CONFIG 0x1A +#define INV_MPU6050_REG_GYRO_CONFIG 0x1B +#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C + +#define INV_MPU6050_REG_FIFO_EN 0x23 +#define INV_MPU6050_BIT_ACCEL_OUT 0x08 +#define INV_MPU6050_BITS_GYRO_OUT 0x70 + +#define INV_MPU6050_REG_INT_ENABLE 0x38 +#define INV_MPU6050_BIT_DATA_RDY_EN 0x01 +#define INV_MPU6050_BIT_DMP_INT_EN 0x02 + +#define INV_MPU6050_REG_RAW_ACCEL 0x3B +#define INV_MPU6050_REG_TEMPERATURE 0x41 +#define INV_MPU6050_REG_RAW_GYRO 0x43 + +#define INV_MPU6050_REG_USER_CTRL 0x6A +#define INV_MPU6050_BIT_FIFO_RST 0x04 +#define INV_MPU6050_BIT_DMP_RST 0x08 +#define INV_MPU6050_BIT_I2C_MST_EN 0x20 +#define INV_MPU6050_BIT_FIFO_EN 0x40 +#define INV_MPU6050_BIT_DMP_EN 0x80 + +#define INV_MPU6050_REG_PWR_MGMT_1 0x6B +#define INV_MPU6050_BIT_H_RESET 0x80 +#define INV_MPU6050_BIT_SLEEP 0x40 +#define INV_MPU6050_BIT_CLK_MASK 0x7 + +#define INV_MPU6050_REG_PWR_MGMT_2 0x6C +#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38 +#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07 + +#define INV_MPU6050_REG_FIFO_COUNT_H 0x72 +#define INV_MPU6050_REG_FIFO_R_W 0x74 + +#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 +#define INV_MPU6050_FIFO_COUNT_BYTE 2 +#define INV_MPU6050_FIFO_THRESHOLD 500 +#define INV_MPU6050_POWER_UP_TIME 100 +#define INV_MPU6050_TEMP_UP_TIME 100 +#define INV_MPU6050_SENSOR_UP_TIME 30 +#define INV_MPU6050_REG_UP_TIME 5 + +#define INV_MPU6050_TEMP_OFFSET 12421 +#define INV_MPU6050_TEMP_SCALE 2941 +#define INV_MPU6050_MAX_GYRO_FS_PARAM 3 +#define INV_MPU6050_MAX_ACCL_FS_PARAM 3 +#define INV_MPU6050_THREE_AXIS 3 +#define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT 3 +#define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT 3 + +/* 6 + 6 round up and plus 8 */ +#define INV_MPU6050_OUTPUT_DATA_SIZE 24 + +/* init parameters */ +#define INV_MPU6050_INIT_FIFO_RATE 50 +#define INV_MPU6050_TIME_STAMP_TOR 5 +#define INV_MPU6050_MAX_FIFO_RATE 1000 +#define INV_MPU6050_MIN_FIFO_RATE 4 +#define INV_MPU6050_ONE_K_HZ 1000 + +/* scan element definition */ +enum inv_mpu6050_scan { + INV_MPU6050_SCAN_ACCL_X, + INV_MPU6050_SCAN_ACCL_Y, + INV_MPU6050_SCAN_ACCL_Z, + INV_MPU6050_SCAN_GYRO_X, + INV_MPU6050_SCAN_GYRO_Y, + INV_MPU6050_SCAN_GYRO_Z, + INV_MPU6050_SCAN_TIMESTAMP, +}; + +enum inv_mpu6050_filter_e { + INV_MPU6050_FILTER_256HZ_NOLPF2 = 0, + INV_MPU6050_FILTER_188HZ, + INV_MPU6050_FILTER_98HZ, + INV_MPU6050_FILTER_42HZ, + INV_MPU6050_FILTER_20HZ, + INV_MPU6050_FILTER_10HZ, + INV_MPU6050_FILTER_5HZ, + INV_MPU6050_FILTER_2100HZ_NOLPF, + NUM_MPU6050_FILTER +}; + +/* IIO attribute address */ +enum INV_MPU6050_IIO_ATTR_ADDR { + ATTR_GYRO_MATRIX, + ATTR_ACCL_MATRIX, +}; + +enum inv_mpu6050_accl_fs_e { + INV_MPU6050_FS_02G = 0, + INV_MPU6050_FS_04G, + INV_MPU6050_FS_08G, + INV_MPU6050_FS_16G, + NUM_ACCL_FSR +}; + +enum inv_mpu6050_fsr_e { + INV_MPU6050_FSR_250DPS = 0, + INV_MPU6050_FSR_500DPS, + INV_MPU6050_FSR_1000DPS, + INV_MPU6050_FSR_2000DPS, + NUM_MPU6050_FSR +}; + +enum inv_mpu6050_clock_sel_e { + INV_CLK_INTERNAL = 0, + INV_CLK_PLL, + NUM_CLK +}; + +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_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); +int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c new file mode 100644 index 000000000000..331781ffbb15 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -0,0 +1,196 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/sysfs.h> +#include <linux/jiffies.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kfifo.h> +#include <linux/poll.h> +#include "inv_mpu_iio.h" + +int inv_reset_fifo(struct iio_dev *indio_dev) +{ + int result; + u8 d; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + /* disable interrupt */ + result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + if (result) { + dev_err(&st->client->dev, "int_enable failed %d\n", result); + return result; + } + /* disable the sensor output to FIFO */ + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); + if (result) + goto reset_fifo_fail; + /* disable fifo reading */ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); + if (result) + goto reset_fifo_fail; + + /* reset FIFO*/ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_RST); + if (result) + goto reset_fifo_fail; + /* enable interrupt */ + if (st->chip_config.accl_fifo_enable || + st->chip_config.gyro_fifo_enable) { + result = inv_mpu6050_write_reg(st, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN); + if (result) + return result; + } + /* enable FIFO reading and I2C master interface*/ + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_EN); + if (result) + goto reset_fifo_fail; + /* enable sensor output to FIFO */ + d = 0; + if (st->chip_config.gyro_fifo_enable) + d |= INV_MPU6050_BITS_GYRO_OUT; + if (st->chip_config.accl_fifo_enable) + d |= INV_MPU6050_BIT_ACCEL_OUT; + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d); + if (result) + goto reset_fifo_fail; + + return 0; + +reset_fifo_fail: + dev_err(&st->client->dev, "reset fifo failed %d\n", result); + result = inv_mpu6050_write_reg(st, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN); + + return result; +} + +static void inv_clear_kfifo(struct inv_mpu6050_state *st) +{ + unsigned long flags; + + /* take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + +/** + * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt. + */ +irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + s64 timestamp; + + timestamp = iio_get_time_ns(); + spin_lock(&st->time_stamp_lock); + kfifo_in(&st->timestamps, ×tamp, 1); + spin_unlock(&st->time_stamp_lock); + + return IRQ_WAKE_THREAD; +} + +/** + * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO. + */ +irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + size_t bytes_per_datum; + int result; + u8 data[INV_MPU6050_OUTPUT_DATA_SIZE]; + u16 fifo_count; + s64 timestamp; + u64 *tmp; + + mutex_lock(&indio_dev->mlock); + if (!(st->chip_config.accl_fifo_enable | + st->chip_config.gyro_fifo_enable)) + goto end_session; + bytes_per_datum = 0; + if (st->chip_config.accl_fifo_enable) + bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; + + if (st->chip_config.gyro_fifo_enable) + bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR; + + /* + * read fifo_count register to know how many bytes inside FIFO + * right now + */ + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->fifo_count_h, + INV_MPU6050_FIFO_COUNT_BYTE, data); + if (result != INV_MPU6050_FIFO_COUNT_BYTE) + goto end_session; + 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*/ + if (fifo_count & 1) + goto flush_fifo; + if (fifo_count > INV_MPU6050_FIFO_THRESHOLD) + goto flush_fifo; + /* Timestamp mismatch. */ + if (kfifo_len(&st->timestamps) > + fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) + goto flush_fifo; + while (fifo_count >= bytes_per_datum) { + result = i2c_smbus_read_i2c_block_data(st->client, + st->reg->fifo_r_w, + bytes_per_datum, data); + if (result != bytes_per_datum) + goto flush_fifo; + + result = kfifo_out(&st->timestamps, ×tamp, 1); + /* when there is no timestamp, put timestamp as 0 */ + if (0 == result) + timestamp = 0; + + tmp = (u64 *)data; + tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp; + result = iio_push_to_buffers(indio_dev, data); + if (result) + goto flush_fifo; + fifo_count -= bytes_per_datum; + } + +end_session: + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; + +flush_fifo: + /* Flush HW and SW FIFOs. */ + inv_reset_fifo(indio_dev); + inv_clear_kfifo(st); + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c new file mode 100644 index 000000000000..e1d0869e0ad1 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -0,0 +1,155 @@ +/* +* Copyright (C) 2012 Invensense, Inc. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include "inv_mpu_iio.h" + +static void inv_scan_query(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + st->chip_config.gyro_fifo_enable = + test_bit(INV_MPU6050_SCAN_GYRO_X, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_GYRO_Y, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_GYRO_Z, + indio_dev->active_scan_mask); + + st->chip_config.accl_fifo_enable = + test_bit(INV_MPU6050_SCAN_ACCL_X, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_ACCL_Y, + indio_dev->active_scan_mask) || + test_bit(INV_MPU6050_SCAN_ACCL_Z, + indio_dev->active_scan_mask); +} + +/** + * inv_mpu6050_set_enable() - enable chip functions. + * @indio_dev: Device driver instance. + * @enable: enable/disable + */ +static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int result; + + if (enable) { + result = inv_mpu6050_set_power_itg(st, true); + if (result) + return result; + inv_scan_query(indio_dev); + if (st->chip_config.gyro_fifo_enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + } + if (st->chip_config.accl_fifo_enable) { + result = inv_mpu6050_switch_engine(st, true, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + } + result = inv_reset_fifo(indio_dev); + if (result) + return result; + } else { + result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); + if (result) + return result; + + result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + if (result) + return result; + + result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); + if (result) + return result; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_GYRO_STBY); + if (result) + return result; + + result = inv_mpu6050_switch_engine(st, false, + INV_MPU6050_BIT_PWR_ACCL_STBY); + if (result) + return result; + result = inv_mpu6050_set_power_itg(st, false); + if (result) + return result; + } + st->chip_config.enable = enable; + + return 0; +} + +/** + * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state + * @trig: Trigger instance + * @state: Desired trigger state + */ +static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + return inv_mpu6050_set_enable(trig->private_data, state); +} + +static const struct iio_trigger_ops inv_mpu_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state, +}; + +int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc("%s-dev%d", + indio_dev->name, + indio_dev->id); + if (st->trig == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + "inv_mpu", + st->trig); + if (ret) + goto error_free_trig; + st->trig->dev.parent = &st->client->dev; + st->trig->private_data = indio_dev; + st->trig->ops = &inv_mpu_trigger_ops; + ret = iio_trigger_register(st->trig); + if (ret) + goto error_free_irq; + indio_dev->trig = st->trig; + + return 0; + +error_free_irq: + free_irq(st->client->irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); +error_ret: + return ret; +} + +void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st) +{ + iio_trigger_unregister(st->trig); + free_irq(st->client->irq, st->trig); + iio_trigger_free(st->trig); +} diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 4fe0ead84213..4d6c7d84e155 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -160,7 +160,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig) trig->use_count--; if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) - /* Missed and interrupt so launch new poll now */ + /* Missed an interrupt so launch new poll now */ iio_trigger_poll(trig, 0); } EXPORT_SYMBOL(iio_trigger_notify_done); @@ -193,7 +193,7 @@ static void iio_trigger_put_irq(struct iio_trigger *trig, int irq) * This is not currently handled. Alternative of not enabling trigger unless * the relevant function is in there may be the best option. */ -/* Worth protecting against double additions?*/ +/* Worth protecting against double additions? */ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, struct iio_poll_func *pf) { @@ -201,7 +201,7 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, bool notinuse = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); - /* Prevent the module being removed whilst attached to a trigger */ + /* Prevent the module from being removed whilst attached to a trigger */ __module_get(pf->indio_dev->info->driver_module); pf->irq = iio_trigger_get_irq(trig); ret = request_threaded_irq(pf->irq, pf->h, pf->thread, @@ -288,7 +288,7 @@ void iio_dealloc_pollfunc(struct iio_poll_func *pf) EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); /** - * iio_trigger_read_current() - trigger consumer sysfs query which trigger + * iio_trigger_read_current() - trigger consumer sysfs query current trigger * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. @@ -305,7 +305,7 @@ static ssize_t iio_trigger_read_current(struct device *dev, } /** - * iio_trigger_write_current() trigger consumer sysfs set current trigger + * iio_trigger_write_current() - trigger consumer sysfs set current trigger * * For trigger consumers the current_trigger interface allows the trigger * used for this device to be specified at run time based on the triggers @@ -476,7 +476,7 @@ void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev) { - /* Clean up and associated but not attached triggers references */ + /* Clean up an associated but not attached trigger reference */ if (indio_dev->trig) iio_trigger_put(indio_dev->trig); } diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index c42aba6817e8..b289915b8469 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -93,7 +93,8 @@ static const struct iio_chan_spec } -struct iio_channel *iio_channel_get(const char *name, const char *channel_name) +static struct iio_channel *iio_channel_get_sys(const char *name, + const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; struct iio_channel *channel; @@ -144,6 +145,14 @@ error_no_mem: iio_device_put(c->indio_dev); return ERR_PTR(err); } + +struct iio_channel *iio_channel_get(struct device *dev, + const char *channel_name) +{ + const char *name = dev ? dev_name(dev) : NULL; + + return iio_channel_get_sys(name, channel_name); +} EXPORT_SYMBOL_GPL(iio_channel_get); void iio_channel_release(struct iio_channel *channel) diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index a69fbe19fc8e..16f0d6df239f 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -21,7 +21,6 @@ #include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/trigger_consumer.h> #include <linux/iio/buffer.h> #include <linux/iio/common/st_sensors.h> diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 710b256a5a0e..e6adc4a86425 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_i2c.h> diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 94547e7d6580..51adb797cb7d 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -13,7 +13,6 @@ #include <linux/slab.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> -#include <linux/iio/trigger.h> #include <linux/iio/common/st_sensors.h> #include <linux/iio/common/st_sensors_spi.h> |