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 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 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 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 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 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 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 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 341*e1630207SUwe 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 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) 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 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 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*e1630207SUwe Kleine-König .probe_new = 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