linux/drivers/iio/light/us5182d.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2015 Intel Corporation
   4 *
   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/acpi.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                                0x00
  25#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                                0x01
  32#define US5182D_CFG1_ALS_RES16                          BIT(4)
  33#define US5182D_CFG1_AGAIN_DEFAULT                      0x00
  34
  35#define US5182D_REG_CFG2                                0x02
  36#define US5182D_CFG2_PX_RES16                           BIT(4)
  37#define US5182D_CFG2_PXGAIN_DEFAULT                     BIT(2)
  38
  39#define US5182D_REG_CFG3                                0x03
  40#define US5182D_CFG3_LED_CURRENT100                     (BIT(4) | BIT(5))
  41#define US5182D_CFG3_INT_SOURCE_PX                      BIT(3)
  42
  43#define US5182D_REG_CFG4                                0x10
  44
  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) * Dark
  49 * when ALS < DARK_TH --> ALS_Code = ALS - Lower(0x29) * Dark
  50 */
  51#define US5182D_REG_UDARK_TH                    0x27
  52#define US5182D_REG_DARK_AUTO_EN                0x2b
  53#define US5182D_REG_AUTO_LDARK_GAIN             0x29
  54#define US5182D_REG_AUTO_HDARK_GAIN             0x2a
  55
  56/* Thresholds for events: px low (0x08-l, 0x09-h), px high (0x0a-l 0x0b-h) */
  57#define US5182D_REG_PXL_TH                      0x08
  58#define US5182D_REG_PXH_TH                      0x0a
  59
  60#define US5182D_REG_PXL_TH_DEFAULT              1000
  61#define US5182D_REG_PXH_TH_DEFAULT              30000
  62
  63#define US5182D_OPMODE_ALS                      0x01
  64#define US5182D_OPMODE_PX                       0x02
  65#define US5182D_OPMODE_SHIFT                    4
  66
  67#define US5182D_REG_DARK_AUTO_EN_DEFAULT        0x80
  68#define US5182D_REG_AUTO_LDARK_GAIN_DEFAULT     0x16
  69#define US5182D_REG_AUTO_HDARK_GAIN_DEFAULT     0x00
  70
  71#define US5182D_REG_ADL                         0x0c
  72#define US5182D_REG_PDL                         0x0e
  73
  74#define US5182D_REG_MODE_STORE                  0x21
  75#define US5182D_STORE_MODE                      0x01
  76
  77#define US5182D_REG_CHIPID                      0xb2
  78
  79#define US5182D_OPMODE_MASK                     GENMASK(5, 4)
  80#define US5182D_AGAIN_MASK                      0x07
  81#define US5182D_RESET_CHIP                      0x01
  82
  83#define US5182D_CHIPID                          0x26
  84#define US5182D_DRV_NAME                        "us5182d"
  85
  86#define US5182D_GA_RESOLUTION                   1000
  87
  88#define US5182D_READ_BYTE                       1
  89#define US5182D_READ_WORD                       2
  90#define US5182D_OPSTORE_SLEEP_TIME              20 /* ms */
  91#define US5182D_SLEEP_MS                        3000 /* ms */
  92#define US5182D_PXH_TH_DISABLE                  0xffff
  93#define US5182D_PXL_TH_DISABLE                  0x0000
  94
  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 board
 101 * roughly between 12-32 lux
 102 */
 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_ONLY
 110};
 111
 112enum pmode {
 113        US5182D_CONTINUOUS,
 114        US5182D_ONESHOT
 115};
 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        NULL
 150};
 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 the
 208         * 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 that
 232         * the operation is stored, by writing 1 in the STORE_MODE
 233         * 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        else
 399                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 registers
 447 * @data:       us5182d_data structure
 448 * @index:      index in us5182d_dark_ths array to use for the updated value
 449 *
 450 * Function needs to be called with a lock held because it needs two i2c write
 451 * byte operations as these registers (0x27 0x28) don't work in word mode
 452 * 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 scale
 470 * @data:       us5182d_data structure
 471 * @index:      index in us5182d_scales array to use for the updated value
 472 *
 473 * Function needs to be called with a lock held as we're having more than one
 474 * 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                         const struct i2c_device_id *id)
 837{
 838        struct us5182d_data *data;
 839        struct iio_dev *indio_dev;
 840        int ret;
 841
 842        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 843        if (!indio_dev)
 844                return -ENOMEM;
 845
 846        data = iio_priv(indio_dev);
 847        i2c_set_clientdata(client, indio_dev);
 848        data->client = client;
 849
 850        mutex_init(&data->lock);
 851
 852        indio_dev->info = &us5182d_info;
 853        indio_dev->name = US5182D_DRV_NAME;
 854        indio_dev->channels = us5182d_channels;
 855        indio_dev->num_channels = ARRAY_SIZE(us5182d_channels);
 856        indio_dev->modes = INDIO_DIRECT_MODE;
 857
 858        ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CHIPID);
 859        if (ret != US5182D_CHIPID) {
 860                dev_err(&data->client->dev,
 861                        "Failed to detect US5182 light chip\n");
 862                return (ret < 0) ? ret : -ENODEV;
 863        }
 864
 865        if (client->irq > 0) {
 866                ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
 867                                                us5182d_irq_thread_handler,
 868                                                IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 869                                                "us5182d-irq", indio_dev);
 870                if (ret < 0)
 871                        return ret;
 872        } else
 873                dev_warn(&client->dev, "no valid irq found\n");
 874
 875        us5182d_get_platform_data(indio_dev);
 876        ret = us5182d_init(indio_dev);
 877        if (ret < 0)
 878                return ret;
 879
 880        ret = us5182d_dark_gain_config(indio_dev);
 881        if (ret < 0)
 882                goto out_err;
 883
 884        if (data->default_continuous) {
 885                ret = pm_runtime_set_active(&client->dev);
 886                if (ret < 0)
 887                        goto out_err;
 888        }
 889
 890        pm_runtime_enable(&client->dev);
 891        pm_runtime_set_autosuspend_delay(&client->dev,
 892                                         US5182D_SLEEP_MS);
 893        pm_runtime_use_autosuspend(&client->dev);
 894
 895        ret = iio_device_register(indio_dev);
 896        if (ret < 0)
 897                goto out_err;
 898
 899        return 0;
 900
 901out_err:
 902        us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
 903        return ret;
 904
 905}
 906
 907static int us5182d_remove(struct i2c_client *client)
 908{
 909        struct us5182d_data *data = iio_priv(i2c_get_clientdata(client));
 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        return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
 917}
 918
 919#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
 920static int us5182d_suspend(struct device *dev)
 921{
 922        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 923        struct us5182d_data *data = iio_priv(indio_dev);
 924
 925        if (data->power_mode == US5182D_CONTINUOUS)
 926                return us5182d_shutdown_en(data, US5182D_CFG0_SHUTDOWN_EN);
 927
 928        return 0;
 929}
 930
 931static int us5182d_resume(struct device *dev)
 932{
 933        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 934        struct us5182d_data *data = iio_priv(indio_dev);
 935
 936        if (data->power_mode == US5182D_CONTINUOUS)
 937                return us5182d_shutdown_en(data,
 938                                           ~US5182D_CFG0_SHUTDOWN_EN & 0xff);
 939
 940        return 0;
 941}
 942#endif
 943
 944static const struct dev_pm_ops us5182d_pm_ops = {
 945        SET_SYSTEM_SLEEP_PM_OPS(us5182d_suspend, us5182d_resume)
 946        SET_RUNTIME_PM_OPS(us5182d_suspend, us5182d_resume, NULL)
 947};
 948
 949static const struct acpi_device_id us5182d_acpi_match[] = {
 950        { "USD5182", 0 },
 951        {}
 952};
 953
 954MODULE_DEVICE_TABLE(acpi, us5182d_acpi_match);
 955
 956static const struct i2c_device_id us5182d_id[] = {
 957        { "usd5182", 0 },
 958        {}
 959};
 960
 961MODULE_DEVICE_TABLE(i2c, us5182d_id);
 962
 963static const struct of_device_id us5182d_of_match[] = {
 964        { .compatible = "upisemi,usd5182" },
 965        {}
 966};
 967MODULE_DEVICE_TABLE(of, us5182d_of_match);
 968
 969static struct i2c_driver us5182d_driver = {
 970        .driver = {
 971                .name = US5182D_DRV_NAME,
 972                .pm = &us5182d_pm_ops,
 973                .of_match_table = us5182d_of_match,
 974                .acpi_match_table = ACPI_PTR(us5182d_acpi_match),
 975        },
 976        .probe = us5182d_probe,
 977        .remove = us5182d_remove,
 978        .id_table = us5182d_id,
 979
 980};
 981module_i2c_driver(us5182d_driver);
 982
 983MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
 984MODULE_DESCRIPTION("Driver for us5182d Proximity and Light Sensor");
 985MODULE_LICENSE("GPL v2");
 986