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

iio: dps310: Add pressure sensing capability

The DPS310 supports measurement of pressure, so support that in the
driver. Use background measurement like the temperature sensing and
default to lowest precision and lowest measurement rate.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Eddie James and committed by
Jonathan Cameron
d711a3c7 cc8baffe

+340 -29
+340 -29
drivers/iio/pressure/dps310.c
··· 11 11 * c0 * 0.5 + c1 * T_raw / kT °C 12 12 * 13 13 * TODO: 14 - * - Pressure sensor readings 15 14 * - Optionally support the FIFO 16 15 */ 17 16 18 17 #include <linux/i2c.h> 18 + #include <linux/limits.h> 19 + #include <linux/math64.h> 19 20 #include <linux/module.h> 20 21 #include <linux/regmap.h> 21 22 ··· 32 31 #define DPS310_TMP_B1 0x04 33 32 #define DPS310_TMP_B2 0x05 34 33 #define DPS310_PRS_CFG 0x06 34 + #define DPS310_PRS_RATE_BITS GENMASK(6, 4) 35 + #define DPS310_PRS_PRC_BITS GENMASK(3, 0) 35 36 #define DPS310_TMP_CFG 0x07 36 37 #define DPS310_TMP_RATE_BITS GENMASK(6, 4) 37 38 #define DPS310_TMP_PRC_BITS GENMASK(3, 0) ··· 86 83 struct mutex lock; /* Lock for sequential HW access functions */ 87 84 88 85 s32 c0, c1; 86 + s32 c00, c10, c20, c30, c01, c11, c21; 87 + s32 pressure_raw; 89 88 s32 temp_raw; 90 89 }; 91 90 ··· 98 93 BIT(IIO_CHAN_INFO_SAMP_FREQ) | 99 94 BIT(IIO_CHAN_INFO_PROCESSED), 100 95 }, 96 + { 97 + .type = IIO_PRESSURE, 98 + .info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | 99 + BIT(IIO_CHAN_INFO_SAMP_FREQ) | 100 + BIT(IIO_CHAN_INFO_PROCESSED), 101 + }, 101 102 }; 102 103 103 104 /* To be called after checking the COEF_RDY bit in MEAS_CFG */ 104 - static int dps310_get_temp_coef(struct dps310_data *data) 105 + static int dps310_get_coefs(struct dps310_data *data) 105 106 { 106 107 int rc; 107 - u8 coef[3]; 108 + u8 coef[18]; 108 109 u32 c0, c1; 110 + u32 c00, c10, c20, c30, c01, c11, c21; 109 111 110 - /* 111 - * Read temperature calibration coefficients c0 and c1 from the 112 - * COEF register. The numbers are 12-bit 2's compliment numbers 113 - */ 112 + /* Read all sensor calibration coefficients from the COEF registers. */ 114 113 rc = regmap_bulk_read(data->regmap, DPS310_COEF_BASE, coef, 115 114 sizeof(coef)); 116 115 if (rc < 0) 117 116 return rc; 118 117 118 + /* 119 + * Calculate temperature calibration coefficients c0 and c1. The 120 + * numbers are 12-bit 2's complement numbers. 121 + */ 119 122 c0 = (coef[0] << 4) | (coef[1] >> 4); 120 123 data->c0 = sign_extend32(c0, 11); 121 124 122 125 c1 = ((coef[1] & GENMASK(3, 0)) << 8) | coef[2]; 123 126 data->c1 = sign_extend32(c1, 11); 124 127 128 + /* 129 + * Calculate pressure calibration coefficients. c00 and c10 are 20 bit 130 + * 2's complement numbers, while the rest are 16 bit 2's complement 131 + * numbers. 132 + */ 133 + c00 = (coef[3] << 12) | (coef[4] << 4) | (coef[5] >> 4); 134 + data->c00 = sign_extend32(c00, 19); 135 + 136 + c10 = ((coef[5] & GENMASK(3, 0)) << 16) | (coef[6] << 8) | coef[7]; 137 + data->c10 = sign_extend32(c10, 19); 138 + 139 + c01 = (coef[8] << 8) | coef[9]; 140 + data->c01 = sign_extend32(c01, 15); 141 + 142 + c11 = (coef[10] << 8) | coef[11]; 143 + data->c11 = sign_extend32(c11, 15); 144 + 145 + c20 = (coef[12] << 8) | coef[13]; 146 + data->c20 = sign_extend32(c20, 15); 147 + 148 + c21 = (coef[14] << 8) | coef[15]; 149 + data->c21 = sign_extend32(c21, 15); 150 + 151 + c30 = (coef[16] << 8) | coef[17]; 152 + data->c30 = sign_extend32(c30, 15); 153 + 125 154 return 0; 155 + } 156 + 157 + static int dps310_get_pres_precision(struct dps310_data *data) 158 + { 159 + int rc; 160 + int val; 161 + 162 + rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val); 163 + if (rc < 0) 164 + return rc; 165 + 166 + return BIT(val & GENMASK(2, 0)); 126 167 } 127 168 128 169 static int dps310_get_temp_precision(struct dps310_data *data) ··· 185 134 * reserved so just grab bottom three 186 135 */ 187 136 return BIT(val & GENMASK(2, 0)); 137 + } 138 + 139 + /* Called with lock held */ 140 + static int dps310_set_pres_precision(struct dps310_data *data, int val) 141 + { 142 + int rc; 143 + u8 shift_en; 144 + 145 + if (val < 0 || val > 128) 146 + return -EINVAL; 147 + 148 + shift_en = val >= 16 ? DPS310_PRS_SHIFT_EN : 0; 149 + rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, 150 + DPS310_PRS_SHIFT_EN, shift_en); 151 + if (rc) 152 + return rc; 153 + 154 + return regmap_update_bits(data->regmap, DPS310_PRS_CFG, 155 + DPS310_PRS_PRC_BITS, ilog2(val)); 188 156 } 189 157 190 158 /* Called with lock held */ ··· 226 156 } 227 157 228 158 /* Called with lock held */ 159 + static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq) 160 + { 161 + u8 val; 162 + 163 + if (freq < 0 || freq > 128) 164 + return -EINVAL; 165 + 166 + val = ilog2(freq) << 4; 167 + 168 + return regmap_update_bits(data->regmap, DPS310_PRS_CFG, 169 + DPS310_PRS_RATE_BITS, val); 170 + } 171 + 172 + /* Called with lock held */ 229 173 static int dps310_set_temp_samp_freq(struct dps310_data *data, int freq) 230 174 { 231 175 u8 val; ··· 251 167 252 168 return regmap_update_bits(data->regmap, DPS310_TMP_CFG, 253 169 DPS310_TMP_RATE_BITS, val); 170 + } 171 + 172 + static int dps310_get_pres_samp_freq(struct dps310_data *data) 173 + { 174 + int rc; 175 + int val; 176 + 177 + rc = regmap_read(data->regmap, DPS310_PRS_CFG, &val); 178 + if (rc < 0) 179 + return rc; 180 + 181 + return BIT((val & DPS310_PRS_RATE_BITS) >> 4); 254 182 } 255 183 256 184 static int dps310_get_temp_samp_freq(struct dps310_data *data) ··· 277 181 return BIT((val & DPS310_TMP_RATE_BITS) >> 4); 278 182 } 279 183 184 + static int dps310_get_pres_k(struct dps310_data *data) 185 + { 186 + int rc = dps310_get_pres_precision(data); 187 + 188 + if (rc < 0) 189 + return rc; 190 + 191 + return scale_factors[ilog2(rc)]; 192 + } 193 + 280 194 static int dps310_get_temp_k(struct dps310_data *data) 281 195 { 282 196 int rc = dps310_get_temp_precision(data); ··· 297 191 return scale_factors[ilog2(rc)]; 298 192 } 299 193 300 - static int dps310_read_temp(struct dps310_data *data) 194 + static int dps310_read_pres_raw(struct dps310_data *data) 301 195 { 302 196 int rc; 303 197 int rate; ··· 305 199 int timeout; 306 200 s32 raw; 307 201 u8 val[3]; 202 + 203 + if (mutex_lock_interruptible(&data->lock)) 204 + return -EINTR; 205 + 206 + rate = dps310_get_pres_samp_freq(data); 207 + timeout = DPS310_POLL_TIMEOUT_US(rate); 208 + 209 + /* Poll for sensor readiness; base the timeout upon the sample rate. */ 210 + rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, 211 + ready & DPS310_PRS_RDY, 212 + DPS310_POLL_SLEEP_US(timeout), timeout); 213 + if (rc) 214 + goto done; 215 + 216 + rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val)); 217 + if (rc < 0) 218 + goto done; 219 + 220 + raw = (val[0] << 16) | (val[1] << 8) | val[2]; 221 + data->pressure_raw = sign_extend32(raw, 23); 222 + 223 + done: 224 + mutex_unlock(&data->lock); 225 + return rc; 226 + } 227 + 228 + /* Called with lock held */ 229 + static int dps310_read_temp_ready(struct dps310_data *data) 230 + { 231 + int rc; 232 + u8 val[3]; 233 + s32 raw; 234 + 235 + rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val)); 236 + if (rc < 0) 237 + return rc; 238 + 239 + raw = (val[0] << 16) | (val[1] << 8) | val[2]; 240 + data->temp_raw = sign_extend32(raw, 23); 241 + 242 + return 0; 243 + } 244 + 245 + static int dps310_read_temp_raw(struct dps310_data *data) 246 + { 247 + int rc; 248 + int rate; 249 + int ready; 250 + int timeout; 308 251 309 252 if (mutex_lock_interruptible(&data->lock)) 310 253 return -EINTR; ··· 368 213 if (rc < 0) 369 214 goto done; 370 215 371 - rc = regmap_bulk_read(data->regmap, DPS310_TMP_BASE, val, sizeof(val)); 372 - if (rc < 0) 373 - goto done; 374 - 375 - raw = (val[0] << 16) | (val[1] << 8) | val[2]; 376 - data->temp_raw = sign_extend32(raw, 23); 216 + rc = dps310_read_temp_ready(data); 377 217 378 218 done: 379 219 mutex_unlock(&data->lock); ··· 417 267 int rc; 418 268 struct dps310_data *data = iio_priv(iio); 419 269 420 - if (chan->type != IIO_TEMP) 421 - return -EINVAL; 422 - 423 270 if (mutex_lock_interruptible(&data->lock)) 424 271 return -EINTR; 425 272 426 273 switch (mask) { 427 274 case IIO_CHAN_INFO_SAMP_FREQ: 428 - rc = dps310_set_temp_samp_freq(data, val); 275 + switch (chan->type) { 276 + case IIO_PRESSURE: 277 + rc = dps310_set_pres_samp_freq(data, val); 278 + break; 279 + 280 + case IIO_TEMP: 281 + rc = dps310_set_temp_samp_freq(data, val); 282 + break; 283 + 284 + default: 285 + rc = -EINVAL; 286 + break; 287 + } 429 288 break; 430 289 431 290 case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 432 - rc = dps310_set_temp_precision(data, val); 291 + switch (chan->type) { 292 + case IIO_PRESSURE: 293 + rc = dps310_set_pres_precision(data, val); 294 + break; 295 + 296 + case IIO_TEMP: 297 + rc = dps310_set_temp_precision(data, val); 298 + break; 299 + 300 + default: 301 + rc = -EINVAL; 302 + break; 303 + } 433 304 break; 434 305 435 306 default: ··· 460 289 461 290 mutex_unlock(&data->lock); 462 291 return rc; 292 + } 293 + 294 + static int dps310_calculate_pressure(struct dps310_data *data) 295 + { 296 + int i; 297 + int rc; 298 + int t_ready; 299 + int kpi = dps310_get_pres_k(data); 300 + int kti = dps310_get_temp_k(data); 301 + s64 rem = 0ULL; 302 + s64 pressure = 0ULL; 303 + s64 p; 304 + s64 t; 305 + s64 denoms[7]; 306 + s64 nums[7]; 307 + s64 rems[7]; 308 + s64 kp; 309 + s64 kt; 310 + 311 + if (kpi < 0) 312 + return kpi; 313 + 314 + if (kti < 0) 315 + return kti; 316 + 317 + kp = (s64)kpi; 318 + kt = (s64)kti; 319 + 320 + /* Refresh temp if it's ready, otherwise just use the latest value */ 321 + if (mutex_trylock(&data->lock)) { 322 + rc = regmap_read(data->regmap, DPS310_MEAS_CFG, &t_ready); 323 + if (rc >= 0 && t_ready & DPS310_TMP_RDY) 324 + dps310_read_temp_ready(data); 325 + 326 + mutex_unlock(&data->lock); 327 + } 328 + 329 + p = (s64)data->pressure_raw; 330 + t = (s64)data->temp_raw; 331 + 332 + /* Section 4.9.1 of the DPS310 spec; algebra'd to avoid underflow */ 333 + nums[0] = (s64)data->c00; 334 + denoms[0] = 1LL; 335 + nums[1] = p * (s64)data->c10; 336 + denoms[1] = kp; 337 + nums[2] = p * p * (s64)data->c20; 338 + denoms[2] = kp * kp; 339 + nums[3] = p * p * p * (s64)data->c30; 340 + denoms[3] = kp * kp * kp; 341 + nums[4] = t * (s64)data->c01; 342 + denoms[4] = kt; 343 + nums[5] = t * p * (s64)data->c11; 344 + denoms[5] = kp * kt; 345 + nums[6] = t * p * p * (s64)data->c21; 346 + denoms[6] = kp * kp * kt; 347 + 348 + /* Kernel lacks a div64_s64_rem function; denoms are all positive */ 349 + for (i = 0; i < 7; ++i) { 350 + u64 irem; 351 + 352 + if (nums[i] < 0LL) { 353 + pressure -= div64_u64_rem(-nums[i], denoms[i], &irem); 354 + rems[i] = -irem; 355 + } else { 356 + pressure += div64_u64_rem(nums[i], denoms[i], &irem); 357 + rems[i] = (s64)irem; 358 + } 359 + } 360 + 361 + /* Increase precision and calculate the remainder sum */ 362 + for (i = 0; i < 7; ++i) 363 + rem += div64_s64((s64)rems[i] * 1000000000LL, denoms[i]); 364 + 365 + pressure += div_s64(rem, 1000000000LL); 366 + if (pressure < 0LL) 367 + return -ERANGE; 368 + 369 + return (int)min_t(s64, pressure, INT_MAX); 370 + } 371 + 372 + static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2, 373 + long mask) 374 + { 375 + int rc; 376 + 377 + switch (mask) { 378 + case IIO_CHAN_INFO_SAMP_FREQ: 379 + rc = dps310_get_pres_samp_freq(data); 380 + if (rc < 0) 381 + return rc; 382 + 383 + *val = rc; 384 + return IIO_VAL_INT; 385 + 386 + case IIO_CHAN_INFO_PROCESSED: 387 + rc = dps310_read_pres_raw(data); 388 + if (rc) 389 + return rc; 390 + 391 + rc = dps310_calculate_pressure(data); 392 + if (rc < 0) 393 + return rc; 394 + 395 + *val = rc; 396 + *val2 = 1000; /* Convert Pa to KPa per IIO ABI */ 397 + return IIO_VAL_FRACTIONAL; 398 + 399 + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: 400 + rc = dps310_get_pres_precision(data); 401 + if (rc < 0) 402 + return rc; 403 + 404 + *val = rc; 405 + return IIO_VAL_INT; 406 + 407 + default: 408 + return -EINVAL; 409 + } 463 410 } 464 411 465 412 static int dps310_calculate_temp(struct dps310_data *data) ··· 599 310 return (int)div_s64(t * 1000LL, kt); 600 311 } 601 312 602 - static int dps310_read_raw(struct iio_dev *iio, 603 - struct iio_chan_spec const *chan, 604 - int *val, int *val2, long mask) 313 + static int dps310_read_temp(struct dps310_data *data, int *val, int *val2, 314 + long mask) 605 315 { 606 - struct dps310_data *data = iio_priv(iio); 607 316 int rc; 608 317 609 318 switch (mask) { ··· 614 327 return IIO_VAL_INT; 615 328 616 329 case IIO_CHAN_INFO_PROCESSED: 617 - rc = dps310_read_temp(data); 330 + rc = dps310_read_temp_raw(data); 618 331 if (rc) 619 332 return rc; 620 333 ··· 632 345 633 346 *val = rc; 634 347 return IIO_VAL_INT; 348 + 349 + default: 350 + return -EINVAL; 351 + } 352 + } 353 + 354 + static int dps310_read_raw(struct iio_dev *iio, 355 + struct iio_chan_spec const *chan, 356 + int *val, int *val2, long mask) 357 + { 358 + struct dps310_data *data = iio_priv(iio); 359 + 360 + switch (chan->type) { 361 + case IIO_PRESSURE: 362 + return dps310_read_pressure(data, val, val2, mask); 363 + 364 + case IIO_TEMP: 365 + return dps310_read_temp(data, val, val2, mask); 635 366 636 367 default: 637 368 return -EINVAL; ··· 749 444 return rc; 750 445 751 446 /* 447 + * Set up pressure sensor in single sample, one measurement per second 448 + * mode 449 + */ 450 + rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0); 451 + 452 + /* 752 453 * Set up external (MEMS) temperature sensor in single sample, one 753 454 * measurement per second mode 754 455 */ ··· 762 451 if (rc < 0) 763 452 return rc; 764 453 765 - /* Temp shift is disabled when PRC <= 8 */ 454 + /* Temp and pressure shifts are disabled when PRC <= 8 */ 766 455 rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, 767 - DPS310_TMP_SHIFT_EN, 0); 456 + DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0); 768 457 if (rc < 0) 769 458 return rc; 770 459 ··· 774 463 if (rc < 0) 775 464 return rc; 776 465 777 - /* Turn on temperature measurement in the background */ 466 + /* Turn on temperature and pressure measurement in the background */ 778 467 rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, 779 - DPS310_MEAS_CTRL_BITS, 468 + DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN | 780 469 DPS310_TEMP_EN | DPS310_BACKGROUND); 781 470 if (rc < 0) 782 471 return rc; ··· 790 479 if (rc < 0) 791 480 return rc; 792 481 793 - rc = dps310_get_temp_coef(data); 482 + rc = dps310_get_coefs(data); 794 483 if (rc < 0) 795 484 return rc; 796 485