162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * tcs3414.c - Support for TAOS TCS3414 digital color sensor
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Digital color sensor with 16-bit channels for red, green, blue, clear);
862306a36Sopenharmony_ci * 7-bit I2C slave address 0x39 (TCS3414) or 0x29, 0x49, 0x59 (TCS3413,
962306a36Sopenharmony_ci * TCS3415, TCS3416, resp.)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * TODO: sync, interrupt support, thresholds, prescaler
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/pm.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/iio/iio.h>
2062306a36Sopenharmony_ci#include <linux/iio/sysfs.h>
2162306a36Sopenharmony_ci#include <linux/iio/trigger_consumer.h>
2262306a36Sopenharmony_ci#include <linux/iio/buffer.h>
2362306a36Sopenharmony_ci#include <linux/iio/triggered_buffer.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define TCS3414_DRV_NAME "tcs3414"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define TCS3414_COMMAND BIT(7)
2862306a36Sopenharmony_ci#define TCS3414_COMMAND_WORD (TCS3414_COMMAND | BIT(5))
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define TCS3414_CONTROL (TCS3414_COMMAND | 0x00)
3162306a36Sopenharmony_ci#define TCS3414_TIMING (TCS3414_COMMAND | 0x01)
3262306a36Sopenharmony_ci#define TCS3414_ID (TCS3414_COMMAND | 0x04)
3362306a36Sopenharmony_ci#define TCS3414_GAIN (TCS3414_COMMAND | 0x07)
3462306a36Sopenharmony_ci#define TCS3414_DATA_GREEN (TCS3414_COMMAND_WORD | 0x10)
3562306a36Sopenharmony_ci#define TCS3414_DATA_RED (TCS3414_COMMAND_WORD | 0x12)
3662306a36Sopenharmony_ci#define TCS3414_DATA_BLUE (TCS3414_COMMAND_WORD | 0x14)
3762306a36Sopenharmony_ci#define TCS3414_DATA_CLEAR (TCS3414_COMMAND_WORD | 0x16)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define TCS3414_CONTROL_ADC_VALID BIT(4)
4062306a36Sopenharmony_ci#define TCS3414_CONTROL_ADC_EN BIT(1)
4162306a36Sopenharmony_ci#define TCS3414_CONTROL_POWER BIT(0)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define TCS3414_INTEG_MASK GENMASK(1, 0)
4462306a36Sopenharmony_ci#define TCS3414_INTEG_12MS 0x0
4562306a36Sopenharmony_ci#define TCS3414_INTEG_100MS 0x1
4662306a36Sopenharmony_ci#define TCS3414_INTEG_400MS 0x2
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define TCS3414_GAIN_MASK GENMASK(5, 4)
4962306a36Sopenharmony_ci#define TCS3414_GAIN_SHIFT 4
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistruct tcs3414_data {
5262306a36Sopenharmony_ci	struct i2c_client *client;
5362306a36Sopenharmony_ci	u8 control;
5462306a36Sopenharmony_ci	u8 gain;
5562306a36Sopenharmony_ci	u8 timing;
5662306a36Sopenharmony_ci	/* Ensure timestamp is naturally aligned */
5762306a36Sopenharmony_ci	struct {
5862306a36Sopenharmony_ci		u16 chans[4];
5962306a36Sopenharmony_ci		s64 timestamp __aligned(8);
6062306a36Sopenharmony_ci	} scan;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define TCS3414_CHANNEL(_color, _si, _addr) { \
6462306a36Sopenharmony_ci	.type = IIO_INTENSITY, \
6562306a36Sopenharmony_ci	.modified = 1, \
6662306a36Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
6762306a36Sopenharmony_ci	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
6862306a36Sopenharmony_ci		BIT(IIO_CHAN_INFO_INT_TIME), \
6962306a36Sopenharmony_ci	.channel2 = IIO_MOD_LIGHT_##_color, \
7062306a36Sopenharmony_ci	.address = _addr, \
7162306a36Sopenharmony_ci	.scan_index = _si, \
7262306a36Sopenharmony_ci	.scan_type = { \
7362306a36Sopenharmony_ci		.sign = 'u', \
7462306a36Sopenharmony_ci		.realbits = 16, \
7562306a36Sopenharmony_ci		.storagebits = 16, \
7662306a36Sopenharmony_ci		.endianness = IIO_CPU, \
7762306a36Sopenharmony_ci	}, \
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* scale factors: 1/gain */
8162306a36Sopenharmony_cistatic const int tcs3414_scales[][2] = {
8262306a36Sopenharmony_ci	{1, 0}, {0, 250000}, {0, 62500}, {0, 15625}
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* integration time in ms */
8662306a36Sopenharmony_cistatic const int tcs3414_times[] = { 12, 100, 400 };
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const struct iio_chan_spec tcs3414_channels[] = {
8962306a36Sopenharmony_ci	TCS3414_CHANNEL(GREEN, 0, TCS3414_DATA_GREEN),
9062306a36Sopenharmony_ci	TCS3414_CHANNEL(RED, 1, TCS3414_DATA_RED),
9162306a36Sopenharmony_ci	TCS3414_CHANNEL(BLUE, 2, TCS3414_DATA_BLUE),
9262306a36Sopenharmony_ci	TCS3414_CHANNEL(CLEAR, 3, TCS3414_DATA_CLEAR),
9362306a36Sopenharmony_ci	IIO_CHAN_SOFT_TIMESTAMP(4),
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int tcs3414_req_data(struct tcs3414_data *data)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int tries = 25;
9962306a36Sopenharmony_ci	int ret;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
10262306a36Sopenharmony_ci		data->control | TCS3414_CONTROL_ADC_EN);
10362306a36Sopenharmony_ci	if (ret < 0)
10462306a36Sopenharmony_ci		return ret;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	while (tries--) {
10762306a36Sopenharmony_ci		ret = i2c_smbus_read_byte_data(data->client, TCS3414_CONTROL);
10862306a36Sopenharmony_ci		if (ret < 0)
10962306a36Sopenharmony_ci			return ret;
11062306a36Sopenharmony_ci		if (ret & TCS3414_CONTROL_ADC_VALID)
11162306a36Sopenharmony_ci			break;
11262306a36Sopenharmony_ci		msleep(20);
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
11662306a36Sopenharmony_ci		data->control);
11762306a36Sopenharmony_ci	if (ret < 0)
11862306a36Sopenharmony_ci		return ret;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (tries < 0) {
12162306a36Sopenharmony_ci		dev_err(&data->client->dev, "data not ready\n");
12262306a36Sopenharmony_ci		return -EIO;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int tcs3414_read_raw(struct iio_dev *indio_dev,
12962306a36Sopenharmony_ci			   struct iio_chan_spec const *chan,
13062306a36Sopenharmony_ci			   int *val, int *val2, long mask)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(indio_dev);
13362306a36Sopenharmony_ci	int i, ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	switch (mask) {
13662306a36Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
13762306a36Sopenharmony_ci		ret = iio_device_claim_direct_mode(indio_dev);
13862306a36Sopenharmony_ci		if (ret)
13962306a36Sopenharmony_ci			return ret;
14062306a36Sopenharmony_ci		ret = tcs3414_req_data(data);
14162306a36Sopenharmony_ci		if (ret < 0) {
14262306a36Sopenharmony_ci			iio_device_release_direct_mode(indio_dev);
14362306a36Sopenharmony_ci			return ret;
14462306a36Sopenharmony_ci		}
14562306a36Sopenharmony_ci		ret = i2c_smbus_read_word_data(data->client, chan->address);
14662306a36Sopenharmony_ci		iio_device_release_direct_mode(indio_dev);
14762306a36Sopenharmony_ci		if (ret < 0)
14862306a36Sopenharmony_ci			return ret;
14962306a36Sopenharmony_ci		*val = ret;
15062306a36Sopenharmony_ci		return IIO_VAL_INT;
15162306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
15262306a36Sopenharmony_ci		i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
15362306a36Sopenharmony_ci		*val = tcs3414_scales[i][0];
15462306a36Sopenharmony_ci		*val2 = tcs3414_scales[i][1];
15562306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
15662306a36Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
15762306a36Sopenharmony_ci		*val = 0;
15862306a36Sopenharmony_ci		*val2 = tcs3414_times[data->timing & TCS3414_INTEG_MASK] * 1000;
15962306a36Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	return -EINVAL;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic int tcs3414_write_raw(struct iio_dev *indio_dev,
16562306a36Sopenharmony_ci			       struct iio_chan_spec const *chan,
16662306a36Sopenharmony_ci			       int val, int val2, long mask)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(indio_dev);
16962306a36Sopenharmony_ci	int i;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	switch (mask) {
17262306a36Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
17362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(tcs3414_scales); i++) {
17462306a36Sopenharmony_ci			if (val == tcs3414_scales[i][0] &&
17562306a36Sopenharmony_ci				val2 == tcs3414_scales[i][1]) {
17662306a36Sopenharmony_ci				data->gain &= ~TCS3414_GAIN_MASK;
17762306a36Sopenharmony_ci				data->gain |= i << TCS3414_GAIN_SHIFT;
17862306a36Sopenharmony_ci				return i2c_smbus_write_byte_data(
17962306a36Sopenharmony_ci					data->client, TCS3414_GAIN,
18062306a36Sopenharmony_ci					data->gain);
18162306a36Sopenharmony_ci			}
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci		return -EINVAL;
18462306a36Sopenharmony_ci	case IIO_CHAN_INFO_INT_TIME:
18562306a36Sopenharmony_ci		if (val != 0)
18662306a36Sopenharmony_ci			return -EINVAL;
18762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(tcs3414_times); i++) {
18862306a36Sopenharmony_ci			if (val2 == tcs3414_times[i] * 1000) {
18962306a36Sopenharmony_ci				data->timing &= ~TCS3414_INTEG_MASK;
19062306a36Sopenharmony_ci				data->timing |= i;
19162306a36Sopenharmony_ci				return i2c_smbus_write_byte_data(
19262306a36Sopenharmony_ci					data->client, TCS3414_TIMING,
19362306a36Sopenharmony_ci					data->timing);
19462306a36Sopenharmony_ci			}
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci	default:
19862306a36Sopenharmony_ci		return -EINVAL;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic irqreturn_t tcs3414_trigger_handler(int irq, void *p)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct iio_poll_func *pf = p;
20562306a36Sopenharmony_ci	struct iio_dev *indio_dev = pf->indio_dev;
20662306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(indio_dev);
20762306a36Sopenharmony_ci	int i, j = 0;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for_each_set_bit(i, indio_dev->active_scan_mask,
21062306a36Sopenharmony_ci		indio_dev->masklength) {
21162306a36Sopenharmony_ci		int ret = i2c_smbus_read_word_data(data->client,
21262306a36Sopenharmony_ci			TCS3414_DATA_GREEN + 2*i);
21362306a36Sopenharmony_ci		if (ret < 0)
21462306a36Sopenharmony_ci			goto done;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		data->scan.chans[j++] = ret;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
22062306a36Sopenharmony_ci		iio_get_time_ns(indio_dev));
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cidone:
22362306a36Sopenharmony_ci	iio_trigger_notify_done(indio_dev->trig);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return IRQ_HANDLED;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic IIO_CONST_ATTR(scale_available, "1 0.25 0.0625 0.015625");
22962306a36Sopenharmony_cistatic IIO_CONST_ATTR_INT_TIME_AVAIL("0.012 0.1 0.4");
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic struct attribute *tcs3414_attributes[] = {
23262306a36Sopenharmony_ci	&iio_const_attr_scale_available.dev_attr.attr,
23362306a36Sopenharmony_ci	&iio_const_attr_integration_time_available.dev_attr.attr,
23462306a36Sopenharmony_ci	NULL
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const struct attribute_group tcs3414_attribute_group = {
23862306a36Sopenharmony_ci	.attrs = tcs3414_attributes,
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic const struct iio_info tcs3414_info = {
24262306a36Sopenharmony_ci	.read_raw = tcs3414_read_raw,
24362306a36Sopenharmony_ci	.write_raw = tcs3414_write_raw,
24462306a36Sopenharmony_ci	.attrs = &tcs3414_attribute_group,
24562306a36Sopenharmony_ci};
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int tcs3414_buffer_postenable(struct iio_dev *indio_dev)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(indio_dev);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	data->control |= TCS3414_CONTROL_ADC_EN;
25262306a36Sopenharmony_ci	return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
25362306a36Sopenharmony_ci		data->control);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int tcs3414_buffer_predisable(struct iio_dev *indio_dev)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(indio_dev);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	data->control &= ~TCS3414_CONTROL_ADC_EN;
26162306a36Sopenharmony_ci	return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
26262306a36Sopenharmony_ci		data->control);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = {
26662306a36Sopenharmony_ci	.postenable = tcs3414_buffer_postenable,
26762306a36Sopenharmony_ci	.predisable = tcs3414_buffer_predisable,
26862306a36Sopenharmony_ci};
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic int tcs3414_powerdown(struct tcs3414_data *data)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
27362306a36Sopenharmony_ci		data->control & ~(TCS3414_CONTROL_POWER |
27462306a36Sopenharmony_ci		TCS3414_CONTROL_ADC_EN));
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void tcs3414_powerdown_cleanup(void *data)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	tcs3414_powerdown(data);
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int tcs3414_probe(struct i2c_client *client)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct tcs3414_data *data;
28562306a36Sopenharmony_ci	struct iio_dev *indio_dev;
28662306a36Sopenharmony_ci	int ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
28962306a36Sopenharmony_ci	if (indio_dev == NULL)
29062306a36Sopenharmony_ci		return -ENOMEM;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	data = iio_priv(indio_dev);
29362306a36Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
29462306a36Sopenharmony_ci	data->client = client;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	indio_dev->info = &tcs3414_info;
29762306a36Sopenharmony_ci	indio_dev->name = TCS3414_DRV_NAME;
29862306a36Sopenharmony_ci	indio_dev->channels = tcs3414_channels;
29962306a36Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(tcs3414_channels);
30062306a36Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(data->client, TCS3414_ID);
30362306a36Sopenharmony_ci	if (ret < 0)
30462306a36Sopenharmony_ci		return ret;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	switch (ret & 0xf0) {
30762306a36Sopenharmony_ci	case 0x00:
30862306a36Sopenharmony_ci		dev_info(&client->dev, "TCS3404 found\n");
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case 0x10:
31162306a36Sopenharmony_ci		dev_info(&client->dev, "TCS3413/14/15/16 found\n");
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	default:
31462306a36Sopenharmony_ci		return -ENODEV;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	data->control = TCS3414_CONTROL_POWER;
31862306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
31962306a36Sopenharmony_ci		data->control);
32062306a36Sopenharmony_ci	if (ret < 0)
32162306a36Sopenharmony_ci		return ret;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	ret = devm_add_action_or_reset(&client->dev, tcs3414_powerdown_cleanup,
32462306a36Sopenharmony_ci				       data);
32562306a36Sopenharmony_ci	if (ret < 0)
32662306a36Sopenharmony_ci		return ret;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	data->timing = TCS3414_INTEG_12MS; /* free running */
32962306a36Sopenharmony_ci	ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING,
33062306a36Sopenharmony_ci		data->timing);
33162306a36Sopenharmony_ci	if (ret < 0)
33262306a36Sopenharmony_ci		return ret;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	ret = i2c_smbus_read_byte_data(data->client, TCS3414_GAIN);
33562306a36Sopenharmony_ci	if (ret < 0)
33662306a36Sopenharmony_ci		return ret;
33762306a36Sopenharmony_ci	data->gain = ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, NULL,
34062306a36Sopenharmony_ci		tcs3414_trigger_handler, &tcs3414_buffer_setup_ops);
34162306a36Sopenharmony_ci	if (ret < 0)
34262306a36Sopenharmony_ci		return ret;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return devm_iio_device_register(&client->dev, indio_dev);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int tcs3414_suspend(struct device *dev)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
35062306a36Sopenharmony_ci		to_i2c_client(dev)));
35162306a36Sopenharmony_ci	return tcs3414_powerdown(data);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic int tcs3414_resume(struct device *dev)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
35762306a36Sopenharmony_ci		to_i2c_client(dev)));
35862306a36Sopenharmony_ci	return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
35962306a36Sopenharmony_ci		data->control);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend,
36362306a36Sopenharmony_ci				tcs3414_resume);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic const struct i2c_device_id tcs3414_id[] = {
36662306a36Sopenharmony_ci	{ "tcs3414", 0 },
36762306a36Sopenharmony_ci	{ }
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tcs3414_id);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic struct i2c_driver tcs3414_driver = {
37262306a36Sopenharmony_ci	.driver = {
37362306a36Sopenharmony_ci		.name	= TCS3414_DRV_NAME,
37462306a36Sopenharmony_ci		.pm	= pm_sleep_ptr(&tcs3414_pm_ops),
37562306a36Sopenharmony_ci	},
37662306a36Sopenharmony_ci	.probe		= tcs3414_probe,
37762306a36Sopenharmony_ci	.id_table	= tcs3414_id,
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_cimodule_i2c_driver(tcs3414_driver);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ciMODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
38262306a36Sopenharmony_ciMODULE_DESCRIPTION("TCS3414 digital color sensors driver");
38362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
384