987 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2015 Intel Corporation4 *5 * Driver for UPISEMI us5182d Proximity and Ambient Light Sensor.6 *7 * To do: Interrupt support.8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/mod_devicetable.h>13#include <linux/delay.h>14#include <linux/i2c.h>15#include <linux/iio/events.h>16#include <linux/iio/iio.h>17#include <linux/interrupt.h>18#include <linux/irq.h>19#include <linux/iio/sysfs.h>20#include <linux/mutex.h>21#include <linux/pm.h>22#include <linux/pm_runtime.h>23 24#define US5182D_REG_CFG0 0x0025#define US5182D_CFG0_ONESHOT_EN BIT(6)26#define US5182D_CFG0_SHUTDOWN_EN BIT(7)27#define US5182D_CFG0_WORD_ENABLE BIT(0)28#define US5182D_CFG0_PROX BIT(3)29#define US5182D_CFG0_PX_IRQ BIT(2)30 31#define US5182D_REG_CFG1 0x0132#define US5182D_CFG1_ALS_RES16 BIT(4)33#define US5182D_CFG1_AGAIN_DEFAULT 0x0034 35#define US5182D_REG_CFG2 0x0236#define US5182D_CFG2_PX_RES16 BIT(4)37#define US5182D_CFG2_PXGAIN_DEFAULT BIT(2)38 39#define US5182D_REG_CFG3 0x0340#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))41#define US5182D_CFG3_INT_SOURCE_PX BIT(3)42 43#define US5182D_REG_CFG4 0x1044 45/*46 * Registers for tuning the auto dark current cancelling feature.47 * DARK_TH(reg 0x27,0x28) - threshold (counts) for auto dark cancelling.48 * when ALS > DARK_TH --> ALS_Code = ALS - Upper(0x2A) * Dark49 * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark50 */51#define US5182D_REG_UDARK_TH 0x2752#define US5182D_REG_DARK_AUTO_EN 0x2b53#define US5182D_REG_AUTO_LDARK_GAIN 0x2954#define US5182D_REG_AUTO_HDARK_GAIN 0x2a55 56/* Thresholds for events: px low (0x08-l, 0x09-h), px high (0x0a-l 0x0b-h) */57#define US5182D_REG_PXL_TH 0x0858#define US5182D_REG_PXH_TH 0x0a59 60#define US5182D_REG_PXL_TH_DEFAULT 100061#define US5182D_REG_PXH_TH_DEFAULT 3000062 63#define US5182D_OPMODE_ALS 0x0164#define US5182D_OPMODE_PX 0x0265#define US5182D_OPMODE_SHIFT 466 67#define US5182D_REG_DARK_AUTO_EN_DEFAULT 0x8068#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT 0x1669#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT 0x0070 71#define US5182D_REG_ADL 0x0c72#define US5182D_REG_PDL 0x0e73 74#define US5182D_REG_MODE_STORE 0x2175#define US5182D_STORE_MODE 0x0176 77#define US5182D_REG_CHIPID 0xb278 79#define US5182D_OPMODE_MASK GENMASK(5, 4)80#define US5182D_AGAIN_MASK 0x0781#define US5182D_RESET_CHIP 0x0182 83#define US5182D_CHIPID 0x2684#define US5182D_DRV_NAME "us5182d"85 86#define US5182D_GA_RESOLUTION 100087 88#define US5182D_READ_BYTE 189#define US5182D_READ_WORD 290#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */91#define US5182D_SLEEP_MS 3000 /* ms */92#define US5182D_PXH_TH_DISABLE 0xffff93#define US5182D_PXL_TH_DISABLE 0x000094 95/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */96static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,97 3900, 2100};98 99/*100 * Experimental thresholds that work with US5182D sensor on evaluation board101 * roughly between 12-32 lux102 */103static u16 us5182d_dark_ths_vals[] = {170, 200, 512, 512, 800, 2000, 4000,104 8000};105 106enum mode {107 US5182D_ALS_PX,108 US5182D_ALS_ONLY,109 US5182D_PX_ONLY110};111 112enum pmode {113 US5182D_CONTINUOUS,114 US5182D_ONESHOT115};116 117struct us5182d_data {118 struct i2c_client *client;119 struct mutex lock;120 121 /* Glass attenuation factor */122 u32 ga;123 124 /* Dark gain tuning */125 u8 lower_dark_gain;126 u8 upper_dark_gain;127 u16 *us5182d_dark_ths;128 129 u16 px_low_th;130 u16 px_high_th;131 132 int rising_en;133 int falling_en;134 135 u8 opmode;136 u8 power_mode;137 138 bool als_enabled;139 bool px_enabled;140 141 bool default_continuous;142};143 144static IIO_CONST_ATTR(in_illuminance_scale_available,145 "0.0021 0.0039 0.0076 0.0196 0.0336 0.061 0.1078 0.1885");146 147static struct attribute *us5182d_attrs[] = {148 &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,149 NULL150};151 152static const struct attribute_group us5182d_attr_group = {153 .attrs = us5182d_attrs,154};155 156static const struct {157 u8 reg;158 u8 val;159} us5182d_regvals[] = {160 {US5182D_REG_CFG0, US5182D_CFG0_WORD_ENABLE},161 {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},162 {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |163 US5182D_CFG2_PXGAIN_DEFAULT)},164 {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100 |165 US5182D_CFG3_INT_SOURCE_PX},166 {US5182D_REG_CFG4, 0x00},167};168 169static const struct iio_event_spec us5182d_events[] = {170 {171 .type = IIO_EV_TYPE_THRESH,172 .dir = IIO_EV_DIR_RISING,173 .mask_separate = BIT(IIO_EV_INFO_VALUE) |174 BIT(IIO_EV_INFO_ENABLE),175 },176 {177 .type = IIO_EV_TYPE_THRESH,178 .dir = IIO_EV_DIR_FALLING,179 .mask_separate = BIT(IIO_EV_INFO_VALUE) |180 BIT(IIO_EV_INFO_ENABLE),181 },182};183 184static const struct iio_chan_spec us5182d_channels[] = {185 {186 .type = IIO_LIGHT,187 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |188 BIT(IIO_CHAN_INFO_SCALE),189 },190 {191 .type = IIO_PROXIMITY,192 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),193 .event_spec = us5182d_events,194 .num_event_specs = ARRAY_SIZE(us5182d_events),195 }196};197 198static int us5182d_oneshot_en(struct us5182d_data *data)199{200 int ret;201 202 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);203 if (ret < 0)204 return ret;205 206 /*207 * In oneshot mode the chip will power itself down after taking the208 * required measurement.209 */210 ret = ret | US5182D_CFG0_ONESHOT_EN;211 212 return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);213}214 215static int us5182d_set_opmode(struct us5182d_data *data, u8 mode)216{217 int ret;218 219 if (mode == data->opmode)220 return 0;221 222 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);223 if (ret < 0)224 return ret;225 226 /* update mode */227 ret = ret & ~US5182D_OPMODE_MASK;228 ret = ret | (mode << US5182D_OPMODE_SHIFT);229 230 /*231 * After updating the operating mode, the chip requires that232 * the operation is stored, by writing 1 in the STORE_MODE233 * register (auto-clearing).234 */235 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);236 if (ret < 0)237 return ret;238 239 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_MODE_STORE,240 US5182D_STORE_MODE);241 if (ret < 0)242 return ret;243 244 data->opmode = mode;245 msleep(US5182D_OPSTORE_SLEEP_TIME);246 247 return 0;248}249 250static int us5182d_als_enable(struct us5182d_data *data)251{252 int ret;253 u8 mode;254 255 if (data->power_mode == US5182D_ONESHOT) {256 ret = us5182d_set_opmode(data, US5182D_ALS_ONLY);257 if (ret < 0)258 return ret;259 data->px_enabled = false;260 }261 262 if (data->als_enabled)263 return 0;264 265 mode = data->px_enabled ? US5182D_ALS_PX : US5182D_ALS_ONLY;266 267 ret = us5182d_set_opmode(data, mode);268 if (ret < 0)269 return ret;270 271 data->als_enabled = true;272 273 return 0;274}275 276static int us5182d_px_enable(struct us5182d_data *data)277{278 int ret;279 u8 mode;280 281 if (data->power_mode == US5182D_ONESHOT) {282 ret = us5182d_set_opmode(data, US5182D_PX_ONLY);283 if (ret < 0)284 return ret;285 data->als_enabled = false;286 }287 288 if (data->px_enabled)289 return 0;290 291 mode = data->als_enabled ? US5182D_ALS_PX : US5182D_PX_ONLY;292 293 ret = us5182d_set_opmode(data, mode);294 if (ret < 0)295 return ret;296 297 data->px_enabled = true;298 299 return 0;300}301 302static int us5182d_get_als(struct us5182d_data *data)303{304 int ret;305 unsigned long result;306 307 ret = us5182d_als_enable(data);308 if (ret < 0)309 return ret;310 311 ret = i2c_smbus_read_word_data(data->client,312 US5182D_REG_ADL);313 if (ret < 0)314 return ret;315 316 result = ret * data->ga / US5182D_GA_RESOLUTION;317 if (result > 0xffff)318 result = 0xffff;319 320 return result;321}322 323static int us5182d_get_px(struct us5182d_data *data)324{325 int ret;326 327 ret = us5182d_px_enable(data);328 if (ret < 0)329 return ret;330 331 return i2c_smbus_read_word_data(data->client,332 US5182D_REG_PDL);333}334 335static int us5182d_shutdown_en(struct us5182d_data *data, u8 state)336{337 int ret;338 339 if (data->power_mode == US5182D_ONESHOT)340 return 0;341 342 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);343 if (ret < 0)344 return ret;345 346 ret = ret & ~US5182D_CFG0_SHUTDOWN_EN;347 ret = ret | state;348 349 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0, ret);350 if (ret < 0)351 return ret;352 353 if (state & US5182D_CFG0_SHUTDOWN_EN) {354 data->als_enabled = false;355 data->px_enabled = false;356 }357 358 return ret;359}360 361 362static int us5182d_set_power_state(struct us5182d_data *data, bool on)363{364 int ret;365 366 if (data->power_mode == US5182D_ONESHOT)367 return 0;368 369 if (on) {370 ret = pm_runtime_resume_and_get(&data->client->dev);371 } else {372 pm_runtime_mark_last_busy(&data->client->dev);373 ret = pm_runtime_put_autosuspend(&data->client->dev);374 }375 376 return ret;377}378 379static int us5182d_read_value(struct us5182d_data *data,380 struct iio_chan_spec const *chan)381{382 int ret, value;383 384 mutex_lock(&data->lock);385 386 if (data->power_mode == US5182D_ONESHOT) {387 ret = us5182d_oneshot_en(data);388 if (ret < 0)389 goto out_err;390 }391 392 ret = us5182d_set_power_state(data, true);393 if (ret < 0)394 goto out_err;395 396 if (chan->type == IIO_LIGHT)397 ret = us5182d_get_als(data);398 else399 ret = us5182d_get_px(data);400 if (ret < 0)401 goto out_poweroff;402 403 value = ret;404 405 ret = us5182d_set_power_state(data, false);406 if (ret < 0)407 goto out_err;408 409 mutex_unlock(&data->lock);410 return value;411 412out_poweroff:413 us5182d_set_power_state(data, false);414out_err:415 mutex_unlock(&data->lock);416 return ret;417}418 419static int us5182d_read_raw(struct iio_dev *indio_dev,420 struct iio_chan_spec const *chan, int *val,421 int *val2, long mask)422{423 struct us5182d_data *data = iio_priv(indio_dev);424 int ret;425 426 switch (mask) {427 case IIO_CHAN_INFO_RAW:428 ret = us5182d_read_value(data, chan);429 if (ret < 0)430 return ret;431 *val = ret;432 return IIO_VAL_INT;433 case IIO_CHAN_INFO_SCALE:434 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);435 if (ret < 0)436 return ret;437 *val = 0;438 *val2 = us5182d_scales[ret & US5182D_AGAIN_MASK];439 return IIO_VAL_INT_PLUS_MICRO;440 default:441 return -EINVAL;442 }443}444 445/**446 * us5182d_update_dark_th - update Darh_Th registers447 * @data: us5182d_data structure448 * @index: index in us5182d_dark_ths array to use for the updated value449 *450 * Function needs to be called with a lock held because it needs two i2c write451 * byte operations as these registers (0x27 0x28) don't work in word mode452 * accessing.453 */454static int us5182d_update_dark_th(struct us5182d_data *data, int index)455{456 __be16 dark_th = cpu_to_be16(data->us5182d_dark_ths[index]);457 int ret;458 459 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH,460 ((u8 *)&dark_th)[0]);461 if (ret < 0)462 return ret;463 464 return i2c_smbus_write_byte_data(data->client, US5182D_REG_UDARK_TH + 1,465 ((u8 *)&dark_th)[1]);466}467 468/**469 * us5182d_apply_scale - update the ALS scale470 * @data: us5182d_data structure471 * @index: index in us5182d_scales array to use for the updated value472 *473 * Function needs to be called with a lock held as we're having more than one474 * i2c operation.475 */476static int us5182d_apply_scale(struct us5182d_data *data, int index)477{478 int ret;479 480 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG1);481 if (ret < 0)482 return ret;483 484 ret = ret & (~US5182D_AGAIN_MASK);485 ret |= index;486 487 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG1, ret);488 if (ret < 0)489 return ret;490 491 return us5182d_update_dark_th(data, index);492}493 494static int us5182d_write_raw(struct iio_dev *indio_dev,495 struct iio_chan_spec const *chan, int val,496 int val2, long mask)497{498 struct us5182d_data *data = iio_priv(indio_dev);499 int ret, i;500 501 switch (mask) {502 case IIO_CHAN_INFO_SCALE:503 if (val != 0)504 return -EINVAL;505 for (i = 0; i < ARRAY_SIZE(us5182d_scales); i++)506 if (val2 == us5182d_scales[i]) {507 mutex_lock(&data->lock);508 ret = us5182d_apply_scale(data, i);509 mutex_unlock(&data->lock);510 return ret;511 }512 break;513 default:514 return -EINVAL;515 }516 517 return -EINVAL;518}519 520static int us5182d_setup_prox(struct iio_dev *indio_dev,521 enum iio_event_direction dir, u16 val)522{523 struct us5182d_data *data = iio_priv(indio_dev);524 525 if (dir == IIO_EV_DIR_FALLING)526 return i2c_smbus_write_word_data(data->client,527 US5182D_REG_PXL_TH, val);528 else if (dir == IIO_EV_DIR_RISING)529 return i2c_smbus_write_word_data(data->client,530 US5182D_REG_PXH_TH, val);531 532 return 0;533}534 535static int us5182d_read_thresh(struct iio_dev *indio_dev,536 const struct iio_chan_spec *chan, enum iio_event_type type,537 enum iio_event_direction dir, enum iio_event_info info, int *val,538 int *val2)539{540 struct us5182d_data *data = iio_priv(indio_dev);541 542 switch (dir) {543 case IIO_EV_DIR_RISING:544 mutex_lock(&data->lock);545 *val = data->px_high_th;546 mutex_unlock(&data->lock);547 break;548 case IIO_EV_DIR_FALLING:549 mutex_lock(&data->lock);550 *val = data->px_low_th;551 mutex_unlock(&data->lock);552 break;553 default:554 return -EINVAL;555 }556 557 return IIO_VAL_INT;558}559 560static int us5182d_write_thresh(struct iio_dev *indio_dev,561 const struct iio_chan_spec *chan, enum iio_event_type type,562 enum iio_event_direction dir, enum iio_event_info info, int val,563 int val2)564{565 struct us5182d_data *data = iio_priv(indio_dev);566 int ret;567 568 if (val < 0 || val > USHRT_MAX || val2 != 0)569 return -EINVAL;570 571 switch (dir) {572 case IIO_EV_DIR_RISING:573 mutex_lock(&data->lock);574 if (data->rising_en) {575 ret = us5182d_setup_prox(indio_dev, dir, val);576 if (ret < 0)577 goto err;578 }579 data->px_high_th = val;580 mutex_unlock(&data->lock);581 break;582 case IIO_EV_DIR_FALLING:583 mutex_lock(&data->lock);584 if (data->falling_en) {585 ret = us5182d_setup_prox(indio_dev, dir, val);586 if (ret < 0)587 goto err;588 }589 data->px_low_th = val;590 mutex_unlock(&data->lock);591 break;592 default:593 return -EINVAL;594 }595 596 return 0;597err:598 mutex_unlock(&data->lock);599 return ret;600}601 602static int us5182d_read_event_config(struct iio_dev *indio_dev,603 const struct iio_chan_spec *chan, enum iio_event_type type,604 enum iio_event_direction dir)605{606 struct us5182d_data *data = iio_priv(indio_dev);607 int ret;608 609 switch (dir) {610 case IIO_EV_DIR_RISING:611 mutex_lock(&data->lock);612 ret = data->rising_en;613 mutex_unlock(&data->lock);614 break;615 case IIO_EV_DIR_FALLING:616 mutex_lock(&data->lock);617 ret = data->falling_en;618 mutex_unlock(&data->lock);619 break;620 default:621 ret = -EINVAL;622 break;623 }624 625 return ret;626}627 628static int us5182d_write_event_config(struct iio_dev *indio_dev,629 const struct iio_chan_spec *chan, enum iio_event_type type,630 enum iio_event_direction dir, int state)631{632 struct us5182d_data *data = iio_priv(indio_dev);633 int ret;634 u16 new_th;635 636 mutex_lock(&data->lock);637 638 switch (dir) {639 case IIO_EV_DIR_RISING:640 if (data->rising_en == state) {641 mutex_unlock(&data->lock);642 return 0;643 }644 new_th = US5182D_PXH_TH_DISABLE;645 if (state) {646 data->power_mode = US5182D_CONTINUOUS;647 ret = us5182d_set_power_state(data, true);648 if (ret < 0)649 goto err;650 ret = us5182d_px_enable(data);651 if (ret < 0)652 goto err_poweroff;653 new_th = data->px_high_th;654 }655 ret = us5182d_setup_prox(indio_dev, dir, new_th);656 if (ret < 0)657 goto err_poweroff;658 data->rising_en = state;659 break;660 case IIO_EV_DIR_FALLING:661 if (data->falling_en == state) {662 mutex_unlock(&data->lock);663 return 0;664 }665 new_th = US5182D_PXL_TH_DISABLE;666 if (state) {667 data->power_mode = US5182D_CONTINUOUS;668 ret = us5182d_set_power_state(data, true);669 if (ret < 0)670 goto err;671 ret = us5182d_px_enable(data);672 if (ret < 0)673 goto err_poweroff;674 new_th = data->px_low_th;675 }676 ret = us5182d_setup_prox(indio_dev, dir, new_th);677 if (ret < 0)678 goto err_poweroff;679 data->falling_en = state;680 break;681 default:682 ret = -EINVAL;683 goto err;684 }685 686 if (!state) {687 ret = us5182d_set_power_state(data, false);688 if (ret < 0)689 goto err;690 }691 692 if (!data->falling_en && !data->rising_en && !data->default_continuous)693 data->power_mode = US5182D_ONESHOT;694 695 mutex_unlock(&data->lock);696 return 0;697 698err_poweroff:699 if (state)700 us5182d_set_power_state(data, false);701err:702 mutex_unlock(&data->lock);703 return ret;704}705 706static const struct iio_info us5182d_info = {707 .read_raw = us5182d_read_raw,708 .write_raw = us5182d_write_raw,709 .attrs = &us5182d_attr_group,710 .read_event_value = &us5182d_read_thresh,711 .write_event_value = &us5182d_write_thresh,712 .read_event_config = &us5182d_read_event_config,713 .write_event_config = &us5182d_write_event_config,714};715 716static int us5182d_reset(struct iio_dev *indio_dev)717{718 struct us5182d_data *data = iio_priv(indio_dev);719 720 return i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG3,721 US5182D_RESET_CHIP);722}723 724static int us5182d_init(struct iio_dev *indio_dev)725{726 struct us5182d_data *data = iio_priv(indio_dev);727 int i, ret;728 729 ret = us5182d_reset(indio_dev);730 if (ret < 0)731 return ret;732 733 data->opmode = 0;734 data->power_mode = US5182D_CONTINUOUS;735 data->px_low_th = US5182D_REG_PXL_TH_DEFAULT;736 data->px_high_th = US5182D_REG_PXH_TH_DEFAULT;737 738 for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {739 ret = i2c_smbus_write_byte_data(data->client,740 us5182d_regvals[i].reg,741 us5182d_regvals[i].val);742 if (ret < 0)743 return ret;744 }745 746 data->als_enabled = true;747 data->px_enabled = true;748 749 if (!data->default_continuous) {750 ret = us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);751 if (ret < 0)752 return ret;753 data->power_mode = US5182D_ONESHOT;754 }755 756 return ret;757}758 759static void us5182d_get_platform_data(struct iio_dev *indio_dev)760{761 struct us5182d_data *data = iio_priv(indio_dev);762 763 if (device_property_read_u32(&data->client->dev, "upisemi,glass-coef",764 &data->ga))765 data->ga = US5182D_GA_RESOLUTION;766 if (device_property_read_u16_array(&data->client->dev,767 "upisemi,dark-ths",768 data->us5182d_dark_ths,769 ARRAY_SIZE(us5182d_dark_ths_vals)))770 data->us5182d_dark_ths = us5182d_dark_ths_vals;771 if (device_property_read_u8(&data->client->dev,772 "upisemi,upper-dark-gain",773 &data->upper_dark_gain))774 data->upper_dark_gain = US5182D_REG_AUTO_HDARK_GAIN_DEFAULT;775 if (device_property_read_u8(&data->client->dev,776 "upisemi,lower-dark-gain",777 &data->lower_dark_gain))778 data->lower_dark_gain = US5182D_REG_AUTO_LDARK_GAIN_DEFAULT;779 data->default_continuous = device_property_read_bool(&data->client->dev,780 "upisemi,continuous");781}782 783static int us5182d_dark_gain_config(struct iio_dev *indio_dev)784{785 struct us5182d_data *data = iio_priv(indio_dev);786 int ret;787 788 ret = us5182d_update_dark_th(data, US5182D_CFG1_AGAIN_DEFAULT);789 if (ret < 0)790 return ret;791 792 ret = i2c_smbus_write_byte_data(data->client,793 US5182D_REG_AUTO_LDARK_GAIN,794 data->lower_dark_gain);795 if (ret < 0)796 return ret;797 798 ret = i2c_smbus_write_byte_data(data->client,799 US5182D_REG_AUTO_HDARK_GAIN,800 data->upper_dark_gain);801 if (ret < 0)802 return ret;803 804 return i2c_smbus_write_byte_data(data->client, US5182D_REG_DARK_AUTO_EN,805 US5182D_REG_DARK_AUTO_EN_DEFAULT);806}807 808static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)809{810 struct iio_dev *indio_dev = private;811 struct us5182d_data *data = iio_priv(indio_dev);812 enum iio_event_direction dir;813 int ret;814 u64 ev;815 816 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);817 if (ret < 0) {818 dev_err(&data->client->dev, "i2c transfer error in irq\n");819 return IRQ_HANDLED;820 }821 822 dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;823 ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir);824 825 iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));826 827 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0,828 ret & ~US5182D_CFG0_PX_IRQ);829 if (ret < 0)830 dev_err(&data->client->dev, "i2c transfer error in irq\n");831 832 return IRQ_HANDLED;833}834 835static int us5182d_probe(struct i2c_client *client)836{837 struct us5182d_data *data;838 struct iio_dev *indio_dev;839 int ret;840 841 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));842 if (!indio_dev)843 return -ENOMEM;844 845 data = iio_priv(indio_dev);846 i2c_set_clientdata(client, indio_dev);847 data->client = client;848 849 mutex_init(&data->lock);850 851 indio_dev->info = &us5182d_info;852 indio_dev->name = US5182D_DRV_NAME;853 indio_dev->channels = us5182d_channels;854 indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);855 indio_dev->modes = INDIO_DIRECT_MODE;856 857 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);858 if (ret != US5182D_CHIPID) {859 dev_err(&data->client->dev,860 "Failed to detect US5182 light chip\n");861 return (ret < 0) ? ret : -ENODEV;862 }863 864 if (client->irq > 0) {865 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,866 us5182d_irq_thread_handler,867 IRQF_TRIGGER_LOW | IRQF_ONESHOT,868 "us5182d-irq", indio_dev);869 if (ret < 0)870 return ret;871 } else872 dev_warn(&client->dev, "no valid irq found\n");873 874 us5182d_get_platform_data(indio_dev);875 ret = us5182d_init(indio_dev);876 if (ret < 0)877 return ret;878 879 ret = us5182d_dark_gain_config(indio_dev);880 if (ret < 0)881 goto out_err;882 883 if (data->default_continuous) {884 ret = pm_runtime_set_active(&client->dev);885 if (ret < 0)886 goto out_err;887 }888 889 pm_runtime_enable(&client->dev);890 pm_runtime_set_autosuspend_delay(&client->dev,891 US5182D_SLEEP_MS);892 pm_runtime_use_autosuspend(&client->dev);893 894 ret = iio_device_register(indio_dev);895 if (ret < 0)896 goto out_err;897 898 return 0;899 900out_err:901 us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);902 return ret;903 904}905 906static void us5182d_remove(struct i2c_client *client)907{908 struct us5182d_data *data = iio_priv(i2c_get_clientdata(client));909 int ret;910 911 iio_device_unregister(i2c_get_clientdata(client));912 913 pm_runtime_disable(&client->dev);914 pm_runtime_set_suspended(&client->dev);915 916 ret = us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);917 if (ret)918 dev_warn(&client->dev, "Failed to shut down (%pe)\n",919 ERR_PTR(ret));920}921 922static int us5182d_suspend(struct device *dev)923{924 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));925 struct us5182d_data *data = iio_priv(indio_dev);926 927 if (data->power_mode == US5182D_CONTINUOUS)928 return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);929 930 return 0;931}932 933static int us5182d_resume(struct device *dev)934{935 struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));936 struct us5182d_data *data = iio_priv(indio_dev);937 938 if (data->power_mode == US5182D_CONTINUOUS)939 return us5182d_shutdown_en(data,940 ~US5182D_CFG0_SHUTDOWN_EN & 0xff);941 942 return 0;943}944 945static const struct dev_pm_ops us5182d_pm_ops = {946 SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume)947 RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL)948};949 950static const struct acpi_device_id us5182d_acpi_match[] = {951 { "USD5182", 0 },952 {}953};954 955MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);956 957static const struct i2c_device_id us5182d_id[] = {958 { "usd5182" },959 {}960};961 962MODULE_DEVICE_TABLE(i2c, us5182d_id);963 964static const struct of_device_id us5182d_of_match[] = {965 { .compatible = "upisemi,usd5182" },966 {}967};968MODULE_DEVICE_TABLE(of, us5182d_of_match);969 970static struct i2c_driver us5182d_driver = {971 .driver = {972 .name = US5182D_DRV_NAME,973 .pm = pm_ptr(&us5182d_pm_ops),974 .of_match_table = us5182d_of_match,975 .acpi_match_table = us5182d_acpi_match,976 },977 .probe = us5182d_probe,978 .remove = us5182d_remove,979 .id_table = us5182d_id,980 981};982module_i2c_driver(us5182d_driver);983 984MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");985MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");986MODULE_LICENSE("GPL v2");987