xref: /linux/drivers/iio/light/cm3323.c (revision 054101c186b9e41d2b57543070c4a520d38402da)
18b054426SDaniel Baluta /*
28b054426SDaniel Baluta  * CM3323 - Capella Color Light Sensor
38b054426SDaniel Baluta  *
48b054426SDaniel Baluta  * Copyright (c) 2015, Intel Corporation.
58b054426SDaniel Baluta  *
68b054426SDaniel Baluta  * This file is subject to the terms and conditions of version 2 of
78b054426SDaniel Baluta  * the GNU General Public License.  See the file COPYING in the main
88b054426SDaniel Baluta  * directory of this archive for more details.
98b054426SDaniel Baluta  *
108b054426SDaniel Baluta  * IIO driver for CM3323 (7-bit I2C slave address 0x10)
118b054426SDaniel Baluta  *
128b054426SDaniel Baluta  * TODO: calibscale to correct the lens factor
138b054426SDaniel Baluta  */
148b054426SDaniel Baluta #include <linux/module.h>
158b054426SDaniel Baluta #include <linux/init.h>
168b054426SDaniel Baluta #include <linux/i2c.h>
178b054426SDaniel Baluta #include <linux/mutex.h>
188b054426SDaniel Baluta 
198b054426SDaniel Baluta #include <linux/iio/iio.h>
208b054426SDaniel Baluta #include <linux/iio/sysfs.h>
218b054426SDaniel Baluta 
228b054426SDaniel Baluta #define CM3323_DRV_NAME "cm3323"
238b054426SDaniel Baluta 
248b054426SDaniel Baluta #define CM3323_CMD_CONF		0x00
258b054426SDaniel Baluta #define CM3323_CMD_RED_DATA	0x08
268b054426SDaniel Baluta #define CM3323_CMD_GREEN_DATA	0x09
278b054426SDaniel Baluta #define CM3323_CMD_BLUE_DATA	0x0A
288b054426SDaniel Baluta #define CM3323_CMD_CLEAR_DATA	0x0B
298b054426SDaniel Baluta 
308b054426SDaniel Baluta #define CM3323_CONF_SD_BIT	BIT(0) /* sensor disable */
318b054426SDaniel Baluta #define CM3323_CONF_AF_BIT	BIT(1) /* auto/manual force mode */
32*054101c1SHartmut Knaack #define CM3323_CONF_IT_MASK	GENMASK(6, 4)
338b054426SDaniel Baluta #define CM3323_CONF_IT_SHIFT	4
348b054426SDaniel Baluta 
358b054426SDaniel Baluta #define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
368b054426SDaniel Baluta 
378b054426SDaniel Baluta static const struct {
388b054426SDaniel Baluta 	int val;
398b054426SDaniel Baluta 	int val2;
408b054426SDaniel Baluta } cm3323_int_time[] = {
418b054426SDaniel Baluta 	{0, 40000},  /* 40 ms */
428b054426SDaniel Baluta 	{0, 80000},  /* 80 ms */
438b054426SDaniel Baluta 	{0, 160000}, /* 160 ms */
448b054426SDaniel Baluta 	{0, 320000}, /* 320 ms */
458b054426SDaniel Baluta 	{0, 640000}, /* 640 ms */
468b054426SDaniel Baluta 	{1, 280000}, /* 1280 ms */
478b054426SDaniel Baluta };
488b054426SDaniel Baluta 
498b054426SDaniel Baluta struct cm3323_data {
508b054426SDaniel Baluta 	struct i2c_client *client;
518b054426SDaniel Baluta 	u16 reg_conf;
528b054426SDaniel Baluta 	struct mutex mutex;
538b054426SDaniel Baluta };
548b054426SDaniel Baluta 
558b054426SDaniel Baluta #define CM3323_COLOR_CHANNEL(_color, _addr) { \
568b054426SDaniel Baluta 	.type = IIO_INTENSITY, \
578b054426SDaniel Baluta 	.modified = 1, \
588b054426SDaniel Baluta 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
598b054426SDaniel Baluta 	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
608b054426SDaniel Baluta 	.channel2 = IIO_MOD_LIGHT_##_color, \
618b054426SDaniel Baluta 	.address = _addr, \
628b054426SDaniel Baluta }
638b054426SDaniel Baluta 
648b054426SDaniel Baluta static const struct iio_chan_spec cm3323_channels[] = {
658b054426SDaniel Baluta 	CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),
668b054426SDaniel Baluta 	CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),
678b054426SDaniel Baluta 	CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),
688b054426SDaniel Baluta 	CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),
698b054426SDaniel Baluta };
708b054426SDaniel Baluta 
718b054426SDaniel Baluta static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);
728b054426SDaniel Baluta 
738b054426SDaniel Baluta static struct attribute *cm3323_attributes[] = {
748b054426SDaniel Baluta 	&iio_const_attr_integration_time_available.dev_attr.attr,
758b054426SDaniel Baluta 	NULL
768b054426SDaniel Baluta };
778b054426SDaniel Baluta 
788b054426SDaniel Baluta static const struct attribute_group cm3323_attribute_group = {
798b054426SDaniel Baluta 	.attrs = cm3323_attributes,
808b054426SDaniel Baluta };
818b054426SDaniel Baluta 
828b054426SDaniel Baluta static int cm3323_init(struct iio_dev *indio_dev)
838b054426SDaniel Baluta {
848b054426SDaniel Baluta 	int ret;
858b054426SDaniel Baluta 	struct cm3323_data *data = iio_priv(indio_dev);
868b054426SDaniel Baluta 
878b054426SDaniel Baluta 	ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
888b054426SDaniel Baluta 	if (ret < 0) {
898b054426SDaniel Baluta 		dev_err(&data->client->dev, "Error reading reg_conf\n");
908b054426SDaniel Baluta 		return ret;
918b054426SDaniel Baluta 	}
928b054426SDaniel Baluta 
938b054426SDaniel Baluta 	/* enable sensor and set auto force mode */
948b054426SDaniel Baluta 	ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
958b054426SDaniel Baluta 
968b054426SDaniel Baluta 	ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
978b054426SDaniel Baluta 	if (ret < 0) {
988b054426SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_conf\n");
998b054426SDaniel Baluta 		return ret;
1008b054426SDaniel Baluta 	}
1018b054426SDaniel Baluta 
1028b054426SDaniel Baluta 	data->reg_conf = ret;
1038b054426SDaniel Baluta 
1048b054426SDaniel Baluta 	return 0;
1058b054426SDaniel Baluta }
1068b054426SDaniel Baluta 
1078b054426SDaniel Baluta static void cm3323_disable(struct iio_dev *indio_dev)
1088b054426SDaniel Baluta {
1098b054426SDaniel Baluta 	int ret;
1108b054426SDaniel Baluta 	struct cm3323_data *data = iio_priv(indio_dev);
1118b054426SDaniel Baluta 
1128b054426SDaniel Baluta 	ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF,
1138b054426SDaniel Baluta 					CM3323_CONF_SD_BIT);
1148b054426SDaniel Baluta 	if (ret < 0)
1158b054426SDaniel Baluta 		dev_err(&data->client->dev, "Error writing reg_conf\n");
1168b054426SDaniel Baluta }
1178b054426SDaniel Baluta 
1188b054426SDaniel Baluta static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
1198b054426SDaniel Baluta {
1208b054426SDaniel Baluta 	int i, ret;
1218b054426SDaniel Baluta 	u16 reg_conf;
1228b054426SDaniel Baluta 
1238b054426SDaniel Baluta 	for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
1248b054426SDaniel Baluta 		if (val == cm3323_int_time[i].val &&
1258b054426SDaniel Baluta 		    val2 == cm3323_int_time[i].val2) {
1268b054426SDaniel Baluta 			reg_conf = data->reg_conf;
1278b054426SDaniel Baluta 			reg_conf |= i << CM3323_CONF_IT_SHIFT;
1288b054426SDaniel Baluta 
1298b054426SDaniel Baluta 			ret = i2c_smbus_write_word_data(data->client,
1308b054426SDaniel Baluta 							CM3323_CMD_CONF,
1318b054426SDaniel Baluta 							reg_conf);
1328b054426SDaniel Baluta 			if (ret < 0)
1338b054426SDaniel Baluta 				return ret;
1348b054426SDaniel Baluta 
1358b054426SDaniel Baluta 			data->reg_conf = reg_conf;
1368b054426SDaniel Baluta 			return 0;
1378b054426SDaniel Baluta 		}
1388b054426SDaniel Baluta 	}
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;
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 	.driver_module	= THIS_MODULE,
2128b054426SDaniel Baluta 	.read_raw	= cm3323_read_raw,
2138b054426SDaniel Baluta 	.write_raw	= cm3323_write_raw,
2148b054426SDaniel Baluta 	.attrs		= &cm3323_attribute_group,
2158b054426SDaniel Baluta };
2168b054426SDaniel Baluta 
2178b054426SDaniel Baluta static int cm3323_probe(struct i2c_client *client,
2188b054426SDaniel Baluta 			const struct i2c_device_id *id)
2198b054426SDaniel Baluta {
2208b054426SDaniel Baluta 	struct cm3323_data *data;
2218b054426SDaniel Baluta 	struct iio_dev *indio_dev;
2228b054426SDaniel Baluta 	int ret;
2238b054426SDaniel Baluta 
2248b054426SDaniel Baluta 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
2258b054426SDaniel Baluta 	if (!indio_dev)
2268b054426SDaniel Baluta 		return -ENOMEM;
2278b054426SDaniel Baluta 
2288b054426SDaniel Baluta 	data = iio_priv(indio_dev);
2298b054426SDaniel Baluta 	i2c_set_clientdata(client, indio_dev);
2308b054426SDaniel Baluta 	data->client = client;
2318b054426SDaniel Baluta 
2328b054426SDaniel Baluta 	mutex_init(&data->mutex);
2338b054426SDaniel Baluta 
2348b054426SDaniel Baluta 	indio_dev->dev.parent = &client->dev;
2358b054426SDaniel Baluta 	indio_dev->info = &cm3323_info;
2368b054426SDaniel Baluta 	indio_dev->name = CM3323_DRV_NAME;
2378b054426SDaniel Baluta 	indio_dev->channels = cm3323_channels;
2388b054426SDaniel Baluta 	indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);
2398b054426SDaniel Baluta 	indio_dev->modes = INDIO_DIRECT_MODE;
2408b054426SDaniel Baluta 
2418b054426SDaniel Baluta 	ret = cm3323_init(indio_dev);
2428b054426SDaniel Baluta 	if (ret < 0) {
2438b054426SDaniel Baluta 		dev_err(&client->dev, "cm3323 chip init failed\n");
2448b054426SDaniel Baluta 		return ret;
2458b054426SDaniel Baluta 	}
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 	}
2518b054426SDaniel Baluta 	return 0;
2528b054426SDaniel Baluta err_init:
2538b054426SDaniel Baluta 	cm3323_disable(indio_dev);
2548b054426SDaniel Baluta 	return ret;
2558b054426SDaniel Baluta }
2568b054426SDaniel Baluta 
2578b054426SDaniel Baluta static int cm3323_remove(struct i2c_client *client)
2588b054426SDaniel Baluta {
2598b054426SDaniel Baluta 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
2608b054426SDaniel Baluta 
2618b054426SDaniel Baluta 	iio_device_unregister(indio_dev);
2628b054426SDaniel Baluta 	cm3323_disable(indio_dev);
2638b054426SDaniel Baluta 
2648b054426SDaniel Baluta 	return 0;
2658b054426SDaniel Baluta }
2668b054426SDaniel Baluta 
2678b054426SDaniel Baluta static const struct i2c_device_id cm3323_id[] = {
2688b054426SDaniel Baluta 	{"cm3323", 0},
2698b054426SDaniel Baluta 	{}
2708b054426SDaniel Baluta };
2718b054426SDaniel Baluta MODULE_DEVICE_TABLE(i2c, cm3323_id);
2728b054426SDaniel Baluta 
2738b054426SDaniel Baluta static struct i2c_driver cm3323_driver = {
2748b054426SDaniel Baluta 	.driver = {
2758b054426SDaniel Baluta 		.name = CM3323_DRV_NAME,
2768b054426SDaniel Baluta 	},
2778b054426SDaniel Baluta 	.probe		= cm3323_probe,
2788b054426SDaniel Baluta 	.remove		= cm3323_remove,
2798b054426SDaniel Baluta 	.id_table	= cm3323_id,
2808b054426SDaniel Baluta };
2818b054426SDaniel Baluta 
2828b054426SDaniel Baluta module_i2c_driver(cm3323_driver);
2838b054426SDaniel Baluta 
2848b054426SDaniel Baluta MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
2858b054426SDaniel Baluta MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");
2868b054426SDaniel Baluta MODULE_LICENSE("GPL v2");
287