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

iio: Add driver for Infineon DPS310

The DPS310 is a temperature and pressure sensor. It can be accessed over
i2c and SPI, but this driver only supports polling over i2c.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Joel Stanley and committed by
Jonathan Cameron
ba6ec48e bc4054b5

+486
+6
MAINTAINERS
··· 7761 7761 S: Maintained 7762 7762 F: drivers/ipack/ 7763 7763 7764 + INFINEON DPS310 Driver 7765 + M: Eddie James <eajames@linux.ibm.com> 7766 + L: linux-iio@vger.kernel.org 7767 + F: drivers/iio/pressure/dps310.c 7768 + S: Maintained 7769 + 7764 7770 INFINIBAND SUBSYSTEM 7765 7771 M: Doug Ledford <dledford@redhat.com> 7766 7772 M: Jason Gunthorpe <jgg@mellanox.com>
+11
drivers/iio/pressure/Kconfig
··· 52 52 To compile this driver as a module, choose M here: the module 53 53 will be called cros_ec_baro. 54 54 55 + config DPS310 56 + tristate "Infineon DPS310 pressure and temperature sensor" 57 + depends on I2C 58 + select REGMAP_I2C 59 + help 60 + Support for the Infineon DPS310 digital barometric pressure sensor. 61 + It can be accessed over I2C bus. 62 + 63 + This driver can also be built as a module. If so, the module will be 64 + called dps310. 65 + 55 66 config HID_SENSOR_PRESS 56 67 depends on HID_SENSOR_HUB 57 68 select IIO_BUFFER
+1
drivers/iio/pressure/Makefile
··· 9 9 bmp280-objs := bmp280-core.o bmp280-regmap.o 10 10 obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o 11 11 obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o 12 + obj-$(CONFIG_DPS310) += dps310.o 12 13 obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o 13 14 obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o 14 15 obj-$(CONFIG_HP03) += hp03.o
+468
drivers/iio/pressure/dps310.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + // Copyright IBM Corp 2019 3 + /* 4 + * The DPS310 is a barometric pressure and temperature sensor. 5 + * Currently only reading a single temperature is supported by 6 + * this driver. 7 + * 8 + * https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242 9 + * 10 + * Temperature calculation: 11 + * c0 * 0.5 + c1 * T_raw / kT °C 12 + * 13 + * TODO: 14 + * - Pressure sensor readings 15 + * - Optionally support the FIFO 16 + */ 17 + 18 + #include <linux/i2c.h> 19 + #include <linux/module.h> 20 + #include <linux/regmap.h> 21 + 22 + #include <linux/iio/iio.h> 23 + #include <linux/iio/sysfs.h> 24 + 25 + #define DPS310_DEV_NAME "dps310" 26 + 27 + #define DPS310_PRS_B0 0x00 28 + #define DPS310_PRS_B1 0x01 29 + #define DPS310_PRS_B2 0x02 30 + #define DPS310_TMP_B0 0x03 31 + #define DPS310_TMP_B1 0x04 32 + #define DPS310_TMP_B2 0x05 33 + #define DPS310_PRS_CFG 0x06 34 + #define DPS310_TMP_CFG 0x07 35 + #define DPS310_TMP_RATE_BITS GENMASK(6, 4) 36 + #define DPS310_TMP_PRC_BITS GENMASK(3, 0) 37 + #define DPS310_TMP_EXT BIT(7) 38 + #define DPS310_MEAS_CFG 0x08 39 + #define DPS310_MEAS_CTRL_BITS GENMASK(2, 0) 40 + #define DPS310_PRS_EN BIT(0) 41 + #define DPS310_TEMP_EN BIT(1) 42 + #define DPS310_BACKGROUND BIT(2) 43 + #define DPS310_PRS_RDY BIT(4) 44 + #define DPS310_TMP_RDY BIT(5) 45 + #define DPS310_SENSOR_RDY BIT(6) 46 + #define DPS310_COEF_RDY BIT(7) 47 + #define DPS310_CFG_REG 0x09 48 + #define DPS310_INT_HL BIT(7) 49 + #define DPS310_TMP_SHIFT_EN BIT(3) 50 + #define DPS310_PRS_SHIFT_EN BIT(4) 51 + #define DPS310_FIFO_EN BIT(5) 52 + #define DPS310_SPI_EN BIT(6) 53 + #define DPS310_RESET 0x0c 54 + #define DPS310_RESET_MAGIC 0x09 55 + #define DPS310_COEF_BASE 0x10 56 + #define DPS310_COEF_SRC 0x28 57 + 58 + /* Make sure sleep time is <= 20ms for usleep_range */ 59 + #define DPS310_POLL_SLEEP_US(t) min(20000, (t) / 8) 60 + /* Silently handle error in rate value here */ 61 + #define DPS310_POLL_TIMEOUT_US(rc) ((rc) <= 0 ? 1000000 : 1000000 / (rc)) 62 + 63 + #define DPS310_PRS_BASE DPS310_PRS_B0 64 + #define DPS310_TMP_BASE DPS310_TMP_B0 65 + 66 + /* 67 + * These values (defined in the spec) indicate how to scale the raw register 68 + * values for each level of precision available. 69 + */ 70 + static const int scale_factors[] = { 71 + 524288, 72 + 1572864, 73 + 3670016, 74 + 7864320, 75 + 253952, 76 + 516096, 77 + 1040384, 78 + 2088960, 79 + }; 80 + 81 + struct dps310_data { 82 + struct i2c_client *client; 83 + struct regmap *regmap; 84 + struct mutex lock; /* Lock for sequential HW access functions */ 85 + 86 + s32 c0, c1; 87 + s32 temp_raw; 88 + }; 89 + 90 + static const struct iio_chan_spec dps310_channels[] = { 91 + { 92 + .type = IIO_TEMP, 93 + .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | 94 + BIT(IIO_CHAN_INFO_SAMP_FREQ) | 95 + BIT(IIO_CHAN_INFO_PROCESSED), 96 + }, 97 + }; 98 + 99 + /* To be called after checking the COEF_RDY bit in MEAS_CFG */ 100 + static int dps310_get_temp_coef(struct dps310_data *data) 101 + { 102 + int rc; 103 + u8 coef[3]; 104 + u32 c0, c1; 105 + 106 + /* 107 + * Read temperature calibration coefficients c0 and c1 from the 108 + * COEF register. The numbers are 12-bit 2's compliment numbers 109 + */ 110 + rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef, 111 + sizeof(coef)); 112 + if (rc < 0) 113 + return rc; 114 + 115 + c0 = (coef[0] << 4) | (coef[1] >> 4); 116 + data->c0 = sign_extend32(c0, 11); 117 + 118 + c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2]; 119 + data->c1 = sign_extend32(c1, 11); 120 + 121 + return 0; 122 + } 123 + 124 + static int dps310_get_temp_precision(struct dps310_data *data) 125 + { 126 + int rc; 127 + int val; 128 + 129 + rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val); 130 + if (rc < 0) 131 + return rc; 132 + 133 + /* 134 + * Scale factor is bottom 4 bits of the register, but 1111 is 135 + * reserved so just grab bottom three 136 + */ 137 + return BIT(val & GENMASK(2, 0)); 138 + } 139 + 140 + /* Called with lock held */ 141 + static int dps310_set_temp_precision(struct dps310_data *data, int val) 142 + { 143 + int rc; 144 + u8 shift_en; 145 + 146 + if (val < 0 || val > 128) 147 + return -EINVAL; 148 + 149 + shift_en = val >= 16 ? DPS310_TMP_SHIFT_EN : 0; 150 + rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, 151 + DPS310_TMP_SHIFT_EN, shift_en); 152 + if (rc) 153 + return rc; 154 + 155 + return regmap_update_bits(data->regmap, DPS310_TMP_CFG, 156 + DPS310_TMP_PRC_BITS, ilog2(val)); 157 + } 158 + 159 + /* Called with lock held */ 160 + static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq) 161 + { 162 + u8 val; 163 + 164 + if (freq < 0 || freq > 128) 165 + return -EINVAL; 166 + 167 + val = ilog2(freq) << 4; 168 + 169 + return regmap_update_bits(data->regmap, DPS310_TMP_CFG, 170 + DPS310_TMP_RATE_BITS, val); 171 + } 172 + 173 + static int dps310_get_temp_samp_freq(struct dps310_data *data) 174 + { 175 + int rc; 176 + int val; 177 + 178 + rc = regmap_read(data->regmap, DPS310_TMP_CFG, &val); 179 + if (rc < 0) 180 + return rc; 181 + 182 + return BIT((val & DPS310_TMP_RATE_BITS) >> 4); 183 + } 184 + 185 + static int dps310_get_temp_k(struct dps310_data *data) 186 + { 187 + int rc = dps310_get_temp_precision(data); 188 + 189 + if (rc < 0) 190 + return rc; 191 + 192 + return scale_factors[ilog2(rc)]; 193 + } 194 + 195 + static int dps310_read_temp(struct dps310_data *data) 196 + { 197 + int rc; 198 + int rate; 199 + int ready; 200 + int timeout; 201 + s32 raw; 202 + u8 val[3]; 203 + 204 + if (mutex_lock_interruptible(&data->lock)) 205 + return -EINTR; 206 + 207 + rate = dps310_get_temp_samp_freq(data); 208 + timeout = DPS310_POLL_TIMEOUT_US(rate); 209 + 210 + /* Poll for sensor readiness; base the timeout upon the sample rate. */ 211 + rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, 212 + ready & DPS310_TMP_RDY, 213 + DPS310_POLL_SLEEP_US(timeout), timeout); 214 + if (rc < 0) 215 + goto done; 216 + 217 + rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val)); 218 + if (rc < 0) 219 + goto done; 220 + 221 + raw = (val[0] << 16) | (val[1] << 8) | val[2]; 222 + data->temp_raw = sign_extend32(raw, 23); 223 + 224 + done: 225 + mutex_unlock(&data->lock); 226 + return rc; 227 + } 228 + 229 + static bool dps310_is_writeable_reg(struct device *dev, unsigned int reg) 230 + { 231 + switch (reg) { 232 + case DPS310_PRS_CFG: 233 + case DPS310_TMP_CFG: 234 + case DPS310_MEAS_CFG: 235 + case DPS310_CFG_REG: 236 + case DPS310_RESET: 237 + return true; 238 + default: 239 + return false; 240 + } 241 + } 242 + 243 + static bool dps310_is_volatile_reg(struct device *dev, unsigned int reg) 244 + { 245 + switch (reg) { 246 + case DPS310_PRS_B0: 247 + case DPS310_PRS_B1: 248 + case DPS310_PRS_B2: 249 + case DPS310_TMP_B0: 250 + case DPS310_TMP_B1: 251 + case DPS310_TMP_B2: 252 + case DPS310_MEAS_CFG: 253 + return true; 254 + default: 255 + return false; 256 + } 257 + } 258 + 259 + static int dps310_write_raw(struct iio_dev *iio, 260 + struct iio_chan_spec const *chan, int val, 261 + int val2, long mask) 262 + { 263 + int rc; 264 + struct dps310_data *data = iio_priv(iio); 265 + 266 + if (chan->type != IIO_TEMP) 267 + return -EINVAL; 268 + 269 + if (mutex_lock_interruptible(&data->lock)) 270 + return -EINTR; 271 + 272 + switch (mask) { 273 + case IIO_CHAN_INFO_SAMP_FREQ: 274 + rc = dps310_set_temp_samp_freq(data, val); 275 + break; 276 + 277 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 278 + rc = dps310_set_temp_precision(data, val); 279 + break; 280 + 281 + default: 282 + rc = -EINVAL; 283 + break; 284 + } 285 + 286 + mutex_unlock(&data->lock); 287 + return rc; 288 + } 289 + 290 + static int dps310_calculate_temp(struct dps310_data *data) 291 + { 292 + s64 c0; 293 + s64 t; 294 + int kt = dps310_get_temp_k(data); 295 + 296 + if (kt < 0) 297 + return kt; 298 + 299 + /* Obtain inverse-scaled offset */ 300 + c0 = div_s64((s64)kt * (s64)data->c0, 2); 301 + 302 + /* Add the offset to the unscaled temperature */ 303 + t = c0 + ((s64)data->temp_raw * (s64)data->c1); 304 + 305 + /* Convert to milliCelsius and scale the temperature */ 306 + return (int)div_s64(t * 1000LL, kt); 307 + } 308 + 309 + static int dps310_read_raw(struct iio_dev *iio, 310 + struct iio_chan_spec const *chan, 311 + int *val, int *val2, long mask) 312 + { 313 + struct dps310_data *data = iio_priv(iio); 314 + int rc; 315 + 316 + switch (mask) { 317 + case IIO_CHAN_INFO_SAMP_FREQ: 318 + rc = dps310_get_temp_samp_freq(data); 319 + if (rc < 0) 320 + return rc; 321 + 322 + *val = rc; 323 + return IIO_VAL_INT; 324 + 325 + case IIO_CHAN_INFO_PROCESSED: 326 + rc = dps310_read_temp(data); 327 + if (rc) 328 + return rc; 329 + 330 + rc = dps310_calculate_temp(data); 331 + if (rc < 0) 332 + return rc; 333 + 334 + *val = rc; 335 + return IIO_VAL_INT; 336 + 337 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 338 + rc = dps310_get_temp_precision(data); 339 + if (rc < 0) 340 + return rc; 341 + 342 + *val = rc; 343 + return IIO_VAL_INT; 344 + 345 + default: 346 + return -EINVAL; 347 + } 348 + } 349 + 350 + static void dps310_reset(void *action_data) 351 + { 352 + struct dps310_data *data = action_data; 353 + 354 + regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC); 355 + } 356 + 357 + static const struct regmap_config dps310_regmap_config = { 358 + .reg_bits = 8, 359 + .val_bits = 8, 360 + .writeable_reg = dps310_is_writeable_reg, 361 + .volatile_reg = dps310_is_volatile_reg, 362 + .cache_type = REGCACHE_RBTREE, 363 + .max_register = DPS310_COEF_SRC, 364 + }; 365 + 366 + static const struct iio_info dps310_info = { 367 + .read_raw = dps310_read_raw, 368 + .write_raw = dps310_write_raw, 369 + }; 370 + 371 + static int dps310_probe(struct i2c_client *client, 372 + const struct i2c_device_id *id) 373 + { 374 + struct dps310_data *data; 375 + struct iio_dev *iio; 376 + int rc, ready; 377 + 378 + iio = devm_iio_device_alloc(&client->dev, sizeof(*data)); 379 + if (!iio) 380 + return -ENOMEM; 381 + 382 + data = iio_priv(iio); 383 + data->client = client; 384 + mutex_init(&data->lock); 385 + 386 + iio->dev.parent = &client->dev; 387 + iio->name = id->name; 388 + iio->channels = dps310_channels; 389 + iio->num_channels = ARRAY_SIZE(dps310_channels); 390 + iio->info = &dps310_info; 391 + iio->modes = INDIO_DIRECT_MODE; 392 + 393 + data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config); 394 + if (IS_ERR(data->regmap)) 395 + return PTR_ERR(data->regmap); 396 + 397 + /* Register to run the device reset when the device is removed */ 398 + rc = devm_add_action_or_reset(&client->dev, dps310_reset, data); 399 + if (rc) 400 + return rc; 401 + 402 + /* 403 + * Set up external (MEMS) temperature sensor in single sample, one 404 + * measurement per second mode 405 + */ 406 + rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT); 407 + if (rc < 0) 408 + return rc; 409 + 410 + /* Temp shift is disabled when PRC <= 8 */ 411 + rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, 412 + DPS310_TMP_SHIFT_EN, 0); 413 + if (rc < 0) 414 + return rc; 415 + 416 + /* MEAS_CFG doesn't update correctly unless first written with 0 */ 417 + rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, 418 + DPS310_MEAS_CTRL_BITS, 0); 419 + if (rc < 0) 420 + return rc; 421 + 422 + /* Turn on temperature measurement in the background */ 423 + rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, 424 + DPS310_MEAS_CTRL_BITS, 425 + DPS310_TEMP_EN | DPS310_BACKGROUND); 426 + if (rc < 0) 427 + return rc; 428 + 429 + /* 430 + * Calibration coefficients required for reporting temperature. 431 + * They are available 40ms after the device has started 432 + */ 433 + rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, 434 + ready & DPS310_COEF_RDY, 10000, 40000); 435 + if (rc < 0) 436 + return rc; 437 + 438 + rc = dps310_get_temp_coef(data); 439 + if (rc < 0) 440 + return rc; 441 + 442 + rc = devm_iio_device_register(&client->dev, iio); 443 + if (rc) 444 + return rc; 445 + 446 + i2c_set_clientdata(client, iio); 447 + 448 + return 0; 449 + } 450 + 451 + static const struct i2c_device_id dps310_id[] = { 452 + { DPS310_DEV_NAME, 0 }, 453 + {} 454 + }; 455 + MODULE_DEVICE_TABLE(i2c, dps310_id); 456 + 457 + static struct i2c_driver dps310_driver = { 458 + .driver = { 459 + .name = DPS310_DEV_NAME, 460 + }, 461 + .probe = dps310_probe, 462 + .id_table = dps310_id, 463 + }; 464 + module_i2c_driver(dps310_driver); 465 + 466 + MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>"); 467 + MODULE_DESCRIPTION("Infineon DPS310 pressure and temperature sensor"); 468 + MODULE_LICENSE("GPL v2");