diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2016-06-10 05:30:17 -0300 |
commit | d635711daa98be86d4c7fd01499c34f566b54ccb (patch) | |
tree | aa5cc3760a27c3d57146498cb82fa549547de06c /drivers/iio/imu/inv_mpu6050 | |
parent | c91265cd0efb83778f015b4d4b1129bd2cfd075e (diff) |
Linux-libre 4.6.2-gnu
Diffstat (limited to 'drivers/iio/imu/inv_mpu6050')
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/Kconfig | 23 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/Makefile | 8 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 24 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 458 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 232 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 37 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 54 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 99 | ||||
-rw-r--r-- | drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 32 |
9 files changed, 640 insertions, 327 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig index 8f8d1370e..847455a2d 100644 --- a/drivers/iio/imu/inv_mpu6050/Kconfig +++ b/drivers/iio/imu/inv_mpu6050/Kconfig @@ -3,15 +3,30 @@ # config INV_MPU6050_IIO - tristate "Invensense MPU6050 devices" - depends on I2C && SYSFS - depends on I2C_MUX + tristate select IIO_BUFFER select IIO_TRIGGERED_BUFFER + +config INV_MPU6050_I2C + tristate "Invensense MPU6050 devices (I2C)" + depends on I2C_MUX + select INV_MPU6050_IIO + select REGMAP_I2C help This driver supports the Invensense MPU6050 devices. This driver can also support MPU6500 in MPU6050 compatibility mode and also in MPU6500 mode with some limitations. It is a gyroscope/accelerometer combo device. This driver can be built as a module. The module will be called - inv-mpu6050. + inv-mpu6050-i2c. + +config INV_MPU6050_SPI + tristate "Invensense MPU6050 devices (SPI)" + depends on SPI_MASTER + select INV_MPU6050_IIO + select REGMAP_SPI + 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-spi. diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile index f566f6a7b..734af5e6c 100644 --- a/drivers/iio/imu/inv_mpu6050/Makefile +++ b/drivers/iio/imu/inv_mpu6050/Makefile @@ -3,4 +3,10 @@ # obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o -inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o inv_mpu_acpi.o +inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o + +obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o +inv-mpu6050-i2c-objs := inv_mpu_i2c.o inv_mpu_acpi.o + +obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o +inv-mpu6050-spi-objs := inv_mpu_spi.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index 1c982a56a..2771106fd 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -66,11 +66,11 @@ static int asus_acpi_get_sensor_info(struct acpi_device *adev, union acpi_object *elem; int j; - elem = &(cpm->package.elements[i]); + elem = &cpm->package.elements[i]; for (j = 0; j < elem->package.count; ++j) { union acpi_object *sub_elem; - sub_elem = &(elem->package.elements[j]); + sub_elem = &elem->package.elements[j]; if (sub_elem->type == ACPI_TYPE_STRING) strlcpy(info->type, sub_elem->string.pointer, sizeof(info->type)); @@ -139,22 +139,23 @@ static int inv_mpu_process_acpi_config(struct i2c_client *client, return 0; } -int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) +int inv_mpu_acpi_create_mux_client(struct i2c_client *client) { + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev)); st->mux_client = NULL; - if (ACPI_HANDLE(&st->client->dev)) { + if (ACPI_HANDLE(&client->dev)) { struct i2c_board_info info; struct acpi_device *adev; int ret = -1; - adev = ACPI_COMPANION(&st->client->dev); + adev = ACPI_COMPANION(&client->dev); memset(&info, 0, sizeof(info)); dmi_check_system(inv_mpu_dev_list); switch (matched_product_name) { case INV_MPU_ASUS_T100TA: - ret = asus_acpi_get_sensor_info(adev, st->client, + ret = asus_acpi_get_sensor_info(adev, client, &info); break; /* Add more matched product processing here */ @@ -166,7 +167,7 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) /* No matching DMI, so create device on INV6XX type */ unsigned short primary, secondary; - ret = inv_mpu_process_acpi_config(st->client, &primary, + ret = inv_mpu_process_acpi_config(client, &primary, &secondary); if (!ret && secondary) { char *name; @@ -185,14 +186,15 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) st->mux_client = i2c_new_device(st->mux_adapter, &info); if (!st->mux_client) return -ENODEV; - } return 0; } -void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) +void inv_mpu_acpi_delete_mux_client(struct i2c_client *client) { + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev)); + if (st->mux_client) i2c_unregister_device(st->mux_client); } @@ -200,12 +202,12 @@ void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) #include "inv_mpu_iio.h" -int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) +int inv_mpu_acpi_create_mux_client(struct i2c_client *client) { return 0; } -void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) +void inv_mpu_acpi_delete_mux_client(struct i2c_client *client) { } #endif diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index f0e06093b..d192953e9 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -39,6 +39,26 @@ static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724}; */ static const int accel_scale[] = {598, 1196, 2392, 4785}; +static const struct inv_mpu6050_reg_map reg_set_6500 = { + .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, + .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG, + .accl_offset = INV_MPU6500_REG_ACCEL_OFFSET, + .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET, +}; + static const struct inv_mpu6050_reg_map reg_set_6050 = { .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV, .lpf = INV_MPU6050_REG_CONFIG, @@ -55,6 +75,8 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = { .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, + .accl_offset = INV_MPU6050_REG_ACCEL_OFFSET, + .gyro_offset = INV_MPU6050_REG_GYRO_OFFSET, }; static const struct inv_mpu6050_chip_config chip_config_6050 = { @@ -66,7 +88,13 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = { .accl_fs = INV_MPU6050_FS_02G, }; -static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = { +static const struct inv_mpu6050_hw hw_info[] = { + { + .num_reg = 117, + .name = "MPU6500", + .reg = ®_set_6500, + .config = &chip_config_6050, + }, { .num_reg = 117, .name = "MPU6050", @@ -75,134 +103,53 @@ static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = { }, }; -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); -} - -/* - * The i2c read/write needs to happen in unlocked mode. As the parent - * adapter is common. If we use locked versions, it will fail as - * the mux adapter will lock the parent i2c adapter, while calling - * select/deselect functions. - */ -static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st, - u8 reg, u8 d) -{ - int ret; - u8 buf[2]; - struct i2c_msg msg[1] = { - { - .addr = st->client->addr, - .flags = 0, - .len = sizeof(buf), - .buf = buf, - } - }; - - buf[0] = reg; - buf[1] = d; - ret = __i2c_transfer(st->client->adapter, msg, 1); - if (ret != 1) - return ret; - - return 0; -} - -static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv, - u32 chan_id) -{ - struct iio_dev *indio_dev = mux_priv; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - int ret = 0; - - /* Use the same mutex which was used everywhere to protect power-op */ - mutex_lock(&indio_dev->mlock); - if (!st->powerup_count) { - ret = inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1, - 0); - if (ret) - goto write_error; - - msleep(INV_MPU6050_REG_UP_TIME); - } - if (!ret) { - st->powerup_count++; - ret = inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg, - st->client->irq | - INV_MPU6050_BIT_BYPASS_EN); - } -write_error: - mutex_unlock(&indio_dev->mlock); - - return ret; -} - -static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap, - void *mux_priv, u32 chan_id) -{ - struct iio_dev *indio_dev = mux_priv; - struct inv_mpu6050_state *st = iio_priv(indio_dev); - - mutex_lock(&indio_dev->mlock); - /* It doesn't really mattter, if any of the calls fails */ - inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg, - st->client->irq); - st->powerup_count--; - if (!st->powerup_count) - inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_SLEEP); - mutex_unlock(&indio_dev->mlock); - - return 0; -} - int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) { - u8 d, mgmt_1; + unsigned int 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) + /* + * 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 (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { + result = regmap_read(st->map, st->reg->pwr_mgmt_1, &mgmt_1); + if (result) 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 */ + if ((mask == INV_MPU6050_BIT_PWR_GYRO_STBY) && (!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); + result = regmap_write(st->map, 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) + result = regmap_read(st->map, st->reg->pwr_mgmt_2, &d); + if (result) return result; if (en) d &= ~mask; else d |= mask; - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d); + result = regmap_write(st->map, st->reg->pwr_mgmt_2, d); if (result) return result; if (en) { /* Wait for output stabilize */ msleep(INV_MPU6050_TEMP_UP_TIME); - if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) { + if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { /* switch internal clock to PLL */ mgmt_1 |= INV_CLK_PLL; - result = inv_mpu6050_write_reg(st, - st->reg->pwr_mgmt_1, mgmt_1); + result = regmap_write(st->map, + st->reg->pwr_mgmt_1, mgmt_1); if (result) return result; } @@ -218,25 +165,26 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) if (power_on) { /* Already under indio-dev->mlock mutex */ if (!st->powerup_count) - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, - 0); + result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); if (!result) st->powerup_count++; } else { st->powerup_count--; if (!st->powerup_count) - result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, - INV_MPU6050_BIT_SLEEP); + result = regmap_write(st->map, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_SLEEP); } if (result) return result; if (power_on) - msleep(INV_MPU6050_REG_UP_TIME); + usleep_range(INV_MPU6050_REG_UP_TIME_MIN, + INV_MPU6050_REG_UP_TIME_MAX); return 0; } +EXPORT_SYMBOL_GPL(inv_mpu6050_set_power_itg); /** * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. @@ -257,59 +205,73 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) 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); + result = regmap_write(st->map, st->reg->gyro_config, d); if (result) return result; d = INV_MPU6050_FILTER_20HZ; - result = inv_mpu6050_write_reg(st, st->reg->lpf, d); + result = regmap_write(st->map, 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); + result = regmap_write(st->map, 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); + result = regmap_write(st->map, 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)); + sizeof(struct inv_mpu6050_chip_config)); result = inv_mpu6050_set_power_itg(st, false); return result; } +static int inv_mpu6050_sensor_set(struct inv_mpu6050_state *st, int reg, + int axis, int val) +{ + int ind, result; + __be16 d = cpu_to_be16(val); + + ind = (axis - IIO_MOD_X) * 2; + result = regmap_bulk_write(st->map, reg + ind, (u8 *)&d, 2); + if (result) + return -EINVAL; + + return 0; +} + static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, - int axis, int *val) + 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) + result = regmap_bulk_read(st->map, reg + ind, (u8 *)&d, 2); + if (result) 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) { +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); + int ret = 0; switch (mask) { case IIO_CHAN_INFO_RAW: { - int ret, result; + int result; ret = IIO_VAL_INT; result = 0; @@ -323,16 +285,16 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_ANGL_VEL: if (!st->chip_config.gyro_fifo_enable || - !st->chip_config.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); + ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, + chan->channel2, val); if (!st->chip_config.gyro_fifo_enable || - !st->chip_config.enable) { + !st->chip_config.enable) { result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) @@ -341,16 +303,16 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, break; case IIO_ACCEL: if (!st->chip_config.accl_fifo_enable || - !st->chip_config.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); + chan->channel2, val); if (!st->chip_config.accl_fifo_enable || - !st->chip_config.enable) { + !st->chip_config.enable) { result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) @@ -360,8 +322,8 @@ static int inv_mpu6050_read_raw(struct iio_dev *indio_dev, case IIO_TEMP: /* wait for stablization */ msleep(INV_MPU6050_SENSOR_UP_TIME); - inv_mpu6050_sensor_show(st, st->reg->temperature, - IIO_MOD_X, val); + ret = inv_mpu6050_sensor_show(st, st->reg->temperature, + IIO_MOD_X, val); break; default: ret = -EINVAL; @@ -405,6 +367,20 @@ error_read_raw: default: return -EINVAL; } + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ANGL_VEL: + ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset, + chan->channel2, val); + return IIO_VAL_INT; + case IIO_ACCEL: + ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset, + chan->channel2, val); + return IIO_VAL_INT; + + default: + return -EINVAL; + } default: return -EINVAL; } @@ -418,8 +394,7 @@ static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val) for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) { if (gyro_scale_6050[i] == val) { d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, - st->reg->gyro_config, d); + result = regmap_write(st->map, st->reg->gyro_config, d); if (result) return result; @@ -448,6 +423,7 @@ static int inv_write_raw_get_fmt(struct iio_dev *indio_dev, return -EINVAL; } + static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) { int result, i; @@ -456,8 +432,7 @@ static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) { if (accel_scale[i] == val) { d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); - result = inv_mpu6050_write_reg(st, - st->reg->accl_config, d); + result = regmap_write(st->map, st->reg->accl_config, d); if (result) return result; @@ -470,16 +445,17 @@ static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) } static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) { + 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 */ + /* + * 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; @@ -502,6 +478,21 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_CALIBBIAS: + switch (chan->type) { + case IIO_ANGL_VEL: + result = inv_mpu6050_sensor_set(st, + st->reg->gyro_offset, + chan->channel2, val); + break; + case IIO_ACCEL: + result = inv_mpu6050_sensor_set(st, + st->reg->accl_offset, + chan->channel2, val); + break; + default: + result = -EINVAL; + } default: result = -EINVAL; break; @@ -537,7 +528,7 @@ static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) i++; data = d[i]; - result = inv_mpu6050_write_reg(st, st->reg->lpf, data); + result = regmap_write(st->map, st->reg->lpf, data); if (result) return result; st->chip_config.lpf = data; @@ -548,8 +539,9 @@ static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) /** * 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) +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; @@ -560,7 +552,7 @@ static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, if (kstrtoint(buf, 10, &fifo_rate)) return -EINVAL; if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || - fifo_rate > INV_MPU6050_MAX_FIFO_RATE) + fifo_rate > INV_MPU6050_MAX_FIFO_RATE) return -EINVAL; if (fifo_rate == st->chip_config.fifo_rate) return count; @@ -575,7 +567,7 @@ static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev, 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); + result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) goto fifo_rate_fail; st->chip_config.fifo_rate = fifo_rate; @@ -596,8 +588,9 @@ fifo_rate_fail: /** * 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) +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)); @@ -608,16 +601,18 @@ static ssize_t inv_fifo_rate_show(struct device *dev, * 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) +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 */ + /* + * 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; @@ -654,14 +649,15 @@ static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev, .type = _type, \ .modified = 1, \ .channel2 = _channel2, \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ .scan_index = _index, \ .scan_type = { \ .sign = 's', \ .realbits = 16, \ .storagebits = 16, \ - .shift = 0 , \ + .shift = 0, \ .endianness = IIO_BE, \ }, \ } @@ -674,7 +670,7 @@ static const struct iio_chan_spec inv_mpu_channels[] = { */ { .type = IIO_TEMP, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), .scan_index = -1, @@ -727,25 +723,25 @@ static const struct iio_info mpu_info = { /** * 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) +static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) { 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); + result = regmap_write(st->map, 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 */ + /* + * 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; @@ -754,65 +750,59 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st, return result; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_ACCL_STBY); + INV_MPU6050_BIT_PWR_ACCL_STBY); if (result) return result; result = inv_mpu6050_switch_engine(st, false, - INV_MPU6050_BIT_PWR_GYRO_STBY); + 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) +int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, + int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type) { struct inv_mpu6050_state *st; struct iio_dev *indio_dev; struct inv_mpu6050_platform_data *pdata; + struct device *dev = regmap_get_device(regmap); int result; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENOSYS; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); - st->client = client; + st->chip_type = chip_type; st->powerup_count = 0; - pdata = dev_get_platdata(&client->dev); + st->irq = irq; + st->map = regmap; + pdata = dev_get_platdata(dev); if (pdata) st->plat_data = *pdata; /* power is turned on inside check chip type*/ - result = inv_check_and_setup_chip(st, id); + 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(&client->dev, - "Could not initialize device.\n"); + dev_err(dev, "Could not initialize device.\n"); return result; } - i2c_set_clientdata(client, indio_dev); - indio_dev->dev.parent = &client->dev; - /* id will be NULL when enumerated via ACPI */ - if (id) - indio_dev->name = (char *)id->name; + dev_set_drvdata(dev, indio_dev); + indio_dev->dev.parent = dev; + /* name will be NULL when enumerated via ACPI */ + if (name) + indio_dev->name = name; else - indio_dev->name = (char *)dev_name(&client->dev); + indio_dev->name = dev_name(dev); indio_dev->channels = inv_mpu_channels; indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); @@ -824,13 +814,12 @@ static int inv_mpu_probe(struct i2c_client *client, inv_mpu6050_read_fifo, NULL); if (result) { - dev_err(&st->client->dev, "configure buffer fail %d\n", - result); + dev_err(dev, "configure buffer fail %d\n", result); return result; } result = inv_mpu6050_probe_trigger(indio_dev); if (result) { - dev_err(&st->client->dev, "trigger probe fail %d\n", result); + dev_err(dev, "trigger probe fail %d\n", result); goto out_unreg_ring; } @@ -838,102 +827,47 @@ static int inv_mpu_probe(struct i2c_client *client, 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); + dev_err(dev, "IIO register fail %d\n", result); goto out_remove_trigger; } - st->mux_adapter = i2c_add_mux_adapter(client->adapter, - &client->dev, - indio_dev, - 0, 0, 0, - inv_mpu6050_select_bypass, - inv_mpu6050_deselect_bypass); - if (!st->mux_adapter) { - result = -ENODEV; - goto out_unreg_device; - } - - result = inv_mpu_acpi_create_mux_client(st); - if (result) - goto out_del_mux; - return 0; -out_del_mux: - i2c_del_mux_adapter(st->mux_adapter); -out_unreg_device: - iio_device_unregister(indio_dev); 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); -static int inv_mpu_remove(struct i2c_client *client) +int inv_mpu_core_remove(struct device *dev) { - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct inv_mpu6050_state *st = iio_priv(indio_dev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); - inv_mpu_acpi_delete_mux_client(st); - i2c_del_mux_adapter(st->mux_adapter); iio_device_unregister(indio_dev); - inv_mpu6050_remove_trigger(st); + 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) { - return inv_mpu6050_set_power_itg( - iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true); + return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(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); + return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(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}, - {"mpu6500", INV_MPU6500}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, inv_mpu_id); - -static const struct acpi_device_id inv_acpi_match[] = { - {"INVN6500", 0}, - { }, -}; - -MODULE_DEVICE_TABLE(acpi, inv_acpi_match); - -static struct i2c_driver inv_mpu_driver = { - .probe = inv_mpu_probe, - .remove = inv_mpu_remove, - .id_table = inv_mpu_id, - .driver = { - .name = "inv-mpu6050", - .pm = INV_MPU6050_PMOPS, - .acpi_match_table = ACPI_PTR(inv_acpi_match), - }, -}; - -module_i2c_driver(inv_mpu_driver); +SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); +EXPORT_SYMBOL_GPL(inv_mpu_pmops); MODULE_AUTHOR("Invensense Corporation"); MODULE_DESCRIPTION("Invensense device MPU6050 driver"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c new file mode 100644 index 000000000..5ee4e0dc0 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -0,0 +1,232 @@ +/* +* 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/acpi.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/i2c-mux.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include "inv_mpu_iio.h" + +static const struct regmap_config inv_mpu_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +/* + * The i2c read/write needs to happen in unlocked mode. As the parent + * adapter is common. If we use locked versions, it will fail as + * the mux adapter will lock the parent i2c adapter, while calling + * select/deselect functions. + */ +static int inv_mpu6050_write_reg_unlocked(struct i2c_client *client, + u8 reg, u8 d) +{ + int ret; + u8 buf[2] = {reg, d}; + struct i2c_msg msg[1] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + } + }; + + ret = __i2c_transfer(client->adapter, msg, 1); + if (ret != 1) + return ret; + + return 0; +} + +static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv, + u32 chan_id) +{ + struct i2c_client *client = mux_priv; + struct iio_dev *indio_dev = dev_get_drvdata(&client->dev); + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int ret = 0; + + /* Use the same mutex which was used everywhere to protect power-op */ + mutex_lock(&indio_dev->mlock); + if (!st->powerup_count) { + ret = inv_mpu6050_write_reg_unlocked(client, + 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 = inv_mpu6050_write_reg_unlocked(client, + st->reg->int_pin_cfg, + INV_MPU6050_INT_PIN_CFG | + INV_MPU6050_BIT_BYPASS_EN); + } +write_error: + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap, + void *mux_priv, u32 chan_id) +{ + struct i2c_client *client = mux_priv; + struct iio_dev *indio_dev = dev_get_drvdata(&client->dev); + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + mutex_lock(&indio_dev->mlock); + /* It doesn't really mattter, if any of the calls fails */ + inv_mpu6050_write_reg_unlocked(client, st->reg->int_pin_cfg, + INV_MPU6050_INT_PIN_CFG); + st->powerup_count--; + if (!st->powerup_count) + inv_mpu6050_write_reg_unlocked(client, st->reg->pwr_mgmt_1, + INV_MPU6050_BIT_SLEEP); + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +static const char *inv_mpu_match_acpi_device(struct device *dev, int *chip_id) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return NULL; + + *chip_id = (int)id->driver_data; + + return dev_name(dev); +} + +/** + * 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; + int result, chip_type; + struct regmap *regmap; + const char *name; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -EOPNOTSUPP; + + if (id) { + chip_type = (int)id->driver_data; + name = id->name; + } else if (ACPI_HANDLE(&client->dev)) { + name = inv_mpu_match_acpi_device(&client->dev, &chip_type); + if (!name) + return -ENODEV; + } else { + return -ENOSYS; + } + + regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + result = inv_mpu_core_probe(regmap, client->irq, name, + NULL, chip_type); + if (result < 0) + return result; + + st = iio_priv(dev_get_drvdata(&client->dev)); + st->mux_adapter = i2c_add_mux_adapter(client->adapter, + &client->dev, + client, + 0, 0, 0, + inv_mpu6050_select_bypass, + inv_mpu6050_deselect_bypass); + if (!st->mux_adapter) { + result = -ENODEV; + goto out_unreg_device; + } + + result = inv_mpu_acpi_create_mux_client(client); + if (result) + goto out_del_mux; + + return 0; + +out_del_mux: + i2c_del_mux_adapter(st->mux_adapter); +out_unreg_device: + inv_mpu_core_remove(&client->dev); + 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); + + inv_mpu_acpi_delete_mux_client(client); + i2c_del_mux_adapter(st->mux_adapter); + + return inv_mpu_core_remove(&client->dev); +} + +/* + * 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}, + {"mpu6500", INV_MPU6500}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, inv_mpu_id); + +static const struct acpi_device_id inv_acpi_match[] = { + {"INVN6500", 0}, + { }, +}; + +MODULE_DEVICE_TABLE(acpi, inv_acpi_match); + +static struct i2c_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), + .name = "inv-mpu6050-i2c", + .pm = &inv_mpu_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 index db0a4a275..e302a4970 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -15,6 +15,7 @@ #include <linux/spinlock.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/regmap.h> #include <linux/iio/sysfs.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/trigger.h> @@ -38,6 +39,9 @@ * @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. + * @int_pin_cfg; Controls interrupt pin configuration. + * @accl_offset: Controls the accelerometer calibration offset. + * @gyro_offset: Controls the gyroscope calibration offset. */ struct inv_mpu6050_reg_map { u8 sample_rate_div; @@ -55,12 +59,15 @@ struct inv_mpu6050_reg_map { u8 pwr_mgmt_1; u8 pwr_mgmt_2; u8 int_pin_cfg; + u8 accl_offset; + u8 gyro_offset; }; /*device enum */ enum inv_devices { INV_MPU6050, INV_MPU6500, + INV_MPU6000, INV_NUM_PARTS }; @@ -107,9 +114,10 @@ struct inv_mpu6050_hw { * @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. + * @map regmap pointer. + * @irq interrupt number. */ struct inv_mpu6050_state { #define TIMESTAMP_FIFO_SIZE 16 @@ -119,15 +127,19 @@ struct inv_mpu6050_state { const struct inv_mpu6050_hw *hw; enum inv_devices chip_type; spinlock_t time_stamp_lock; - struct i2c_client *client; struct i2c_adapter *mux_adapter; struct i2c_client *mux_client; unsigned int powerup_count; struct inv_mpu6050_platform_data plat_data; DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); + struct regmap *map; + int irq; }; /*register and associated bit definition*/ +#define INV_MPU6050_REG_ACCEL_OFFSET 0x06 +#define INV_MPU6050_REG_GYRO_OFFSET 0x13 + #define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19 #define INV_MPU6050_REG_CONFIG 0x1A #define INV_MPU6050_REG_GYRO_CONFIG 0x1B @@ -151,6 +163,7 @@ struct inv_mpu6050_state { #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_BIT_I2C_IF_DIS 0x10 #define INV_MPU6050_REG_PWR_MGMT_1 0x6B #define INV_MPU6050_BIT_H_RESET 0x80 @@ -167,10 +180,18 @@ struct inv_mpu6050_state { #define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 #define INV_MPU6050_FIFO_COUNT_BYTE 2 #define INV_MPU6050_FIFO_THRESHOLD 500 + +/* mpu6500 registers */ +#define INV_MPU6500_REG_ACCEL_OFFSET 0x77 + +/* delay time in milliseconds */ #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 + +/* delay time in microseconds */ +#define INV_MPU6050_REG_UP_TIME_MIN 5000 +#define INV_MPU6050_REG_UP_TIME_MAX 10000 #define INV_MPU6050_TEMP_OFFSET 12421 #define INV_MPU6050_TEMP_SCALE 2941 @@ -185,6 +206,7 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_INT_PIN_CFG 0x37 #define INV_MPU6050_BIT_BYPASS_EN 0x2 +#define INV_MPU6050_INT_PIN_CFG 0 /* init parameters */ #define INV_MPU6050_INIT_FIFO_RATE 50 @@ -252,5 +274,10 @@ 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); -int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st); -void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st); +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 ba27e2775..d0700628e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/slab.h> -#include <linux/i2c.h> #include <linux/err.h> #include <linux/delay.h> #include <linux/sysfs.h> @@ -41,23 +40,24 @@ int inv_reset_fifo(struct iio_dev *indio_dev) struct inv_mpu6050_state *st = iio_priv(indio_dev); /* disable interrupt */ - result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + result = regmap_write(st->map, st->reg->int_enable, 0); if (result) { - dev_err(&st->client->dev, "int_enable failed %d\n", result); + dev_err(regmap_get_device(st->map), "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); + result = regmap_write(st->map, 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); + result = regmap_write(st->map, 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); + result = regmap_write(st->map, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_RST); if (result) goto reset_fifo_fail; @@ -67,14 +67,14 @@ int inv_reset_fifo(struct iio_dev *indio_dev) /* 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); + result = regmap_write(st->map, 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); + result = regmap_write(st->map, st->reg->user_ctrl, + INV_MPU6050_BIT_FIFO_EN); if (result) goto reset_fifo_fail; /* enable sensor output to FIFO */ @@ -83,16 +83,16 @@ int inv_reset_fifo(struct iio_dev *indio_dev) 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); + result = regmap_write(st->map, 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); + dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result); + result = regmap_write(st->map, st->reg->int_enable, + INV_MPU6050_BIT_DATA_RDY_EN); return result; } @@ -109,7 +109,7 @@ irqreturn_t inv_mpu6050_irq_handler(int irq, void *p) timestamp = iio_get_time_ns(); kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, - &st->time_stamp_lock); + &st->time_stamp_lock); return IRQ_WAKE_THREAD; } @@ -143,10 +143,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) * 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) + result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data, + INV_MPU6050_FIFO_COUNT_BYTE); + if (result) goto end_session; fifo_count = be16_to_cpup((__be16 *)(&data[0])); if (fifo_count < bytes_per_datum) @@ -158,22 +157,21 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) goto flush_fifo; /* Timestamp mismatch. */ if (kfifo_len(&st->timestamps) > - fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR) - goto flush_fifo; + 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) + result = regmap_bulk_read(st->map, st->reg->fifo_r_w, + data, bytes_per_datum); + if (result) goto flush_fifo; result = kfifo_out(&st->timestamps, ×tamp, 1); /* when there is no timestamp, put timestamp as 0 */ - if (0 == result) + if (result == 0) timestamp = 0; result = iio_push_to_buffers_with_timestamp(indio_dev, data, - timestamp); + timestamp); if (result) goto flush_fifo; fifo_count -= bytes_per_datum; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c new file mode 100644 index 000000000..7bcb8d839 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -0,0 +1,99 @@ +/* +* Copyright (C) 2015 Intel Corporation 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/acpi.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/iio/iio.h> +#include "inv_mpu_iio.h" + +static const struct regmap_config inv_mpu_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int inv_mpu_i2c_disable(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int ret = 0; + + ret = inv_mpu6050_set_power_itg(st, true); + if (ret) + return ret; + + ret = regmap_write(st->map, INV_MPU6050_REG_USER_CTRL, + INV_MPU6050_BIT_I2C_IF_DIS); + if (ret) { + inv_mpu6050_set_power_itg(st, false); + return ret; + } + + return inv_mpu6050_set_power_itg(st, false); +} + +static int inv_mpu_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const struct spi_device_id *id = spi_get_device_id(spi); + const char *name = id ? id->name : NULL; + const int chip_type = id ? id->driver_data : 0; + + regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return inv_mpu_core_probe(regmap, spi->irq, name, + 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 + */ +static const struct spi_device_id inv_mpu_id[] = { + {"mpu6000", INV_MPU6000}, + {} +}; + +MODULE_DEVICE_TABLE(spi, inv_mpu_id); + +static const struct acpi_device_id inv_acpi_match[] = { + {"INVN6000", 0}, + { }, +}; +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), + .name = "inv-mpu6000-spi", + .pm = &inv_mpu_pmops, + }, +}; + +module_spi_driver(inv_mpu_driver); + +MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>"); +MODULE_DESCRIPTION("Invensense device MPU6000 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index 844610c3a..e8818d4dd 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -19,19 +19,19 @@ static void inv_scan_query(struct iio_dev *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); + 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); + 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); } /** @@ -65,15 +65,15 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) if (result) return result; } else { - result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0); + result = regmap_write(st->map, st->reg->fifo_en, 0); if (result) return result; - result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0); + result = regmap_write(st->map, st->reg->int_enable, 0); if (result) return result; - result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0); + result = regmap_write(st->map, st->reg->user_ctrl, 0); if (result) return result; @@ -101,7 +101,7 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) * @state: Desired trigger state */ static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) + bool state) { return inv_mpu6050_set_enable(iio_trigger_get_drvdata(trig), state); } @@ -123,7 +123,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) if (!st->trig) return -ENOMEM; - ret = devm_request_irq(&indio_dev->dev, st->client->irq, + ret = devm_request_irq(&indio_dev->dev, st->irq, &iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, "inv_mpu", @@ -131,7 +131,7 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev) if (ret) return ret; - st->trig->dev.parent = &st->client->dev; + st->trig->dev.parent = regmap_get_device(st->map); st->trig->ops = &inv_mpu_trigger_ops; iio_trigger_set_drvdata(st->trig, indio_dev); |