linux/drivers/iio/light/adjd_s311.c
<<
>>
Prefs
   1/*
   2 * adjd_s311.c - Support for ADJD-S311-CR999 digital color sensor
   3 *
   4 * Copyright (C) 2012 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 * driver for ADJD-S311-CR999 digital color sensor (10-bit channels for
  11 * red, green, blue, clear); 7-bit I2C slave address 0x74
  12 *
  13 * limitations: no calibration, no offset mode, no sleep mode
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/init.h>
  18#include <linux/interrupt.h>
  19#include <linux/i2c.h>
  20#include <linux/slab.h>
  21#include <linux/delay.h>
  22#include <linux/bitmap.h>
  23#include <linux/err.h>
  24#include <linux/irq.h>
  25
  26#include <linux/iio/iio.h>
  27#include <linux/iio/sysfs.h>
  28#include <linux/iio/trigger_consumer.h>
  29#include <linux/iio/buffer.h>
  30#include <linux/iio/triggered_buffer.h>
  31
  32#define ADJD_S311_DRV_NAME "adjd_s311"
  33
  34#define ADJD_S311_CTRL          0x00
  35#define ADJD_S311_CONFIG        0x01
  36#define ADJD_S311_CAP_RED       0x06
  37#define ADJD_S311_CAP_GREEN     0x07
  38#define ADJD_S311_CAP_BLUE      0x08
  39#define ADJD_S311_CAP_CLEAR     0x09
  40#define ADJD_S311_INT_RED       0x0a
  41#define ADJD_S311_INT_GREEN     0x0c
  42#define ADJD_S311_INT_BLUE      0x0e
  43#define ADJD_S311_INT_CLEAR     0x10
  44#define ADJD_S311_DATA_RED      0x40
  45#define ADJD_S311_DATA_GREEN    0x42
  46#define ADJD_S311_DATA_BLUE     0x44
  47#define ADJD_S311_DATA_CLEAR    0x46
  48#define ADJD_S311_OFFSET_RED    0x48
  49#define ADJD_S311_OFFSET_GREEN  0x49
  50#define ADJD_S311_OFFSET_BLUE   0x4a
  51#define ADJD_S311_OFFSET_CLEAR  0x4b
  52
  53#define ADJD_S311_CTRL_GOFS     0x02
  54#define ADJD_S311_CTRL_GSSR     0x01
  55#define ADJD_S311_CAP_MASK      0x0f
  56#define ADJD_S311_INT_MASK      0x0fff
  57#define ADJD_S311_DATA_MASK     0x03ff
  58
  59struct adjd_s311_data {
  60        struct i2c_client *client;
  61        u16 *buffer;
  62};
  63
  64enum adjd_s311_channel_idx {
  65        IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR
  66};
  67
  68#define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED + (chan) * 2)
  69#define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED + (chan) * 2)
  70#define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan))
  71
  72static int adjd_s311_req_data(struct iio_dev *indio_dev)
  73{
  74        struct adjd_s311_data *data = iio_priv(indio_dev);
  75        int tries = 10;
  76
  77        int ret = i2c_smbus_write_byte_data(data->client, ADJD_S311_CTRL,
  78                ADJD_S311_CTRL_GSSR);
  79        if (ret < 0)
  80                return ret;
  81
  82        while (tries--) {
  83                ret = i2c_smbus_read_byte_data(data->client, ADJD_S311_CTRL);
  84                if (ret < 0)
  85                        return ret;
  86                if (!(ret & ADJD_S311_CTRL_GSSR))
  87                        break;
  88                msleep(20);
  89        }
  90
  91        if (tries < 0) {
  92                dev_err(&data->client->dev,
  93                        "adjd_s311_req_data() failed, data not ready\n");
  94                return -EIO;
  95        }
  96
  97        return 0;
  98}
  99
 100static int adjd_s311_read_data(struct iio_dev *indio_dev, u8 reg, int *val)
 101{
 102        struct adjd_s311_data *data = iio_priv(indio_dev);
 103
 104        int ret = adjd_s311_req_data(indio_dev);
 105        if (ret < 0)
 106                return ret;
 107
 108        ret = i2c_smbus_read_word_data(data->client, reg);
 109        if (ret < 0)
 110                return ret;
 111
 112        *val = ret & ADJD_S311_DATA_MASK;
 113
 114        return 0;
 115}
 116
 117static ssize_t adjd_s311_read_int_time(struct iio_dev *indio_dev,
 118        uintptr_t private, const struct iio_chan_spec *chan, char *buf)
 119{
 120        struct adjd_s311_data *data = iio_priv(indio_dev);
 121        s32 ret;
 122
 123        ret = i2c_smbus_read_word_data(data->client,
 124                ADJD_S311_INT_REG(chan->address));
 125        if (ret < 0)
 126                return ret;
 127
 128        return sprintf(buf, "%d\n", ret & ADJD_S311_INT_MASK);
 129}
 130
 131static ssize_t adjd_s311_write_int_time(struct iio_dev *indio_dev,
 132         uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
 133         size_t len)
 134{
 135        struct adjd_s311_data *data = iio_priv(indio_dev);
 136        unsigned long int_time;
 137        int ret;
 138
 139        ret = kstrtoul(buf, 10, &int_time);
 140        if (ret)
 141                return ret;
 142
 143        if (int_time > ADJD_S311_INT_MASK)
 144                return -EINVAL;
 145
 146        ret = i2c_smbus_write_word_data(data->client,
 147                ADJD_S311_INT_REG(chan->address), int_time);
 148        if (ret < 0)
 149                return ret;
 150
 151        return len;
 152}
 153
 154static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
 155{
 156        struct iio_poll_func *pf = p;
 157        struct iio_dev *indio_dev = pf->indio_dev;
 158        struct adjd_s311_data *data = iio_priv(indio_dev);
 159        s64 time_ns = iio_get_time_ns();
 160        int len = 0;
 161        int i, j = 0;
 162
 163        int ret = adjd_s311_req_data(indio_dev);
 164        if (ret < 0)
 165                goto done;
 166
 167        for_each_set_bit(i, indio_dev->active_scan_mask,
 168                indio_dev->masklength) {
 169                ret = i2c_smbus_read_word_data(data->client,
 170                        ADJD_S311_DATA_REG(i));
 171                if (ret < 0)
 172                        goto done;
 173
 174                data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
 175                len += 2;
 176        }
 177
 178        if (indio_dev->scan_timestamp)
 179                *(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
 180                        = time_ns;
 181        iio_push_to_buffers(indio_dev, (u8 *)data->buffer);
 182
 183done:
 184        iio_trigger_notify_done(indio_dev->trig);
 185
 186        return IRQ_HANDLED;
 187}
 188
 189static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = {
 190        {
 191                .name = "integration_time",
 192                .read = adjd_s311_read_int_time,
 193                .write = adjd_s311_write_int_time,
 194        },
 195        { }
 196};
 197
 198#define ADJD_S311_CHANNEL(_color, _scan_idx) { \
 199        .type = IIO_INTENSITY, \
 200        .modified = 1, \
 201        .address = (IDX_##_color), \
 202        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
 203                BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
 204        .channel2 = (IIO_MOD_LIGHT_##_color), \
 205        .scan_index = (_scan_idx), \
 206        .scan_type = IIO_ST('u', 10, 16, 0), \
 207        .ext_info = adjd_s311_ext_info, \
 208}
 209
 210static const struct iio_chan_spec adjd_s311_channels[] = {
 211        ADJD_S311_CHANNEL(RED, 0),
 212        ADJD_S311_CHANNEL(GREEN, 1),
 213        ADJD_S311_CHANNEL(BLUE, 2),
 214        ADJD_S311_CHANNEL(CLEAR, 3),
 215        IIO_CHAN_SOFT_TIMESTAMP(4),
 216};
 217
 218static int adjd_s311_read_raw(struct iio_dev *indio_dev,
 219                           struct iio_chan_spec const *chan,
 220                           int *val, int *val2, long mask)
 221{
 222        struct adjd_s311_data *data = iio_priv(indio_dev);
 223        int ret;
 224
 225        switch (mask) {
 226        case IIO_CHAN_INFO_RAW:
 227                ret = adjd_s311_read_data(indio_dev,
 228                        ADJD_S311_DATA_REG(chan->address), val);
 229                if (ret < 0)
 230                        return ret;
 231                return IIO_VAL_INT;
 232        case IIO_CHAN_INFO_HARDWAREGAIN:
 233                ret = i2c_smbus_read_byte_data(data->client,
 234                        ADJD_S311_CAP_REG(chan->address));
 235                if (ret < 0)
 236                        return ret;
 237                *val = ret & ADJD_S311_CAP_MASK;
 238                return IIO_VAL_INT;
 239        }
 240        return -EINVAL;
 241}
 242
 243static int adjd_s311_write_raw(struct iio_dev *indio_dev,
 244                               struct iio_chan_spec const *chan,
 245                               int val, int val2, long mask)
 246{
 247        struct adjd_s311_data *data = iio_priv(indio_dev);
 248        int ret;
 249
 250        switch (mask) {
 251        case IIO_CHAN_INFO_HARDWAREGAIN:
 252                if (val < 0 || val > ADJD_S311_CAP_MASK)
 253                        return -EINVAL;
 254
 255                ret = i2c_smbus_write_byte_data(data->client,
 256                        ADJD_S311_CAP_REG(chan->address), val);
 257                return ret;
 258        }
 259        return -EINVAL;
 260}
 261
 262static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
 263        const unsigned long *scan_mask)
 264{
 265        struct adjd_s311_data *data = iio_priv(indio_dev);
 266
 267        kfree(data->buffer);
 268        data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
 269        if (data->buffer == NULL)
 270                return -ENOMEM;
 271
 272        return 0;
 273}
 274
 275static const struct iio_info adjd_s311_info = {
 276        .read_raw = adjd_s311_read_raw,
 277        .write_raw = adjd_s311_write_raw,
 278        .update_scan_mode = adjd_s311_update_scan_mode,
 279        .driver_module = THIS_MODULE,
 280};
 281
 282static int adjd_s311_probe(struct i2c_client *client,
 283                           const struct i2c_device_id *id)
 284{
 285        struct adjd_s311_data *data;
 286        struct iio_dev *indio_dev;
 287        int err;
 288
 289        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 290        if (indio_dev == NULL)
 291                return -ENOMEM;
 292
 293        data = iio_priv(indio_dev);
 294        i2c_set_clientdata(client, indio_dev);
 295        data->client = client;
 296
 297        indio_dev->dev.parent = &client->dev;
 298        indio_dev->info = &adjd_s311_info;
 299        indio_dev->name = ADJD_S311_DRV_NAME;
 300        indio_dev->channels = adjd_s311_channels;
 301        indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
 302        indio_dev->modes = INDIO_DIRECT_MODE;
 303
 304        err = iio_triggered_buffer_setup(indio_dev, NULL,
 305                adjd_s311_trigger_handler, NULL);
 306        if (err < 0)
 307                return err;
 308
 309        err = iio_device_register(indio_dev);
 310        if (err)
 311                goto exit_unreg_buffer;
 312
 313        dev_info(&client->dev, "ADJD-S311 color sensor registered\n");
 314
 315        return 0;
 316
 317exit_unreg_buffer:
 318        iio_triggered_buffer_cleanup(indio_dev);
 319        return err;
 320}
 321
 322static int adjd_s311_remove(struct i2c_client *client)
 323{
 324        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 325        struct adjd_s311_data *data = iio_priv(indio_dev);
 326
 327        iio_device_unregister(indio_dev);
 328        iio_triggered_buffer_cleanup(indio_dev);
 329        kfree(data->buffer);
 330
 331        return 0;
 332}
 333
 334static const struct i2c_device_id adjd_s311_id[] = {
 335        { "adjd_s311", 0 },
 336        { }
 337};
 338MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
 339
 340static struct i2c_driver adjd_s311_driver = {
 341        .driver = {
 342                .name   = ADJD_S311_DRV_NAME,
 343        },
 344        .probe          = adjd_s311_probe,
 345        .remove         = adjd_s311_remove,
 346        .id_table       = adjd_s311_id,
 347};
 348module_i2c_driver(adjd_s311_driver);
 349
 350MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 351MODULE_DESCRIPTION("ADJD-S311 color sensor");
 352MODULE_LICENSE("GPL");
 353