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