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 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 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 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 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 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 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 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