linux/drivers/iio/light/rpr0521.c
<<
>>
Prefs
   1/*
   2 * RPR-0521 ROHM Ambient Light and Proximity Sensor
   3 *
   4 * Copyright (c) 2015, Intel Corporation.
   5 *
   6 * This file is subject to the terms and conditions of version 2 of
   7 * the GNU General Public License.  See the file COPYING in the main
   8 * directory of this archive for more details.
   9 *
  10 * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
  11 *
  12 * TODO: illuminance channel, PM support, buffer
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/i2c.h>
  18#include <linux/regmap.h>
  19#include <linux/delay.h>
  20#include <linux/acpi.h>
  21
  22#include <linux/iio/iio.h>
  23#include <linux/iio/sysfs.h>
  24#include <linux/pm_runtime.h>
  25
  26#define RPR0521_REG_SYSTEM_CTRL         0x40
  27#define RPR0521_REG_MODE_CTRL           0x41
  28#define RPR0521_REG_ALS_CTRL            0x42
  29#define RPR0521_REG_PXS_CTRL            0x43
  30#define RPR0521_REG_PXS_DATA            0x44 /* 16-bit, little endian */
  31#define RPR0521_REG_ALS_DATA0           0x46 /* 16-bit, little endian */
  32#define RPR0521_REG_ALS_DATA1           0x48 /* 16-bit, little endian */
  33#define RPR0521_REG_ID                  0x92
  34
  35#define RPR0521_MODE_ALS_MASK           BIT(7)
  36#define RPR0521_MODE_PXS_MASK           BIT(6)
  37#define RPR0521_MODE_MEAS_TIME_MASK     GENMASK(3, 0)
  38#define RPR0521_ALS_DATA0_GAIN_MASK     GENMASK(5, 4)
  39#define RPR0521_ALS_DATA0_GAIN_SHIFT    4
  40#define RPR0521_ALS_DATA1_GAIN_MASK     GENMASK(3, 2)
  41#define RPR0521_ALS_DATA1_GAIN_SHIFT    2
  42#define RPR0521_PXS_GAIN_MASK           GENMASK(5, 4)
  43#define RPR0521_PXS_GAIN_SHIFT          4
  44
  45#define RPR0521_MODE_ALS_ENABLE         BIT(7)
  46#define RPR0521_MODE_ALS_DISABLE        0x00
  47#define RPR0521_MODE_PXS_ENABLE         BIT(6)
  48#define RPR0521_MODE_PXS_DISABLE        0x00
  49
  50#define RPR0521_MANUFACT_ID             0xE0
  51#define RPR0521_DEFAULT_MEAS_TIME       0x06 /* ALS - 100ms, PXS - 100ms */
  52
  53#define RPR0521_DRV_NAME                "RPR0521"
  54#define RPR0521_REGMAP_NAME             "rpr0521_regmap"
  55
  56#define RPR0521_SLEEP_DELAY_MS  2000
  57
  58#define RPR0521_ALS_SCALE_AVAIL "0.007812 0.015625 0.5 1"
  59#define RPR0521_PXS_SCALE_AVAIL "0.125 0.5 1"
  60
  61struct rpr0521_gain {
  62        int scale;
  63        int uscale;
  64};
  65
  66static const struct rpr0521_gain rpr0521_als_gain[4] = {
  67        {1, 0},         /* x1 */
  68        {0, 500000},    /* x2 */
  69        {0, 15625},     /* x64 */
  70        {0, 7812},      /* x128 */
  71};
  72
  73static const struct rpr0521_gain rpr0521_pxs_gain[3] = {
  74        {1, 0},         /* x1 */
  75        {0, 500000},    /* x2 */
  76        {0, 125000},    /* x4 */
  77};
  78
  79enum rpr0521_channel {
  80        RPR0521_CHAN_ALS_DATA0,
  81        RPR0521_CHAN_ALS_DATA1,
  82        RPR0521_CHAN_PXS,
  83};
  84
  85struct rpr0521_reg_desc {
  86        u8 address;
  87        u8 device_mask;
  88};
  89
  90static const struct rpr0521_reg_desc rpr0521_data_reg[] = {
  91        [RPR0521_CHAN_ALS_DATA0] = {
  92                .address        = RPR0521_REG_ALS_DATA0,
  93                .device_mask    = RPR0521_MODE_ALS_MASK,
  94        },
  95        [RPR0521_CHAN_ALS_DATA1] = {
  96                .address        = RPR0521_REG_ALS_DATA1,
  97                .device_mask    = RPR0521_MODE_ALS_MASK,
  98        },
  99        [RPR0521_CHAN_PXS]      = {
 100                .address        = RPR0521_REG_PXS_DATA,
 101                .device_mask    = RPR0521_MODE_PXS_MASK,
 102        },
 103};
 104
 105static const struct rpr0521_gain_info {
 106        u8 reg;
 107        u8 mask;
 108        u8 shift;
 109        const struct rpr0521_gain *gain;
 110        int size;
 111} rpr0521_gain[] = {
 112        [RPR0521_CHAN_ALS_DATA0] = {
 113                .reg    = RPR0521_REG_ALS_CTRL,
 114                .mask   = RPR0521_ALS_DATA0_GAIN_MASK,
 115                .shift  = RPR0521_ALS_DATA0_GAIN_SHIFT,
 116                .gain   = rpr0521_als_gain,
 117                .size   = ARRAY_SIZE(rpr0521_als_gain),
 118        },
 119        [RPR0521_CHAN_ALS_DATA1] = {
 120                .reg    = RPR0521_REG_ALS_CTRL,
 121                .mask   = RPR0521_ALS_DATA1_GAIN_MASK,
 122                .shift  = RPR0521_ALS_DATA1_GAIN_SHIFT,
 123                .gain   = rpr0521_als_gain,
 124                .size   = ARRAY_SIZE(rpr0521_als_gain),
 125        },
 126        [RPR0521_CHAN_PXS] = {
 127                .reg    = RPR0521_REG_PXS_CTRL,
 128                .mask   = RPR0521_PXS_GAIN_MASK,
 129                .shift  = RPR0521_PXS_GAIN_SHIFT,
 130                .gain   = rpr0521_pxs_gain,
 131                .size   = ARRAY_SIZE(rpr0521_pxs_gain),
 132        },
 133};
 134
 135struct rpr0521_data {
 136        struct i2c_client *client;
 137
 138        /* protect device params updates (e.g state, gain) */
 139        struct mutex lock;
 140
 141        /* device active status */
 142        bool als_dev_en;
 143        bool pxs_dev_en;
 144
 145        /* optimize runtime pm ops - enable device only if needed */
 146        bool als_ps_need_en;
 147        bool pxs_ps_need_en;
 148
 149        struct regmap *regmap;
 150};
 151
 152static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
 153static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL);
 154
 155static struct attribute *rpr0521_attributes[] = {
 156        &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
 157        &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
 158        NULL,
 159};
 160
 161static const struct attribute_group rpr0521_attribute_group = {
 162        .attrs = rpr0521_attributes,
 163};
 164
 165static const struct iio_chan_spec rpr0521_channels[] = {
 166        {
 167                .type = IIO_INTENSITY,
 168                .modified = 1,
 169                .address = RPR0521_CHAN_ALS_DATA0,
 170                .channel2 = IIO_MOD_LIGHT_BOTH,
 171                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 172                        BIT(IIO_CHAN_INFO_SCALE),
 173        },
 174        {
 175                .type = IIO_INTENSITY,
 176                .modified = 1,
 177                .address = RPR0521_CHAN_ALS_DATA1,
 178                .channel2 = IIO_MOD_LIGHT_IR,
 179                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 180                        BIT(IIO_CHAN_INFO_SCALE),
 181        },
 182        {
 183                .type = IIO_PROXIMITY,
 184                .address = RPR0521_CHAN_PXS,
 185                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 186                        BIT(IIO_CHAN_INFO_SCALE),
 187        }
 188};
 189
 190static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
 191{
 192        int ret;
 193
 194        ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
 195                                 RPR0521_MODE_ALS_MASK,
 196                                 status);
 197        if (ret < 0)
 198                return ret;
 199
 200        data->als_dev_en = true;
 201
 202        return 0;
 203}
 204
 205static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status)
 206{
 207        int ret;
 208
 209        ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
 210                                 RPR0521_MODE_PXS_MASK,
 211                                 status);
 212        if (ret < 0)
 213                return ret;
 214
 215        data->pxs_dev_en = true;
 216
 217        return 0;
 218}
 219
 220/**
 221 * rpr0521_set_power_state - handles runtime PM state and sensors enabled status
 222 *
 223 * @data: rpr0521 device private data
 224 * @on: state to be set for devices in @device_mask
 225 * @device_mask: bitmask specifying for which device we need to update @on state
 226 *
 227 * We rely on rpr0521_runtime_resume to enable our @device_mask devices, but
 228 * if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to
 229 * rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable
 230 * bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not
 231 * be called twice.
 232 */
 233static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
 234                                   u8 device_mask)
 235{
 236#ifdef CONFIG_PM
 237        int ret;
 238        u8 update_mask = 0;
 239
 240        if (device_mask & RPR0521_MODE_ALS_MASK) {
 241                if (on && !data->als_ps_need_en && data->pxs_dev_en)
 242                        update_mask |= RPR0521_MODE_ALS_MASK;
 243                else
 244                        data->als_ps_need_en = on;
 245        }
 246
 247        if (device_mask & RPR0521_MODE_PXS_MASK) {
 248                if (on && !data->pxs_ps_need_en && data->als_dev_en)
 249                        update_mask |= RPR0521_MODE_PXS_MASK;
 250                else
 251                        data->pxs_ps_need_en = on;
 252        }
 253
 254        if (update_mask) {
 255                ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
 256                                         update_mask, update_mask);
 257                if (ret < 0)
 258                        return ret;
 259        }
 260
 261        if (on) {
 262                ret = pm_runtime_get_sync(&data->client->dev);
 263        } else {
 264                pm_runtime_mark_last_busy(&data->client->dev);
 265                ret = pm_runtime_put_autosuspend(&data->client->dev);
 266        }
 267        if (ret < 0) {
 268                dev_err(&data->client->dev,
 269                        "Failed: rpr0521_set_power_state for %d, ret %d\n",
 270                        on, ret);
 271                if (on)
 272                        pm_runtime_put_noidle(&data->client->dev);
 273
 274                return ret;
 275        }
 276#endif
 277        return 0;
 278}
 279
 280static int rpr0521_get_gain(struct rpr0521_data *data, int chan,
 281                            int *val, int *val2)
 282{
 283        int ret, reg, idx;
 284
 285        ret = regmap_read(data->regmap, rpr0521_gain[chan].reg, &reg);
 286        if (ret < 0)
 287                return ret;
 288
 289        idx = (rpr0521_gain[chan].mask & reg) >> rpr0521_gain[chan].shift;
 290        *val = rpr0521_gain[chan].gain[idx].scale;
 291        *val2 = rpr0521_gain[chan].gain[idx].uscale;
 292
 293        return 0;
 294}
 295
 296static int rpr0521_set_gain(struct rpr0521_data *data, int chan,
 297                            int val, int val2)
 298{
 299        int i, idx = -EINVAL;
 300
 301        /* get gain index */
 302        for (i = 0; i < rpr0521_gain[chan].size; i++)
 303                if (val == rpr0521_gain[chan].gain[i].scale &&
 304                    val2 == rpr0521_gain[chan].gain[i].uscale) {
 305                        idx = i;
 306                        break;
 307                }
 308
 309        if (idx < 0)
 310                return idx;
 311
 312        return regmap_update_bits(data->regmap, rpr0521_gain[chan].reg,
 313                                  rpr0521_gain[chan].mask,
 314                                  idx << rpr0521_gain[chan].shift);
 315}
 316
 317static int rpr0521_read_raw(struct iio_dev *indio_dev,
 318                            struct iio_chan_spec const *chan, int *val,
 319                            int *val2, long mask)
 320{
 321        struct rpr0521_data *data = iio_priv(indio_dev);
 322        int ret;
 323        u8 device_mask;
 324        __le16 raw_data;
 325
 326        switch (mask) {
 327        case IIO_CHAN_INFO_RAW:
 328                if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
 329                        return -EINVAL;
 330
 331                device_mask = rpr0521_data_reg[chan->address].device_mask;
 332
 333                mutex_lock(&data->lock);
 334                ret = rpr0521_set_power_state(data, true, device_mask);
 335                if (ret < 0) {
 336                        mutex_unlock(&data->lock);
 337                        return ret;
 338                }
 339
 340                ret = regmap_bulk_read(data->regmap,
 341                                       rpr0521_data_reg[chan->address].address,
 342                                       &raw_data, 2);
 343                if (ret < 0) {
 344                        rpr0521_set_power_state(data, false, device_mask);
 345                        mutex_unlock(&data->lock);
 346                        return ret;
 347                }
 348
 349                ret = rpr0521_set_power_state(data, false, device_mask);
 350                mutex_unlock(&data->lock);
 351                if (ret < 0)
 352                        return ret;
 353
 354                *val = le16_to_cpu(raw_data);
 355
 356                return IIO_VAL_INT;
 357        case IIO_CHAN_INFO_SCALE:
 358                mutex_lock(&data->lock);
 359                ret = rpr0521_get_gain(data, chan->address, val, val2);
 360                mutex_unlock(&data->lock);
 361                if (ret < 0)
 362                        return ret;
 363
 364                return IIO_VAL_INT_PLUS_MICRO;
 365        default:
 366                return -EINVAL;
 367        }
 368}
 369
 370static int rpr0521_write_raw(struct iio_dev *indio_dev,
 371                             struct iio_chan_spec const *chan, int val,
 372                             int val2, long mask)
 373{
 374        struct rpr0521_data *data = iio_priv(indio_dev);
 375        int ret;
 376
 377        switch (mask) {
 378        case IIO_CHAN_INFO_SCALE:
 379                mutex_lock(&data->lock);
 380                ret = rpr0521_set_gain(data, chan->address, val, val2);
 381                mutex_unlock(&data->lock);
 382
 383                return ret;
 384        default:
 385                return -EINVAL;
 386        }
 387}
 388
 389static const struct iio_info rpr0521_info = {
 390        .driver_module  = THIS_MODULE,
 391        .read_raw       = rpr0521_read_raw,
 392        .write_raw      = rpr0521_write_raw,
 393        .attrs          = &rpr0521_attribute_group,
 394};
 395
 396static int rpr0521_init(struct rpr0521_data *data)
 397{
 398        int ret;
 399        int id;
 400
 401        ret = regmap_read(data->regmap, RPR0521_REG_ID, &id);
 402        if (ret < 0) {
 403                dev_err(&data->client->dev, "Failed to read REG_ID register\n");
 404                return ret;
 405        }
 406
 407        if (id != RPR0521_MANUFACT_ID) {
 408                dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
 409                        id, RPR0521_MANUFACT_ID);
 410                return -ENODEV;
 411        }
 412
 413        /* set default measurement time - 100 ms for both ALS and PS */
 414        ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
 415                                 RPR0521_MODE_MEAS_TIME_MASK,
 416                                 RPR0521_DEFAULT_MEAS_TIME);
 417        if (ret) {
 418                pr_err("regmap_update_bits returned %d\n", ret);
 419                return ret;
 420        }
 421
 422        ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
 423        if (ret < 0)
 424                return ret;
 425        ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
 426        if (ret < 0)
 427                return ret;
 428
 429        return 0;
 430}
 431
 432static int rpr0521_poweroff(struct rpr0521_data *data)
 433{
 434        int ret;
 435
 436        ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
 437                                 RPR0521_MODE_ALS_MASK |
 438                                 RPR0521_MODE_PXS_MASK,
 439                                 RPR0521_MODE_ALS_DISABLE |
 440                                 RPR0521_MODE_PXS_DISABLE);
 441        if (ret < 0)
 442                return ret;
 443
 444        data->als_dev_en = false;
 445        data->pxs_dev_en = false;
 446
 447        return 0;
 448}
 449
 450static bool rpr0521_is_volatile_reg(struct device *dev, unsigned int reg)
 451{
 452        switch (reg) {
 453        case RPR0521_REG_MODE_CTRL:
 454        case RPR0521_REG_ALS_CTRL:
 455        case RPR0521_REG_PXS_CTRL:
 456                return false;
 457        default:
 458                return true;
 459        }
 460}
 461
 462static const struct regmap_config rpr0521_regmap_config = {
 463        .name           = RPR0521_REGMAP_NAME,
 464
 465        .reg_bits       = 8,
 466        .val_bits       = 8,
 467
 468        .max_register   = RPR0521_REG_ID,
 469        .cache_type     = REGCACHE_RBTREE,
 470        .volatile_reg   = rpr0521_is_volatile_reg,
 471};
 472
 473static int rpr0521_probe(struct i2c_client *client,
 474                         const struct i2c_device_id *id)
 475{
 476        struct rpr0521_data *data;
 477        struct iio_dev *indio_dev;
 478        struct regmap *regmap;
 479        int ret;
 480
 481        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 482        if (!indio_dev)
 483                return -ENOMEM;
 484
 485        regmap = devm_regmap_init_i2c(client, &rpr0521_regmap_config);
 486        if (IS_ERR(regmap)) {
 487                dev_err(&client->dev, "regmap_init failed!\n");
 488                return PTR_ERR(regmap);
 489        }
 490
 491        data = iio_priv(indio_dev);
 492        i2c_set_clientdata(client, indio_dev);
 493        data->client = client;
 494        data->regmap = regmap;
 495
 496        mutex_init(&data->lock);
 497
 498        indio_dev->dev.parent = &client->dev;
 499        indio_dev->info = &rpr0521_info;
 500        indio_dev->name = RPR0521_DRV_NAME;
 501        indio_dev->channels = rpr0521_channels;
 502        indio_dev->num_channels = ARRAY_SIZE(rpr0521_channels);
 503        indio_dev->modes = INDIO_DIRECT_MODE;
 504
 505        ret = rpr0521_init(data);
 506        if (ret < 0) {
 507                dev_err(&client->dev, "rpr0521 chip init failed\n");
 508                return ret;
 509        }
 510
 511        ret = pm_runtime_set_active(&client->dev);
 512        if (ret < 0)
 513                return ret;
 514
 515        pm_runtime_enable(&client->dev);
 516        pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
 517        pm_runtime_use_autosuspend(&client->dev);
 518
 519        return iio_device_register(indio_dev);
 520}
 521
 522static int rpr0521_remove(struct i2c_client *client)
 523{
 524        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 525
 526        iio_device_unregister(indio_dev);
 527
 528        pm_runtime_disable(&client->dev);
 529        pm_runtime_set_suspended(&client->dev);
 530        pm_runtime_put_noidle(&client->dev);
 531
 532        rpr0521_poweroff(iio_priv(indio_dev));
 533
 534        return 0;
 535}
 536
 537#ifdef CONFIG_PM
 538static int rpr0521_runtime_suspend(struct device *dev)
 539{
 540        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 541        struct rpr0521_data *data = iio_priv(indio_dev);
 542        int ret;
 543
 544        /* disable channels and sets {als,pxs}_dev_en to false */
 545        mutex_lock(&data->lock);
 546        ret = rpr0521_poweroff(data);
 547        mutex_unlock(&data->lock);
 548
 549        return ret;
 550}
 551
 552static int rpr0521_runtime_resume(struct device *dev)
 553{
 554        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 555        struct rpr0521_data *data = iio_priv(indio_dev);
 556        int ret;
 557
 558        if (data->als_ps_need_en) {
 559                ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
 560                if (ret < 0)
 561                        return ret;
 562                data->als_ps_need_en = false;
 563        }
 564
 565        if (data->pxs_ps_need_en) {
 566                ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
 567                if (ret < 0)
 568                        return ret;
 569                data->pxs_ps_need_en = false;
 570        }
 571
 572        return 0;
 573}
 574#endif
 575
 576static const struct dev_pm_ops rpr0521_pm_ops = {
 577        SET_RUNTIME_PM_OPS(rpr0521_runtime_suspend,
 578                           rpr0521_runtime_resume, NULL)
 579};
 580
 581static const struct acpi_device_id rpr0521_acpi_match[] = {
 582        {"RPR0521", 0},
 583        { }
 584};
 585MODULE_DEVICE_TABLE(acpi, rpr0521_acpi_match);
 586
 587static const struct i2c_device_id rpr0521_id[] = {
 588        {"rpr0521", 0},
 589        { }
 590};
 591
 592MODULE_DEVICE_TABLE(i2c, rpr0521_id);
 593
 594static struct i2c_driver rpr0521_driver = {
 595        .driver = {
 596                .name   = RPR0521_DRV_NAME,
 597                .pm     = &rpr0521_pm_ops,
 598                .acpi_match_table = ACPI_PTR(rpr0521_acpi_match),
 599        },
 600        .probe          = rpr0521_probe,
 601        .remove         = rpr0521_remove,
 602        .id_table       = rpr0521_id,
 603};
 604
 605module_i2c_driver(rpr0521_driver);
 606
 607MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
 608MODULE_DESCRIPTION("RPR0521 ROHM Ambient Light and Proximity Sensor driver");
 609MODULE_LICENSE("GPL v2");
 610