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