* [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 *) ®
+
+ 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 *) ®
> +
> + 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).