diff options
author | Matt Ranostay <mranostay@gmail.com> | 2015-12-02 00:05:22 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2015-12-05 11:40:48 -0500 |
commit | 366e65633cf4f117609965cd6e189f2cd11533d2 (patch) | |
tree | 353c0dbefc78bd9a5174dac2379d842aa264bce5 /drivers/iio | |
parent | 8d6c16dd7213fa43702416e3dd1059e9e36bc758 (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.c | 95 |
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 | ||
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 *) ® | ||
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) | ||
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 | |||
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); | ||
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 | ||
90 | static inline int lidar_write_control(struct lidar_data *data, int val) | 134 | 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) | |||
100 | 144 | ||
101 | static int lidar_read_measurement(struct lidar_data *data, u16 *reg) | 145 | static 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 | ||
121 | static int lidar_get_measurement(struct lidar_data *data, u16 *reg) | 157 | static 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; |