xref: /openbmc/linux/drivers/iio/light/cm3323.c (revision 7cf15f42)
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[] = {
2538b054426SDaniel Baluta 	{"cm3323", 0},
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 	},
269*7cf15f42SUwe 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