1190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
2190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver.
3190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Chip is combined proximity and ambient light sensor.
4190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
5190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
7190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Contact: Samu Onkalo <samu.p.onkalo@nokia.com>
8190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
9190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * This program is free software; you can redistribute it and/or
10190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * modify it under the terms of the GNU General Public License
11190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * version 2 as published by the Free Software Foundation.
12190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
13190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * This program is distributed in the hope that it will be useful, but
14190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * WITHOUT ANY WARRANTY; without even the implied warranty of
15190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
16190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * General Public License for more details.
17190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
18190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * You should have received a copy of the GNU General Public License
19190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * along with this program; if not, write to the Free Software
20190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * 02110-1301 USA
22190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo *
23190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
24190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
25190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/kernel.h>
26190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/module.h>
27190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/i2c.h>
28190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/interrupt.h>
29190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/mutex.h>
30190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/i2c/bh1770glc.h>
31190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/regulator/consumer.h>
32190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/pm_runtime.h>
33190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/workqueue.h>
34190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/delay.h>
35190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/wait.h>
36190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#include <linux/slab.h>
37190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
38190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_CONTROL	0x80 /* ALS operation mode control */
39190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_CONTROL	0x81 /* PS operation mode control */
40190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_I_LED		0x82 /* active LED and LED1, LED2 current */
41190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_I_LED3		0x83 /* LED3 current setting */
42190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_PS_MEAS	0x84 /* Forced mode trigger */
43190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_MEAS_RATE	0x85 /* PS meas. rate at stand alone mode */
44190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_MEAS_RATE	0x86 /* ALS meas. rate at stand alone mode */
45190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PART_ID		0x8a /* Part number and revision ID */
46190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_MANUFACT_ID	0x8b /* Manufacturerer ID */
47190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_DATA_0	0x8c /* ALS DATA low byte */
48190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_DATA_1	0x8d /* ALS DATA high byte */
49190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_PS_STATUS	0x8e /* Measurement data and int status */
50190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_DATA_LED1	0x8f /* PS data from LED1 */
51190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_DATA_LED2	0x90 /* PS data from LED2 */
52190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_DATA_LED3	0x91 /* PS data from LED3 */
53190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INTERRUPT	0x92 /* Interrupt setting */
54190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_TH_LED1	0x93 /* PS interrupt threshold for LED1 */
55190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_TH_LED2	0x94 /* PS interrupt threshold for LED2 */
56190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_TH_LED3	0x95 /* PS interrupt threshold for LED3 */
57190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_TH_UP_0	0x96 /* ALS upper threshold low byte */
58190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_TH_UP_1	0x97 /* ALS upper threshold high byte */
59190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_TH_LOW_0	0x98 /* ALS lower threshold low byte */
60190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_TH_LOW_1	0x99 /* ALS lower threshold high byte */
61190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
62190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* MANUFACT_ID */
63190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_MANUFACT_ROHM	0x01
64190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_MANUFACT_OSRAM	0x03
65190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
66190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* PART_ID */
67190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PART		0x90
68190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PART_MASK	0xf0
69190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_REV_MASK		0x0f
70190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_REV_SHIFT	0
71190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_REV_0		0x00
72190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_REV_1		0x01
73190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
74190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Operating modes for both */
75190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_STANDBY		0x00
76190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_FORCED		0x02
77190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_STANDALONE	0x03
78190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_SWRESET		(0x01 << 2)
79190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
80190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PS_TRIG_MEAS	(1 << 0)
81190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ALS_TRIG_MEAS	(1 << 1)
82190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
83190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Interrupt control */
84190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_OUTPUT_MODE	(1 << 3) /* 0 = latched */
85190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_POLARITY	(1 << 2) /* 1 = active high */
86190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_ALS_ENA	(1 << 1)
87190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_PS_ENA	(1 << 0)
88190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
89190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Interrupt status */
90190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED1_DATA	(1 << 0)
91190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED1_INT	(1 << 1)
92190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED2_DATA	(1 << 2)
93190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED2_INT	(1 << 3)
94190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED3_DATA	(1 << 4)
95190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LED3_INT	(1 << 5)
96190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_LEDS_INT	((1 << 1) | (1 << 3) | (1 << 5))
97190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_ALS_DATA	(1 << 6)
98190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_INT_ALS_INT	(1 << 7)
99190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
100190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Led channels */
101190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LED1		0x00
102190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
103190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_DISABLE		0
104190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_ENABLE		1
105190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_CHANNELS	1
106190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
107190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_DEFAULT_RATE	1 /* Index to lux rate table */
108190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_DEFAULT_RATE 1 /* Direct HW value =~ 50Hz */
109190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_DEF_RATE_THRESH 6 /* Direct HW value =~ 5 Hz */
110190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_STARTUP_DELAY	50
111190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_RESET_TIME	10
112190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_TIMEOUT		2100 /* Timeout in 2.1 seconds */
113190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
114190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_RANGE	65535
115190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_RANGE	255
116190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_COEF_SCALER	1024
117190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_CALIB_SCALER	8192
118190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_NEUTRAL_CALIB_VALUE (1 * BH1770_CALIB_SCALER)
119190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_DEF_THRES	1000
120190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_DEF_THRES	70
121190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_DEF_ABS_THRES   100
122190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_DEFAULT_PERSISTENCE  10
123190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_PROX_MAX_PERSISTENCE 50
124190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_GA_SCALE	16384
125190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_CF_SCALE	2048 /* CF ChipFactor */
126190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_NEUTRAL_CF	BH1770_LUX_CF_SCALE
127190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define BH1770_LUX_CORR_SCALE	4096
128190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
129190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define PROX_ABOVE_THRESHOLD	1
130190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define PROX_BELOW_THRESHOLD	0
131190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
132190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define PROX_IGNORE_LUX_LIMIT	500
133190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
134190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostruct bh1770_chip {
135190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_platform_data	*pdata;
136190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	char				chipname[10];
137190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8				revision;
138190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client		*client;
139190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct regulator_bulk_data	regs[2];
140190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct mutex			mutex; /* avoid parallel access */
141190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	wait_queue_head_t		wait;
142190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
143190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bool			int_mode_prox;
144190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bool			int_mode_lux;
145190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct delayed_work	prox_work;
146190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32	lux_cf; /* Chip specific factor */
147190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32	lux_ga;
148190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32	lux_calib;
149190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int	lux_rate_index;
150190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32	lux_corr;
151190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	lux_data_raw;
152190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	lux_threshold_hi;
153190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	lux_threshold_lo;
154190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	lux_thres_hi_onchip;
155190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	lux_thres_lo_onchip;
156190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bool	lux_wait_result;
157190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
158190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int	prox_enable_count;
159190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	prox_coef;
160190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16	prox_const;
161190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int	prox_rate;
162190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int	prox_rate_threshold;
163190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_persistence;
164190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_persistence_counter;
165190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_data;
166190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_threshold;
167190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_threshold_hw;
168190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bool	prox_force_update;
169190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_abs_thres;
170190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8	prox_led;
171190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
172190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
173190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const char reg_vcc[] = "Vcc";
174190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const char reg_vleds[] = "Vleds";
175190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
176190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
177190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Supported stand alone rates in ms from chip data sheet
178190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * {10, 20, 30, 40, 70, 100, 200, 500, 1000, 2000};
179190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
180190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2};
181190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500};
182190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
183190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Supported IR-led currents in mA */
184190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200};
185190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
186190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
187190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Supported stand alone rates in ms from chip data sheet
188190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * {100, 200, 500, 1000, 2000};
189190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
190190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const s16 lux_rates_hz[] = {10, 5, 2, 1, 0};
191190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
192190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
193190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * interrupt control functions are called while keeping chip->mutex
194190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * excluding module probe / remove
195190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
196190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline int bh1770_lux_interrupt_control(struct bh1770_chip *chip,
197190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					int lux)
198190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
199190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->int_mode_lux = lux;
200190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Set interrupt modes, interrupt active low, latched */
201190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i2c_smbus_write_byte_data(chip->client,
202190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_INTERRUPT,
203190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					(lux << 1) | chip->int_mode_prox);
204190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
205190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
206190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline int bh1770_prox_interrupt_control(struct bh1770_chip *chip,
207190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					int ps)
208190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
209190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->int_mode_prox = ps;
210190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i2c_smbus_write_byte_data(chip->client,
211190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_INTERRUPT,
212190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					(chip->int_mode_lux << 1) | (ps << 0));
213190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
214190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
215190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* chip->mutex is always kept here */
216190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_lux_rate(struct bh1770_chip *chip, int rate_index)
217190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
218190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* sysfs may call this when the chip is powered off */
219190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (pm_runtime_suspended(&chip->client->dev))
220190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
221190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
222190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Proper proximity response needs fastest lux rate (100ms) */
223190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->prox_enable_count)
224190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		rate_index = 0;
225190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
226190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i2c_smbus_write_byte_data(chip->client,
227190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_ALS_MEAS_RATE,
228190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					rate_index);
229190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
230190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
231190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_prox_rate(struct bh1770_chip *chip, int mode)
232190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
233190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int rate;
234190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
235190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	rate = (mode == PROX_ABOVE_THRESHOLD) ?
236190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_rate_threshold : chip->prox_rate;
237190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
238190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i2c_smbus_write_byte_data(chip->client,
239190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_PS_MEAS_RATE,
240190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					rate);
241190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
242190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
243190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* InfraredLED is controlled by the chip during proximity scanning */
244190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline int bh1770_led_cfg(struct bh1770_chip *chip)
245190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
246190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* LED cfg, current for leds 1 and 2 */
247190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i2c_smbus_write_byte_data(chip->client,
248190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_I_LED,
249190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					(BH1770_LED1 << 6) |
250190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					(BH1770_LED_5mA << 3) |
251190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					chip->prox_led);
252190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
253190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
254190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
255190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Following two functions converts raw ps values from HW to normalized
256190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * values. Purpose is to compensate differences between different sensor
257190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * versions and variants so that result means about the same between
258190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * versions.
259190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
260190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline u8 bh1770_psraw_to_adjusted(struct bh1770_chip *chip, u8 psraw)
261190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
262190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16 adjusted;
263190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	adjusted = (u16)(((u32)(psraw + chip->prox_const) * chip->prox_coef) /
264190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		BH1770_COEF_SCALER);
265190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (adjusted > BH1770_PROX_RANGE)
266190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		adjusted = BH1770_PROX_RANGE;
267190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return adjusted;
268190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
269190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
270190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline u8 bh1770_psadjusted_to_raw(struct bh1770_chip *chip, u8 ps)
271190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
272190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16 raw;
273190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
274190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	raw = (((u32)ps * BH1770_COEF_SCALER) / chip->prox_coef);
275190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (raw > chip->prox_const)
276190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		raw = raw - chip->prox_const;
277190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else
278190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		raw = 0;
279190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return raw;
280190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
281190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
282190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
283190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Following two functions converts raw lux values from HW to normalized
284190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * values. Purpose is to compensate differences between different sensor
285190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * versions and variants so that result means about the same between
286190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * versions. Chip->mutex is kept when this is called.
287190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
288190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_prox_set_threshold(struct bh1770_chip *chip)
289190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
290190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8 tmp = 0;
291190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
292190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* sysfs may call this when the chip is powered off */
293190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (pm_runtime_suspended(&chip->client->dev))
294190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
295190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
296190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	tmp = bh1770_psadjusted_to_raw(chip, chip->prox_threshold);
297190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_threshold_hw = tmp;
298190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
299190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return	i2c_smbus_write_byte_data(chip->client, BH1770_PS_TH_LED1,
300190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					tmp);
301190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
302190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
303190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline u16 bh1770_lux_raw_to_adjusted(struct bh1770_chip *chip, u16 raw)
304190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
305190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32 lux;
306190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	lux = ((u32)raw * chip->lux_corr) / BH1770_LUX_CORR_SCALE;
307190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return min(lux, (u32)BH1770_LUX_RANGE);
308190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
309190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
310190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic inline u16 bh1770_lux_adjusted_to_raw(struct bh1770_chip *chip,
311190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					u16 adjusted)
312190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
313190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return (u32)adjusted * BH1770_LUX_CORR_SCALE / chip->lux_corr;
314190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
315190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
316190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* chip->mutex is kept when this is called */
317190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_lux_update_thresholds(struct bh1770_chip *chip,
318190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					u16 threshold_hi, u16 threshold_lo)
319190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
320190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8 data[4];
321190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret;
322190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
323190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* sysfs may call this when the chip is powered off */
324190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (pm_runtime_suspended(&chip->client->dev))
325190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
326190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
327190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
328190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Compensate threshold values with the correction factors if not
329190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * set to minimum or maximum.
330190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Min & max values disables interrupts.
331190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
332190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (threshold_hi != BH1770_LUX_RANGE && threshold_hi != 0)
333190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		threshold_hi = bh1770_lux_adjusted_to_raw(chip, threshold_hi);
334190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
335190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (threshold_lo != BH1770_LUX_RANGE && threshold_lo != 0)
336190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		threshold_lo = bh1770_lux_adjusted_to_raw(chip, threshold_lo);
337190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
338190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->lux_thres_hi_onchip == threshold_hi &&
339190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	    chip->lux_thres_lo_onchip == threshold_lo)
340190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
341190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
342190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_thres_hi_onchip = threshold_hi;
343190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_thres_lo_onchip = threshold_lo;
344190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
345190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	data[0] = threshold_hi;
346190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	data[1] = threshold_hi >> 8;
347190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	data[2] = threshold_lo;
348190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	data[3] = threshold_lo >> 8;
349190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
350190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_write_i2c_block_data(chip->client,
351190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_ALS_TH_UP_0,
352190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					ARRAY_SIZE(data),
353190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					data);
354190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
355190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
356190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
357190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_lux_get_result(struct bh1770_chip *chip)
358190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
359190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u16 data;
360190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret;
361190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
362190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_0);
363190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
364190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
365190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
366190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	data = ret & 0xff;
367190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_1);
368190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
369190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
370190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
371190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_data_raw = data | ((ret & 0xff) << 8);
372190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
373190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
374190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
375190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
376190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* Calculate correction value which contains chip and device specific parts */
377190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic u32 bh1770_get_corr_value(struct bh1770_chip *chip)
378190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
379190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32 tmp;
380190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Impact of glass attenuation correction */
381190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	tmp = (BH1770_LUX_CORR_SCALE * chip->lux_ga) / BH1770_LUX_GA_SCALE;
382190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Impact of chip factor correction */
383190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	tmp = (tmp * chip->lux_cf) / BH1770_LUX_CF_SCALE;
384190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Impact of Device specific calibration correction */
385190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	tmp = (tmp * chip->lux_calib) / BH1770_CALIB_SCALER;
386190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return tmp;
387190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
388190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
389190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_lux_read_result(struct bh1770_chip *chip)
390190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
391190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_lux_get_result(chip);
392190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return bh1770_lux_raw_to_adjusted(chip, chip->lux_data_raw);
393190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
394190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
395190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
396190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * Chip on / off functions are called while keeping mutex except probe
397190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * or remove phase
398190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
399190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_chip_on(struct bh1770_chip *chip)
400190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
401190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
402190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					chip->regs);
403190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
404190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
405190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
406190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
407190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
408190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Reset the chip */
409190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client, BH1770_ALS_CONTROL,
410190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				BH1770_SWRESET);
411190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	usleep_range(BH1770_RESET_TIME, BH1770_RESET_TIME * 2);
412190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
413190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
414190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * ALS is started always since proximity needs als results
415190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * for realibility estimation.
416190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Let's assume dark until the first ALS measurement is ready.
417190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
418190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_data_raw = 0;
419190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_data = 0;
420190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_write_byte_data(chip->client,
421190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_ALS_CONTROL, BH1770_STANDALONE);
422190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
423190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Assume reset defaults */
424190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_thres_hi_onchip = BH1770_LUX_RANGE;
425190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_thres_lo_onchip = 0;
426190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
427190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
428190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
429190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
430190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic void bh1770_chip_off(struct bh1770_chip *chip)
431190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
432190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client,
433190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_INTERRUPT, BH1770_DISABLE);
434190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client,
435190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				BH1770_ALS_CONTROL, BH1770_STANDBY);
436190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client,
437190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				BH1770_PS_CONTROL, BH1770_STANDBY);
438190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
439190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
440190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
441190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* chip->mutex is kept when this is called */
442190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_prox_mode_control(struct bh1770_chip *chip)
443190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
444190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->prox_enable_count) {
445190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_force_update = true; /* Force immediate update */
446190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
447190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_lux_rate(chip, chip->lux_rate_index);
448190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_set_threshold(chip);
449190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_led_cfg(chip);
450190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_rate(chip, PROX_BELOW_THRESHOLD);
451190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_interrupt_control(chip, BH1770_ENABLE);
452190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		i2c_smbus_write_byte_data(chip->client,
453190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_PS_CONTROL, BH1770_STANDALONE);
454190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	} else {
455190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_data = 0;
456190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_lux_rate(chip, chip->lux_rate_index);
457190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_interrupt_control(chip, BH1770_DISABLE);
458190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		i2c_smbus_write_byte_data(chip->client,
459190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_PS_CONTROL, BH1770_STANDBY);
460190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
461190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
462190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
463190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
464190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* chip->mutex is kept when this is called */
465190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_prox_read_result(struct bh1770_chip *chip)
466190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
467190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret;
468190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bool above;
469190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8 mode;
470190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
471190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_read_byte_data(chip->client, BH1770_PS_DATA_LED1);
472190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
473190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto out;
474190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
475190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret > chip->prox_threshold_hw)
476190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		above = true;
477190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else
478190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		above = false;
479190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
480190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
481190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * when ALS levels goes above limit, proximity result may be
482190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * false proximity. Thus ignore the result. With real proximity
483190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * there is a shadow causing low als levels.
484190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
485190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->lux_data_raw > PROX_IGNORE_LUX_LIMIT)
486190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = 0;
487190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
488190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_data = bh1770_psraw_to_adjusted(chip, ret);
489190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
490190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Strong proximity level or force mode requires immediate response */
491190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->prox_data >= chip->prox_abs_thres ||
492190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	    chip->prox_force_update)
493190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_persistence_counter = chip->prox_persistence;
494190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
495190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_force_update = false;
496190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
497190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Persistence filttering to reduce false proximity events */
498190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (likely(above)) {
499190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (chip->prox_persistence_counter < chip->prox_persistence) {
500190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			chip->prox_persistence_counter++;
501190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			ret = -ENODATA;
502190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		} else {
503190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			mode = PROX_ABOVE_THRESHOLD;
504190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			ret = 0;
505190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		}
506190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	} else {
507190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_persistence_counter = 0;
508190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		mode = PROX_BELOW_THRESHOLD;
509190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_data = 0;
510190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = 0;
511190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
512190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
513190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Set proximity detection rate based on above or below value */
514190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret == 0) {
515190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_rate(chip, mode);
516190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		sysfs_notify(&chip->client->dev.kobj, NULL, "prox0_raw");
517190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
518190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkaloout:
519190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
520190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
521190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
522190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_detect(struct bh1770_chip *chip)
523190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
524190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client *client = chip->client;
525190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	s32 ret;
526190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u8 manu, part;
527190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
528190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_read_byte_data(client, BH1770_MANUFACT_ID);
529190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
530190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto error;
531190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	manu = (u8)ret;
532190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
533190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = i2c_smbus_read_byte_data(client, BH1770_PART_ID);
534190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
535190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto error;
536190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	part = (u8)ret;
537190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
538190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->revision = (part & BH1770_REV_MASK) >> BH1770_REV_SHIFT;
539190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_coef = BH1770_COEF_SCALER;
540190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_const = 0;
541190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_cf = BH1770_NEUTRAL_CF;
542190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
543190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if ((manu == BH1770_MANUFACT_ROHM) &&
544190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	    ((part & BH1770_PART_MASK) == BH1770_PART)) {
545190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		snprintf(chip->chipname, sizeof(chip->chipname), "BH1770GLC");
546190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
547190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
548190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
549190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if ((manu == BH1770_MANUFACT_OSRAM) &&
550190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	    ((part & BH1770_PART_MASK) == BH1770_PART)) {
551190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		snprintf(chip->chipname, sizeof(chip->chipname), "SFH7770");
552190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/* Values selected by comparing different versions */
553190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_coef = 819; /* 0.8 * BH1770_COEF_SCALER */
554190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_const = 40;
555190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return 0;
556190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
557190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
558190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = -ENODEV;
559190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkaloerror:
560190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	dev_dbg(&client->dev, "BH1770 or SFH7770 not found\n");
561190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
562190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
563190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
564190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
565190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/*
566190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * This work is re-scheduled at every proximity interrupt.
567190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * If this work is running, it means that there hasn't been any
568190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * proximity interrupt in time. Situation is handled as no-proximity.
569190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * It would be nice to have low-threshold interrupt or interrupt
570190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * when measurement and hi-threshold are both 0. But neither of those exists.
571190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo * This is a workaroud for missing HW feature.
572190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo */
573190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
574190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic void bh1770_prox_work(struct work_struct *work)
575190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
576190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =
577190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		container_of(work, struct bh1770_chip, prox_work.work);
578190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
579190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
580190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_prox_read_result(chip);
581190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
582190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
583190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
584190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo/* This is threaded irq handler */
585190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic irqreturn_t bh1770_irq(int irq, void *data)
586190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
587190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = data;
588190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int status;
589190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int rate = 0;
590190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
591190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
592190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	status = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_PS_STATUS);
593190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
594190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Acknowledge interrupt by reading this register */
595190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_read_byte_data(chip->client, BH1770_INTERRUPT);
596190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
597190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
598190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Check if there is fresh data available for als.
599190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * If this is the very first data, update thresholds after that.
600190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
601190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (status & BH1770_INT_ALS_DATA) {
602190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_lux_get_result(chip);
603190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (unlikely(chip->lux_wait_result)) {
604190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			chip->lux_wait_result = false;
605190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			wake_up(&chip->wait);
606190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			bh1770_lux_update_thresholds(chip,
607190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						chip->lux_threshold_hi,
608190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						chip->lux_threshold_lo);
609190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		}
610190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
611190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
612190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Disable interrupt logic to guarantee acknowledgement */
613190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
614190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  (0 << 1) | (0 << 0));
615190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
616190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if ((status & BH1770_INT_ALS_INT))
617190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		sysfs_notify(&chip->client->dev.kobj, NULL, "lux0_input");
618190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
619190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->int_mode_prox && (status & BH1770_INT_LEDS_INT)) {
620190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		rate = prox_rates_ms[chip->prox_rate_threshold];
621190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_read_result(chip);
622190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
623190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
624190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Re-enable interrupt logic */
625190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT,
626190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  (chip->int_mode_lux << 1) |
627190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  (chip->int_mode_prox << 0));
628190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
629190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
630190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
631190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Can't cancel work while keeping mutex since the work uses the
632190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * same mutex.
633190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
634190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (rate) {
635190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/*
636190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 * Simulate missing no-proximity interrupt 50ms after the
637190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 * next expected interrupt time.
638190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 */
639190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		cancel_delayed_work_sync(&chip->prox_work);
640190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		schedule_delayed_work(&chip->prox_work,
641190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				msecs_to_jiffies(rate + 50));
642190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
643190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return IRQ_HANDLED;
644190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
645190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
646190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_power_state_store(struct device *dev,
647190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      struct device_attribute *attr,
648190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      const char *buf, size_t count)
649190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
650190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
651190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
652aec04288904a7308f2900926902040e7a69ae2beDan Carpenter	ssize_t ret;
653190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
654190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
655190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
656190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
657190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
658190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (value) {
659190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		pm_runtime_get_sync(dev);
660190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
661190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = bh1770_lux_rate(chip, chip->lux_rate_index);
662aec04288904a7308f2900926902040e7a69ae2beDan Carpenter		if (ret < 0) {
663aec04288904a7308f2900926902040e7a69ae2beDan Carpenter			pm_runtime_put(dev);
664aec04288904a7308f2900926902040e7a69ae2beDan Carpenter			goto leave;
665aec04288904a7308f2900926902040e7a69ae2beDan Carpenter		}
666190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
667aec04288904a7308f2900926902040e7a69ae2beDan Carpenter		ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
668190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (ret < 0) {
669190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			pm_runtime_put(dev);
670190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			goto leave;
671190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		}
672190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
673190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/* This causes interrupt after the next measurement cycle */
674190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
675190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_LUX_DEF_THRES);
676190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/* Inform that we are waiting for a result from ALS */
677190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->lux_wait_result = true;
678190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_mode_control(chip);
679190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	} else if (!pm_runtime_suspended(dev)) {
680190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		pm_runtime_put(dev);
681190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
682190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = count;
683190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkaloleave:
684190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
685190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
686190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
687190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
688190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_power_state_show(struct device *dev,
689190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
690190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
691190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", !pm_runtime_suspended(dev));
692190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
693190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
694190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_lux_result_show(struct device *dev,
695190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
696190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
697190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
698190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ssize_t ret;
699190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	long timeout;
700190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
701190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (pm_runtime_suspended(dev))
702190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EIO; /* Chip is not enabled at all */
703190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
704190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	timeout = wait_event_interruptible_timeout(chip->wait,
705190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					!chip->lux_wait_result,
706190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					msecs_to_jiffies(BH1770_TIMEOUT));
707190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!timeout)
708190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EIO;
709190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
710190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
711190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = sprintf(buf, "%d\n", bh1770_lux_read_result(chip));
712190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
713190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
714190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
715190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
716190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
717190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_lux_range_show(struct device *dev,
718190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
719190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
720190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", BH1770_LUX_RANGE);
721190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
722190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
723190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_enable_store(struct device *dev,
724190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      struct device_attribute *attr,
725190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      const char *buf, size_t count)
726190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
727190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
728190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
729190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
730190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
731190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
732190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
733190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
734190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Assume no proximity. Sensor will tell real state soon */
735190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!chip->prox_enable_count)
736190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_data = 0;
737190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
738190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (value)
739190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_enable_count++;
740190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else if (chip->prox_enable_count > 0)
741190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->prox_enable_count--;
742190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else
743190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto leave;
744190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
745190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Run control only when chip is powered on */
746190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!pm_runtime_suspended(dev))
747190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_mode_control(chip);
748190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkaloleave:
749190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
750190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return count;
751190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
752190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
753190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_enable_show(struct device *dev,
754190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
755190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
756190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
757190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ssize_t len;
758190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
759190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
760190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	len = sprintf(buf, "%d\n", chip->prox_enable_count);
761190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
762190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
763190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
764190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
765190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_result_show(struct device *dev,
766190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
767190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
768190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
769190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ssize_t ret;
770190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
771190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
772190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->prox_enable_count && !pm_runtime_suspended(dev))
773190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = sprintf(buf, "%d\n", chip->prox_data);
774190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else
775190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = -EIO;
776190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
777190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
778190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
779190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
780190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_range_show(struct device *dev,
781190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
782190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
783190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", BH1770_PROX_RANGE);
784190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
785190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
786190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_prox_rate_avail(struct device *dev,
787190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
788190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
789190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int i;
790190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int pos = 0;
791190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	for (i = 0; i < ARRAY_SIZE(prox_rates_hz); i++)
792190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		pos += sprintf(buf + pos, "%d ", prox_rates_hz[i]);
793190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	sprintf(buf + pos - 1, "\n");
794190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return pos;
795190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
796190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
797190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_prox_rate_above(struct device *dev,
798190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
799190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
800190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
801190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate_threshold]);
802190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
803190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
804190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_prox_rate_below(struct device *dev,
805190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
806190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
807190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
808190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate]);
809190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
810190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
811190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_prox_rate_validate(int rate)
812190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
813190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int i;
814190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
815190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	for (i = 0; i < ARRAY_SIZE(prox_rates_hz) - 1; i++)
816190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (rate >= prox_rates_hz[i])
817190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			break;
818190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return i;
819190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
820190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
821190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_prox_rate_above(struct device *dev,
822190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					struct device_attribute *attr,
823190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					const char *buf, size_t count)
824190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
825190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
826190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
827190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
828190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
829190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
830190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
831190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
832190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_rate_threshold = bh1770_prox_rate_validate(value);
833190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
834190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return count;
835190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
836190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
837190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_prox_rate_below(struct device *dev,
838190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					struct device_attribute *attr,
839190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					const char *buf, size_t count)
840190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
841190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
842190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
843190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
844190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
845190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
846190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
847190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
848190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_rate = bh1770_prox_rate_validate(value);
849190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
850190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return count;
851190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
852190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
853190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_prox_thres(struct device *dev,
854190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
855190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
856190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
857190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", chip->prox_threshold);
858190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
859190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
860190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_prox_thres(struct device *dev,
861190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      struct device_attribute *attr,
862190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      const char *buf, size_t count)
863190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
864190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
865190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
866190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret;
867190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
868190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
869190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
870190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (value > BH1770_PROX_RANGE)
871190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
872190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
873190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
874190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_threshold = value;
875190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = bh1770_prox_set_threshold(chip);
876190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
877190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
878190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
879190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return count;
880190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
881190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
882190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_persistence_show(struct device *dev,
883190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				 struct device_attribute *attr, char *buf)
884190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
885190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
886190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
887190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%u\n", chip->prox_persistence);
888190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
889190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
890190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_persistence_store(struct device *dev,
891190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				struct device_attribute *attr,
892190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				const char *buf, size_t len)
893190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
894190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
895190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
896190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
897190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
898190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
899190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
900190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (value > BH1770_PROX_MAX_PERSISTENCE)
901190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
902190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
903190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_persistence = value;
904190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
905190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
906190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
907190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
908190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_abs_thres_show(struct device *dev,
909190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				 struct device_attribute *attr, char *buf)
910190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
911190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
912190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%u\n", chip->prox_abs_thres);
913190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
914190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
915190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_prox_abs_thres_store(struct device *dev,
916190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				struct device_attribute *attr,
917190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				const char *buf, size_t len)
918190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
919190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
920190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
921190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
922190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
923190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
924190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
925190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (value > BH1770_PROX_RANGE)
926190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
927190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
928190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_abs_thres = value;
929190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
930190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
931190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
932190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
933190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_chip_id_show(struct device *dev,
934190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
935190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
936190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
937190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%s rev %d\n", chip->chipname, chip->revision);
938190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
939190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
940190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_lux_calib_default_show(struct device *dev,
941190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				 struct device_attribute *attr, char *buf)
942190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
943190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%u\n", BH1770_CALIB_SCALER);
944190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
945190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
946190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_lux_calib_show(struct device *dev,
947190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				 struct device_attribute *attr, char *buf)
948190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
949190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
950190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ssize_t len;
951190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
952190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
953190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	len = sprintf(buf, "%u\n", chip->lux_calib);
954190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
955190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
956190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
957190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
958190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_lux_calib_store(struct device *dev,
959190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  struct device_attribute *attr,
960190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  const char *buf, size_t len)
961190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
962190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = dev_get_drvdata(dev);
963190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long value;
964190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32 old_calib;
965190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	u32 new_corr;
966190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
967190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &value))
968190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
969190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
970190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
971190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	old_calib = chip->lux_calib;
972190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_calib = value;
973190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	new_corr = bh1770_get_corr_value(chip);
974190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (new_corr == 0) {
975190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->lux_calib = old_calib;
976190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		mutex_unlock(&chip->mutex);
977190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
978190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
979190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_corr = new_corr;
980190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Refresh thresholds on HW after changing correction value */
981190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_lux_update_thresholds(chip, chip->lux_threshold_hi,
982190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				chip->lux_threshold_lo);
983190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
984190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
985190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
986190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
987190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
988190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
989190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_lux_rate_avail(struct device *dev,
990190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
991190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
992190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int i;
993190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int pos = 0;
994190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	for (i = 0; i < ARRAY_SIZE(lux_rates_hz); i++)
995190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		pos += sprintf(buf + pos, "%d ", lux_rates_hz[i]);
996190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	sprintf(buf + pos - 1, "\n");
997190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return pos;
998190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
999190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1000190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_lux_rate(struct device *dev,
1001190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
1002190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1003190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1004190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", lux_rates_hz[chip->lux_rate_index]);
1005190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1006190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1007190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_lux_rate(struct device *dev,
1008190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      struct device_attribute *attr,
1009190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				      const char *buf, size_t count)
1010190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1011190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1012190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long rate_hz;
1013190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret, i;
1014190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1015190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &rate_hz))
1016190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
1017190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1018190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	for (i = 0; i < ARRAY_SIZE(lux_rates_hz) - 1; i++)
1019190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (rate_hz >= lux_rates_hz[i])
1020190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			break;
1021190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1022190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
1023190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_rate_index = i;
1024190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	ret = bh1770_lux_rate(chip, i);
1025190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
1026190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1027190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
1028190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
1029190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1030190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return count;
1031190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1032190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1033190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_lux_thresh_above(struct device *dev,
1034190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
1035190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1036190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1037190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", chip->lux_threshold_hi);
1038190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1039190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1040190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_get_lux_thresh_below(struct device *dev,
1041190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				   struct device_attribute *attr, char *buf)
1042190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1043190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1044190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return sprintf(buf, "%d\n", chip->lux_threshold_lo);
1045190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1046190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1047190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_lux_thresh(struct bh1770_chip *chip, u16 *target,
1048190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				const char *buf)
1049190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1050190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret = 0;
1051190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	unsigned long thresh;
1052190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1053190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (strict_strtoul(buf, 0, &thresh))
1054190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
1055190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1056190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (thresh > BH1770_LUX_RANGE)
1057190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -EINVAL;
1058190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1059190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_lock(&chip->mutex);
1060190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	*target = thresh;
1061190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
1062190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Don't update values in HW if we are still waiting for
1063190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * first interrupt to come after device handle open call.
1064190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
1065190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!chip->lux_wait_result)
1066190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = bh1770_lux_update_thresholds(chip,
1067190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						chip->lux_threshold_hi,
1068190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						chip->lux_threshold_lo);
1069190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_unlock(&chip->mutex);
1070190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
1071190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1072190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1073190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1074190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_lux_thresh_above(struct device *dev,
1075190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  struct device_attribute *attr,
1076190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  const char *buf, size_t len)
1077190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1078190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1079190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_hi, buf);
1080190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
1081190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
1082190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
1083190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1084190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1085190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic ssize_t bh1770_set_lux_thresh_below(struct device *dev,
1086190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  struct device_attribute *attr,
1087190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				  const char *buf, size_t len)
1088190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1089190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip =  dev_get_drvdata(dev);
1090190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_lo, buf);
1091190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (ret < 0)
1092190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return ret;
1093190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return len;
1094190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1095190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1096190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, bh1770_prox_enable_show,
1097190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_prox_enable_store);
1098190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_thresh_above1_value, S_IRUGO | S_IWUSR,
1099190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_prox_abs_thres_show,
1100190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_prox_abs_thres_store);
1101190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_thresh_above0_value, S_IRUGO | S_IWUSR,
1102190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_get_prox_thres,
1103190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_prox_thres);
1104190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_raw, S_IRUGO, bh1770_prox_result_show, NULL);
1105190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_sensor_range, S_IRUGO, bh1770_prox_range_show, NULL);
1106190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_thresh_above_count, S_IRUGO | S_IWUSR,
1107190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_prox_persistence_show,
1108190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_prox_persistence_store);
1109190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_rate_above, S_IRUGO | S_IWUSR,
1110190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_get_prox_rate_above,
1111190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_prox_rate_above);
1112190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_rate_below, S_IRUGO | S_IWUSR,
1113190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_get_prox_rate_below,
1114190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_prox_rate_below);
1115190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(prox0_rate_avail, S_IRUGO, bh1770_get_prox_rate_avail, NULL);
1116190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1117190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, bh1770_lux_calib_show,
1118190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_lux_calib_store);
1119190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_calibscale_default, S_IRUGO,
1120190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_lux_calib_default_show,
1121190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						NULL);
1122190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_input, S_IRUGO, bh1770_lux_result_show, NULL);
1123190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_sensor_range, S_IRUGO, bh1770_lux_range_show, NULL);
1124190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, bh1770_get_lux_rate,
1125190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_lux_rate);
1126190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_rate_avail, S_IRUGO, bh1770_get_lux_rate_avail, NULL);
1127190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR,
1128190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_get_lux_thresh_above,
1129190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_lux_thresh_above);
1130190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR,
1131190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_get_lux_thresh_below,
1132190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						bh1770_set_lux_thresh_below);
1133190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(chip_id, S_IRUGO, bh1770_chip_id_show, NULL);
1134190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, bh1770_power_state_show,
1135190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo						 bh1770_power_state_store);
1136190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1137190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1138190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic struct attribute *sysfs_attrs[] = {
1139190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_calibscale.attr,
1140190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_calibscale_default.attr,
1141190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_input.attr,
1142190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_sensor_range.attr,
1143190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_rate.attr,
1144190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_rate_avail.attr,
1145190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_thresh_above_value.attr,
1146190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_lux0_thresh_below_value.attr,
1147190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_raw.attr,
1148190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_sensor_range.attr,
1149190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_raw_en.attr,
1150190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_thresh_above_count.attr,
1151190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_rate_above.attr,
1152190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_rate_below.attr,
1153190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_rate_avail.attr,
1154190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_thresh_above0_value.attr,
1155190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_prox0_thresh_above1_value.attr,
1156190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_chip_id.attr,
1157190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	&dev_attr_power_state.attr,
1158190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	NULL
1159190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
1160190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1161190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic struct attribute_group bh1770_attribute_group = {
1162190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	.attrs = sysfs_attrs
1163190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
1164190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1165190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int __devinit bh1770_probe(struct i2c_client *client,
1166190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				const struct i2c_device_id *id)
1167190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1168190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip;
1169190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int err;
1170190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1171190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip = kzalloc(sizeof *chip, GFP_KERNEL);
1172190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!chip)
1173190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		return -ENOMEM;
1174190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1175190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	i2c_set_clientdata(client, chip);
1176190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->client  = client;
1177190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1178190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	mutex_init(&chip->mutex);
1179190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	init_waitqueue_head(&chip->wait);
1180190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	INIT_DELAYED_WORK(&chip->prox_work, bh1770_prox_work);
1181190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1182190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (client->dev.platform_data == NULL) {
1183190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&client->dev, "platform data is mandatory\n");
1184190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		err = -EINVAL;
1185190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail1;
1186190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1187190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1188190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->pdata		= client->dev.platform_data;
1189190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_calib		= BH1770_LUX_NEUTRAL_CALIB_VALUE;
1190190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_rate_index	= BH1770_LUX_DEFAULT_RATE;
1191190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_threshold_lo	= BH1770_LUX_DEF_THRES;
1192190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_threshold_hi	= BH1770_LUX_DEF_THRES;
1193190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1194190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->pdata->glass_attenuation == 0)
1195190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->lux_ga = BH1770_NEUTRAL_GA;
1196190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	else
1197190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->lux_ga = chip->pdata->glass_attenuation;
1198190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1199190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_threshold	= BH1770_PROX_DEF_THRES;
1200190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_led		= chip->pdata->led_def_curr;
1201190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_abs_thres	= BH1770_PROX_DEF_ABS_THRES;
1202190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_persistence	= BH1770_DEFAULT_PERSISTENCE;
1203190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_rate_threshold = BH1770_PROX_DEF_RATE_THRESH;
1204190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_rate		= BH1770_PROX_DEFAULT_RATE;
1205190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->prox_data		= 0;
1206190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1207190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->regs[0].supply = reg_vcc;
1208190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->regs[1].supply = reg_vleds;
1209190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1210190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	err = regulator_bulk_get(&client->dev,
1211190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				 ARRAY_SIZE(chip->regs), chip->regs);
1212190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (err < 0) {
1213190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&client->dev, "Cannot get regulators\n");
1214190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail1;
1215190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1216190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1217190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
1218190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				chip->regs);
1219190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (err < 0) {
1220190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&client->dev, "Cannot enable regulators\n");
1221190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail2;
1222190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1223190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1224190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2);
1225190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	err = bh1770_detect(chip);
1226190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (err < 0)
1227190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail3;
1228190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1229190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/* Start chip */
1230190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_chip_on(chip);
1231190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	pm_runtime_set_active(&client->dev);
1232190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	pm_runtime_enable(&client->dev);
1233190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1234190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	chip->lux_corr = bh1770_get_corr_value(chip);
1235190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->lux_corr == 0) {
1236190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&client->dev, "Improper correction values\n");
1237190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		err = -EINVAL;
1238190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail3;
1239190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1240190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1241190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->pdata->setup_resources) {
1242190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		err = chip->pdata->setup_resources();
1243190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		if (err) {
1244190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			err = -EINVAL;
1245190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			goto fail3;
1246190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		}
1247190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1248190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1249190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	err = sysfs_create_group(&chip->client->dev.kobj,
1250190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				&bh1770_attribute_group);
1251190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (err < 0) {
1252190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&chip->client->dev, "Sysfs registration failed\n");
1253190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail4;
1254190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1255190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1256190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	/*
1257190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * Chip needs level triggered interrupt to work. However,
1258190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * level triggering doesn't work always correctly with power
1259190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 * management. Select both
1260190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	 */
1261190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	err = request_threaded_irq(client->irq, NULL,
1262190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				bh1770_irq,
1263190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				IRQF_TRIGGER_FALLING | IRQF_ONESHOT |
1264190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				IRQF_TRIGGER_LOW,
1265190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo				"bh1770", chip);
1266190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (err) {
1267190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		dev_err(&client->dev, "could not get IRQ %d\n",
1268190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			client->irq);
1269190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		goto fail5;
1270190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1271190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
1272190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return err;
1273190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalofail5:
1274190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	sysfs_remove_group(&chip->client->dev.kobj,
1275190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			&bh1770_attribute_group);
1276190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalofail4:
1277190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->pdata->release_resources)
1278190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->pdata->release_resources();
1279190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalofail3:
1280190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs);
1281190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalofail2:
1282190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
1283190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalofail1:
1284190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	kfree(chip);
1285190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return err;
1286190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1287190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1288190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int __devexit bh1770_remove(struct i2c_client *client)
1289190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1290190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = i2c_get_clientdata(client);
1291190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1292190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	free_irq(client->irq, chip);
1293190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1294190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	sysfs_remove_group(&chip->client->dev.kobj,
1295190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo			&bh1770_attribute_group);
1296190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1297190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (chip->pdata->release_resources)
1298190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->pdata->release_resources();
1299190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1300190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	cancel_delayed_work_sync(&chip->prox_work);
1301190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1302190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!pm_runtime_suspended(&client->dev))
1303190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_chip_off(chip);
1304190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1305190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	pm_runtime_disable(&client->dev);
1306190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	pm_runtime_set_suspended(&client->dev);
1307190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1308190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs);
1309190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	kfree(chip);
1310190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
1311190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1312190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1313190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#ifdef CONFIG_PM
1314190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_suspend(struct device *dev)
1315190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1316190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1317190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = i2c_get_clientdata(client);
1318190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1319190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_chip_off(chip);
1320190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1321190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
1322190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1323190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1324190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_resume(struct device *dev)
1325190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1326190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1327190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = i2c_get_clientdata(client);
1328190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	int ret = 0;
1329190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1330190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_chip_on(chip);
1331190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1332190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	if (!pm_runtime_suspended(dev)) {
1333190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/*
1334190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 * If we were enabled at suspend time, it is expected
1335190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 * everything works nice and smoothly
1336190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		 */
1337190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret = bh1770_lux_rate(chip, chip->lux_rate_index);
1338190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE);
1339190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1340190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/* This causes interrupt after the next measurement cycle */
1341190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES,
1342190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo					BH1770_LUX_DEF_THRES);
1343190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		/* Inform that we are waiting for a result from ALS */
1344190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		chip->lux_wait_result = true;
1345190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		bh1770_prox_mode_control(chip);
1346190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	}
1347190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return ret;
1348190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1349190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1350190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#else
1351190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define bh1770_suspend	NULL
1352190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define bh1770_shutdown NULL
1353190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#define bh1770_resume	NULL
1354190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#endif
1355190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1356190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#ifdef CONFIG_PM_RUNTIME
1357190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_runtime_suspend(struct device *dev)
1358190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1359190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1360190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = i2c_get_clientdata(client);
1361190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1362190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_chip_off(chip);
1363190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1364190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
1365190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1366190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1367190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic int bh1770_runtime_resume(struct device *dev)
1368190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo{
1369190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
1370190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	struct bh1770_chip *chip = i2c_get_clientdata(client);
1371190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1372190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	bh1770_chip_on(chip);
1373190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1374190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	return 0;
1375190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo}
1376190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo#endif
1377190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1378190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const struct i2c_device_id bh1770_id[] = {
1379190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	{"bh1770glc", 0 },
1380190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	{"sfh7770", 0 },
1381190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	{}
1382190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
1383190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1384190420ab34ab4c077c641893ac19f364cf3606e4Samu OnkaloMODULE_DEVICE_TABLE(i2c, bh1770_id);
1385190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1386190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic const struct dev_pm_ops bh1770_pm_ops = {
1387190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	SET_SYSTEM_SLEEP_PM_OPS(bh1770_suspend, bh1770_resume)
1388190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	SET_RUNTIME_PM_OPS(bh1770_runtime_suspend, bh1770_runtime_resume, NULL)
1389190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
1390190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1391190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalostatic struct i2c_driver bh1770_driver = {
1392190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	.driver	 = {
1393190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		.name	= "bh1770glc",
1394190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		.owner	= THIS_MODULE,
1395190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo		.pm	= &bh1770_pm_ops,
1396190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	},
1397190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	.probe	  = bh1770_probe,
1398190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	.remove	  = __devexit_p(bh1770_remove),
1399190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo	.id_table = bh1770_id,
1400190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo};
1401190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1402a64fe2ed76614d37abb6966a67f4f39d10efba3cAxel Linmodule_i2c_driver(bh1770_driver);
1403190420ab34ab4c077c641893ac19f364cf3606e4Samu Onkalo
1404190420ab34ab4c077c641893ac19f364cf3606e4Samu OnkaloMODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor");
1405190420ab34ab4c077c641893ac19f364cf3606e4Samu OnkaloMODULE_AUTHOR("Samu Onkalo, Nokia Corporation");
1406190420ab34ab4c077c641893ac19f364cf3606e4Samu OnkaloMODULE_LICENSE("GPL v2");
1407