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