aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
diff options
context:
space:
mode:
authorMatt Ranostay <mranostay@gmail.com>2015-12-02 00:05:22 -0500
committerJonathan Cameron <jic23@kernel.org>2015-12-05 11:40:48 -0500
commit366e65633cf4f117609965cd6e189f2cd11533d2 (patch)
tree353c0dbefc78bd9a5174dac2379d842aa264bce5 /drivers/iio
parent8d6c16dd7213fa43702416e3dd1059e9e36bc758 (diff)
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 <mranostay@gmail.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c95
1 files 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 be8ccef735f8..e7ea44d61942 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -36,8 +36,10 @@
36#define LIDAR_REG_STATUS_INVALID BIT(3) 36#define LIDAR_REG_STATUS_INVALID BIT(3)
37#define LIDAR_REG_STATUS_READY BIT(0) 37#define LIDAR_REG_STATUS_READY BIT(0)
38 38
39#define LIDAR_REG_DATA_HBYTE 0x0f 39#define LIDAR_REG_DATA_HBYTE 0x0f
40#define LIDAR_REG_DATA_LBYTE 0x10 40#define LIDAR_REG_DATA_LBYTE 0x10
41#define LIDAR_REG_DATA_WORD_READ BIT(7)
42
41#define LIDAR_REG_PWR_CONTROL 0x65 43#define LIDAR_REG_PWR_CONTROL 0x65
42 44
43#define LIDAR_DRV_NAME "lidar" 45#define LIDAR_DRV_NAME "lidar"
@@ -46,6 +48,9 @@ struct lidar_data {
46 struct iio_dev *indio_dev; 48 struct iio_dev *indio_dev;
47 struct i2c_client *client; 49 struct i2c_client *client;
48 50
51 int (*xfer)(struct lidar_data *data, u8 reg, u8 *val, int len);
52 int i2c_enabled;
53
49 u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */ 54 u16 buffer[8]; /* 2 byte distance + 8 byte timestamp */
50}; 55};
51 56
@@ -64,7 +69,28 @@ static const struct iio_chan_spec lidar_channels[] = {
64 IIO_CHAN_SOFT_TIMESTAMP(1), 69 IIO_CHAN_SOFT_TIMESTAMP(1),
65}; 70};
66 71
67static int lidar_read_byte(struct lidar_data *data, int reg) 72static 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
93static int lidar_smbus_xfer(struct lidar_data *data, u8 reg, u8 *val, int len)
68{ 94{
69 struct i2c_client *client = data->client; 95 struct i2c_client *client = data->client;
70 int ret; 96 int ret;
@@ -74,17 +100,35 @@ static int lidar_read_byte(struct lidar_data *data, int reg)
74 * so in turn i2c_smbus_read_byte_data cannot be used 100 * so in turn i2c_smbus_read_byte_data cannot be used
75 */ 101 */
76 102
77 ret = i2c_smbus_write_byte(client, reg); 103 while (len--) {
78 if (ret < 0) { 104 ret = i2c_smbus_write_byte(client, reg++);
79 dev_err(&client->dev, "cannot write addr value"); 105 if (ret < 0) {
80 return ret; 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;
81 } 117 }
82 118
83 ret = i2c_smbus_read_byte(client); 119 return 0;
120}
121
122static 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);
84 if (ret < 0) 128 if (ret < 0)
85 dev_err(&client->dev, "cannot read data value"); 129 return ret;
86 130
87 return ret; 131 return val;
88} 132}
89 133
90static inline int lidar_write_control(struct lidar_data *data, int val) 134static 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)
100 144
101static int lidar_read_measurement(struct lidar_data *data, u16 *reg) 145static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
102{ 146{
103 int ret; 147 int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE |
104 int val; 148 (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0),
105 149 (u8 *) reg, 2);
106 ret = lidar_read_byte(data, LIDAR_REG_DATA_HBYTE);
107 if (ret < 0)
108 return ret;
109 val = ret << 8;
110 150
111 ret = lidar_read_byte(data, LIDAR_REG_DATA_LBYTE); 151 if (!ret)
112 if (ret < 0) 152 *reg = be16_to_cpu(*reg);
113 return ret;
114 153
115 val |= ret; 154 return ret;
116 *reg = val;
117
118 return 0;
119} 155}
120 156
121static int lidar_get_measurement(struct lidar_data *data, u16 *reg) 157static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
@@ -233,6 +269,16 @@ static int lidar_probe(struct i2c_client *client,
233 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 269 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
234 if (!indio_dev) 270 if (!indio_dev)
235 return -ENOMEM; 271 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;
236 282
237 indio_dev->info = &lidar_info; 283 indio_dev->info = &lidar_info;
238 indio_dev->name = LIDAR_DRV_NAME; 284 indio_dev->name = LIDAR_DRV_NAME;
@@ -240,7 +286,6 @@ static int lidar_probe(struct i2c_client *client,
240 indio_dev->num_channels = ARRAY_SIZE(lidar_channels); 286 indio_dev->num_channels = ARRAY_SIZE(lidar_channels);
241 indio_dev->modes = INDIO_DIRECT_MODE; 287 indio_dev->modes = INDIO_DIRECT_MODE;
242 288
243 data = iio_priv(indio_dev);
244 i2c_set_clientdata(client, indio_dev); 289 i2c_set_clientdata(client, indio_dev);
245 290
246 data->client = client; 291 data->client = client;