brintos

brintos / linux-shallow public Read only

0
0
Text · 45.0 KiB · 81e718c Raw
1618 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 Samsung Electronics Co., Ltd.4 * Author: Jacek Anaszewski <j.anaszewski@samsung.com>5 *6 * IIO features supported by the driver:7 *8 * Read-only raw channels:9 *   - illuminance_clear [lux]10 *   - illuminance_ir11 *   - proximity12 *13 * Triggered buffer:14 *   - illuminance_clear15 *   - illuminance_ir16 *   - proximity17 *18 * Events:19 *   - illuminance_clear (rising and falling)20 *   - proximity (rising and falling)21 *     - both falling and rising thresholds for the proximity events22 *       must be set to the values greater than 0.23 *24 * The driver supports triggered buffers for all the three25 * channels as well as high and low threshold events for the26 * illuminance_clear and proxmimity channels. Triggers27 * can be enabled simultaneously with both illuminance_clear28 * events. Proximity events cannot be enabled simultaneously29 * with any triggers or illuminance events. Enabling/disabling30 * one of the proximity events automatically enables/disables31 * the other one.32 */33 34#include <linux/debugfs.h>35#include <linux/delay.h>36#include <linux/i2c.h>37#include <linux/interrupt.h>38#include <linux/irq.h>39#include <linux/irq_work.h>40#include <linux/module.h>41#include <linux/mod_devicetable.h>42#include <linux/mutex.h>43#include <linux/regmap.h>44#include <linux/regulator/consumer.h>45#include <linux/slab.h>46#include <linux/unaligned.h>47#include <linux/iio/buffer.h>48#include <linux/iio/events.h>49#include <linux/iio/iio.h>50#include <linux/iio/sysfs.h>51#include <linux/iio/trigger.h>52#include <linux/iio/trigger_consumer.h>53#include <linux/iio/triggered_buffer.h>54 55#define GP2A_I2C_NAME "gp2ap020a00f"56 57/* Registers */58#define GP2AP020A00F_OP_REG	0x00 /* Basic operations */59#define GP2AP020A00F_ALS_REG	0x01 /* ALS related settings */60#define GP2AP020A00F_PS_REG	0x02 /* PS related settings */61#define GP2AP020A00F_LED_REG	0x03 /* LED reg */62#define GP2AP020A00F_TL_L_REG	0x04 /* ALS: Threshold low LSB */63#define GP2AP020A00F_TL_H_REG	0x05 /* ALS: Threshold low MSB */64#define GP2AP020A00F_TH_L_REG	0x06 /* ALS: Threshold high LSB */65#define GP2AP020A00F_TH_H_REG	0x07 /* ALS: Threshold high MSB */66#define GP2AP020A00F_PL_L_REG	0x08 /* PS: Threshold low LSB */67#define GP2AP020A00F_PL_H_REG	0x09 /* PS: Threshold low MSB */68#define GP2AP020A00F_PH_L_REG	0x0a /* PS: Threshold high LSB */69#define GP2AP020A00F_PH_H_REG	0x0b /* PS: Threshold high MSB */70#define GP2AP020A00F_D0_L_REG	0x0c /* ALS result: Clear/Illuminance LSB */71#define GP2AP020A00F_D0_H_REG	0x0d /* ALS result: Clear/Illuminance MSB */72#define GP2AP020A00F_D1_L_REG	0x0e /* ALS result: IR LSB */73#define GP2AP020A00F_D1_H_REG	0x0f /* ALS result: IR LSB */74#define GP2AP020A00F_D2_L_REG	0x10 /* PS result LSB */75#define GP2AP020A00F_D2_H_REG	0x11 /* PS result MSB */76#define GP2AP020A00F_NUM_REGS	0x12 /* Number of registers */77 78/* OP_REG bits */79#define GP2AP020A00F_OP3_MASK		0x80 /* Software shutdown */80#define GP2AP020A00F_OP3_SHUTDOWN	0x0081#define GP2AP020A00F_OP3_OPERATION	0x8082#define GP2AP020A00F_OP2_MASK		0x40 /* Auto shutdown/Continuous mode */83#define GP2AP020A00F_OP2_AUTO_SHUTDOWN	0x0084#define GP2AP020A00F_OP2_CONT_OPERATION	0x4085#define GP2AP020A00F_OP_MASK		0x30 /* Operating mode selection  */86#define GP2AP020A00F_OP_ALS_AND_PS	0x0087#define GP2AP020A00F_OP_ALS		0x1088#define GP2AP020A00F_OP_PS		0x2089#define GP2AP020A00F_OP_DEBUG		0x3090#define GP2AP020A00F_PROX_MASK		0x08 /* PS: detection/non-detection */91#define GP2AP020A00F_PROX_NON_DETECT	0x0092#define GP2AP020A00F_PROX_DETECT	0x0893#define GP2AP020A00F_FLAG_P		0x04 /* PS: interrupt result  */94#define GP2AP020A00F_FLAG_A		0x02 /* ALS: interrupt result  */95#define GP2AP020A00F_TYPE_MASK		0x01 /* Output data type selection */96#define GP2AP020A00F_TYPE_MANUAL_CALC	0x0097#define GP2AP020A00F_TYPE_AUTO_CALC	0x0198 99/* ALS_REG bits */100#define GP2AP020A00F_PRST_MASK		0xc0 /* Number of measurement cycles */101#define GP2AP020A00F_PRST_ONCE		0x00102#define GP2AP020A00F_PRST_4_CYCLES	0x40103#define GP2AP020A00F_PRST_8_CYCLES	0x80104#define GP2AP020A00F_PRST_16_CYCLES	0xc0105#define GP2AP020A00F_RES_A_MASK		0x38 /* ALS: Resolution */106#define GP2AP020A00F_RES_A_800ms	0x00107#define GP2AP020A00F_RES_A_400ms	0x08108#define GP2AP020A00F_RES_A_200ms	0x10109#define GP2AP020A00F_RES_A_100ms	0x18110#define GP2AP020A00F_RES_A_25ms		0x20111#define GP2AP020A00F_RES_A_6_25ms	0x28112#define GP2AP020A00F_RES_A_1_56ms	0x30113#define GP2AP020A00F_RES_A_0_39ms	0x38114#define GP2AP020A00F_RANGE_A_MASK	0x07 /* ALS: Max measurable range */115#define GP2AP020A00F_RANGE_A_x1		0x00116#define GP2AP020A00F_RANGE_A_x2		0x01117#define GP2AP020A00F_RANGE_A_x4		0x02118#define GP2AP020A00F_RANGE_A_x8		0x03119#define GP2AP020A00F_RANGE_A_x16	0x04120#define GP2AP020A00F_RANGE_A_x32	0x05121#define GP2AP020A00F_RANGE_A_x64	0x06122#define GP2AP020A00F_RANGE_A_x128	0x07123 124/* PS_REG bits */125#define GP2AP020A00F_ALC_MASK		0x80 /* Auto light cancel */126#define GP2AP020A00F_ALC_ON		0x80127#define GP2AP020A00F_ALC_OFF		0x00128#define GP2AP020A00F_INTTYPE_MASK	0x40 /* Interrupt type setting */129#define GP2AP020A00F_INTTYPE_LEVEL	0x00130#define GP2AP020A00F_INTTYPE_PULSE	0x40131#define GP2AP020A00F_RES_P_MASK		0x38 /* PS: Resolution */132#define GP2AP020A00F_RES_P_800ms_x2	0x00133#define GP2AP020A00F_RES_P_400ms_x2	0x08134#define GP2AP020A00F_RES_P_200ms_x2	0x10135#define GP2AP020A00F_RES_P_100ms_x2	0x18136#define GP2AP020A00F_RES_P_25ms_x2	0x20137#define GP2AP020A00F_RES_P_6_25ms_x2	0x28138#define GP2AP020A00F_RES_P_1_56ms_x2	0x30139#define GP2AP020A00F_RES_P_0_39ms_x2	0x38140#define GP2AP020A00F_RANGE_P_MASK	0x07 /* PS: Max measurable range */141#define GP2AP020A00F_RANGE_P_x1		0x00142#define GP2AP020A00F_RANGE_P_x2		0x01143#define GP2AP020A00F_RANGE_P_x4		0x02144#define GP2AP020A00F_RANGE_P_x8		0x03145#define GP2AP020A00F_RANGE_P_x16	0x04146#define GP2AP020A00F_RANGE_P_x32	0x05147#define GP2AP020A00F_RANGE_P_x64	0x06148#define GP2AP020A00F_RANGE_P_x128	0x07149 150/* LED reg bits */151#define GP2AP020A00F_INTVAL_MASK	0xc0 /* Intermittent operating */152#define GP2AP020A00F_INTVAL_0		0x00153#define GP2AP020A00F_INTVAL_4		0x40154#define GP2AP020A00F_INTVAL_8		0x80155#define GP2AP020A00F_INTVAL_16		0xc0156#define GP2AP020A00F_IS_MASK		0x30 /* ILED drive peak current */157#define GP2AP020A00F_IS_13_8mA		0x00158#define GP2AP020A00F_IS_27_5mA		0x10159#define GP2AP020A00F_IS_55mA		0x20160#define GP2AP020A00F_IS_110mA		0x30161#define GP2AP020A00F_PIN_MASK		0x0c /* INT terminal setting */162#define GP2AP020A00F_PIN_ALS_OR_PS	0x00163#define GP2AP020A00F_PIN_ALS		0x04164#define GP2AP020A00F_PIN_PS		0x08165#define GP2AP020A00F_PIN_PS_DETECT	0x0c166#define GP2AP020A00F_FREQ_MASK		0x02 /* LED modulation frequency */167#define GP2AP020A00F_FREQ_327_5kHz	0x00168#define GP2AP020A00F_FREQ_81_8kHz	0x02169#define GP2AP020A00F_RST		0x01 /* Software reset */170 171#define GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR	0172#define GP2AP020A00F_SCAN_MODE_LIGHT_IR		1173#define GP2AP020A00F_SCAN_MODE_PROXIMITY	2174#define GP2AP020A00F_CHAN_TIMESTAMP		3175 176#define GP2AP020A00F_DATA_READY_TIMEOUT		msecs_to_jiffies(1000)177#define GP2AP020A00F_DATA_REG(chan)		(GP2AP020A00F_D0_L_REG + \178							(chan) * 2)179#define GP2AP020A00F_THRESH_REG(th_val_id)	(GP2AP020A00F_TL_L_REG + \180							(th_val_id) * 2)181#define GP2AP020A00F_THRESH_VAL_ID(reg_addr)	((reg_addr - 4) / 2)182 183#define GP2AP020A00F_SUBTRACT_MODE	0184#define GP2AP020A00F_ADD_MODE		1185 186#define GP2AP020A00F_MAX_CHANNELS	3187 188enum gp2ap020a00f_opmode {189	GP2AP020A00F_OPMODE_READ_RAW_CLEAR,190	GP2AP020A00F_OPMODE_READ_RAW_IR,191	GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY,192	GP2AP020A00F_OPMODE_ALS,193	GP2AP020A00F_OPMODE_PS,194	GP2AP020A00F_OPMODE_ALS_AND_PS,195	GP2AP020A00F_OPMODE_PROX_DETECT,196	GP2AP020A00F_OPMODE_SHUTDOWN,197	GP2AP020A00F_NUM_OPMODES,198};199 200enum gp2ap020a00f_cmd {201	GP2AP020A00F_CMD_READ_RAW_CLEAR,202	GP2AP020A00F_CMD_READ_RAW_IR,203	GP2AP020A00F_CMD_READ_RAW_PROXIMITY,204	GP2AP020A00F_CMD_TRIGGER_CLEAR_EN,205	GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS,206	GP2AP020A00F_CMD_TRIGGER_IR_EN,207	GP2AP020A00F_CMD_TRIGGER_IR_DIS,208	GP2AP020A00F_CMD_TRIGGER_PROX_EN,209	GP2AP020A00F_CMD_TRIGGER_PROX_DIS,210	GP2AP020A00F_CMD_ALS_HIGH_EV_EN,211	GP2AP020A00F_CMD_ALS_HIGH_EV_DIS,212	GP2AP020A00F_CMD_ALS_LOW_EV_EN,213	GP2AP020A00F_CMD_ALS_LOW_EV_DIS,214	GP2AP020A00F_CMD_PROX_HIGH_EV_EN,215	GP2AP020A00F_CMD_PROX_HIGH_EV_DIS,216	GP2AP020A00F_CMD_PROX_LOW_EV_EN,217	GP2AP020A00F_CMD_PROX_LOW_EV_DIS,218};219 220enum gp2ap020a00f_flags {221	GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER,222	GP2AP020A00F_FLAG_ALS_IR_TRIGGER,223	GP2AP020A00F_FLAG_PROX_TRIGGER,224	GP2AP020A00F_FLAG_PROX_RISING_EV,225	GP2AP020A00F_FLAG_PROX_FALLING_EV,226	GP2AP020A00F_FLAG_ALS_RISING_EV,227	GP2AP020A00F_FLAG_ALS_FALLING_EV,228	GP2AP020A00F_FLAG_LUX_MODE_HI,229	GP2AP020A00F_FLAG_DATA_READY,230};231 232enum gp2ap020a00f_thresh_val_id {233	GP2AP020A00F_THRESH_TL,234	GP2AP020A00F_THRESH_TH,235	GP2AP020A00F_THRESH_PL,236	GP2AP020A00F_THRESH_PH,237};238 239struct gp2ap020a00f_data {240	struct i2c_client *client;241	struct mutex lock;242	char *buffer;243	struct regulator *vled_reg;244	unsigned long flags;245	enum gp2ap020a00f_opmode cur_opmode;246	struct iio_trigger *trig;247	struct regmap *regmap;248	unsigned int thresh_val[4];249	u8 debug_reg_addr;250	struct irq_work work;251	wait_queue_head_t data_ready_queue;252};253 254static const u8 gp2ap020a00f_reg_init_tab[] = {255	[GP2AP020A00F_OP_REG] = GP2AP020A00F_OP3_SHUTDOWN,256	[GP2AP020A00F_ALS_REG] = GP2AP020A00F_RES_A_25ms |257				 GP2AP020A00F_RANGE_A_x8,258	[GP2AP020A00F_PS_REG] = GP2AP020A00F_ALC_ON |259				GP2AP020A00F_RES_P_1_56ms_x2 |260				GP2AP020A00F_RANGE_P_x4,261	[GP2AP020A00F_LED_REG] = GP2AP020A00F_INTVAL_0 |262				 GP2AP020A00F_IS_110mA |263				 GP2AP020A00F_FREQ_327_5kHz,264	[GP2AP020A00F_TL_L_REG] = 0,265	[GP2AP020A00F_TL_H_REG] = 0,266	[GP2AP020A00F_TH_L_REG] = 0,267	[GP2AP020A00F_TH_H_REG] = 0,268	[GP2AP020A00F_PL_L_REG] = 0,269	[GP2AP020A00F_PL_H_REG] = 0,270	[GP2AP020A00F_PH_L_REG] = 0,271	[GP2AP020A00F_PH_H_REG] = 0,272};273 274static bool gp2ap020a00f_is_volatile_reg(struct device *dev, unsigned int reg)275{276	switch (reg) {277	case GP2AP020A00F_OP_REG:278	case GP2AP020A00F_D0_L_REG:279	case GP2AP020A00F_D0_H_REG:280	case GP2AP020A00F_D1_L_REG:281	case GP2AP020A00F_D1_H_REG:282	case GP2AP020A00F_D2_L_REG:283	case GP2AP020A00F_D2_H_REG:284		return true;285	default:286		return false;287	}288}289 290static const struct regmap_config gp2ap020a00f_regmap_config = {291	.reg_bits = 8,292	.val_bits = 8,293 294	.max_register = GP2AP020A00F_D2_H_REG,295	.cache_type = REGCACHE_RBTREE,296 297	.volatile_reg = gp2ap020a00f_is_volatile_reg,298};299 300static const struct gp2ap020a00f_mutable_config_regs {301	u8 op_reg;302	u8 als_reg;303	u8 ps_reg;304	u8 led_reg;305} opmode_regs_settings[GP2AP020A00F_NUM_OPMODES] = {306	[GP2AP020A00F_OPMODE_READ_RAW_CLEAR] = {307		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION308		| GP2AP020A00F_OP3_OPERATION309		| GP2AP020A00F_TYPE_AUTO_CALC,310		GP2AP020A00F_PRST_ONCE,311		GP2AP020A00F_INTTYPE_LEVEL,312		GP2AP020A00F_PIN_ALS313	},314	[GP2AP020A00F_OPMODE_READ_RAW_IR] = {315		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION316		| GP2AP020A00F_OP3_OPERATION317		| GP2AP020A00F_TYPE_MANUAL_CALC,318		GP2AP020A00F_PRST_ONCE,319		GP2AP020A00F_INTTYPE_LEVEL,320		GP2AP020A00F_PIN_ALS321	},322	[GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY] = {323		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION324		| GP2AP020A00F_OP3_OPERATION325		| GP2AP020A00F_TYPE_MANUAL_CALC,326		GP2AP020A00F_PRST_ONCE,327		GP2AP020A00F_INTTYPE_LEVEL,328		GP2AP020A00F_PIN_PS329	},330	[GP2AP020A00F_OPMODE_PROX_DETECT] = {331		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION332		| GP2AP020A00F_OP3_OPERATION333		| GP2AP020A00F_TYPE_MANUAL_CALC,334		GP2AP020A00F_PRST_4_CYCLES,335		GP2AP020A00F_INTTYPE_PULSE,336		GP2AP020A00F_PIN_PS_DETECT337	},338	[GP2AP020A00F_OPMODE_ALS] = {339		GP2AP020A00F_OP_ALS | GP2AP020A00F_OP2_CONT_OPERATION340		| GP2AP020A00F_OP3_OPERATION341		| GP2AP020A00F_TYPE_AUTO_CALC,342		GP2AP020A00F_PRST_ONCE,343		GP2AP020A00F_INTTYPE_LEVEL,344		GP2AP020A00F_PIN_ALS345	},346	[GP2AP020A00F_OPMODE_PS] = {347		GP2AP020A00F_OP_PS | GP2AP020A00F_OP2_CONT_OPERATION348		| GP2AP020A00F_OP3_OPERATION349		| GP2AP020A00F_TYPE_MANUAL_CALC,350		GP2AP020A00F_PRST_4_CYCLES,351		GP2AP020A00F_INTTYPE_LEVEL,352		GP2AP020A00F_PIN_PS353	},354	[GP2AP020A00F_OPMODE_ALS_AND_PS] = {355		GP2AP020A00F_OP_ALS_AND_PS356		| GP2AP020A00F_OP2_CONT_OPERATION357		| GP2AP020A00F_OP3_OPERATION358		| GP2AP020A00F_TYPE_AUTO_CALC,359		GP2AP020A00F_PRST_4_CYCLES,360		GP2AP020A00F_INTTYPE_LEVEL,361		GP2AP020A00F_PIN_ALS_OR_PS362	},363	[GP2AP020A00F_OPMODE_SHUTDOWN] = { GP2AP020A00F_OP3_SHUTDOWN, },364};365 366static int gp2ap020a00f_set_operation_mode(struct gp2ap020a00f_data *data,367					enum gp2ap020a00f_opmode op)368{369	unsigned int op_reg_val;370	int err;371 372	if (op != GP2AP020A00F_OPMODE_SHUTDOWN) {373		err = regmap_read(data->regmap, GP2AP020A00F_OP_REG,374					&op_reg_val);375		if (err < 0)376			return err;377		/*378		 * Shutdown the device if the operation being executed entails379		 * mode transition.380		 */381		if ((opmode_regs_settings[op].op_reg & GP2AP020A00F_OP_MASK) !=382		    (op_reg_val & GP2AP020A00F_OP_MASK)) {383			/* set shutdown mode */384			err = regmap_update_bits(data->regmap,385				GP2AP020A00F_OP_REG, GP2AP020A00F_OP3_MASK,386				GP2AP020A00F_OP3_SHUTDOWN);387			if (err < 0)388				return err;389		}390 391		err = regmap_update_bits(data->regmap, GP2AP020A00F_ALS_REG,392			GP2AP020A00F_PRST_MASK, opmode_regs_settings[op]393								.als_reg);394		if (err < 0)395			return err;396 397		err = regmap_update_bits(data->regmap, GP2AP020A00F_PS_REG,398			GP2AP020A00F_INTTYPE_MASK, opmode_regs_settings[op]399								.ps_reg);400		if (err < 0)401			return err;402 403		err = regmap_update_bits(data->regmap, GP2AP020A00F_LED_REG,404			GP2AP020A00F_PIN_MASK, opmode_regs_settings[op]405								.led_reg);406		if (err < 0)407			return err;408	}409 410	/* Set OP_REG and apply operation mode (power on / off) */411	err = regmap_update_bits(data->regmap,412				 GP2AP020A00F_OP_REG,413				 GP2AP020A00F_OP_MASK | GP2AP020A00F_OP2_MASK |414				 GP2AP020A00F_OP3_MASK | GP2AP020A00F_TYPE_MASK,415				 opmode_regs_settings[op].op_reg);416	if (err < 0)417		return err;418 419	data->cur_opmode = op;420 421	return 0;422}423 424static bool gp2ap020a00f_als_enabled(struct gp2ap020a00f_data *data)425{426	return test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags) ||427	       test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags) ||428	       test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags) ||429	       test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);430}431 432static bool gp2ap020a00f_prox_detect_enabled(struct gp2ap020a00f_data *data)433{434	return test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags) ||435	       test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);436}437 438static int gp2ap020a00f_write_event_threshold(struct gp2ap020a00f_data *data,439				enum gp2ap020a00f_thresh_val_id th_val_id,440				bool enable)441{442	__le16 thresh_buf = 0;443	unsigned int thresh_reg_val;444 445	if (!enable)446		thresh_reg_val = 0;447	else if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags) &&448		 th_val_id != GP2AP020A00F_THRESH_PL &&449		 th_val_id != GP2AP020A00F_THRESH_PH)450		/*451		 * For the high lux mode ALS threshold has to be scaled down452		 * to allow for proper comparison with the output value.453		 */454		thresh_reg_val = data->thresh_val[th_val_id] / 16;455	else456		thresh_reg_val = data->thresh_val[th_val_id] > 16000 ?457					16000 :458					data->thresh_val[th_val_id];459 460	thresh_buf = cpu_to_le16(thresh_reg_val);461 462	return regmap_bulk_write(data->regmap,463				 GP2AP020A00F_THRESH_REG(th_val_id),464				 (u8 *)&thresh_buf, 2);465}466 467static int gp2ap020a00f_alter_opmode(struct gp2ap020a00f_data *data,468			enum gp2ap020a00f_opmode diff_mode, int add_sub)469{470	enum gp2ap020a00f_opmode new_mode;471 472	if (diff_mode != GP2AP020A00F_OPMODE_ALS &&473	    diff_mode != GP2AP020A00F_OPMODE_PS)474		return -EINVAL;475 476	if (add_sub == GP2AP020A00F_ADD_MODE) {477		if (data->cur_opmode == GP2AP020A00F_OPMODE_SHUTDOWN)478			new_mode =  diff_mode;479		else480			new_mode = GP2AP020A00F_OPMODE_ALS_AND_PS;481	} else {482		if (data->cur_opmode == GP2AP020A00F_OPMODE_ALS_AND_PS)483			new_mode = (diff_mode == GP2AP020A00F_OPMODE_ALS) ?484					GP2AP020A00F_OPMODE_PS :485					GP2AP020A00F_OPMODE_ALS;486		else487			new_mode = GP2AP020A00F_OPMODE_SHUTDOWN;488	}489 490	return gp2ap020a00f_set_operation_mode(data, new_mode);491}492 493static int gp2ap020a00f_exec_cmd(struct gp2ap020a00f_data *data,494					enum gp2ap020a00f_cmd cmd)495{496	int err = 0;497 498	switch (cmd) {499	case GP2AP020A00F_CMD_READ_RAW_CLEAR:500		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)501			return -EBUSY;502		err = gp2ap020a00f_set_operation_mode(data,503					GP2AP020A00F_OPMODE_READ_RAW_CLEAR);504		break;505	case GP2AP020A00F_CMD_READ_RAW_IR:506		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)507			return -EBUSY;508		err = gp2ap020a00f_set_operation_mode(data,509					GP2AP020A00F_OPMODE_READ_RAW_IR);510		break;511	case GP2AP020A00F_CMD_READ_RAW_PROXIMITY:512		if (data->cur_opmode != GP2AP020A00F_OPMODE_SHUTDOWN)513			return -EBUSY;514		err = gp2ap020a00f_set_operation_mode(data,515					GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY);516		break;517	case GP2AP020A00F_CMD_TRIGGER_CLEAR_EN:518		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)519			return -EBUSY;520		if (!gp2ap020a00f_als_enabled(data))521			err = gp2ap020a00f_alter_opmode(data,522						GP2AP020A00F_OPMODE_ALS,523						GP2AP020A00F_ADD_MODE);524		set_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);525		break;526	case GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS:527		clear_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &data->flags);528		if (gp2ap020a00f_als_enabled(data))529			break;530		err = gp2ap020a00f_alter_opmode(data,531						GP2AP020A00F_OPMODE_ALS,532						GP2AP020A00F_SUBTRACT_MODE);533		break;534	case GP2AP020A00F_CMD_TRIGGER_IR_EN:535		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)536			return -EBUSY;537		if (!gp2ap020a00f_als_enabled(data))538			err = gp2ap020a00f_alter_opmode(data,539						GP2AP020A00F_OPMODE_ALS,540						GP2AP020A00F_ADD_MODE);541		set_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);542		break;543	case GP2AP020A00F_CMD_TRIGGER_IR_DIS:544		clear_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &data->flags);545		if (gp2ap020a00f_als_enabled(data))546			break;547		err = gp2ap020a00f_alter_opmode(data,548						GP2AP020A00F_OPMODE_ALS,549						GP2AP020A00F_SUBTRACT_MODE);550		break;551	case GP2AP020A00F_CMD_TRIGGER_PROX_EN:552		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)553			return -EBUSY;554		err = gp2ap020a00f_alter_opmode(data,555						GP2AP020A00F_OPMODE_PS,556						GP2AP020A00F_ADD_MODE);557		set_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);558		break;559	case GP2AP020A00F_CMD_TRIGGER_PROX_DIS:560		clear_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &data->flags);561		err = gp2ap020a00f_alter_opmode(data,562						GP2AP020A00F_OPMODE_PS,563						GP2AP020A00F_SUBTRACT_MODE);564		break;565	case GP2AP020A00F_CMD_ALS_HIGH_EV_EN:566		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))567			return 0;568		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)569			return -EBUSY;570		if (!gp2ap020a00f_als_enabled(data)) {571			err = gp2ap020a00f_alter_opmode(data,572						GP2AP020A00F_OPMODE_ALS,573						GP2AP020A00F_ADD_MODE);574			if (err < 0)575				return err;576		}577		set_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);578		err =  gp2ap020a00f_write_event_threshold(data,579					GP2AP020A00F_THRESH_TH, true);580		break;581	case GP2AP020A00F_CMD_ALS_HIGH_EV_DIS:582		if (!test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags))583			return 0;584		clear_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags);585		if (!gp2ap020a00f_als_enabled(data)) {586			err = gp2ap020a00f_alter_opmode(data,587						GP2AP020A00F_OPMODE_ALS,588						GP2AP020A00F_SUBTRACT_MODE);589			if (err < 0)590				return err;591		}592		err =  gp2ap020a00f_write_event_threshold(data,593					GP2AP020A00F_THRESH_TH, false);594		break;595	case GP2AP020A00F_CMD_ALS_LOW_EV_EN:596		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))597			return 0;598		if (data->cur_opmode == GP2AP020A00F_OPMODE_PROX_DETECT)599			return -EBUSY;600		if (!gp2ap020a00f_als_enabled(data)) {601			err = gp2ap020a00f_alter_opmode(data,602						GP2AP020A00F_OPMODE_ALS,603						GP2AP020A00F_ADD_MODE);604			if (err < 0)605				return err;606		}607		set_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);608		err =  gp2ap020a00f_write_event_threshold(data,609					GP2AP020A00F_THRESH_TL, true);610		break;611	case GP2AP020A00F_CMD_ALS_LOW_EV_DIS:612		if (!test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags))613			return 0;614		clear_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags);615		if (!gp2ap020a00f_als_enabled(data)) {616			err = gp2ap020a00f_alter_opmode(data,617						GP2AP020A00F_OPMODE_ALS,618						GP2AP020A00F_SUBTRACT_MODE);619			if (err < 0)620				return err;621		}622		err =  gp2ap020a00f_write_event_threshold(data,623					GP2AP020A00F_THRESH_TL, false);624		break;625	case GP2AP020A00F_CMD_PROX_HIGH_EV_EN:626		if (test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))627			return 0;628		if (gp2ap020a00f_als_enabled(data) ||629		    data->cur_opmode == GP2AP020A00F_OPMODE_PS)630			return -EBUSY;631		if (!gp2ap020a00f_prox_detect_enabled(data)) {632			err = gp2ap020a00f_set_operation_mode(data,633					GP2AP020A00F_OPMODE_PROX_DETECT);634			if (err < 0)635				return err;636		}637		set_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);638		err =  gp2ap020a00f_write_event_threshold(data,639					GP2AP020A00F_THRESH_PH, true);640		break;641	case GP2AP020A00F_CMD_PROX_HIGH_EV_DIS:642		if (!test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags))643			return 0;644		clear_bit(GP2AP020A00F_FLAG_PROX_RISING_EV, &data->flags);645		err = gp2ap020a00f_set_operation_mode(data,646					GP2AP020A00F_OPMODE_SHUTDOWN);647		if (err < 0)648			return err;649		err =  gp2ap020a00f_write_event_threshold(data,650					GP2AP020A00F_THRESH_PH, false);651		break;652	case GP2AP020A00F_CMD_PROX_LOW_EV_EN:653		if (test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))654			return 0;655		if (gp2ap020a00f_als_enabled(data) ||656		    data->cur_opmode == GP2AP020A00F_OPMODE_PS)657			return -EBUSY;658		if (!gp2ap020a00f_prox_detect_enabled(data)) {659			err = gp2ap020a00f_set_operation_mode(data,660					GP2AP020A00F_OPMODE_PROX_DETECT);661			if (err < 0)662				return err;663		}664		set_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);665		err =  gp2ap020a00f_write_event_threshold(data,666					GP2AP020A00F_THRESH_PL, true);667		break;668	case GP2AP020A00F_CMD_PROX_LOW_EV_DIS:669		if (!test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags))670			return 0;671		clear_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV, &data->flags);672		err = gp2ap020a00f_set_operation_mode(data,673					GP2AP020A00F_OPMODE_SHUTDOWN);674		if (err < 0)675			return err;676		err =  gp2ap020a00f_write_event_threshold(data,677					GP2AP020A00F_THRESH_PL, false);678		break;679	}680 681	return err;682}683 684static int wait_conversion_complete_irq(struct gp2ap020a00f_data *data)685{686	int ret;687 688	ret = wait_event_timeout(data->data_ready_queue,689				 test_bit(GP2AP020A00F_FLAG_DATA_READY,690					  &data->flags),691				 GP2AP020A00F_DATA_READY_TIMEOUT);692	clear_bit(GP2AP020A00F_FLAG_DATA_READY, &data->flags);693 694	return ret > 0 ? 0 : -ETIME;695}696 697static int gp2ap020a00f_read_output(struct gp2ap020a00f_data *data,698					unsigned int output_reg, int *val)699{700	u8 reg_buf[2];701	int err;702 703	err = wait_conversion_complete_irq(data);704	if (err < 0)705		dev_dbg(&data->client->dev, "data ready timeout\n");706 707	err = regmap_bulk_read(data->regmap, output_reg, reg_buf, 2);708	if (err < 0)709		return err;710 711	*val = le16_to_cpup((__le16 *)reg_buf);712 713	return err;714}715 716static bool gp2ap020a00f_adjust_lux_mode(struct gp2ap020a00f_data *data,717				 int output_val)718{719	u8 new_range = 0xff;720	int err;721 722	if (!test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags)) {723		if (output_val > 16000) {724			set_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags);725			new_range = GP2AP020A00F_RANGE_A_x128;726		}727	} else {728		if (output_val < 1000) {729			clear_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags);730			new_range = GP2AP020A00F_RANGE_A_x8;731		}732	}733 734	if (new_range != 0xff) {735		/* Clear als threshold registers to avoid spurious736		 * events caused by lux mode transition.737		 */738		err =  gp2ap020a00f_write_event_threshold(data,739					GP2AP020A00F_THRESH_TH, false);740		if (err < 0) {741			dev_err(&data->client->dev,742				"Clearing als threshold register failed.\n");743			return false;744		}745 746		err =  gp2ap020a00f_write_event_threshold(data,747					GP2AP020A00F_THRESH_TL, false);748		if (err < 0) {749			dev_err(&data->client->dev,750				"Clearing als threshold register failed.\n");751			return false;752		}753 754		/* Change lux mode */755		err = regmap_update_bits(data->regmap,756			GP2AP020A00F_OP_REG,757			GP2AP020A00F_OP3_MASK,758			GP2AP020A00F_OP3_SHUTDOWN);759 760		if (err < 0) {761			dev_err(&data->client->dev,762				"Shutting down the device failed.\n");763			return false;764		}765 766		err = regmap_update_bits(data->regmap,767			GP2AP020A00F_ALS_REG,768			GP2AP020A00F_RANGE_A_MASK,769			new_range);770 771		if (err < 0) {772			dev_err(&data->client->dev,773				"Adjusting device lux mode failed.\n");774			return false;775		}776 777		err = regmap_update_bits(data->regmap,778			GP2AP020A00F_OP_REG,779			GP2AP020A00F_OP3_MASK,780			GP2AP020A00F_OP3_OPERATION);781 782		if (err < 0) {783			dev_err(&data->client->dev,784				"Powering up the device failed.\n");785			return false;786		}787 788		/* Adjust als threshold register values to the new lux mode */789		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &data->flags)) {790			err =  gp2ap020a00f_write_event_threshold(data,791					GP2AP020A00F_THRESH_TH, true);792			if (err < 0) {793				dev_err(&data->client->dev,794				"Adjusting als threshold value failed.\n");795				return false;796			}797		}798 799		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &data->flags)) {800			err =  gp2ap020a00f_write_event_threshold(data,801					GP2AP020A00F_THRESH_TL, true);802			if (err < 0) {803				dev_err(&data->client->dev,804				"Adjusting als threshold value failed.\n");805				return false;806			}807		}808 809		return true;810	}811 812	return false;813}814 815static void gp2ap020a00f_output_to_lux(struct gp2ap020a00f_data *data,816						int *output_val)817{818	if (test_bit(GP2AP020A00F_FLAG_LUX_MODE_HI, &data->flags))819		*output_val *= 16;820}821 822static void gp2ap020a00f_iio_trigger_work(struct irq_work *work)823{824	struct gp2ap020a00f_data *data =825		container_of(work, struct gp2ap020a00f_data, work);826 827	iio_trigger_poll(data->trig);828}829 830static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data)831{832	struct iio_dev *indio_dev = data;833	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);834	unsigned int op_reg_val;835	int ret;836 837	/* Read interrupt flags */838	ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG, &op_reg_val);839	if (ret < 0)840		return IRQ_HANDLED;841 842	if (gp2ap020a00f_prox_detect_enabled(priv)) {843		if (op_reg_val & GP2AP020A00F_PROX_DETECT) {844			iio_push_event(indio_dev,845			       IIO_UNMOD_EVENT_CODE(846				    IIO_PROXIMITY,847				    GP2AP020A00F_SCAN_MODE_PROXIMITY,848				    IIO_EV_TYPE_ROC,849				    IIO_EV_DIR_RISING),850			       iio_get_time_ns(indio_dev));851		} else {852			iio_push_event(indio_dev,853			       IIO_UNMOD_EVENT_CODE(854				    IIO_PROXIMITY,855				    GP2AP020A00F_SCAN_MODE_PROXIMITY,856				    IIO_EV_TYPE_ROC,857				    IIO_EV_DIR_FALLING),858			       iio_get_time_ns(indio_dev));859		}860	}861 862	return IRQ_HANDLED;863}864 865static irqreturn_t gp2ap020a00f_thresh_event_handler(int irq, void *data)866{867	struct iio_dev *indio_dev = data;868	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);869	u8 op_reg_flags, d0_reg_buf[2];870	unsigned int output_val, op_reg_val;871	int thresh_val_id, ret;872 873	/* Read interrupt flags */874	ret = regmap_read(priv->regmap, GP2AP020A00F_OP_REG,875							&op_reg_val);876	if (ret < 0)877		goto done;878 879	op_reg_flags = op_reg_val & (GP2AP020A00F_FLAG_A | GP2AP020A00F_FLAG_P880					| GP2AP020A00F_PROX_DETECT);881 882	op_reg_val &= (~GP2AP020A00F_FLAG_A & ~GP2AP020A00F_FLAG_P883					& ~GP2AP020A00F_PROX_DETECT);884 885	/* Clear interrupt flags (if not in INTTYPE_PULSE mode) */886	if (priv->cur_opmode != GP2AP020A00F_OPMODE_PROX_DETECT) {887		ret = regmap_write(priv->regmap, GP2AP020A00F_OP_REG,888								op_reg_val);889		if (ret < 0)890			goto done;891	}892 893	if (op_reg_flags & GP2AP020A00F_FLAG_A) {894		/* Check D0 register to assess if the lux mode895		 * transition is required.896		 */897		ret = regmap_bulk_read(priv->regmap, GP2AP020A00F_D0_L_REG,898							d0_reg_buf, 2);899		if (ret < 0)900			goto done;901 902		output_val = le16_to_cpup((__le16 *)d0_reg_buf);903 904		if (gp2ap020a00f_adjust_lux_mode(priv, output_val))905			goto done;906 907		gp2ap020a00f_output_to_lux(priv, &output_val);908 909		/*910		 * We need to check output value to distinguish911		 * between high and low ambient light threshold event.912		 */913		if (test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV, &priv->flags)) {914			thresh_val_id =915			    GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TH_L_REG);916			if (output_val > priv->thresh_val[thresh_val_id])917				iio_push_event(indio_dev,918				       IIO_MOD_EVENT_CODE(919					    IIO_LIGHT,920					    GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,921					    IIO_MOD_LIGHT_CLEAR,922					    IIO_EV_TYPE_THRESH,923					    IIO_EV_DIR_RISING),924				       iio_get_time_ns(indio_dev));925		}926 927		if (test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV, &priv->flags)) {928			thresh_val_id =929			    GP2AP020A00F_THRESH_VAL_ID(GP2AP020A00F_TL_L_REG);930			if (output_val < priv->thresh_val[thresh_val_id])931				iio_push_event(indio_dev,932				       IIO_MOD_EVENT_CODE(933					    IIO_LIGHT,934					    GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,935					    IIO_MOD_LIGHT_CLEAR,936					    IIO_EV_TYPE_THRESH,937					    IIO_EV_DIR_FALLING),938				       iio_get_time_ns(indio_dev));939		}940	}941 942	if (priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_CLEAR ||943	    priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_IR ||944	    priv->cur_opmode == GP2AP020A00F_OPMODE_READ_RAW_PROXIMITY) {945		set_bit(GP2AP020A00F_FLAG_DATA_READY, &priv->flags);946		wake_up(&priv->data_ready_queue);947		goto done;948	}949 950	if (test_bit(GP2AP020A00F_FLAG_ALS_CLEAR_TRIGGER, &priv->flags) ||951	    test_bit(GP2AP020A00F_FLAG_ALS_IR_TRIGGER, &priv->flags) ||952	    test_bit(GP2AP020A00F_FLAG_PROX_TRIGGER, &priv->flags))953		/* This fires off the trigger. */954		irq_work_queue(&priv->work);955 956done:957	return IRQ_HANDLED;958}959 960static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)961{962	struct iio_poll_func *pf = data;963	struct iio_dev *indio_dev = pf->indio_dev;964	struct gp2ap020a00f_data *priv = iio_priv(indio_dev);965	size_t d_size = 0;966	int i, out_val, ret;967 968	iio_for_each_active_channel(indio_dev, i) {969		ret = regmap_bulk_read(priv->regmap,970				GP2AP020A00F_DATA_REG(i),971				&priv->buffer[d_size], 2);972		if (ret < 0)973			goto done;974 975		if (i == GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR ||976		    i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) {977			out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]);978			gp2ap020a00f_output_to_lux(priv, &out_val);979 980			put_unaligned_le32(out_val, &priv->buffer[d_size]);981			d_size += 4;982		} else {983			d_size += 2;984		}985	}986 987	iio_push_to_buffers_with_timestamp(indio_dev, priv->buffer,988		pf->timestamp);989done:990	iio_trigger_notify_done(indio_dev->trig);991 992	return IRQ_HANDLED;993}994 995static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,996					     enum iio_event_direction event_dir)997{998	switch (chan->type) {999	case IIO_PROXIMITY:1000		if (event_dir == IIO_EV_DIR_RISING)1001			return GP2AP020A00F_PH_L_REG;1002		else1003			return GP2AP020A00F_PL_L_REG;1004	case IIO_LIGHT:1005		if (event_dir == IIO_EV_DIR_RISING)1006			return GP2AP020A00F_TH_L_REG;1007		else1008			return GP2AP020A00F_TL_L_REG;1009	default:1010		break;1011	}1012 1013	return -EINVAL;1014}1015 1016static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,1017					const struct iio_chan_spec *chan,1018					enum iio_event_type type,1019					enum iio_event_direction dir,1020					enum iio_event_info info,1021					int val, int val2)1022{1023	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1024	bool event_en = false;1025	u8 thresh_val_id;1026	u8 thresh_reg_l;1027	int err = 0;1028 1029	mutex_lock(&data->lock);1030 1031	thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);1032	thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l);1033 1034	if (thresh_val_id > GP2AP020A00F_THRESH_PH) {1035		err = -EINVAL;1036		goto error_unlock;1037	}1038 1039	switch (thresh_reg_l) {1040	case GP2AP020A00F_TH_L_REG:1041		event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,1042							&data->flags);1043		break;1044	case GP2AP020A00F_TL_L_REG:1045		event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,1046							&data->flags);1047		break;1048	case GP2AP020A00F_PH_L_REG:1049		if (val == 0) {1050			err = -EINVAL;1051			goto error_unlock;1052		}1053		event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,1054							&data->flags);1055		break;1056	case GP2AP020A00F_PL_L_REG:1057		if (val == 0) {1058			err = -EINVAL;1059			goto error_unlock;1060		}1061		event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,1062							&data->flags);1063		break;1064	}1065 1066	data->thresh_val[thresh_val_id] = val;1067	err =  gp2ap020a00f_write_event_threshold(data, thresh_val_id,1068							event_en);1069error_unlock:1070	mutex_unlock(&data->lock);1071 1072	return err;1073}1074 1075static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,1076				       const struct iio_chan_spec *chan,1077				       enum iio_event_type type,1078				       enum iio_event_direction dir,1079				       enum iio_event_info info,1080				       int *val, int *val2)1081{1082	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1083	u8 thresh_reg_l;1084	int err = IIO_VAL_INT;1085 1086	mutex_lock(&data->lock);1087 1088	thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);1089 1090	if (thresh_reg_l > GP2AP020A00F_PH_L_REG) {1091		err = -EINVAL;1092		goto error_unlock;1093	}1094 1095	*val = data->thresh_val[GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l)];1096 1097error_unlock:1098	mutex_unlock(&data->lock);1099 1100	return err;1101}1102 1103static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev,1104						int state)1105{1106	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1107	enum gp2ap020a00f_cmd cmd_high_ev, cmd_low_ev;1108	int err;1109 1110	cmd_high_ev = state ? GP2AP020A00F_CMD_PROX_HIGH_EV_EN :1111			      GP2AP020A00F_CMD_PROX_HIGH_EV_DIS;1112	cmd_low_ev = state ? GP2AP020A00F_CMD_PROX_LOW_EV_EN :1113			     GP2AP020A00F_CMD_PROX_LOW_EV_DIS;1114 1115	/*1116	 * In order to enable proximity detection feature in the device1117	 * both high and low threshold registers have to be written1118	 * with different values, greater than zero.1119	 */1120	if (state) {1121		if (data->thresh_val[GP2AP020A00F_THRESH_PL] == 0)1122			return -EINVAL;1123 1124		if (data->thresh_val[GP2AP020A00F_THRESH_PH] == 0)1125			return -EINVAL;1126	}1127 1128	err = gp2ap020a00f_exec_cmd(data, cmd_high_ev);1129	if (err < 0)1130		return err;1131 1132	err = gp2ap020a00f_exec_cmd(data, cmd_low_ev);1133	if (err < 0)1134		return err;1135 1136	free_irq(data->client->irq, indio_dev);1137 1138	if (state)1139		err = request_threaded_irq(data->client->irq, NULL,1140					   &gp2ap020a00f_prox_sensing_handler,1141					   IRQF_TRIGGER_RISING |1142					   IRQF_TRIGGER_FALLING |1143					   IRQF_ONESHOT,1144					   "gp2ap020a00f_prox_sensing",1145					   indio_dev);1146	else {1147		err = request_threaded_irq(data->client->irq, NULL,1148					   &gp2ap020a00f_thresh_event_handler,1149					   IRQF_TRIGGER_FALLING |1150					   IRQF_ONESHOT,1151					   "gp2ap020a00f_thresh_event",1152					   indio_dev);1153	}1154 1155	return err;1156}1157 1158static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,1159					   const struct iio_chan_spec *chan,1160					   enum iio_event_type type,1161					   enum iio_event_direction dir,1162					   int state)1163{1164	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1165	enum gp2ap020a00f_cmd cmd;1166	int err;1167 1168	mutex_lock(&data->lock);1169 1170	switch (chan->type) {1171	case IIO_PROXIMITY:1172		err = gp2ap020a00f_write_prox_event_config(indio_dev, state);1173		break;1174	case IIO_LIGHT:1175		if (dir == IIO_EV_DIR_RISING) {1176			cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN :1177				      GP2AP020A00F_CMD_ALS_HIGH_EV_DIS;1178			err = gp2ap020a00f_exec_cmd(data, cmd);1179		} else {1180			cmd = state ? GP2AP020A00F_CMD_ALS_LOW_EV_EN :1181				      GP2AP020A00F_CMD_ALS_LOW_EV_DIS;1182			err = gp2ap020a00f_exec_cmd(data, cmd);1183		}1184		break;1185	default:1186		err = -EINVAL;1187	}1188 1189	mutex_unlock(&data->lock);1190 1191	return err;1192}1193 1194static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,1195					   const struct iio_chan_spec *chan,1196					   enum iio_event_type type,1197					   enum iio_event_direction dir)1198{1199	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1200	int event_en = 0;1201 1202	mutex_lock(&data->lock);1203 1204	switch (chan->type) {1205	case IIO_PROXIMITY:1206		if (dir == IIO_EV_DIR_RISING)1207			event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,1208								&data->flags);1209		else1210			event_en = test_bit(GP2AP020A00F_FLAG_PROX_FALLING_EV,1211								&data->flags);1212		break;1213	case IIO_LIGHT:1214		if (dir == IIO_EV_DIR_RISING)1215			event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,1216								&data->flags);1217		else1218			event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,1219								&data->flags);1220		break;1221	default:1222		event_en = -EINVAL;1223		break;1224	}1225 1226	mutex_unlock(&data->lock);1227 1228	return event_en;1229}1230 1231static int gp2ap020a00f_read_channel(struct gp2ap020a00f_data *data,1232				struct iio_chan_spec const *chan, int *val)1233{1234	enum gp2ap020a00f_cmd cmd;1235	int err;1236 1237	switch (chan->scan_index) {1238	case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:1239		cmd = GP2AP020A00F_CMD_READ_RAW_CLEAR;1240		break;1241	case GP2AP020A00F_SCAN_MODE_LIGHT_IR:1242		cmd = GP2AP020A00F_CMD_READ_RAW_IR;1243		break;1244	case GP2AP020A00F_SCAN_MODE_PROXIMITY:1245		cmd = GP2AP020A00F_CMD_READ_RAW_PROXIMITY;1246		break;1247	default:1248		return -EINVAL;1249	}1250 1251	err = gp2ap020a00f_exec_cmd(data, cmd);1252	if (err < 0) {1253		dev_err(&data->client->dev,1254			"gp2ap020a00f_exec_cmd failed\n");1255		goto error_ret;1256	}1257 1258	err = gp2ap020a00f_read_output(data, chan->address, val);1259	if (err < 0)1260		dev_err(&data->client->dev,1261			"gp2ap020a00f_read_output failed\n");1262 1263	err = gp2ap020a00f_set_operation_mode(data,1264					GP2AP020A00F_OPMODE_SHUTDOWN);1265	if (err < 0)1266		dev_err(&data->client->dev,1267			"Failed to shut down the device.\n");1268 1269	if (cmd == GP2AP020A00F_CMD_READ_RAW_CLEAR ||1270	    cmd == GP2AP020A00F_CMD_READ_RAW_IR)1271		gp2ap020a00f_output_to_lux(data, val);1272 1273error_ret:1274	return err;1275}1276 1277static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,1278			   struct iio_chan_spec const *chan,1279			   int *val, int *val2,1280			   long mask)1281{1282	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1283	int err = -EINVAL;1284 1285	if (mask == IIO_CHAN_INFO_RAW) {1286		err = iio_device_claim_direct_mode(indio_dev);1287		if (err)1288			return err;1289 1290		err = gp2ap020a00f_read_channel(data, chan, val);1291		iio_device_release_direct_mode(indio_dev);1292	}1293	return err < 0 ? err : IIO_VAL_INT;1294}1295 1296static const struct iio_event_spec gp2ap020a00f_event_spec_light[] = {1297	{1298		.type = IIO_EV_TYPE_THRESH,1299		.dir = IIO_EV_DIR_RISING,1300		.mask_separate = BIT(IIO_EV_INFO_VALUE) |1301			BIT(IIO_EV_INFO_ENABLE),1302	}, {1303		.type = IIO_EV_TYPE_THRESH,1304		.dir = IIO_EV_DIR_FALLING,1305		.mask_separate = BIT(IIO_EV_INFO_VALUE) |1306			BIT(IIO_EV_INFO_ENABLE),1307	},1308};1309 1310static const struct iio_event_spec gp2ap020a00f_event_spec_prox[] = {1311	{1312		.type = IIO_EV_TYPE_ROC,1313		.dir = IIO_EV_DIR_RISING,1314		.mask_separate = BIT(IIO_EV_INFO_VALUE) |1315			BIT(IIO_EV_INFO_ENABLE),1316	}, {1317		.type = IIO_EV_TYPE_ROC,1318		.dir = IIO_EV_DIR_FALLING,1319		.mask_separate = BIT(IIO_EV_INFO_VALUE) |1320			BIT(IIO_EV_INFO_ENABLE),1321	},1322};1323 1324static const struct iio_chan_spec gp2ap020a00f_channels[] = {1325	{1326		.type = IIO_LIGHT,1327		.channel2 = IIO_MOD_LIGHT_CLEAR,1328		.modified = 1,1329		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),1330		.scan_type = {1331			.sign = 'u',1332			.realbits = 24,1333			.shift = 0,1334			.storagebits = 32,1335			.endianness = IIO_LE,1336		},1337		.scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,1338		.address = GP2AP020A00F_D0_L_REG,1339		.event_spec = gp2ap020a00f_event_spec_light,1340		.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_light),1341	},1342	{1343		.type = IIO_LIGHT,1344		.channel2 = IIO_MOD_LIGHT_IR,1345		.modified = 1,1346		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),1347		.scan_type = {1348			.sign = 'u',1349			.realbits = 24,1350			.shift = 0,1351			.storagebits = 32,1352			.endianness = IIO_LE,1353		},1354		.scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_IR,1355		.address = GP2AP020A00F_D1_L_REG,1356	},1357	{1358		.type = IIO_PROXIMITY,1359		.modified = 0,1360		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),1361		.scan_type = {1362			.sign = 'u',1363			.realbits = 16,1364			.shift = 0,1365			.storagebits = 16,1366			.endianness = IIO_LE,1367		},1368		.scan_index = GP2AP020A00F_SCAN_MODE_PROXIMITY,1369		.address = GP2AP020A00F_D2_L_REG,1370		.event_spec = gp2ap020a00f_event_spec_prox,1371		.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_prox),1372	},1373	IIO_CHAN_SOFT_TIMESTAMP(GP2AP020A00F_CHAN_TIMESTAMP),1374};1375 1376static const struct iio_info gp2ap020a00f_info = {1377	.read_raw = &gp2ap020a00f_read_raw,1378	.read_event_value = &gp2ap020a00f_read_event_val,1379	.read_event_config = &gp2ap020a00f_read_event_config,1380	.write_event_value = &gp2ap020a00f_write_event_val,1381	.write_event_config = &gp2ap020a00f_write_event_config,1382};1383 1384static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)1385{1386	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1387	int i, err = 0;1388 1389	mutex_lock(&data->lock);1390 1391	/*1392	 * Enable triggers according to the scan_mask. Enabling either1393	 * LIGHT_CLEAR or LIGHT_IR scan mode results in enabling ALS1394	 * module in the device, which generates samples in both D0 (clear)1395	 * and D1 (ir) registers. As the two registers are bound to the1396	 * two separate IIO channels they are treated in the driver logic1397	 * as if they were controlled independently.1398	 */1399	iio_for_each_active_channel(indio_dev, i) {1400		switch (i) {1401		case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:1402			err = gp2ap020a00f_exec_cmd(data,1403					GP2AP020A00F_CMD_TRIGGER_CLEAR_EN);1404			break;1405		case GP2AP020A00F_SCAN_MODE_LIGHT_IR:1406			err = gp2ap020a00f_exec_cmd(data,1407					GP2AP020A00F_CMD_TRIGGER_IR_EN);1408			break;1409		case GP2AP020A00F_SCAN_MODE_PROXIMITY:1410			err = gp2ap020a00f_exec_cmd(data,1411					GP2AP020A00F_CMD_TRIGGER_PROX_EN);1412			break;1413		}1414	}1415 1416	if (err < 0)1417		goto error_unlock;1418 1419	data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);1420	if (!data->buffer)1421		err = -ENOMEM;1422 1423error_unlock:1424	mutex_unlock(&data->lock);1425 1426	return err;1427}1428 1429static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)1430{1431	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1432	int i, err = 0;1433 1434	mutex_lock(&data->lock);1435 1436	iio_for_each_active_channel(indio_dev, i) {1437		switch (i) {1438		case GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR:1439			err = gp2ap020a00f_exec_cmd(data,1440					GP2AP020A00F_CMD_TRIGGER_CLEAR_DIS);1441			break;1442		case GP2AP020A00F_SCAN_MODE_LIGHT_IR:1443			err = gp2ap020a00f_exec_cmd(data,1444					GP2AP020A00F_CMD_TRIGGER_IR_DIS);1445			break;1446		case GP2AP020A00F_SCAN_MODE_PROXIMITY:1447			err = gp2ap020a00f_exec_cmd(data,1448					GP2AP020A00F_CMD_TRIGGER_PROX_DIS);1449			break;1450		}1451	}1452 1453	if (err == 0)1454		kfree(data->buffer);1455 1456	mutex_unlock(&data->lock);1457 1458	return err;1459}1460 1461static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {1462	.postenable = &gp2ap020a00f_buffer_postenable,1463	.predisable = &gp2ap020a00f_buffer_predisable,1464};1465 1466static int gp2ap020a00f_probe(struct i2c_client *client)1467{1468	const struct i2c_device_id *id = i2c_client_get_device_id(client);1469	struct gp2ap020a00f_data *data;1470	struct iio_dev *indio_dev;1471	struct regmap *regmap;1472	int err;1473 1474	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));1475	if (!indio_dev)1476		return -ENOMEM;1477 1478	data = iio_priv(indio_dev);1479 1480	data->vled_reg = devm_regulator_get(&client->dev, "vled");1481	if (IS_ERR(data->vled_reg))1482		return PTR_ERR(data->vled_reg);1483 1484	err = regulator_enable(data->vled_reg);1485	if (err)1486		return err;1487 1488	regmap = devm_regmap_init_i2c(client, &gp2ap020a00f_regmap_config);1489	if (IS_ERR(regmap)) {1490		dev_err(&client->dev, "Regmap initialization failed.\n");1491		err = PTR_ERR(regmap);1492		goto error_regulator_disable;1493	}1494 1495	/* Initialize device registers */1496	err = regmap_bulk_write(regmap, GP2AP020A00F_OP_REG,1497			gp2ap020a00f_reg_init_tab,1498			ARRAY_SIZE(gp2ap020a00f_reg_init_tab));1499 1500	if (err < 0) {1501		dev_err(&client->dev, "Device initialization failed.\n");1502		goto error_regulator_disable;1503	}1504 1505	i2c_set_clientdata(client, indio_dev);1506 1507	data->client = client;1508	data->cur_opmode = GP2AP020A00F_OPMODE_SHUTDOWN;1509	data->regmap = regmap;1510	init_waitqueue_head(&data->data_ready_queue);1511 1512	mutex_init(&data->lock);1513	indio_dev->channels = gp2ap020a00f_channels;1514	indio_dev->num_channels = ARRAY_SIZE(gp2ap020a00f_channels);1515	indio_dev->info = &gp2ap020a00f_info;1516	indio_dev->name = id->name;1517	indio_dev->modes = INDIO_DIRECT_MODE;1518 1519	/* Allocate buffer */1520	err = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,1521		&gp2ap020a00f_trigger_handler, &gp2ap020a00f_buffer_setup_ops);1522	if (err < 0)1523		goto error_regulator_disable;1524 1525	/* Allocate trigger */1526	data->trig = devm_iio_trigger_alloc(&client->dev, "%s-trigger",1527							indio_dev->name);1528	if (data->trig == NULL) {1529		err = -ENOMEM;1530		dev_err(&indio_dev->dev, "Failed to allocate iio trigger.\n");1531		goto error_uninit_buffer;1532	}1533 1534	/* This needs to be requested here for read_raw calls to work. */1535	err = request_threaded_irq(client->irq, NULL,1536				   &gp2ap020a00f_thresh_event_handler,1537				   IRQF_TRIGGER_FALLING |1538				   IRQF_ONESHOT,1539				   "gp2ap020a00f_als_event",1540				   indio_dev);1541	if (err < 0) {1542		dev_err(&client->dev, "Irq request failed.\n");1543		goto error_uninit_buffer;1544	}1545 1546	init_irq_work(&data->work, gp2ap020a00f_iio_trigger_work);1547 1548	err = iio_trigger_register(data->trig);1549	if (err < 0) {1550		dev_err(&client->dev, "Failed to register iio trigger.\n");1551		goto error_free_irq;1552	}1553 1554	err = iio_device_register(indio_dev);1555	if (err < 0)1556		goto error_trigger_unregister;1557 1558	return 0;1559 1560error_trigger_unregister:1561	iio_trigger_unregister(data->trig);1562error_free_irq:1563	free_irq(client->irq, indio_dev);1564error_uninit_buffer:1565	iio_triggered_buffer_cleanup(indio_dev);1566error_regulator_disable:1567	regulator_disable(data->vled_reg);1568 1569	return err;1570}1571 1572static void gp2ap020a00f_remove(struct i2c_client *client)1573{1574	struct iio_dev *indio_dev = i2c_get_clientdata(client);1575	struct gp2ap020a00f_data *data = iio_priv(indio_dev);1576	int err;1577 1578	err = gp2ap020a00f_set_operation_mode(data,1579					GP2AP020A00F_OPMODE_SHUTDOWN);1580	if (err < 0)1581		dev_err(&indio_dev->dev, "Failed to power off the device.\n");1582 1583	iio_device_unregister(indio_dev);1584	iio_trigger_unregister(data->trig);1585	free_irq(client->irq, indio_dev);1586	iio_triggered_buffer_cleanup(indio_dev);1587	regulator_disable(data->vled_reg);1588}1589 1590static const struct i2c_device_id gp2ap020a00f_id[] = {1591	{ GP2A_I2C_NAME },1592	{ }1593};1594 1595MODULE_DEVICE_TABLE(i2c, gp2ap020a00f_id);1596 1597static const struct of_device_id gp2ap020a00f_of_match[] = {1598	{ .compatible = "sharp,gp2ap020a00f" },1599	{ }1600};1601MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match);1602 1603static struct i2c_driver gp2ap020a00f_driver = {1604	.driver = {1605		.name	= GP2A_I2C_NAME,1606		.of_match_table = gp2ap020a00f_of_match,1607	},1608	.probe		= gp2ap020a00f_probe,1609	.remove		= gp2ap020a00f_remove,1610	.id_table	= gp2ap020a00f_id,1611};1612 1613module_i2c_driver(gp2ap020a00f_driver);1614 1615MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");1616MODULE_DESCRIPTION("Sharp GP2AP020A00F Proximity/ALS sensor driver");1617MODULE_LICENSE("GPL v2");1618