136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28b054426SDaniel Baluta /*
38b054426SDaniel Baluta * CM3323 - Capella Color Light Sensor
48b054426SDaniel Baluta *
58b054426SDaniel Baluta * Copyright (c) 2015, Intel Corporation.
68b054426SDaniel Baluta *
78b054426SDaniel Baluta * IIO driver for CM3323 (7-bit I2C slave address 0x10)
88b054426SDaniel Baluta *
98b054426SDaniel Baluta * TODO: calibscale to correct the lens factor
108b054426SDaniel Baluta */
118b054426SDaniel Baluta #include <linux/module.h>
128b054426SDaniel Baluta #include <linux/init.h>
138b054426SDaniel Baluta #include <linux/i2c.h>
148b054426SDaniel Baluta #include <linux/mutex.h>
158b054426SDaniel Baluta
168b054426SDaniel Baluta #include <linux/iio/iio.h>
178b054426SDaniel Baluta #include <linux/iio/sysfs.h>
188b054426SDaniel Baluta
198b054426SDaniel Baluta #define CM3323_DRV_NAME "cm3323"
208b054426SDaniel Baluta
218b054426SDaniel Baluta #define CM3323_CMD_CONF 0x00
228b054426SDaniel Baluta #define CM3323_CMD_RED_DATA 0x08
238b054426SDaniel Baluta #define CM3323_CMD_GREEN_DATA 0x09
248b054426SDaniel Baluta #define CM3323_CMD_BLUE_DATA 0x0A
258b054426SDaniel Baluta #define CM3323_CMD_CLEAR_DATA 0x0B
268b054426SDaniel Baluta
278b054426SDaniel Baluta #define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */
288b054426SDaniel Baluta #define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */
29054101c1SHartmut Knaack #define CM3323_CONF_IT_MASK GENMASK(6, 4)
308b054426SDaniel Baluta #define CM3323_CONF_IT_SHIFT 4
318b054426SDaniel Baluta
328b054426SDaniel Baluta #define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
338b054426SDaniel Baluta
348b054426SDaniel Baluta static const struct {
358b054426SDaniel Baluta int val;
368b054426SDaniel Baluta int val2;
378b054426SDaniel Baluta } cm3323_int_time[] = {
388b054426SDaniel Baluta {0, 40000}, /* 40 ms */
398b054426SDaniel Baluta {0, 80000}, /* 80 ms */
408b054426SDaniel Baluta {0, 160000}, /* 160 ms */
418b054426SDaniel Baluta {0, 320000}, /* 320 ms */
428b054426SDaniel Baluta {0, 640000}, /* 640 ms */
438b054426SDaniel Baluta {1, 280000}, /* 1280 ms */
448b054426SDaniel Baluta };
458b054426SDaniel Baluta
468b054426SDaniel Baluta struct cm3323_data {
478b054426SDaniel Baluta struct i2c_client *client;
488b054426SDaniel Baluta u16 reg_conf;
498b054426SDaniel Baluta struct mutex mutex;
508b054426SDaniel Baluta };
518b054426SDaniel Baluta
528b054426SDaniel Baluta #define CM3323_COLOR_CHANNEL(_color, _addr) { \
538b054426SDaniel Baluta .type = IIO_INTENSITY, \
548b054426SDaniel Baluta .modified = 1, \
558b054426SDaniel Baluta .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
568b054426SDaniel Baluta .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
578b054426SDaniel Baluta .channel2 = IIO_MOD_LIGHT_##_color, \
588b054426SDaniel Baluta .address = _addr, \
598b054426SDaniel Baluta }
608b054426SDaniel Baluta
618b054426SDaniel Baluta static const struct iio_chan_spec cm3323_channels[] = {
628b054426SDaniel Baluta CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),
638b054426SDaniel Baluta CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),
648b054426SDaniel Baluta CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),
658b054426SDaniel Baluta CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),
668b054426SDaniel Baluta };
678b054426SDaniel Baluta
688b054426SDaniel Baluta static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);
698b054426SDaniel Baluta
708b054426SDaniel Baluta static struct attribute *cm3323_attributes[] = {
718b054426SDaniel Baluta &iio_const_attr_integration_time_available.dev_attr.attr,
728b054426SDaniel Baluta NULL
738b054426SDaniel Baluta };
748b054426SDaniel Baluta
758b054426SDaniel Baluta static const struct attribute_group cm3323_attribute_group = {
768b054426SDaniel Baluta .attrs = cm3323_attributes,
778b054426SDaniel Baluta };
788b054426SDaniel Baluta
cm3323_init(struct iio_dev * indio_dev)798b054426SDaniel Baluta static int cm3323_init(struct iio_dev *indio_dev)
808b054426SDaniel Baluta {
818b054426SDaniel Baluta int ret;
828b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev);
838b054426SDaniel Baluta
848b054426SDaniel Baluta ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
858b054426SDaniel Baluta if (ret < 0) {
868b054426SDaniel Baluta dev_err(&data->client->dev, "Error reading reg_conf\n");
878b054426SDaniel Baluta return ret;
888b054426SDaniel Baluta }
898b054426SDaniel Baluta
908b054426SDaniel Baluta /* enable sensor and set auto force mode */
918b054426SDaniel Baluta ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
928b054426SDaniel Baluta
938b054426SDaniel Baluta ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
948b054426SDaniel Baluta if (ret < 0) {
958b054426SDaniel Baluta dev_err(&data->client->dev, "Error writing reg_conf\n");
968b054426SDaniel Baluta return ret;
978b054426SDaniel Baluta }
988b054426SDaniel Baluta
998b054426SDaniel Baluta data->reg_conf = ret;
1008b054426SDaniel Baluta
1018b054426SDaniel Baluta return 0;
1028b054426SDaniel Baluta }
1038b054426SDaniel Baluta
cm3323_disable(void * data)104dff38165SChuhong Yuan static void cm3323_disable(void *data)
1058b054426SDaniel Baluta {
1068b054426SDaniel Baluta int ret;
107dff38165SChuhong Yuan struct iio_dev *indio_dev = data;
108dff38165SChuhong Yuan struct cm3323_data *cm_data = iio_priv(indio_dev);
1098b054426SDaniel Baluta
110dff38165SChuhong Yuan ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF,
1118b054426SDaniel Baluta CM3323_CONF_SD_BIT);
1128b054426SDaniel Baluta if (ret < 0)
113dff38165SChuhong Yuan dev_err(&cm_data->client->dev, "Error writing reg_conf\n");
1148b054426SDaniel Baluta }
1158b054426SDaniel Baluta
cm3323_set_it_bits(struct cm3323_data * data,int val,int val2)1168b054426SDaniel Baluta static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
1178b054426SDaniel Baluta {
1188b054426SDaniel Baluta int i, ret;
1198b054426SDaniel Baluta u16 reg_conf;
1208b054426SDaniel Baluta
1218b054426SDaniel Baluta for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
1228b054426SDaniel Baluta if (val == cm3323_int_time[i].val &&
1238b054426SDaniel Baluta val2 == cm3323_int_time[i].val2) {
124c288503bSHartmut Knaack reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK;
1258b054426SDaniel Baluta reg_conf |= i << CM3323_CONF_IT_SHIFT;
1268b054426SDaniel Baluta
1278b054426SDaniel Baluta ret = i2c_smbus_write_word_data(data->client,
1288b054426SDaniel Baluta CM3323_CMD_CONF,
1298b054426SDaniel Baluta reg_conf);
1308b054426SDaniel Baluta if (ret < 0)
1318b054426SDaniel Baluta return ret;
1328b054426SDaniel Baluta
1338b054426SDaniel Baluta data->reg_conf = reg_conf;
1348bf62ec8SHartmut Knaack
1358b054426SDaniel Baluta return 0;
1368b054426SDaniel Baluta }
1378b054426SDaniel Baluta }
1388bf62ec8SHartmut Knaack
1398b054426SDaniel Baluta return -EINVAL;
1408b054426SDaniel Baluta }
1418b054426SDaniel Baluta
cm3323_get_it_bits(struct cm3323_data * data)1428b054426SDaniel Baluta static int cm3323_get_it_bits(struct cm3323_data *data)
1438b054426SDaniel Baluta {
1448b054426SDaniel Baluta int bits;
1458b054426SDaniel Baluta
1468b054426SDaniel Baluta bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>
1478b054426SDaniel Baluta CM3323_CONF_IT_SHIFT;
1488b054426SDaniel Baluta
1498b054426SDaniel Baluta if (bits >= ARRAY_SIZE(cm3323_int_time))
1508b054426SDaniel Baluta return -EINVAL;
1518bf62ec8SHartmut Knaack
1528b054426SDaniel Baluta return bits;
1538b054426SDaniel Baluta }
1548b054426SDaniel Baluta
cm3323_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)1558b054426SDaniel Baluta static int cm3323_read_raw(struct iio_dev *indio_dev,
1568b054426SDaniel Baluta struct iio_chan_spec const *chan, int *val,
1578b054426SDaniel Baluta int *val2, long mask)
1588b054426SDaniel Baluta {
1590ff8c78dSHartmut Knaack int ret;
1608b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev);
1618b054426SDaniel Baluta
1628b054426SDaniel Baluta switch (mask) {
1638b054426SDaniel Baluta case IIO_CHAN_INFO_RAW:
1648b054426SDaniel Baluta mutex_lock(&data->mutex);
1658b054426SDaniel Baluta ret = i2c_smbus_read_word_data(data->client, chan->address);
1668b054426SDaniel Baluta if (ret < 0) {
1678b054426SDaniel Baluta mutex_unlock(&data->mutex);
1688b054426SDaniel Baluta return ret;
1698b054426SDaniel Baluta }
1708b054426SDaniel Baluta *val = ret;
1718b054426SDaniel Baluta mutex_unlock(&data->mutex);
1728b054426SDaniel Baluta
1738b054426SDaniel Baluta return IIO_VAL_INT;
1748b054426SDaniel Baluta case IIO_CHAN_INFO_INT_TIME:
1758b054426SDaniel Baluta mutex_lock(&data->mutex);
1760ff8c78dSHartmut Knaack ret = cm3323_get_it_bits(data);
1770ff8c78dSHartmut Knaack if (ret < 0) {
1788b054426SDaniel Baluta mutex_unlock(&data->mutex);
1790ff8c78dSHartmut Knaack return ret;
1808b054426SDaniel Baluta }
1818b054426SDaniel Baluta
1820ff8c78dSHartmut Knaack *val = cm3323_int_time[ret].val;
1830ff8c78dSHartmut Knaack *val2 = cm3323_int_time[ret].val2;
1848b054426SDaniel Baluta mutex_unlock(&data->mutex);
1858b054426SDaniel Baluta
1868b054426SDaniel Baluta return IIO_VAL_INT_PLUS_MICRO;
1878b054426SDaniel Baluta default:
1888b054426SDaniel Baluta return -EINVAL;
1898b054426SDaniel Baluta }
1908b054426SDaniel Baluta }
1918b054426SDaniel Baluta
cm3323_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)1928b054426SDaniel Baluta static int cm3323_write_raw(struct iio_dev *indio_dev,
1938b054426SDaniel Baluta struct iio_chan_spec const *chan, int val,
1948b054426SDaniel Baluta int val2, long mask)
1958b054426SDaniel Baluta {
1968b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev);
1978b054426SDaniel Baluta int ret;
1988b054426SDaniel Baluta
1998b054426SDaniel Baluta switch (mask) {
2008b054426SDaniel Baluta case IIO_CHAN_INFO_INT_TIME:
2018b054426SDaniel Baluta mutex_lock(&data->mutex);
2028b054426SDaniel Baluta ret = cm3323_set_it_bits(data, val, val2);
2038b054426SDaniel Baluta mutex_unlock(&data->mutex);
2048b054426SDaniel Baluta
2058b054426SDaniel Baluta return ret;
2068b054426SDaniel Baluta default:
2078b054426SDaniel Baluta return -EINVAL;
2088b054426SDaniel Baluta }
2098b054426SDaniel Baluta }
2108b054426SDaniel Baluta
2118b054426SDaniel Baluta static const struct iio_info cm3323_info = {
2128b054426SDaniel Baluta .read_raw = cm3323_read_raw,
2138b054426SDaniel Baluta .write_raw = cm3323_write_raw,
2148b054426SDaniel Baluta .attrs = &cm3323_attribute_group,
2158b054426SDaniel Baluta };
2168b054426SDaniel Baluta
cm3323_probe(struct i2c_client * client)217ebbcdb1aSUwe Kleine-König static int cm3323_probe(struct i2c_client *client)
2188b054426SDaniel Baluta {
2198b054426SDaniel Baluta struct cm3323_data *data;
2208b054426SDaniel Baluta struct iio_dev *indio_dev;
2218b054426SDaniel Baluta int ret;
2228b054426SDaniel Baluta
2238b054426SDaniel Baluta indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
2248b054426SDaniel Baluta if (!indio_dev)
2258b054426SDaniel Baluta return -ENOMEM;
2268b054426SDaniel Baluta
2278b054426SDaniel Baluta data = iio_priv(indio_dev);
2288b054426SDaniel Baluta i2c_set_clientdata(client, indio_dev);
2298b054426SDaniel Baluta data->client = client;
2308b054426SDaniel Baluta
2318b054426SDaniel Baluta mutex_init(&data->mutex);
2328b054426SDaniel Baluta
2338b054426SDaniel Baluta indio_dev->info = &cm3323_info;
2348b054426SDaniel Baluta indio_dev->name = CM3323_DRV_NAME;
2358b054426SDaniel Baluta indio_dev->channels = cm3323_channels;
2368b054426SDaniel Baluta indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);
2378b054426SDaniel Baluta indio_dev->modes = INDIO_DIRECT_MODE;
2388b054426SDaniel Baluta
2398b054426SDaniel Baluta ret = cm3323_init(indio_dev);
2408b054426SDaniel Baluta if (ret < 0) {
2418b054426SDaniel Baluta dev_err(&client->dev, "cm3323 chip init failed\n");
2428b054426SDaniel Baluta return ret;
2438b054426SDaniel Baluta }
2448bf62ec8SHartmut Knaack
245dff38165SChuhong Yuan ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);
246dff38165SChuhong Yuan if (ret < 0)
2478b054426SDaniel Baluta return ret;
2488b054426SDaniel Baluta
249dff38165SChuhong Yuan return devm_iio_device_register(&client->dev, indio_dev);
2508b054426SDaniel Baluta }
2518b054426SDaniel Baluta
2528b054426SDaniel Baluta static const struct i2c_device_id cm3323_id[] = {
253*4391affaSUwe Kleine-König { "cm3323" },
2548b054426SDaniel Baluta {}
2558b054426SDaniel Baluta };
2568b054426SDaniel Baluta MODULE_DEVICE_TABLE(i2c, cm3323_id);
2578b054426SDaniel Baluta
258ee8ea747SSiddharth Manthan static const struct of_device_id cm3323_of_match[] = {
259ee8ea747SSiddharth Manthan { .compatible = "capella,cm3323", },
260ee8ea747SSiddharth Manthan { /* sentinel */ }
261ee8ea747SSiddharth Manthan };
262ee8ea747SSiddharth Manthan MODULE_DEVICE_TABLE(of, cm3323_of_match);
263ee8ea747SSiddharth Manthan
2648b054426SDaniel Baluta static struct i2c_driver cm3323_driver = {
2658b054426SDaniel Baluta .driver = {
2668b054426SDaniel Baluta .name = CM3323_DRV_NAME,
267ee8ea747SSiddharth Manthan .of_match_table = cm3323_of_match,
2688b054426SDaniel Baluta },
2697cf15f42SUwe Kleine-König .probe = cm3323_probe,
2708b054426SDaniel Baluta .id_table = cm3323_id,
2718b054426SDaniel Baluta };
2728b054426SDaniel Baluta
2738b054426SDaniel Baluta module_i2c_driver(cm3323_driver);
2748b054426SDaniel Baluta
2758b054426SDaniel Baluta MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
2768b054426SDaniel Baluta MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");
2778b054426SDaniel Baluta MODULE_LICENSE("GPL v2");
278