18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2015 Intel Corporation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Driver for TXC PA12203001 Proximity and Ambient Light Sensor.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * To do: Interrupt support.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/acpi.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/i2c.h>
158c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
168c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h>
178c2ecf20Sopenharmony_ci#include <linux/mutex.h>
188c2ecf20Sopenharmony_ci#include <linux/pm.h>
198c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
208c2ecf20Sopenharmony_ci#include <linux/regmap.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define PA12203001_DRIVER_NAME	"pa12203001"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG0		0x00
258c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG1		0x01
268c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG2		0x02
278c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG3		0x03
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define PA12203001_REG_ADL		0x0b
308c2ecf20Sopenharmony_ci#define PA12203001_REG_PDH		0x0e
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define PA12203001_REG_POFS		0x10
338c2ecf20Sopenharmony_ci#define PA12203001_REG_PSET		0x11
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define PA12203001_ALS_EN_MASK		BIT(0)
368c2ecf20Sopenharmony_ci#define PA12203001_PX_EN_MASK		BIT(1)
378c2ecf20Sopenharmony_ci#define PA12203001_PX_NORMAL_MODE_MASK		GENMASK(7, 6)
388c2ecf20Sopenharmony_ci#define PA12203001_AFSR_MASK		GENMASK(5, 4)
398c2ecf20Sopenharmony_ci#define PA12203001_AFSR_SHIFT		4
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define PA12203001_PSCAN			0x03
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* als range 31000, ps, als disabled */
448c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG0_DEFAULT		0x30
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* led current: 100 mA */
478c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG1_DEFAULT		0x20
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* ps mode: normal, interrupts not active */
508c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG2_DEFAULT		0xcc
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define PA12203001_REG_CFG3_DEFAULT		0x00
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define PA12203001_SLEEP_DELAY_MS		3000
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define PA12203001_CHIP_ENABLE		0xff
578c2ecf20Sopenharmony_ci#define PA12203001_CHIP_DISABLE		0x00
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/* available scales: corresponding to [500, 4000, 7000, 31000]  lux */
608c2ecf20Sopenharmony_cistatic const int pa12203001_scales[] = { 7629, 61036, 106813, 473029};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistruct pa12203001_data {
638c2ecf20Sopenharmony_ci	struct i2c_client *client;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* protect device states */
668c2ecf20Sopenharmony_ci	struct mutex lock;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	bool als_enabled;
698c2ecf20Sopenharmony_ci	bool px_enabled;
708c2ecf20Sopenharmony_ci	bool als_needs_enable;
718c2ecf20Sopenharmony_ci	bool px_needs_enable;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	struct regmap *map;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic const struct {
778c2ecf20Sopenharmony_ci	u8 reg;
788c2ecf20Sopenharmony_ci	u8 val;
798c2ecf20Sopenharmony_ci} regvals[] = {
808c2ecf20Sopenharmony_ci	{PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT},
818c2ecf20Sopenharmony_ci	{PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT},
828c2ecf20Sopenharmony_ci	{PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT},
838c2ecf20Sopenharmony_ci	{PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT},
848c2ecf20Sopenharmony_ci	{PA12203001_REG_PSET, PA12203001_PSCAN},
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic IIO_CONST_ATTR(in_illuminance_scale_available,
888c2ecf20Sopenharmony_ci		      "0.007629 0.061036 0.106813 0.473029");
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic struct attribute *pa12203001_attrs[] = {
918c2ecf20Sopenharmony_ci	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
928c2ecf20Sopenharmony_ci	NULL
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic const struct attribute_group pa12203001_attr_group = {
968c2ecf20Sopenharmony_ci	.attrs = pa12203001_attrs,
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic const struct iio_chan_spec pa12203001_channels[] = {
1008c2ecf20Sopenharmony_ci	{
1018c2ecf20Sopenharmony_ci		.type = IIO_LIGHT,
1028c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
1038c2ecf20Sopenharmony_ci				      BIT(IIO_CHAN_INFO_SCALE),
1048c2ecf20Sopenharmony_ci	},
1058c2ecf20Sopenharmony_ci	{
1068c2ecf20Sopenharmony_ci		.type = IIO_PROXIMITY,
1078c2ecf20Sopenharmony_ci		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic const struct regmap_range pa12203001_volatile_regs_ranges[] = {
1128c2ecf20Sopenharmony_ci	regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1),
1138c2ecf20Sopenharmony_ci	regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH),
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic const struct regmap_access_table pa12203001_volatile_regs = {
1178c2ecf20Sopenharmony_ci	.yes_ranges = pa12203001_volatile_regs_ranges,
1188c2ecf20Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges),
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const struct regmap_config pa12203001_regmap_config = {
1228c2ecf20Sopenharmony_ci	.reg_bits = 8,
1238c2ecf20Sopenharmony_ci	.val_bits = 8,
1248c2ecf20Sopenharmony_ci	.max_register = PA12203001_REG_PSET,
1258c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
1268c2ecf20Sopenharmony_ci	.volatile_table = &pa12203001_volatile_regs,
1278c2ecf20Sopenharmony_ci};
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int ret;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
1348c2ecf20Sopenharmony_ci				 PA12203001_ALS_EN_MASK, enable);
1358c2ecf20Sopenharmony_ci	if (ret < 0)
1368c2ecf20Sopenharmony_ci		return ret;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	data->als_enabled = !!enable;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	int ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ret = regmap_update_bits(data->map, PA12203001_REG_CFG0,
1488c2ecf20Sopenharmony_ci				 PA12203001_PX_EN_MASK, enable);
1498c2ecf20Sopenharmony_ci	if (ret < 0)
1508c2ecf20Sopenharmony_ci		return ret;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	data->px_enabled = !!enable;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	return 0;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic int pa12203001_set_power_state(struct pa12203001_data *data, bool on,
1588c2ecf20Sopenharmony_ci				      u8 mask)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
1618c2ecf20Sopenharmony_ci	int ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (on && (mask & PA12203001_ALS_EN_MASK)) {
1648c2ecf20Sopenharmony_ci		mutex_lock(&data->lock);
1658c2ecf20Sopenharmony_ci		if (data->px_enabled) {
1668c2ecf20Sopenharmony_ci			ret = pa12203001_als_enable(data,
1678c2ecf20Sopenharmony_ci						    PA12203001_ALS_EN_MASK);
1688c2ecf20Sopenharmony_ci			if (ret < 0)
1698c2ecf20Sopenharmony_ci				goto err;
1708c2ecf20Sopenharmony_ci		} else {
1718c2ecf20Sopenharmony_ci			data->als_needs_enable = true;
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (on && (mask & PA12203001_PX_EN_MASK)) {
1778c2ecf20Sopenharmony_ci		mutex_lock(&data->lock);
1788c2ecf20Sopenharmony_ci		if (data->als_enabled) {
1798c2ecf20Sopenharmony_ci			ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
1808c2ecf20Sopenharmony_ci			if (ret < 0)
1818c2ecf20Sopenharmony_ci				goto err;
1828c2ecf20Sopenharmony_ci		} else {
1838c2ecf20Sopenharmony_ci			data->px_needs_enable = true;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci		mutex_unlock(&data->lock);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (on) {
1898c2ecf20Sopenharmony_ci		ret = pm_runtime_get_sync(&data->client->dev);
1908c2ecf20Sopenharmony_ci		if (ret < 0)
1918c2ecf20Sopenharmony_ci			pm_runtime_put_noidle(&data->client->dev);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	} else {
1948c2ecf20Sopenharmony_ci		pm_runtime_mark_last_busy(&data->client->dev);
1958c2ecf20Sopenharmony_ci		ret = pm_runtime_put_autosuspend(&data->client->dev);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return ret;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cierr:
2018c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
2028c2ecf20Sopenharmony_ci	return ret;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci#endif
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int pa12203001_read_raw(struct iio_dev *indio_dev,
2098c2ecf20Sopenharmony_ci			       struct iio_chan_spec const *chan, int *val,
2108c2ecf20Sopenharmony_ci			       int *val2, long mask)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct pa12203001_data *data = iio_priv(indio_dev);
2138c2ecf20Sopenharmony_ci	int ret;
2148c2ecf20Sopenharmony_ci	u8 dev_mask;
2158c2ecf20Sopenharmony_ci	unsigned int reg_byte;
2168c2ecf20Sopenharmony_ci	__le16 reg_word;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	switch (mask) {
2198c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
2208c2ecf20Sopenharmony_ci		switch (chan->type) {
2218c2ecf20Sopenharmony_ci		case IIO_LIGHT:
2228c2ecf20Sopenharmony_ci			dev_mask = PA12203001_ALS_EN_MASK;
2238c2ecf20Sopenharmony_ci			ret = pa12203001_set_power_state(data, true, dev_mask);
2248c2ecf20Sopenharmony_ci			if (ret < 0)
2258c2ecf20Sopenharmony_ci				return ret;
2268c2ecf20Sopenharmony_ci			/*
2278c2ecf20Sopenharmony_ci			 * ALS ADC value is stored in registers
2288c2ecf20Sopenharmony_ci			 * PA12203001_REG_ADL and in PA12203001_REG_ADL + 1.
2298c2ecf20Sopenharmony_ci			 */
2308c2ecf20Sopenharmony_ci			ret = regmap_bulk_read(data->map, PA12203001_REG_ADL,
2318c2ecf20Sopenharmony_ci					       &reg_word, 2);
2328c2ecf20Sopenharmony_ci			if (ret < 0)
2338c2ecf20Sopenharmony_ci				goto reg_err;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci			*val = le16_to_cpu(reg_word);
2368c2ecf20Sopenharmony_ci			ret = pa12203001_set_power_state(data, false, dev_mask);
2378c2ecf20Sopenharmony_ci			if (ret < 0)
2388c2ecf20Sopenharmony_ci				return ret;
2398c2ecf20Sopenharmony_ci			break;
2408c2ecf20Sopenharmony_ci		case IIO_PROXIMITY:
2418c2ecf20Sopenharmony_ci			dev_mask = PA12203001_PX_EN_MASK;
2428c2ecf20Sopenharmony_ci			ret = pa12203001_set_power_state(data, true, dev_mask);
2438c2ecf20Sopenharmony_ci			if (ret < 0)
2448c2ecf20Sopenharmony_ci				return ret;
2458c2ecf20Sopenharmony_ci			ret = regmap_read(data->map, PA12203001_REG_PDH,
2468c2ecf20Sopenharmony_ci					  &reg_byte);
2478c2ecf20Sopenharmony_ci			if (ret < 0)
2488c2ecf20Sopenharmony_ci				goto reg_err;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci			*val = reg_byte;
2518c2ecf20Sopenharmony_ci			ret = pa12203001_set_power_state(data, false, dev_mask);
2528c2ecf20Sopenharmony_ci			if (ret < 0)
2538c2ecf20Sopenharmony_ci				return ret;
2548c2ecf20Sopenharmony_ci			break;
2558c2ecf20Sopenharmony_ci		default:
2568c2ecf20Sopenharmony_ci			return -EINVAL;
2578c2ecf20Sopenharmony_ci		}
2588c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
2598c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
2608c2ecf20Sopenharmony_ci		ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
2618c2ecf20Sopenharmony_ci		if (ret < 0)
2628c2ecf20Sopenharmony_ci			return ret;
2638c2ecf20Sopenharmony_ci		*val = 0;
2648c2ecf20Sopenharmony_ci		reg_byte = (reg_byte & PA12203001_AFSR_MASK);
2658c2ecf20Sopenharmony_ci		*val2 = pa12203001_scales[reg_byte >> 4];
2668c2ecf20Sopenharmony_ci		return IIO_VAL_INT_PLUS_MICRO;
2678c2ecf20Sopenharmony_ci	default:
2688c2ecf20Sopenharmony_ci		return -EINVAL;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cireg_err:
2728c2ecf20Sopenharmony_ci	pa12203001_set_power_state(data, false, dev_mask);
2738c2ecf20Sopenharmony_ci	return ret;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int pa12203001_write_raw(struct iio_dev *indio_dev,
2778c2ecf20Sopenharmony_ci				struct iio_chan_spec const *chan, int val,
2788c2ecf20Sopenharmony_ci				int val2, long mask)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	struct pa12203001_data *data = iio_priv(indio_dev);
2818c2ecf20Sopenharmony_ci	int i, ret, new_val;
2828c2ecf20Sopenharmony_ci	unsigned int reg_byte;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	switch (mask) {
2858c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_SCALE:
2868c2ecf20Sopenharmony_ci		ret = regmap_read(data->map, PA12203001_REG_CFG0, &reg_byte);
2878c2ecf20Sopenharmony_ci		if (val != 0 || ret < 0)
2888c2ecf20Sopenharmony_ci			return -EINVAL;
2898c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) {
2908c2ecf20Sopenharmony_ci			if (val2 == pa12203001_scales[i]) {
2918c2ecf20Sopenharmony_ci				new_val = i << PA12203001_AFSR_SHIFT;
2928c2ecf20Sopenharmony_ci				return regmap_update_bits(data->map,
2938c2ecf20Sopenharmony_ci							  PA12203001_REG_CFG0,
2948c2ecf20Sopenharmony_ci							  PA12203001_AFSR_MASK,
2958c2ecf20Sopenharmony_ci							  new_val);
2968c2ecf20Sopenharmony_ci			}
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	default:
3008c2ecf20Sopenharmony_ci		break;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return -EINVAL;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic const struct iio_info pa12203001_info = {
3078c2ecf20Sopenharmony_ci	.read_raw = pa12203001_read_raw,
3088c2ecf20Sopenharmony_ci	.write_raw = pa12203001_write_raw,
3098c2ecf20Sopenharmony_ci	.attrs = &pa12203001_attr_group,
3108c2ecf20Sopenharmony_ci};
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int pa12203001_init(struct iio_dev *indio_dev)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct pa12203001_data *data = iio_priv(indio_dev);
3158c2ecf20Sopenharmony_ci	int i, ret;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regvals); i++) {
3188c2ecf20Sopenharmony_ci		ret = regmap_write(data->map, regvals[i].reg, regvals[i].val);
3198c2ecf20Sopenharmony_ci		if (ret < 0)
3208c2ecf20Sopenharmony_ci			return ret;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return 0;
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct pa12203001_data *data = iio_priv(indio_dev);
3298c2ecf20Sopenharmony_ci	int ret;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
3328c2ecf20Sopenharmony_ci	ret = pa12203001_als_enable(data, state);
3338c2ecf20Sopenharmony_ci	if (ret < 0)
3348c2ecf20Sopenharmony_ci		goto out;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	ret = pa12203001_px_enable(data, state);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ciout:
3398c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
3408c2ecf20Sopenharmony_ci	return ret;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int pa12203001_probe(struct i2c_client *client,
3448c2ecf20Sopenharmony_ci			    const struct i2c_device_id *id)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct pa12203001_data *data;
3478c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
3488c2ecf20Sopenharmony_ci	int ret;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	indio_dev = devm_iio_device_alloc(&client->dev,
3518c2ecf20Sopenharmony_ci					  sizeof(struct pa12203001_data));
3528c2ecf20Sopenharmony_ci	if (!indio_dev)
3538c2ecf20Sopenharmony_ci		return -ENOMEM;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	data = iio_priv(indio_dev);
3568c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, indio_dev);
3578c2ecf20Sopenharmony_ci	data->client = client;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config);
3608c2ecf20Sopenharmony_ci	if (IS_ERR(data->map))
3618c2ecf20Sopenharmony_ci		return PTR_ERR(data->map);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	mutex_init(&data->lock);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	indio_dev->info = &pa12203001_info;
3668c2ecf20Sopenharmony_ci	indio_dev->name = PA12203001_DRIVER_NAME;
3678c2ecf20Sopenharmony_ci	indio_dev->channels = pa12203001_channels;
3688c2ecf20Sopenharmony_ci	indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels);
3698c2ecf20Sopenharmony_ci	indio_dev->modes = INDIO_DIRECT_MODE;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	ret = pa12203001_init(indio_dev);
3728c2ecf20Sopenharmony_ci	if (ret < 0)
3738c2ecf20Sopenharmony_ci		return ret;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
3768c2ecf20Sopenharmony_ci	if (ret < 0)
3778c2ecf20Sopenharmony_ci		return ret;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	ret = pm_runtime_set_active(&client->dev);
3808c2ecf20Sopenharmony_ci	if (ret < 0)
3818c2ecf20Sopenharmony_ci		goto out_err;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	pm_runtime_enable(&client->dev);
3848c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&client->dev,
3858c2ecf20Sopenharmony_ci					 PA12203001_SLEEP_DELAY_MS);
3868c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&client->dev);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	ret = iio_device_register(indio_dev);
3898c2ecf20Sopenharmony_ci	if (ret < 0)
3908c2ecf20Sopenharmony_ci		goto out_err;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciout_err:
3958c2ecf20Sopenharmony_ci	pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
3968c2ecf20Sopenharmony_ci	return ret;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int pa12203001_remove(struct i2c_client *client)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(client);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	iio_device_unregister(indio_dev);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
4068c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM)
4128c2ecf20Sopenharmony_cistatic int pa12203001_suspend(struct device *dev)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci#endif
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
4218c2ecf20Sopenharmony_cistatic int pa12203001_resume(struct device *dev)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE);
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci#endif
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
4308c2ecf20Sopenharmony_cistatic int pa12203001_runtime_resume(struct device *dev)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	struct pa12203001_data *data;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	mutex_lock(&data->lock);
4378c2ecf20Sopenharmony_ci	if (data->als_needs_enable) {
4388c2ecf20Sopenharmony_ci		pa12203001_als_enable(data, PA12203001_ALS_EN_MASK);
4398c2ecf20Sopenharmony_ci		data->als_needs_enable = false;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci	if (data->px_needs_enable) {
4428c2ecf20Sopenharmony_ci		pa12203001_px_enable(data, PA12203001_PX_EN_MASK);
4438c2ecf20Sopenharmony_ci		data->px_needs_enable = false;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	mutex_unlock(&data->lock);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return 0;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci#endif
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic const struct dev_pm_ops pa12203001_pm_ops = {
4528c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume)
4538c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL)
4548c2ecf20Sopenharmony_ci};
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic const struct acpi_device_id pa12203001_acpi_match[] = {
4578c2ecf20Sopenharmony_ci	{ "TXCPA122", 0},
4588c2ecf20Sopenharmony_ci	{}
4598c2ecf20Sopenharmony_ci};
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic const struct i2c_device_id pa12203001_id[] = {
4648c2ecf20Sopenharmony_ci		{"txcpa122", 0},
4658c2ecf20Sopenharmony_ci		{}
4668c2ecf20Sopenharmony_ci};
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pa12203001_id);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic struct i2c_driver pa12203001_driver = {
4718c2ecf20Sopenharmony_ci	.driver = {
4728c2ecf20Sopenharmony_ci		.name = PA12203001_DRIVER_NAME,
4738c2ecf20Sopenharmony_ci		.pm = &pa12203001_pm_ops,
4748c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
4758c2ecf20Sopenharmony_ci	},
4768c2ecf20Sopenharmony_ci	.probe = pa12203001_probe,
4778c2ecf20Sopenharmony_ci	.remove = pa12203001_remove,
4788c2ecf20Sopenharmony_ci	.id_table = pa12203001_id,
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci};
4818c2ecf20Sopenharmony_cimodule_i2c_driver(pa12203001_driver);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>");
4848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor");
4858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
486