root/drivers/iio/light/isl29125.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isl29125_read_data
  2. isl29125_read_raw
  3. isl29125_write_raw
  4. isl29125_trigger_handler
  5. isl29125_buffer_preenable
  6. isl29125_buffer_predisable
  7. isl29125_probe
  8. isl29125_powerdown
  9. isl29125_remove
  10. isl29125_suspend
  11. isl29125_resume

   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 
  51 struct 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 
  72 static 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 
  79 static 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 
  87 static 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 
 116 fail:
 117         i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1);
 118         return ret;
 119 }
 120 
 121 static 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 
 150 static 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 
 173 static 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 
 193 done:
 194         iio_trigger_notify_done(indio_dev->trig);
 195 
 196         return IRQ_HANDLED;
 197 }
 198 
 199 static IIO_CONST_ATTR(scale_available, "0.005722 0.152590");
 200 
 201 static struct attribute *isl29125_attributes[] = {
 202         &iio_const_attr_scale_available.dev_attr.attr,
 203         NULL
 204 };
 205 
 206 static const struct attribute_group isl29125_attribute_group = {
 207         .attrs = isl29125_attributes,
 208 };
 209 
 210 static 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 
 216 static 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 
 225 static 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 
 240 static 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 
 246 static 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 
 295 buffer_cleanup:
 296         iio_triggered_buffer_cleanup(indio_dev);
 297         return ret;
 298 }
 299 
 300 static 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 
 306 static 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
 318 static 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 
 325 static 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 
 334 static SIMPLE_DEV_PM_OPS(isl29125_pm_ops, isl29125_suspend, isl29125_resume);
 335 
 336 static const struct i2c_device_id isl29125_id[] = {
 337         { "isl29125", 0 },
 338         { }
 339 };
 340 MODULE_DEVICE_TABLE(i2c, isl29125_id);
 341 
 342 static 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 };
 351 module_i2c_driver(isl29125_driver);
 352 
 353 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 354 MODULE_DESCRIPTION("ISL29125 RGB light sensor driver");
 355 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */