154359Sroberto// SPDX-License-Identifier: GPL-2.0-only
254359Sroberto/*
354359Sroberto * tsl4531.c - Support for TAOS TSL4531 ambient light sensor
454359Sroberto *
554359Sroberto * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net>
654359Sroberto *
754359Sroberto * IIO driver for the TSL4531x family
854359Sroberto *   TSL45311/TSL45313: 7-bit I2C slave address 0x39
954359Sroberto *   TSL45315/TSL45317: 7-bit I2C slave address 0x29
1054359Sroberto *
1154359Sroberto * TODO: single cycle measurement
1254359Sroberto */
1354359Sroberto
1454359Sroberto#include <linux/module.h>
1554359Sroberto#include <linux/i2c.h>
1654359Sroberto#include <linux/err.h>
1754359Sroberto#include <linux/delay.h>
1854359Sroberto
1954359Sroberto#include <linux/iio/iio.h>
2054359Sroberto#include <linux/iio/sysfs.h>
2154359Sroberto
2254359Sroberto#define TSL4531_DRV_NAME "tsl4531"
2354359Sroberto
2454359Sroberto#define TSL4531_COMMAND BIT(7)
2554359Sroberto
2654359Sroberto#define TSL4531_CONTROL (TSL4531_COMMAND | 0x00)
2754359Sroberto#define TSL4531_CONFIG (TSL4531_COMMAND | 0x01)
2854359Sroberto#define TSL4531_DATA (TSL4531_COMMAND | 0x04)
2954359Sroberto#define TSL4531_ID (TSL4531_COMMAND | 0x0a)
3054359Sroberto
3154359Sroberto/* operating modes in control register */
3254359Sroberto#define TSL4531_MODE_POWERDOWN 0x00
3354359Sroberto#define TSL4531_MODE_SINGLE_ADC 0x02
3454359Sroberto#define TSL4531_MODE_NORMAL 0x03
35280849Scy
3654359Sroberto/* integration time control in config register */
3754359Sroberto#define TSL4531_TCNTRL_400MS 0x00
3854359Sroberto#define TSL4531_TCNTRL_200MS 0x01
3954359Sroberto#define TSL4531_TCNTRL_100MS 0x02
4054359Sroberto
4154359Sroberto/* part number in id register */
4254359Sroberto#define TSL45311_ID 0x8
4354359Sroberto#define TSL45313_ID 0x9
4454359Sroberto#define TSL45315_ID 0xa
4554359Sroberto#define TSL45317_ID 0xb
4654359Sroberto#define TSL4531_ID_SHIFT 4
4754359Sroberto
4854359Srobertostruct tsl4531_data {
4954359Sroberto	struct i2c_client *client;
5054359Sroberto	struct mutex lock;
5154359Sroberto	int int_time;
5254359Sroberto};
5354359Sroberto
5454359Srobertostatic IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4");
5554359Sroberto
5654359Srobertostatic struct attribute *tsl4531_attributes[] = {
5754359Sroberto	&iio_const_attr_integration_time_available.dev_attr.attr,
5854359Sroberto	NULL
5954359Sroberto};
6054359Sroberto
6154359Srobertostatic const struct attribute_group tsl4531_attribute_group = {
6254359Sroberto	.attrs = tsl4531_attributes,
6354359Sroberto};
6454359Sroberto
6554359Srobertostatic const struct iio_chan_spec tsl4531_channels[] = {
6654359Sroberto	{
6754359Sroberto		.type = IIO_LIGHT,
68280849Scy		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
6954359Sroberto			BIT(IIO_CHAN_INFO_SCALE) |
7054359Sroberto			BIT(IIO_CHAN_INFO_INT_TIME)
7154359Sroberto	}
7254359Sroberto};
7354359Sroberto
7454359Srobertostatic int tsl4531_read_raw(struct iio_dev *indio_dev,
7554359Sroberto				struct iio_chan_spec const *chan,
7654359Sroberto				int *val, int *val2, long mask)
7754359Sroberto{
78280849Scy	struct tsl4531_data *data = iio_priv(indio_dev);
79280849Scy	int ret;
80280849Scy
81280849Scy	switch (mask) {
82280849Scy	case IIO_CHAN_INFO_RAW:
8354359Sroberto		ret = i2c_smbus_read_word_data(data->client,
84280849Scy			TSL4531_DATA);
85280849Scy		if (ret < 0)
86280849Scy			return ret;
87280849Scy		*val = ret;
88280849Scy		return IIO_VAL_INT;
89280849Scy	case IIO_CHAN_INFO_SCALE:
90280849Scy		/* 0.. 1x, 1 .. 2x, 2 .. 4x */
91280849Scy		*val = 1 << data->int_time;
92280849Scy		return IIO_VAL_INT;
93280849Scy	case IIO_CHAN_INFO_INT_TIME:
94280849Scy		if (data->int_time == 0)
95280849Scy			*val2 = 400000;
96280849Scy		else if (data->int_time == 1)
97280849Scy			*val2 = 200000;
98280849Scy		else if (data->int_time == 2)
99280849Scy			*val2 = 100000;
100280849Scy		else
101280849Scy			return -EINVAL;
102280849Scy		*val = 0;
10354359Sroberto		return IIO_VAL_INT_PLUS_MICRO;
10454359Sroberto	default:
10554359Sroberto		return -EINVAL;
10654359Sroberto	}
10754359Sroberto}
10854359Sroberto
109280849Scystatic int tsl4531_write_raw(struct iio_dev *indio_dev,
11054359Sroberto			     struct iio_chan_spec const *chan,
11154359Sroberto			     int val, int val2, long mask)
11254359Sroberto{
11354359Sroberto	struct tsl4531_data *data = iio_priv(indio_dev);
114280849Scy	int int_time, ret;
115280849Scy
11654359Sroberto	switch (mask) {
11754359Sroberto	case IIO_CHAN_INFO_INT_TIME:
11854359Sroberto		if (val != 0)
11954359Sroberto			return -EINVAL;
12054359Sroberto		if (val2 == 400000)
12154359Sroberto			int_time = 0;
12254359Sroberto		else if (val2 == 200000)
123280849Scy			int_time = 1;
12454359Sroberto		else if (val2 == 100000)
125280849Scy			int_time = 2;
126280849Scy		else
127280849Scy			return -EINVAL;
12854359Sroberto		mutex_lock(&data->lock);
129280849Scy		ret = i2c_smbus_write_byte_data(data->client,
13054359Sroberto			TSL4531_CONFIG, int_time);
131280849Scy		if (ret >= 0)
132280849Scy			data->int_time = int_time;
133280849Scy		mutex_unlock(&data->lock);
13454359Sroberto		return ret;
135280849Scy	default:
13654359Sroberto		return -EINVAL;
137280849Scy	}
138280849Scy}
139280849Scy
140280849Scystatic const struct iio_info tsl4531_info = {
14154359Sroberto	.read_raw = tsl4531_read_raw,
142280849Scy	.write_raw = tsl4531_write_raw,
14354359Sroberto	.attrs = &tsl4531_attribute_group,
144280849Scy};
145280849Scy
146280849Scystatic int tsl4531_check_id(struct i2c_client *client)
147280849Scy{
148280849Scy	int ret = i2c_smbus_read_byte_data(client, TSL4531_ID);
149280849Scy	if (ret < 0)
150280849Scy		return ret;
151280849Scy
152280849Scy	switch (ret >> TSL4531_ID_SHIFT) {
153280849Scy	case TSL45311_ID:
154280849Scy	case TSL45313_ID:
15554359Sroberto	case TSL45315_ID:
15654359Sroberto	case TSL45317_ID:
15754359Sroberto		return 0;
158280849Scy	default:
159280849Scy		return -ENODEV;
160280849Scy	}
161280849Scy}
16254359Sroberto
16354359Srobertostatic int tsl4531_probe(struct i2c_client *client)
16454359Sroberto{
165280849Scy	struct tsl4531_data *data;
166280849Scy	struct iio_dev *indio_dev;
167280849Scy	int ret;
16854359Sroberto
16954359Sroberto	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
17054359Sroberto	if (!indio_dev)
171280849Scy		return -ENOMEM;
172280849Scy
173280849Scy	data = iio_priv(indio_dev);
17454359Sroberto	i2c_set_clientdata(client, indio_dev);
17554359Sroberto	data->client = client;
17654359Sroberto	mutex_init(&data->lock);
177280849Scy
178280849Scy	ret = tsl4531_check_id(client);
179280849Scy	if (ret) {
18054359Sroberto		dev_err(&client->dev, "no TSL4531 sensor\n");
181280849Scy		return ret;
18254359Sroberto	}
183280849Scy
184280849Scy	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
185280849Scy		TSL4531_MODE_NORMAL);
186280849Scy	if (ret < 0)
18754359Sroberto		return ret;
188280849Scy
18954359Sroberto	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG,
19054359Sroberto		TSL4531_TCNTRL_400MS);
19154359Sroberto	if (ret < 0)
19254359Sroberto		return ret;
19354359Sroberto
19454359Sroberto	indio_dev->info = &tsl4531_info;
19554359Sroberto	indio_dev->channels = tsl4531_channels;
196280849Scy	indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels);
197280849Scy	indio_dev->name = TSL4531_DRV_NAME;
198280849Scy	indio_dev->modes = INDIO_DIRECT_MODE;
199280849Scy
200280849Scy	return iio_device_register(indio_dev);
20154359Sroberto}
20254359Sroberto
203280849Scystatic int tsl4531_powerdown(struct i2c_client *client)
20454359Sroberto{
20554359Sroberto	return i2c_smbus_write_byte_data(client, TSL4531_CONTROL,
206280849Scy		TSL4531_MODE_POWERDOWN);
207280849Scy}
208280849Scy
209280849Scystatic void tsl4531_remove(struct i2c_client *client)
210280849Scy{
211280849Scy	iio_device_unregister(i2c_get_clientdata(client));
212280849Scy	tsl4531_powerdown(client);
213280849Scy}
21454359Sroberto
21554359Srobertostatic int tsl4531_suspend(struct device *dev)
21654359Sroberto{
21754359Sroberto	return tsl4531_powerdown(to_i2c_client(dev));
21854359Sroberto}
219280849Scy
220280849Scystatic int tsl4531_resume(struct device *dev)
22154359Sroberto{
22254359Sroberto	return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL,
223280849Scy		TSL4531_MODE_NORMAL);
22454359Sroberto}
22554359Sroberto
22654359Srobertostatic DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend,
22754359Sroberto				tsl4531_resume);
22854359Sroberto
22954359Srobertostatic const struct i2c_device_id tsl4531_id[] = {
23054359Sroberto	{ "tsl4531", 0 },
23154359Sroberto	{ }
23254359Sroberto};
23354359SrobertoMODULE_DEVICE_TABLE(i2c, tsl4531_id);
23454359Sroberto
235182007Srobertostatic struct i2c_driver tsl4531_driver = {
23654359Sroberto	.driver = {
23754359Sroberto		.name   = TSL4531_DRV_NAME,
23854359Sroberto		.pm	= pm_sleep_ptr(&tsl4531_pm_ops),
239280849Scy	},
240280849Scy	.probe = tsl4531_probe,
241280849Scy	.remove = tsl4531_remove,
242280849Scy	.id_table = tsl4531_id,
243280849Scy};
244280849Scy
24554359Srobertomodule_i2c_driver(tsl4531_driver);
24654359Sroberto
24754359SrobertoMODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
24854359SrobertoMODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors driver");
24954359SrobertoMODULE_LICENSE("GPL");
250280849Scy