Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * adjd_s311.c - Support for ADJD-S311-CR999 digital color sensor
0004  *
0005  * Copyright (C) 2012 Peter Meerwald <pmeerw@pmeerw.net>
0006  *
0007  * driver for ADJD-S311-CR999 digital color sensor (10-bit channels for
0008  * red, green, blue, clear); 7-bit I2C slave address 0x74
0009  *
0010  * limitations: no calibration, no offset mode, no sleep mode
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/i2c.h>
0016 #include <linux/slab.h>
0017 #include <linux/delay.h>
0018 #include <linux/bitmap.h>
0019 #include <linux/err.h>
0020 #include <linux/irq.h>
0021 
0022 #include <linux/iio/iio.h>
0023 #include <linux/iio/sysfs.h>
0024 #include <linux/iio/trigger_consumer.h>
0025 #include <linux/iio/buffer.h>
0026 #include <linux/iio/triggered_buffer.h>
0027 
0028 #define ADJD_S311_DRV_NAME "adjd_s311"
0029 
0030 #define ADJD_S311_CTRL      0x00
0031 #define ADJD_S311_CONFIG    0x01
0032 #define ADJD_S311_CAP_RED   0x06
0033 #define ADJD_S311_CAP_GREEN 0x07
0034 #define ADJD_S311_CAP_BLUE  0x08
0035 #define ADJD_S311_CAP_CLEAR 0x09
0036 #define ADJD_S311_INT_RED   0x0a
0037 #define ADJD_S311_INT_GREEN 0x0c
0038 #define ADJD_S311_INT_BLUE  0x0e
0039 #define ADJD_S311_INT_CLEAR 0x10
0040 #define ADJD_S311_DATA_RED  0x40
0041 #define ADJD_S311_DATA_GREEN    0x42
0042 #define ADJD_S311_DATA_BLUE 0x44
0043 #define ADJD_S311_DATA_CLEAR    0x46
0044 #define ADJD_S311_OFFSET_RED    0x48
0045 #define ADJD_S311_OFFSET_GREEN  0x49
0046 #define ADJD_S311_OFFSET_BLUE   0x4a
0047 #define ADJD_S311_OFFSET_CLEAR  0x4b
0048 
0049 #define ADJD_S311_CTRL_GOFS 0x02
0050 #define ADJD_S311_CTRL_GSSR 0x01
0051 #define ADJD_S311_CAP_MASK  0x0f
0052 #define ADJD_S311_INT_MASK  0x0fff
0053 #define ADJD_S311_DATA_MASK 0x03ff
0054 
0055 struct adjd_s311_data {
0056     struct i2c_client *client;
0057     struct {
0058         s16 chans[4];
0059         s64 ts __aligned(8);
0060     } scan;
0061 };
0062 
0063 enum adjd_s311_channel_idx {
0064     IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR
0065 };
0066 
0067 #define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED + (chan) * 2)
0068 #define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED + (chan) * 2)
0069 #define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan))
0070 
0071 static int adjd_s311_req_data(struct iio_dev *indio_dev)
0072 {
0073     struct adjd_s311_data *data = iio_priv(indio_dev);
0074     int tries = 10;
0075 
0076     int ret = i2c_smbus_write_byte_data(data->client, ADJD_S311_CTRL,
0077         ADJD_S311_CTRL_GSSR);
0078     if (ret < 0)
0079         return ret;
0080 
0081     while (tries--) {
0082         ret = i2c_smbus_read_byte_data(data->client, ADJD_S311_CTRL);
0083         if (ret < 0)
0084             return ret;
0085         if (!(ret & ADJD_S311_CTRL_GSSR))
0086             break;
0087         msleep(20);
0088     }
0089 
0090     if (tries < 0) {
0091         dev_err(&data->client->dev,
0092             "adjd_s311_req_data() failed, data not ready\n");
0093         return -EIO;
0094     }
0095 
0096     return 0;
0097 }
0098 
0099 static int adjd_s311_read_data(struct iio_dev *indio_dev, u8 reg, int *val)
0100 {
0101     struct adjd_s311_data *data = iio_priv(indio_dev);
0102 
0103     int ret = adjd_s311_req_data(indio_dev);
0104     if (ret < 0)
0105         return ret;
0106 
0107     ret = i2c_smbus_read_word_data(data->client, reg);
0108     if (ret < 0)
0109         return ret;
0110 
0111     *val = ret & ADJD_S311_DATA_MASK;
0112 
0113     return 0;
0114 }
0115 
0116 static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
0117 {
0118     struct iio_poll_func *pf = p;
0119     struct iio_dev *indio_dev = pf->indio_dev;
0120     struct adjd_s311_data *data = iio_priv(indio_dev);
0121     s64 time_ns = iio_get_time_ns(indio_dev);
0122     int i, j = 0;
0123 
0124     int ret = adjd_s311_req_data(indio_dev);
0125     if (ret < 0)
0126         goto done;
0127 
0128     for_each_set_bit(i, indio_dev->active_scan_mask,
0129         indio_dev->masklength) {
0130         ret = i2c_smbus_read_word_data(data->client,
0131             ADJD_S311_DATA_REG(i));
0132         if (ret < 0)
0133             goto done;
0134 
0135         data->scan.chans[j++] = ret & ADJD_S311_DATA_MASK;
0136     }
0137 
0138     iio_push_to_buffers_with_timestamp(indio_dev, &data->scan, time_ns);
0139 
0140 done:
0141     iio_trigger_notify_done(indio_dev->trig);
0142 
0143     return IRQ_HANDLED;
0144 }
0145 
0146 #define ADJD_S311_CHANNEL(_color, _scan_idx) { \
0147     .type = IIO_INTENSITY, \
0148     .modified = 1, \
0149     .address = (IDX_##_color), \
0150     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
0151         BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
0152         BIT(IIO_CHAN_INFO_INT_TIME), \
0153     .channel2 = (IIO_MOD_LIGHT_##_color), \
0154     .scan_index = (_scan_idx), \
0155     .scan_type = { \
0156         .sign = 'u', \
0157         .realbits = 10, \
0158         .storagebits = 16, \
0159         .endianness = IIO_CPU, \
0160     }, \
0161 }
0162 
0163 static const struct iio_chan_spec adjd_s311_channels[] = {
0164     ADJD_S311_CHANNEL(RED, 0),
0165     ADJD_S311_CHANNEL(GREEN, 1),
0166     ADJD_S311_CHANNEL(BLUE, 2),
0167     ADJD_S311_CHANNEL(CLEAR, 3),
0168     IIO_CHAN_SOFT_TIMESTAMP(4),
0169 };
0170 
0171 static int adjd_s311_read_raw(struct iio_dev *indio_dev,
0172                struct iio_chan_spec const *chan,
0173                int *val, int *val2, long mask)
0174 {
0175     struct adjd_s311_data *data = iio_priv(indio_dev);
0176     int ret;
0177 
0178     switch (mask) {
0179     case IIO_CHAN_INFO_RAW:
0180         ret = adjd_s311_read_data(indio_dev,
0181             ADJD_S311_DATA_REG(chan->address), val);
0182         if (ret < 0)
0183             return ret;
0184         return IIO_VAL_INT;
0185     case IIO_CHAN_INFO_HARDWAREGAIN:
0186         ret = i2c_smbus_read_byte_data(data->client,
0187             ADJD_S311_CAP_REG(chan->address));
0188         if (ret < 0)
0189             return ret;
0190         *val = ret & ADJD_S311_CAP_MASK;
0191         return IIO_VAL_INT;
0192     case IIO_CHAN_INFO_INT_TIME:
0193         ret = i2c_smbus_read_word_data(data->client,
0194             ADJD_S311_INT_REG(chan->address));
0195         if (ret < 0)
0196             return ret;
0197         *val = 0;
0198         /*
0199          * not documented, based on measurement:
0200          * 4095 LSBs correspond to roughly 4 ms
0201          */
0202         *val2 = ret & ADJD_S311_INT_MASK;
0203         return IIO_VAL_INT_PLUS_MICRO;
0204     }
0205     return -EINVAL;
0206 }
0207 
0208 static int adjd_s311_write_raw(struct iio_dev *indio_dev,
0209                    struct iio_chan_spec const *chan,
0210                    int val, int val2, long mask)
0211 {
0212     struct adjd_s311_data *data = iio_priv(indio_dev);
0213 
0214     switch (mask) {
0215     case IIO_CHAN_INFO_HARDWAREGAIN:
0216         if (val < 0 || val > ADJD_S311_CAP_MASK)
0217             return -EINVAL;
0218 
0219         return i2c_smbus_write_byte_data(data->client,
0220             ADJD_S311_CAP_REG(chan->address), val);
0221     case IIO_CHAN_INFO_INT_TIME:
0222         if (val != 0 || val2 < 0 || val2 > ADJD_S311_INT_MASK)
0223             return -EINVAL;
0224 
0225         return i2c_smbus_write_word_data(data->client,
0226             ADJD_S311_INT_REG(chan->address), val2);
0227     }
0228     return -EINVAL;
0229 }
0230 
0231 static const struct iio_info adjd_s311_info = {
0232     .read_raw = adjd_s311_read_raw,
0233     .write_raw = adjd_s311_write_raw,
0234 };
0235 
0236 static int adjd_s311_probe(struct i2c_client *client,
0237                const struct i2c_device_id *id)
0238 {
0239     struct adjd_s311_data *data;
0240     struct iio_dev *indio_dev;
0241     int err;
0242 
0243     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0244     if (indio_dev == NULL)
0245         return -ENOMEM;
0246 
0247     data = iio_priv(indio_dev);
0248     data->client = client;
0249 
0250     indio_dev->info = &adjd_s311_info;
0251     indio_dev->name = ADJD_S311_DRV_NAME;
0252     indio_dev->channels = adjd_s311_channels;
0253     indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
0254     indio_dev->modes = INDIO_DIRECT_MODE;
0255 
0256     err = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
0257                           adjd_s311_trigger_handler, NULL);
0258     if (err < 0)
0259         return err;
0260 
0261     return devm_iio_device_register(&client->dev, indio_dev);
0262 }
0263 
0264 static const struct i2c_device_id adjd_s311_id[] = {
0265     { "adjd_s311", 0 },
0266     { }
0267 };
0268 MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
0269 
0270 static struct i2c_driver adjd_s311_driver = {
0271     .driver = {
0272         .name   = ADJD_S311_DRV_NAME,
0273     },
0274     .probe      = adjd_s311_probe,
0275     .id_table   = adjd_s311_id,
0276 };
0277 module_i2c_driver(adjd_s311_driver);
0278 
0279 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
0280 MODULE_DESCRIPTION("ADJD-S311 color sensor");
0281 MODULE_LICENSE("GPL");