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

vcnl4035.c (17334B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * VCNL4035 Ambient Light and Proximity Sensor - 7-bit I2C slave address 0x60
      4 *
      5 * Copyright (c) 2018, DENX Software Engineering GmbH
      6 * Author: Parthiban Nallathambi <pn@denx.de>
      7 *
      8 * TODO: Proximity
      9 */
     10#include <linux/bitops.h>
     11#include <linux/i2c.h>
     12#include <linux/module.h>
     13#include <linux/pm_runtime.h>
     14#include <linux/regmap.h>
     15
     16#include <linux/iio/buffer.h>
     17#include <linux/iio/events.h>
     18#include <linux/iio/iio.h>
     19#include <linux/iio/sysfs.h>
     20#include <linux/iio/trigger.h>
     21#include <linux/iio/trigger_consumer.h>
     22#include <linux/iio/triggered_buffer.h>
     23
     24#define VCNL4035_DRV_NAME	"vcnl4035"
     25#define VCNL4035_IRQ_NAME	"vcnl4035_event"
     26#define VCNL4035_REGMAP_NAME	"vcnl4035_regmap"
     27
     28/* Device registers */
     29#define VCNL4035_ALS_CONF	0x00
     30#define VCNL4035_ALS_THDH	0x01
     31#define VCNL4035_ALS_THDL	0x02
     32#define VCNL4035_ALS_DATA	0x0B
     33#define VCNL4035_WHITE_DATA	0x0C
     34#define VCNL4035_INT_FLAG	0x0D
     35#define VCNL4035_DEV_ID		0x0E
     36
     37/* Register masks */
     38#define VCNL4035_MODE_ALS_MASK		BIT(0)
     39#define VCNL4035_MODE_ALS_WHITE_CHAN	BIT(8)
     40#define VCNL4035_MODE_ALS_INT_MASK	BIT(1)
     41#define VCNL4035_ALS_IT_MASK		GENMASK(7, 5)
     42#define VCNL4035_ALS_PERS_MASK		GENMASK(3, 2)
     43#define VCNL4035_INT_ALS_IF_H_MASK	BIT(12)
     44#define VCNL4035_INT_ALS_IF_L_MASK	BIT(13)
     45
     46/* Default values */
     47#define VCNL4035_MODE_ALS_ENABLE	BIT(0)
     48#define VCNL4035_MODE_ALS_DISABLE	0x00
     49#define VCNL4035_MODE_ALS_INT_ENABLE	BIT(1)
     50#define VCNL4035_MODE_ALS_INT_DISABLE	0
     51#define VCNL4035_DEV_ID_VAL		0x80
     52#define VCNL4035_ALS_IT_DEFAULT		0x01
     53#define VCNL4035_ALS_PERS_DEFAULT	0x00
     54#define VCNL4035_ALS_THDH_DEFAULT	5000
     55#define VCNL4035_ALS_THDL_DEFAULT	100
     56#define VCNL4035_SLEEP_DELAY_MS		2000
     57
     58struct vcnl4035_data {
     59	struct i2c_client *client;
     60	struct regmap *regmap;
     61	unsigned int als_it_val;
     62	unsigned int als_persistence;
     63	unsigned int als_thresh_low;
     64	unsigned int als_thresh_high;
     65	struct iio_trigger *drdy_trigger0;
     66};
     67
     68static inline bool vcnl4035_is_triggered(struct vcnl4035_data *data)
     69{
     70	int ret;
     71	int reg;
     72
     73	ret = regmap_read(data->regmap, VCNL4035_INT_FLAG, &reg);
     74	if (ret < 0)
     75		return false;
     76
     77	return !!(reg &
     78		(VCNL4035_INT_ALS_IF_H_MASK | VCNL4035_INT_ALS_IF_L_MASK));
     79}
     80
     81static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
     82{
     83	struct iio_dev *indio_dev = private;
     84	struct vcnl4035_data *data = iio_priv(indio_dev);
     85
     86	if (vcnl4035_is_triggered(data)) {
     87		iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
     88							0,
     89							IIO_EV_TYPE_THRESH,
     90							IIO_EV_DIR_EITHER),
     91				iio_get_time_ns(indio_dev));
     92		iio_trigger_poll_chained(data->drdy_trigger0);
     93		return IRQ_HANDLED;
     94	}
     95
     96	return IRQ_NONE;
     97}
     98
     99/* Triggered buffer */
    100static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
    101{
    102	struct iio_poll_func *pf = p;
    103	struct iio_dev *indio_dev = pf->indio_dev;
    104	struct vcnl4035_data *data = iio_priv(indio_dev);
    105	/* Ensure naturally aligned timestamp */
    106	u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)]  __aligned(8);
    107	int ret;
    108
    109	ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
    110	if (ret < 0) {
    111		dev_err(&data->client->dev,
    112			"Trigger consumer can't read from sensor.\n");
    113		goto fail_read;
    114	}
    115	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
    116					iio_get_time_ns(indio_dev));
    117
    118fail_read:
    119	iio_trigger_notify_done(indio_dev->trig);
    120
    121	return IRQ_HANDLED;
    122}
    123
    124static int vcnl4035_als_drdy_set_state(struct iio_trigger *trigger,
    125					bool enable_drdy)
    126{
    127	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
    128	struct vcnl4035_data *data = iio_priv(indio_dev);
    129	int val = enable_drdy ? VCNL4035_MODE_ALS_INT_ENABLE :
    130					VCNL4035_MODE_ALS_INT_DISABLE;
    131
    132	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    133				 VCNL4035_MODE_ALS_INT_MASK,
    134				 val);
    135}
    136
    137static const struct iio_trigger_ops vcnl4035_trigger_ops = {
    138	.validate_device = iio_trigger_validate_own_device,
    139	.set_trigger_state = vcnl4035_als_drdy_set_state,
    140};
    141
    142static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
    143{
    144	int ret;
    145	struct device *dev = &data->client->dev;
    146
    147	if (on) {
    148		ret = pm_runtime_resume_and_get(dev);
    149	} else {
    150		pm_runtime_mark_last_busy(dev);
    151		ret = pm_runtime_put_autosuspend(dev);
    152	}
    153
    154	return ret;
    155}
    156
    157/*
    158 *	Device IT	INT Time (ms)	Scale (lux/step)
    159 *	000		50		0.064
    160 *	001		100		0.032
    161 *	010		200		0.016
    162 *	100		400		0.008
    163 *	101 - 111	800		0.004
    164 * Values are proportional, so ALS INT is selected for input due to
    165 * simplicity reason. Integration time value and scaling is
    166 * calculated based on device INT value
    167 *
    168 * Raw value needs to be scaled using ALS steps
    169 */
    170static int vcnl4035_read_raw(struct iio_dev *indio_dev,
    171			    struct iio_chan_spec const *chan, int *val,
    172			    int *val2, long mask)
    173{
    174	struct vcnl4035_data *data = iio_priv(indio_dev);
    175	int ret;
    176	int raw_data;
    177	unsigned int reg;
    178
    179	switch (mask) {
    180	case IIO_CHAN_INFO_RAW:
    181		ret = vcnl4035_set_pm_runtime_state(data, true);
    182		if  (ret < 0)
    183			return ret;
    184
    185		ret = iio_device_claim_direct_mode(indio_dev);
    186		if (!ret) {
    187			if (chan->channel)
    188				reg = VCNL4035_ALS_DATA;
    189			else
    190				reg = VCNL4035_WHITE_DATA;
    191			ret = regmap_read(data->regmap, reg, &raw_data);
    192			iio_device_release_direct_mode(indio_dev);
    193			if (!ret) {
    194				*val = raw_data;
    195				ret = IIO_VAL_INT;
    196			}
    197		}
    198		vcnl4035_set_pm_runtime_state(data, false);
    199		return ret;
    200	case IIO_CHAN_INFO_INT_TIME:
    201		*val = 50;
    202		if (data->als_it_val)
    203			*val = data->als_it_val * 100;
    204		return IIO_VAL_INT;
    205	case IIO_CHAN_INFO_SCALE:
    206		*val = 64;
    207		if (!data->als_it_val)
    208			*val2 = 1000;
    209		else
    210			*val2 = data->als_it_val * 2 * 1000;
    211		return IIO_VAL_FRACTIONAL;
    212	default:
    213		return -EINVAL;
    214	}
    215}
    216
    217static int vcnl4035_write_raw(struct iio_dev *indio_dev,
    218				struct iio_chan_spec const *chan,
    219				int val, int val2, long mask)
    220{
    221	int ret;
    222	struct vcnl4035_data *data = iio_priv(indio_dev);
    223
    224	switch (mask) {
    225	case IIO_CHAN_INFO_INT_TIME:
    226		if (val <= 0 || val > 800)
    227			return -EINVAL;
    228
    229		ret = vcnl4035_set_pm_runtime_state(data, true);
    230		if  (ret < 0)
    231			return ret;
    232
    233		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    234					 VCNL4035_ALS_IT_MASK,
    235					 val / 100);
    236		if (!ret)
    237			data->als_it_val = val / 100;
    238
    239		vcnl4035_set_pm_runtime_state(data, false);
    240		return ret;
    241	default:
    242		return -EINVAL;
    243	}
    244}
    245
    246/* No direct ABI for persistence and threshold, so eventing */
    247static int vcnl4035_read_thresh(struct iio_dev *indio_dev,
    248		const struct iio_chan_spec *chan, enum iio_event_type type,
    249		enum iio_event_direction dir, enum iio_event_info info,
    250		int *val, int *val2)
    251{
    252	struct vcnl4035_data *data = iio_priv(indio_dev);
    253
    254	switch (info) {
    255	case IIO_EV_INFO_VALUE:
    256		switch (dir) {
    257		case IIO_EV_DIR_RISING:
    258			*val = data->als_thresh_high;
    259			return IIO_VAL_INT;
    260		case IIO_EV_DIR_FALLING:
    261			*val = data->als_thresh_low;
    262			return IIO_VAL_INT;
    263		default:
    264			return -EINVAL;
    265		}
    266		break;
    267	case IIO_EV_INFO_PERIOD:
    268		*val = data->als_persistence;
    269		return IIO_VAL_INT;
    270	default:
    271		return -EINVAL;
    272	}
    273
    274}
    275
    276static int vcnl4035_write_thresh(struct iio_dev *indio_dev,
    277		const struct iio_chan_spec *chan, enum iio_event_type type,
    278		enum iio_event_direction dir, enum iio_event_info info, int val,
    279		int val2)
    280{
    281	struct vcnl4035_data *data = iio_priv(indio_dev);
    282	int ret;
    283
    284	switch (info) {
    285	case IIO_EV_INFO_VALUE:
    286		/* 16 bit threshold range 0 - 65535 */
    287		if (val < 0 || val > 65535)
    288			return -EINVAL;
    289		if (dir == IIO_EV_DIR_RISING) {
    290			if (val < data->als_thresh_low)
    291				return -EINVAL;
    292			ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
    293					   val);
    294			if (ret)
    295				return ret;
    296			data->als_thresh_high = val;
    297		} else {
    298			if (val > data->als_thresh_high)
    299				return -EINVAL;
    300			ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
    301					   val);
    302			if (ret)
    303				return ret;
    304			data->als_thresh_low = val;
    305		}
    306		return ret;
    307	case IIO_EV_INFO_PERIOD:
    308		/* allow only 1 2 4 8 as persistence value */
    309		if (val < 0 || val > 8 || hweight8(val) != 1)
    310			return -EINVAL;
    311		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    312					 VCNL4035_ALS_PERS_MASK, val);
    313		if (!ret)
    314			data->als_persistence = val;
    315		return ret;
    316	default:
    317		return -EINVAL;
    318	}
    319}
    320
    321static IIO_CONST_ATTR_INT_TIME_AVAIL("50 100 200 400 800");
    322
    323static struct attribute *vcnl4035_attributes[] = {
    324	&iio_const_attr_integration_time_available.dev_attr.attr,
    325	NULL,
    326};
    327
    328static const struct attribute_group vcnl4035_attribute_group = {
    329	.attrs = vcnl4035_attributes,
    330};
    331
    332static const struct iio_info vcnl4035_info = {
    333	.read_raw		= vcnl4035_read_raw,
    334	.write_raw		= vcnl4035_write_raw,
    335	.read_event_value	= vcnl4035_read_thresh,
    336	.write_event_value	= vcnl4035_write_thresh,
    337	.attrs			= &vcnl4035_attribute_group,
    338};
    339
    340static const struct iio_event_spec vcnl4035_event_spec[] = {
    341	{
    342		.type = IIO_EV_TYPE_THRESH,
    343		.dir = IIO_EV_DIR_RISING,
    344		.mask_separate = BIT(IIO_EV_INFO_VALUE),
    345	}, {
    346		.type = IIO_EV_TYPE_THRESH,
    347		.dir = IIO_EV_DIR_FALLING,
    348		.mask_separate = BIT(IIO_EV_INFO_VALUE),
    349	}, {
    350		.type = IIO_EV_TYPE_THRESH,
    351		.dir = IIO_EV_DIR_EITHER,
    352		.mask_separate = BIT(IIO_EV_INFO_PERIOD),
    353	},
    354};
    355
    356enum vcnl4035_scan_index_order {
    357	VCNL4035_CHAN_INDEX_LIGHT,
    358	VCNL4035_CHAN_INDEX_WHITE_LED,
    359};
    360
    361static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
    362	.validate_scan_mask = &iio_validate_scan_mask_onehot,
    363};
    364
    365static const struct iio_chan_spec vcnl4035_channels[] = {
    366	{
    367		.type = IIO_LIGHT,
    368		.channel = 0,
    369		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
    370				BIT(IIO_CHAN_INFO_INT_TIME) |
    371				BIT(IIO_CHAN_INFO_SCALE),
    372		.event_spec = vcnl4035_event_spec,
    373		.num_event_specs = ARRAY_SIZE(vcnl4035_event_spec),
    374		.scan_index = VCNL4035_CHAN_INDEX_LIGHT,
    375		.scan_type = {
    376			.sign = 'u',
    377			.realbits = 16,
    378			.storagebits = 16,
    379			.endianness = IIO_LE,
    380		},
    381	},
    382	{
    383		.type = IIO_INTENSITY,
    384		.channel = 1,
    385		.modified = 1,
    386		.channel2 = IIO_MOD_LIGHT_BOTH,
    387		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
    388		.scan_index = VCNL4035_CHAN_INDEX_WHITE_LED,
    389		.scan_type = {
    390			.sign = 'u',
    391			.realbits = 16,
    392			.storagebits = 16,
    393			.endianness = IIO_LE,
    394		},
    395	},
    396};
    397
    398static int vcnl4035_set_als_power_state(struct vcnl4035_data *data, u8 status)
    399{
    400	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    401					VCNL4035_MODE_ALS_MASK,
    402					status);
    403}
    404
    405static int vcnl4035_init(struct vcnl4035_data *data)
    406{
    407	int ret;
    408	int id;
    409
    410	ret = regmap_read(data->regmap, VCNL4035_DEV_ID, &id);
    411	if (ret < 0) {
    412		dev_err(&data->client->dev, "Failed to read DEV_ID register\n");
    413		return ret;
    414	}
    415
    416	if (id != VCNL4035_DEV_ID_VAL) {
    417		dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
    418			id, VCNL4035_DEV_ID_VAL);
    419		return -ENODEV;
    420	}
    421
    422	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
    423	if (ret < 0)
    424		return ret;
    425
    426	/* ALS white channel enable */
    427	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    428				 VCNL4035_MODE_ALS_WHITE_CHAN,
    429				 1);
    430	if (ret) {
    431		dev_err(&data->client->dev, "set white channel enable %d\n",
    432			ret);
    433		return ret;
    434	}
    435
    436	/* set default integration time - 100 ms for ALS */
    437	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    438				 VCNL4035_ALS_IT_MASK,
    439				 VCNL4035_ALS_IT_DEFAULT);
    440	if (ret) {
    441		dev_err(&data->client->dev, "set default ALS IT returned %d\n",
    442			ret);
    443		return ret;
    444	}
    445	data->als_it_val = VCNL4035_ALS_IT_DEFAULT;
    446
    447	/* set default persistence time - 1 for ALS */
    448	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
    449				 VCNL4035_ALS_PERS_MASK,
    450				 VCNL4035_ALS_PERS_DEFAULT);
    451	if (ret) {
    452		dev_err(&data->client->dev, "set default PERS returned %d\n",
    453			ret);
    454		return ret;
    455	}
    456	data->als_persistence = VCNL4035_ALS_PERS_DEFAULT;
    457
    458	/* set default HIGH threshold for ALS */
    459	ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
    460				VCNL4035_ALS_THDH_DEFAULT);
    461	if (ret) {
    462		dev_err(&data->client->dev, "set default THDH returned %d\n",
    463			ret);
    464		return ret;
    465	}
    466	data->als_thresh_high = VCNL4035_ALS_THDH_DEFAULT;
    467
    468	/* set default LOW threshold for ALS */
    469	ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
    470				VCNL4035_ALS_THDL_DEFAULT);
    471	if (ret) {
    472		dev_err(&data->client->dev, "set default THDL returned %d\n",
    473			ret);
    474		return ret;
    475	}
    476	data->als_thresh_low = VCNL4035_ALS_THDL_DEFAULT;
    477
    478	return 0;
    479}
    480
    481static bool vcnl4035_is_volatile_reg(struct device *dev, unsigned int reg)
    482{
    483	switch (reg) {
    484	case VCNL4035_ALS_CONF:
    485	case VCNL4035_DEV_ID:
    486		return false;
    487	default:
    488		return true;
    489	}
    490}
    491
    492static const struct regmap_config vcnl4035_regmap_config = {
    493	.name		= VCNL4035_REGMAP_NAME,
    494	.reg_bits	= 8,
    495	.val_bits	= 16,
    496	.max_register	= VCNL4035_DEV_ID,
    497	.cache_type	= REGCACHE_RBTREE,
    498	.volatile_reg	= vcnl4035_is_volatile_reg,
    499	.val_format_endian = REGMAP_ENDIAN_LITTLE,
    500};
    501
    502static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
    503{
    504	int ret;
    505	struct vcnl4035_data *data = iio_priv(indio_dev);
    506
    507	data->drdy_trigger0 = devm_iio_trigger_alloc(
    508			indio_dev->dev.parent,
    509			"%s-dev%d", indio_dev->name, iio_device_id(indio_dev));
    510	if (!data->drdy_trigger0)
    511		return -ENOMEM;
    512
    513	data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
    514	iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
    515	ret = devm_iio_trigger_register(indio_dev->dev.parent,
    516					data->drdy_trigger0);
    517	if (ret) {
    518		dev_err(&data->client->dev, "iio trigger register failed\n");
    519		return ret;
    520	}
    521
    522	/* Trigger setup */
    523	ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
    524					NULL, vcnl4035_trigger_consumer_handler,
    525					&iio_triggered_buffer_setup_ops);
    526	if (ret < 0) {
    527		dev_err(&data->client->dev, "iio triggered buffer setup failed\n");
    528		return ret;
    529	}
    530
    531	/* IRQ to trigger mapping */
    532	ret = devm_request_threaded_irq(&data->client->dev, data->client->irq,
    533			NULL, vcnl4035_drdy_irq_thread,
    534			IRQF_TRIGGER_LOW | IRQF_ONESHOT,
    535			VCNL4035_IRQ_NAME, indio_dev);
    536	if (ret < 0)
    537		dev_err(&data->client->dev, "request irq %d for trigger0 failed\n",
    538				data->client->irq);
    539	return ret;
    540}
    541
    542static int vcnl4035_probe(struct i2c_client *client,
    543				const struct i2c_device_id *id)
    544{
    545	struct vcnl4035_data *data;
    546	struct iio_dev *indio_dev;
    547	struct regmap *regmap;
    548	int ret;
    549
    550	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
    551	if (!indio_dev)
    552		return -ENOMEM;
    553
    554	regmap = devm_regmap_init_i2c(client, &vcnl4035_regmap_config);
    555	if (IS_ERR(regmap)) {
    556		dev_err(&client->dev, "regmap_init failed!\n");
    557		return PTR_ERR(regmap);
    558	}
    559
    560	data = iio_priv(indio_dev);
    561	i2c_set_clientdata(client, indio_dev);
    562	data->client = client;
    563	data->regmap = regmap;
    564
    565	indio_dev->info = &vcnl4035_info;
    566	indio_dev->name = VCNL4035_DRV_NAME;
    567	indio_dev->channels = vcnl4035_channels;
    568	indio_dev->num_channels = ARRAY_SIZE(vcnl4035_channels);
    569	indio_dev->modes = INDIO_DIRECT_MODE;
    570
    571	ret = vcnl4035_init(data);
    572	if (ret < 0) {
    573		dev_err(&client->dev, "vcnl4035 chip init failed\n");
    574		return ret;
    575	}
    576
    577	if (client->irq > 0) {
    578		ret = vcnl4035_probe_trigger(indio_dev);
    579		if (ret < 0) {
    580			dev_err(&client->dev, "vcnl4035 unable init trigger\n");
    581			goto fail_poweroff;
    582		}
    583	}
    584
    585	ret = pm_runtime_set_active(&client->dev);
    586	if (ret < 0)
    587		goto fail_poweroff;
    588
    589	ret = iio_device_register(indio_dev);
    590	if (ret < 0)
    591		goto fail_poweroff;
    592
    593	pm_runtime_enable(&client->dev);
    594	pm_runtime_set_autosuspend_delay(&client->dev, VCNL4035_SLEEP_DELAY_MS);
    595	pm_runtime_use_autosuspend(&client->dev);
    596
    597	return 0;
    598
    599fail_poweroff:
    600	vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
    601	return ret;
    602}
    603
    604static int vcnl4035_remove(struct i2c_client *client)
    605{
    606	struct iio_dev *indio_dev = i2c_get_clientdata(client);
    607
    608	pm_runtime_dont_use_autosuspend(&client->dev);
    609	pm_runtime_disable(&client->dev);
    610	iio_device_unregister(indio_dev);
    611	pm_runtime_set_suspended(&client->dev);
    612
    613	return vcnl4035_set_als_power_state(iio_priv(indio_dev),
    614					VCNL4035_MODE_ALS_DISABLE);
    615}
    616
    617static int __maybe_unused vcnl4035_runtime_suspend(struct device *dev)
    618{
    619	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
    620	struct vcnl4035_data *data = iio_priv(indio_dev);
    621	int ret;
    622
    623	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
    624	regcache_mark_dirty(data->regmap);
    625
    626	return ret;
    627}
    628
    629static int __maybe_unused vcnl4035_runtime_resume(struct device *dev)
    630{
    631	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
    632	struct vcnl4035_data *data = iio_priv(indio_dev);
    633	int ret;
    634
    635	regcache_sync(data->regmap);
    636	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
    637	if (ret < 0)
    638		return ret;
    639
    640	/* wait for 1 ALS integration cycle */
    641	msleep(data->als_it_val * 100);
    642
    643	return 0;
    644}
    645
    646static const struct dev_pm_ops vcnl4035_pm_ops = {
    647	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
    648				pm_runtime_force_resume)
    649	SET_RUNTIME_PM_OPS(vcnl4035_runtime_suspend,
    650			   vcnl4035_runtime_resume, NULL)
    651};
    652
    653static const struct i2c_device_id vcnl4035_id[] = {
    654	{ "vcnl4035", 0 },
    655	{ }
    656};
    657MODULE_DEVICE_TABLE(i2c, vcnl4035_id);
    658
    659static const struct of_device_id vcnl4035_of_match[] = {
    660	{ .compatible = "vishay,vcnl4035", },
    661	{ }
    662};
    663MODULE_DEVICE_TABLE(of, vcnl4035_of_match);
    664
    665static struct i2c_driver vcnl4035_driver = {
    666	.driver = {
    667		.name   = VCNL4035_DRV_NAME,
    668		.pm	= &vcnl4035_pm_ops,
    669		.of_match_table = vcnl4035_of_match,
    670	},
    671	.probe  = vcnl4035_probe,
    672	.remove	= vcnl4035_remove,
    673	.id_table = vcnl4035_id,
    674};
    675
    676module_i2c_driver(vcnl4035_driver);
    677
    678MODULE_AUTHOR("Parthiban Nallathambi <pn@denx.de>");
    679MODULE_DESCRIPTION("VCNL4035 Ambient Light Sensor driver");
    680MODULE_LICENSE("GPL v2");