linux/drivers/iio/light/ltr501.c
<<
>>
Prefs
   1/*
   2 * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor
   3 *
   4 * Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
   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 * 7-bit I2C slave address 0x23
  11 *
  12 * TODO: interrupt, threshold, measurement rate, IR LED characteristics
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/i2c.h>
  17#include <linux/err.h>
  18#include <linux/delay.h>
  19
  20#include <linux/iio/iio.h>
  21#include <linux/iio/sysfs.h>
  22#include <linux/iio/trigger_consumer.h>
  23#include <linux/iio/buffer.h>
  24#include <linux/iio/triggered_buffer.h>
  25
  26#define LTR501_DRV_NAME "ltr501"
  27
  28#define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
  29#define LTR501_PS_CONTR 0x81 /* PS operation mode */
  30#define LTR501_PART_ID 0x86
  31#define LTR501_MANUFAC_ID 0x87
  32#define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
  33#define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
  34#define LTR501_ALS_PS_STATUS 0x8c
  35#define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
  36
  37#define LTR501_ALS_CONTR_SW_RESET BIT(2)
  38#define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
  39#define LTR501_CONTR_PS_GAIN_SHIFT 2
  40#define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
  41#define LTR501_CONTR_ACTIVE BIT(1)
  42
  43#define LTR501_STATUS_ALS_RDY BIT(2)
  44#define LTR501_STATUS_PS_RDY BIT(0)
  45
  46#define LTR501_PS_DATA_MASK 0x7ff
  47
  48struct ltr501_data {
  49        struct i2c_client *client;
  50        struct mutex lock_als, lock_ps;
  51        u8 als_contr, ps_contr;
  52};
  53
  54static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
  55{
  56        int tries = 100;
  57        int ret;
  58
  59        while (tries--) {
  60                ret = i2c_smbus_read_byte_data(data->client,
  61                        LTR501_ALS_PS_STATUS);
  62                if (ret < 0)
  63                        return ret;
  64                if ((ret & drdy_mask) == drdy_mask)
  65                        return 0;
  66                msleep(25);
  67        }
  68
  69        dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n");
  70        return -EIO;
  71}
  72
  73static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2])
  74{
  75        int ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY);
  76        if (ret < 0)
  77                return ret;
  78        /* always read both ALS channels in given order */
  79        return i2c_smbus_read_i2c_block_data(data->client,
  80                LTR501_ALS_DATA1, 2 * sizeof(__le16), (u8 *) buf);
  81}
  82
  83static int ltr501_read_ps(struct ltr501_data *data)
  84{
  85        int ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY);
  86        if (ret < 0)
  87                return ret;
  88        return i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
  89}
  90
  91#define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \
  92        .type = IIO_INTENSITY, \
  93        .modified = 1, \
  94        .address = (_addr), \
  95        .channel2 = (_mod), \
  96        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
  97        .info_mask_shared_by_type = (_shared), \
  98        .scan_index = (_idx), \
  99        .scan_type = { \
 100                .sign = 'u', \
 101                .realbits = 16, \
 102                .storagebits = 16, \
 103                .endianness = IIO_CPU, \
 104        } \
 105}
 106
 107static const struct iio_chan_spec ltr501_channels[] = {
 108        LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0),
 109        LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR,
 110                BIT(IIO_CHAN_INFO_SCALE)),
 111        {
 112                .type = IIO_PROXIMITY,
 113                .address = LTR501_PS_DATA,
 114                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 115                        BIT(IIO_CHAN_INFO_SCALE),
 116                .scan_index = 2,
 117                .scan_type = {
 118                        .sign = 'u',
 119                        .realbits = 11,
 120                        .storagebits = 16,
 121                        .endianness = IIO_CPU,
 122                },
 123        },
 124        IIO_CHAN_SOFT_TIMESTAMP(3),
 125};
 126
 127static const int ltr501_ps_gain[4][2] = {
 128        {1, 0}, {0, 250000}, {0, 125000}, {0, 62500}
 129};
 130
 131static int ltr501_read_raw(struct iio_dev *indio_dev,
 132                                struct iio_chan_spec const *chan,
 133                                int *val, int *val2, long mask)
 134{
 135        struct ltr501_data *data = iio_priv(indio_dev);
 136        __le16 buf[2];
 137        int ret, i;
 138
 139        switch (mask) {
 140        case IIO_CHAN_INFO_RAW:
 141                if (iio_buffer_enabled(indio_dev))
 142                        return -EBUSY;
 143
 144                switch (chan->type) {
 145                case IIO_INTENSITY:
 146                        mutex_lock(&data->lock_als);
 147                        ret = ltr501_read_als(data, buf);
 148                        mutex_unlock(&data->lock_als);
 149                        if (ret < 0)
 150                                return ret;
 151                        *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ?
 152                                buf[0] : buf[1]);
 153                        return IIO_VAL_INT;
 154                case IIO_PROXIMITY:
 155                        mutex_lock(&data->lock_ps);
 156                        ret = ltr501_read_ps(data);
 157                        mutex_unlock(&data->lock_ps);
 158                        if (ret < 0)
 159                                return ret;
 160                        *val = ret & LTR501_PS_DATA_MASK;
 161                        return IIO_VAL_INT;
 162                default:
 163                        return -EINVAL;
 164                }
 165        case IIO_CHAN_INFO_SCALE:
 166                switch (chan->type) {
 167                case IIO_INTENSITY:
 168                        if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) {
 169                                *val = 0;
 170                                *val2 = 5000;
 171                                return IIO_VAL_INT_PLUS_MICRO;
 172                        } else {
 173                                *val = 1;
 174                                *val2 = 0;
 175                                return IIO_VAL_INT;
 176                        }
 177                case IIO_PROXIMITY:
 178                        i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >>
 179                                LTR501_CONTR_PS_GAIN_SHIFT;
 180                        *val = ltr501_ps_gain[i][0];
 181                        *val2 = ltr501_ps_gain[i][1];
 182                        return IIO_VAL_INT_PLUS_MICRO;
 183                default:
 184                        return -EINVAL;
 185                }
 186        }
 187        return -EINVAL;
 188}
 189
 190static int ltr501_get_ps_gain_index(int val, int val2)
 191{
 192        int i;
 193
 194        for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++)
 195                if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1])
 196                        return i;
 197
 198        return -1;
 199}
 200
 201static int ltr501_write_raw(struct iio_dev *indio_dev,
 202                               struct iio_chan_spec const *chan,
 203                               int val, int val2, long mask)
 204{
 205        struct ltr501_data *data = iio_priv(indio_dev);
 206        int i;
 207
 208        if (iio_buffer_enabled(indio_dev))
 209                return -EBUSY;
 210
 211        switch (mask) {
 212        case IIO_CHAN_INFO_SCALE:
 213                switch (chan->type) {
 214                case IIO_INTENSITY:
 215                        if (val == 0 && val2 == 5000)
 216                                data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK;
 217                        else if (val == 1 && val2 == 0)
 218                                data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK;
 219                        else
 220                                return -EINVAL;
 221                        return i2c_smbus_write_byte_data(data->client,
 222                                LTR501_ALS_CONTR, data->als_contr);
 223                case IIO_PROXIMITY:
 224                        i = ltr501_get_ps_gain_index(val, val2);
 225                        if (i < 0)
 226                                return -EINVAL;
 227                        data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK;
 228                        data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT;
 229                        return i2c_smbus_write_byte_data(data->client,
 230                                LTR501_PS_CONTR, data->ps_contr);
 231                default:
 232                        return -EINVAL;
 233                }
 234        }
 235        return -EINVAL;
 236}
 237
 238static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625");
 239static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005");
 240
 241static struct attribute *ltr501_attributes[] = {
 242        &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
 243        &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
 244        NULL
 245};
 246
 247static const struct attribute_group ltr501_attribute_group = {
 248        .attrs = ltr501_attributes,
 249};
 250
 251static const struct iio_info ltr501_info = {
 252        .read_raw = ltr501_read_raw,
 253        .write_raw = ltr501_write_raw,
 254        .attrs = &ltr501_attribute_group,
 255        .driver_module = THIS_MODULE,
 256};
 257
 258static int ltr501_write_contr(struct i2c_client *client, u8 als_val, u8 ps_val)
 259{
 260        int ret = i2c_smbus_write_byte_data(client, LTR501_ALS_CONTR, als_val);
 261        if (ret < 0)
 262                return ret;
 263
 264        return i2c_smbus_write_byte_data(client, LTR501_PS_CONTR, ps_val);
 265}
 266
 267static irqreturn_t ltr501_trigger_handler(int irq, void *p)
 268{
 269        struct iio_poll_func *pf = p;
 270        struct iio_dev *indio_dev = pf->indio_dev;
 271        struct ltr501_data *data = iio_priv(indio_dev);
 272        u16 buf[8];
 273        __le16 als_buf[2];
 274        u8 mask = 0;
 275        int j = 0;
 276        int ret;
 277
 278        memset(buf, 0, sizeof(buf));
 279
 280        /* figure out which data needs to be ready */
 281        if (test_bit(0, indio_dev->active_scan_mask) ||
 282                test_bit(1, indio_dev->active_scan_mask))
 283                mask |= LTR501_STATUS_ALS_RDY;
 284        if (test_bit(2, indio_dev->active_scan_mask))
 285                mask |= LTR501_STATUS_PS_RDY;
 286
 287        ret = ltr501_drdy(data, mask);
 288        if (ret < 0)
 289                goto done;
 290
 291        if (mask & LTR501_STATUS_ALS_RDY) {
 292                ret = i2c_smbus_read_i2c_block_data(data->client,
 293                        LTR501_ALS_DATA1, sizeof(als_buf), (u8 *) als_buf);
 294                if (ret < 0)
 295                        return ret;
 296                if (test_bit(0, indio_dev->active_scan_mask))
 297                        buf[j++] = le16_to_cpu(als_buf[1]);
 298                if (test_bit(1, indio_dev->active_scan_mask))
 299                        buf[j++] = le16_to_cpu(als_buf[0]);
 300        }
 301
 302        if (mask & LTR501_STATUS_PS_RDY) {
 303                ret = i2c_smbus_read_word_data(data->client, LTR501_PS_DATA);
 304                if (ret < 0)
 305                        goto done;
 306                buf[j++] = ret & LTR501_PS_DATA_MASK;
 307        }
 308
 309        iio_push_to_buffers_with_timestamp(indio_dev, buf,
 310                iio_get_time_ns());
 311
 312done:
 313        iio_trigger_notify_done(indio_dev->trig);
 314
 315        return IRQ_HANDLED;
 316}
 317
 318static int ltr501_init(struct ltr501_data *data)
 319{
 320        int ret;
 321
 322        ret = i2c_smbus_read_byte_data(data->client, LTR501_ALS_CONTR);
 323        if (ret < 0)
 324                return ret;
 325        data->als_contr = ret | LTR501_CONTR_ACTIVE;
 326
 327        ret = i2c_smbus_read_byte_data(data->client, LTR501_PS_CONTR);
 328        if (ret < 0)
 329                return ret;
 330        data->ps_contr = ret | LTR501_CONTR_ACTIVE;
 331
 332        return ltr501_write_contr(data->client, data->als_contr,
 333                data->ps_contr);
 334}
 335
 336static int ltr501_powerdown(struct ltr501_data *data)
 337{
 338        return ltr501_write_contr(data->client,
 339                                  data->als_contr & ~LTR501_CONTR_ACTIVE,
 340                                  data->ps_contr & ~LTR501_CONTR_ACTIVE);
 341}
 342
 343static int ltr501_probe(struct i2c_client *client,
 344                          const struct i2c_device_id *id)
 345{
 346        struct ltr501_data *data;
 347        struct iio_dev *indio_dev;
 348        int ret;
 349
 350        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 351        if (!indio_dev)
 352                return -ENOMEM;
 353
 354        data = iio_priv(indio_dev);
 355        i2c_set_clientdata(client, indio_dev);
 356        data->client = client;
 357        mutex_init(&data->lock_als);
 358        mutex_init(&data->lock_ps);
 359
 360        ret = i2c_smbus_read_byte_data(data->client, LTR501_PART_ID);
 361        if (ret < 0)
 362                return ret;
 363        if ((ret >> 4) != 0x8)
 364                return -ENODEV;
 365
 366        indio_dev->dev.parent = &client->dev;
 367        indio_dev->info = &ltr501_info;
 368        indio_dev->channels = ltr501_channels;
 369        indio_dev->num_channels = ARRAY_SIZE(ltr501_channels);
 370        indio_dev->name = LTR501_DRV_NAME;
 371        indio_dev->modes = INDIO_DIRECT_MODE;
 372
 373        ret = ltr501_init(data);
 374        if (ret < 0)
 375                return ret;
 376
 377        ret = iio_triggered_buffer_setup(indio_dev, NULL,
 378                ltr501_trigger_handler, NULL);
 379        if (ret)
 380                goto powerdown_on_error;
 381
 382        ret = iio_device_register(indio_dev);
 383        if (ret)
 384                goto error_unreg_buffer;
 385
 386        return 0;
 387
 388error_unreg_buffer:
 389        iio_triggered_buffer_cleanup(indio_dev);
 390powerdown_on_error:
 391        ltr501_powerdown(data);
 392        return ret;
 393}
 394
 395static int ltr501_remove(struct i2c_client *client)
 396{
 397        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 398
 399        iio_device_unregister(indio_dev);
 400        iio_triggered_buffer_cleanup(indio_dev);
 401        ltr501_powerdown(iio_priv(indio_dev));
 402
 403        return 0;
 404}
 405
 406#ifdef CONFIG_PM_SLEEP
 407static int ltr501_suspend(struct device *dev)
 408{
 409        struct ltr501_data *data = iio_priv(i2c_get_clientdata(
 410                to_i2c_client(dev)));
 411        return ltr501_powerdown(data);
 412}
 413
 414static int ltr501_resume(struct device *dev)
 415{
 416        struct ltr501_data *data = iio_priv(i2c_get_clientdata(
 417                to_i2c_client(dev)));
 418
 419        return ltr501_write_contr(data->client, data->als_contr,
 420                data->ps_contr);
 421}
 422#endif
 423
 424static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume);
 425
 426static const struct i2c_device_id ltr501_id[] = {
 427        { "ltr501", 0 },
 428        { }
 429};
 430MODULE_DEVICE_TABLE(i2c, ltr501_id);
 431
 432static struct i2c_driver ltr501_driver = {
 433        .driver = {
 434                .name   = LTR501_DRV_NAME,
 435                .pm     = &ltr501_pm_ops,
 436                .owner  = THIS_MODULE,
 437        },
 438        .probe  = ltr501_probe,
 439        .remove = ltr501_remove,
 440        .id_table = ltr501_id,
 441};
 442
 443module_i2c_driver(ltr501_driver);
 444
 445MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 446MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver");
 447MODULE_LICENSE("GPL");
 448