From: Jonathan Cameron <jic23@kernel.org>
To: Matt Ranostay <mranostay@gmail.com>, linux-iio@vger.kernel.org
Subject: Re: [PATCH v3 1/] iio: proximity: lidar: optimize i2c transactions
Date: Sat, 5 Dec 2015 16:50:11 +0000 [thread overview]
Message-ID: <566315C3.4000909@kernel.org> (raw)
In-Reply-To: <1449032722-25646-2-git-send-email-mranostay@gmail.com>
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;
>
prev parent reply other threads:[~2015-12-05 16:50 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
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 message]
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=566315C3.4000909@kernel.org \
--to=jic23@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=mranostay@gmail.com \
/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.