18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * tsl4531.c - Support for TAOS TSL4531 ambient light sensor 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * IIO driver for the TSL4531x family 88c2ecf20Sopenharmony_ci * TSL45311/TSL45313: 7-bit I2C slave address 0x39 98c2ecf20Sopenharmony_ci * TSL45315/TSL45317: 7-bit I2C slave address 0x29 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * TODO: single cycle measurement 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/i2c.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 208c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define TSL4531_DRV_NAME "tsl4531" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define TSL4531_COMMAND BIT(7) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define TSL4531_CONTROL (TSL4531_COMMAND | 0x00) 278c2ecf20Sopenharmony_ci#define TSL4531_CONFIG (TSL4531_COMMAND | 0x01) 288c2ecf20Sopenharmony_ci#define TSL4531_DATA (TSL4531_COMMAND | 0x04) 298c2ecf20Sopenharmony_ci#define TSL4531_ID (TSL4531_COMMAND | 0x0a) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* operating modes in control register */ 328c2ecf20Sopenharmony_ci#define TSL4531_MODE_POWERDOWN 0x00 338c2ecf20Sopenharmony_ci#define TSL4531_MODE_SINGLE_ADC 0x02 348c2ecf20Sopenharmony_ci#define TSL4531_MODE_NORMAL 0x03 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* integration time control in config register */ 378c2ecf20Sopenharmony_ci#define TSL4531_TCNTRL_400MS 0x00 388c2ecf20Sopenharmony_ci#define TSL4531_TCNTRL_200MS 0x01 398c2ecf20Sopenharmony_ci#define TSL4531_TCNTRL_100MS 0x02 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* part number in id register */ 428c2ecf20Sopenharmony_ci#define TSL45311_ID 0x8 438c2ecf20Sopenharmony_ci#define TSL45313_ID 0x9 448c2ecf20Sopenharmony_ci#define TSL45315_ID 0xa 458c2ecf20Sopenharmony_ci#define TSL45317_ID 0xb 468c2ecf20Sopenharmony_ci#define TSL4531_ID_SHIFT 4 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct tsl4531_data { 498c2ecf20Sopenharmony_ci struct i2c_client *client; 508c2ecf20Sopenharmony_ci struct mutex lock; 518c2ecf20Sopenharmony_ci int int_time; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4"); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct attribute *tsl4531_attributes[] = { 578c2ecf20Sopenharmony_ci &iio_const_attr_integration_time_available.dev_attr.attr, 588c2ecf20Sopenharmony_ci NULL 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic const struct attribute_group tsl4531_attribute_group = { 628c2ecf20Sopenharmony_ci .attrs = tsl4531_attributes, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct iio_chan_spec tsl4531_channels[] = { 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci .type = IIO_LIGHT, 688c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 698c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | 708c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_INT_TIME) 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int tsl4531_read_raw(struct iio_dev *indio_dev, 758c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 768c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct tsl4531_data *data = iio_priv(indio_dev); 798c2ecf20Sopenharmony_ci int ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci switch (mask) { 828c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 838c2ecf20Sopenharmony_ci ret = i2c_smbus_read_word_data(data->client, 848c2ecf20Sopenharmony_ci TSL4531_DATA); 858c2ecf20Sopenharmony_ci if (ret < 0) 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci *val = ret; 888c2ecf20Sopenharmony_ci return IIO_VAL_INT; 898c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 908c2ecf20Sopenharmony_ci /* 0.. 1x, 1 .. 2x, 2 .. 4x */ 918c2ecf20Sopenharmony_ci *val = 1 << data->int_time; 928c2ecf20Sopenharmony_ci return IIO_VAL_INT; 938c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 948c2ecf20Sopenharmony_ci if (data->int_time == 0) 958c2ecf20Sopenharmony_ci *val2 = 400000; 968c2ecf20Sopenharmony_ci else if (data->int_time == 1) 978c2ecf20Sopenharmony_ci *val2 = 200000; 988c2ecf20Sopenharmony_ci else if (data->int_time == 2) 998c2ecf20Sopenharmony_ci *val2 = 100000; 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci return -EINVAL; 1028c2ecf20Sopenharmony_ci *val = 0; 1038c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 1048c2ecf20Sopenharmony_ci default: 1058c2ecf20Sopenharmony_ci return -EINVAL; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int tsl4531_write_raw(struct iio_dev *indio_dev, 1108c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1118c2ecf20Sopenharmony_ci int val, int val2, long mask) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct tsl4531_data *data = iio_priv(indio_dev); 1148c2ecf20Sopenharmony_ci int int_time, ret; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci switch (mask) { 1178c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_INT_TIME: 1188c2ecf20Sopenharmony_ci if (val != 0) 1198c2ecf20Sopenharmony_ci return -EINVAL; 1208c2ecf20Sopenharmony_ci if (val2 == 400000) 1218c2ecf20Sopenharmony_ci int_time = 0; 1228c2ecf20Sopenharmony_ci else if (val2 == 200000) 1238c2ecf20Sopenharmony_ci int_time = 1; 1248c2ecf20Sopenharmony_ci else if (val2 == 100000) 1258c2ecf20Sopenharmony_ci int_time = 2; 1268c2ecf20Sopenharmony_ci else 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci mutex_lock(&data->lock); 1298c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(data->client, 1308c2ecf20Sopenharmony_ci TSL4531_CONFIG, int_time); 1318c2ecf20Sopenharmony_ci if (ret >= 0) 1328c2ecf20Sopenharmony_ci data->int_time = int_time; 1338c2ecf20Sopenharmony_ci mutex_unlock(&data->lock); 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci default: 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct iio_info tsl4531_info = { 1418c2ecf20Sopenharmony_ci .read_raw = tsl4531_read_raw, 1428c2ecf20Sopenharmony_ci .write_raw = tsl4531_write_raw, 1438c2ecf20Sopenharmony_ci .attrs = &tsl4531_attribute_group, 1448c2ecf20Sopenharmony_ci}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int tsl4531_check_id(struct i2c_client *client) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int ret = i2c_smbus_read_byte_data(client, TSL4531_ID); 1498c2ecf20Sopenharmony_ci if (ret < 0) 1508c2ecf20Sopenharmony_ci return ret; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci switch (ret >> TSL4531_ID_SHIFT) { 1538c2ecf20Sopenharmony_ci case TSL45311_ID: 1548c2ecf20Sopenharmony_ci case TSL45313_ID: 1558c2ecf20Sopenharmony_ci case TSL45315_ID: 1568c2ecf20Sopenharmony_ci case TSL45317_ID: 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci default: 1598c2ecf20Sopenharmony_ci return -ENODEV; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int tsl4531_probe(struct i2c_client *client, 1648c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct tsl4531_data *data; 1678c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 1718c2ecf20Sopenharmony_ci if (!indio_dev) 1728c2ecf20Sopenharmony_ci return -ENOMEM; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci data = iio_priv(indio_dev); 1758c2ecf20Sopenharmony_ci i2c_set_clientdata(client, indio_dev); 1768c2ecf20Sopenharmony_ci data->client = client; 1778c2ecf20Sopenharmony_ci mutex_init(&data->lock); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ret = tsl4531_check_id(client); 1808c2ecf20Sopenharmony_ci if (ret) { 1818c2ecf20Sopenharmony_ci dev_err(&client->dev, "no TSL4531 sensor\n"); 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL, 1868c2ecf20Sopenharmony_ci TSL4531_MODE_NORMAL); 1878c2ecf20Sopenharmony_ci if (ret < 0) 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG, 1918c2ecf20Sopenharmony_ci TSL4531_TCNTRL_400MS); 1928c2ecf20Sopenharmony_ci if (ret < 0) 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci indio_dev->info = &tsl4531_info; 1968c2ecf20Sopenharmony_ci indio_dev->channels = tsl4531_channels; 1978c2ecf20Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels); 1988c2ecf20Sopenharmony_ci indio_dev->name = TSL4531_DRV_NAME; 1998c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return iio_device_register(indio_dev); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int tsl4531_powerdown(struct i2c_client *client) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(client, TSL4531_CONTROL, 2078c2ecf20Sopenharmony_ci TSL4531_MODE_POWERDOWN); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int tsl4531_remove(struct i2c_client *client) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci iio_device_unregister(i2c_get_clientdata(client)); 2138c2ecf20Sopenharmony_ci tsl4531_powerdown(client); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return 0; 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 2198c2ecf20Sopenharmony_cistatic int tsl4531_suspend(struct device *dev) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci return tsl4531_powerdown(to_i2c_client(dev)); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int tsl4531_resume(struct device *dev) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL, 2278c2ecf20Sopenharmony_ci TSL4531_MODE_NORMAL); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume); 2318c2ecf20Sopenharmony_ci#define TSL4531_PM_OPS (&tsl4531_pm_ops) 2328c2ecf20Sopenharmony_ci#else 2338c2ecf20Sopenharmony_ci#define TSL4531_PM_OPS NULL 2348c2ecf20Sopenharmony_ci#endif 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct i2c_device_id tsl4531_id[] = { 2378c2ecf20Sopenharmony_ci { "tsl4531", 0 }, 2388c2ecf20Sopenharmony_ci { } 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tsl4531_id); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic struct i2c_driver tsl4531_driver = { 2438c2ecf20Sopenharmony_ci .driver = { 2448c2ecf20Sopenharmony_ci .name = TSL4531_DRV_NAME, 2458c2ecf20Sopenharmony_ci .pm = TSL4531_PM_OPS, 2468c2ecf20Sopenharmony_ci }, 2478c2ecf20Sopenharmony_ci .probe = tsl4531_probe, 2488c2ecf20Sopenharmony_ci .remove = tsl4531_remove, 2498c2ecf20Sopenharmony_ci .id_table = tsl4531_id, 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cimodule_i2c_driver(tsl4531_driver); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 2558c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors driver"); 2568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 257