Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: proximity: vl53l0x-i2c: Added continuous mode support

The continuous mode of the sensor is enabled in the buffer_postenable.
Replaced the original irq handler with a threaded irq handler to perform
i2c reads during continuous mode.
The continuous mode is disabled by disabling the buffer.
Added a trigger for this device to be used for continuous mode.

Signed-off-by: Abhash Jha <abhashkumarjha123@gmail.com>
Link: https://patch.msgid.link/20240909101508.263085-3-abhashkumarjha123@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Abhash Jha and committed by
Jonathan Cameron
762186c6 962b48d4

+136 -26
+136 -26
drivers/iio/proximity/vl53l0x-i2c.c
··· 22 22 #include <linux/module.h> 23 23 24 24 #include <linux/iio/iio.h> 25 + #include <linux/iio/buffer.h> 26 + #include <linux/iio/trigger.h> 27 + #include <linux/iio/trigger_consumer.h> 28 + #include <linux/iio/triggered_buffer.h> 29 + 30 + #include <asm/unaligned.h> 25 31 26 32 #define VL_REG_SYSRANGE_START 0x00 27 33 ··· 49 43 #define VL_REG_RESULT_RANGE_STATUS_COMPLETE BIT(0) 50 44 51 45 #define VL53L0X_MODEL_ID_VAL 0xEE 46 + #define VL53L0X_CONTINUOUS_MODE 0x02 47 + #define VL53L0X_SINGLE_MODE 0x01 52 48 53 49 struct vl53l0x_data { 54 50 struct i2c_client *client; 55 51 struct completion completion; 56 52 struct regulator *vdd_supply; 57 53 struct gpio_desc *reset_gpio; 54 + struct iio_trigger *trig; 55 + 56 + struct { 57 + u16 chan; 58 + aligned_s64 timestamp; 59 + } scan; 58 60 }; 59 61 60 - static irqreturn_t vl53l0x_handle_irq(int irq, void *priv) 62 + static int vl53l0x_clear_irq(struct vl53l0x_data *data) 63 + { int ret; 64 + 65 + ret = i2c_smbus_write_byte_data(data->client, 66 + VL_REG_SYSTEM_INTERRUPT_CLEAR, 1); 67 + if (ret < 0) { 68 + dev_err(&data->client->dev, "failed to clear irq: %d\n", ret); 69 + return -EINVAL; 70 + } 71 + 72 + return 0; 73 + } 74 + 75 + static irqreturn_t vl53l0x_trigger_handler(int irq, void *priv) 76 + { 77 + struct iio_poll_func *pf = priv; 78 + struct iio_dev *indio_dev = pf->indio_dev; 79 + struct vl53l0x_data *data = iio_priv(indio_dev); 80 + u8 buffer[12]; 81 + int ret; 82 + 83 + ret = i2c_smbus_read_i2c_block_data(data->client, 84 + VL_REG_RESULT_RANGE_STATUS, 85 + sizeof(buffer), buffer); 86 + if (ret < 0) 87 + return ret; 88 + else if (ret != 12) 89 + return -EREMOTEIO; 90 + 91 + data->scan.chan = get_unaligned_be16(&buffer[10]); 92 + iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, 93 + iio_get_time_ns(indio_dev)); 94 + 95 + iio_trigger_notify_done(indio_dev->trig); 96 + vl53l0x_clear_irq(data); 97 + 98 + return IRQ_HANDLED; 99 + } 100 + 101 + static irqreturn_t vl53l0x_threaded_irq(int irq, void *priv) 61 102 { 62 103 struct iio_dev *indio_dev = priv; 63 104 struct vl53l0x_data *data = iio_priv(indio_dev); 64 105 65 - complete(&data->completion); 106 + if (iio_buffer_enabled(indio_dev)) 107 + iio_trigger_poll_nested(indio_dev->trig); 108 + else 109 + complete(&data->completion); 66 110 67 111 return IRQ_HANDLED; 68 112 } ··· 127 71 if (!irq_flags) 128 72 irq_flags = IRQF_TRIGGER_FALLING; 129 73 130 - ret = devm_request_irq(&client->dev, client->irq, vl53l0x_handle_irq, 131 - irq_flags, indio_dev->name, indio_dev); 74 + ret = devm_request_threaded_irq(&client->dev, client->irq, 75 + NULL, vl53l0x_threaded_irq, 76 + irq_flags | IRQF_ONESHOT, indio_dev->name, indio_dev); 132 77 if (ret) { 133 78 dev_err(&client->dev, "devm_request_irq error: %d\n", ret); 134 79 return ret; ··· 142 85 dev_err(&client->dev, "failed to configure IRQ: %d\n", ret); 143 86 144 87 return ret; 145 - } 146 - 147 - static void vl53l0x_clear_irq(struct vl53l0x_data *data) 148 - { 149 - struct device *dev = &data->client->dev; 150 - int ret; 151 - 152 - ret = i2c_smbus_write_byte_data(data->client, 153 - VL_REG_SYSTEM_INTERRUPT_CLEAR, 1); 154 - if (ret < 0) 155 - dev_err(dev, "failed to clear error irq: %d\n", ret); 156 - 157 - ret = i2c_smbus_write_byte_data(data->client, 158 - VL_REG_SYSTEM_INTERRUPT_CLEAR, 0); 159 - if (ret < 0) 160 - dev_err(dev, "failed to clear range irq: %d\n", ret); 161 - 162 - ret = i2c_smbus_read_byte_data(data->client, VL_REG_RESULT_INT_STATUS); 163 - if (ret < 0 || ret & 0x07) 164 - dev_err(dev, "failed to clear irq: %d\n", ret); 165 88 } 166 89 167 90 static int vl53l0x_read_proximity(struct vl53l0x_data *data, ··· 165 128 if (time_left == 0) 166 129 return -ETIMEDOUT; 167 130 168 - vl53l0x_clear_irq(data); 131 + ret = vl53l0x_clear_irq(data); 132 + if (ret < 0) 133 + return ret; 169 134 } else { 170 135 do { 171 136 ret = i2c_smbus_read_byte_data(client, ··· 192 153 return -EREMOTEIO; 193 154 194 155 /* Values should be between 30~1200 in millimeters. */ 195 - *val = (buffer[10] << 8) + buffer[11]; 156 + *val = get_unaligned_be16(&buffer[10]); 196 157 197 158 return 0; 198 159 } ··· 202 163 .type = IIO_DISTANCE, 203 164 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 204 165 BIT(IIO_CHAN_INFO_SCALE), 166 + .scan_index = 0, 167 + .scan_type = { 168 + .sign = 'u', 169 + .realbits = 12, 170 + .storagebits = 16, 171 + }, 205 172 }, 173 + IIO_CHAN_SOFT_TIMESTAMP(1), 206 174 }; 207 175 208 176 static int vl53l0x_read_raw(struct iio_dev *indio_dev, ··· 239 193 } 240 194 } 241 195 196 + static int vl53l0x_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) 197 + { 198 + struct vl53l0x_data *data = iio_priv(indio_dev); 199 + 200 + return data->trig == trig ? 0 : -EINVAL; 201 + } 202 + 242 203 static const struct iio_info vl53l0x_info = { 243 204 .read_raw = vl53l0x_read_raw, 205 + .validate_trigger = vl53l0x_validate_trigger, 244 206 }; 245 207 246 208 static void vl53l0x_power_off(void *_data) ··· 274 220 275 221 return 0; 276 222 } 223 + 224 + static int vl53l0x_buffer_postenable(struct iio_dev *indio_dev) 225 + { 226 + struct vl53l0x_data *data = iio_priv(indio_dev); 227 + 228 + return i2c_smbus_write_byte_data(data->client, VL_REG_SYSRANGE_START, 229 + VL53L0X_CONTINUOUS_MODE); 230 + } 231 + 232 + static int vl53l0x_buffer_postdisable(struct iio_dev *indio_dev) 233 + { 234 + struct vl53l0x_data *data = iio_priv(indio_dev); 235 + int ret; 236 + 237 + ret = i2c_smbus_write_byte_data(data->client, VL_REG_SYSRANGE_START, 238 + VL53L0X_SINGLE_MODE); 239 + if (ret < 0) 240 + return ret; 241 + 242 + /* Let the ongoing reading finish */ 243 + reinit_completion(&data->completion); 244 + wait_for_completion_timeout(&data->completion, HZ / 10); 245 + 246 + return vl53l0x_clear_irq(data); 247 + } 248 + 249 + static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { 250 + .postenable = &vl53l0x_buffer_postenable, 251 + .postdisable = &vl53l0x_buffer_postdisable, 252 + }; 253 + 254 + static const struct iio_trigger_ops vl53l0x_trigger_ops = { 255 + .validate_device = iio_trigger_validate_own_device, 256 + }; 277 257 278 258 static int vl53l0x_probe(struct i2c_client *client) 279 259 { ··· 366 278 if (client->irq) { 367 279 init_completion(&data->completion); 368 280 281 + data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", 282 + indio_dev->name, 283 + iio_device_id(indio_dev)); 284 + if (!data->trig) 285 + return -ENOMEM; 286 + 287 + data->trig->ops = &vl53l0x_trigger_ops; 288 + iio_trigger_set_drvdata(data->trig, indio_dev); 289 + ret = devm_iio_trigger_register(&client->dev, data->trig); 290 + if (ret) 291 + return ret; 292 + 293 + indio_dev->trig = iio_trigger_get(data->trig); 294 + 369 295 ret = vl53l0x_configure_irq(client, indio_dev); 296 + if (ret) 297 + return ret; 298 + 299 + ret = devm_iio_triggered_buffer_setup(&client->dev, 300 + indio_dev, 301 + NULL, 302 + &vl53l0x_trigger_handler, 303 + &iio_triggered_buffer_setup_ops); 370 304 if (ret) 371 305 return ret; 372 306 }