cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tsl4531.c (5772B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * tsl4531.c - Support for TAOS TSL4531 ambient light sensor
      4 *
      5 * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net>
      6 *
      7 * IIO driver for the TSL4531x family
      8 *   TSL45311/TSL45313: 7-bit I2C slave address 0x39
      9 *   TSL45315/TSL45317: 7-bit I2C slave address 0x29
     10 *
     11 * TODO: single cycle measurement
     12 */
     13
     14#include <linux/module.h>
     15#include <linux/i2c.h>
     16#include <linux/err.h>
     17#include <linux/delay.h>
     18
     19#include <linux/iio/iio.h>
     20#include <linux/iio/sysfs.h>
     21
     22#define TSL4531_DRV_NAME "tsl4531"
     23
     24#define TSL4531_COMMAND BIT(7)
     25
     26#define TSL4531_CONTROL (TSL4531_COMMAND | 0x00)
     27#define TSL4531_CONFIG (TSL4531_COMMAND | 0x01)
     28#define TSL4531_DATA (TSL4531_COMMAND | 0x04)
     29#define TSL4531_ID (TSL4531_COMMAND | 0x0a)
     30
     31/* operating modes in control register */
     32#define TSL4531_MODE_POWERDOWN 0x00
     33#define TSL4531_MODE_SINGLE_ADC 0x02
     34#define TSL4531_MODE_NORMAL 0x03
     35
     36/* integration time control in config register */
     37#define TSL4531_TCNTRL_400MS 0x00
     38#define TSL4531_TCNTRL_200MS 0x01
     39#define TSL4531_TCNTRL_100MS 0x02
     40
     41/* part number in id register */
     42#define TSL45311_ID 0x8
     43#define TSL45313_ID 0x9
     44#define TSL45315_ID 0xa
     45#define TSL45317_ID 0xb
     46#define TSL4531_ID_SHIFT 4
     47
     48struct tsl4531_data {
     49	struct i2c_client *client;
     50	struct mutex lock;
     51	int int_time;
     52};
     53
     54static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4");
     55
     56static struct attribute *tsl4531_attributes[] = {
     57	&iio_const_attr_integration_time_available.dev_attr.attr,
     58	NULL
     59};
     60
     61static const struct attribute_group tsl4531_attribute_group = {
     62	.attrs = tsl4531_attributes,
     63};
     64
     65static const struct iio_chan_spec tsl4531_channels[] = {
     66	{
     67		.type = IIO_LIGHT,
     68		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
     69			BIT(IIO_CHAN_INFO_SCALE) |
     70			BIT(IIO_CHAN_INFO_INT_TIME)
     71	}
     72};
     73
     74static int tsl4531_read_raw(struct iio_dev *indio_dev,
     75				struct iio_chan_spec const *chan,
     76				int *val, int *val2, long mask)
     77{
     78	struct tsl4531_data *data = iio_priv(indio_dev);
     79	int ret;
     80
     81	switch (mask) {
     82	case IIO_CHAN_INFO_RAW:
     83		ret = i2c_smbus_read_word_data(data->client,
     84			TSL4531_DATA);
     85		if (ret < 0)
     86			return ret;
     87		*val = ret;
     88		return IIO_VAL_INT;
     89	case IIO_CHAN_INFO_SCALE:
     90		/* 0.. 1x, 1 .. 2x, 2 .. 4x */
     91		*val = 1 << data->int_time;
     92		return IIO_VAL_INT;
     93	case IIO_CHAN_INFO_INT_TIME:
     94		if (data->int_time == 0)
     95			*val2 = 400000;
     96		else if (data->int_time == 1)
     97			*val2 = 200000;
     98		else if (data->int_time == 2)
     99			*val2 = 100000;
    100		else
    101			return -EINVAL;
    102		*val = 0;
    103		return IIO_VAL_INT_PLUS_MICRO;
    104	default:
    105		return -EINVAL;
    106	}
    107}
    108
    109static int tsl4531_write_raw(struct iio_dev *indio_dev,
    110			     struct iio_chan_spec const *chan,
    111			     int val, int val2, long mask)
    112{
    113	struct tsl4531_data *data = iio_priv(indio_dev);
    114	int int_time, ret;
    115
    116	switch (mask) {
    117	case IIO_CHAN_INFO_INT_TIME:
    118		if (val != 0)
    119			return -EINVAL;
    120		if (val2 == 400000)
    121			int_time = 0;
    122		else if (val2 == 200000)
    123			int_time = 1;
    124		else if (val2 == 100000)
    125			int_time = 2;
    126		else
    127			return -EINVAL;
    128		mutex_lock(&data->lock);
    129		ret = i2c_smbus_write_byte_data(data->client,
    130			TSL4531_CONFIG, int_time);
    131		if (ret >= 0)
    132			data->int_time = int_time;
    133		mutex_unlock(&data->lock);
    134		return ret;
    135	default:
    136		return -EINVAL;
    137	}
    138}
    139
    140static const struct iio_info tsl4531_info = {
    141	.read_raw = tsl4531_read_raw,
    142	.write_raw = tsl4531_write_raw,
    143	.attrs = &tsl4531_attribute_group,
    144};
    145
    146static int tsl4531_check_id(struct i2c_client *client)
    147{
    148	int ret = i2c_smbus_read_byte_data(client, TSL4531_ID);
    149	if (ret < 0)
    150		return ret;
    151
    152	switch (ret >> TSL4531_ID_SHIFT) {
    153	case TSL45311_ID:
    154	case TSL45313_ID:
    155	case TSL45315_ID:
    156	case TSL45317_ID:
    157		return 0;
    158	default:
    159		return -ENODEV;
    160	}
    161}
    162
    163static int tsl4531_probe(struct i2c_client *client,
    164			  const struct i2c_device_id *id)
    165{
    166	struct tsl4531_data *data;
    167	struct iio_dev *indio_dev;
    168	int ret;
    169
    170	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    171	if (!indio_dev)
    172		return -ENOMEM;
    173
    174	data = iio_priv(indio_dev);
    175	i2c_set_clientdata(client, indio_dev);
    176	data->client = client;
    177	mutex_init(&data->lock);
    178
    179	ret = tsl4531_check_id(client);
    180	if (ret) {
    181		dev_err(&client->dev, "no TSL4531 sensor\n");
    182		return ret;
    183	}
    184
    185	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
    186		TSL4531_MODE_NORMAL);
    187	if (ret < 0)
    188		return ret;
    189
    190	ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG,
    191		TSL4531_TCNTRL_400MS);
    192	if (ret < 0)
    193		return ret;
    194
    195	indio_dev->info = &tsl4531_info;
    196	indio_dev->channels = tsl4531_channels;
    197	indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels);
    198	indio_dev->name = TSL4531_DRV_NAME;
    199	indio_dev->modes = INDIO_DIRECT_MODE;
    200
    201	return iio_device_register(indio_dev);
    202}
    203
    204static int tsl4531_powerdown(struct i2c_client *client)
    205{
    206	return i2c_smbus_write_byte_data(client, TSL4531_CONTROL,
    207		TSL4531_MODE_POWERDOWN);
    208}
    209
    210static int tsl4531_remove(struct i2c_client *client)
    211{
    212	iio_device_unregister(i2c_get_clientdata(client));
    213	tsl4531_powerdown(client);
    214
    215	return 0;
    216}
    217
    218static int tsl4531_suspend(struct device *dev)
    219{
    220	return tsl4531_powerdown(to_i2c_client(dev));
    221}
    222
    223static int tsl4531_resume(struct device *dev)
    224{
    225	return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL,
    226		TSL4531_MODE_NORMAL);
    227}
    228
    229static DEFINE_SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend,
    230				tsl4531_resume);
    231
    232static const struct i2c_device_id tsl4531_id[] = {
    233	{ "tsl4531", 0 },
    234	{ }
    235};
    236MODULE_DEVICE_TABLE(i2c, tsl4531_id);
    237
    238static struct i2c_driver tsl4531_driver = {
    239	.driver = {
    240		.name   = TSL4531_DRV_NAME,
    241		.pm	= pm_sleep_ptr(&tsl4531_pm_ops),
    242	},
    243	.probe  = tsl4531_probe,
    244	.remove = tsl4531_remove,
    245	.id_table = tsl4531_id,
    246};
    247
    248module_i2c_driver(tsl4531_driver);
    249
    250MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
    251MODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors driver");
    252MODULE_LICENSE("GPL");