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