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

zopt2201.c (13753B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor
      4 *
      5 * Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
      6 *
      7 * Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet
      8 * 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed)
      9 *
     10 * TODO: interrupt support, ALS/UVB raw mode
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/i2c.h>
     15#include <linux/mutex.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#include <asm/unaligned.h>
     23
     24#define ZOPT2201_DRV_NAME "zopt2201"
     25
     26/* Registers */
     27#define ZOPT2201_MAIN_CTRL		0x00
     28#define ZOPT2201_LS_MEAS_RATE		0x04
     29#define ZOPT2201_LS_GAIN		0x05
     30#define ZOPT2201_PART_ID		0x06
     31#define ZOPT2201_MAIN_STATUS		0x07
     32#define ZOPT2201_ALS_DATA		0x0d /* LSB first, 13 to 20 bits */
     33#define ZOPT2201_UVB_DATA		0x10 /* LSB first, 13 to 20 bits */
     34#define ZOPT2201_UV_COMP_DATA		0x13 /* LSB first, 13 to 20 bits */
     35#define ZOPT2201_COMP_DATA		0x16 /* LSB first, 13 to 20 bits */
     36#define ZOPT2201_INT_CFG		0x19
     37#define ZOPT2201_INT_PST		0x1a
     38
     39#define ZOPT2201_MAIN_CTRL_LS_MODE	BIT(3) /* 0 .. ALS, 1 .. UV B */
     40#define ZOPT2201_MAIN_CTRL_LS_EN	BIT(1)
     41
     42/* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */
     43#define ZOPT2201_MEAS_RES_20BIT		0 /* takes 400 ms */
     44#define ZOPT2201_MEAS_RES_19BIT		1 /* takes 200 ms */
     45#define ZOPT2201_MEAS_RES_18BIT		2 /* takes 100 ms, default */
     46#define ZOPT2201_MEAS_RES_17BIT		3 /* takes 50 ms */
     47#define ZOPT2201_MEAS_RES_16BIT		4 /* takes 25 ms */
     48#define ZOPT2201_MEAS_RES_13BIT		5 /* takes 3.125 ms */
     49#define ZOPT2201_MEAS_RES_SHIFT		4
     50
     51/* Values for ZOPT2201_LS_MEAS_RATE measurement rate */
     52#define ZOPT2201_MEAS_FREQ_25MS		0
     53#define ZOPT2201_MEAS_FREQ_50MS		1
     54#define ZOPT2201_MEAS_FREQ_100MS	2 /* default */
     55#define ZOPT2201_MEAS_FREQ_200MS	3
     56#define ZOPT2201_MEAS_FREQ_500MS	4
     57#define ZOPT2201_MEAS_FREQ_1000MS	5
     58#define ZOPT2201_MEAS_FREQ_2000MS	6
     59
     60/* Values for ZOPT2201_LS_GAIN */
     61#define ZOPT2201_LS_GAIN_1		0
     62#define ZOPT2201_LS_GAIN_3		1
     63#define ZOPT2201_LS_GAIN_6		2
     64#define ZOPT2201_LS_GAIN_9		3
     65#define ZOPT2201_LS_GAIN_18		4
     66
     67/* Values for ZOPT2201_MAIN_STATUS */
     68#define ZOPT2201_MAIN_STATUS_POWERON	BIT(5)
     69#define ZOPT2201_MAIN_STATUS_INT	BIT(4)
     70#define ZOPT2201_MAIN_STATUS_DRDY	BIT(3)
     71
     72#define ZOPT2201_PART_NUMBER		0xb2
     73
     74struct zopt2201_data {
     75	struct i2c_client *client;
     76	struct mutex lock;
     77	u8 gain;
     78	u8 res;
     79	u8 rate;
     80};
     81
     82static const struct {
     83	unsigned int gain; /* gain factor */
     84	unsigned int scale; /* micro lux per count */
     85} zopt2201_gain_als[] = {
     86	{  1, 19200000 },
     87	{  3,  6400000 },
     88	{  6,  3200000 },
     89	{  9,  2133333 },
     90	{ 18,  1066666 },
     91};
     92
     93static const struct {
     94	unsigned int gain; /* gain factor */
     95	unsigned int scale; /* micro W/m2 per count */
     96} zopt2201_gain_uvb[] = {
     97	{  1, 460800 },
     98	{  3, 153600 },
     99	{  6,  76800 },
    100	{  9,  51200 },
    101	{ 18,  25600 },
    102};
    103
    104static const struct {
    105	unsigned int bits; /* sensor resolution in bits */
    106	unsigned long us; /* measurement time in micro seconds */
    107} zopt2201_resolution[] = {
    108	{ 20, 400000 },
    109	{ 19, 200000 },
    110	{ 18, 100000 },
    111	{ 17,  50000 },
    112	{ 16,  25000 },
    113	{ 13,   3125 },
    114};
    115
    116static const struct {
    117	unsigned int scale, uscale; /* scale factor as integer + micro */
    118	u8 gain; /* gain register value */
    119	u8 res; /* resolution register value */
    120} zopt2201_scale_als[] = {
    121	{ 19, 200000, 0, 5 },
    122	{  6, 400000, 1, 5 },
    123	{  3, 200000, 2, 5 },
    124	{  2, 400000, 0, 4 },
    125	{  2, 133333, 3, 5 },
    126	{  1, 200000, 0, 3 },
    127	{  1,  66666, 4, 5 },
    128	{  0, 800000, 1, 4 },
    129	{  0, 600000, 0, 2 },
    130	{  0, 400000, 2, 4 },
    131	{  0, 300000, 0, 1 },
    132	{  0, 266666, 3, 4 },
    133	{  0, 200000, 2, 3 },
    134	{  0, 150000, 0, 0 },
    135	{  0, 133333, 4, 4 },
    136	{  0, 100000, 2, 2 },
    137	{  0,  66666, 4, 3 },
    138	{  0,  50000, 2, 1 },
    139	{  0,  33333, 4, 2 },
    140	{  0,  25000, 2, 0 },
    141	{  0,  16666, 4, 1 },
    142	{  0,   8333, 4, 0 },
    143};
    144
    145static const struct {
    146	unsigned int scale, uscale; /* scale factor as integer + micro */
    147	u8 gain; /* gain register value */
    148	u8 res; /* resolution register value */
    149} zopt2201_scale_uvb[] = {
    150	{ 0, 460800, 0, 5 },
    151	{ 0, 153600, 1, 5 },
    152	{ 0,  76800, 2, 5 },
    153	{ 0,  57600, 0, 4 },
    154	{ 0,  51200, 3, 5 },
    155	{ 0,  28800, 0, 3 },
    156	{ 0,  25600, 4, 5 },
    157	{ 0,  19200, 1, 4 },
    158	{ 0,  14400, 0, 2 },
    159	{ 0,   9600, 2, 4 },
    160	{ 0,   7200, 0, 1 },
    161	{ 0,   6400, 3, 4 },
    162	{ 0,   4800, 2, 3 },
    163	{ 0,   3600, 0, 0 },
    164	{ 0,   3200, 4, 4 },
    165	{ 0,   2400, 2, 2 },
    166	{ 0,   1600, 4, 3 },
    167	{ 0,   1200, 2, 1 },
    168	{ 0,    800, 4, 2 },
    169	{ 0,    600, 2, 0 },
    170	{ 0,    400, 4, 1 },
    171	{ 0,    200, 4, 0 },
    172};
    173
    174static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode)
    175{
    176	u8 out = ZOPT2201_MAIN_CTRL_LS_EN;
    177
    178	if (uvb_mode)
    179		out |= ZOPT2201_MAIN_CTRL_LS_MODE;
    180
    181	return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out);
    182}
    183
    184static int zopt2201_read(struct zopt2201_data *data, u8 reg)
    185{
    186	struct i2c_client *client = data->client;
    187	int tries = 10;
    188	u8 buf[3];
    189	int ret;
    190
    191	mutex_lock(&data->lock);
    192	ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
    193	if (ret < 0)
    194		goto fail;
    195
    196	while (tries--) {
    197		unsigned long t = zopt2201_resolution[data->res].us;
    198
    199		if (t <= 20000)
    200			usleep_range(t, t + 1000);
    201		else
    202			msleep(t / 1000);
    203		ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
    204		if (ret < 0)
    205			goto fail;
    206		if (ret & ZOPT2201_MAIN_STATUS_DRDY)
    207			break;
    208	}
    209
    210	if (tries < 0) {
    211		ret = -ETIMEDOUT;
    212		goto fail;
    213	}
    214
    215	ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
    216	if (ret < 0)
    217		goto fail;
    218
    219	ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
    220	if (ret < 0)
    221		goto fail;
    222	mutex_unlock(&data->lock);
    223
    224	return get_unaligned_le24(&buf[0]);
    225
    226fail:
    227	mutex_unlock(&data->lock);
    228	return ret;
    229}
    230
    231static const struct iio_chan_spec zopt2201_channels[] = {
    232	{
    233		.type = IIO_LIGHT,
    234		.address = ZOPT2201_ALS_DATA,
    235		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    236				      BIT(IIO_CHAN_INFO_SCALE),
    237		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
    238	},
    239	{
    240		.type = IIO_INTENSITY,
    241		.modified = 1,
    242		.channel2 = IIO_MOD_LIGHT_UV,
    243		.address = ZOPT2201_UVB_DATA,
    244		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    245				      BIT(IIO_CHAN_INFO_SCALE),
    246		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
    247	},
    248	{
    249		.type = IIO_UVINDEX,
    250		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
    251	},
    252};
    253
    254static int zopt2201_read_raw(struct iio_dev *indio_dev,
    255				struct iio_chan_spec const *chan,
    256				int *val, int *val2, long mask)
    257{
    258	struct zopt2201_data *data = iio_priv(indio_dev);
    259	u64 tmp;
    260	int ret;
    261
    262	switch (mask) {
    263	case IIO_CHAN_INFO_RAW:
    264		ret = zopt2201_read(data, chan->address);
    265		if (ret < 0)
    266			return ret;
    267		*val = ret;
    268		return IIO_VAL_INT;
    269	case IIO_CHAN_INFO_PROCESSED:
    270		ret = zopt2201_read(data, ZOPT2201_UVB_DATA);
    271		if (ret < 0)
    272			return ret;
    273		*val = ret * 18 *
    274			(1 << (20 - zopt2201_resolution[data->res].bits)) /
    275			zopt2201_gain_uvb[data->gain].gain;
    276		return IIO_VAL_INT;
    277	case IIO_CHAN_INFO_SCALE:
    278		switch (chan->address) {
    279		case ZOPT2201_ALS_DATA:
    280			*val = zopt2201_gain_als[data->gain].scale;
    281			break;
    282		case ZOPT2201_UVB_DATA:
    283			*val = zopt2201_gain_uvb[data->gain].scale;
    284			break;
    285		default:
    286			return -EINVAL;
    287		}
    288
    289		*val2 = 1000000;
    290		*val2 *= (1 << (zopt2201_resolution[data->res].bits - 13));
    291		tmp = div_s64(*val * 1000000ULL, *val2);
    292		*val = div_s64_rem(tmp, 1000000, val2);
    293
    294		return IIO_VAL_INT_PLUS_MICRO;
    295	case IIO_CHAN_INFO_INT_TIME:
    296		*val = 0;
    297		*val2 = zopt2201_resolution[data->res].us;
    298		return IIO_VAL_INT_PLUS_MICRO;
    299	default:
    300		return -EINVAL;
    301	}
    302}
    303
    304static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
    305{
    306	int ret;
    307
    308	ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE,
    309					(res << ZOPT2201_MEAS_RES_SHIFT) |
    310					data->rate);
    311	if (ret < 0)
    312		return ret;
    313
    314	data->res = res;
    315
    316	return 0;
    317}
    318
    319static int zopt2201_write_resolution(struct zopt2201_data *data,
    320				     int val, int val2)
    321{
    322	int i, ret;
    323
    324	if (val != 0)
    325		return -EINVAL;
    326
    327	for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
    328		if (val2 == zopt2201_resolution[i].us) {
    329			mutex_lock(&data->lock);
    330			ret = zopt2201_set_resolution(data, i);
    331			mutex_unlock(&data->lock);
    332			return ret;
    333		}
    334
    335	return -EINVAL;
    336}
    337
    338static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
    339{
    340	int ret;
    341
    342	ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain);
    343	if (ret < 0)
    344		return ret;
    345
    346	data->gain = gain;
    347
    348	return 0;
    349}
    350
    351static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
    352{
    353	int ret;
    354
    355	mutex_lock(&data->lock);
    356	ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
    357	if (ret < 0)
    358		goto unlock;
    359
    360	ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
    361
    362unlock:
    363	mutex_unlock(&data->lock);
    364	return ret;
    365}
    366
    367static int zopt2201_write_scale_als(struct zopt2201_data *data,
    368				     int val, int val2)
    369{
    370	int i;
    371
    372	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
    373		if (val == zopt2201_scale_als[i].scale &&
    374		    val2 == zopt2201_scale_als[i].uscale) {
    375			return zopt2201_write_scale_als_by_idx(data, i);
    376		}
    377
    378	return -EINVAL;
    379}
    380
    381static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
    382{
    383	int ret;
    384
    385	mutex_lock(&data->lock);
    386	ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
    387	if (ret < 0)
    388		goto unlock;
    389
    390	ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
    391
    392unlock:
    393	mutex_unlock(&data->lock);
    394	return ret;
    395}
    396
    397static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
    398				     int val, int val2)
    399{
    400	int i;
    401
    402	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
    403		if (val == zopt2201_scale_uvb[i].scale &&
    404		    val2 == zopt2201_scale_uvb[i].uscale)
    405			return zopt2201_write_scale_uvb_by_idx(data, i);
    406
    407	return -EINVAL;
    408}
    409
    410static int zopt2201_write_raw(struct iio_dev *indio_dev,
    411			      struct iio_chan_spec const *chan,
    412			      int val, int val2, long mask)
    413{
    414	struct zopt2201_data *data = iio_priv(indio_dev);
    415
    416	switch (mask) {
    417	case IIO_CHAN_INFO_INT_TIME:
    418		return zopt2201_write_resolution(data, val, val2);
    419	case IIO_CHAN_INFO_SCALE:
    420		switch (chan->address) {
    421		case ZOPT2201_ALS_DATA:
    422			return zopt2201_write_scale_als(data, val, val2);
    423		case ZOPT2201_UVB_DATA:
    424			return zopt2201_write_scale_uvb(data, val, val2);
    425		default:
    426			return -EINVAL;
    427		}
    428	}
    429
    430	return -EINVAL;
    431}
    432
    433static ssize_t zopt2201_show_int_time_available(struct device *dev,
    434						struct device_attribute *attr,
    435						char *buf)
    436{
    437	size_t len = 0;
    438	int i;
    439
    440	for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
    441		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ",
    442				 zopt2201_resolution[i].us);
    443	buf[len - 1] = '\n';
    444
    445	return len;
    446}
    447
    448static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available);
    449
    450static ssize_t zopt2201_show_als_scale_avail(struct device *dev,
    451					     struct device_attribute *attr,
    452					     char *buf)
    453{
    454	ssize_t len = 0;
    455	int i;
    456
    457	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
    458		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
    459				 zopt2201_scale_als[i].scale,
    460				 zopt2201_scale_als[i].uscale);
    461	buf[len - 1] = '\n';
    462
    463	return len;
    464}
    465
    466static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev,
    467					     struct device_attribute *attr,
    468					     char *buf)
    469{
    470	ssize_t len = 0;
    471	int i;
    472
    473	for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
    474		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
    475				 zopt2201_scale_uvb[i].scale,
    476				 zopt2201_scale_uvb[i].uscale);
    477	buf[len - 1] = '\n';
    478
    479	return len;
    480}
    481
    482static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444,
    483		       zopt2201_show_als_scale_avail, NULL, 0);
    484static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444,
    485		       zopt2201_show_uvb_scale_avail, NULL, 0);
    486
    487static struct attribute *zopt2201_attributes[] = {
    488	&iio_dev_attr_integration_time_available.dev_attr.attr,
    489	&iio_dev_attr_in_illuminance_scale_available.dev_attr.attr,
    490	&iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr,
    491	NULL
    492};
    493
    494static const struct attribute_group zopt2201_attribute_group = {
    495	.attrs = zopt2201_attributes,
    496};
    497
    498static const struct iio_info zopt2201_info = {
    499	.read_raw = zopt2201_read_raw,
    500	.write_raw = zopt2201_write_raw,
    501	.attrs = &zopt2201_attribute_group,
    502};
    503
    504static int zopt2201_probe(struct i2c_client *client,
    505			  const struct i2c_device_id *id)
    506{
    507	struct zopt2201_data *data;
    508	struct iio_dev *indio_dev;
    509	int ret;
    510
    511	if (!i2c_check_functionality(client->adapter,
    512				     I2C_FUNC_SMBUS_READ_I2C_BLOCK))
    513		return -EOPNOTSUPP;
    514
    515	ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID);
    516	if (ret < 0)
    517		return ret;
    518	if (ret != ZOPT2201_PART_NUMBER)
    519		return -ENODEV;
    520
    521	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    522	if (!indio_dev)
    523		return -ENOMEM;
    524
    525	data = iio_priv(indio_dev);
    526	i2c_set_clientdata(client, indio_dev);
    527	data->client = client;
    528	mutex_init(&data->lock);
    529
    530	indio_dev->info = &zopt2201_info;
    531	indio_dev->channels = zopt2201_channels;
    532	indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels);
    533	indio_dev->name = ZOPT2201_DRV_NAME;
    534	indio_dev->modes = INDIO_DIRECT_MODE;
    535
    536	data->rate = ZOPT2201_MEAS_FREQ_100MS;
    537	ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT);
    538	if (ret < 0)
    539		return ret;
    540
    541	ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3);
    542	if (ret < 0)
    543		return ret;
    544
    545	return devm_iio_device_register(&client->dev, indio_dev);
    546}
    547
    548static const struct i2c_device_id zopt2201_id[] = {
    549	{ "zopt2201", 0 },
    550	{ }
    551};
    552MODULE_DEVICE_TABLE(i2c, zopt2201_id);
    553
    554static struct i2c_driver zopt2201_driver = {
    555	.driver = {
    556		.name   = ZOPT2201_DRV_NAME,
    557	},
    558	.probe  = zopt2201_probe,
    559	.id_table = zopt2201_id,
    560};
    561
    562module_i2c_driver(zopt2201_driver);
    563
    564MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
    565MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver");
    566MODULE_LICENSE("GPL");