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

max44009.c (13344B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * max44009.c - Support for MAX44009 Ambient Light Sensor
      4 *
      5 * Copyright (c) 2019 Robert Eshleman <bobbyeshleman@gmail.com>
      6 *
      7 * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX44009.pdf
      8 *
      9 * TODO: Support continuous mode and configuring from manual mode to
     10 *	 automatic mode.
     11 *
     12 * Default I2C address: 0x4a
     13 */
     14
     15#include <linux/init.h>
     16#include <linux/kernel.h>
     17#include <linux/bits.h>
     18#include <linux/i2c.h>
     19#include <linux/iio/events.h>
     20#include <linux/iio/iio.h>
     21#include <linux/iio/sysfs.h>
     22#include <linux/interrupt.h>
     23#include <linux/module.h>
     24#include <linux/util_macros.h>
     25
     26#define MAX44009_DRV_NAME "max44009"
     27
     28/* Registers in datasheet order */
     29#define MAX44009_REG_INT_STATUS 0x0
     30#define MAX44009_REG_INT_EN 0x1
     31#define MAX44009_REG_CFG 0x2
     32#define MAX44009_REG_LUX_HI 0x3
     33#define MAX44009_REG_LUX_LO 0x4
     34#define MAX44009_REG_UPPER_THR 0x5
     35#define MAX44009_REG_LOWER_THR 0x6
     36#define MAX44009_REG_THR_TIMER 0x7
     37
     38#define MAX44009_CFG_TIM_MASK GENMASK(2, 0)
     39#define MAX44009_CFG_MAN_MODE_MASK BIT(6)
     40
     41/* The maximum rising threshold for the max44009 */
     42#define MAX44009_MAXIMUM_THRESHOLD 7520256
     43
     44#define MAX44009_THRESH_EXP_MASK (0xf << 4)
     45#define MAX44009_THRESH_EXP_RSHIFT 4
     46#define MAX44009_THRESH_MANT_LSHIFT 4
     47#define MAX44009_THRESH_MANT_MASK 0xf
     48
     49#define MAX44009_UPPER_THR_MINIMUM 15
     50
     51/* The max44009 always scales raw readings by 0.045 and is non-configurable */
     52#define MAX44009_SCALE_NUMERATOR 45
     53#define MAX44009_SCALE_DENOMINATOR 1000
     54
     55/* The fixed-point fractional multiplier for de-scaling threshold values */
     56#define MAX44009_FRACT_MULT 1000000
     57
     58static const u32 max44009_int_time_ns_array[] = {
     59	800000000,
     60	400000000,
     61	200000000,
     62	100000000,
     63	50000000, /* Manual mode only */
     64	25000000, /* Manual mode only */
     65	12500000, /* Manual mode only */
     66	6250000,  /* Manual mode only */
     67};
     68
     69static const char max44009_int_time_str[] =
     70	"0.8 "
     71	"0.4 "
     72	"0.2 "
     73	"0.1 "
     74	"0.05 "
     75	"0.025 "
     76	"0.0125 "
     77	"0.00625";
     78
     79struct max44009_data {
     80	struct i2c_client *client;
     81	struct mutex lock;
     82};
     83
     84static const struct iio_event_spec max44009_event_spec[] = {
     85	{
     86		.type = IIO_EV_TYPE_THRESH,
     87		.dir = IIO_EV_DIR_RISING,
     88		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
     89				 BIT(IIO_EV_INFO_ENABLE),
     90	},
     91	{
     92		.type = IIO_EV_TYPE_THRESH,
     93		.dir = IIO_EV_DIR_FALLING,
     94		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
     95				 BIT(IIO_EV_INFO_ENABLE),
     96	},
     97};
     98
     99static const struct iio_chan_spec max44009_channels[] = {
    100	{
    101		.type = IIO_LIGHT,
    102		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
    103				      BIT(IIO_CHAN_INFO_INT_TIME),
    104		.event_spec = max44009_event_spec,
    105		.num_event_specs = ARRAY_SIZE(max44009_event_spec),
    106	},
    107};
    108
    109static int max44009_read_int_time(struct max44009_data *data)
    110{
    111
    112	int ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_CFG);
    113
    114	if (ret < 0)
    115		return ret;
    116
    117	return max44009_int_time_ns_array[ret & MAX44009_CFG_TIM_MASK];
    118}
    119
    120static int max44009_write_int_time(struct max44009_data *data,
    121				   int val, int val2)
    122{
    123	struct i2c_client *client = data->client;
    124	int ret, int_time, config;
    125	s64 ns;
    126
    127	ns = val * NSEC_PER_SEC + val2;
    128	int_time = find_closest_descending(
    129			ns,
    130			max44009_int_time_ns_array,
    131			ARRAY_SIZE(max44009_int_time_ns_array));
    132
    133	ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG);
    134	if (ret < 0)
    135		return ret;
    136
    137	config = ret;
    138	config &= int_time;
    139
    140	/*
    141	 * To set the integration time, the device must also be in manual
    142	 * mode.
    143	 */
    144	config |= MAX44009_CFG_MAN_MODE_MASK;
    145
    146	return i2c_smbus_write_byte_data(client, MAX44009_REG_CFG, config);
    147}
    148
    149static int max44009_write_raw(struct iio_dev *indio_dev,
    150			      struct iio_chan_spec const *chan, int val,
    151			      int val2, long mask)
    152{
    153	struct max44009_data *data = iio_priv(indio_dev);
    154	int ret;
    155
    156	if (mask == IIO_CHAN_INFO_INT_TIME && chan->type == IIO_LIGHT) {
    157		mutex_lock(&data->lock);
    158		ret = max44009_write_int_time(data, val, val2);
    159		mutex_unlock(&data->lock);
    160		return ret;
    161	}
    162	return -EINVAL;
    163}
    164
    165static int max44009_write_raw_get_fmt(struct iio_dev *indio_dev,
    166				      struct iio_chan_spec const *chan,
    167				      long mask)
    168{
    169	return IIO_VAL_INT_PLUS_NANO;
    170}
    171
    172static int max44009_lux_raw(u8 hi, u8 lo)
    173{
    174	int mantissa;
    175	int exponent;
    176
    177	/*
    178	 * The mantissa consists of the low nibble of the Lux High Byte
    179	 * and the low nibble of the Lux Low Byte.
    180	 */
    181	mantissa = ((hi & 0xf) << 4) | (lo & 0xf);
    182
    183	/* The exponent byte is just the upper nibble of the Lux High Byte */
    184	exponent = (hi >> 4) & 0xf;
    185
    186	/*
    187	 * The exponent value is base 2 to the power of the raw exponent byte.
    188	 */
    189	exponent = 1 << exponent;
    190
    191	return exponent * mantissa;
    192}
    193
    194#define MAX44009_READ_LUX_XFER_LEN (4)
    195
    196static int max44009_read_lux_raw(struct max44009_data *data)
    197{
    198	int ret;
    199	u8 hireg = MAX44009_REG_LUX_HI;
    200	u8 loreg = MAX44009_REG_LUX_LO;
    201	u8 lo = 0;
    202	u8 hi = 0;
    203
    204	struct i2c_msg msgs[] = {
    205		{
    206			.addr = data->client->addr,
    207			.flags = 0,
    208			.len = sizeof(hireg),
    209			.buf = &hireg,
    210		},
    211		{
    212			.addr = data->client->addr,
    213			.flags = I2C_M_RD,
    214			.len = sizeof(hi),
    215			.buf = &hi,
    216		},
    217		{
    218			.addr = data->client->addr,
    219			.flags = 0,
    220			.len = sizeof(loreg),
    221			.buf = &loreg,
    222		},
    223		{
    224			.addr = data->client->addr,
    225			.flags = I2C_M_RD,
    226			.len = sizeof(lo),
    227			.buf = &lo,
    228		}
    229	};
    230
    231	/*
    232	 * Use i2c_transfer instead of smbus read because i2c_transfer
    233	 * does NOT use a stop bit between address write and data read.
    234	 * Using a stop bit causes disjoint upper/lower byte reads and
    235	 * reduces accuracy.
    236	 */
    237	ret = i2c_transfer(data->client->adapter,
    238			   msgs, MAX44009_READ_LUX_XFER_LEN);
    239
    240	if (ret != MAX44009_READ_LUX_XFER_LEN)
    241		return -EIO;
    242
    243	return max44009_lux_raw(hi, lo);
    244}
    245
    246static int max44009_read_raw(struct iio_dev *indio_dev,
    247			     struct iio_chan_spec const *chan, int *val,
    248			     int *val2, long mask)
    249{
    250	struct max44009_data *data = iio_priv(indio_dev);
    251	int lux_raw;
    252	int ret;
    253
    254	switch (mask) {
    255	case IIO_CHAN_INFO_PROCESSED:
    256		switch (chan->type) {
    257		case IIO_LIGHT:
    258			ret = max44009_read_lux_raw(data);
    259			if (ret < 0)
    260				return ret;
    261			lux_raw = ret;
    262
    263			*val = lux_raw * MAX44009_SCALE_NUMERATOR;
    264			*val2 = MAX44009_SCALE_DENOMINATOR;
    265			return IIO_VAL_FRACTIONAL;
    266		default:
    267			return -EINVAL;
    268		}
    269	case IIO_CHAN_INFO_INT_TIME:
    270		switch (chan->type) {
    271		case IIO_LIGHT:
    272			ret = max44009_read_int_time(data);
    273			if (ret < 0)
    274				return ret;
    275
    276			*val2 = ret;
    277			*val = 0;
    278			return IIO_VAL_INT_PLUS_NANO;
    279		default:
    280			return -EINVAL;
    281		}
    282	default:
    283		return -EINVAL;
    284	}
    285}
    286
    287static IIO_CONST_ATTR(illuminance_integration_time_available,
    288		      max44009_int_time_str);
    289
    290static struct attribute *max44009_attributes[] = {
    291	&iio_const_attr_illuminance_integration_time_available.dev_attr.attr,
    292	NULL,
    293};
    294
    295static const struct attribute_group max44009_attribute_group = {
    296	.attrs = max44009_attributes,
    297};
    298
    299static int max44009_threshold_byte_from_fraction(int integral, int fractional)
    300{
    301	int mantissa, exp;
    302
    303	if ((integral <= 0 && fractional <= 0) ||
    304	     integral > MAX44009_MAXIMUM_THRESHOLD ||
    305	     (integral == MAX44009_MAXIMUM_THRESHOLD && fractional != 0))
    306		return -EINVAL;
    307
    308	/* Reverse scaling of fixed-point integral */
    309	mantissa = integral * MAX44009_SCALE_DENOMINATOR;
    310	mantissa /= MAX44009_SCALE_NUMERATOR;
    311
    312	/* Reverse scaling of fixed-point fractional */
    313	mantissa += fractional / MAX44009_FRACT_MULT *
    314		    (MAX44009_SCALE_DENOMINATOR / MAX44009_SCALE_NUMERATOR);
    315
    316	for (exp = 0; mantissa > 0xff; exp++)
    317		mantissa >>= 1;
    318
    319	mantissa >>= 4;
    320	mantissa &= 0xf;
    321	exp <<= 4;
    322
    323	return exp | mantissa;
    324}
    325
    326static int max44009_get_thr_reg(enum iio_event_direction dir)
    327{
    328	switch (dir) {
    329	case IIO_EV_DIR_RISING:
    330		return MAX44009_REG_UPPER_THR;
    331	case IIO_EV_DIR_FALLING:
    332		return MAX44009_REG_LOWER_THR;
    333	default:
    334		return -EINVAL;
    335	}
    336}
    337
    338static int max44009_write_event_value(struct iio_dev *indio_dev,
    339				      const struct iio_chan_spec *chan,
    340				      enum iio_event_type type,
    341				      enum iio_event_direction dir,
    342				      enum iio_event_info info,
    343				      int val, int val2)
    344{
    345	struct max44009_data *data = iio_priv(indio_dev);
    346	int reg, threshold;
    347
    348	if (info != IIO_EV_INFO_VALUE || chan->type != IIO_LIGHT)
    349		return -EINVAL;
    350
    351	threshold = max44009_threshold_byte_from_fraction(val, val2);
    352	if (threshold < 0)
    353		return threshold;
    354
    355	reg = max44009_get_thr_reg(dir);
    356	if (reg < 0)
    357		return reg;
    358
    359	return i2c_smbus_write_byte_data(data->client, reg, threshold);
    360}
    361
    362static int max44009_read_threshold(struct iio_dev *indio_dev,
    363				   enum iio_event_direction dir)
    364{
    365	struct max44009_data *data = iio_priv(indio_dev);
    366	int byte, reg;
    367	int mantissa, exponent;
    368
    369	reg = max44009_get_thr_reg(dir);
    370	if (reg < 0)
    371		return reg;
    372
    373	byte = i2c_smbus_read_byte_data(data->client, reg);
    374	if (byte < 0)
    375		return byte;
    376
    377	mantissa = byte & MAX44009_THRESH_MANT_MASK;
    378	mantissa <<= MAX44009_THRESH_MANT_LSHIFT;
    379
    380	/*
    381	 * To get the upper threshold, always adds the minimum upper threshold
    382	 * value to the shifted byte value (see datasheet).
    383	 */
    384	if (dir == IIO_EV_DIR_RISING)
    385		mantissa += MAX44009_UPPER_THR_MINIMUM;
    386
    387	/*
    388	 * Exponent is base 2 to the power of the threshold exponent byte
    389	 * value
    390	 */
    391	exponent = byte & MAX44009_THRESH_EXP_MASK;
    392	exponent >>= MAX44009_THRESH_EXP_RSHIFT;
    393
    394	return (1 << exponent) * mantissa;
    395}
    396
    397static int max44009_read_event_value(struct iio_dev *indio_dev,
    398				     const struct iio_chan_spec *chan,
    399				     enum iio_event_type type,
    400				     enum iio_event_direction dir,
    401				     enum iio_event_info info,
    402				     int *val, int *val2)
    403{
    404	int ret;
    405	int threshold;
    406
    407	if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
    408		return -EINVAL;
    409
    410	ret = max44009_read_threshold(indio_dev, dir);
    411	if (ret < 0)
    412		return ret;
    413	threshold = ret;
    414
    415	*val = threshold * MAX44009_SCALE_NUMERATOR;
    416	*val2 = MAX44009_SCALE_DENOMINATOR;
    417
    418	return IIO_VAL_FRACTIONAL;
    419}
    420
    421static int max44009_write_event_config(struct iio_dev *indio_dev,
    422				       const struct iio_chan_spec *chan,
    423				       enum iio_event_type type,
    424				       enum iio_event_direction dir,
    425				       int state)
    426{
    427	struct max44009_data *data = iio_priv(indio_dev);
    428	int ret;
    429
    430	if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
    431		return -EINVAL;
    432
    433	ret = i2c_smbus_write_byte_data(data->client,
    434					MAX44009_REG_INT_EN, state);
    435	if (ret < 0)
    436		return ret;
    437
    438	/*
    439	 * Set device to trigger interrupt immediately upon exceeding
    440	 * the threshold limit.
    441	 */
    442	return i2c_smbus_write_byte_data(data->client,
    443					 MAX44009_REG_THR_TIMER, 0);
    444}
    445
    446static int max44009_read_event_config(struct iio_dev *indio_dev,
    447				      const struct iio_chan_spec *chan,
    448				      enum iio_event_type type,
    449				      enum iio_event_direction dir)
    450{
    451	struct max44009_data *data = iio_priv(indio_dev);
    452
    453	if (chan->type != IIO_LIGHT || type != IIO_EV_TYPE_THRESH)
    454		return -EINVAL;
    455
    456	return i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_EN);
    457}
    458
    459static const struct iio_info max44009_info = {
    460	.read_raw = max44009_read_raw,
    461	.write_raw = max44009_write_raw,
    462	.write_raw_get_fmt = max44009_write_raw_get_fmt,
    463	.read_event_value = max44009_read_event_value,
    464	.read_event_config = max44009_read_event_config,
    465	.write_event_value = max44009_write_event_value,
    466	.write_event_config = max44009_write_event_config,
    467	.attrs = &max44009_attribute_group,
    468};
    469
    470static irqreturn_t max44009_threaded_irq_handler(int irq, void *p)
    471{
    472	struct iio_dev *indio_dev = p;
    473	struct max44009_data *data = iio_priv(indio_dev);
    474	int ret;
    475
    476	ret = i2c_smbus_read_byte_data(data->client, MAX44009_REG_INT_STATUS);
    477	if (ret) {
    478		iio_push_event(indio_dev,
    479			       IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
    480						    IIO_EV_TYPE_THRESH,
    481						    IIO_EV_DIR_EITHER),
    482			       iio_get_time_ns(indio_dev));
    483
    484		return IRQ_HANDLED;
    485	}
    486
    487	return IRQ_NONE;
    488}
    489
    490static int max44009_probe(struct i2c_client *client,
    491			  const struct i2c_device_id *id)
    492{
    493	struct max44009_data *data;
    494	struct iio_dev *indio_dev;
    495	int ret;
    496
    497	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    498	if (!indio_dev)
    499		return -ENOMEM;
    500
    501	data = iio_priv(indio_dev);
    502	i2c_set_clientdata(client, indio_dev);
    503	data->client = client;
    504	indio_dev->info = &max44009_info;
    505	indio_dev->modes = INDIO_DIRECT_MODE;
    506	indio_dev->name = MAX44009_DRV_NAME;
    507	indio_dev->channels = max44009_channels;
    508	indio_dev->num_channels = ARRAY_SIZE(max44009_channels);
    509	mutex_init(&data->lock);
    510
    511	/* Clear any stale interrupt bit */
    512	ret = i2c_smbus_read_byte_data(client, MAX44009_REG_CFG);
    513	if (ret < 0)
    514		return ret;
    515
    516	if (client->irq > 0) {
    517		ret = devm_request_threaded_irq(&client->dev, client->irq,
    518						NULL,
    519						max44009_threaded_irq_handler,
    520						IRQF_TRIGGER_FALLING |
    521						IRQF_ONESHOT | IRQF_SHARED,
    522						"max44009_event",
    523						indio_dev);
    524		if (ret < 0)
    525			return ret;
    526	}
    527
    528	return devm_iio_device_register(&client->dev, indio_dev);
    529}
    530
    531static const struct i2c_device_id max44009_id[] = {
    532	{ "max44009", 0 },
    533	{ }
    534};
    535MODULE_DEVICE_TABLE(i2c, max44009_id);
    536
    537static struct i2c_driver max44009_driver = {
    538	.driver = {
    539		.name = MAX44009_DRV_NAME,
    540	},
    541	.probe = max44009_probe,
    542	.id_table = max44009_id,
    543};
    544module_i2c_driver(max44009_driver);
    545
    546static const struct of_device_id max44009_of_match[] = {
    547	{ .compatible = "maxim,max44009" },
    548	{ }
    549};
    550MODULE_DEVICE_TABLE(of, max44009_of_match);
    551
    552MODULE_AUTHOR("Robert Eshleman <bobbyeshleman@gmail.com>");
    553MODULE_LICENSE("GPL v2");
    554MODULE_DESCRIPTION("MAX44009 ambient light sensor driver");