From: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
To: Srinivas Pandruvada
<srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v3] iio: imu: inv_mpu6050: Add i2c mux for by pass
Date: Sat, 06 Dec 2014 11:01:28 +0000 [thread overview]
Message-ID: <5482E208.6030905@kernel.org> (raw)
In-Reply-To: <1417819929-27730-2-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
On 05/12/14 22:52, Srinivas Pandruvada wrote:
> This chip allows some limited number of sensors connected to it as
> slaves, which can be directly accessed by register interface of this
> driver.But the current upstream driver doesn't support such mode.
> To attach such slaves to main processor i2c bus, chip has to be set
> up in bypass mode. This change adds i2c mux, which will enable/disable
> this mode for transaction to/from such slave devices.
> This was discussed for a while in mailing list, this was the outcome:
> Reference:
> http://www.spinics.net/lists/linux-iio/msg12126.html
> http://comments.gmane.org/gmane.linux.kernel.iio/11470
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Reviewed-by: Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>
Applied to the togreg branch of IIO.git
Thanks,
>
> ---
> drivers/iio/imu/inv_mpu6050/Kconfig | 1 +
> drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 115 +++++++++++++++++++++++++++--
> drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 6 ++
> 3 files changed, 116 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
> index 2d0608b..48fbc0b 100644
> --- a/drivers/iio/imu/inv_mpu6050/Kconfig
> +++ b/drivers/iio/imu/inv_mpu6050/Kconfig
> @@ -7,6 +7,7 @@ config INV_MPU6050_IIO
> depends on I2C && SYSFS
> select IIO_BUFFER
> select IIO_TRIGGERED_BUFFER
> + select I2C_MUX
> help
> This driver supports the Invensense MPU6050 devices.
> This driver can also support MPU6500 in MPU6050 compatibility mode
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> index b75519d..6d2c115 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> @@ -23,6 +23,7 @@
> #include <linux/kfifo.h>
> #include <linux/spinlock.h>
> #include <linux/iio/iio.h>
> +#include <linux/i2c-mux.h>
> #include "inv_mpu_iio.h"
>
> /*
> @@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
> .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,
> };
>
> static const struct inv_mpu6050_chip_config chip_config_6050 = {
> @@ -77,6 +79,83 @@ 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;
> @@ -133,13 +212,22 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
>
> int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
> {
> - int result;
> + int result = 0;
> +
> + 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);
> + 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);
> + }
>
> - 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;
>
> @@ -673,6 +761,7 @@ static int inv_mpu_probe(struct i2c_client *client,
>
> st = iio_priv(indio_dev);
> st->client = client;
> + st->powerup_count = 0;
> pdata = dev_get_platdata(&client->dev);
> if (pdata)
> st->plat_data = *pdata;
> @@ -720,8 +809,21 @@ static int inv_mpu_probe(struct i2c_client *client,
> 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;
> + }
> +
> return 0;
>
> +out_unreg_device:
> + iio_device_unregister(indio_dev);
> out_remove_trigger:
> inv_mpu6050_remove_trigger(st);
> out_unreg_ring:
> @@ -734,6 +836,7 @@ 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);
>
> + i2c_del_mux_adapter(st->mux_adapter);
> iio_device_unregister(indio_dev);
> inv_mpu6050_remove_trigger(st);
> iio_triggered_buffer_cleanup(indio_dev);
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index e779931..aa837de 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -54,6 +54,7 @@ struct inv_mpu6050_reg_map {
> u8 int_enable;
> u8 pwr_mgmt_1;
> u8 pwr_mgmt_2;
> + u8 int_pin_cfg;
> };
>
> /*device enum */
> @@ -119,6 +120,8 @@ struct inv_mpu6050_state {
> enum inv_devices chip_type;
> spinlock_t time_stamp_lock;
> struct i2c_client *client;
> + struct i2c_adapter *mux_adapter;
> + unsigned int powerup_count;
> struct inv_mpu6050_platform_data plat_data;
> DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
> };
> @@ -179,6 +182,9 @@ struct inv_mpu6050_state {
> /* 6 + 6 round up and plus 8 */
> #define INV_MPU6050_OUTPUT_DATA_SIZE 24
>
> +#define INV_MPU6050_REG_INT_PIN_CFG 0x37
> +#define INV_MPU6050_BIT_BYPASS_EN 0x2
> +
> /* init parameters */
> #define INV_MPU6050_INIT_FIFO_RATE 50
> #define INV_MPU6050_TIME_STAMP_TOR 5
>
WARNING: multiple messages have this Message-ID (diff)
From: Jonathan Cameron <jic23@kernel.org>
To: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>,
wsa@the-dreams.de
Cc: linux-iio@vger.kernel.org, linux-i2c@vger.kernel.org
Subject: Re: [PATCH v3] iio: imu: inv_mpu6050: Add i2c mux for by pass
Date: Sat, 06 Dec 2014 11:01:28 +0000 [thread overview]
Message-ID: <5482E208.6030905@kernel.org> (raw)
In-Reply-To: <1417819929-27730-2-git-send-email-srinivas.pandruvada@linux.intel.com>
On 05/12/14 22:52, Srinivas Pandruvada wrote:
> This chip allows some limited number of sensors connected to it as
> slaves, which can be directly accessed by register interface of this
> driver.But the current upstream driver doesn't support such mode.
> To attach such slaves to main processor i2c bus, chip has to be set
> up in bypass mode. This change adds i2c mux, which will enable/disable
> this mode for transaction to/from such slave devices.
> This was discussed for a while in mailing list, this was the outcome:
> Reference:
> http://www.spinics.net/lists/linux-iio/msg12126.html
> http://comments.gmane.org/gmane.linux.kernel.iio/11470
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
> Reviewed-by: Wolfram Sang <wsa@the-dreams.de>
Applied to the togreg branch of IIO.git
Thanks,
>
> ---
> drivers/iio/imu/inv_mpu6050/Kconfig | 1 +
> drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 115 +++++++++++++++++++++++++++--
> drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 6 ++
> 3 files changed, 116 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
> index 2d0608b..48fbc0b 100644
> --- a/drivers/iio/imu/inv_mpu6050/Kconfig
> +++ b/drivers/iio/imu/inv_mpu6050/Kconfig
> @@ -7,6 +7,7 @@ config INV_MPU6050_IIO
> depends on I2C && SYSFS
> select IIO_BUFFER
> select IIO_TRIGGERED_BUFFER
> + select I2C_MUX
> help
> This driver supports the Invensense MPU6050 devices.
> This driver can also support MPU6500 in MPU6050 compatibility mode
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> index b75519d..6d2c115 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> @@ -23,6 +23,7 @@
> #include <linux/kfifo.h>
> #include <linux/spinlock.h>
> #include <linux/iio/iio.h>
> +#include <linux/i2c-mux.h>
> #include "inv_mpu_iio.h"
>
> /*
> @@ -52,6 +53,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
> .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,
> };
>
> static const struct inv_mpu6050_chip_config chip_config_6050 = {
> @@ -77,6 +79,83 @@ 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;
> @@ -133,13 +212,22 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
>
> int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
> {
> - int result;
> + int result = 0;
> +
> + 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);
> + 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);
> + }
>
> - 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;
>
> @@ -673,6 +761,7 @@ static int inv_mpu_probe(struct i2c_client *client,
>
> st = iio_priv(indio_dev);
> st->client = client;
> + st->powerup_count = 0;
> pdata = dev_get_platdata(&client->dev);
> if (pdata)
> st->plat_data = *pdata;
> @@ -720,8 +809,21 @@ static int inv_mpu_probe(struct i2c_client *client,
> 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;
> + }
> +
> return 0;
>
> +out_unreg_device:
> + iio_device_unregister(indio_dev);
> out_remove_trigger:
> inv_mpu6050_remove_trigger(st);
> out_unreg_ring:
> @@ -734,6 +836,7 @@ 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);
>
> + i2c_del_mux_adapter(st->mux_adapter);
> iio_device_unregister(indio_dev);
> inv_mpu6050_remove_trigger(st);
> iio_triggered_buffer_cleanup(indio_dev);
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index e779931..aa837de 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -54,6 +54,7 @@ struct inv_mpu6050_reg_map {
> u8 int_enable;
> u8 pwr_mgmt_1;
> u8 pwr_mgmt_2;
> + u8 int_pin_cfg;
> };
>
> /*device enum */
> @@ -119,6 +120,8 @@ struct inv_mpu6050_state {
> enum inv_devices chip_type;
> spinlock_t time_stamp_lock;
> struct i2c_client *client;
> + struct i2c_adapter *mux_adapter;
> + unsigned int powerup_count;
> struct inv_mpu6050_platform_data plat_data;
> DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
> };
> @@ -179,6 +182,9 @@ struct inv_mpu6050_state {
> /* 6 + 6 round up and plus 8 */
> #define INV_MPU6050_OUTPUT_DATA_SIZE 24
>
> +#define INV_MPU6050_REG_INT_PIN_CFG 0x37
> +#define INV_MPU6050_BIT_BYPASS_EN 0x2
> +
> /* init parameters */
> #define INV_MPU6050_INIT_FIFO_RATE 50
> #define INV_MPU6050_TIME_STAMP_TOR 5
>
next prev parent reply other threads:[~2014-12-06 11:01 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-05 22:52 [PATCH v3] iio: imu: inv_mpu6050: Add i2c mux for by pass Srinivas Pandruvada
2014-12-05 22:52 ` Srinivas Pandruvada
[not found] ` <1417819929-27730-1-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-12-05 22:52 ` Srinivas Pandruvada
2014-12-05 22:52 ` Srinivas Pandruvada
[not found] ` <1417819929-27730-2-git-send-email-srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-12-06 11:01 ` Jonathan Cameron [this message]
2014-12-06 11:01 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5482E208.6030905@kernel.org \
--to=jic23-dgejt+ai2ygdnm+yrofe0a@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=srinivas.pandruvada-VuQAYsv1563Yd54FQh9/CA@public.gmane.org \
--cc=wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.