linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/1] iio: proximity: lidar: optimize i2c transactions
@ 2015-12-02  5:05 Matt Ranostay
  2015-12-02  5:05 ` [PATCH v3 1/] " Matt Ranostay
  0 siblings, 1 reply; 3+ messages in thread
From: Matt Ranostay @ 2015-12-02  5:05 UTC (permalink / raw)
  To: linux-iio, jic23; +Cc: Matt Ranostay

Changes from v2:
* change incorrect i2c_transfer function return check from message length
  to messages executed

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 v3 1/] iio: proximity: lidar: optimize i2c transactions
  2015-12-02  5:05 [PATCH v3 0/1] iio: proximity: lidar: optimize i2c transactions Matt Ranostay
@ 2015-12-02  5:05 ` Matt Ranostay
  2015-12-05 16:50   ` Jonathan Cameron
  0 siblings, 1 reply; 3+ messages in thread
From: Matt Ranostay @ 2015-12-02  5:05 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..05db6ce 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 == 2) ? 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 v3 1/] iio: proximity: lidar: optimize i2c transactions
  2015-12-02  5:05 ` [PATCH v3 1/] " Matt Ranostay
@ 2015-12-05 16:50   ` Jonathan Cameron
  0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Cameron @ 2015-12-05 16:50 UTC (permalink / raw)
  To: Matt Ranostay, linux-iio

On 02/12/15 05:05, Matt Ranostay 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>
This ended up more fiddly that I expected, but seems like you got
it right to me.

Applied to the togreg branch of iio.git - initially pushed out as
testing for the autobuilders to play with it.

Jonathan
> ---
>  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..05db6ce 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 == 2) ? 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;
> 


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

end of thread, other threads:[~2015-12-05 16:50 UTC | newest]

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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).