278 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * CM3323 - Capella Color Light Sensor4 *5 * Copyright (c) 2015, Intel Corporation.6 *7 * IIO driver for CM3323 (7-bit I2C slave address 0x10)8 *9 * TODO: calibscale to correct the lens factor10 */11#include <linux/module.h>12#include <linux/init.h>13#include <linux/i2c.h>14#include <linux/mutex.h>15 16#include <linux/iio/iio.h>17#include <linux/iio/sysfs.h>18 19#define CM3323_DRV_NAME "cm3323"20 21#define CM3323_CMD_CONF 0x0022#define CM3323_CMD_RED_DATA 0x0823#define CM3323_CMD_GREEN_DATA 0x0924#define CM3323_CMD_BLUE_DATA 0x0A25#define CM3323_CMD_CLEAR_DATA 0x0B26 27#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */28#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */29#define CM3323_CONF_IT_MASK GENMASK(6, 4)30#define CM3323_CONF_IT_SHIFT 431 32#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"33 34static const struct {35 int val;36 int val2;37} cm3323_int_time[] = {38 {0, 40000}, /* 40 ms */39 {0, 80000}, /* 80 ms */40 {0, 160000}, /* 160 ms */41 {0, 320000}, /* 320 ms */42 {0, 640000}, /* 640 ms */43 {1, 280000}, /* 1280 ms */44};45 46struct cm3323_data {47 struct i2c_client *client;48 u16 reg_conf;49 struct mutex mutex;50};51 52#define CM3323_COLOR_CHANNEL(_color, _addr) { \53 .type = IIO_INTENSITY, \54 .modified = 1, \55 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \56 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \57 .channel2 = IIO_MOD_LIGHT_##_color, \58 .address = _addr, \59}60 61static const struct iio_chan_spec cm3323_channels[] = {62 CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),63 CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),64 CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),65 CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),66};67 68static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);69 70static struct attribute *cm3323_attributes[] = {71 &iio_const_attr_integration_time_available.dev_attr.attr,72 NULL73};74 75static const struct attribute_group cm3323_attribute_group = {76 .attrs = cm3323_attributes,77};78 79static int cm3323_init(struct iio_dev *indio_dev)80{81 int ret;82 struct cm3323_data *data = iio_priv(indio_dev);83 84 ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);85 if (ret < 0) {86 dev_err(&data->client->dev, "Error reading reg_conf\n");87 return ret;88 }89 90 /* enable sensor and set auto force mode */91 ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);92 93 ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);94 if (ret < 0) {95 dev_err(&data->client->dev, "Error writing reg_conf\n");96 return ret;97 }98 99 data->reg_conf = ret;100 101 return 0;102}103 104static void cm3323_disable(void *data)105{106 int ret;107 struct iio_dev *indio_dev = data;108 struct cm3323_data *cm_data = iio_priv(indio_dev);109 110 ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF,111 CM3323_CONF_SD_BIT);112 if (ret < 0)113 dev_err(&cm_data->client->dev, "Error writing reg_conf\n");114}115 116static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)117{118 int i, ret;119 u16 reg_conf;120 121 for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {122 if (val == cm3323_int_time[i].val &&123 val2 == cm3323_int_time[i].val2) {124 reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK;125 reg_conf |= i << CM3323_CONF_IT_SHIFT;126 127 ret = i2c_smbus_write_word_data(data->client,128 CM3323_CMD_CONF,129 reg_conf);130 if (ret < 0)131 return ret;132 133 data->reg_conf = reg_conf;134 135 return 0;136 }137 }138 139 return -EINVAL;140}141 142static int cm3323_get_it_bits(struct cm3323_data *data)143{144 int bits;145 146 bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>147 CM3323_CONF_IT_SHIFT;148 149 if (bits >= ARRAY_SIZE(cm3323_int_time))150 return -EINVAL;151 152 return bits;153}154 155static int cm3323_read_raw(struct iio_dev *indio_dev,156 struct iio_chan_spec const *chan, int *val,157 int *val2, long mask)158{159 int ret;160 struct cm3323_data *data = iio_priv(indio_dev);161 162 switch (mask) {163 case IIO_CHAN_INFO_RAW:164 mutex_lock(&data->mutex);165 ret = i2c_smbus_read_word_data(data->client, chan->address);166 if (ret < 0) {167 mutex_unlock(&data->mutex);168 return ret;169 }170 *val = ret;171 mutex_unlock(&data->mutex);172 173 return IIO_VAL_INT;174 case IIO_CHAN_INFO_INT_TIME:175 mutex_lock(&data->mutex);176 ret = cm3323_get_it_bits(data);177 if (ret < 0) {178 mutex_unlock(&data->mutex);179 return ret;180 }181 182 *val = cm3323_int_time[ret].val;183 *val2 = cm3323_int_time[ret].val2;184 mutex_unlock(&data->mutex);185 186 return IIO_VAL_INT_PLUS_MICRO;187 default:188 return -EINVAL;189 }190}191 192static int cm3323_write_raw(struct iio_dev *indio_dev,193 struct iio_chan_spec const *chan, int val,194 int val2, long mask)195{196 struct cm3323_data *data = iio_priv(indio_dev);197 int ret;198 199 switch (mask) {200 case IIO_CHAN_INFO_INT_TIME:201 mutex_lock(&data->mutex);202 ret = cm3323_set_it_bits(data, val, val2);203 mutex_unlock(&data->mutex);204 205 return ret;206 default:207 return -EINVAL;208 }209}210 211static const struct iio_info cm3323_info = {212 .read_raw = cm3323_read_raw,213 .write_raw = cm3323_write_raw,214 .attrs = &cm3323_attribute_group,215};216 217static int cm3323_probe(struct i2c_client *client)218{219 struct cm3323_data *data;220 struct iio_dev *indio_dev;221 int ret;222 223 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));224 if (!indio_dev)225 return -ENOMEM;226 227 data = iio_priv(indio_dev);228 i2c_set_clientdata(client, indio_dev);229 data->client = client;230 231 mutex_init(&data->mutex);232 233 indio_dev->info = &cm3323_info;234 indio_dev->name = CM3323_DRV_NAME;235 indio_dev->channels = cm3323_channels;236 indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);237 indio_dev->modes = INDIO_DIRECT_MODE;238 239 ret = cm3323_init(indio_dev);240 if (ret < 0) {241 dev_err(&client->dev, "cm3323 chip init failed\n");242 return ret;243 }244 245 ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);246 if (ret < 0)247 return ret;248 249 return devm_iio_device_register(&client->dev, indio_dev);250}251 252static const struct i2c_device_id cm3323_id[] = {253 { "cm3323" },254 {}255};256MODULE_DEVICE_TABLE(i2c, cm3323_id);257 258static const struct of_device_id cm3323_of_match[] = {259 { .compatible = "capella,cm3323", },260 { /* sentinel */ }261};262MODULE_DEVICE_TABLE(of, cm3323_of_match);263 264static struct i2c_driver cm3323_driver = {265 .driver = {266 .name = CM3323_DRV_NAME,267 .of_match_table = cm3323_of_match,268 },269 .probe = cm3323_probe,270 .id_table = cm3323_id,271};272 273module_i2c_driver(cm3323_driver);274 275MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");276MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");277MODULE_LICENSE("GPL v2");278