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 1048b054426SDaniel Baluta static void cm3323_disable(struct iio_dev *indio_dev) 1058b054426SDaniel Baluta { 1068b054426SDaniel Baluta int ret; 1078b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev); 1088b054426SDaniel Baluta 1098b054426SDaniel Baluta ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, 1108b054426SDaniel Baluta CM3323_CONF_SD_BIT); 1118b054426SDaniel Baluta if (ret < 0) 1128b054426SDaniel Baluta dev_err(&data->client->dev, "Error writing reg_conf\n"); 1138b054426SDaniel Baluta } 1148b054426SDaniel Baluta 1158b054426SDaniel Baluta static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) 1168b054426SDaniel Baluta { 1178b054426SDaniel Baluta int i, ret; 1188b054426SDaniel Baluta u16 reg_conf; 1198b054426SDaniel Baluta 1208b054426SDaniel Baluta for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) { 1218b054426SDaniel Baluta if (val == cm3323_int_time[i].val && 1228b054426SDaniel Baluta val2 == cm3323_int_time[i].val2) { 123c288503bSHartmut Knaack reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK; 1248b054426SDaniel Baluta reg_conf |= i << CM3323_CONF_IT_SHIFT; 1258b054426SDaniel Baluta 1268b054426SDaniel Baluta ret = i2c_smbus_write_word_data(data->client, 1278b054426SDaniel Baluta CM3323_CMD_CONF, 1288b054426SDaniel Baluta reg_conf); 1298b054426SDaniel Baluta if (ret < 0) 1308b054426SDaniel Baluta return ret; 1318b054426SDaniel Baluta 1328b054426SDaniel Baluta data->reg_conf = reg_conf; 1338bf62ec8SHartmut Knaack 1348b054426SDaniel Baluta return 0; 1358b054426SDaniel Baluta } 1368b054426SDaniel Baluta } 1378bf62ec8SHartmut Knaack 1388b054426SDaniel Baluta return -EINVAL; 1398b054426SDaniel Baluta } 1408b054426SDaniel Baluta 1418b054426SDaniel Baluta static int cm3323_get_it_bits(struct cm3323_data *data) 1428b054426SDaniel Baluta { 1438b054426SDaniel Baluta int bits; 1448b054426SDaniel Baluta 1458b054426SDaniel Baluta bits = (data->reg_conf & CM3323_CONF_IT_MASK) >> 1468b054426SDaniel Baluta CM3323_CONF_IT_SHIFT; 1478b054426SDaniel Baluta 1488b054426SDaniel Baluta if (bits >= ARRAY_SIZE(cm3323_int_time)) 1498b054426SDaniel Baluta return -EINVAL; 1508bf62ec8SHartmut Knaack 1518b054426SDaniel Baluta return bits; 1528b054426SDaniel Baluta } 1538b054426SDaniel Baluta 1548b054426SDaniel Baluta static int cm3323_read_raw(struct iio_dev *indio_dev, 1558b054426SDaniel Baluta struct iio_chan_spec const *chan, int *val, 1568b054426SDaniel Baluta int *val2, long mask) 1578b054426SDaniel Baluta { 1580ff8c78dSHartmut Knaack int ret; 1598b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev); 1608b054426SDaniel Baluta 1618b054426SDaniel Baluta switch (mask) { 1628b054426SDaniel Baluta case IIO_CHAN_INFO_RAW: 1638b054426SDaniel Baluta mutex_lock(&data->mutex); 1648b054426SDaniel Baluta ret = i2c_smbus_read_word_data(data->client, chan->address); 1658b054426SDaniel Baluta if (ret < 0) { 1668b054426SDaniel Baluta mutex_unlock(&data->mutex); 1678b054426SDaniel Baluta return ret; 1688b054426SDaniel Baluta } 1698b054426SDaniel Baluta *val = ret; 1708b054426SDaniel Baluta mutex_unlock(&data->mutex); 1718b054426SDaniel Baluta 1728b054426SDaniel Baluta return IIO_VAL_INT; 1738b054426SDaniel Baluta case IIO_CHAN_INFO_INT_TIME: 1748b054426SDaniel Baluta mutex_lock(&data->mutex); 1750ff8c78dSHartmut Knaack ret = cm3323_get_it_bits(data); 1760ff8c78dSHartmut Knaack if (ret < 0) { 1778b054426SDaniel Baluta mutex_unlock(&data->mutex); 1780ff8c78dSHartmut Knaack return ret; 1798b054426SDaniel Baluta } 1808b054426SDaniel Baluta 1810ff8c78dSHartmut Knaack *val = cm3323_int_time[ret].val; 1820ff8c78dSHartmut Knaack *val2 = cm3323_int_time[ret].val2; 1838b054426SDaniel Baluta mutex_unlock(&data->mutex); 1848b054426SDaniel Baluta 1858b054426SDaniel Baluta return IIO_VAL_INT_PLUS_MICRO; 1868b054426SDaniel Baluta default: 1878b054426SDaniel Baluta return -EINVAL; 1888b054426SDaniel Baluta } 1898b054426SDaniel Baluta } 1908b054426SDaniel Baluta 1918b054426SDaniel Baluta static int cm3323_write_raw(struct iio_dev *indio_dev, 1928b054426SDaniel Baluta struct iio_chan_spec const *chan, int val, 1938b054426SDaniel Baluta int val2, long mask) 1948b054426SDaniel Baluta { 1958b054426SDaniel Baluta struct cm3323_data *data = iio_priv(indio_dev); 1968b054426SDaniel Baluta int ret; 1978b054426SDaniel Baluta 1988b054426SDaniel Baluta switch (mask) { 1998b054426SDaniel Baluta case IIO_CHAN_INFO_INT_TIME: 2008b054426SDaniel Baluta mutex_lock(&data->mutex); 2018b054426SDaniel Baluta ret = cm3323_set_it_bits(data, val, val2); 2028b054426SDaniel Baluta mutex_unlock(&data->mutex); 2038b054426SDaniel Baluta 2048b054426SDaniel Baluta return ret; 2058b054426SDaniel Baluta default: 2068b054426SDaniel Baluta return -EINVAL; 2078b054426SDaniel Baluta } 2088b054426SDaniel Baluta } 2098b054426SDaniel Baluta 2108b054426SDaniel Baluta static const struct iio_info cm3323_info = { 2118b054426SDaniel Baluta .read_raw = cm3323_read_raw, 2128b054426SDaniel Baluta .write_raw = cm3323_write_raw, 2138b054426SDaniel Baluta .attrs = &cm3323_attribute_group, 2148b054426SDaniel Baluta }; 2158b054426SDaniel Baluta 2168b054426SDaniel Baluta static int cm3323_probe(struct i2c_client *client, 2178b054426SDaniel Baluta const struct i2c_device_id *id) 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->dev.parent = &client->dev; 2348b054426SDaniel Baluta indio_dev->info = &cm3323_info; 2358b054426SDaniel Baluta indio_dev->name = CM3323_DRV_NAME; 2368b054426SDaniel Baluta indio_dev->channels = cm3323_channels; 2378b054426SDaniel Baluta indio_dev->num_channels = ARRAY_SIZE(cm3323_channels); 2388b054426SDaniel Baluta indio_dev->modes = INDIO_DIRECT_MODE; 2398b054426SDaniel Baluta 2408b054426SDaniel Baluta ret = cm3323_init(indio_dev); 2418b054426SDaniel Baluta if (ret < 0) { 2428b054426SDaniel Baluta dev_err(&client->dev, "cm3323 chip init failed\n"); 2438b054426SDaniel Baluta return ret; 2448b054426SDaniel Baluta } 2458bf62ec8SHartmut Knaack 2468b054426SDaniel Baluta ret = iio_device_register(indio_dev); 2478b054426SDaniel Baluta if (ret < 0) { 2488b054426SDaniel Baluta dev_err(&client->dev, "failed to register iio dev\n"); 2498b054426SDaniel Baluta goto err_init; 2508b054426SDaniel Baluta } 2518bf62ec8SHartmut Knaack 2528b054426SDaniel Baluta return 0; 2538b054426SDaniel Baluta err_init: 2548b054426SDaniel Baluta cm3323_disable(indio_dev); 2558b054426SDaniel Baluta return ret; 2568b054426SDaniel Baluta } 2578b054426SDaniel Baluta 2588b054426SDaniel Baluta static int cm3323_remove(struct i2c_client *client) 2598b054426SDaniel Baluta { 2608b054426SDaniel Baluta struct iio_dev *indio_dev = i2c_get_clientdata(client); 2618b054426SDaniel Baluta 2628b054426SDaniel Baluta iio_device_unregister(indio_dev); 2638b054426SDaniel Baluta cm3323_disable(indio_dev); 2648b054426SDaniel Baluta 2658b054426SDaniel Baluta return 0; 2668b054426SDaniel Baluta } 2678b054426SDaniel Baluta 2688b054426SDaniel Baluta static const struct i2c_device_id cm3323_id[] = { 2698b054426SDaniel Baluta {"cm3323", 0}, 2708b054426SDaniel Baluta {} 2718b054426SDaniel Baluta }; 2728b054426SDaniel Baluta MODULE_DEVICE_TABLE(i2c, cm3323_id); 2738b054426SDaniel Baluta 2748b054426SDaniel Baluta static struct i2c_driver cm3323_driver = { 2758b054426SDaniel Baluta .driver = { 2768b054426SDaniel Baluta .name = CM3323_DRV_NAME, 2778b054426SDaniel Baluta }, 2788b054426SDaniel Baluta .probe = cm3323_probe, 2798b054426SDaniel Baluta .remove = cm3323_remove, 2808b054426SDaniel Baluta .id_table = cm3323_id, 2818b054426SDaniel Baluta }; 2828b054426SDaniel Baluta 2838b054426SDaniel Baluta module_i2c_driver(cm3323_driver); 2848b054426SDaniel Baluta 2858b054426SDaniel Baluta MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); 2868b054426SDaniel Baluta MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver"); 2878b054426SDaniel Baluta MODULE_LICENSE("GPL v2"); 288