Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * CM3323 - Capella Color Light Sensor
0004  *
0005  * Copyright (c) 2015, Intel Corporation.
0006  *
0007  * IIO driver for CM3323 (7-bit I2C slave address 0x10)
0008  *
0009  * TODO: calibscale to correct the lens factor
0010  */
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/i2c.h>
0014 #include <linux/mutex.h>
0015 
0016 #include <linux/iio/iio.h>
0017 #include <linux/iio/sysfs.h>
0018 
0019 #define CM3323_DRV_NAME "cm3323"
0020 
0021 #define CM3323_CMD_CONF     0x00
0022 #define CM3323_CMD_RED_DATA 0x08
0023 #define CM3323_CMD_GREEN_DATA   0x09
0024 #define CM3323_CMD_BLUE_DATA    0x0A
0025 #define CM3323_CMD_CLEAR_DATA   0x0B
0026 
0027 #define CM3323_CONF_SD_BIT  BIT(0) /* sensor disable */
0028 #define CM3323_CONF_AF_BIT  BIT(1) /* auto/manual force mode */
0029 #define CM3323_CONF_IT_MASK GENMASK(6, 4)
0030 #define CM3323_CONF_IT_SHIFT    4
0031 
0032 #define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
0033 
0034 static const struct {
0035     int val;
0036     int val2;
0037 } cm3323_int_time[] = {
0038     {0, 40000},  /* 40 ms */
0039     {0, 80000},  /* 80 ms */
0040     {0, 160000}, /* 160 ms */
0041     {0, 320000}, /* 320 ms */
0042     {0, 640000}, /* 640 ms */
0043     {1, 280000}, /* 1280 ms */
0044 };
0045 
0046 struct cm3323_data {
0047     struct i2c_client *client;
0048     u16 reg_conf;
0049     struct mutex mutex;
0050 };
0051 
0052 #define CM3323_COLOR_CHANNEL(_color, _addr) { \
0053     .type = IIO_INTENSITY, \
0054     .modified = 1, \
0055     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
0056     .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
0057     .channel2 = IIO_MOD_LIGHT_##_color, \
0058     .address = _addr, \
0059 }
0060 
0061 static const struct iio_chan_spec cm3323_channels[] = {
0062     CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),
0063     CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),
0064     CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),
0065     CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),
0066 };
0067 
0068 static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);
0069 
0070 static struct attribute *cm3323_attributes[] = {
0071     &iio_const_attr_integration_time_available.dev_attr.attr,
0072     NULL
0073 };
0074 
0075 static const struct attribute_group cm3323_attribute_group = {
0076     .attrs = cm3323_attributes,
0077 };
0078 
0079 static int cm3323_init(struct iio_dev *indio_dev)
0080 {
0081     int ret;
0082     struct cm3323_data *data = iio_priv(indio_dev);
0083 
0084     ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
0085     if (ret < 0) {
0086         dev_err(&data->client->dev, "Error reading reg_conf\n");
0087         return ret;
0088     }
0089 
0090     /* enable sensor and set auto force mode */
0091     ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
0092 
0093     ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
0094     if (ret < 0) {
0095         dev_err(&data->client->dev, "Error writing reg_conf\n");
0096         return ret;
0097     }
0098 
0099     data->reg_conf = ret;
0100 
0101     return 0;
0102 }
0103 
0104 static void cm3323_disable(void *data)
0105 {
0106     int ret;
0107     struct iio_dev *indio_dev = data;
0108     struct cm3323_data *cm_data = iio_priv(indio_dev);
0109 
0110     ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF,
0111                     CM3323_CONF_SD_BIT);
0112     if (ret < 0)
0113         dev_err(&cm_data->client->dev, "Error writing reg_conf\n");
0114 }
0115 
0116 static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
0117 {
0118     int i, ret;
0119     u16 reg_conf;
0120 
0121     for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
0122         if (val == cm3323_int_time[i].val &&
0123             val2 == cm3323_int_time[i].val2) {
0124             reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK;
0125             reg_conf |= i << CM3323_CONF_IT_SHIFT;
0126 
0127             ret = i2c_smbus_write_word_data(data->client,
0128                             CM3323_CMD_CONF,
0129                             reg_conf);
0130             if (ret < 0)
0131                 return ret;
0132 
0133             data->reg_conf = reg_conf;
0134 
0135             return 0;
0136         }
0137     }
0138 
0139     return -EINVAL;
0140 }
0141 
0142 static int cm3323_get_it_bits(struct cm3323_data *data)
0143 {
0144     int bits;
0145 
0146     bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>
0147         CM3323_CONF_IT_SHIFT;
0148 
0149     if (bits >= ARRAY_SIZE(cm3323_int_time))
0150         return -EINVAL;
0151 
0152     return bits;
0153 }
0154 
0155 static int cm3323_read_raw(struct iio_dev *indio_dev,
0156                struct iio_chan_spec const *chan, int *val,
0157                int *val2, long mask)
0158 {
0159     int ret;
0160     struct cm3323_data *data = iio_priv(indio_dev);
0161 
0162     switch (mask) {
0163     case IIO_CHAN_INFO_RAW:
0164         mutex_lock(&data->mutex);
0165         ret = i2c_smbus_read_word_data(data->client, chan->address);
0166         if (ret < 0) {
0167             mutex_unlock(&data->mutex);
0168             return ret;
0169         }
0170         *val = ret;
0171         mutex_unlock(&data->mutex);
0172 
0173         return IIO_VAL_INT;
0174     case IIO_CHAN_INFO_INT_TIME:
0175         mutex_lock(&data->mutex);
0176         ret = cm3323_get_it_bits(data);
0177         if (ret < 0) {
0178             mutex_unlock(&data->mutex);
0179             return ret;
0180         }
0181 
0182         *val = cm3323_int_time[ret].val;
0183         *val2 = cm3323_int_time[ret].val2;
0184         mutex_unlock(&data->mutex);
0185 
0186         return IIO_VAL_INT_PLUS_MICRO;
0187     default:
0188         return -EINVAL;
0189     }
0190 }
0191 
0192 static int cm3323_write_raw(struct iio_dev *indio_dev,
0193                 struct iio_chan_spec const *chan, int val,
0194                 int val2, long mask)
0195 {
0196     struct cm3323_data *data = iio_priv(indio_dev);
0197     int ret;
0198 
0199     switch (mask) {
0200     case IIO_CHAN_INFO_INT_TIME:
0201         mutex_lock(&data->mutex);
0202         ret = cm3323_set_it_bits(data, val, val2);
0203         mutex_unlock(&data->mutex);
0204 
0205         return ret;
0206     default:
0207         return -EINVAL;
0208     }
0209 }
0210 
0211 static const struct iio_info cm3323_info = {
0212     .read_raw   = cm3323_read_raw,
0213     .write_raw  = cm3323_write_raw,
0214     .attrs      = &cm3323_attribute_group,
0215 };
0216 
0217 static int cm3323_probe(struct i2c_client *client,
0218             const struct i2c_device_id *id)
0219 {
0220     struct cm3323_data *data;
0221     struct iio_dev *indio_dev;
0222     int ret;
0223 
0224     indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
0225     if (!indio_dev)
0226         return -ENOMEM;
0227 
0228     data = iio_priv(indio_dev);
0229     i2c_set_clientdata(client, indio_dev);
0230     data->client = client;
0231 
0232     mutex_init(&data->mutex);
0233 
0234     indio_dev->info = &cm3323_info;
0235     indio_dev->name = CM3323_DRV_NAME;
0236     indio_dev->channels = cm3323_channels;
0237     indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);
0238     indio_dev->modes = INDIO_DIRECT_MODE;
0239 
0240     ret = cm3323_init(indio_dev);
0241     if (ret < 0) {
0242         dev_err(&client->dev, "cm3323 chip init failed\n");
0243         return ret;
0244     }
0245 
0246     ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);
0247     if (ret < 0)
0248         return ret;
0249 
0250     return devm_iio_device_register(&client->dev, indio_dev);
0251 }
0252 
0253 static const struct i2c_device_id cm3323_id[] = {
0254     {"cm3323", 0},
0255     {}
0256 };
0257 MODULE_DEVICE_TABLE(i2c, cm3323_id);
0258 
0259 static const struct of_device_id cm3323_of_match[] = {
0260     { .compatible = "capella,cm3323", },
0261     { /* sentinel */ }
0262 };
0263 MODULE_DEVICE_TABLE(of, cm3323_of_match);
0264 
0265 static struct i2c_driver cm3323_driver = {
0266     .driver = {
0267         .name = CM3323_DRV_NAME,
0268         .of_match_table = cm3323_of_match,
0269     },
0270     .probe      = cm3323_probe,
0271     .id_table   = cm3323_id,
0272 };
0273 
0274 module_i2c_driver(cm3323_driver);
0275 
0276 MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
0277 MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");
0278 MODULE_LICENSE("GPL v2");