Skip to content

Commit

Permalink
iio: imu: inv_mpu6050: Separate driver into core and i2c functionality.
Browse files Browse the repository at this point in the history
Separate this driver into core and i2c functionality.
This is in preparation for adding spi support.

Signed-off-by: Adriana Reus <adriana.reus@intel.com>
Reviewed-by: Lucas De Marchi <lucas.demarchi@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
  • Loading branch information
Adriana Reus authored and Jonathan Cameron committed Feb 13, 2016
1 parent d430f3c commit b3eea8d
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 203 deletions.
10 changes: 7 additions & 3 deletions drivers/iio/imu/inv_mpu6050/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
#

config INV_MPU6050_IIO
tristate "Invensense MPU6050 devices"
depends on I2C && SYSFS
tristate
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER

config INV_MPU6050_I2C
tristate "Invensense MPU6050 devices (I2C)"
depends on I2C
select INV_MPU6050_IIO
select I2C_MUX
select REGMAP_I2C
help
Expand All @@ -15,4 +19,4 @@ config INV_MPU6050_IIO
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.
5 changes: 4 additions & 1 deletion drivers/iio/imu/inv_mpu6050/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
#

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
18 changes: 10 additions & 8 deletions drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -191,21 +192,22 @@ int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st)
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);
}
#else

#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
208 changes: 25 additions & 183 deletions drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@
#include <linux/acpi.h>
#include "inv_mpu_iio.h"

static const struct regmap_config inv_mpu_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};

/*
* this is the gyro scale translated from dynamic range plus/minus
* {250, 500, 1000, 2000} to rad/s
Expand Down Expand Up @@ -80,83 +75,6 @@ static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = {
},
};

/*
* 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,
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 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,
INV_MPU6050_INT_PIN_CFG);
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)
{
unsigned int d, mgmt_1;
Expand Down Expand Up @@ -758,42 +676,23 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
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)
{
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;
struct regmap *regmap;

if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK))
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);
}

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->powerup_count = 0;
st->irq = irq;
st->map = regmap;
pdata = dev_get_platdata(&client->dev);
pdata = dev_get_platdata(dev);
if (pdata)
st->plat_data = *pdata;
/* power is turned on inside check chip type*/
Expand All @@ -803,18 +702,17 @@ static int inv_mpu_probe(struct i2c_client *client,

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);

Expand All @@ -826,116 +724,60 @@ 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;
}

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);
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");
Expand Down
Loading

0 comments on commit b3eea8d

Please sign in to comment.