brintos

brintos / linux-shallow public Read only

0
0
Text · 6.3 KiB · 79a64e2 Raw
278 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * CM3323 - Capella Color Light Sensor4 *5 * Copyright (c) 2015, Intel Corporation.6 *7 * IIO driver for CM3323 (7-bit I2C slave address 0x10)8 *9 * TODO: calibscale to correct the lens factor10 */11#include <linux/module.h>12#include <linux/init.h>13#include <linux/i2c.h>14#include <linux/mutex.h>15 16#include <linux/iio/iio.h>17#include <linux/iio/sysfs.h>18 19#define CM3323_DRV_NAME "cm3323"20 21#define CM3323_CMD_CONF		0x0022#define CM3323_CMD_RED_DATA	0x0823#define CM3323_CMD_GREEN_DATA	0x0924#define CM3323_CMD_BLUE_DATA	0x0A25#define CM3323_CMD_CLEAR_DATA	0x0B26 27#define CM3323_CONF_SD_BIT	BIT(0) /* sensor disable */28#define CM3323_CONF_AF_BIT	BIT(1) /* auto/manual force mode */29#define CM3323_CONF_IT_MASK	GENMASK(6, 4)30#define CM3323_CONF_IT_SHIFT	431 32#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"33 34static const struct {35	int val;36	int val2;37} cm3323_int_time[] = {38	{0, 40000},  /* 40 ms */39	{0, 80000},  /* 80 ms */40	{0, 160000}, /* 160 ms */41	{0, 320000}, /* 320 ms */42	{0, 640000}, /* 640 ms */43	{1, 280000}, /* 1280 ms */44};45 46struct cm3323_data {47	struct i2c_client *client;48	u16 reg_conf;49	struct mutex mutex;50};51 52#define CM3323_COLOR_CHANNEL(_color, _addr) { \53	.type = IIO_INTENSITY, \54	.modified = 1, \55	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \56	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \57	.channel2 = IIO_MOD_LIGHT_##_color, \58	.address = _addr, \59}60 61static const struct iio_chan_spec cm3323_channels[] = {62	CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),63	CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),64	CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),65	CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),66};67 68static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);69 70static struct attribute *cm3323_attributes[] = {71	&iio_const_attr_integration_time_available.dev_attr.attr,72	NULL73};74 75static const struct attribute_group cm3323_attribute_group = {76	.attrs = cm3323_attributes,77};78 79static int cm3323_init(struct iio_dev *indio_dev)80{81	int ret;82	struct cm3323_data *data = iio_priv(indio_dev);83 84	ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);85	if (ret < 0) {86		dev_err(&data->client->dev, "Error reading reg_conf\n");87		return ret;88	}89 90	/* enable sensor and set auto force mode */91	ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);92 93	ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);94	if (ret < 0) {95		dev_err(&data->client->dev, "Error writing reg_conf\n");96		return ret;97	}98 99	data->reg_conf = ret;100 101	return 0;102}103 104static void cm3323_disable(void *data)105{106	int ret;107	struct iio_dev *indio_dev = data;108	struct cm3323_data *cm_data = iio_priv(indio_dev);109 110	ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF,111					CM3323_CONF_SD_BIT);112	if (ret < 0)113		dev_err(&cm_data->client->dev, "Error writing reg_conf\n");114}115 116static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)117{118	int i, ret;119	u16 reg_conf;120 121	for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {122		if (val == cm3323_int_time[i].val &&123		    val2 == cm3323_int_time[i].val2) {124			reg_conf = data->reg_conf & ~CM3323_CONF_IT_MASK;125			reg_conf |= i << CM3323_CONF_IT_SHIFT;126 127			ret = i2c_smbus_write_word_data(data->client,128							CM3323_CMD_CONF,129							reg_conf);130			if (ret < 0)131				return ret;132 133			data->reg_conf = reg_conf;134 135			return 0;136		}137	}138 139	return -EINVAL;140}141 142static int cm3323_get_it_bits(struct cm3323_data *data)143{144	int bits;145 146	bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>147		CM3323_CONF_IT_SHIFT;148 149	if (bits >= ARRAY_SIZE(cm3323_int_time))150		return -EINVAL;151 152	return bits;153}154 155static int cm3323_read_raw(struct iio_dev *indio_dev,156			   struct iio_chan_spec const *chan, int *val,157			   int *val2, long mask)158{159	int ret;160	struct cm3323_data *data = iio_priv(indio_dev);161 162	switch (mask) {163	case IIO_CHAN_INFO_RAW:164		mutex_lock(&data->mutex);165		ret = i2c_smbus_read_word_data(data->client, chan->address);166		if (ret < 0) {167			mutex_unlock(&data->mutex);168			return ret;169		}170		*val = ret;171		mutex_unlock(&data->mutex);172 173		return IIO_VAL_INT;174	case IIO_CHAN_INFO_INT_TIME:175		mutex_lock(&data->mutex);176		ret = cm3323_get_it_bits(data);177		if (ret < 0) {178			mutex_unlock(&data->mutex);179			return ret;180		}181 182		*val = cm3323_int_time[ret].val;183		*val2 = cm3323_int_time[ret].val2;184		mutex_unlock(&data->mutex);185 186		return IIO_VAL_INT_PLUS_MICRO;187	default:188		return -EINVAL;189	}190}191 192static int cm3323_write_raw(struct iio_dev *indio_dev,193			    struct iio_chan_spec const *chan, int val,194			    int val2, long mask)195{196	struct cm3323_data *data = iio_priv(indio_dev);197	int ret;198 199	switch (mask) {200	case IIO_CHAN_INFO_INT_TIME:201		mutex_lock(&data->mutex);202		ret = cm3323_set_it_bits(data, val, val2);203		mutex_unlock(&data->mutex);204 205		return ret;206	default:207		return -EINVAL;208	}209}210 211static const struct iio_info cm3323_info = {212	.read_raw	= cm3323_read_raw,213	.write_raw	= cm3323_write_raw,214	.attrs		= &cm3323_attribute_group,215};216 217static int cm3323_probe(struct i2c_client *client)218{219	struct cm3323_data *data;220	struct iio_dev *indio_dev;221	int ret;222 223	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));224	if (!indio_dev)225		return -ENOMEM;226 227	data = iio_priv(indio_dev);228	i2c_set_clientdata(client, indio_dev);229	data->client = client;230 231	mutex_init(&data->mutex);232 233	indio_dev->info = &cm3323_info;234	indio_dev->name = CM3323_DRV_NAME;235	indio_dev->channels = cm3323_channels;236	indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);237	indio_dev->modes = INDIO_DIRECT_MODE;238 239	ret = cm3323_init(indio_dev);240	if (ret < 0) {241		dev_err(&client->dev, "cm3323 chip init failed\n");242		return ret;243	}244 245	ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);246	if (ret < 0)247		return ret;248 249	return devm_iio_device_register(&client->dev, indio_dev);250}251 252static const struct i2c_device_id cm3323_id[] = {253	{ "cm3323" },254	{}255};256MODULE_DEVICE_TABLE(i2c, cm3323_id);257 258static const struct of_device_id cm3323_of_match[] = {259	{ .compatible = "capella,cm3323", },260	{ /* sentinel */ }261};262MODULE_DEVICE_TABLE(of, cm3323_of_match);263 264static struct i2c_driver cm3323_driver = {265	.driver = {266		.name = CM3323_DRV_NAME,267		.of_match_table = cm3323_of_match,268	},269	.probe		= cm3323_probe,270	.id_table	= cm3323_id,271};272 273module_i2c_driver(cm3323_driver);274 275MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");276MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");277MODULE_LICENSE("GPL v2");278