brintos

brintos / linux-shallow public Read only

0
0
Text · 28.9 KiB · 3c14e4c Raw
1196 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * apds9960.c - Support for Avago APDS9960 gesture/RGB/ALS/proximity sensor4 *5 * Copyright (C) 2015, 20186 * Author: Matt Ranostay <matt.ranostay@konsulko.com>7 *8 * TODO: gesture + proximity calib offsets9 */10 11#include <linux/acpi.h>12#include <linux/module.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/delay.h>16#include <linux/mutex.h>17#include <linux/err.h>18#include <linux/irq.h>19#include <linux/i2c.h>20#include <linux/pm_runtime.h>21#include <linux/regmap.h>22#include <linux/iio/iio.h>23#include <linux/iio/buffer.h>24#include <linux/iio/events.h>25#include <linux/iio/kfifo_buf.h>26#include <linux/iio/sysfs.h>27 28#define APDS9960_REGMAP_NAME	"apds9960_regmap"29#define APDS9960_DRV_NAME	"apds9960"30 31#define APDS9960_REG_RAM_START	0x0032#define APDS9960_REG_RAM_END	0x7f33 34#define APDS9960_REG_ENABLE	0x8035#define APDS9960_REG_ATIME	0x8136#define APDS9960_REG_WTIME	0x8337 38#define APDS9960_REG_AILTL	0x8439#define APDS9960_REG_AILTH	0x8540#define APDS9960_REG_AIHTL	0x8641#define APDS9960_REG_AIHTH	0x8742 43#define APDS9960_REG_PILT	0x8944#define APDS9960_REG_PIHT	0x8b45#define APDS9960_REG_PERS	0x8c46 47#define APDS9960_REG_CONFIG_1	0x8d48#define APDS9960_REG_PPULSE	0x8e49 50#define APDS9960_REG_CONTROL	0x8f51#define APDS9960_REG_CONTROL_AGAIN_MASK		0x0352#define APDS9960_REG_CONTROL_PGAIN_MASK		0x0c53#define APDS9960_REG_CONTROL_AGAIN_MASK_SHIFT	054#define APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT	255 56#define APDS9960_REG_CONFIG_2	0x9057#define APDS9960_REG_ID		0x9258 59#define APDS9960_REG_STATUS	0x9360#define APDS9960_REG_STATUS_PS_INT	BIT(5)61#define APDS9960_REG_STATUS_ALS_INT	BIT(4)62#define APDS9960_REG_STATUS_GINT	BIT(2)63 64#define APDS9960_REG_PDATA	0x9c65#define APDS9960_REG_POFFSET_UR	0x9d66#define APDS9960_REG_POFFSET_DL 0x9e67#define APDS9960_REG_CONFIG_3	0x9f68 69#define APDS9960_REG_GPENTH	0xa070#define APDS9960_REG_GEXTH	0xa171 72#define APDS9960_REG_GCONF_1	0xa273#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK		0xc074#define APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT	675 76#define APDS9960_REG_GCONF_2	0xa377#define APDS9960_REG_GCONF_2_GGAIN_MASK			0x6078#define APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT		579 80#define APDS9960_REG_GOFFSET_U	0xa481#define APDS9960_REG_GOFFSET_D	0xa582#define APDS9960_REG_GPULSE	0xa683#define APDS9960_REG_GOFFSET_L	0xa784#define APDS9960_REG_GOFFSET_R	0xa985#define APDS9960_REG_GCONF_3	0xaa86 87#define APDS9960_REG_GCONF_4	0xab88#define APDS9960_REG_GFLVL	0xae89#define APDS9960_REG_GSTATUS	0xaf90 91#define APDS9960_REG_IFORCE	0xe492#define APDS9960_REG_PICLEAR	0xe593#define APDS9960_REG_CICLEAR	0xe694#define APDS9960_REG_AICLEAR	0xe795 96#define APDS9960_DEFAULT_PERS	0x3397#define APDS9960_DEFAULT_GPENTH	0x5098#define APDS9960_DEFAULT_GEXTH	0x4099 100#define APDS9960_MAX_PXS_THRES_VAL	255101#define APDS9960_MAX_ALS_THRES_VAL	0xffff102#define APDS9960_MAX_INT_TIME_IN_US	1000000103 104enum apds9960_als_channel_idx {105	IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE,106};107 108#define APDS9960_REG_ALS_BASE	0x94109#define APDS9960_REG_ALS_CHANNEL(_colour) \110	(APDS9960_REG_ALS_BASE + (IDX_ALS_##_colour * 2))111 112enum apds9960_gesture_channel_idx {113	IDX_DIR_UP, IDX_DIR_DOWN, IDX_DIR_LEFT, IDX_DIR_RIGHT,114};115 116#define APDS9960_REG_GFIFO_BASE	0xfc117#define APDS9960_REG_GFIFO_DIR(_dir) \118	(APDS9960_REG_GFIFO_BASE + IDX_DIR_##_dir)119 120struct apds9960_data {121	struct i2c_client *client;122	struct iio_dev *indio_dev;123	struct mutex lock;124 125	/* regmap fields */126	struct regmap *regmap;127	struct regmap_field *reg_int_als;128	struct regmap_field *reg_int_ges;129	struct regmap_field *reg_int_pxs;130 131	struct regmap_field *reg_enable_als;132	struct regmap_field *reg_enable_ges;133	struct regmap_field *reg_enable_pxs;134 135	/* state */136	int als_int;137	int pxs_int;138	int gesture_mode_running;139 140	/* gain values */141	int als_gain;142	int pxs_gain;143 144	/* integration time value in us */145	int als_adc_int_us;146 147	/* gesture buffer */148	u8 buffer[4]; /* 4 8-bit channels */149 150	/* calibration value buffer */151	int calibbias[5];152};153 154enum {155	APDS9960_CHAN_PROXIMITY,156	APDS9960_CHAN_GESTURE_UP,157	APDS9960_CHAN_GESTURE_DOWN,158	APDS9960_CHAN_GESTURE_LEFT,159	APDS9960_CHAN_GESTURE_RIGHT,160};161 162static const unsigned int apds9960_offset_regs[][2] = {163	[APDS9960_CHAN_PROXIMITY] = {APDS9960_REG_POFFSET_UR, APDS9960_REG_POFFSET_DL},164	[APDS9960_CHAN_GESTURE_UP] = {APDS9960_REG_GOFFSET_U, 0},165	[APDS9960_CHAN_GESTURE_DOWN] = {APDS9960_REG_GOFFSET_D, 0},166	[APDS9960_CHAN_GESTURE_LEFT] = {APDS9960_REG_GOFFSET_L, 0},167	[APDS9960_CHAN_GESTURE_RIGHT] = {APDS9960_REG_GOFFSET_R, 0},168};169 170static const struct reg_default apds9960_reg_defaults[] = {171	/* Default ALS integration time = 2.48ms */172	{ APDS9960_REG_ATIME, 0xff },173};174 175static const struct regmap_range apds9960_volatile_ranges[] = {176	regmap_reg_range(APDS9960_REG_STATUS,177				APDS9960_REG_PDATA),178	regmap_reg_range(APDS9960_REG_GFLVL,179				APDS9960_REG_GSTATUS),180	regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),181				APDS9960_REG_GFIFO_DIR(RIGHT)),182	regmap_reg_range(APDS9960_REG_IFORCE,183				APDS9960_REG_AICLEAR),184};185 186static const struct regmap_access_table apds9960_volatile_table = {187	.yes_ranges	= apds9960_volatile_ranges,188	.n_yes_ranges	= ARRAY_SIZE(apds9960_volatile_ranges),189};190 191static const struct regmap_range apds9960_precious_ranges[] = {192	regmap_reg_range(APDS9960_REG_RAM_START, APDS9960_REG_RAM_END),193};194 195static const struct regmap_access_table apds9960_precious_table = {196	.yes_ranges	= apds9960_precious_ranges,197	.n_yes_ranges	= ARRAY_SIZE(apds9960_precious_ranges),198};199 200static const struct regmap_range apds9960_readable_ranges[] = {201	regmap_reg_range(APDS9960_REG_ENABLE,202				APDS9960_REG_GSTATUS),203	regmap_reg_range(APDS9960_REG_GFIFO_DIR(UP),204				APDS9960_REG_GFIFO_DIR(RIGHT)),205};206 207static const struct regmap_access_table apds9960_readable_table = {208	.yes_ranges	= apds9960_readable_ranges,209	.n_yes_ranges	= ARRAY_SIZE(apds9960_readable_ranges),210};211 212static const struct regmap_range apds9960_writeable_ranges[] = {213	regmap_reg_range(APDS9960_REG_ENABLE, APDS9960_REG_CONFIG_2),214	regmap_reg_range(APDS9960_REG_POFFSET_UR, APDS9960_REG_GCONF_4),215	regmap_reg_range(APDS9960_REG_IFORCE, APDS9960_REG_AICLEAR),216};217 218static const struct regmap_access_table apds9960_writeable_table = {219	.yes_ranges	= apds9960_writeable_ranges,220	.n_yes_ranges	= ARRAY_SIZE(apds9960_writeable_ranges),221};222 223static const struct regmap_config apds9960_regmap_config = {224	.name = APDS9960_REGMAP_NAME,225	.reg_bits = 8,226	.val_bits = 8,227	.use_single_read = true,228	.use_single_write = true,229 230	.volatile_table = &apds9960_volatile_table,231	.precious_table = &apds9960_precious_table,232	.rd_table = &apds9960_readable_table,233	.wr_table = &apds9960_writeable_table,234 235	.reg_defaults = apds9960_reg_defaults,236	.num_reg_defaults = ARRAY_SIZE(apds9960_reg_defaults),237	.max_register = APDS9960_REG_GFIFO_DIR(RIGHT),238	.cache_type = REGCACHE_RBTREE,239};240 241static const struct iio_event_spec apds9960_pxs_event_spec[] = {242	{243		.type = IIO_EV_TYPE_THRESH,244		.dir = IIO_EV_DIR_RISING,245		.mask_separate = BIT(IIO_EV_INFO_VALUE),246	},247	{248		.type = IIO_EV_TYPE_THRESH,249		.dir = IIO_EV_DIR_FALLING,250		.mask_separate = BIT(IIO_EV_INFO_VALUE),251	},252	{253		.type = IIO_EV_TYPE_THRESH,254		.mask_separate = BIT(IIO_EV_INFO_ENABLE),255	},256};257 258static const struct iio_event_spec apds9960_als_event_spec[] = {259	{260		.type = IIO_EV_TYPE_THRESH,261		.dir = IIO_EV_DIR_RISING,262		.mask_separate = BIT(IIO_EV_INFO_VALUE),263	},264	{265		.type = IIO_EV_TYPE_THRESH,266		.dir = IIO_EV_DIR_FALLING,267		.mask_separate = BIT(IIO_EV_INFO_VALUE),268	},269	{270		.type = IIO_EV_TYPE_THRESH,271		.mask_separate = BIT(IIO_EV_INFO_ENABLE),272	},273};274 275#define APDS9960_GESTURE_CHANNEL(_dir, _si) { \276	.type = IIO_PROXIMITY, \277	.info_mask_separate = BIT(IIO_CHAN_INFO_CALIBBIAS), \278	.channel = _si + 1, \279	.scan_index = _si, \280	.indexed = 1, \281	.scan_type = { \282		.sign = 'u', \283		.realbits = 8, \284		.storagebits = 8, \285	}, \286}287 288#define APDS9960_INTENSITY_CHANNEL(_colour) { \289	.type = IIO_INTENSITY, \290	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \291	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \292			BIT(IIO_CHAN_INFO_INT_TIME), \293	.channel2 = IIO_MOD_LIGHT_##_colour, \294	.address = APDS9960_REG_ALS_CHANNEL(_colour), \295	.modified = 1, \296	.scan_index = -1, \297}298 299static const unsigned long apds9960_scan_masks[] = {0xf, 0};300 301static const struct iio_chan_spec apds9960_channels[] = {302	{303		.type = IIO_PROXIMITY,304		.address = APDS9960_REG_PDATA,305		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |306			BIT(IIO_CHAN_INFO_CALIBBIAS),307		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),308		.channel = 0,309		.indexed = 0,310		.scan_index = -1,311 312		.event_spec = apds9960_pxs_event_spec,313		.num_event_specs = ARRAY_SIZE(apds9960_pxs_event_spec),314	},315	/* Gesture Sensor */316	APDS9960_GESTURE_CHANNEL(UP, 0),317	APDS9960_GESTURE_CHANNEL(DOWN, 1),318	APDS9960_GESTURE_CHANNEL(LEFT, 2),319	APDS9960_GESTURE_CHANNEL(RIGHT, 3),320	/* ALS */321	{322		.type = IIO_INTENSITY,323		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),324		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |325			BIT(IIO_CHAN_INFO_INT_TIME),326		.channel2 = IIO_MOD_LIGHT_CLEAR,327		.address = APDS9960_REG_ALS_CHANNEL(CLEAR),328		.modified = 1,329		.scan_index = -1,330 331		.event_spec = apds9960_als_event_spec,332		.num_event_specs = ARRAY_SIZE(apds9960_als_event_spec),333	},334	/* RGB Sensor */335	APDS9960_INTENSITY_CHANNEL(RED),336	APDS9960_INTENSITY_CHANNEL(GREEN),337	APDS9960_INTENSITY_CHANNEL(BLUE),338};339 340static int apds9960_set_calibbias(struct apds9960_data *data,341		struct iio_chan_spec const *chan, int calibbias)342{343	int ret, i;344 345	if (calibbias < S8_MIN || calibbias > S8_MAX)346		return -EINVAL;347 348	guard(mutex)(&data->lock);349	for (i = 0; i < 2; i++) {350		if (apds9960_offset_regs[chan->channel][i] == 0)351			break;352 353		ret = regmap_write(data->regmap, apds9960_offset_regs[chan->channel][i], calibbias);354		if (ret < 0)355			return ret;356	}357	data->calibbias[chan->channel] = calibbias;358 359	return 0;360}361 362/* integration time in us */363static const int apds9960_int_time[][2] = {364	{ 28000, 246},365	{100000, 219},366	{200000, 182},367	{700000,   0}368};369 370/* gain mapping */371static const int apds9960_pxs_gain_map[] = {1, 2, 4, 8};372static const int apds9960_als_gain_map[] = {1, 4, 16, 64};373 374static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8");375static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64");376static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7");377 378static struct attribute *apds9960_attributes[] = {379	&iio_const_attr_proximity_scale_available.dev_attr.attr,380	&iio_const_attr_intensity_scale_available.dev_attr.attr,381	&iio_const_attr_integration_time_available.dev_attr.attr,382	NULL,383};384 385static const struct attribute_group apds9960_attribute_group = {386	.attrs = apds9960_attributes,387};388 389static const struct reg_field apds9960_reg_field_int_als =390				REG_FIELD(APDS9960_REG_ENABLE, 4, 4);391 392static const struct reg_field apds9960_reg_field_int_ges =393				REG_FIELD(APDS9960_REG_GCONF_4, 1, 1);394 395static const struct reg_field apds9960_reg_field_int_pxs =396				REG_FIELD(APDS9960_REG_ENABLE, 5, 5);397 398static const struct reg_field apds9960_reg_field_enable_als =399				REG_FIELD(APDS9960_REG_ENABLE, 1, 1);400 401static const struct reg_field apds9960_reg_field_enable_ges =402				REG_FIELD(APDS9960_REG_ENABLE, 6, 6);403 404static const struct reg_field apds9960_reg_field_enable_pxs =405				REG_FIELD(APDS9960_REG_ENABLE, 2, 2);406 407static int apds9960_set_it_time(struct apds9960_data *data, int val2)408{409	int ret = -EINVAL;410	int idx;411 412	for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) {413		if (apds9960_int_time[idx][0] == val2) {414			mutex_lock(&data->lock);415			ret = regmap_write(data->regmap, APDS9960_REG_ATIME,416						 apds9960_int_time[idx][1]);417			if (!ret)418				data->als_adc_int_us = val2;419			mutex_unlock(&data->lock);420			break;421		}422	}423 424	return ret;425}426 427static int apds9960_set_pxs_gain(struct apds9960_data *data, int val)428{429	int ret = -EINVAL;430	int idx;431 432	for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) {433		if (apds9960_pxs_gain_map[idx] == val) {434			/* pxs + gesture gains are mirrored */435			mutex_lock(&data->lock);436			ret = regmap_update_bits(data->regmap,437				APDS9960_REG_CONTROL,438				APDS9960_REG_CONTROL_PGAIN_MASK,439				idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT);440			if (ret) {441				mutex_unlock(&data->lock);442				break;443			}444 445			ret = regmap_update_bits(data->regmap,446				APDS9960_REG_GCONF_2,447				APDS9960_REG_GCONF_2_GGAIN_MASK,448				idx << APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT);449			if (!ret)450				data->pxs_gain = idx;451			mutex_unlock(&data->lock);452			break;453		}454	}455 456	return ret;457}458 459static int apds9960_set_als_gain(struct apds9960_data *data, int val)460{461	int ret = -EINVAL;462	int idx;463 464	for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) {465		if (apds9960_als_gain_map[idx] == val) {466			mutex_lock(&data->lock);467			ret = regmap_update_bits(data->regmap,468					APDS9960_REG_CONTROL,469					APDS9960_REG_CONTROL_AGAIN_MASK, idx);470			if (!ret)471				data->als_gain = idx;472			mutex_unlock(&data->lock);473			break;474		}475	}476 477	return ret;478}479 480#ifdef CONFIG_PM481static int apds9960_set_power_state(struct apds9960_data *data, bool on)482{483	struct device *dev = &data->client->dev;484	int ret = 0;485 486	mutex_lock(&data->lock);487 488	if (on) {489		int suspended;490 491		suspended = pm_runtime_suspended(dev);492		ret = pm_runtime_get_sync(dev);493 494		/* Allow one integration cycle before allowing a reading */495		if (suspended)496			usleep_range(data->als_adc_int_us,497				     APDS9960_MAX_INT_TIME_IN_US);498	} else {499		pm_runtime_mark_last_busy(dev);500		ret = pm_runtime_put_autosuspend(dev);501	}502 503	mutex_unlock(&data->lock);504 505	return ret;506}507#else508static int apds9960_set_power_state(struct apds9960_data *data, bool on)509{510	return 0;511}512#endif513 514static int apds9960_read_raw(struct iio_dev *indio_dev,515			     struct iio_chan_spec const *chan,516			     int *val, int *val2, long mask)517{518	struct apds9960_data *data = iio_priv(indio_dev);519	__le16 buf;520	int ret = -EINVAL;521 522	if (data->gesture_mode_running)523		return -EBUSY;524 525	switch (mask) {526	case IIO_CHAN_INFO_RAW:527		apds9960_set_power_state(data, true);528		switch (chan->type) {529		case IIO_PROXIMITY:530			ret = regmap_read(data->regmap, chan->address, val);531			if (!ret)532				ret = IIO_VAL_INT;533			break;534		case IIO_INTENSITY:535			ret = regmap_bulk_read(data->regmap, chan->address,536					       &buf, 2);537			if (!ret) {538				ret = IIO_VAL_INT;539				*val = le16_to_cpu(buf);540			}541			break;542		default:543			ret = -EINVAL;544		}545		apds9960_set_power_state(data, false);546		break;547	case IIO_CHAN_INFO_INT_TIME:548		/* RGB + ALS sensors only have integration time */549		mutex_lock(&data->lock);550		switch (chan->type) {551		case IIO_INTENSITY:552			*val = 0;553			*val2 = data->als_adc_int_us;554			ret = IIO_VAL_INT_PLUS_MICRO;555			break;556		default:557			ret = -EINVAL;558		}559		mutex_unlock(&data->lock);560		break;561	case IIO_CHAN_INFO_SCALE:562		mutex_lock(&data->lock);563		switch (chan->type) {564		case IIO_PROXIMITY:565			*val = apds9960_pxs_gain_map[data->pxs_gain];566			ret = IIO_VAL_INT;567			break;568		case IIO_INTENSITY:569			*val = apds9960_als_gain_map[data->als_gain];570			ret = IIO_VAL_INT;571			break;572		default:573			ret = -EINVAL;574		}575		mutex_unlock(&data->lock);576		break;577	case IIO_CHAN_INFO_CALIBBIAS:578		mutex_lock(&data->lock);579		*val = data->calibbias[chan->channel];580		ret = IIO_VAL_INT;581		mutex_unlock(&data->lock);582		break;583	}584 585	return ret;586};587 588static int apds9960_write_raw(struct iio_dev *indio_dev,589			     struct iio_chan_spec const *chan,590			     int val, int val2, long mask)591{592	struct apds9960_data *data = iio_priv(indio_dev);593 594	switch (mask) {595	case IIO_CHAN_INFO_INT_TIME:596		/* RGB + ALS sensors only have int time */597		switch (chan->type) {598		case IIO_INTENSITY:599			if (val != 0)600				return -EINVAL;601			return apds9960_set_it_time(data, val2);602		default:603			return -EINVAL;604		}605	case IIO_CHAN_INFO_SCALE:606		if (val2 != 0)607			return -EINVAL;608		switch (chan->type) {609		case IIO_PROXIMITY:610			return apds9960_set_pxs_gain(data, val);611		case IIO_INTENSITY:612			return apds9960_set_als_gain(data, val);613		default:614			return -EINVAL;615		}616	case IIO_CHAN_INFO_CALIBBIAS:617		if (val2 != 0)618			return -EINVAL;619		return apds9960_set_calibbias(data, chan, val);620	default:621		return -EINVAL;622	}623 624	return 0;625}626 627static inline int apds9960_get_thres_reg(const struct iio_chan_spec *chan,628					 enum iio_event_direction dir,629					 u8 *reg)630{631	switch (dir) {632	case IIO_EV_DIR_RISING:633		switch (chan->type) {634		case IIO_PROXIMITY:635			*reg = APDS9960_REG_PIHT;636			break;637		case IIO_INTENSITY:638			*reg = APDS9960_REG_AIHTL;639			break;640		default:641			return -EINVAL;642		}643		break;644	case IIO_EV_DIR_FALLING:645		switch (chan->type) {646		case IIO_PROXIMITY:647			*reg = APDS9960_REG_PILT;648			break;649		case IIO_INTENSITY:650			*reg = APDS9960_REG_AILTL;651			break;652		default:653			return -EINVAL;654		}655		break;656	default:657		return -EINVAL;658	}659 660	return 0;661}662 663static int apds9960_read_event(struct iio_dev *indio_dev,664			       const struct iio_chan_spec *chan,665			       enum iio_event_type type,666			       enum iio_event_direction dir,667			       enum iio_event_info info,668			       int *val, int *val2)669{670	u8 reg;671	__le16 buf;672	int ret = 0;673	struct apds9960_data *data = iio_priv(indio_dev);674 675	if (info != IIO_EV_INFO_VALUE)676		return -EINVAL;677 678	ret = apds9960_get_thres_reg(chan, dir, &reg);679	if (ret < 0)680		return ret;681 682	if (chan->type == IIO_PROXIMITY) {683		ret = regmap_read(data->regmap, reg, val);684		if (ret < 0)685			return ret;686	} else if (chan->type == IIO_INTENSITY) {687		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);688		if (ret < 0)689			return ret;690		*val = le16_to_cpu(buf);691	} else692		return -EINVAL;693 694	*val2 = 0;695 696	return IIO_VAL_INT;697}698 699static int apds9960_write_event(struct iio_dev *indio_dev,700				const struct iio_chan_spec *chan,701				enum iio_event_type type,702				enum iio_event_direction dir,703				enum iio_event_info info,704				int val, int val2)705{706	u8 reg;707	__le16 buf;708	int ret = 0;709	struct apds9960_data *data = iio_priv(indio_dev);710 711	if (info != IIO_EV_INFO_VALUE)712		return -EINVAL;713 714	ret = apds9960_get_thres_reg(chan, dir, &reg);715	if (ret < 0)716		return ret;717 718	if (chan->type == IIO_PROXIMITY) {719		if (val < 0 || val > APDS9960_MAX_PXS_THRES_VAL)720			return -EINVAL;721		ret = regmap_write(data->regmap, reg, val);722		if (ret < 0)723			return ret;724	} else if (chan->type == IIO_INTENSITY) {725		if (val < 0 || val > APDS9960_MAX_ALS_THRES_VAL)726			return -EINVAL;727		buf = cpu_to_le16(val);728		ret = regmap_bulk_write(data->regmap, reg, &buf, 2);729		if (ret < 0)730			return ret;731	} else732		return -EINVAL;733 734	return 0;735}736 737static int apds9960_read_event_config(struct iio_dev *indio_dev,738				      const struct iio_chan_spec *chan,739				      enum iio_event_type type,740				      enum iio_event_direction dir)741{742	struct apds9960_data *data = iio_priv(indio_dev);743 744	switch (chan->type) {745	case IIO_PROXIMITY:746		return data->pxs_int;747	case IIO_INTENSITY:748		return data->als_int;749	default:750		return -EINVAL;751	}752 753	return 0;754}755 756static int apds9960_write_event_config(struct iio_dev *indio_dev,757				       const struct iio_chan_spec *chan,758				       enum iio_event_type type,759				       enum iio_event_direction dir,760				       int state)761{762	struct apds9960_data *data = iio_priv(indio_dev);763	int ret;764 765	state = !!state;766 767	switch (chan->type) {768	case IIO_PROXIMITY:769		if (data->pxs_int == state)770			return -EINVAL;771 772		ret = regmap_field_write(data->reg_int_pxs, state);773		if (ret)774			return ret;775		data->pxs_int = state;776		apds9960_set_power_state(data, state);777		break;778	case IIO_INTENSITY:779		if (data->als_int == state)780			return -EINVAL;781 782		ret = regmap_field_write(data->reg_int_als, state);783		if (ret)784			return ret;785		data->als_int = state;786		apds9960_set_power_state(data, state);787		break;788	default:789		return -EINVAL;790	}791 792	return 0;793}794 795static const struct iio_info apds9960_info = {796	.attrs = &apds9960_attribute_group,797	.read_raw = apds9960_read_raw,798	.write_raw = apds9960_write_raw,799	.read_event_value = apds9960_read_event,800	.write_event_value = apds9960_write_event,801	.read_event_config = apds9960_read_event_config,802	.write_event_config = apds9960_write_event_config,803 804};805 806static inline int apds9660_fifo_is_empty(struct apds9960_data *data)807{808	int cnt;809	int ret;810 811	ret = regmap_read(data->regmap, APDS9960_REG_GFLVL, &cnt);812	if (ret)813		return ret;814 815	return cnt;816}817 818static void apds9960_read_gesture_fifo(struct apds9960_data *data)819{820	int ret, cnt = 0;821 822	mutex_lock(&data->lock);823	data->gesture_mode_running = 1;824 825	while (cnt || (cnt = apds9660_fifo_is_empty(data) > 0)) {826		ret = regmap_bulk_read(data->regmap, APDS9960_REG_GFIFO_BASE,827				      &data->buffer, 4);828 829		if (ret)830			goto err_read;831 832		iio_push_to_buffers(data->indio_dev, data->buffer);833		cnt--;834	}835 836err_read:837	data->gesture_mode_running = 0;838	mutex_unlock(&data->lock);839}840 841static irqreturn_t apds9960_interrupt_handler(int irq, void *private)842{843	struct iio_dev *indio_dev = private;844	struct apds9960_data *data = iio_priv(indio_dev);845	int ret, status;846 847	ret = regmap_read(data->regmap, APDS9960_REG_STATUS, &status);848	if (ret < 0) {849		dev_err(&data->client->dev, "irq status reg read failed\n");850		return IRQ_HANDLED;851	}852 853	if ((status & APDS9960_REG_STATUS_ALS_INT) && data->als_int) {854		iio_push_event(indio_dev,855			       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,856						    IIO_EV_TYPE_THRESH,857						    IIO_EV_DIR_EITHER),858			       iio_get_time_ns(indio_dev));859		regmap_write(data->regmap, APDS9960_REG_CICLEAR, 1);860	}861 862	if ((status & APDS9960_REG_STATUS_PS_INT) && data->pxs_int) {863		iio_push_event(indio_dev,864			       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,865						    IIO_EV_TYPE_THRESH,866						    IIO_EV_DIR_EITHER),867			       iio_get_time_ns(indio_dev));868		regmap_write(data->regmap, APDS9960_REG_PICLEAR, 1);869	}870 871	if (status & APDS9960_REG_STATUS_GINT)872		apds9960_read_gesture_fifo(data);873 874	return IRQ_HANDLED;875}876 877static int apds9960_set_powermode(struct apds9960_data *data, bool state)878{879	return regmap_update_bits(data->regmap, APDS9960_REG_ENABLE, 1, state);880}881 882static int apds9960_buffer_postenable(struct iio_dev *indio_dev)883{884	struct apds9960_data *data = iio_priv(indio_dev);885	int ret;886 887	ret = regmap_field_write(data->reg_int_ges, 1);888	if (ret)889		return ret;890 891	ret = regmap_field_write(data->reg_enable_ges, 1);892	if (ret)893		return ret;894 895	pm_runtime_get_sync(&data->client->dev);896 897	return 0;898}899 900static int apds9960_buffer_predisable(struct iio_dev *indio_dev)901{902	struct apds9960_data *data = iio_priv(indio_dev);903	int ret;904 905	ret = regmap_field_write(data->reg_enable_ges, 0);906	if (ret)907		return ret;908 909	ret = regmap_field_write(data->reg_int_ges, 0);910	if (ret)911		return ret;912 913	pm_runtime_put_autosuspend(&data->client->dev);914 915	return 0;916}917 918static const struct iio_buffer_setup_ops apds9960_buffer_setup_ops = {919	.postenable = apds9960_buffer_postenable,920	.predisable = apds9960_buffer_predisable,921};922 923static int apds9960_regfield_init(struct apds9960_data *data)924{925	struct device *dev = &data->client->dev;926	struct regmap *regmap = data->regmap;927 928	data->reg_int_als = devm_regmap_field_alloc(dev, regmap,929						apds9960_reg_field_int_als);930	if (IS_ERR(data->reg_int_als)) {931		dev_err(dev, "INT ALS reg field init failed\n");932		return PTR_ERR(data->reg_int_als);933	}934 935	data->reg_int_ges = devm_regmap_field_alloc(dev, regmap,936						apds9960_reg_field_int_ges);937	if (IS_ERR(data->reg_int_ges)) {938		dev_err(dev, "INT gesture reg field init failed\n");939		return PTR_ERR(data->reg_int_ges);940	}941 942	data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap,943						apds9960_reg_field_int_pxs);944	if (IS_ERR(data->reg_int_pxs)) {945		dev_err(dev, "INT pxs reg field init failed\n");946		return PTR_ERR(data->reg_int_pxs);947	}948 949	data->reg_enable_als = devm_regmap_field_alloc(dev, regmap,950						apds9960_reg_field_enable_als);951	if (IS_ERR(data->reg_enable_als)) {952		dev_err(dev, "Enable ALS reg field init failed\n");953		return PTR_ERR(data->reg_enable_als);954	}955 956	data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap,957						apds9960_reg_field_enable_ges);958	if (IS_ERR(data->reg_enable_ges)) {959		dev_err(dev, "Enable gesture reg field init failed\n");960		return PTR_ERR(data->reg_enable_ges);961	}962 963	data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap,964						apds9960_reg_field_enable_pxs);965	if (IS_ERR(data->reg_enable_pxs)) {966		dev_err(dev, "Enable PXS reg field init failed\n");967		return PTR_ERR(data->reg_enable_pxs);968	}969 970	return 0;971}972 973static int apds9960_chip_init(struct apds9960_data *data)974{975	int ret;976 977	/* Default IT for ALS of 28 ms */978	ret = apds9960_set_it_time(data, 28000);979	if (ret)980		return ret;981 982	/* Ensure gesture interrupt is OFF */983	ret = regmap_field_write(data->reg_int_ges, 0);984	if (ret)985		return ret;986 987	/* Disable gesture sensor, since polling is useless from user-space */988	ret = regmap_field_write(data->reg_enable_ges, 0);989	if (ret)990		return ret;991 992	/* Ensure proximity interrupt is OFF */993	ret = regmap_field_write(data->reg_int_pxs, 0);994	if (ret)995		return ret;996 997	/* Enable proximity sensor for polling */998	ret = regmap_field_write(data->reg_enable_pxs, 1);999	if (ret)1000		return ret;1001 1002	/* Ensure ALS interrupt is OFF */1003	ret = regmap_field_write(data->reg_int_als, 0);1004	if (ret)1005		return ret;1006 1007	/* Enable ALS sensor for polling */1008	ret = regmap_field_write(data->reg_enable_als, 1);1009	if (ret)1010		return ret;1011	/*1012	 * When enabled trigger an interrupt after 3 readings1013	 * outside threshold for ALS + PXS1014	 */1015	ret = regmap_write(data->regmap, APDS9960_REG_PERS,1016			   APDS9960_DEFAULT_PERS);1017	if (ret)1018		return ret;1019 1020	/*1021	 * Wait for 4 event outside gesture threshold to prevent interrupt1022	 * flooding.1023	 */1024	ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1,1025			APDS9960_REG_GCONF_1_GFIFO_THRES_MASK,1026			BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT);1027	if (ret)1028		return ret;1029 1030	/* Default ENTER and EXIT thresholds for the GESTURE engine. */1031	ret = regmap_write(data->regmap, APDS9960_REG_GPENTH,1032			   APDS9960_DEFAULT_GPENTH);1033	if (ret)1034		return ret;1035 1036	ret = regmap_write(data->regmap, APDS9960_REG_GEXTH,1037			   APDS9960_DEFAULT_GEXTH);1038	if (ret)1039		return ret;1040 1041	return apds9960_set_powermode(data, 1);1042}1043 1044static int apds9960_probe(struct i2c_client *client)1045{1046	struct apds9960_data *data;1047	struct iio_dev *indio_dev;1048	int ret;1049 1050	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));1051	if (!indio_dev)1052		return -ENOMEM;1053 1054	indio_dev->info = &apds9960_info;1055	indio_dev->name = APDS9960_DRV_NAME;1056	indio_dev->channels = apds9960_channels;1057	indio_dev->num_channels = ARRAY_SIZE(apds9960_channels);1058	indio_dev->available_scan_masks = apds9960_scan_masks;1059	indio_dev->modes = INDIO_DIRECT_MODE;1060 1061	ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,1062					  &apds9960_buffer_setup_ops);1063	if (ret)1064		return ret;1065 1066	data = iio_priv(indio_dev);1067	i2c_set_clientdata(client, indio_dev);1068 1069	data->regmap = devm_regmap_init_i2c(client, &apds9960_regmap_config);1070	if (IS_ERR(data->regmap)) {1071		dev_err(&client->dev, "regmap initialization failed.\n");1072		return PTR_ERR(data->regmap);1073	}1074 1075	data->client = client;1076	data->indio_dev = indio_dev;1077	mutex_init(&data->lock);1078 1079	ret = pm_runtime_set_active(&client->dev);1080	if (ret)1081		goto error_power_down;1082 1083	pm_runtime_enable(&client->dev);1084	pm_runtime_set_autosuspend_delay(&client->dev, 5000);1085	pm_runtime_use_autosuspend(&client->dev);1086 1087	apds9960_set_power_state(data, true);1088 1089	ret = apds9960_regfield_init(data);1090	if (ret)1091		goto error_power_down;1092 1093	ret = apds9960_chip_init(data);1094	if (ret)1095		goto error_power_down;1096 1097	if (client->irq <= 0) {1098		dev_err(&client->dev, "no valid irq defined\n");1099		ret = -EINVAL;1100		goto error_power_down;1101	}1102	ret = devm_request_threaded_irq(&client->dev, client->irq,1103					NULL, apds9960_interrupt_handler,1104					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,1105					"apds9960_event",1106					indio_dev);1107	if (ret) {1108		dev_err(&client->dev, "request irq (%d) failed\n", client->irq);1109		goto error_power_down;1110	}1111 1112	ret = iio_device_register(indio_dev);1113	if (ret)1114		goto error_power_down;1115 1116	apds9960_set_power_state(data, false);1117 1118	return 0;1119 1120error_power_down:1121	apds9960_set_power_state(data, false);1122 1123	return ret;1124}1125 1126static void apds9960_remove(struct i2c_client *client)1127{1128	struct iio_dev *indio_dev = i2c_get_clientdata(client);1129	struct apds9960_data *data = iio_priv(indio_dev);1130 1131	iio_device_unregister(indio_dev);1132	pm_runtime_disable(&client->dev);1133	pm_runtime_set_suspended(&client->dev);1134	apds9960_set_powermode(data, 0);1135}1136 1137#ifdef CONFIG_PM1138static int apds9960_runtime_suspend(struct device *dev)1139{1140	struct apds9960_data *data =1141			iio_priv(i2c_get_clientdata(to_i2c_client(dev)));1142 1143	return apds9960_set_powermode(data, 0);1144}1145 1146static int apds9960_runtime_resume(struct device *dev)1147{1148	struct apds9960_data *data =1149			iio_priv(i2c_get_clientdata(to_i2c_client(dev)));1150 1151	return apds9960_set_powermode(data, 1);1152}1153#endif1154 1155static const struct dev_pm_ops apds9960_pm_ops = {1156	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,1157				pm_runtime_force_resume)1158	SET_RUNTIME_PM_OPS(apds9960_runtime_suspend,1159			   apds9960_runtime_resume, NULL)1160};1161 1162static const struct i2c_device_id apds9960_id[] = {1163	{ "apds9960" },1164	{}1165};1166MODULE_DEVICE_TABLE(i2c, apds9960_id);1167 1168static const struct acpi_device_id apds9960_acpi_match[] = {1169	{ "MSHW0184" },1170	{ }1171};1172MODULE_DEVICE_TABLE(acpi, apds9960_acpi_match);1173 1174static const struct of_device_id apds9960_of_match[] = {1175	{ .compatible = "avago,apds9960" },1176	{ }1177};1178MODULE_DEVICE_TABLE(of, apds9960_of_match);1179 1180static struct i2c_driver apds9960_driver = {1181	.driver = {1182		.name	= APDS9960_DRV_NAME,1183		.of_match_table = apds9960_of_match,1184		.pm	= &apds9960_pm_ops,1185		.acpi_match_table = apds9960_acpi_match,1186	},1187	.probe		= apds9960_probe,1188	.remove		= apds9960_remove,1189	.id_table	= apds9960_id,1190};1191module_i2c_driver(apds9960_driver);1192 1193MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");1194MODULE_DESCRIPTION("APDS9960 Gesture/RGB/ALS/Proximity sensor");1195MODULE_LICENSE("GPL");1196