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_preenable(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        int ret;
 229
 230        ret = iio_triggered_buffer_predisable(indio_dev);
 231        if (ret < 0)
 232                return ret;
 233
 234        data->conf1 &= ~ISL29125_MODE_MASK;
 235        data->conf1 |= ISL29125_MODE_PD;
 236        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 237                data->conf1);
 238}
 239
 240static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = {
 241        .preenable = isl29125_buffer_preenable,
 242        .postenable = &iio_triggered_buffer_postenable,
 243        .predisable = isl29125_buffer_predisable,
 244};
 245
 246static int isl29125_probe(struct i2c_client *client,
 247                           const struct i2c_device_id *id)
 248{
 249        struct isl29125_data *data;
 250        struct iio_dev *indio_dev;
 251        int ret;
 252
 253        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 254        if (indio_dev == NULL)
 255                return -ENOMEM;
 256
 257        data = iio_priv(indio_dev);
 258        i2c_set_clientdata(client, indio_dev);
 259        data->client = client;
 260
 261        indio_dev->dev.parent = &client->dev;
 262        indio_dev->info = &isl29125_info;
 263        indio_dev->name = ISL29125_DRV_NAME;
 264        indio_dev->channels = isl29125_channels;
 265        indio_dev->num_channels = ARRAY_SIZE(isl29125_channels);
 266        indio_dev->modes = INDIO_DIRECT_MODE;
 267
 268        ret = i2c_smbus_read_byte_data(data->client, ISL29125_DEVICE_ID);
 269        if (ret < 0)
 270                return ret;
 271        if (ret != ISL29125_ID)
 272                return -ENODEV;
 273
 274        data->conf1 = ISL29125_MODE_PD | ISL29125_MODE_RANGE;
 275        ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 276                data->conf1);
 277        if (ret < 0)
 278                return ret;
 279
 280        ret = i2c_smbus_write_byte_data(data->client, ISL29125_STATUS, 0);
 281        if (ret < 0)
 282                return ret;
 283
 284        ret = iio_triggered_buffer_setup(indio_dev, NULL,
 285                isl29125_trigger_handler, &isl29125_buffer_setup_ops);
 286        if (ret < 0)
 287                return ret;
 288
 289        ret = iio_device_register(indio_dev);
 290        if (ret < 0)
 291                goto buffer_cleanup;
 292
 293        return 0;
 294
 295buffer_cleanup:
 296        iio_triggered_buffer_cleanup(indio_dev);
 297        return ret;
 298}
 299
 300static int isl29125_powerdown(struct isl29125_data *data)
 301{
 302        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 303                (data->conf1 & ~ISL29125_MODE_MASK) | ISL29125_MODE_PD);
 304}
 305
 306static int isl29125_remove(struct i2c_client *client)
 307{
 308        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 309
 310        iio_device_unregister(indio_dev);
 311        iio_triggered_buffer_cleanup(indio_dev);
 312        isl29125_powerdown(iio_priv(indio_dev));
 313
 314        return 0;
 315}
 316
 317#ifdef CONFIG_PM_SLEEP
 318static int isl29125_suspend(struct device *dev)
 319{
 320        struct isl29125_data *data = iio_priv(i2c_get_clientdata(
 321                to_i2c_client(dev)));
 322        return isl29125_powerdown(data);
 323}
 324
 325static int isl29125_resume(struct device *dev)
 326{
 327        struct isl29125_data *data = iio_priv(i2c_get_clientdata(
 328                to_i2c_client(dev)));
 329        return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1,
 330                data->conf1);
 331}
 332#endif
 333
 334static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume);
 335
 336static const struct i2c_device_id isl29125_id[] = {
 337        { "isl29125", 0 },
 338        { }
 339};
 340MODULE_DEVICE_TABLE(i2c, isl29125_id);
 341
 342static struct i2c_driver isl29125_driver = {
 343        .driver = {
 344                .name   = ISL29125_DRV_NAME,
 345                .pm     = &isl29125_pm_ops,
 346        },
 347        .probe          = isl29125_probe,
 348        .remove         = isl29125_remove,
 349        .id_table       = isl29125_id,
 350};
 351module_i2c_driver(isl29125_driver);
 352
 353MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 354MODULE_DESCRIPTION("ISL29125 RGB light sensor driver");
 355MODULE_LICENSE("GPL");
 356