Linux IIO development
 help / color / mirror / Atom feed
* [PATCH v2 0/1] iio: proximity: lidar: optimize i2c transactions
@ 2015-12-01  2:16 Matt Ranostay
  2015-12-01  2:16 ` [PATCH v2 1/1] " Matt Ranostay
  0 siblings, 1 reply; 3+ messages in thread
From: Matt Ranostay @ 2015-12-01  2:16 UTC (permalink / raw)
  To: linux-iio, jic23; +Cc: Matt Ranostay

Changes from v1:
* allow smbus method as fallback if i2c mode isn't possible

Matt Ranostay (1):
  iio: proximity: lidar: optimize i2c transactions

 drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 95 +++++++++++++++++------
 1 file changed, 70 insertions(+), 25 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/1] iio: proximity: lidar: optimize i2c transactions
  2015-12-01  2:16 [PATCH v2 0/1] iio: proximity: lidar: optimize i2c transactions Matt Ranostay
@ 2015-12-01  2:16 ` Matt Ranostay
  2015-12-02  5:00   ` Matt Ranostay
  0 siblings, 1 reply; 3+ messages in thread
From: Matt Ranostay @ 2015-12-01  2:16 UTC (permalink / raw)
  To: linux-iio, jic23; +Cc: Matt Ranostay

Optimize device tranactions using i2c transfers versus multiple
possibly racey i2c_smbus_* function calls, and only one transaction
for distance measurement. Falls back to smbus method if i2c
functionality isn't available.

Signed-off-by: Matt Ranostay <mranostay@gmail.com>
---
 drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 95 +++++++++++++++++------
 1 file changed, 70 insertions(+), 25 deletions(-)

diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 32f24f1..1cdcc5a 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -36,8 +36,10 @@
 #define LIDAR_REG_STATUS_INVALID	BIT(3)
 #define LIDAR_REG_STATUS_READY		BIT(0)
 
-#define LIDAR_REG_DATA_HBYTE	0x0f
-#define LIDAR_REG_DATA_LBYTE	0x10
+#define LIDAR_REG_DATA_HBYTE		0x0f
+#define LIDAR_REG_DATA_LBYTE		0x10
+#define LIDAR_REG_DATA_WORD_READ	BIT(7)
+
 #define LIDAR_REG_PWR_CONTROL	0x65
 
 #define LIDAR_DRV_NAME "lidar"
@@ -46,6 +48,9 @@ struct lidar_data {
 	struct iio_dev *indio_dev;
 	struct i2c_client *client;
 
+	int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
+	int i2c_enabled;
+
 	u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
 };
 
@@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(1),
 };
 
-static int lidar_read_byte(struct lidar_data *data, int reg)
+static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
+{
+	struct i2c_client *client = data->client;
+	struct i2c_msg msg[2];
+	int ret;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = client->flags | I2C_M_STOP;
+	msg[0].len = 1;
+	msg[0].buf  = (char *) &reg;
+
+	msg[1].addr = client->addr;
+	msg[1].flags = client->flags | I2C_M_RD;
+	msg[1].len = len;
+	msg[1].buf = (char *) val;
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+
+	return (ret == len) ? 0 : ret;
+}
+
+static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
 {
 	struct i2c_client *client = data->client;
 	int ret;
@@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
 	 * so in turn i2c_smbus_read_byte_data cannot be used
 	 */
 
-	ret = i2c_smbus_write_byte(client, reg);
-	if (ret < 0) {
-		dev_err(&client->dev, "cannot write addr value");
-		return ret;
+	while (len--) {
+		ret = i2c_smbus_write_byte(client, reg++);
+		if (ret < 0) {
+			dev_err(&client->dev, "cannot write addr value");
+			return ret;
+		}
+
+		ret = i2c_smbus_read_byte(client);
+		if (ret < 0) {
+			dev_err(&client->dev, "cannot read data value");
+			return ret;
+		}
+
+		*(val++) = ret;
 	}
 
-	ret = i2c_smbus_read_byte(client);
+	return 0;
+}
+
+static int lidar_read_byte(struct lidar_data *data, u8 reg)
+{
+	int ret;
+	u8 val;
+
+	ret = data->xfer(data, reg, &val, 1);
 	if (ret < 0)
-		dev_err(&client->dev, "cannot read data value");
+		return ret;
 
-	return ret;
+	return val;
 }
 
 static inline int lidar_write_control(struct lidar_data *data, int val)
@@ -100,22 +144,14 @@ static inline int lidar_write_power(struct lidar_data *data, int val)
 
 static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
 {
-	int ret;
-	int val;
-
-	ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
-	if (ret < 0)
-		return ret;
-	val = ret << 8;
+	int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
+			(data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
+			(u8 *) reg, 2);
 
-	ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
-	if (ret < 0)
-		return ret;
+	if (!ret)
+		*reg = be16_to_cpu(*reg);
 
-	val |= ret;
-	*reg = val;
-
-	return 0;
+	return ret;
 }
 
 static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
@@ -237,6 +273,16 @@ static int lidar_probe(struct i2c_client *client,
 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 	if (!indio_dev)
 		return -ENOMEM;
+	data = iio_priv(indio_dev);
+
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		data->xfer = lidar_i2c_xfer;
+		data->i2c_enabled = 1;
+	} else if (i2c_check_functionality(client->adapter,
+				I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
+		data->xfer = lidar_smbus_xfer;
+	else
+		return -ENOTSUPP;
 
 	indio_dev->info = &lidar_info;
 	indio_dev->name = LIDAR_DRV_NAME;
@@ -244,7 +290,6 @@ static int lidar_probe(struct i2c_client *client,
 	indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
-	data = iio_priv(indio_dev);
 	i2c_set_clientdata(client, indio_dev);
 
 	data->client = client;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2 1/1] iio: proximity: lidar: optimize i2c transactions
  2015-12-01  2:16 ` [PATCH v2 1/1] " Matt Ranostay
