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