Skip to content

Commit 366e656

Browse files
mranostayjic23
authored andcommitted
iio: proximity: lidar: optimize i2c transactions
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 <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 8d6c16d commit 366e656

File tree

1 file changed

+70
-25
lines changed

1 file changed

+70
-25
lines changed

drivers/iio/proximity/pulsedlight-lidar-lite-v2.c

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,10 @@
3636
#define LIDAR_REG_STATUS_INVALID BIT(3)
3737
#define LIDAR_REG_STATUS_READY BIT(0)
3838

39-
#define LIDAR_REG_DATA_HBYTE 0x0f
40-
#define LIDAR_REG_DATA_LBYTE 0x10
39+
#define LIDAR_REG_DATA_HBYTE 0x0f
40+
#define LIDAR_REG_DATA_LBYTE 0x10
41+
#define LIDAR_REG_DATA_WORD_READ BIT(7)
42+
4143
#define LIDAR_REG_PWR_CONTROL 0x65
4244

4345
#define LIDAR_DRV_NAME "lidar"
@@ -46,6 +48,9 @@ struct lidar_data {
4648
struct iio_dev *indio_dev;
4749
struct i2c_client *client;
4850

51+
int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
52+
int i2c_enabled;
53+
4954
u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
5055
};
5156

@@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
6469
IIO_CHAN_SOFT_TIMESTAMP(1),
6570
};
6671

67-
static int lidar_read_byte(struct lidar_data *data, int reg)
72+
static int lidar_i2c_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
73+
{
74+
struct i2c_client *client = data->client;
75+
struct i2c_msg msg[2];
76+
int ret;
77+
78+
msg[0].addr = client->addr;
79+
msg[0].flags = client->flags | I2C_M_STOP;
80+
msg[0].len = 1;
81+
msg[0].buf = (char *) &reg;
82+
83+
msg[1].addr = client->addr;
84+
msg[1].flags = client->flags | I2C_M_RD;
85+
msg[1].len = len;
86+
msg[1].buf = (char *) val;
87+
88+
ret = i2c_transfer(client->adapter, msg, 2);
89+
90+
return (ret == 2) ? 0 : ret;
91+
}
92+
93+
static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
6894
{
6995
struct i2c_client *client = data->client;
7096
int ret;
@@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
74100
* so in turn i2c_smbus_read_byte_data cannot be used
75101
*/
76102

77-
ret = i2c_smbus_write_byte(client, reg);
78-
if (ret < 0) {
79-
dev_err(&client->dev, "cannot write addr value");
80-
return ret;
103+
while (len--) {
104+
ret = i2c_smbus_write_byte(client, reg++);
105+
if (ret < 0) {
106+
dev_err(&client->dev, "cannot write addr value");
107+
return ret;
108+
}
109+
110+
ret = i2c_smbus_read_byte(client);
111+
if (ret < 0) {
112+
dev_err(&client->dev, "cannot read data value");
113+
return ret;
114+
}
115+
116+
*(val++) = ret;
81117
}
82118

83-
ret = i2c_smbus_read_byte(client);
119+
return 0;
120+
}
121+
122+
static int lidar_read_byte(struct lidar_data *data, u8 reg)
123+
{
124+
int ret;
125+
u8 val;
126+
127+
ret = data->xfer(data, reg, &val, 1);
84128
if (ret < 0)
85-
dev_err(&client->dev, "cannot read data value");
129+
return ret;
86130

87-
return ret;
131+
return val;
88132
}
89133

90134
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)
100144

101145
static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
102146
{
103-
int ret;
104-
int val;
105-
106-
ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
107-
if (ret < 0)
108-
return ret;
109-
val = ret << 8;
147+
int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
148+
(data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
149+
(u8 *) reg, 2);
110150

111-
ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE);
112-
if (ret < 0)
113-
return ret;
151+
if (!ret)
152+
*reg = be16_to_cpu(*reg);
114153

115-
val |= ret;
116-
*reg = val;
117-
118-
return 0;
154+
return ret;
119155
}
120156

121157
static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
@@ -233,14 +269,23 @@ static int lidar_probe(struct i2c_client *client,
233269
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
234270
if (!indio_dev)
235271
return -ENOMEM;
272+
data = iio_priv(indio_dev);
273+
274+
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
275+
data->xfer = lidar_i2c_xfer;
276+
data->i2c_enabled = 1;
277+
} else if (i2c_check_functionality(client->adapter,
278+
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
279+
data->xfer = lidar_smbus_xfer;
280+
else
281+
return -ENOTSUPP;
236282

237283
indio_dev->info = &lidar_info;
238284
indio_dev->name = LIDAR_DRV_NAME;
239285
indio_dev->channels = lidar_channels;
240286
indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
241287
indio_dev->modes = INDIO_DIRECT_MODE;
242288

243-
data = iio_priv(indio_dev);
244289
i2c_set_clientdata(client, indio_dev);
245290

246291
data->client = client;

0 commit comments

Comments
 (0)