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

lv0104cs.c (11769B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * lv0104cs.c: LV0104CS Ambient Light Sensor Driver
      4 *
      5 * Copyright (C) 2018
      6 * Author: Jeff LaBundy <jeff@labundy.com>
      7 *
      8 * 7-bit I2C slave address: 0x13
      9 *
     10 * Link to data sheet: https://www.onsemi.com/pub/Collateral/LV0104CS-D.PDF
     11 */
     12
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/i2c.h>
     16#include <linux/err.h>
     17#include <linux/mutex.h>
     18#include <linux/delay.h>
     19#include <linux/iio/iio.h>
     20#include <linux/iio/sysfs.h>
     21
     22#define LV0104CS_REGVAL_MEASURE		0xE0
     23#define LV0104CS_REGVAL_SLEEP		0x00
     24
     25#define LV0104CS_SCALE_0_25X		0
     26#define LV0104CS_SCALE_1X		1
     27#define LV0104CS_SCALE_2X		2
     28#define LV0104CS_SCALE_8X		3
     29#define LV0104CS_SCALE_SHIFT		3
     30
     31#define LV0104CS_INTEG_12_5MS		0
     32#define LV0104CS_INTEG_100MS		1
     33#define LV0104CS_INTEG_200MS		2
     34#define LV0104CS_INTEG_SHIFT		1
     35
     36#define LV0104CS_CALIBSCALE_UNITY	31
     37
     38struct lv0104cs_private {
     39	struct i2c_client *client;
     40	struct mutex lock;
     41	u8 calibscale;
     42	u8 scale;
     43	u8 int_time;
     44};
     45
     46struct lv0104cs_mapping {
     47	int val;
     48	int val2;
     49	u8 regval;
     50};
     51
     52static const struct lv0104cs_mapping lv0104cs_calibscales[] = {
     53	{ 0, 666666, 0x81 },
     54	{ 0, 800000, 0x82 },
     55	{ 0, 857142, 0x83 },
     56	{ 0, 888888, 0x84 },
     57	{ 0, 909090, 0x85 },
     58	{ 0, 923076, 0x86 },
     59	{ 0, 933333, 0x87 },
     60	{ 0, 941176, 0x88 },
     61	{ 0, 947368, 0x89 },
     62	{ 0, 952380, 0x8A },
     63	{ 0, 956521, 0x8B },
     64	{ 0, 960000, 0x8C },
     65	{ 0, 962962, 0x8D },
     66	{ 0, 965517, 0x8E },
     67	{ 0, 967741, 0x8F },
     68	{ 0, 969696, 0x90 },
     69	{ 0, 971428, 0x91 },
     70	{ 0, 972972, 0x92 },
     71	{ 0, 974358, 0x93 },
     72	{ 0, 975609, 0x94 },
     73	{ 0, 976744, 0x95 },
     74	{ 0, 977777, 0x96 },
     75	{ 0, 978723, 0x97 },
     76	{ 0, 979591, 0x98 },
     77	{ 0, 980392, 0x99 },
     78	{ 0, 981132, 0x9A },
     79	{ 0, 981818, 0x9B },
     80	{ 0, 982456, 0x9C },
     81	{ 0, 983050, 0x9D },
     82	{ 0, 983606, 0x9E },
     83	{ 0, 984126, 0x9F },
     84	{ 1, 0, 0x80 },
     85	{ 1, 16129, 0xBF },
     86	{ 1, 16666, 0xBE },
     87	{ 1, 17241, 0xBD },
     88	{ 1, 17857, 0xBC },
     89	{ 1, 18518, 0xBB },
     90	{ 1, 19230, 0xBA },
     91	{ 1, 20000, 0xB9 },
     92	{ 1, 20833, 0xB8 },
     93	{ 1, 21739, 0xB7 },
     94	{ 1, 22727, 0xB6 },
     95	{ 1, 23809, 0xB5 },
     96	{ 1, 24999, 0xB4 },
     97	{ 1, 26315, 0xB3 },
     98	{ 1, 27777, 0xB2 },
     99	{ 1, 29411, 0xB1 },
    100	{ 1, 31250, 0xB0 },
    101	{ 1, 33333, 0xAF },
    102	{ 1, 35714, 0xAE },
    103	{ 1, 38461, 0xAD },
    104	{ 1, 41666, 0xAC },
    105	{ 1, 45454, 0xAB },
    106	{ 1, 50000, 0xAA },
    107	{ 1, 55555, 0xA9 },
    108	{ 1, 62500, 0xA8 },
    109	{ 1, 71428, 0xA7 },
    110	{ 1, 83333, 0xA6 },
    111	{ 1, 100000, 0xA5 },
    112	{ 1, 125000, 0xA4 },
    113	{ 1, 166666, 0xA3 },
    114	{ 1, 250000, 0xA2 },
    115	{ 1, 500000, 0xA1 },
    116};
    117
    118static const struct lv0104cs_mapping lv0104cs_scales[] = {
    119	{ 0, 250000, LV0104CS_SCALE_0_25X << LV0104CS_SCALE_SHIFT },
    120	{ 1, 0, LV0104CS_SCALE_1X << LV0104CS_SCALE_SHIFT },
    121	{ 2, 0, LV0104CS_SCALE_2X << LV0104CS_SCALE_SHIFT },
    122	{ 8, 0, LV0104CS_SCALE_8X << LV0104CS_SCALE_SHIFT },
    123};
    124
    125static const struct lv0104cs_mapping lv0104cs_int_times[] = {
    126	{ 0, 12500, LV0104CS_INTEG_12_5MS << LV0104CS_INTEG_SHIFT },
    127	{ 0, 100000, LV0104CS_INTEG_100MS << LV0104CS_INTEG_SHIFT },
    128	{ 0, 200000, LV0104CS_INTEG_200MS << LV0104CS_INTEG_SHIFT },
    129};
    130
    131static int lv0104cs_write_reg(struct i2c_client *client, u8 regval)
    132{
    133	int ret;
    134
    135	ret = i2c_master_send(client, (char *)&regval, sizeof(regval));
    136	if (ret < 0)
    137		return ret;
    138	if (ret != sizeof(regval))
    139		return -EIO;
    140
    141	return 0;
    142}
    143
    144static int lv0104cs_read_adc(struct i2c_client *client, u16 *adc_output)
    145{
    146	__be16 regval;
    147	int ret;
    148
    149	ret = i2c_master_recv(client, (char *)&regval, sizeof(regval));
    150	if (ret < 0)
    151		return ret;
    152	if (ret != sizeof(regval))
    153		return -EIO;
    154
    155	*adc_output = be16_to_cpu(regval);
    156
    157	return 0;
    158}
    159
    160static int lv0104cs_get_lux(struct lv0104cs_private *lv0104cs,
    161				int *val, int *val2)
    162{
    163	u8 regval = LV0104CS_REGVAL_MEASURE;
    164	u16 adc_output;
    165	int ret;
    166
    167	regval |= lv0104cs_scales[lv0104cs->scale].regval;
    168	regval |= lv0104cs_int_times[lv0104cs->int_time].regval;
    169	ret = lv0104cs_write_reg(lv0104cs->client, regval);
    170	if (ret)
    171		return ret;
    172
    173	/* wait for integration time to pass (with margin) */
    174	switch (lv0104cs->int_time) {
    175	case LV0104CS_INTEG_12_5MS:
    176		msleep(50);
    177		break;
    178
    179	case LV0104CS_INTEG_100MS:
    180		msleep(150);
    181		break;
    182
    183	case LV0104CS_INTEG_200MS:
    184		msleep(250);
    185		break;
    186
    187	default:
    188		return -EINVAL;
    189	}
    190
    191	ret = lv0104cs_read_adc(lv0104cs->client, &adc_output);
    192	if (ret)
    193		return ret;
    194
    195	ret = lv0104cs_write_reg(lv0104cs->client, LV0104CS_REGVAL_SLEEP);
    196	if (ret)
    197		return ret;
    198
    199	/* convert ADC output to lux */
    200	switch (lv0104cs->scale) {
    201	case LV0104CS_SCALE_0_25X:
    202		*val = adc_output * 4;
    203		*val2 = 0;
    204		return 0;
    205
    206	case LV0104CS_SCALE_1X:
    207		*val = adc_output;
    208		*val2 = 0;
    209		return 0;
    210
    211	case LV0104CS_SCALE_2X:
    212		*val = adc_output / 2;
    213		*val2 = (adc_output % 2) * 500000;
    214		return 0;
    215
    216	case LV0104CS_SCALE_8X:
    217		*val = adc_output / 8;
    218		*val2 = (adc_output % 8) * 125000;
    219		return 0;
    220
    221	default:
    222		return -EINVAL;
    223	}
    224}
    225
    226static int lv0104cs_read_raw(struct iio_dev *indio_dev,
    227				struct iio_chan_spec const *chan,
    228				int *val, int *val2, long mask)
    229{
    230	struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
    231	int ret;
    232
    233	if (chan->type != IIO_LIGHT)
    234		return -EINVAL;
    235
    236	mutex_lock(&lv0104cs->lock);
    237
    238	switch (mask) {
    239	case IIO_CHAN_INFO_PROCESSED:
    240		ret = lv0104cs_get_lux(lv0104cs, val, val2);
    241		if (ret)
    242			goto err_mutex;
    243		ret = IIO_VAL_INT_PLUS_MICRO;
    244		break;
    245
    246	case IIO_CHAN_INFO_CALIBSCALE:
    247		*val = lv0104cs_calibscales[lv0104cs->calibscale].val;
    248		*val2 = lv0104cs_calibscales[lv0104cs->calibscale].val2;
    249		ret = IIO_VAL_INT_PLUS_MICRO;
    250		break;
    251
    252	case IIO_CHAN_INFO_SCALE:
    253		*val = lv0104cs_scales[lv0104cs->scale].val;
    254		*val2 = lv0104cs_scales[lv0104cs->scale].val2;
    255		ret = IIO_VAL_INT_PLUS_MICRO;
    256		break;
    257
    258	case IIO_CHAN_INFO_INT_TIME:
    259		*val = lv0104cs_int_times[lv0104cs->int_time].val;
    260		*val2 = lv0104cs_int_times[lv0104cs->int_time].val2;
    261		ret = IIO_VAL_INT_PLUS_MICRO;
    262		break;
    263
    264	default:
    265		ret = -EINVAL;
    266	}
    267
    268err_mutex:
    269	mutex_unlock(&lv0104cs->lock);
    270
    271	return ret;
    272}
    273
    274static int lv0104cs_set_calibscale(struct lv0104cs_private *lv0104cs,
    275				int val, int val2)
    276{
    277	int calibscale = val * 1000000 + val2;
    278	int floor, ceil, mid;
    279	int ret, i, index;
    280
    281	/* round to nearest quantized calibscale (sensitivity) */
    282	for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales) - 1; i++) {
    283		floor = lv0104cs_calibscales[i].val * 1000000
    284				+ lv0104cs_calibscales[i].val2;
    285		ceil = lv0104cs_calibscales[i + 1].val * 1000000
    286				+ lv0104cs_calibscales[i + 1].val2;
    287		mid = (floor + ceil) / 2;
    288
    289		/* round down */
    290		if (calibscale >= floor && calibscale < mid) {
    291			index = i;
    292			break;
    293		}
    294
    295		/* round up */
    296		if (calibscale >= mid && calibscale <= ceil) {
    297			index = i + 1;
    298			break;
    299		}
    300	}
    301
    302	if (i == ARRAY_SIZE(lv0104cs_calibscales) - 1)
    303		return -EINVAL;
    304
    305	mutex_lock(&lv0104cs->lock);
    306
    307	/* set calibscale (sensitivity) */
    308	ret = lv0104cs_write_reg(lv0104cs->client,
    309			lv0104cs_calibscales[index].regval);
    310	if (ret)
    311		goto err_mutex;
    312
    313	lv0104cs->calibscale = index;
    314
    315err_mutex:
    316	mutex_unlock(&lv0104cs->lock);
    317
    318	return ret;
    319}
    320
    321static int lv0104cs_set_scale(struct lv0104cs_private *lv0104cs,
    322				int val, int val2)
    323{
    324	int i;
    325
    326	/* hard matching */
    327	for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
    328		if (val != lv0104cs_scales[i].val)
    329			continue;
    330
    331		if (val2 == lv0104cs_scales[i].val2)
    332			break;
    333	}
    334
    335	if (i == ARRAY_SIZE(lv0104cs_scales))
    336		return -EINVAL;
    337
    338	mutex_lock(&lv0104cs->lock);
    339	lv0104cs->scale = i;
    340	mutex_unlock(&lv0104cs->lock);
    341
    342	return 0;
    343}
    344
    345static int lv0104cs_set_int_time(struct lv0104cs_private *lv0104cs,
    346				int val, int val2)
    347{
    348	int i;
    349
    350	/* hard matching */
    351	for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
    352		if (val != lv0104cs_int_times[i].val)
    353			continue;
    354
    355		if (val2 == lv0104cs_int_times[i].val2)
    356			break;
    357	}
    358
    359	if (i == ARRAY_SIZE(lv0104cs_int_times))
    360		return -EINVAL;
    361
    362	mutex_lock(&lv0104cs->lock);
    363	lv0104cs->int_time = i;
    364	mutex_unlock(&lv0104cs->lock);
    365
    366	return 0;
    367}
    368
    369static int lv0104cs_write_raw(struct iio_dev *indio_dev,
    370				struct iio_chan_spec const *chan,
    371				int val, int val2, long mask)
    372{
    373	struct lv0104cs_private *lv0104cs = iio_priv(indio_dev);
    374
    375	if (chan->type != IIO_LIGHT)
    376		return -EINVAL;
    377
    378	switch (mask) {
    379	case IIO_CHAN_INFO_CALIBSCALE:
    380		return lv0104cs_set_calibscale(lv0104cs, val, val2);
    381
    382	case IIO_CHAN_INFO_SCALE:
    383		return lv0104cs_set_scale(lv0104cs, val, val2);
    384
    385	case IIO_CHAN_INFO_INT_TIME:
    386		return lv0104cs_set_int_time(lv0104cs, val, val2);
    387
    388	default:
    389		return -EINVAL;
    390	}
    391}
    392
    393static ssize_t lv0104cs_show_calibscale_avail(struct device *dev,
    394				struct device_attribute *attr, char *buf)
    395{
    396	ssize_t len = 0;
    397	int i;
    398
    399	for (i = 0; i < ARRAY_SIZE(lv0104cs_calibscales); i++) {
    400		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
    401				lv0104cs_calibscales[i].val,
    402				lv0104cs_calibscales[i].val2);
    403	}
    404
    405	buf[len - 1] = '\n';
    406
    407	return len;
    408}
    409
    410static ssize_t lv0104cs_show_scale_avail(struct device *dev,
    411				struct device_attribute *attr, char *buf)
    412{
    413	ssize_t len = 0;
    414	int i;
    415
    416	for (i = 0; i < ARRAY_SIZE(lv0104cs_scales); i++) {
    417		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
    418				lv0104cs_scales[i].val,
    419				lv0104cs_scales[i].val2);
    420	}
    421
    422	buf[len - 1] = '\n';
    423
    424	return len;
    425}
    426
    427static ssize_t lv0104cs_show_int_time_avail(struct device *dev,
    428				struct device_attribute *attr, char *buf)
    429{
    430	ssize_t len = 0;
    431	int i;
    432
    433	for (i = 0; i < ARRAY_SIZE(lv0104cs_int_times); i++) {
    434		len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
    435				lv0104cs_int_times[i].val,
    436				lv0104cs_int_times[i].val2);
    437	}
    438
    439	buf[len - 1] = '\n';
    440
    441	return len;
    442}
    443
    444static IIO_DEVICE_ATTR(calibscale_available, 0444,
    445				lv0104cs_show_calibscale_avail, NULL, 0);
    446static IIO_DEVICE_ATTR(scale_available, 0444,
    447				lv0104cs_show_scale_avail, NULL, 0);
    448static IIO_DEV_ATTR_INT_TIME_AVAIL(lv0104cs_show_int_time_avail);
    449
    450static struct attribute *lv0104cs_attributes[] = {
    451	&iio_dev_attr_calibscale_available.dev_attr.attr,
    452	&iio_dev_attr_scale_available.dev_attr.attr,
    453	&iio_dev_attr_integration_time_available.dev_attr.attr,
    454	NULL
    455};
    456
    457static const struct attribute_group lv0104cs_attribute_group = {
    458	.attrs = lv0104cs_attributes,
    459};
    460
    461static const struct iio_info lv0104cs_info = {
    462	.attrs = &lv0104cs_attribute_group,
    463	.read_raw = &lv0104cs_read_raw,
    464	.write_raw = &lv0104cs_write_raw,
    465};
    466
    467static const struct iio_chan_spec lv0104cs_channels[] = {
    468	{
    469		.type = IIO_LIGHT,
    470		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
    471				      BIT(IIO_CHAN_INFO_CALIBSCALE) |
    472				      BIT(IIO_CHAN_INFO_SCALE) |
    473				      BIT(IIO_CHAN_INFO_INT_TIME),
    474	},
    475};
    476
    477static int lv0104cs_probe(struct i2c_client *client,
    478				const struct i2c_device_id *id)
    479{
    480	struct iio_dev *indio_dev;
    481	struct lv0104cs_private *lv0104cs;
    482	int ret;
    483
    484	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*lv0104cs));
    485	if (!indio_dev)
    486		return -ENOMEM;
    487
    488	lv0104cs = iio_priv(indio_dev);
    489
    490	i2c_set_clientdata(client, lv0104cs);
    491	lv0104cs->client = client;
    492
    493	mutex_init(&lv0104cs->lock);
    494
    495	lv0104cs->calibscale = LV0104CS_CALIBSCALE_UNITY;
    496	lv0104cs->scale = LV0104CS_SCALE_1X;
    497	lv0104cs->int_time = LV0104CS_INTEG_200MS;
    498
    499	ret = lv0104cs_write_reg(lv0104cs->client,
    500			lv0104cs_calibscales[LV0104CS_CALIBSCALE_UNITY].regval);
    501	if (ret)
    502		return ret;
    503
    504	indio_dev->modes = INDIO_DIRECT_MODE;
    505	indio_dev->channels = lv0104cs_channels;
    506	indio_dev->num_channels = ARRAY_SIZE(lv0104cs_channels);
    507	indio_dev->name = client->name;
    508	indio_dev->info = &lv0104cs_info;
    509
    510	return devm_iio_device_register(&client->dev, indio_dev);
    511}
    512
    513static const struct i2c_device_id lv0104cs_id[] = {
    514	{ "lv0104cs", 0 },
    515	{ }
    516};
    517MODULE_DEVICE_TABLE(i2c, lv0104cs_id);
    518
    519static struct i2c_driver lv0104cs_i2c_driver = {
    520	.driver = {
    521		.name	= "lv0104cs",
    522	},
    523	.id_table	= lv0104cs_id,
    524	.probe		= lv0104cs_probe,
    525};
    526module_i2c_driver(lv0104cs_i2c_driver);
    527
    528MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
    529MODULE_DESCRIPTION("LV0104CS Ambient Light Sensor Driver");
    530MODULE_LICENSE("GPL");