@ 2015-12-02  5:00   ` Matt Ranostay
  0 siblings, 0 replies; 3+ messages in thread
From: Matt Ranostay @ 2015-12-02  5:00 UTC (permalink / raw)
  To: linux-iio@vger.kernel.org, Jonathan Cameron; +Cc: Matt Ranostay

Please ignore version... there is an issue within this patchset with
the i2c_transfer return check.

On Mon, Nov 30, 2015 at 6:16 PM, Matt Ranostay <mranostay@gmail.com> wrote:
> Optimize device tranactions using i2c transfers versus multiple
> possibly racey i2c_smbus_* function calls, and only one transaction
> for distance measurement. Falls back to smbus method if i2c
> functionality isn't available.
>
> Signed-off-by: Matt Ranostay <mranostay@gmail.com>
> ---
>  drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 95 +++++++++++++++++------
>  1 file changed, 70 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
> index 32f24f1..1cdcc5a 100644
> --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
> +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
> @@ -36,8 +36,10 @@
>  #define LIDAR_REG_STATUS_INVALID       BIT(3)
>  #define LIDAR_REG_STATUS_READY         BIT(0)
>
> -#define LIDAR_REG_DATA_HBYTE   0x0f
> -#define LIDAR_REG_DATA_LBYTE   0x10
> +#define LIDAR_REG_DATA_HBYTE           0x0f
> +#define LIDAR_REG_DATA_LBYTE           0x10
> +#define LIDAR_REG_DATA_WORD_READ       BIT(7)
> +
>  #define LIDAR_REG_PWR_CONTROL  0x65
>
>  #define LIDAR_DRV_NAME "lidar"
> @@ -46,6 +48,9 @@ struct lidar_data {
>         struct iio_dev *indio_dev;
>         struct i2c_client *client;
>
> +       int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
> +       int i2c_enabled;
> +
>         u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
>  };
>
> @@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
>         IIO_CHAN_SOFT_TIMESTAMP(1),
>  };
>
> -static int lidar_read_byte(struct lidar_data *data, int reg)
> +static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
> +{
> +       struct i2c_client *client = data->client;
> +       struct i2c_msg msg[2];
> +       int ret;
> +
> +       msg[0].addr = client->addr;
> +       msg[0].flags = client->flags | I2C_M_STOP;
> +       msg[0].len = 1;
> +       msg[0].buf  = (char *) &reg;
> +
> +       msg[1].addr = client->addr;
> +       msg[1].flags = client->flags | I2C_M_RD;
> +       msg[1].len = len;
> +       msg[1].buf = (char *) val;
> +
> +       ret = i2c_transfer(client->adapter, msg, 2);
> +
> +       return (ret == len) ? 0 : ret;
> +}
> +
> +static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
>  {
>         struct i2c_client *client = data->client;
>         int ret;
> @@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
>          * so in turn i2c_smbus_read_byte_data cannot be used
>          */
>
> -       ret = i2c_smbus_write_byte(client, reg);
> -       if (ret < 0) {
> -               dev_err(&client->dev, "cannot write addr value");
> -               return ret;
> +       while (len--) {
> +               ret = i2c_smbus_write_byte(client, reg++);
> +               if (ret < 0) {
> +                       dev_err(&client->dev, "cannot write addr value");
> +                       return ret;
> +               }
> +
> +               ret = i2c_smbus_read_byte(client);
> +               if (ret < 0) {
> +                       dev_err(&client->dev, "cannot read data value");
> +                       return ret;
> +               }
> +
> +               *(val++) = ret;
>         }
>
> -       ret = i2c_smbus_read_byte(client);
> +       return 0;
> +}
> +
> +static int lidar_read_byte(struct lidar_data *data, u8 reg)
> +{
> +       int ret;
> +       u8 val;
> +
> +       ret = data->xfer(data, reg, &val, 1);
>         if (ret < 0)
> -               dev_err(&client->dev, "cannot read data value");
> +               return ret;
>
> -       return ret;
> +       return val;
>  }
>
>  static inline int lidar_write_control(struct lidar_data *data, int val)
> @@ -100,22 +144,14 @@ static inline int lidar_write_power(struct lidar_data *data, int val)
>
>  static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
>  {
> -       int ret;
> -       int val;
> -
> -       ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
> -       if (ret < 0)
> -               return ret;
> -       val = ret << 8;
> +       int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
> +                       (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
> +                       (u8 *) reg, 2);
>
> -       ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
> -       if (ret < 0)
> -               return ret;
> +       if (!ret)
> +               *reg = be16_to_cpu(*reg);
>
> -       val |= ret;
> -       *reg = val;
> -
> -       return 0;
> +       return ret;
>  }
>
>  static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
> @@ -237,6 +273,16 @@ static int lidar_probe(struct i2c_client *client,
>         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
>         if (!indio_dev)
>                 return -ENOMEM;
> +       data = iio_priv(indio_dev);
> +
> +       if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +               data->xfer = lidar_i2c_xfer;
> +               data->i2c_enabled = 1;
> +       } else if (i2c_check_functionality(client->adapter,
> +                               I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
> +               data->xfer = lidar_smbus_xfer;
> +       else
> +               return -ENOTSUPP;
>
>         indio_dev->info = &lidar_info;
>         indio_dev->name = LIDAR_DRV_NAME;
> @@ -244,7 +290,6 @@ static int lidar_probe(struct i2c_client *client,
>         indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
>         indio_dev->modes = INDIO_DIRECT_MODE;
>
> -       data = iio_priv(indio_dev);
>         i2c_set_clientdata(client, indio_dev);
>
>         data->client = client;
> --
> 1.9.1
>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-12-02  5:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-01  2:16 [PATCH v2 0/1] iio: proximity: lidar: optimize i2c transactions Matt Ranostay
2015-12-01  2:16 ` [PATCH v2 1/1] " Matt Ranostay
2015-12-02  5:00   ` Matt Ranostay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox