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 ®_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 ®_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, ®_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, ®_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