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 ®_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 ®_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, ®_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, ®_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[] = {
465*4391affaSUwe Kleine-König { "txcpa122" },
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,
4759f4e9ffeSJonathan Cameron .acpi_match_table = pa12203001_acpi_match,
4768ab6abfcSAdriana Reus },
4777cf15f42SUwe 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