linux/drivers/iio/light/isl29125.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * isl29125.c - Support for Intersil ISL29125 RGB light sensor
   4 *
   5 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
   6 *
   7 * RGB light sensor with 16-bit channels for red, green, blue);
   8 * 7-bit I2C slave address 0x44
   9 *
  10 * TODO: interrupt support, IR compensation, thresholds, 12bit
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/i2c.h>
  15#include <linux/delay.h>
  16#include <linux/pm.h>
  17
  18#include <linux/iio/iio.h>
  19#include <linux/iio/sysfs.h>
  20#include <linux/iio/trigger_consumer.h>
  21#include <linux/iio/buffer.h>
  22#include <linux/iio/triggered_buffer.h>
  23
  24#define ISL29125_DRV_NAME "isl29125"
  25
  26#define ISL29125_DEVICE_ID 0x00
  27#define ISL29125_CONF1 0x01
  28#define ISL29125_CONF2 0x02
  29#define ISL29125_CONF3 0x03
  30#define ISL29125_STATUS 0x08
  31#define ISL29125_GREEN_DATA 0x09
  32#define ISL29125_RED_DATA 0x0b
  33#define ISL29125_BLUE_DATA 0x0d
  34
  35#define ISL29125_ID 0x7d
  36
  37#define ISL29125_MODE_MASK GENMASK(2, 0)
  38#define ISL29125_MODE_PD 0x0
  39#define ISL29125_MODE_G 0x1
  40#define ISL29125_MODE_R 0x2
  41#define ISL29125_MODE_B 0x3
  42#define ISL29125_MODE_RGB 0x5
  43
  44#define ISL29125_SENSING_RANGE_0 5722   /* 375 lux full range */
  45#define ISL29125_SENSING_RANGE_1 152590 /* 10k lux full range */
  46
  47#define ISL29125_MODE_RANGE BIT(3)
  48
  49#define ISL29125_STATUS_CONV BIT(1)
  50
  51struct isl29125_data {
  52        struct i2c_client *client;
  53        u8 conf1;
  54        u16 buffer[8]; /* 3x 16-bit, padding, 8 bytes timestamp */
  55};
  56
  57#define ISL29125_CHANNEL(_color, _si) { \
  58        .type = IIO_INTENSITY, \
  59        .modified = 1, \
  60        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
  61        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
  62        .channel2 = IIO_MOD_LIGHT_##_color, \
  63        .scan_index = _si, \
  64        .scan_type = { \
  65                .sign = 'u', \
  66                .realbits = 16, \
  67                .storagebits = 16, \
  68                .endianness = IIO_CPU, \
  69        }, \
  70}
  71
  72static const struct iio_chan_spec isl29125_channels[] = {
  73        ISL29125_CHANNEL(GREEN, 0),
  74        ISL29125_CHANNEL(RED, 1),
  75        ISL29125_CHANNEL(BLUE, 2),
  76        IIO_CHAN_SOFT_TIMESTAMP(3),
  77};
  78
  79static const struct {
  80        u8 mode, data;
  81} isl29125_regs[] = {
  82        {ISL29125_MODE_G, ISL29125_GREEN_DATA},
  83        {ISL29125_MODE_R, ISL29125_RED_DATA},
  84        {ISL29125_MODE_B, ISL29125_BLUE_DATA},
  85};
  86
  87static int isl29125_read_data(struct isl29125_data *data, int si)
  88{
  89        int tries = 5;
  90        int ret;
  91
  92        ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
  93                data->conf1 | isl29125_regs[si].mode);
  94        if (ret < 0)
  95                return ret;
  96
  97        msleep(101);
  98
  99        while (tries--) {
 100                ret = i2c_smbus_read_byte_data(data->client, ISL29125_STATUS);
 101                if (ret < 0)
 102                        goto fail;
 103                if (ret & ISL29125_STATUS_CONV)
 104                        break;
 105                msleep(20);
 106        }
 107
 108        if (tries < 0) {
 109                dev_err(&data->client->dev, "data not ready\n");
 110                ret = -EIO;
 111                goto fail;
 112        }
 113
 114        ret = i2c_smbus_read_word_data(data->client, isl29125_regs[si].data);
 115
 116fail:
 117        i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1);
 118        return ret;
 119}
 120
 121static int isl29125_read_raw(struct iio_dev *indio_dev,
 122                           struct iio_chan_spec const *chan,
 123                           int *val, int *val2, long mask)
 124{
 125        struct isl29125_data *data = iio_priv(indio_dev);
 126        int ret;
 127
 128        switch (mask) {
 129        case IIO_CHAN_INFO_RAW:
 130                ret = iio_device_claim_direct_mode(indio_dev);
 131                if (ret)
 132                        return ret;
 133                ret = isl29125_read_data(data, chan->scan_index);
 134                iio_device_release_direct_mode(indio_dev);
 135                if (ret < 0)
 136                        return ret;
 137                *val = ret;
 138                return IIO_VAL_INT;
 139        case IIO_CHAN_INFO_SCALE:
 140                *val = 0;
 141                if (data->conf1 & ISL29125_MODE_RANGE)
 142                        *val2 = ISL29125_SENSING_RANGE_1; /*10k lux full range*/
 143                else
 144                        *val2 = ISL29125_SENSING_RANGE_0; /*375 lux full range*/
 145                return IIO_VAL_INT_PLUS_MICRO;
 146        }
 147        return -EINVAL;
 148}
 149
 150static int isl29125_write_raw(struct iio_dev *indio_dev,
 151                               struct iio_chan_spec const *chan,
 152                               int val, int val2, long mask)
 153{
 154        struct isl29125_data *data = iio_priv(indio_dev);
 155
 156        switch (mask) {
 157        case IIO_CHAN_INFO_SCALE:
 158                if (val != 0)
 159                        return -EINVAL;
 160                if (val2 == ISL29125_SENSING_RANGE_1)
 161                        data->conf1 |= ISL29125_MODE_RANGE;
 162                else if (val2 == ISL29125_SENSING_RANGE_0)
 163                        data->conf1 &= ~ISL29125_MODE_RANGE;
 164                else
 165                        return -EINVAL;
 166                return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 167                        data->conf1);
 168        default:
 169                return -EINVAL;
 170        }
 171}
 172
 173static irqreturn_t isl29125_trigger_handler(int irq, void *p)
 174{
 175        struct iio_poll_func *pf = p;
 176        struct iio_dev *indio_dev = pf->indio_dev;
 177        struct isl29125_data *data = iio_priv(indio_dev);
 178        int i, j = 0;
 179
 180        for_each_set_bit(i, indio_dev->active_scan_mask,
 181                indio_dev->masklength) {
 182                int ret = i2c_smbus_read_word_data(data->client,
 183                        isl29125_regs[i].data);
 184                if (ret < 0)
 185                        goto done;
 186
 187                data->buffer[j++] = ret;
 188        }
 189
 190        iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
 191                iio_get_time_ns(indio_dev));
 192
 193done:
 194        iio_trigger_notify_done(indio_dev->trig);
 195
 196        return IRQ_HANDLED;
 197}
 198
 199static IIO_CONST_ATTR(scale_available, "0.005722 0.152590");
 200
 201static struct attribute *isl29125_attributes[] = {
 202        &iio_const_attr_scale_available.dev_attr.attr,
 203        NULL
 204};
 205
 206static const struct attribute_group isl29125_attribute_group = {
 207        .attrs = isl29125_attributes,
 208};
 209
 210static const struct iio_info isl29125_info = {
 211        .read_raw = isl29125_read_raw,
 212        .write_raw = isl29125_write_raw,
 213        .attrs = &isl29125_attribute_group,
 214};
 215
 216static int isl29125_buffer_postenable(struct iio_dev *indio_dev)
 217{
 218        struct isl29125_data *data = iio_priv(indio_dev);
 219
 220        data->conf1 |= ISL29125_MODE_RGB;
 221        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 222                data->conf1);
 223}
 224
 225static int isl29125_buffer_predisable(struct iio_dev *indio_dev)
 226{
 227        struct isl29125_data *data = iio_priv(indio_dev);
 228
 229        data->conf1 &= ~ISL29125_MODE_MASK;
 230        data->conf1 |= ISL29125_MODE_PD;
 231        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 232                data->conf1);
 233}
 234
 235static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = {
 236        .postenable = isl29125_buffer_postenable,
 237        .predisable = isl29125_buffer_predisable,
 238};
 239
 240static int isl29125_probe(struct i2c_client *client,
 241                           const struct i2c_device_id *id)
 242{
 243        struct isl29125_data *data;
 244        struct iio_dev *indio_dev;
 245        int ret;
 246
 247        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 248        if (indio_dev == NULL)
 249                return -ENOMEM;
 250
 251        data = iio_priv(indio_dev);
 252        i2c_set_clientdata(client, indio_dev);
 253        data->client = client;
 254
 255        indio_dev->info = &isl29125_info;
 256        indio_dev->name = ISL29125_DRV_NAME;
 257        indio_dev->channels = isl29125_channels;
 258        indio_dev->num_channels = ARRAY_SIZE(isl29125_channels);
 259        indio_dev->modes = INDIO_DIRECT_MODE;
 260
 261        ret = i2c_smbus_read_byte_data(data->client, ISL29125_DEVICE_ID);
 262        if (ret < 0)
 263                return ret;
 264        if (ret != ISL29125_ID)
 265                return -ENODEV;
 266
 267        data->conf1 = ISL29125_MODE_PD | ISL29125_MODE_RANGE;
 268        ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 269                data->conf1);
 270        if (ret < 0)
 271                return ret;
 272
 273        ret = i2c_smbus_write_byte_data(data->client, ISL29125_STATUS, 0);
 274        if (ret < 0)
 275                return ret;
 276
 277        ret = iio_triggered_buffer_setup(indio_dev, NULL,
 278                isl29125_trigger_handler, &isl29125_buffer_setup_ops);
 279        if (ret < 0)
 280                return ret;
 281
 282        ret = iio_device_register(indio_dev);
 283        if (ret < 0)
 284                goto buffer_cleanup;
 285
 286        return 0;
 287
 288buffer_cleanup:
 289        iio_triggered_buffer_cleanup(indio_dev);
 290        return ret;
 291}
 292
 293static int isl29125_powerdown(struct isl29125_data *data)
 294{
 295        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 296                (data->conf1 & ~ISL29125_MODE_MASK) | ISL29125_MODE_PD);
 297}
 298
 299static int isl29125_remove(struct i2c_client *client)
 300{
 301        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 302
 303        iio_device_unregister(indio_dev);
 304        iio_triggered_buffer_cleanup(indio_dev);
 305        isl29125_powerdown(iio_priv(indio_dev));
 306
 307        return 0;
 308}
 309
 310#ifdef CONFIG_PM_SLEEP
 311static int isl29125_suspend(struct device *dev)
 312{
 313        struct isl29125_data *data = iio_priv(i2c_get_clientdata(
 314                to_i2c_client(dev)));
 315        return isl29125_powerdown(data);
 316}
 317
 318static int isl29125_resume(struct device *dev)
 319{
 320        struct isl29125_data *data = iio_priv(i2c_get_clientdata(
 321                to_i2c_client(dev)));
 322        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 323                data->conf1);
 324}
 325#endif
 326
 327static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume);
 328
 329static const struct i2c_device_id isl29125_id[] = {
 330        { "isl29125", 0 },
 331        { }
 332};
 333MODULE_DEVICE_TABLE(i2c, isl29125_id);
 334
 335static struct i2c_driver isl29125_driver = {
 336        .driver = {
 337                .name   = ISL29125_DRV_NAME,
 338                .pm     = &isl29125_pm_ops,
 339        },
 340        .probe          = isl29125_probe,
 341        .remove         = isl29125_remove,
 342        .id_table       = isl29125_id,
 343};
 344module_i2c_driver(isl29125_driver);
 345
 346MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 347MODULE_DESCRIPTION("ISL29125 RGB light sensor driver");
 348MODULE_LICENSE("GPL");
 349