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: temperature: tmp006: add triggered buffer support

Add support for continuous data capture using triggered buffers for the
tmp006 sensor. The device features a "data ready" interrupt line which
is pulled down once a new measurement is ready to be read.

Signed-off-by: Antoni Pokusinski <apokusinski01@gmail.com>
Link: https://patch.msgid.link/20240908172153.177406-2-apokusinski01@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Antoni Pokusinski and committed by
Jonathan Cameron
91f75ccf 819b69ab

+123 -13
+2
drivers/iio/temperature/Kconfig
··· 91 91 config TMP006 92 92 tristate "TMP006 infrared thermopile sensor" 93 93 depends on I2C 94 + select IIO_BUFFER 95 + select IIO_TRIGGERED_BUFFER 94 96 help 95 97 If you say yes here you get support for the Texas Instruments 96 98 TMP006 infrared thermopile sensor.
+121 -13
drivers/iio/temperature/tmp006.c
··· 7 7 * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor 8 8 * 9 9 * (7-bit I2C slave address 0x40, changeable via ADR pins) 10 - * 11 - * TODO: data ready irq 12 10 */ 13 11 14 12 #include <linux/err.h> ··· 19 21 20 22 #include <linux/iio/iio.h> 21 23 #include <linux/iio/sysfs.h> 24 + #include <linux/iio/trigger.h> 25 + #include <linux/iio/triggered_buffer.h> 26 + #include <linux/iio/trigger_consumer.h> 22 27 23 28 #define TMP006_VOBJECT 0x00 24 29 #define TMP006_TAMBIENT 0x01 ··· 46 45 struct tmp006_data { 47 46 struct i2c_client *client; 48 47 u16 config; 48 + struct iio_trigger *drdy_trig; 49 49 }; 50 50 51 51 static int tmp006_read_measurement(struct tmp006_data *data, u8 reg) ··· 85 83 case IIO_CHAN_INFO_RAW: 86 84 if (channel->type == IIO_VOLTAGE) { 87 85 /* LSB is 156.25 nV */ 88 - ret = tmp006_read_measurement(data, TMP006_VOBJECT); 89 - if (ret < 0) 90 - return ret; 86 + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { 87 + ret = tmp006_read_measurement(data, TMP006_VOBJECT); 88 + if (ret < 0) 89 + return ret; 90 + } 91 91 *val = sign_extend32(ret, 15); 92 92 } else if (channel->type == IIO_TEMP) { 93 93 /* LSB is 0.03125 degrees Celsius */ 94 - ret = tmp006_read_measurement(data, TMP006_TAMBIENT); 95 - if (ret < 0) 96 - return ret; 94 + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { 95 + ret = tmp006_read_measurement(data, TMP006_TAMBIENT); 96 + if (ret < 0) 97 + return ret; 98 + } 97 99 *val = sign_extend32(ret, 15) >> TMP006_TAMBIENT_SHIFT; 98 100 } else { 99 101 break; ··· 134 128 long mask) 135 129 { 136 130 struct tmp006_data *data = iio_priv(indio_dev); 137 - int i; 131 + int ret, i; 138 132 139 133 if (mask != IIO_CHAN_INFO_SAMP_FREQ) 140 134 return -EINVAL; ··· 142 136 for (i = 0; i < ARRAY_SIZE(tmp006_freqs); i++) 143 137 if ((val == tmp006_freqs[i][0]) && 144 138 (val2 == tmp006_freqs[i][1])) { 139 + ret = iio_device_claim_direct_mode(indio_dev); 140 + if (ret) 141 + return ret; 142 + 145 143 data->config &= ~TMP006_CONFIG_CR_MASK; 146 144 data->config |= i << TMP006_CONFIG_CR_SHIFT; 147 145 148 - return i2c_smbus_write_word_swapped(data->client, 149 - TMP006_CONFIG, 150 - data->config); 146 + ret = i2c_smbus_write_word_swapped(data->client, 147 + TMP006_CONFIG, 148 + data->config); 151 149 150 + iio_device_release_direct_mode(indio_dev); 151 + return ret; 152 152 } 153 153 return -EINVAL; 154 154 } ··· 176 164 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 177 165 BIT(IIO_CHAN_INFO_SCALE), 178 166 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 167 + .scan_index = 0, 168 + .scan_type = { 169 + .sign = 's', 170 + .realbits = 16, 171 + .storagebits = 16, 172 + .endianness = IIO_BE, 173 + } 179 174 }, 180 175 { 181 176 .type = IIO_TEMP, 182 177 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 183 178 BIT(IIO_CHAN_INFO_SCALE), 184 179 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), 185 - } 180 + .scan_index = 1, 181 + .scan_type = { 182 + .sign = 's', 183 + .realbits = 14, 184 + .storagebits = 16, 185 + .shift = TMP006_TAMBIENT_SHIFT, 186 + .endianness = IIO_BE, 187 + } 188 + }, 189 + IIO_CHAN_SOFT_TIMESTAMP(2), 186 190 }; 187 191 188 192 static const struct iio_info tmp006_info = { ··· 241 213 tmp006_power(dev, false); 242 214 } 243 215 216 + static irqreturn_t tmp006_trigger_handler(int irq, void *p) 217 + { 218 + struct iio_poll_func *pf = p; 219 + struct iio_dev *indio_dev = pf->indio_dev; 220 + struct tmp006_data *data = iio_priv(indio_dev); 221 + struct { 222 + s16 channels[2]; 223 + s64 ts __aligned(8); 224 + } scan; 225 + s32 ret; 226 + 227 + ret = i2c_smbus_read_word_data(data->client, TMP006_VOBJECT); 228 + if (ret < 0) 229 + goto err; 230 + scan.channels[0] = ret; 231 + 232 + ret = i2c_smbus_read_word_data(data->client, TMP006_TAMBIENT); 233 + if (ret < 0) 234 + goto err; 235 + scan.channels[1] = ret; 236 + 237 + iio_push_to_buffers_with_timestamp(indio_dev, &scan, 238 + iio_get_time_ns(indio_dev)); 239 + err: 240 + iio_trigger_notify_done(indio_dev->trig); 241 + return IRQ_HANDLED; 242 + } 243 + 244 + static int tmp006_set_trigger_state(struct iio_trigger *trig, bool state) 245 + { 246 + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 247 + struct tmp006_data *data = iio_priv(indio_dev); 248 + 249 + if (state) 250 + data->config |= TMP006_CONFIG_DRDY_EN; 251 + else 252 + data->config &= ~TMP006_CONFIG_DRDY_EN; 253 + 254 + return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, 255 + data->config); 256 + } 257 + 258 + static const struct iio_trigger_ops tmp006_trigger_ops = { 259 + .set_trigger_state = tmp006_set_trigger_state, 260 + }; 261 + 262 + static const unsigned long tmp006_scan_masks[] = { 0x3, 0 }; 263 + 244 264 static int tmp006_probe(struct i2c_client *client) 245 265 { 246 266 struct iio_dev *indio_dev; ··· 317 241 318 242 indio_dev->channels = tmp006_channels; 319 243 indio_dev->num_channels = ARRAY_SIZE(tmp006_channels); 244 + indio_dev->available_scan_masks = tmp006_scan_masks; 320 245 321 246 ret = i2c_smbus_read_word_swapped(data->client, TMP006_CONFIG); 322 247 if (ret < 0) ··· 332 255 333 256 ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup, 334 257 &client->dev); 258 + if (ret < 0) 259 + return ret; 260 + 261 + if (client->irq > 0) { 262 + data->drdy_trig = devm_iio_trigger_alloc(&client->dev, 263 + "%s-dev%d", 264 + indio_dev->name, 265 + iio_device_id(indio_dev)); 266 + if (!data->drdy_trig) 267 + return -ENOMEM; 268 + 269 + data->drdy_trig->ops = &tmp006_trigger_ops; 270 + iio_trigger_set_drvdata(data->drdy_trig, indio_dev); 271 + ret = iio_trigger_register(data->drdy_trig); 272 + if (ret) 273 + return ret; 274 + 275 + indio_dev->trig = iio_trigger_get(data->drdy_trig); 276 + 277 + ret = devm_request_threaded_irq(&client->dev, client->irq, 278 + iio_trigger_generic_data_rdy_poll, 279 + NULL, 280 + IRQF_ONESHOT, 281 + "tmp006_irq", 282 + data->drdy_trig); 283 + if (ret < 0) 284 + return ret; 285 + } 286 + 287 + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL, 288 + tmp006_trigger_handler, NULL); 335 289 if (ret < 0) 336 290 return ret; 337 291