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

iio: mpl3115: add threshold events support

Add support for pressure and temperature rising threshold events. For
both channels *_en and *_value (in raw units) attributes are exposed.

Since in write_event_config() the ctrl_reg1.active and ctrl_reg4
are modified, accessing the data->ctrl_reg{1,4} in set_trigger_state()
and write_event_config() needs to be now guarded by data->lock.
Otherwise, it would be possible that 2 concurrent threads executing
these functions would access the data->ctrl_reg{1,4} at the same time
and then one would overwrite the other's result.

Signed-off-by: Antoni Pokusinski <apokusinski01@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Antoni Pokusinski and committed by
Jonathan Cameron
6062cd20 47e4b1ca

+212 -11
+212 -11
drivers/iio/pressure/mpl3115.c
··· 14 14 #include <linux/cleanup.h> 15 15 #include <linux/delay.h> 16 16 #include <linux/i2c.h> 17 + #include <linux/limits.h> 17 18 #include <linux/module.h> 18 19 #include <linux/property.h> 19 20 #include <linux/unaligned.h> 20 21 21 22 #include <linux/iio/buffer.h> 23 + #include <linux/iio/events.h> 22 24 #include <linux/iio/iio.h> 23 25 #include <linux/iio/sysfs.h> 24 26 #include <linux/iio/triggered_buffer.h> ··· 33 31 #define MPL3115_WHO_AM_I 0x0c 34 32 #define MPL3115_INT_SOURCE 0x12 35 33 #define MPL3115_PT_DATA_CFG 0x13 34 + #define MPL3115_PRESS_TGT 0x16 /* MSB first, 16 bit */ 35 + #define MPL3115_TEMP_TGT 0x18 36 36 #define MPL3115_CTRL_REG1 0x26 37 37 #define MPL3115_CTRL_REG2 0x27 38 38 #define MPL3115_CTRL_REG3 0x28 ··· 47 43 #define MPL3115_STATUS_TEMP_RDY BIT(1) 48 44 49 45 #define MPL3115_INT_SRC_DRDY BIT(7) 46 + #define MPL3115_INT_SRC_PTH BIT(3) 47 + #define MPL3115_INT_SRC_TTH BIT(2) 50 48 51 49 #define MPL3115_PT_DATA_EVENT_ALL GENMASK(2, 0) 52 50 ··· 63 57 #define MPL3115_CTRL3_IPOL2 BIT(1) 64 58 65 59 #define MPL3115_CTRL4_INT_EN_DRDY BIT(7) 60 + #define MPL3115_CTRL4_INT_EN_PTH BIT(3) 61 + #define MPL3115_CTRL4_INT_EN_TTH BIT(2) 66 62 67 63 #define MPL3115_CTRL5_INT_CFG_DRDY BIT(7) 68 64 ··· 92 84 struct iio_trigger *drdy_trig; 93 85 struct mutex lock; 94 86 u8 ctrl_reg1; 87 + u8 ctrl_reg4; 95 88 }; 96 89 97 90 enum mpl3115_irq_pin { ··· 322 313 return IRQ_HANDLED; 323 314 } 324 315 316 + static const struct iio_event_spec mpl3115_temp_press_event[] = { 317 + { 318 + .type = IIO_EV_TYPE_THRESH, 319 + .dir = IIO_EV_DIR_RISING, 320 + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | 321 + BIT(IIO_EV_INFO_VALUE), 322 + }, 323 + }; 324 + 325 325 static const struct iio_chan_spec mpl3115_channels[] = { 326 326 { 327 327 .type = IIO_PRESSURE, ··· 346 328 .storagebits = 32, 347 329 .shift = 12, 348 330 .endianness = IIO_BE, 349 - } 331 + }, 332 + .event_spec = mpl3115_temp_press_event, 333 + .num_event_specs = ARRAY_SIZE(mpl3115_temp_press_event), 350 334 }, 351 335 { 352 336 .type = IIO_TEMP, ··· 364 344 .storagebits = 16, 365 345 .shift = 4, 366 346 .endianness = IIO_BE, 367 - } 347 + }, 348 + .event_spec = mpl3115_temp_press_event, 349 + .num_event_specs = ARRAY_SIZE(mpl3115_temp_press_event), 368 350 }, 369 351 IIO_CHAN_SOFT_TIMESTAMP(2), 370 352 }; ··· 376 354 struct iio_dev *indio_dev = private; 377 355 struct mpl3115_data *data = iio_priv(indio_dev); 378 356 int ret; 357 + u8 val_press[3]; 358 + __be16 val_temp; 379 359 380 360 ret = i2c_smbus_read_byte_data(data->client, MPL3115_INT_SOURCE); 381 361 if (ret < 0) 382 362 return IRQ_HANDLED; 383 363 384 - if (!(ret & MPL3115_INT_SRC_DRDY)) 364 + if (!(ret & (MPL3115_INT_SRC_TTH | MPL3115_INT_SRC_PTH | 365 + MPL3115_INT_SRC_DRDY))) 385 366 return IRQ_NONE; 386 367 387 - iio_trigger_poll_nested(data->drdy_trig); 368 + if (ret & MPL3115_INT_SRC_DRDY) 369 + iio_trigger_poll_nested(data->drdy_trig); 370 + 371 + if (ret & MPL3115_INT_SRC_PTH) { 372 + iio_push_event(indio_dev, 373 + IIO_UNMOD_EVENT_CODE(IIO_PRESSURE, 0, 374 + IIO_EV_TYPE_THRESH, 375 + IIO_EV_DIR_RISING), 376 + iio_get_time_ns(indio_dev)); 377 + 378 + /* Reset the SRC_PTH bit in INT_SOURCE */ 379 + i2c_smbus_read_i2c_block_data(data->client, 380 + MPL3115_OUT_PRESS, 381 + sizeof(val_press), val_press); 382 + } 383 + 384 + if (ret & MPL3115_INT_SRC_TTH) { 385 + iio_push_event(indio_dev, 386 + IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, 387 + IIO_EV_TYPE_THRESH, 388 + IIO_EV_DIR_RISING), 389 + iio_get_time_ns(indio_dev)); 390 + 391 + /* Reset the SRC_TTH bit in INT_SOURCE */ 392 + i2c_smbus_read_i2c_block_data(data->client, 393 + MPL3115_OUT_TEMP, 394 + sizeof(val_temp), 395 + (u8 *)&val_temp); 396 + } 388 397 389 398 return IRQ_HANDLED; 390 399 } ··· 436 383 goto reg1_cleanup; 437 384 438 385 data->ctrl_reg1 = ctrl_reg1; 386 + data->ctrl_reg4 = ctrl_reg4; 439 387 440 388 return 0; 441 389 ··· 450 396 { 451 397 struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 452 398 struct mpl3115_data *data = iio_priv(indio_dev); 453 - u8 ctrl_reg1 = data->ctrl_reg1; 454 - u8 ctrl_reg4 = state ? MPL3115_CTRL4_INT_EN_DRDY : 0; 455 - 456 - if (state) 457 - ctrl_reg1 |= MPL3115_CTRL1_ACTIVE; 458 - else 459 - ctrl_reg1 &= ~MPL3115_CTRL1_ACTIVE; 399 + u8 ctrl_reg1, ctrl_reg4; 460 400 461 401 guard(mutex)(&data->lock); 402 + 403 + ctrl_reg1 = data->ctrl_reg1; 404 + ctrl_reg4 = data->ctrl_reg4; 405 + 406 + if (state) { 407 + ctrl_reg1 |= MPL3115_CTRL1_ACTIVE; 408 + ctrl_reg4 |= MPL3115_CTRL4_INT_EN_DRDY; 409 + } else { 410 + ctrl_reg4 &= ~MPL3115_CTRL4_INT_EN_DRDY; 411 + 412 + if (!ctrl_reg4) 413 + ctrl_reg1 &= ~MPL3115_CTRL1_ACTIVE; 414 + } 462 415 463 416 return mpl3115_config_interrupt(data, ctrl_reg1, ctrl_reg4); 464 417 } ··· 474 413 .set_trigger_state = mpl3115_set_trigger_state, 475 414 }; 476 415 416 + static int mpl3115_read_event_config(struct iio_dev *indio_dev, 417 + const struct iio_chan_spec *chan, 418 + enum iio_event_type type, 419 + enum iio_event_direction dir) 420 + { 421 + struct mpl3115_data *data = iio_priv(indio_dev); 422 + 423 + if (chan->type == IIO_PRESSURE) 424 + return !!(data->ctrl_reg4 & MPL3115_CTRL4_INT_EN_PTH); 425 + 426 + if (chan->type == IIO_TEMP) 427 + return !!(data->ctrl_reg4 & MPL3115_CTRL4_INT_EN_TTH); 428 + 429 + return -EINVAL; 430 + } 431 + 432 + static int mpl3115_write_event_config(struct iio_dev *indio_dev, 433 + const struct iio_chan_spec *chan, 434 + enum iio_event_type type, 435 + enum iio_event_direction dir, 436 + bool state) 437 + { 438 + struct mpl3115_data *data = iio_priv(indio_dev); 439 + u8 int_en_mask; 440 + u8 ctrl_reg1, ctrl_reg4; 441 + 442 + switch (chan->type) { 443 + case IIO_PRESSURE: 444 + int_en_mask = MPL3115_CTRL4_INT_EN_PTH; 445 + break; 446 + case IIO_TEMP: 447 + int_en_mask = MPL3115_CTRL4_INT_EN_TTH; 448 + break; 449 + default: 450 + return -EINVAL; 451 + } 452 + 453 + guard(mutex)(&data->lock); 454 + 455 + ctrl_reg1 = data->ctrl_reg1; 456 + ctrl_reg4 = data->ctrl_reg4; 457 + 458 + if (state) { 459 + ctrl_reg1 |= MPL3115_CTRL1_ACTIVE; 460 + ctrl_reg4 |= int_en_mask; 461 + } else { 462 + ctrl_reg4 &= ~int_en_mask; 463 + 464 + if (!ctrl_reg4) 465 + ctrl_reg1 &= ~MPL3115_CTRL1_ACTIVE; 466 + } 467 + 468 + return mpl3115_config_interrupt(data, ctrl_reg1, ctrl_reg4); 469 + } 470 + 471 + static int mpl3115_read_thresh(struct iio_dev *indio_dev, 472 + const struct iio_chan_spec *chan, 473 + enum iio_event_type type, 474 + enum iio_event_direction dir, 475 + enum iio_event_info info, 476 + int *val, int *val2) 477 + { 478 + struct mpl3115_data *data = iio_priv(indio_dev); 479 + int ret; 480 + __be16 press_tgt; 481 + 482 + if (info != IIO_EV_INFO_VALUE) 483 + return -EINVAL; 484 + 485 + switch (chan->type) { 486 + case IIO_PRESSURE: 487 + ret = i2c_smbus_read_i2c_block_data(data->client, 488 + MPL3115_PRESS_TGT, 489 + sizeof(press_tgt), 490 + (u8 *)&press_tgt); 491 + if (ret < 0) 492 + return ret; 493 + 494 + /* 495 + * Target value for the pressure is 16-bit unsigned value, 496 + * expressed in 2 Pa units 497 + */ 498 + *val = be16_to_cpu(press_tgt) << 1; 499 + 500 + return IIO_VAL_INT; 501 + case IIO_TEMP: 502 + ret = i2c_smbus_read_byte_data(data->client, MPL3115_TEMP_TGT); 503 + if (ret < 0) 504 + return ret; 505 + 506 + /* Target value for the temperature is 8-bit 2's complement */ 507 + *val = sign_extend32(ret, 7); 508 + 509 + return IIO_VAL_INT; 510 + default: 511 + return -EINVAL; 512 + } 513 + } 514 + 515 + static int mpl3115_write_thresh(struct iio_dev *indio_dev, 516 + const struct iio_chan_spec *chan, 517 + enum iio_event_type type, 518 + enum iio_event_direction dir, 519 + enum iio_event_info info, 520 + int val, int val2) 521 + { 522 + struct mpl3115_data *data = iio_priv(indio_dev); 523 + __be16 press_tgt; 524 + 525 + if (info != IIO_EV_INFO_VALUE) 526 + return -EINVAL; 527 + 528 + switch (chan->type) { 529 + case IIO_PRESSURE: 530 + val >>= 1; 531 + 532 + if (val < 0 || val > U16_MAX) 533 + return -EINVAL; 534 + 535 + press_tgt = cpu_to_be16(val); 536 + 537 + return i2c_smbus_write_i2c_block_data(data->client, 538 + MPL3115_PRESS_TGT, 539 + sizeof(press_tgt), 540 + (u8 *)&press_tgt); 541 + case IIO_TEMP: 542 + if (val < S8_MIN || val > S8_MAX) 543 + return -EINVAL; 544 + 545 + return i2c_smbus_write_byte_data(data->client, 546 + MPL3115_TEMP_TGT, val); 547 + default: 548 + return -EINVAL; 549 + } 550 + } 551 + 477 552 static const struct iio_info mpl3115_info = { 478 553 .read_raw = &mpl3115_read_raw, 479 554 .read_avail = &mpl3115_read_avail, 480 555 .write_raw = &mpl3115_write_raw, 556 + .read_event_config = mpl3115_read_event_config, 557 + .write_event_config = mpl3115_write_event_config, 558 + .read_event_value = mpl3115_read_thresh, 559 + .write_event_value = mpl3115_write_thresh, 481 560 }; 482 561 483 562 static int mpl3115_trigger_probe(struct mpl3115_data *data,