18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
48c2ecf20Sopenharmony_ci * Chip is combined proximity and ambient light sensor.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/mutex.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_data/bh1770glc.h>
178c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
198c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include <linux/wait.h>
228c2ecf20Sopenharmony_ci#include <linux/slab.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define BH1770_ALS_CONTROL	0x80 /* ALS operation mode control */
258c2ecf20Sopenharmony_ci#define BH1770_PS_CONTROL	0x81 /* PS operation mode control */
268c2ecf20Sopenharmony_ci#define BH1770_I_LED		0x82 /* active LED and LED1, LED2 current */
278c2ecf20Sopenharmony_ci#define BH1770_I_LED3		0x83 /* LED3 current setting */
288c2ecf20Sopenharmony_ci#define BH1770_ALS_PS_MEAS	0x84 /* Forced mode trigger */
298c2ecf20Sopenharmony_ci#define BH1770_PS_MEAS_RATE	0x85 /* PS meas. rate at stand alone mode */
308c2ecf20Sopenharmony_ci#define BH1770_ALS_MEAS_RATE	0x86 /* ALS meas. rate at stand alone mode */
318c2ecf20Sopenharmony_ci#define BH1770_PART_ID		0x8a /* Part number and revision ID */
328c2ecf20Sopenharmony_ci#define BH1770_MANUFACT_ID	0x8b /* Manufacturerer ID */
338c2ecf20Sopenharmony_ci#define BH1770_ALS_DATA_0	0x8c /* ALS DATA low byte */
348c2ecf20Sopenharmony_ci#define BH1770_ALS_DATA_1	0x8d /* ALS DATA high byte */
358c2ecf20Sopenharmony_ci#define BH1770_ALS_PS_STATUS	0x8e /* Measurement data and int status */
368c2ecf20Sopenharmony_ci#define BH1770_PS_DATA_LED1	0x8f /* PS data from LED1 */
378c2ecf20Sopenharmony_ci#define BH1770_PS_DATA_LED2	0x90 /* PS data from LED2 */
388c2ecf20Sopenharmony_ci#define BH1770_PS_DATA_LED3	0x91 /* PS data from LED3 */
398c2ecf20Sopenharmony_ci#define BH1770_INTERRUPT	0x92 /* Interrupt setting */
408c2ecf20Sopenharmony_ci#define BH1770_PS_TH_LED1	0x93 /* PS interrupt threshold for LED1 */
418c2ecf20Sopenharmony_ci#define BH1770_PS_TH_LED2	0x94 /* PS interrupt threshold for LED2 */
428c2ecf20Sopenharmony_ci#define BH1770_PS_TH_LED3	0x95 /* PS interrupt threshold for LED3 */
438c2ecf20Sopenharmony_ci#define BH1770_ALS_TH_UP_0	0x96 /* ALS upper threshold low byte */
448c2ecf20Sopenharmony_ci#define BH1770_ALS_TH_UP_1	0x97 /* ALS upper threshold high byte */
458c2ecf20Sopenharmony_ci#define BH1770_ALS_TH_LOW_0	0x98 /* ALS lower threshold low byte */
468c2ecf20Sopenharmony_ci#define BH1770_ALS_TH_LOW_1	0x99 /* ALS lower threshold high byte */
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* MANUFACT_ID */
498c2ecf20Sopenharmony_ci#define BH1770_MANUFACT_ROHM	0x01
508c2ecf20Sopenharmony_ci#define BH1770_MANUFACT_OSRAM	0x03
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* PART_ID */
538c2ecf20Sopenharmony_ci#define BH1770_PART		0x90
548c2ecf20Sopenharmony_ci#define BH1770_PART_MASK	0xf0
558c2ecf20Sopenharmony_ci#define BH1770_REV_MASK		0x0f
568c2ecf20Sopenharmony_ci#define BH1770_REV_SHIFT	0
578c2ecf20Sopenharmony_ci#define BH1770_REV_0		0x00
588c2ecf20Sopenharmony_ci#define BH1770_REV_1		0x01
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* Operating modes for both */
618c2ecf20Sopenharmony_ci#define BH1770_STANDBY		0x00
628c2ecf20Sopenharmony_ci#define BH1770_FORCED		0x02
638c2ecf20Sopenharmony_ci#define BH1770_STANDALONE	0x03
648c2ecf20Sopenharmony_ci#define BH1770_SWRESET		(0x01 << 2)
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define BH1770_PS_TRIG_MEAS	(1 << 0)
678c2ecf20Sopenharmony_ci#define BH1770_ALS_TRIG_MEAS	(1 << 1)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* Interrupt control */
708c2ecf20Sopenharmony_ci#define BH1770_INT_OUTPUT_MODE	(1 << 3) /* 0 = latched */
718c2ecf20Sopenharmony_ci#define BH1770_INT_POLARITY	(1 << 2) /* 1 = active high */
728c2ecf20Sopenharmony_ci#define BH1770_INT_ALS_ENA	(1 << 1)
738c2ecf20Sopenharmony_ci#define BH1770_INT_PS_ENA	(1 << 0)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* Interrupt status */
768c2ecf20Sopenharmony_ci#define BH1770_INT_LED1_DATA	(1 << 0)
778c2ecf20Sopenharmony_ci#define BH1770_INT_LED1_INT	(1 << 1)
788c2ecf20Sopenharmony_ci#define BH1770_INT_LED2_DATA	(1 << 2)
798c2ecf20Sopenharmony_ci#define BH1770_INT_LED2_INT	(1 << 3)
808c2ecf20Sopenharmony_ci#define BH1770_INT_LED3_DATA	(1 << 4)
818c2ecf20Sopenharmony_ci#define BH1770_INT_LED3_INT	(1 << 5)
828c2ecf20Sopenharmony_ci#define BH1770_INT_LEDS_INT	((1 << 1) | (1 << 3) | (1 << 5))
838c2ecf20Sopenharmony_ci#define BH1770_INT_ALS_DATA	(1 << 6)
848c2ecf20Sopenharmony_ci#define BH1770_INT_ALS_INT	(1 << 7)
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Led channels */
878c2ecf20Sopenharmony_ci#define BH1770_LED1		0x00
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define BH1770_DISABLE		0
908c2ecf20Sopenharmony_ci#define BH1770_ENABLE		1
918c2ecf20Sopenharmony_ci#define BH1770_PROX_CHANNELS	1
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define BH1770_LUX_DEFAULT_RATE	1 /* Index to lux rate table */
948c2ecf20Sopenharmony_ci#define BH1770_PROX_DEFAULT_RATE 1 /* Direct HW value =~ 50Hz */
958c2ecf20Sopenharmony_ci#define BH1770_PROX_DEF_RATE_THRESH 6 /* Direct HW value =~ 5 Hz */
968c2ecf20Sopenharmony_ci#define BH1770_STARTUP_DELAY	50
978c2ecf20Sopenharmony_ci#define BH1770_RESET_TIME	10
988c2ecf20Sopenharmony_ci#define BH1770_TIMEOUT		2100 /* Timeout in 2.1 seconds */
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define BH1770_LUX_RANGE	65535
1018c2ecf20Sopenharmony_ci#define BH1770_PROX_RANGE	255
1028c2ecf20Sopenharmony_ci#define BH1770_COEF_SCALER	1024
1038c2ecf20Sopenharmony_ci#define BH1770_CALIB_SCALER	8192
1048c2ecf20Sopenharmony_ci#define BH1770_LUX_NEUTRAL_CALIB_VALUE (1 * BH1770_CALIB_SCALER)
1058c2ecf20Sopenharmony_ci#define BH1770_LUX_DEF_THRES	1000
1068c2ecf20Sopenharmony_ci#define BH1770_PROX_DEF_THRES	70
1078c2ecf20Sopenharmony_ci#define BH1770_PROX_DEF_ABS_THRES   100
1088c2ecf20Sopenharmony_ci#define BH1770_DEFAULT_PERSISTENCE  10
1098c2ecf20Sopenharmony_ci#define BH1770_PROX_MAX_PERSISTENCE 50
1108c2ecf20Sopenharmony_ci#define BH1770_LUX_GA_SCALE	16384
1118c2ecf20Sopenharmony_ci#define BH1770_LUX_CF_SCALE	2048 /* CF ChipFactor */
1128c2ecf20Sopenharmony_ci#define BH1770_NEUTRAL_CF	BH1770_LUX_CF_SCALE
1138c2ecf20Sopenharmony_ci#define BH1770_LUX_CORR_SCALE	4096
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define PROX_ABOVE_THRESHOLD	1
1168c2ecf20Sopenharmony_ci#define PROX_BELOW_THRESHOLD	0
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define PROX_IGNORE_LUX_LIMIT	500
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistruct bh1770_chip {
1218c2ecf20Sopenharmony_ci	struct bh1770_platform_data	*pdata;
1228c2ecf20Sopenharmony_ci	char				chipname[10];
1238c2ecf20Sopenharmony_ci	u8				revision;
1248c2ecf20Sopenharmony_ci	struct i2c_client		*client;
1258c2ecf20Sopenharmony_ci	struct regulator_bulk_data	regs[2];
1268c2ecf20Sopenharmony_ci	struct mutex			mutex; /* avoid parallel access */
1278c2ecf20Sopenharmony_ci	wait_queue_head_t		wait;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	bool			int_mode_prox;
1308c2ecf20Sopenharmony_ci	bool			int_mode_lux;
1318c2ecf20Sopenharmony_ci	struct delayed_work	prox_work;
1328c2ecf20Sopenharmony_ci	u32	lux_cf; /* Chip specific factor */
1338c2ecf20Sopenharmony_ci	u32	lux_ga;
1348c2ecf20Sopenharmony_ci	u32	lux_calib;
1358c2ecf20Sopenharmony_ci	int	lux_rate_index;
1368c2ecf20Sopenharmony_ci	u32	lux_corr;
1378c2ecf20Sopenharmony_ci	u16	lux_data_raw;
1388c2ecf20Sopenharmony_ci	u16	lux_threshold_hi;
1398c2ecf20Sopenharmony_ci	u16	lux_threshold_lo;
1408c2ecf20Sopenharmony_ci	u16	lux_thres_hi_onchip;
1418c2ecf20Sopenharmony_ci	u16	lux_thres_lo_onchip;
1428c2ecf20Sopenharmony_ci	bool	lux_wait_result;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	int	prox_enable_count;
1458c2ecf20Sopenharmony_ci	u16	prox_coef;
1468c2ecf20Sopenharmony_ci	u16	prox_const;
1478c2ecf20Sopenharmony_ci	int	prox_rate;
1488c2ecf20Sopenharmony_ci	int	prox_rate_threshold;
1498c2ecf20Sopenharmony_ci	u8	prox_persistence;
1508c2ecf20Sopenharmony_ci	u8	prox_persistence_counter;
1518c2ecf20Sopenharmony_ci	u8	prox_data;
1528c2ecf20Sopenharmony_ci	u8	prox_threshold;
1538c2ecf20Sopenharmony_ci	u8	prox_threshold_hw;
1548c2ecf20Sopenharmony_ci	bool	prox_force_update;
1558c2ecf20Sopenharmony_ci	u8	prox_abs_thres;
1568c2ecf20Sopenharmony_ci	u8	prox_led;
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic const char reg_vcc[] = "Vcc";
1608c2ecf20Sopenharmony_cistatic const char reg_vleds[] = "Vleds";
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/*
1638c2ecf20Sopenharmony_ci * Supported stand alone rates in ms from chip data sheet
1648c2ecf20Sopenharmony_ci * {10, 20, 30, 40, 70, 100, 200, 500, 1000, 2000};
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cistatic const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2};
1678c2ecf20Sopenharmony_cistatic const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/*
1708c2ecf20Sopenharmony_ci * Supported stand alone rates in ms from chip data sheet
1718c2ecf20Sopenharmony_ci * {100, 200, 500, 1000, 2000};
1728c2ecf20Sopenharmony_ci */
1738c2ecf20Sopenharmony_cistatic const s16 lux_rates_hz[] = {10, 5, 2, 1, 0};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci/*
1768c2ecf20Sopenharmony_ci * interrupt control functions are called while keeping chip->mutex
1778c2ecf20Sopenharmony_ci * excluding module probe / remove
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_cistatic inline int bh1770_lux_interrupt_control(struct bh1770_chip *chip,
1808c2ecf20Sopenharmony_ci					int lux)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	chip->int_mode_lux = lux;
1838c2ecf20Sopenharmony_ci	/* Set interrupt modes, interrupt active low, latched */
1848c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(chip->client,
1858c2ecf20Sopenharmony_ci					BH1770_INTERRUPT,
1868c2ecf20Sopenharmony_ci					(lux << 1) | chip->int_mode_prox);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline int bh1770_prox_interrupt_control(struct bh1770_chip *chip,
1908c2ecf20Sopenharmony_ci					int ps)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	chip->int_mode_prox = ps;
1938c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(chip->client,
1948c2ecf20Sopenharmony_ci					BH1770_INTERRUPT,
1958c2ecf20Sopenharmony_ci					(chip->int_mode_lux << 1) | (ps << 0));
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/* chip->mutex is always kept here */
1998c2ecf20Sopenharmony_cistatic int bh1770_lux_rate(struct bh1770_chip *chip, int rate_index)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	/* sysfs may call this when the chip is powered off */
2028c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(&chip->client->dev))
2038c2ecf20Sopenharmony_ci		return 0;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* Proper proximity response needs fastest lux rate (100ms) */
2068c2ecf20Sopenharmony_ci	if (chip->prox_enable_count)
2078c2ecf20Sopenharmony_ci		rate_index = 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(chip->client,
2108c2ecf20Sopenharmony_ci					BH1770_ALS_MEAS_RATE,
2118c2ecf20Sopenharmony_ci					rate_index);
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic int bh1770_prox_rate(struct bh1770_chip *chip, int mode)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int rate;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	rate = (mode == PROX_ABOVE_THRESHOLD) ?
2198c2ecf20Sopenharmony_ci		chip->prox_rate_threshold : chip->prox_rate;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(chip->client,
2228c2ecf20Sopenharmony_ci					BH1770_PS_MEAS_RATE,
2238c2ecf20Sopenharmony_ci					rate);
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci/* InfraredLED is controlled by the chip during proximity scanning */
2278c2ecf20Sopenharmony_cistatic inline int bh1770_led_cfg(struct bh1770_chip *chip)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	/* LED cfg, current for leds 1 and 2 */
2308c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(chip->client,
2318c2ecf20Sopenharmony_ci					BH1770_I_LED,
2328c2ecf20Sopenharmony_ci					(BH1770_LED1 << 6) |
2338c2ecf20Sopenharmony_ci					(BH1770_LED_5mA << 3) |
2348c2ecf20Sopenharmony_ci					chip->prox_led);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/*
2388c2ecf20Sopenharmony_ci * Following two functions converts raw ps values from HW to normalized
2398c2ecf20Sopenharmony_ci * values. Purpose is to compensate differences between different sensor
2408c2ecf20Sopenharmony_ci * versions and variants so that result means about the same between
2418c2ecf20Sopenharmony_ci * versions.
2428c2ecf20Sopenharmony_ci */
2438c2ecf20Sopenharmony_cistatic inline u8 bh1770_psraw_to_adjusted(struct bh1770_chip *chip, u8 psraw)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	u16 adjusted;
2468c2ecf20Sopenharmony_ci	adjusted = (u16)(((u32)(psraw + chip->prox_const) * chip->prox_coef) /
2478c2ecf20Sopenharmony_ci		BH1770_COEF_SCALER);
2488c2ecf20Sopenharmony_ci	if (adjusted > BH1770_PROX_RANGE)
2498c2ecf20Sopenharmony_ci		adjusted = BH1770_PROX_RANGE;
2508c2ecf20Sopenharmony_ci	return adjusted;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic inline u8 bh1770_psadjusted_to_raw(struct bh1770_chip *chip, u8 ps)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	u16 raw;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	raw = (((u32)ps * BH1770_COEF_SCALER) / chip->prox_coef);
2588c2ecf20Sopenharmony_ci	if (raw > chip->prox_const)
2598c2ecf20Sopenharmony_ci		raw = raw - chip->prox_const;
2608c2ecf20Sopenharmony_ci	else
2618c2ecf20Sopenharmony_ci		raw = 0;
2628c2ecf20Sopenharmony_ci	return raw;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/*
2668c2ecf20Sopenharmony_ci * Following two functions converts raw lux values from HW to normalized
2678c2ecf20Sopenharmony_ci * values. Purpose is to compensate differences between different sensor
2688c2ecf20Sopenharmony_ci * versions and variants so that result means about the same between
2698c2ecf20Sopenharmony_ci * versions. Chip->mutex is kept when this is called.
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_cistatic int bh1770_prox_set_threshold(struct bh1770_chip *chip)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	u8 tmp = 0;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* sysfs may call this when the chip is powered off */
2768c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(&chip->client->dev))
2778c2ecf20Sopenharmony_ci		return 0;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	tmp = bh1770_psadjusted_to_raw(chip, chip->prox_threshold);
2808c2ecf20Sopenharmony_ci	chip->prox_threshold_hw = tmp;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return	i2c_smbus_write_byte_data(chip->client, BH1770_PS_TH_LED1,
2838c2ecf20Sopenharmony_ci					tmp);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline u16 bh1770_lux_raw_to_adjusted(struct bh1770_chip *chip, u16 raw)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	u32 lux;
2898c2ecf20Sopenharmony_ci	lux = ((u32)raw * chip->lux_corr) / BH1770_LUX_CORR_SCALE;
2908c2ecf20Sopenharmony_ci	return min(lux, (u32)BH1770_LUX_RANGE);
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic inline u16 bh1770_lux_adjusted_to_raw(struct bh1770_chip *chip,
2948c2ecf20Sopenharmony_ci					u16 adjusted)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	return (u32)adjusted * BH1770_LUX_CORR_SCALE / chip->lux_corr;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci/* chip->mutex is kept when this is called */
3008c2ecf20Sopenharmony_cistatic int bh1770_lux_update_thresholds(struct bh1770_chip *chip,
3018c2ecf20Sopenharmony_ci					u16 threshold_hi, u16 threshold_lo)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	u8 data[4];
3048c2ecf20Sopenharmony_ci	int ret;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* sysfs may call this when the chip is powered off */
3078c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(&chip->client->dev))
3088c2ecf20Sopenharmony_ci		return 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * Compensate threshold values with the correction factors if not
3128c2ecf20Sopenharmony_ci	 * set to minimum or maximum.
3138c2ecf20Sopenharmony_ci	 * Min & max values disables interrupts.
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	if (threshold_hi != BH1770_LUX_RANGE && threshold_hi != 0)
3168c2ecf20Sopenharmony_ci		threshold_hi = bh1770_lux_adjusted_to_raw(chip, threshold_hi);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (threshold_lo != BH1770_LUX_RANGE && threshold_lo != 0)
3198c2ecf20Sopenharmony_ci		threshold_lo = bh1770_lux_adjusted_to_raw(chip, threshold_lo);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (chip->lux_thres_hi_onchip == threshold_hi &&
3228c2ecf20Sopenharmony_ci	    chip->lux_thres_lo_onchip == threshold_lo)
3238c2ecf20Sopenharmony_ci		return 0;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	chip->lux_thres_hi_onchip = threshold_hi;
3268c2ecf20Sopenharmony_ci	chip->lux_thres_lo_onchip = threshold_lo;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	data[0] = threshold_hi;
3298c2ecf20Sopenharmony_ci	data[1] = threshold_hi >> 8;
3308c2ecf20Sopenharmony_ci	data[2] = threshold_lo;
3318c2ecf20Sopenharmony_ci	data[3] = threshold_lo >> 8;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_i2c_block_data(chip->client,
3348c2ecf20Sopenharmony_ci					BH1770_ALS_TH_UP_0,
3358c2ecf20Sopenharmony_ci					ARRAY_SIZE(data),
3368c2ecf20Sopenharmony_ci					data);
3378c2ecf20Sopenharmony_ci	return ret;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic int bh1770_lux_get_result(struct bh1770_chip *chip)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	u16 data;
3438c2ecf20Sopenharmony_ci	int ret;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_0);
3468c2ecf20Sopenharmony_ci	if (ret < 0)
3478c2ecf20Sopenharmony_ci		return ret;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	data = ret & 0xff;
3508c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_1);
3518c2ecf20Sopenharmony_ci	if (ret < 0)
3528c2ecf20Sopenharmony_ci		return ret;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	chip->lux_data_raw = data | ((ret & 0xff) << 8);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return 0;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/* Calculate correction value which contains chip and device specific parts */
3608c2ecf20Sopenharmony_cistatic u32 bh1770_get_corr_value(struct bh1770_chip *chip)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	u32 tmp;
3638c2ecf20Sopenharmony_ci	/* Impact of glass attenuation correction */
3648c2ecf20Sopenharmony_ci	tmp = (BH1770_LUX_CORR_SCALE * chip->lux_ga) / BH1770_LUX_GA_SCALE;
3658c2ecf20Sopenharmony_ci	/* Impact of chip factor correction */
3668c2ecf20Sopenharmony_ci	tmp = (tmp * chip->lux_cf) / BH1770_LUX_CF_SCALE;
3678c2ecf20Sopenharmony_ci	/* Impact of Device specific calibration correction */
3688c2ecf20Sopenharmony_ci	tmp = (tmp * chip->lux_calib) / BH1770_CALIB_SCALER;
3698c2ecf20Sopenharmony_ci	return tmp;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic int bh1770_lux_read_result(struct bh1770_chip *chip)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	bh1770_lux_get_result(chip);
3758c2ecf20Sopenharmony_ci	return bh1770_lux_raw_to_adjusted(chip, chip->lux_data_raw);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci/*
3798c2ecf20Sopenharmony_ci * Chip on / off functions are called while keeping mutex except probe
3808c2ecf20Sopenharmony_ci * or remove phase
3818c2ecf20Sopenharmony_ci */
3828c2ecf20Sopenharmony_cistatic int bh1770_chip_on(struct bh1770_chip *chip)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	int ret = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
3858c2ecf20Sopenharmony_ci					chip->regs);
3868c2ecf20Sopenharmony_ci	if (ret < 0)
3878c2ecf20Sopenharmony_ci		return ret;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* Reset the chip */
3928c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client, BH1770_ALS_CONTROL,
3938c2ecf20Sopenharmony_ci				BH1770_SWRESET);
3948c2ecf20Sopenharmony_ci	usleep_range(BH1770_RESET_TIME, BH1770_RESET_TIME * 2);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/*
3978c2ecf20Sopenharmony_ci	 * ALS is started always since proximity needs als results
3988c2ecf20Sopenharmony_ci	 * for realibility estimation.
3998c2ecf20Sopenharmony_ci	 * Let's assume dark until the first ALS measurement is ready.
4008c2ecf20Sopenharmony_ci	 */
4018c2ecf20Sopenharmony_ci	chip->lux_data_raw = 0;
4028c2ecf20Sopenharmony_ci	chip->prox_data = 0;
4038c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(chip->client,
4048c2ecf20Sopenharmony_ci					BH1770_ALS_CONTROL, BH1770_STANDALONE);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* Assume reset defaults */
4078c2ecf20Sopenharmony_ci	chip->lux_thres_hi_onchip = BH1770_LUX_RANGE;
4088c2ecf20Sopenharmony_ci	chip->lux_thres_lo_onchip = 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	return ret;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic void bh1770_chip_off(struct bh1770_chip *chip)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client,
4168c2ecf20Sopenharmony_ci					BH1770_INTERRUPT, BH1770_DISABLE);
4178c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client,
4188c2ecf20Sopenharmony_ci				BH1770_ALS_CONTROL, BH1770_STANDBY);
4198c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client,
4208c2ecf20Sopenharmony_ci				BH1770_PS_CONTROL, BH1770_STANDBY);
4218c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci/* chip->mutex is kept when this is called */
4258c2ecf20Sopenharmony_cistatic int bh1770_prox_mode_control(struct bh1770_chip *chip)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	if (chip->prox_enable_count) {
4288c2ecf20Sopenharmony_ci		chip->prox_force_update = true; /* Force immediate update */
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci		bh1770_lux_rate(chip, chip->lux_rate_index);
4318c2ecf20Sopenharmony_ci		bh1770_prox_set_threshold(chip);
4328c2ecf20Sopenharmony_ci		bh1770_led_cfg(chip);
4338c2ecf20Sopenharmony_ci		bh1770_prox_rate(chip, PROX_BELOW_THRESHOLD);
4348c2ecf20Sopenharmony_ci		bh1770_prox_interrupt_control(chip, BH1770_ENABLE);
4358c2ecf20Sopenharmony_ci		i2c_smbus_write_byte_data(chip->client,
4368c2ecf20Sopenharmony_ci					BH1770_PS_CONTROL, BH1770_STANDALONE);
4378c2ecf20Sopenharmony_ci	} else {
4388c2ecf20Sopenharmony_ci		chip->prox_data = 0;
4398c2ecf20Sopenharmony_ci		bh1770_lux_rate(chip, chip->lux_rate_index);
4408c2ecf20Sopenharmony_ci		bh1770_prox_interrupt_control(chip, BH1770_DISABLE);
4418c2ecf20Sopenharmony_ci		i2c_smbus_write_byte_data(chip->client,
4428c2ecf20Sopenharmony_ci					BH1770_PS_CONTROL, BH1770_STANDBY);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci/* chip->mutex is kept when this is called */
4488c2ecf20Sopenharmony_cistatic int bh1770_prox_read_result(struct bh1770_chip *chip)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	int ret;
4518c2ecf20Sopenharmony_ci	bool above;
4528c2ecf20Sopenharmony_ci	u8 mode;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(chip->client, BH1770_PS_DATA_LED1);
4558c2ecf20Sopenharmony_ci	if (ret < 0)
4568c2ecf20Sopenharmony_ci		goto out;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (ret > chip->prox_threshold_hw)
4598c2ecf20Sopenharmony_ci		above = true;
4608c2ecf20Sopenharmony_ci	else
4618c2ecf20Sopenharmony_ci		above = false;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/*
4648c2ecf20Sopenharmony_ci	 * when ALS levels goes above limit, proximity result may be
4658c2ecf20Sopenharmony_ci	 * false proximity. Thus ignore the result. With real proximity
4668c2ecf20Sopenharmony_ci	 * there is a shadow causing low als levels.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci	if (chip->lux_data_raw > PROX_IGNORE_LUX_LIMIT)
4698c2ecf20Sopenharmony_ci		ret = 0;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	chip->prox_data = bh1770_psraw_to_adjusted(chip, ret);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/* Strong proximity level or force mode requires immediate response */
4748c2ecf20Sopenharmony_ci	if (chip->prox_data >= chip->prox_abs_thres ||
4758c2ecf20Sopenharmony_ci	    chip->prox_force_update)
4768c2ecf20Sopenharmony_ci		chip->prox_persistence_counter = chip->prox_persistence;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	chip->prox_force_update = false;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/* Persistence filttering to reduce false proximity events */
4818c2ecf20Sopenharmony_ci	if (likely(above)) {
4828c2ecf20Sopenharmony_ci		if (chip->prox_persistence_counter < chip->prox_persistence) {
4838c2ecf20Sopenharmony_ci			chip->prox_persistence_counter++;
4848c2ecf20Sopenharmony_ci			ret = -ENODATA;
4858c2ecf20Sopenharmony_ci		} else {
4868c2ecf20Sopenharmony_ci			mode = PROX_ABOVE_THRESHOLD;
4878c2ecf20Sopenharmony_ci			ret = 0;
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci	} else {
4908c2ecf20Sopenharmony_ci		chip->prox_persistence_counter = 0;
4918c2ecf20Sopenharmony_ci		mode = PROX_BELOW_THRESHOLD;
4928c2ecf20Sopenharmony_ci		chip->prox_data = 0;
4938c2ecf20Sopenharmony_ci		ret = 0;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	/* Set proximity detection rate based on above or below value */
4978c2ecf20Sopenharmony_ci	if (ret == 0) {
4988c2ecf20Sopenharmony_ci		bh1770_prox_rate(chip, mode);
4998c2ecf20Sopenharmony_ci		sysfs_notify(&chip->client->dev.kobj, NULL, "prox0_raw");
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ciout:
5028c2ecf20Sopenharmony_ci	return ret;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_cistatic int bh1770_detect(struct bh1770_chip *chip)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	struct i2c_client *client = chip->client;
5088c2ecf20Sopenharmony_ci	s32 ret;
5098c2ecf20Sopenharmony_ci	u8 manu, part;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(client, BH1770_MANUFACT_ID);
5128c2ecf20Sopenharmony_ci	if (ret < 0)
5138c2ecf20Sopenharmony_ci		goto error;
5148c2ecf20Sopenharmony_ci	manu = (u8)ret;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte_data(client, BH1770_PART_ID);
5178c2ecf20Sopenharmony_ci	if (ret < 0)
5188c2ecf20Sopenharmony_ci		goto error;
5198c2ecf20Sopenharmony_ci	part = (u8)ret;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	chip->revision = (part & BH1770_REV_MASK) >> BH1770_REV_SHIFT;
5228c2ecf20Sopenharmony_ci	chip->prox_coef = BH1770_COEF_SCALER;
5238c2ecf20Sopenharmony_ci	chip->prox_const = 0;
5248c2ecf20Sopenharmony_ci	chip->lux_cf = BH1770_NEUTRAL_CF;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if ((manu == BH1770_MANUFACT_ROHM) &&
5278c2ecf20Sopenharmony_ci	    ((part & BH1770_PART_MASK) == BH1770_PART)) {
5288c2ecf20Sopenharmony_ci		snprintf(chip->chipname, sizeof(chip->chipname), "BH1770GLC");
5298c2ecf20Sopenharmony_ci		return 0;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if ((manu == BH1770_MANUFACT_OSRAM) &&
5338c2ecf20Sopenharmony_ci	    ((part & BH1770_PART_MASK) == BH1770_PART)) {
5348c2ecf20Sopenharmony_ci		snprintf(chip->chipname, sizeof(chip->chipname), "SFH7770");
5358c2ecf20Sopenharmony_ci		/* Values selected by comparing different versions */
5368c2ecf20Sopenharmony_ci		chip->prox_coef = 819; /* 0.8 * BH1770_COEF_SCALER */
5378c2ecf20Sopenharmony_ci		chip->prox_const = 40;
5388c2ecf20Sopenharmony_ci		return 0;
5398c2ecf20Sopenharmony_ci	}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	ret = -ENODEV;
5428c2ecf20Sopenharmony_cierror:
5438c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "BH1770 or SFH7770 not found\n");
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	return ret;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci/*
5498c2ecf20Sopenharmony_ci * This work is re-scheduled at every proximity interrupt.
5508c2ecf20Sopenharmony_ci * If this work is running, it means that there hasn't been any
5518c2ecf20Sopenharmony_ci * proximity interrupt in time. Situation is handled as no-proximity.
5528c2ecf20Sopenharmony_ci * It would be nice to have low-threshold interrupt or interrupt
5538c2ecf20Sopenharmony_ci * when measurement and hi-threshold are both 0. But neither of those exists.
5548c2ecf20Sopenharmony_ci * This is a workaroud for missing HW feature.
5558c2ecf20Sopenharmony_ci */
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic void bh1770_prox_work(struct work_struct *work)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =
5608c2ecf20Sopenharmony_ci		container_of(work, struct bh1770_chip, prox_work.work);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
5638c2ecf20Sopenharmony_ci	bh1770_prox_read_result(chip);
5648c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci/* This is threaded irq handler */
5688c2ecf20Sopenharmony_cistatic irqreturn_t bh1770_irq(int irq, void *data)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = data;
5718c2ecf20Sopenharmony_ci	int status;
5728c2ecf20Sopenharmony_ci	int rate = 0;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
5758c2ecf20Sopenharmony_ci	status = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_PS_STATUS);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* Acknowledge interrupt by reading this register */
5788c2ecf20Sopenharmony_ci	i2c_smbus_read_byte_data(chip->client, BH1770_INTERRUPT);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/*
5818c2ecf20Sopenharmony_ci	 * Check if there is fresh data available for als.
5828c2ecf20Sopenharmony_ci	 * If this is the very first data, update thresholds after that.
5838c2ecf20Sopenharmony_ci	 */
5848c2ecf20Sopenharmony_ci	if (status & BH1770_INT_ALS_DATA) {
5858c2ecf20Sopenharmony_ci		bh1770_lux_get_result(chip);
5868c2ecf20Sopenharmony_ci		if (unlikely(chip->lux_wait_result)) {
5878c2ecf20Sopenharmony_ci			chip->lux_wait_result = false;
5888c2ecf20Sopenharmony_ci			wake_up(&chip->wait);
5898c2ecf20Sopenharmony_ci			bh1770_lux_update_thresholds(chip,
5908c2ecf20Sopenharmony_ci						chip->lux_threshold_hi,
5918c2ecf20Sopenharmony_ci						chip->lux_threshold_lo);
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci	}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/* Disable interrupt logic to guarantee acknowledgement */
5968c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
5978c2ecf20Sopenharmony_ci				  (0 << 1) | (0 << 0));
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if ((status & BH1770_INT_ALS_INT))
6008c2ecf20Sopenharmony_ci		sysfs_notify(&chip->client->dev.kobj, NULL, "lux0_input");
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (chip->int_mode_prox && (status & BH1770_INT_LEDS_INT)) {
6038c2ecf20Sopenharmony_ci		rate = prox_rates_ms[chip->prox_rate_threshold];
6048c2ecf20Sopenharmony_ci		bh1770_prox_read_result(chip);
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	/* Re-enable interrupt logic */
6088c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
6098c2ecf20Sopenharmony_ci				  (chip->int_mode_lux << 1) |
6108c2ecf20Sopenharmony_ci				  (chip->int_mode_prox << 0));
6118c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/*
6148c2ecf20Sopenharmony_ci	 * Can't cancel work while keeping mutex since the work uses the
6158c2ecf20Sopenharmony_ci	 * same mutex.
6168c2ecf20Sopenharmony_ci	 */
6178c2ecf20Sopenharmony_ci	if (rate) {
6188c2ecf20Sopenharmony_ci		/*
6198c2ecf20Sopenharmony_ci		 * Simulate missing no-proximity interrupt 50ms after the
6208c2ecf20Sopenharmony_ci		 * next expected interrupt time.
6218c2ecf20Sopenharmony_ci		 */
6228c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&chip->prox_work);
6238c2ecf20Sopenharmony_ci		schedule_delayed_work(&chip->prox_work,
6248c2ecf20Sopenharmony_ci				msecs_to_jiffies(rate + 50));
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic ssize_t bh1770_power_state_store(struct device *dev,
6308c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
6318c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
6348c2ecf20Sopenharmony_ci	unsigned long value;
6358c2ecf20Sopenharmony_ci	ssize_t ret;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
6388c2ecf20Sopenharmony_ci	if (ret)
6398c2ecf20Sopenharmony_ci		return ret;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
6428c2ecf20Sopenharmony_ci	if (value) {
6438c2ecf20Sopenharmony_ci		pm_runtime_get_sync(dev);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		ret = bh1770_lux_rate(chip, chip->lux_rate_index);
6468c2ecf20Sopenharmony_ci		if (ret < 0) {
6478c2ecf20Sopenharmony_ci			pm_runtime_put(dev);
6488c2ecf20Sopenharmony_ci			goto leave;
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
6528c2ecf20Sopenharmony_ci		if (ret < 0) {
6538c2ecf20Sopenharmony_ci			pm_runtime_put(dev);
6548c2ecf20Sopenharmony_ci			goto leave;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci		/* This causes interrupt after the next measurement cycle */
6588c2ecf20Sopenharmony_ci		bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
6598c2ecf20Sopenharmony_ci					BH1770_LUX_DEF_THRES);
6608c2ecf20Sopenharmony_ci		/* Inform that we are waiting for a result from ALS */
6618c2ecf20Sopenharmony_ci		chip->lux_wait_result = true;
6628c2ecf20Sopenharmony_ci		bh1770_prox_mode_control(chip);
6638c2ecf20Sopenharmony_ci	} else if (!pm_runtime_suspended(dev)) {
6648c2ecf20Sopenharmony_ci		pm_runtime_put(dev);
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci	ret = count;
6678c2ecf20Sopenharmony_cileave:
6688c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
6698c2ecf20Sopenharmony_ci	return ret;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic ssize_t bh1770_power_state_show(struct device *dev,
6738c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_cistatic ssize_t bh1770_lux_result_show(struct device *dev,
6798c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
6828c2ecf20Sopenharmony_ci	ssize_t ret;
6838c2ecf20Sopenharmony_ci	long timeout;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(dev))
6868c2ecf20Sopenharmony_ci		return -EIO; /* Chip is not enabled at all */
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	timeout = wait_event_interruptible_timeout(chip->wait,
6898c2ecf20Sopenharmony_ci					!chip->lux_wait_result,
6908c2ecf20Sopenharmony_ci					msecs_to_jiffies(BH1770_TIMEOUT));
6918c2ecf20Sopenharmony_ci	if (!timeout)
6928c2ecf20Sopenharmony_ci		return -EIO;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
6958c2ecf20Sopenharmony_ci	ret = sprintf(buf, "%d\n", bh1770_lux_read_result(chip));
6968c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return ret;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic ssize_t bh1770_lux_range_show(struct device *dev,
7028c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", BH1770_LUX_RANGE);
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_enable_store(struct device *dev,
7088c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
7098c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
7128c2ecf20Sopenharmony_ci	unsigned long value;
7138c2ecf20Sopenharmony_ci	int ret;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
7168c2ecf20Sopenharmony_ci	if (ret)
7178c2ecf20Sopenharmony_ci		return ret;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
7208c2ecf20Sopenharmony_ci	/* Assume no proximity. Sensor will tell real state soon */
7218c2ecf20Sopenharmony_ci	if (!chip->prox_enable_count)
7228c2ecf20Sopenharmony_ci		chip->prox_data = 0;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	if (value)
7258c2ecf20Sopenharmony_ci		chip->prox_enable_count++;
7268c2ecf20Sopenharmony_ci	else if (chip->prox_enable_count > 0)
7278c2ecf20Sopenharmony_ci		chip->prox_enable_count--;
7288c2ecf20Sopenharmony_ci	else
7298c2ecf20Sopenharmony_ci		goto leave;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	/* Run control only when chip is powered on */
7328c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(dev))
7338c2ecf20Sopenharmony_ci		bh1770_prox_mode_control(chip);
7348c2ecf20Sopenharmony_cileave:
7358c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
7368c2ecf20Sopenharmony_ci	return count;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_enable_show(struct device *dev,
7408c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
7438c2ecf20Sopenharmony_ci	ssize_t len;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
7468c2ecf20Sopenharmony_ci	len = sprintf(buf, "%d\n", chip->prox_enable_count);
7478c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
7488c2ecf20Sopenharmony_ci	return len;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_result_show(struct device *dev,
7528c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
7558c2ecf20Sopenharmony_ci	ssize_t ret;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
7588c2ecf20Sopenharmony_ci	if (chip->prox_enable_count && !pm_runtime_suspended(dev))
7598c2ecf20Sopenharmony_ci		ret = sprintf(buf, "%d\n", chip->prox_data);
7608c2ecf20Sopenharmony_ci	else
7618c2ecf20Sopenharmony_ci		ret = -EIO;
7628c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
7638c2ecf20Sopenharmony_ci	return ret;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_range_show(struct device *dev,
7678c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", BH1770_PROX_RANGE);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_prox_rate_avail(struct device *dev,
7738c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	int i;
7768c2ecf20Sopenharmony_ci	int pos = 0;
7778c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(prox_rates_hz); i++)
7788c2ecf20Sopenharmony_ci		pos += sprintf(buf + pos, "%d ", prox_rates_hz[i]);
7798c2ecf20Sopenharmony_ci	sprintf(buf + pos - 1, "\n");
7808c2ecf20Sopenharmony_ci	return pos;
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_prox_rate_above(struct device *dev,
7848c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
7878c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate_threshold]);
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_prox_rate_below(struct device *dev,
7918c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
7948c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate]);
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic int bh1770_prox_rate_validate(int rate)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	int i;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(prox_rates_hz) - 1; i++)
8028c2ecf20Sopenharmony_ci		if (rate >= prox_rates_hz[i])
8038c2ecf20Sopenharmony_ci			break;
8048c2ecf20Sopenharmony_ci	return i;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_prox_rate_above(struct device *dev,
8088c2ecf20Sopenharmony_ci					struct device_attribute *attr,
8098c2ecf20Sopenharmony_ci					const char *buf, size_t count)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
8128c2ecf20Sopenharmony_ci	unsigned long value;
8138c2ecf20Sopenharmony_ci	int ret;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
8168c2ecf20Sopenharmony_ci	if (ret)
8178c2ecf20Sopenharmony_ci		return ret;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
8208c2ecf20Sopenharmony_ci	chip->prox_rate_threshold = bh1770_prox_rate_validate(value);
8218c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
8228c2ecf20Sopenharmony_ci	return count;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_prox_rate_below(struct device *dev,
8268c2ecf20Sopenharmony_ci					struct device_attribute *attr,
8278c2ecf20Sopenharmony_ci					const char *buf, size_t count)
8288c2ecf20Sopenharmony_ci{
8298c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
8308c2ecf20Sopenharmony_ci	unsigned long value;
8318c2ecf20Sopenharmony_ci	int ret;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
8348c2ecf20Sopenharmony_ci	if (ret)
8358c2ecf20Sopenharmony_ci		return ret;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
8388c2ecf20Sopenharmony_ci	chip->prox_rate = bh1770_prox_rate_validate(value);
8398c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
8408c2ecf20Sopenharmony_ci	return count;
8418c2ecf20Sopenharmony_ci}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_prox_thres(struct device *dev,
8448c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
8478c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", chip->prox_threshold);
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_prox_thres(struct device *dev,
8518c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
8528c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
8538c2ecf20Sopenharmony_ci{
8548c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
8558c2ecf20Sopenharmony_ci	unsigned long value;
8568c2ecf20Sopenharmony_ci	int ret;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
8598c2ecf20Sopenharmony_ci	if (ret)
8608c2ecf20Sopenharmony_ci		return ret;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	if (value > BH1770_PROX_RANGE)
8638c2ecf20Sopenharmony_ci		return -EINVAL;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
8668c2ecf20Sopenharmony_ci	chip->prox_threshold = value;
8678c2ecf20Sopenharmony_ci	ret = bh1770_prox_set_threshold(chip);
8688c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
8698c2ecf20Sopenharmony_ci	if (ret < 0)
8708c2ecf20Sopenharmony_ci		return ret;
8718c2ecf20Sopenharmony_ci	return count;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_persistence_show(struct device *dev,
8758c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", chip->prox_persistence);
8808c2ecf20Sopenharmony_ci}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_persistence_store(struct device *dev,
8838c2ecf20Sopenharmony_ci				struct device_attribute *attr,
8848c2ecf20Sopenharmony_ci				const char *buf, size_t len)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
8878c2ecf20Sopenharmony_ci	unsigned long value;
8888c2ecf20Sopenharmony_ci	int ret;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
8918c2ecf20Sopenharmony_ci	if (ret)
8928c2ecf20Sopenharmony_ci		return ret;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	if (value > BH1770_PROX_MAX_PERSISTENCE)
8958c2ecf20Sopenharmony_ci		return -EINVAL;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	chip->prox_persistence = value;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	return len;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_abs_thres_show(struct device *dev,
9038c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
9068c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", chip->prox_abs_thres);
9078c2ecf20Sopenharmony_ci}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic ssize_t bh1770_prox_abs_thres_store(struct device *dev,
9108c2ecf20Sopenharmony_ci				struct device_attribute *attr,
9118c2ecf20Sopenharmony_ci				const char *buf, size_t len)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
9148c2ecf20Sopenharmony_ci	unsigned long value;
9158c2ecf20Sopenharmony_ci	int ret;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
9188c2ecf20Sopenharmony_ci	if (ret)
9198c2ecf20Sopenharmony_ci		return ret;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (value > BH1770_PROX_RANGE)
9228c2ecf20Sopenharmony_ci		return -EINVAL;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	chip->prox_abs_thres = value;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	return len;
9278c2ecf20Sopenharmony_ci}
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cistatic ssize_t bh1770_chip_id_show(struct device *dev,
9308c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
9338c2ecf20Sopenharmony_ci	return sprintf(buf, "%s rev %d\n", chip->chipname, chip->revision);
9348c2ecf20Sopenharmony_ci}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_cistatic ssize_t bh1770_lux_calib_default_show(struct device *dev,
9378c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
9388c2ecf20Sopenharmony_ci{
9398c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", BH1770_CALIB_SCALER);
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic ssize_t bh1770_lux_calib_show(struct device *dev,
9438c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
9468c2ecf20Sopenharmony_ci	ssize_t len;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
9498c2ecf20Sopenharmony_ci	len = sprintf(buf, "%u\n", chip->lux_calib);
9508c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
9518c2ecf20Sopenharmony_ci	return len;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic ssize_t bh1770_lux_calib_store(struct device *dev,
9558c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
9568c2ecf20Sopenharmony_ci				  const char *buf, size_t len)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = dev_get_drvdata(dev);
9598c2ecf20Sopenharmony_ci	unsigned long value;
9608c2ecf20Sopenharmony_ci	u32 old_calib;
9618c2ecf20Sopenharmony_ci	u32 new_corr;
9628c2ecf20Sopenharmony_ci	int ret;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &value);
9658c2ecf20Sopenharmony_ci	if (ret)
9668c2ecf20Sopenharmony_ci		return ret;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
9698c2ecf20Sopenharmony_ci	old_calib = chip->lux_calib;
9708c2ecf20Sopenharmony_ci	chip->lux_calib = value;
9718c2ecf20Sopenharmony_ci	new_corr = bh1770_get_corr_value(chip);
9728c2ecf20Sopenharmony_ci	if (new_corr == 0) {
9738c2ecf20Sopenharmony_ci		chip->lux_calib = old_calib;
9748c2ecf20Sopenharmony_ci		mutex_unlock(&chip->mutex);
9758c2ecf20Sopenharmony_ci		return -EINVAL;
9768c2ecf20Sopenharmony_ci	}
9778c2ecf20Sopenharmony_ci	chip->lux_corr = new_corr;
9788c2ecf20Sopenharmony_ci	/* Refresh thresholds on HW after changing correction value */
9798c2ecf20Sopenharmony_ci	bh1770_lux_update_thresholds(chip, chip->lux_threshold_hi,
9808c2ecf20Sopenharmony_ci				chip->lux_threshold_lo);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	return len;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_lux_rate_avail(struct device *dev,
9888c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
9898c2ecf20Sopenharmony_ci{
9908c2ecf20Sopenharmony_ci	int i;
9918c2ecf20Sopenharmony_ci	int pos = 0;
9928c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(lux_rates_hz); i++)
9938c2ecf20Sopenharmony_ci		pos += sprintf(buf + pos, "%d ", lux_rates_hz[i]);
9948c2ecf20Sopenharmony_ci	sprintf(buf + pos - 1, "\n");
9958c2ecf20Sopenharmony_ci	return pos;
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_lux_rate(struct device *dev,
9998c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10028c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", lux_rates_hz[chip->lux_rate_index]);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_lux_rate(struct device *dev,
10068c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
10078c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
10088c2ecf20Sopenharmony_ci{
10098c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10108c2ecf20Sopenharmony_ci	unsigned long rate_hz;
10118c2ecf20Sopenharmony_ci	int ret, i;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &rate_hz);
10148c2ecf20Sopenharmony_ci	if (ret)
10158c2ecf20Sopenharmony_ci		return ret;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(lux_rates_hz) - 1; i++)
10188c2ecf20Sopenharmony_ci		if (rate_hz >= lux_rates_hz[i])
10198c2ecf20Sopenharmony_ci			break;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
10228c2ecf20Sopenharmony_ci	chip->lux_rate_index = i;
10238c2ecf20Sopenharmony_ci	ret = bh1770_lux_rate(chip, i);
10248c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (ret < 0)
10278c2ecf20Sopenharmony_ci		return ret;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	return count;
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_lux_thresh_above(struct device *dev,
10338c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10368c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", chip->lux_threshold_hi);
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic ssize_t bh1770_get_lux_thresh_below(struct device *dev,
10408c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10438c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", chip->lux_threshold_lo);
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_lux_thresh(struct bh1770_chip *chip, u16 *target,
10478c2ecf20Sopenharmony_ci				const char *buf)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	unsigned long thresh;
10508c2ecf20Sopenharmony_ci	int ret;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	ret = kstrtoul(buf, 0, &thresh);
10538c2ecf20Sopenharmony_ci	if (ret)
10548c2ecf20Sopenharmony_ci		return ret;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	if (thresh > BH1770_LUX_RANGE)
10578c2ecf20Sopenharmony_ci		return -EINVAL;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	mutex_lock(&chip->mutex);
10608c2ecf20Sopenharmony_ci	*target = thresh;
10618c2ecf20Sopenharmony_ci	/*
10628c2ecf20Sopenharmony_ci	 * Don't update values in HW if we are still waiting for
10638c2ecf20Sopenharmony_ci	 * first interrupt to come after device handle open call.
10648c2ecf20Sopenharmony_ci	 */
10658c2ecf20Sopenharmony_ci	if (!chip->lux_wait_result)
10668c2ecf20Sopenharmony_ci		ret = bh1770_lux_update_thresholds(chip,
10678c2ecf20Sopenharmony_ci						chip->lux_threshold_hi,
10688c2ecf20Sopenharmony_ci						chip->lux_threshold_lo);
10698c2ecf20Sopenharmony_ci	mutex_unlock(&chip->mutex);
10708c2ecf20Sopenharmony_ci	return ret;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_lux_thresh_above(struct device *dev,
10758c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
10768c2ecf20Sopenharmony_ci				  const char *buf, size_t len)
10778c2ecf20Sopenharmony_ci{
10788c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10798c2ecf20Sopenharmony_ci	int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_hi, buf);
10808c2ecf20Sopenharmony_ci	if (ret < 0)
10818c2ecf20Sopenharmony_ci		return ret;
10828c2ecf20Sopenharmony_ci	return len;
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_cistatic ssize_t bh1770_set_lux_thresh_below(struct device *dev,
10868c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
10878c2ecf20Sopenharmony_ci				  const char *buf, size_t len)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	struct bh1770_chip *chip =  dev_get_drvdata(dev);
10908c2ecf20Sopenharmony_ci	int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_lo, buf);
10918c2ecf20Sopenharmony_ci	if (ret < 0)
10928c2ecf20Sopenharmony_ci		return ret;
10938c2ecf20Sopenharmony_ci	return len;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, bh1770_prox_enable_show,
10978c2ecf20Sopenharmony_ci						bh1770_prox_enable_store);
10988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_thresh_above1_value, S_IRUGO | S_IWUSR,
10998c2ecf20Sopenharmony_ci						bh1770_prox_abs_thres_show,
11008c2ecf20Sopenharmony_ci						bh1770_prox_abs_thres_store);
11018c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_thresh_above0_value, S_IRUGO | S_IWUSR,
11028c2ecf20Sopenharmony_ci						bh1770_get_prox_thres,
11038c2ecf20Sopenharmony_ci						bh1770_set_prox_thres);
11048c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_raw, S_IRUGO, bh1770_prox_result_show, NULL);
11058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_sensor_range, S_IRUGO, bh1770_prox_range_show, NULL);
11068c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_thresh_above_count, S_IRUGO | S_IWUSR,
11078c2ecf20Sopenharmony_ci						bh1770_prox_persistence_show,
11088c2ecf20Sopenharmony_ci						bh1770_prox_persistence_store);
11098c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_rate_above, S_IRUGO | S_IWUSR,
11108c2ecf20Sopenharmony_ci						bh1770_get_prox_rate_above,
11118c2ecf20Sopenharmony_ci						bh1770_set_prox_rate_above);
11128c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_rate_below, S_IRUGO | S_IWUSR,
11138c2ecf20Sopenharmony_ci						bh1770_get_prox_rate_below,
11148c2ecf20Sopenharmony_ci						bh1770_set_prox_rate_below);
11158c2ecf20Sopenharmony_cistatic DEVICE_ATTR(prox0_rate_avail, S_IRUGO, bh1770_get_prox_rate_avail, NULL);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, bh1770_lux_calib_show,
11188c2ecf20Sopenharmony_ci						bh1770_lux_calib_store);
11198c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
11208c2ecf20Sopenharmony_ci						bh1770_lux_calib_default_show,
11218c2ecf20Sopenharmony_ci						NULL);
11228c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_input, S_IRUGO, bh1770_lux_result_show, NULL);
11238c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_sensor_range, S_IRUGO, bh1770_lux_range_show, NULL);
11248c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, bh1770_get_lux_rate,
11258c2ecf20Sopenharmony_ci						bh1770_set_lux_rate);
11268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_rate_avail, S_IRUGO, bh1770_get_lux_rate_avail, NULL);
11278c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
11288c2ecf20Sopenharmony_ci						bh1770_get_lux_thresh_above,
11298c2ecf20Sopenharmony_ci						bh1770_set_lux_thresh_above);
11308c2ecf20Sopenharmony_cistatic DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
11318c2ecf20Sopenharmony_ci						bh1770_get_lux_thresh_below,
11328c2ecf20Sopenharmony_ci						bh1770_set_lux_thresh_below);
11338c2ecf20Sopenharmony_cistatic DEVICE_ATTR(chip_id, S_IRUGO, bh1770_chip_id_show, NULL);
11348c2ecf20Sopenharmony_cistatic DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, bh1770_power_state_show,
11358c2ecf20Sopenharmony_ci						 bh1770_power_state_store);
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic struct attribute *sysfs_attrs[] = {
11398c2ecf20Sopenharmony_ci	&dev_attr_lux0_calibscale.attr,
11408c2ecf20Sopenharmony_ci	&dev_attr_lux0_calibscale_default.attr,
11418c2ecf20Sopenharmony_ci	&dev_attr_lux0_input.attr,
11428c2ecf20Sopenharmony_ci	&dev_attr_lux0_sensor_range.attr,
11438c2ecf20Sopenharmony_ci	&dev_attr_lux0_rate.attr,
11448c2ecf20Sopenharmony_ci	&dev_attr_lux0_rate_avail.attr,
11458c2ecf20Sopenharmony_ci	&dev_attr_lux0_thresh_above_value.attr,
11468c2ecf20Sopenharmony_ci	&dev_attr_lux0_thresh_below_value.attr,
11478c2ecf20Sopenharmony_ci	&dev_attr_prox0_raw.attr,
11488c2ecf20Sopenharmony_ci	&dev_attr_prox0_sensor_range.attr,
11498c2ecf20Sopenharmony_ci	&dev_attr_prox0_raw_en.attr,
11508c2ecf20Sopenharmony_ci	&dev_attr_prox0_thresh_above_count.attr,
11518c2ecf20Sopenharmony_ci	&dev_attr_prox0_rate_above.attr,
11528c2ecf20Sopenharmony_ci	&dev_attr_prox0_rate_below.attr,
11538c2ecf20Sopenharmony_ci	&dev_attr_prox0_rate_avail.attr,
11548c2ecf20Sopenharmony_ci	&dev_attr_prox0_thresh_above0_value.attr,
11558c2ecf20Sopenharmony_ci	&dev_attr_prox0_thresh_above1_value.attr,
11568c2ecf20Sopenharmony_ci	&dev_attr_chip_id.attr,
11578c2ecf20Sopenharmony_ci	&dev_attr_power_state.attr,
11588c2ecf20Sopenharmony_ci	NULL
11598c2ecf20Sopenharmony_ci};
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_cistatic const struct attribute_group bh1770_attribute_group = {
11628c2ecf20Sopenharmony_ci	.attrs = sysfs_attrs
11638c2ecf20Sopenharmony_ci};
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_cistatic int bh1770_probe(struct i2c_client *client,
11668c2ecf20Sopenharmony_ci				const struct i2c_device_id *id)
11678c2ecf20Sopenharmony_ci{
11688c2ecf20Sopenharmony_ci	struct bh1770_chip *chip;
11698c2ecf20Sopenharmony_ci	int err;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	chip = devm_kzalloc(&client->dev, sizeof *chip, GFP_KERNEL);
11728c2ecf20Sopenharmony_ci	if (!chip)
11738c2ecf20Sopenharmony_ci		return -ENOMEM;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, chip);
11768c2ecf20Sopenharmony_ci	chip->client  = client;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	mutex_init(&chip->mutex);
11798c2ecf20Sopenharmony_ci	init_waitqueue_head(&chip->wait);
11808c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&chip->prox_work, bh1770_prox_work);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (client->dev.platform_data == NULL) {
11838c2ecf20Sopenharmony_ci		dev_err(&client->dev, "platform data is mandatory\n");
11848c2ecf20Sopenharmony_ci		return -EINVAL;
11858c2ecf20Sopenharmony_ci	}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	chip->pdata		= client->dev.platform_data;
11888c2ecf20Sopenharmony_ci	chip->lux_calib		= BH1770_LUX_NEUTRAL_CALIB_VALUE;
11898c2ecf20Sopenharmony_ci	chip->lux_rate_index	= BH1770_LUX_DEFAULT_RATE;
11908c2ecf20Sopenharmony_ci	chip->lux_threshold_lo	= BH1770_LUX_DEF_THRES;
11918c2ecf20Sopenharmony_ci	chip->lux_threshold_hi	= BH1770_LUX_DEF_THRES;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	if (chip->pdata->glass_attenuation == 0)
11948c2ecf20Sopenharmony_ci		chip->lux_ga = BH1770_NEUTRAL_GA;
11958c2ecf20Sopenharmony_ci	else
11968c2ecf20Sopenharmony_ci		chip->lux_ga = chip->pdata->glass_attenuation;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	chip->prox_threshold	= BH1770_PROX_DEF_THRES;
11998c2ecf20Sopenharmony_ci	chip->prox_led		= chip->pdata->led_def_curr;
12008c2ecf20Sopenharmony_ci	chip->prox_abs_thres	= BH1770_PROX_DEF_ABS_THRES;
12018c2ecf20Sopenharmony_ci	chip->prox_persistence	= BH1770_DEFAULT_PERSISTENCE;
12028c2ecf20Sopenharmony_ci	chip->prox_rate_threshold = BH1770_PROX_DEF_RATE_THRESH;
12038c2ecf20Sopenharmony_ci	chip->prox_rate		= BH1770_PROX_DEFAULT_RATE;
12048c2ecf20Sopenharmony_ci	chip->prox_data		= 0;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	chip->regs[0].supply = reg_vcc;
12078c2ecf20Sopenharmony_ci	chip->regs[1].supply = reg_vleds;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	err = devm_regulator_bulk_get(&client->dev,
12108c2ecf20Sopenharmony_ci				      ARRAY_SIZE(chip->regs), chip->regs);
12118c2ecf20Sopenharmony_ci	if (err < 0) {
12128c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Cannot get regulators\n");
12138c2ecf20Sopenharmony_ci		return err;
12148c2ecf20Sopenharmony_ci	}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
12178c2ecf20Sopenharmony_ci				chip->regs);
12188c2ecf20Sopenharmony_ci	if (err < 0) {
12198c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Cannot enable regulators\n");
12208c2ecf20Sopenharmony_ci		return err;
12218c2ecf20Sopenharmony_ci	}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
12248c2ecf20Sopenharmony_ci	err = bh1770_detect(chip);
12258c2ecf20Sopenharmony_ci	if (err < 0)
12268c2ecf20Sopenharmony_ci		goto fail0;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* Start chip */
12298c2ecf20Sopenharmony_ci	bh1770_chip_on(chip);
12308c2ecf20Sopenharmony_ci	pm_runtime_set_active(&client->dev);
12318c2ecf20Sopenharmony_ci	pm_runtime_enable(&client->dev);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	chip->lux_corr = bh1770_get_corr_value(chip);
12348c2ecf20Sopenharmony_ci	if (chip->lux_corr == 0) {
12358c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Improper correction values\n");
12368c2ecf20Sopenharmony_ci		err = -EINVAL;
12378c2ecf20Sopenharmony_ci		goto fail0;
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if (chip->pdata->setup_resources) {
12418c2ecf20Sopenharmony_ci		err = chip->pdata->setup_resources();
12428c2ecf20Sopenharmony_ci		if (err) {
12438c2ecf20Sopenharmony_ci			err = -EINVAL;
12448c2ecf20Sopenharmony_ci			goto fail0;
12458c2ecf20Sopenharmony_ci		}
12468c2ecf20Sopenharmony_ci	}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	err = sysfs_create_group(&chip->client->dev.kobj,
12498c2ecf20Sopenharmony_ci				&bh1770_attribute_group);
12508c2ecf20Sopenharmony_ci	if (err < 0) {
12518c2ecf20Sopenharmony_ci		dev_err(&chip->client->dev, "Sysfs registration failed\n");
12528c2ecf20Sopenharmony_ci		goto fail1;
12538c2ecf20Sopenharmony_ci	}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	/*
12568c2ecf20Sopenharmony_ci	 * Chip needs level triggered interrupt to work. However,
12578c2ecf20Sopenharmony_ci	 * level triggering doesn't work always correctly with power
12588c2ecf20Sopenharmony_ci	 * management. Select both
12598c2ecf20Sopenharmony_ci	 */
12608c2ecf20Sopenharmony_ci	err = request_threaded_irq(client->irq, NULL,
12618c2ecf20Sopenharmony_ci				bh1770_irq,
12628c2ecf20Sopenharmony_ci				IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
12638c2ecf20Sopenharmony_ci				IRQF_TRIGGER_LOW,
12648c2ecf20Sopenharmony_ci				"bh1770", chip);
12658c2ecf20Sopenharmony_ci	if (err) {
12668c2ecf20Sopenharmony_ci		dev_err(&client->dev, "could not get IRQ %d\n",
12678c2ecf20Sopenharmony_ci			client->irq);
12688c2ecf20Sopenharmony_ci		goto fail2;
12698c2ecf20Sopenharmony_ci	}
12708c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
12718c2ecf20Sopenharmony_ci	return err;
12728c2ecf20Sopenharmony_cifail2:
12738c2ecf20Sopenharmony_ci	sysfs_remove_group(&chip->client->dev.kobj,
12748c2ecf20Sopenharmony_ci			&bh1770_attribute_group);
12758c2ecf20Sopenharmony_cifail1:
12768c2ecf20Sopenharmony_ci	if (chip->pdata->release_resources)
12778c2ecf20Sopenharmony_ci		chip->pdata->release_resources();
12788c2ecf20Sopenharmony_cifail0:
12798c2ecf20Sopenharmony_ci	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
12808c2ecf20Sopenharmony_ci	return err;
12818c2ecf20Sopenharmony_ci}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_cistatic int bh1770_remove(struct i2c_client *client)
12848c2ecf20Sopenharmony_ci{
12858c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = i2c_get_clientdata(client);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	free_irq(client->irq, chip);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	sysfs_remove_group(&chip->client->dev.kobj,
12908c2ecf20Sopenharmony_ci			&bh1770_attribute_group);
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	if (chip->pdata->release_resources)
12938c2ecf20Sopenharmony_ci		chip->pdata->release_resources();
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&chip->prox_work);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(&client->dev))
12988c2ecf20Sopenharmony_ci		bh1770_chip_off(chip);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
13018c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	return 0;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
13078c2ecf20Sopenharmony_cistatic int bh1770_suspend(struct device *dev)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13108c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = i2c_get_clientdata(client);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	bh1770_chip_off(chip);
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	return 0;
13158c2ecf20Sopenharmony_ci}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_cistatic int bh1770_resume(struct device *dev)
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13208c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = i2c_get_clientdata(client);
13218c2ecf20Sopenharmony_ci	int ret = 0;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	bh1770_chip_on(chip);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(dev)) {
13268c2ecf20Sopenharmony_ci		/*
13278c2ecf20Sopenharmony_ci		 * If we were enabled at suspend time, it is expected
13288c2ecf20Sopenharmony_ci		 * everything works nice and smoothly
13298c2ecf20Sopenharmony_ci		 */
13308c2ecf20Sopenharmony_ci		ret = bh1770_lux_rate(chip, chip->lux_rate_index);
13318c2ecf20Sopenharmony_ci		ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci		/* This causes interrupt after the next measurement cycle */
13348c2ecf20Sopenharmony_ci		bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
13358c2ecf20Sopenharmony_ci					BH1770_LUX_DEF_THRES);
13368c2ecf20Sopenharmony_ci		/* Inform that we are waiting for a result from ALS */
13378c2ecf20Sopenharmony_ci		chip->lux_wait_result = true;
13388c2ecf20Sopenharmony_ci		bh1770_prox_mode_control(chip);
13398c2ecf20Sopenharmony_ci	}
13408c2ecf20Sopenharmony_ci	return ret;
13418c2ecf20Sopenharmony_ci}
13428c2ecf20Sopenharmony_ci#endif
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
13458c2ecf20Sopenharmony_cistatic int bh1770_runtime_suspend(struct device *dev)
13468c2ecf20Sopenharmony_ci{
13478c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13488c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = i2c_get_clientdata(client);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	bh1770_chip_off(chip);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	return 0;
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_cistatic int bh1770_runtime_resume(struct device *dev)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13588c2ecf20Sopenharmony_ci	struct bh1770_chip *chip = i2c_get_clientdata(client);
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	bh1770_chip_on(chip);
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	return 0;
13638c2ecf20Sopenharmony_ci}
13648c2ecf20Sopenharmony_ci#endif
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic const struct i2c_device_id bh1770_id[] = {
13678c2ecf20Sopenharmony_ci	{"bh1770glc", 0 },
13688c2ecf20Sopenharmony_ci	{"sfh7770", 0 },
13698c2ecf20Sopenharmony_ci	{}
13708c2ecf20Sopenharmony_ci};
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, bh1770_id);
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_cistatic const struct dev_pm_ops bh1770_pm_ops = {
13758c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(bh1770_suspend, bh1770_resume)
13768c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(bh1770_runtime_suspend, bh1770_runtime_resume, NULL)
13778c2ecf20Sopenharmony_ci};
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_cistatic struct i2c_driver bh1770_driver = {
13808c2ecf20Sopenharmony_ci	.driver	 = {
13818c2ecf20Sopenharmony_ci		.name	= "bh1770glc",
13828c2ecf20Sopenharmony_ci		.pm	= &bh1770_pm_ops,
13838c2ecf20Sopenharmony_ci	},
13848c2ecf20Sopenharmony_ci	.probe	  = bh1770_probe,
13858c2ecf20Sopenharmony_ci	.remove	  = bh1770_remove,
13868c2ecf20Sopenharmony_ci	.id_table = bh1770_id,
13878c2ecf20Sopenharmony_ci};
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_cimodule_i2c_driver(bh1770_driver);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor");
13928c2ecf20Sopenharmony_ciMODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
13938c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1394