From 6d7486d7a8eac8b459c91de4ab099385c16279e7 Mon Sep 17 00:00:00 2001 From: yanfei Date: Sun, 30 Sep 2018 14:21:04 +0800 Subject: [PATCH] (CR):[kane]:kernel:add cap sensor driver add cap sensor driver Change-Id: I10e1ba136c833d6b0214cb33463e7aeab90dd874 Signed-off-by: yanfei --- arch/arm64/boot/dts/exynos/wing-sensor.dtsi | 48 +- arch/arm64/configs/robusta2_evb_defconfig | 3 +- arch/arm64/configs/wing_defconfig | 3 +- drivers/input/misc/Kconfig | 7 + drivers/input/misc/Makefile | 1 + drivers/input/misc/sx933x.h | 755 ++++++++++++ drivers/input/misc/sx933x_sar.c | 1156 +++++++++++++++++++ drivers/regulator/s2mpu09-regulator.c | 1 + 8 files changed, 1955 insertions(+), 19 deletions(-) mode change 100644 => 100755 arch/arm64/configs/wing_defconfig create mode 100755 drivers/input/misc/sx933x.h create mode 100755 drivers/input/misc/sx933x_sar.c mode change 100644 => 100755 drivers/regulator/s2mpu09-regulator.c diff --git a/arch/arm64/boot/dts/exynos/wing-sensor.dtsi b/arch/arm64/boot/dts/exynos/wing-sensor.dtsi index 1bed4b98ea62..0ca6cf9f0482 100755 --- a/arch/arm64/boot/dts/exynos/wing-sensor.dtsi +++ b/arch/arm64/boot/dts/exynos/wing-sensor.dtsi @@ -21,24 +21,38 @@ status = "okay"; samsung,reset-before-trans; clock-frequency = <400000>; - sx9325@28 { - - compatible = "semtech,sx9325"; + sx933x@28 { + compatible = "Semtech,sx933x"; reg = <0x28>; - cap_vdd-supply = <&l3_reg>; - gpios = <&gpa2 6 0>; /* IRQ */ - pinctrl-names = "default"; - pinctrl-0 = <&cap_int_status>; - cap,use_channel = <0x0f>; - cap,use_channel_top = <0x00>; - cap,use_channel_bottom = <0x01>; - cap,raw_data_channel = <0x01>; - cap,scan_period = <0x02>; - reg_array_len = <5>; - reg_array_val = <0x36 0x1b 0x37 0x1b 0x4a 0x66 0x4b 0x00 0x4c 0x00>; - - - }; + Semtech,nirq-gpio = <&gpa2 6 0>; /* IRQ */ + pinctrl-names = "default"; + pinctrl-0 = <&cap_int_status>; + Semtech,button-flag = <0x15>; + Semtech,reg-num = <23>; + Semtech,reg-init = <0x8020 0x1F0000 + 0x8024 0x300008d7 /*again 6.6pf*/ + 0x8028 0x24928000 + 0x802C 0x300010d7 + 0x8030 0x24960000 + 0x8034 0x300010d7 + 0x8038 0x24B20000 + 0x803C 0x300004D4 + 0x8040 0x25920000 + 0x8044 0x300004D4 + 0x8048 0x2C920000 + 0x8054 0x02103010 /*ph0*/ + 0x8058 0x20600C00 + 0x805c 0x0 + 0x8064 0x00900000 /*5mm th*/ + 0x8070 0x0 + 0x8074 0x02103110 /*ph1*/ + 0x8084 0x00BB0000 /*5mm th*/ + 0x8094 0x02103810 /*ph2*/ + 0x80A4 0x00C60000 /*5mm th*/ + 0x80B4 0x0010FF00 + 0x80D4 0x00105A00 + 0x4004 0x67 >; + }; }; diff --git a/arch/arm64/configs/robusta2_evb_defconfig b/arch/arm64/configs/robusta2_evb_defconfig index f1578a7c3b6c..350b0cf056b8 100755 --- a/arch/arm64/configs/robusta2_evb_defconfig +++ b/arch/arm64/configs/robusta2_evb_defconfig @@ -535,7 +535,8 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_DISKCIPHER=y CONFIG_EXYNOS_FMP=y -CONFIG_SARSENSOR_SX9325=y +#CONFIG_SARSENSOR_SX9325=y +CONFIG_SARSENSOR_SX9331=y CONFIG_NFC=y CONFIG_SEC_NFC=y CONFIG_SEC_NFC_PRODUCT_N5=y diff --git a/arch/arm64/configs/wing_defconfig b/arch/arm64/configs/wing_defconfig old mode 100644 new mode 100755 index b3e5f6a1b364..16747f5088c2 --- a/arch/arm64/configs/wing_defconfig +++ b/arch/arm64/configs/wing_defconfig @@ -529,7 +529,8 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_DISKCIPHER=y CONFIG_EXYNOS_FMP=y -CONFIG_SARSENSOR_SX9325=y +#CONFIG_SARSENSOR_SX9325=y +CONFIG_SARSENSOR_SX9331=y CONFIG_NFC=y CONFIG_SEC_NFC=y CONFIG_SEC_NFC_PRODUCT_N5=y diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 22410aba7cda..a6a41c27371e 100755 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -870,6 +870,13 @@ config INPUT_S2MU106_HAPTIC The Haptic Motor driver support both ERM and LRA type actuators. +config SARSENSOR_SX9331 + bool "SARSENSOR SX9331" + default n + help + Say Y here if you have a sar sensor SX9325 connected + to your system.If unsure, say N. + config SARSENSOR_SX9325 bool "SARSENSOR SX9325" default n diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index b066414a3742..f97976c7035d 100755 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -83,4 +83,5 @@ obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o obj-$(CONFIG_INPUT_S2MU106_HAPTIC) += s2mu106_haptic.o +obj-$(CONFIG_SARSENSOR_SX9331) += sx933x_sar.o obj-$(CONFIG_SARSENSOR_SX9325) += sx9325_sar.o diff --git a/drivers/input/misc/sx933x.h b/drivers/input/misc/sx933x.h new file mode 100755 index 000000000000..f2877e48da34 --- /dev/null +++ b/drivers/input/misc/sx933x.h @@ -0,0 +1,755 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ +#ifndef SX933x_H +#define SX933x_H + +#include +#include +#include + +#if 0 +#include +#include +#include +#endif +/* + * I2C Registers + */ +#define SX933X_HOSTIRQSRC_REG 0x4000 +#define SX933X_HOSTIRQMSK_REG 0x4004 +#define SX933X_HOSTIRQCTRL_REG 0x4008 +#define SX933X_PAUSESTAT_REG 0x4010 +#define SX933X_AFECTRL_REG 0x4054 +#define SX933X_CLKGEN_REG 0x4200 +#define SX933X_I2CADDR_REG 0x41C4 +#define SX933X_RESET_REG 0x4240 +#define SX933X_CMD_REG 0x4280 +#define SX933X_TOPSTAT0_REG 0x4284 +#define SX933X_PINCFG_REG 0x42C0 +#define SX933X_PINDOUT_REG 0x42C4 +#define SX933X_PINDIN_REG 0x42C8 +#define SX933X_INFO_REG 0x42D8 +#define SX933X_STAT0_REG 0x8000 +#define SX933X_STAT1_REG 0x8004 +#define SX933X_STAT2_REG 0x8008 +#define SX933X_IRQCFG0_REG 0x800C +#define SX933X_IRQCFG1_REG 0x8010 +#define SX933X_IRQCFG2_REG 0x8014 +#define SX933X_IRQCFG3_REG 0x8018 +#define SX933X_SCANPERIOD_REG 0x801C +#define SX933X_GNRLCTRL2_REG 0x8020 +#define SX933X_AFEPARAMSPH0_REG 0x8024 +#define SX933X_AFEPHPH0_REG 0x8028 +#define SX933X_AFEPARAMSPH1_REG 0x802C +#define SX933X_AFEPHPH1_REG 0x8030 +#define SX933X_AFEPARAMSPH2_REG 0x8034 +#define SX933X_AFEPHPH2_REG 0x8038 +#define SX933X_AFEPARAMSPH3_REG 0x803C +#define SX933X_AFEPHPH3_REG 0x8040 +#define SX933X_AFEPARAMSPH4_REG 0x8044 +#define SX933X_AFEPHPH4_REG 0x8048 +#define SX933X_AFEPARAMSPH5_REG 0x804c +#define SX933X_AFEPHPH5_REG 0x8050 + +#define SX933X_ADCFILTPH0_REG 0x8054 +#define SX933X_AVGBFILTPH0_REG 0x8058 +#define SX933X_AVGAFILTPH0_REG 0x805C +#define SX933X_ADVDIG0PH0_REG 0x8060 +#define SX933X_ADVDIG1PH0_REG 0x8064 +#define SX933X_ADVDIG2PH0_REG 0x8068 +#define SX933X_ADVDIG3PH0_REG 0x806C +#define SX933X_ADVDIG4PH0_REG 0x8070 +#define SX933X_ADCFILTPH1_REG 0x8074 +#define SX933X_AVGBFILTPH1_REG 0x8078 +#define SX933X_AVGAFILTPH1_REG 0x807C +#define SX933X_ADVDIG0PH1_REG 0x8080 +#define SX933X_ADVDIG1PH1_REG 0x8084 +#define SX933X_ADVDIG2PH1_REG 0x8088 +#define SX933X_ADVDIG3PH1_REG 0x808C +#define SX933X_ADVDIG4PH1_REG 0x8090 +#define SX933X_ADCFILTPH2_REG 0x8094 +#define SX933X_AVGBFILTPH2_REG 0x8098 +#define SX933X_AVGAFILTPH2_REG 0x809C +#define SX933X_ADVDIG0PH2_REG 0x80A0 +#define SX933X_ADVDIG1PH2_REG 0x80A4 +#define SX933X_ADVDIG2PH2_REG 0x80A8 +#define SX933X_ADVDIG3PH2_REG 0x80AC +#define SX933X_ADVDIG4PH2_REG 0x80B0 +#define SX933X_ADCFILTPH3_REG 0x80B4 +#define SX933X_AVGBFILTPH3_REG 0x80B8 +#define SX933X_AVGAFILTPH3_REG 0x80BC +#define SX933X_ADVDIG0PH3_REG 0x80C0 +#define SX933X_ADVDIG1PH3_REG 0x80C4 +#define SX933X_ADVDIG2PH3_REG 0x80C8 +#define SX933X_ADVDIG3PH3_REG 0x80CC +#define SX933X_ADVDIG4PH3_REG 0x80D0 +#define SX933X_ADCFILTPH4_REG 0x80D4 +#define SX933X_AVGBFILTPH4_REG 0x80D8 +#define SX933X_AVGAFILTPH4_REG 0x80DC +#define SX933X_ADVDIG0PH4_REG 0x80E0 +#define SX933X_ADVDIG1PH4_REG 0x80E4 +#define SX933X_ADVDIG2PH4_REG 0x80E8 +#define SX933X_ADVDIG3PH4_REG 0x80EC +#define SX933X_ADVDIG4PH4_REG 0x80F0 +#define SX933X_ADCFILTPH5_REG 0x80F4 +#define SX933X_AVGBFILTPH5_REG 0x80F8 +#define SX933X_AVGAFILTPH5_REG 0x80FC +#define SX933X_ADVDIG0PH5_REG 0x8100 +#define SX933X_ADVDIG1PH5_REG 0x8104 +#define SX933X_ADVDIG2PH5_REG 0x8108 +#define SX933X_ADVDIG3PH5_REG 0x810C +#define SX933X_ADVDIG4PH5_REG 0x8110 + +#define SX933X_REFCORRA_REG 0x8124 +#define SX933X_REFCORRB_REG 0x8128 + +#define SX933X_SMARTSAR0A_REG 0x812C +#define SX933X_SMARTSAR1A_REG 0x8130 +#define SX933X_SMARTSAR2A_REG 0x8134 + +#define SX933X_SMARTSAR0B_REG 0x8138 +#define SX933X_SMARTSAR1B_REG 0x813C +#define SX933X_SMARTSAR2B_REG 0x8140 + +#define SX933X_SMARTSAR0C_REG 0x8144 +#define SX933X_SMARTSAR1C_REG 0x8148 +#define SX933X_SMARTSAR2C_REG 0x814C + + + + +#define SX933X_AUTOFREQ0_REG 0x8154 +#define SX933X_AUTOFREQ1_REG 0x8158 + +#define SX933X_USEPH0_REG 0x815C +#define SX933X_USEPH1_REG 0x8160 +#define SX933X_USEPH2_REG 0x8164 +#define SX933X_USEPH3_REG 0x8168 +#define SX933X_USEPH4_REG 0x816C +#define SX933X_USEPH5_REG 0x8170 + +#define SX933X_AVGPH0_REG 0x8174 +#define SX933X_AVGPH1_REG 0x8178 +#define SX933X_AVGPH2_REG 0x817C +#define SX933X_AVGPH3_REG 0x8180 +#define SX933X_AVGPH4_REG 0x8184 +#define SX933X_AVGPH5_REG 0x8188 + +#define SX933X_DIFFPH0_REG 0x818C +#define SX933X_DIFFPH1_REG 0x8190 +#define SX933X_DIFFPH2_REG 0x8194 +#define SX933X_DIFFPH3_REG 0x8198 +#define SX933X_DIFFPH4_REG 0x819C +#define SX933X_DIFFPH5_REG 0x81A0 + +#define SX933X_OFFSETPH0_REG SX933X_AFEPHPH0_REG//bit14:0 +#define SX933X_OFFSETPH1_REG SX933X_AFEPHPH1_REG//bit14:0 +#define SX933X_OFFSETPH2_REG SX933X_AFEPHPH2_REG//bit14:0 +#define SX933X_OFFSETPH3_REG SX933X_AFEPHPH3_REG//bit14:0 +#define SX933X_OFFSETPH4_REG SX933X_AFEPHPH4_REG//bit14:0 +#define SX933X_OFFSETPH5_REG SX933X_AFEPHPH5_REG//bit14:0 + +//i2c register bit mask +#define MSK_IRQSTAT_RESET 0x00000080 +#define MSK_IRQSTAT_TOUCH 0x00000040 +#define MSK_IRQSTAT_RELEASE 0x00000020 +#define MSK_IRQSTAT_COMP 0x00000010 +#define MSK_IRQSTAT_CONV 0x00000008 +#define MSK_IRQSTAT_PROG2IRQ 0x00000004 +#define MSK_IRQSTAT_PROG1IRQ 0x00000002 +#define MSK_IRQSTAT_PROG0IRQ 0x00000001 + +#define I2C_SOFTRESET_VALUE 0x000000DE + +#define I2C_REGCMD_PHEN 0x0000000F +#define I2C_REGCMD_COMPEN 0x0000000E +#define I2C_REGCMD_EN_SLEEP 0x0000000D +#define I2C_REGCMD_EX_SLEEP 0x0000000C + +#define I2C_REGGNRLCTRL2_PHEN_MSK 0x000000FF +#define I2C_REGGNRLCTRL2_COMPEN_MSK 0x00ff0000 + +#define MSK_REGSTAT0_STEADYSTAT5 0x20 +#define MSK_REGSTAT0_STEADYSTAT4 0x10 +#define MSK_REGSTAT0_STEADYSTAT3 0x08 +#define MSK_REGSTAT0_STEADYSTAT2 0x04 +#define MSK_REGSTAT0_STEADYSTAT1 0x02 +#define MSK_REGSTAT0_STEADYSTAT0 0x01 + +#define MSK_REGSTAT0_BODYSTAT5 ((long int)0x20<<8) +#define MSK_REGSTAT0_BODYSTAT4 ((long int)0x10<<8) +#define MSK_REGSTAT0_BODYSTAT3 ((long int)0x08<<8) +#define MSK_REGSTAT0_BODYSTAT2 ((long int)0x04<<8) +#define MSK_REGSTAT0_BODYSTAT1 ((long int)0x02<<8) +#define MSK_REGSTAT0_BODYSTAT0 ((long int)0x01<<8) + +#define MSK_REGSTAT0_TABLESTAT5 ((long int)0x20<<16) +#define MSK_REGSTAT0_TABLESTAT4 ((long int)0x10<<16) +#define MSK_REGSTAT0_TABLESTAT3 ((long int)0x08<<16) +#define MSK_REGSTAT0_TABLESTAT2 ((long int)0x04<<16) +#define MSK_REGSTAT0_TABLESTAT1 ((long int)0x02<<16) +#define MSK_REGSTAT0_TABLESTAT0 ((long int)0x01<<16) + +#define MSK_REGSTAT0_PROXSTAT5 ((long int)0x20<<24) +#define MSK_REGSTAT0_PROXSTAT4 ((long int)0x10<<24) +#define MSK_REGSTAT0_PROXSTAT3 ((long int)0x08<<24) +#define MSK_REGSTAT0_PROXSTAT2 ((long int)0x04<<24) +#define MSK_REGSTAT0_PROXSTAT1 ((long int)0x02<<24) +#define MSK_REGSTAT0_PROXSTAT0 ((long int)0x01<<24) + +#define MSK_REGSTAT1_FAILSTAT5 ((long int)0x20<<24) +#define MSK_REGSTAT1_FAILSTAT4 ((long int)0x10<<24) +#define MSK_REGSTAT1_FAILSTAT3 ((long int)0x08<<24) +#define MSK_REGSTAT1_FAILSTAT2 ((long int)0x04<<24) +#define MSK_REGSTAT1_FAILSTAT1 ((long int)0x02<<24) +#define MSK_REGSTAT1_FAILSTAT0 ((long int)0x01<<24) + +#define MSK_REGSTAT1_COMPSTAT5 ((long int)0x20<<16) +#define MSK_REGSTAT1_COMPSTAT4 ((long int)0x10<<16) +#define MSK_REGSTAT1_COMPSTAT3 ((long int)0x08<<16) +#define MSK_REGSTAT1_COMPSTAT2 ((long int)0x04<<16) +#define MSK_REGSTAT1_COMPSTAT1 ((long int)0x02<<16) +#define MSK_REGSTAT1_COMPSTAT0 ((long int)0x01<<16) +#define MSK_REGSTAT1_SATSTAT5 ((long int)0x20<<8) +#define MSK_REGSTAT1_SATSTAT4 ((long int)0x10<<8) +#define MSK_REGSTAT1_SATSTAT3 ((long int)0x08<<8) +#define MSK_REGSTAT1_SATSTAT2 ((long int)0x04<<8) +#define MSK_REGSTAT1_SATSTAT1 ((long int)0x02<<8) +#define MSK_REGSTAT1_SATSTAT0 ((long int)0x01<<8) + + + +#define MSK_REGSTAT2_STARTUPSTAT5 ((long int)0x20) +#define MSK_REGSTAT2_STARTUPSTAT4 ((long int)0x10) +#define MSK_REGSTAT2_STARTUPSTAT3 ((long int)0x08) +#define MSK_REGSTAT2_STARTUPSTAT2 ((long int)0x04) +#define MSK_REGSTAT2_STARTUPSTAT1 ((long int)0x02) +#define MSK_REGSTAT2_STARTUPSTAT0 ((long int)0x01) + +#define MSK_REGSTAT1_STEADYSTATALL 0x02 + + +#define SX933X_STAT0_PROXSTAT_PH5_FLAG 0x20000000 +#define SX933X_STAT0_PROXSTAT_PH4_FLAG 0x10000000 +#define SX933X_STAT0_PROXSTAT_PH3_FLAG 0x08000000 +#define SX933X_STAT0_PROXSTAT_PH2_FLAG 0x04000000 +#define SX933X_STAT0_PROXSTAT_PH1_FLAG 0x02000000 +#define SX933X_STAT0_PROXSTAT_PH0_FLAG 0x01000000 + +#define SX933X_STAT0_BODYSTAT_PH5_FLAG 0x00002000 +#define SX933X_STAT0_BODYSTAT_PH4_FLAG 0x00001000 +#define SX933X_STAT0_BODYSTAT_PH3_FLAG 0x00000800 +#define SX933X_STAT0_BODYSTAT_PH2_FLAG 0x00000400 +#define SX933X_STAT0_BODYSTAT_PH1_FLAG 0x00000200 +#define SX933X_STAT0_BODYSTAT_PH0_FLAG 0x00000100 + +/* Chip ID */ +#define SX933X_WHOAMI_VALUE 0x00003113 +/*command*/ +#define SX933X_PHASE_CONTROL 0x0000000F +#define SX933X_COMPENSATION_CONTROL 0x0000000E +#define SX933X_ENTER_CONTROL 0x0000000D +#define SX933X_EXIT_CONTROL 0x0000000C + + + + +/************************************** + * define platform data + * + **************************************/ +struct smtc_reg_data +{ + unsigned int reg; + unsigned int val; +}; + +typedef struct smtc_reg_data smtc_reg_data_t; +typedef struct smtc_reg_data *psmtc_reg_data_t; + + +struct _buttonInfo +{ + /*! The Key to send to the input */ + // int keycode; //not use + /*! Mask to look for on Prox Touch Status */ + int ProxMask; + /*! Mask to look for on Table Touch Status */ + int BodyMask; + /*! Current state of button. */ + int state; + struct input_dev *input_dev; + char *name; + struct sensors_classdev sensors_capsensor_cdev; + bool enabled; + //may different project use different buttons + bool used; +}; + +struct totalButtonInformation +{ + struct _buttonInfo *buttons; + int buttonSize; + //struct input_dev *input; //not used +}; + +typedef struct totalButtonInformation buttonInformation_t; +typedef struct totalButtonInformation *pbuttonInformation_t; + + +/* Define Registers that need to be initialized to values different than + * default + */ +/*define the value without Phase enable settings for easy changes in driver*/ +static const struct smtc_reg_data sx933x_i2c_reg_setup[] = +{ + // + { + .reg = SX933X_AFECTRL_REG, + .val = 0x00000400, + }, + // + { + .reg = SX933X_CLKGEN_REG, + .val = 0x00000008, + }, + // + { + .reg = SX933X_PINCFG_REG, + .val = 0x08000000, + }, + { + .reg = SX933X_PINDOUT_REG, + .val = 0x0000003F, + }, + // + { + .reg = SX933X_IRQCFG0_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_IRQCFG1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_IRQCFG2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_IRQCFG3_REG, + .val = 0x00000000, + }, + // + { + .reg = SX933X_SCANPERIOD_REG, + .val = 0x00000032, + }, + { + .reg = SX933X_GNRLCTRL2_REG, + .val = 0x3F001F, //enable phase0~phase4 0x00FF0001, + }, + { + .reg = SX933X_AFEPARAMSPH0_REG, + .val = 0x00010001, + }, + { + .reg = SX933X_AFEPHPH0_REG, + .val = 0x00A00BE3, + }, + { + .reg = SX933X_AFEPARAMSPH1_REG, + .val = 0x300004D4, + }, + { + .reg = SX933X_AFEPHPH1_REG, + .val = 0x00, + }, + { + .reg = SX933X_AFEPARAMSPH2_REG, + .val = 0x300004D4,//0x44F,//AFE setting for phase2 3.85pf + }, + { + .reg = SX933X_AFEPHPH2_REG, + .val = 0x00,//Configure for phase2 + }, + { + .reg = SX933X_AFEPARAMSPH3_REG, + .val = 0x300004D4,//0x44F,//AFE setting for phase3 3.3pf + }, + { + .reg = SX933X_AFEPHPH3_REG, + .val = 0x00,//Configure for phase3 + }, + { + .reg = SX933X_AFEPARAMSPH4_REG, + .val = 0x300004D4,//0x44F,//AFE setting for phase4 9.9pf + }, + { + .reg = SX933X_AFEPHPH4_REG, + .val = 0x00,//Configure for phase4 + }, + { + .reg = SX933X_AFEPARAMSPH5_REG, + .val = 0x300004D4, + }, + { + .reg = SX933X_AFEPHPH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADCFILTPH0_REG, + .val = 0x10162000, + }, + { + .reg = SX933X_AVGBFILTPH0_REG, + .val = 0x20400017, + }, + { + .reg = SX933X_AVGAFILTPH0_REG, + .val = 0x31CF9110, + }, + { + .reg = SX933X_ADVDIG0PH0_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH0_REG, + .val = 0x00, + }, + { + .reg = SX933X_ADVDIG2PH0_REG, + .val = 0x00, + }, + { + .reg = SX933X_ADVDIG3PH0_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH0_REG, + .val = 0x10000, + }, + { + .reg = SX933X_ADCFILTPH1_REG, + .val = 0x100000, + }, + { + .reg = SX933X_AVGBFILTPH1_REG, + .val = 0x20600C00, + }, + { + .reg = SX933X_AVGAFILTPH1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG0PH1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG2PH1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG3PH1_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH1_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADCFILTPH2_REG, + .val = 0x100000, + }, + { + .reg = SX933X_AVGBFILTPH2_REG, + .val = 0x20600C00, + }, + { + .reg = SX933X_AVGAFILTPH2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG0PH2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG2PH2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG3PH2_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH2_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADCFILTPH3_REG, + .val = 0x100000, + }, + { + .reg = SX933X_AVGBFILTPH3_REG, + .val = 0x20600C00, + }, + { + .reg = SX933X_AVGAFILTPH3_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG0PH3_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH3_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG2PH3_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG3PH3_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH3_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADCFILTPH4_REG, + .val = 0x100000, + }, + { + .reg = SX933X_AVGBFILTPH4_REG, + .val = 0x20600C00, + }, + { + .reg = SX933X_AVGAFILTPH4_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG0PH4_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH4_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG2PH4_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG3PH4_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH4_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADCFILTPH5_REG, + .val = 0x100000, + }, + { + .reg = SX933X_AVGBFILTPH5_REG, + .val = 0x20600C00, + }, + { + .reg = SX933X_AVGAFILTPH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG0PH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG1PH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG2PH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG3PH5_REG , + .val = 0x00000000, + }, + { + .reg = SX933X_ADVDIG4PH5_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_REFCORRA_REG, + .val = 0x7B13B10, + }, + { + .reg = SX933X_REFCORRB_REG, + .val = 0x4000000, + }, + { + .reg = SX933X_SMARTSAR0A_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_SMARTSAR1A_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_SMARTSAR2A_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_SMARTSAR0B_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_SMARTSAR1B_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_SMARTSAR2B_REG, + .val = 0x00000000, + }, + // + { + .reg = SX933X_AUTOFREQ0_REG, + .val = 0x00000000, + }, + { + .reg = SX933X_AUTOFREQ1_REG, + .val = 0x00000000, + }, + // + { + .reg = SX933X_HOSTIRQMSK_REG, + .val = 0x00000078, + }, + { + .reg = SX933X_HOSTIRQCTRL_REG, + .val = 0x00, + } +}; + +static struct _buttonInfo psmtcButtons[] = +{ + { + .ProxMask = SX933X_STAT0_PROXSTAT_PH0_FLAG, + .BodyMask = SX933X_STAT0_BODYSTAT_PH0_FLAG, + .name = "Moto_CapSense_Ch0", + .enabled = false, + .used = false, + }, + { + .ProxMask = SX933X_STAT0_PROXSTAT_PH1_FLAG, + .BodyMask = SX933X_STAT0_BODYSTAT_PH1_FLAG, + .name = "Moto_CapSense_Ch1", + .enabled = false, + .used = false, + }, + { + .ProxMask = SX933X_STAT0_PROXSTAT_PH2_FLAG, + .BodyMask = SX933X_STAT0_BODYSTAT_PH2_FLAG, + .name = "Moto_CapSense_Ch2", + .enabled = false, + .used = false, + }, + { + .ProxMask = SX933X_STAT0_PROXSTAT_PH3_FLAG, + .BodyMask = SX933X_STAT0_BODYSTAT_PH3_FLAG, + .name = "Moto_CapSense_Ch3", + .enabled = false, + .used = false, + }, + { + .ProxMask = SX933X_STAT0_PROXSTAT_PH4_FLAG, + .BodyMask = SX933X_STAT0_BODYSTAT_PH4_FLAG, + .name = "Moto_CapSense_Ch4", + .enabled = false, + .used = false, + }, +}; + +struct sx933x_platform_data +{ + int i2c_reg_num; + u32 button_used_flag; + struct regulator *cap_vdd; + bool cap_vdd_en; + struct smtc_reg_data *pi2c_reg; + int irq_gpio; + pbuttonInformation_t pbuttonInformation; + + int (*get_is_nirq_low)(void); + + int (*init_platform_hw)(struct i2c_client *client); + void (*exit_platform_hw)(struct i2c_client *client); +}; +typedef struct sx933x_platform_data sx933x_platform_data_t; +typedef struct sx933x_platform_data *psx933x_platform_data_t; + +/*************************************** + * define data struct/interrupt + * + ***************************************/ + +#define MAX_NUM_STATUS_BITS (8) + +typedef struct sx93XX sx93XX_t, *psx93XX_t; +struct sx93XX +{ + void * bus; /* either i2c_client or spi_client */ + + struct device *pdev; /* common device struction for linux */ + + void *pDevice; /* device specific struct pointer */ + + /* Function Pointers */ + int (*init)(psx93XX_t this); /* (re)initialize device */ + + /* since we are trying to avoid knowing registers, create a pointer to a + * common read register which would be to read what the interrupt source + * is from + */ + int (*refreshStatus)(psx93XX_t this); /* read register status */ + + int (*get_nirq_low)(void); /* get whether nirq is low (platform data) */ + + /* array of functions to call for corresponding status bit */ + void (*statusFunc[MAX_NUM_STATUS_BITS])(psx93XX_t this); + + /* Global variable */ + u8 failStatusCode; /*Fail status code*/ + bool reg_in_dts; + + spinlock_t lock; /* Spin Lock used for nirq worker function */ + int irq; /* irq number used */ + + /* whether irq should be ignored.. cases if enable/disable irq is not used + * or does not work properly */ + char irq_disabled; + + u8 useIrqTimer; /* older models need irq timer for pen up cases */ + + int irqTimeout; /* msecs only set if useIrqTimer is true */ + + /* struct workqueue_struct *ts_workq; */ /* if want to use non default */ + struct delayed_work dworker; /* work struct for worker function */ + u8 phaseselect; +}; + +int sx93XX_IRQ_init(psx93XX_t this); + +#endif diff --git a/drivers/input/misc/sx933x_sar.c b/drivers/input/misc/sx933x_sar.c new file mode 100755 index 000000000000..2a3084c4ea93 --- /dev/null +++ b/drivers/input/misc/sx933x_sar.c @@ -0,0 +1,1156 @@ +/*! \file sx933x.c + * \brief SX933x Driver + * + * Driver for the SX933x + * Copyright (c) 2018 Semtech Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define DRIVER_NAME "sx933x" + +#define MAX_WRITE_ARRAY_SIZE 32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include "sx933x.h" /* main struct, interrupt,init,pointers */ + + +#define SX933x_DEBUG 1 +#define LOG_TAG "[sar SX933x]: " + +#if SX933x_DEBUG +#define LOG_INFO(fmt, args...) pr_info(LOG_TAG fmt, ##args) +#else +#define LOG_INFO(fmt, args...) +#endif +#define LOG_DBG(fmt, args...) pr_info(LOG_TAG fmt, ##args) + +#define USE_DTS_REG + +#define SX933x_I2C_M_WR 0 /* for i2c Write */ +#define SX933x_I2C_M_RD 1 /* for i2c Read */ + +#define IDLE 0 +#define PROXACTIVE 1 +#define BODYACTIVE 2 + +#define MAIN_SENSOR 1 //CS1 + +/* Failer Index */ +#define SX933x_ID_ERROR 1 +#define SX933x_NIRQ_ERROR 2 +#define SX933x_CONN_ERROR 3 +#define SX933x_I2C_ERROR 4 + +/*! \struct sx933x + * Specialized struct containing input event data, platform data, and + * last cap state read if needed. + */ +typedef struct sx933x +{ + pbuttonInformation_t pbuttonInformation; + psx933x_platform_data_t hw; /* specific platform data settings */ +} sx933x_t, *psx933x_t; + +static int irq_gpio_num; +static psx93XX_t global_sx933x; + +static int sx933x_get_nirq_state(void) +{ + return !gpio_get_value(irq_gpio_num); +} + + +/*! \fn static int sx933x_i2c_write_16bit(psx93XX_t this, u8 address, u8 value) + * \brief Sends a write register to the device + * \param this Pointer to main parent struct + * \param address 8-bit register address + * \param value 8-bit register value to write to address + * \return Value from i2c_master_send + */ + +static int sx933x_i2c_write_16bit(psx93XX_t this, u16 reg_addr, u32 buf) +{ + int ret = -ENOMEM; + struct i2c_client *i2c = 0; + struct i2c_msg msg; + unsigned char w_buf[6]; + + if (this && this->bus) + { + i2c = this->bus; + w_buf[0] = (u8)(reg_addr>>8); + w_buf[1] = (u8)(reg_addr); + w_buf[2] = (u8)(buf>>24); + w_buf[3] = (u8)(buf>>16); + w_buf[4] = (u8)(buf>>8); + w_buf[5] = (u8)(buf); + + msg.addr = i2c->addr; + msg.flags = SX933x_I2C_M_WR; + msg.len = 6; //2bytes regaddr + 4bytes data + msg.buf = (u8 *)w_buf; + + ret = i2c_transfer(i2c->adapter, &msg, 1); + if (ret < 0) + LOG_DBG("%s - i2c write reg 0x%x error %d\n", __func__, reg_addr, ret); + + } + return ret; +} + +/*! \fn static int sx933x_i2c_read_16bit(psx93XX_t this, u8 address, u8 *value) + * \brief Reads a register's value from the device + * \param this Pointer to main parent struct + * \param address 8-Bit address to read from + * \param value Pointer to 8-bit value to save register value to + * \return Value from i2c_smbus_read_byte_data if < 0. else 0 + */ +static int sx933x_i2c_read_16bit(psx93XX_t this, u16 reg_addr, u32 *data32) +{ + int ret = -ENOMEM; + struct i2c_client *i2c = 0; + struct i2c_msg msg[2]; + u8 w_buf[2]; + u8 buf[4]; + + if (this && this->bus) + { + i2c = this->bus; + + w_buf[0] = (u8)(reg_addr>>8); + w_buf[1] = (u8)(reg_addr); + + msg[0].addr = i2c->addr; + msg[0].flags = SX933x_I2C_M_WR; + msg[0].len = 2; + msg[0].buf = (u8 *)w_buf; + + msg[1].addr = i2c->addr;; + msg[1].flags = SX933x_I2C_M_RD; + msg[1].len = 4; + msg[1].buf = (u8 *)buf; + + ret = i2c_transfer(i2c->adapter, msg, 2); + if (ret < 0) + LOG_DBG("%s - i2c read reg 0x%x error %d\n", __func__, reg_addr, ret); + + data32[0] = ((u32)buf[0]<<24) | ((u32)buf[1]<<16) | ((u32)buf[2]<<8) | ((u32)buf[3]); + + } + return ret; +} + + + + +//static int sx933x_set_mode(psx93XX_t this, unsigned char mode); + +/*! \fn static int read_regStat(psx93XX_t this) + * \brief Shortcut to read what caused interrupt. + * \details This is to keep the drivers a unified + * function that will read whatever register(s) + * provide information on why the interrupt was caused. + * \param this Pointer to main parent struct + * \return If successful, Value of bit(s) that cause interrupt, else 0 + */ +static int read_regStat(psx93XX_t this) +{ + u32 data = 0; + if (this) + { + if (sx933x_i2c_read_16bit(this,SX933X_HOSTIRQSRC_REG,&data) > 0) //bug + return (data & 0x00FF); + } + return 0; +} + +static int sx933x_Hardware_Check(psx93XX_t this) +{ + int ret; + u32 idCode; + u8 loop = 0; + this->failStatusCode = 0; + + //Check th IRQ Status + while(this->get_nirq_low && this->get_nirq_low()) + { + read_regStat(this); + msleep(100); + if(++loop >10) + { + this->failStatusCode = SX933x_NIRQ_ERROR; + break; + } + } + + //Check I2C Connection + ret = sx933x_i2c_read_16bit(this, SX933X_INFO_REG, &idCode); + if(ret < 0) + { + this->failStatusCode = SX933x_I2C_ERROR; + } + + if(idCode!= SX933X_WHOAMI_VALUE) + { + this->failStatusCode = SX933x_ID_ERROR; + } + + LOG_DBG("sx933x idcode = 0x%x, failcode = 0x%x\n", idCode, this->failStatusCode); + return (int)this->failStatusCode; +} + +static int sx933x_global_variable_init(psx93XX_t this) +{ + this->irq_disabled = 0; + this->failStatusCode = 0; + this->reg_in_dts = true; + return 0; +} + +/*! \brief Perform a manual offset calibration + * \param this Pointer to main parent struct + * \return Value return value from the write register + */ +static int manual_offset_calibration(psx93XX_t this) +{ + int ret = 0; + ret = sx933x_i2c_write_16bit(this, SX933X_CMD_REG, I2C_REGCMD_COMPEN); + return ret; + +} + +/****************************************************************************/ +/*! \brief sysfs show function for manual calibration which currently just + * returns register value. + */ +static ssize_t manual_offset_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 reg_value = 0; + psx93XX_t this = dev_get_drvdata(dev); + + LOG_DBG("Reading IRQSTAT_REG\n"); + sx933x_i2c_read_16bit(this,SX933X_HOSTIRQSRC_REG,®_value); + return sprintf(buf, "%d\n", reg_value); +} + + +static ssize_t manual_offset_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + psx93XX_t this = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) //(strict_strtoul(buf, 10, &val)) { + { + LOG_DBG(" %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + if (val) + manual_offset_calibration(this); + + return count; +} + +/****************************************************************************/ +static ssize_t sx933x_register_write_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u32 reg_address = 0, val = 0; + psx93XX_t this = dev_get_drvdata(dev); + + if (sscanf(buf, "%x,%x", ®_address, &val) != 2) + { + LOG_DBG("%s - The number of data are wrong\n",__func__); + return -EINVAL; + } + + sx933x_i2c_write_16bit(this, reg_address, val); + + LOG_DBG("%s - Register(0x%x) data(0x%x)\n",__func__, reg_address, val); + return count; +} + +static ssize_t sx933x_register_read_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u32 val=0; + int regist = 0; + int nirq_state = 0; + psx93XX_t this = dev_get_drvdata(dev); + + if (sscanf(buf, "%x", ®ist) != 1) + { + LOG_DBG("%s - The number of data are wrong\n",__func__); + return -EINVAL; + } + + sx933x_i2c_read_16bit(this, regist, &val); + nirq_state = sx933x_get_nirq_state(); + + LOG_DBG("%s - Register(0x%2x) data(0x%4x) nirq_state(%d)\n",__func__, regist, val, nirq_state); + return count; +} + +static void read_rawData(psx93XX_t this) +{ + u8 csx, index; + s32 useful; + s32 average; + s32 diff; + u32 uData; + u16 offset; + //s32 state = 0; + + if(this) + { + for(csx =0; csx<5; csx++) + { + index = csx*4; + sx933x_i2c_read_16bit(this, SX933X_USEPH0_REG + index, &uData); + useful = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_AVGPH0_REG + index, &uData); + average = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_DIFFPH0_REG + index, &uData); + diff = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_OFFSETPH0_REG + index*2, &uData); + offset = (u16)(uData & 0x7FFF); + //state = psmtcButtons[csx].state; + LOG_DBG("[PH: %d] Useful = %d Average = %d, DIFF = %d Offset = %d \n", + csx,useful,average,diff,offset); + } + } +} + +static ssize_t sx933x_raw_data_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + char *p = buf; + int csx; + s32 useful, average, diff; + u32 uData; + u16 offset; + psx93XX_t this = dev_get_drvdata(dev); + if(this) { + for(csx =0; csx<5; csx++) { + sx933x_i2c_read_16bit(this, SX933X_USEPH0_REG + csx*4, &uData); + useful = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_AVGPH0_REG + csx*4, &uData); + average = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_DIFFPH0_REG + csx*4, &uData); + diff = (s32)uData>>10; + sx933x_i2c_read_16bit(this, SX933X_OFFSETPH0_REG + csx*8, &uData); + offset = (u16)(uData & 0x7FFF); + p += snprintf(p, PAGE_SIZE, "[PH: %d] Useful = %d, Average = %d, DIFF = %d Offset = %d \n", + csx,useful,average,diff,offset); + } + } + return (p-buf); +} + +static DEVICE_ATTR(manual_calibrate, 0664, manual_offset_calibration_show,manual_offset_calibration_store); +static DEVICE_ATTR(register_write, 0664, NULL,sx933x_register_write_store); +static DEVICE_ATTR(register_read,0664, NULL,sx933x_register_read_store); +static DEVICE_ATTR(raw_data,0664,sx933x_raw_data_show,NULL); + +static struct attribute *sx933x_attributes[] = +{ + &dev_attr_manual_calibrate.attr, + &dev_attr_register_write.attr, + &dev_attr_register_read.attr, + &dev_attr_raw_data.attr, + NULL, +}; +static struct attribute_group sx933x_attr_group = +{ + .attrs = sx933x_attributes, +}; + +/**************************************/ + +/*! \brief Initialize I2C config from platform data + * \param this Pointer to main parent struct + */ +static void sx933x_reg_init(psx93XX_t this) +{ + psx933x_t pDevice = 0; + psx933x_platform_data_t pdata = 0; + int i = 0; + uint32_t tmpvalue; + /* configure device */ + if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw)) + { + /*******************************************************************************/ + // try to initialize from device tree! + /*******************************************************************************/ + while ( i < ARRAY_SIZE(sx933x_i2c_reg_setup)) + { + /* Write all registers/values contained in i2c_reg */ + LOG_DBG("Going to Write Reg: 0x%x Value: 0x%x\n", + sx933x_i2c_reg_setup[i].reg,sx933x_i2c_reg_setup[i].val); + tmpvalue = sx933x_i2c_reg_setup[i].val; + if (sx933x_i2c_reg_setup[i].reg == SX933X_GNRLCTRL2_REG) + { + if((sx933x_i2c_reg_setup[i].val & 0x3F) == 0) + { + tmpvalue = (sx933x_i2c_reg_setup[i].val|0x3F); + } + } + sx933x_i2c_write_16bit(this, sx933x_i2c_reg_setup[i].reg, tmpvalue); + i++; + } +#ifdef USE_DTS_REG + if (this->reg_in_dts == true) + { + i = 0; + while ( i < pdata->i2c_reg_num) + { + /* Write all registers/values contained in i2c_reg */ + LOG_DBG("Going to Write Reg from dts: 0x%x Value: 0x%x\n", + pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val); + sx933x_i2c_write_16bit(this, pdata->pi2c_reg[i].reg,pdata->pi2c_reg[i].val); + i++; + } + } +#endif + /*******************************************************************************/ + sx933x_i2c_write_16bit(this, SX933X_CMD_REG,SX933X_PHASE_CONTROL); //enable phase control + } + else { + LOG_DBG("ERROR! platform data 0x%p\n",pDevice->hw); + } + +} + + +/*! \fn static int initialize(psx93XX_t this) + * \brief Performs all initialization needed to configure the device + * \param this Pointer to main parent struct + * \return Last used command's return value (negative if error) + */ +static int initialize(psx93XX_t this) +{ + int ret, retry; + if (this) + { + LOG_DBG("SX933x income initialize\n"); + /* prepare reset by disabling any irq handling */ + this->irq_disabled = 1; + disable_irq(this->irq); + /* perform a reset */ + for ( retry = 10; retry > 0; retry-- ) { + if (sx933x_i2c_write_16bit(this, SX933X_RESET_REG, I2C_SOFTRESET_VALUE) >= 0) + break; + LOG_DBG("SX933x write SX933X_RESET_REG retry:%d\n", 11 - retry); + msleep(10); + } + /* wait until the reset has finished by monitoring NIRQ */ + LOG_DBG("Sent Software Reset. Waiting until device is back from reset to continue.\n"); + /* just sleep for awhile instead of using a loop with reading irq status */ + msleep(100); + ret = sx933x_global_variable_init(this); + sx933x_reg_init(this); + msleep(100); /* make sure everything is running */ + manual_offset_calibration(this); + + /* re-enable interrupt handling */ + enable_irq(this->irq); + + /* make sure no interrupts are pending since enabling irq will only + * work on next falling edge */ + read_regStat(this); + return 0; + } + return -ENOMEM; +} + +/*! + * \brief Handle what to do when a touch occurs + * \param this Pointer to main parent struct + */ +static void touchProcess(psx93XX_t this) +{ + int counter = 0; + u32 i = 0; + u32 touchFlag = 0; + int numberOfButtons = 0; + psx933x_t pDevice = NULL; + struct _buttonInfo *buttons = NULL; + struct input_dev *input = NULL; + + struct _buttonInfo *pCurrentButton = NULL; + + if (this && (pDevice = this->pDevice)) + { + sx933x_i2c_read_16bit(this, SX933X_STAT0_REG, &i); + LOG_DBG("touchProcess STAT0_REG:0x%08x\n", i); + + buttons = pDevice->pbuttonInformation->buttons; + numberOfButtons = pDevice->pbuttonInformation->buttonSize; + + if (unlikely( buttons==NULL )) + { + LOG_DBG(":ERROR!! buttons NULL!!!\n"); + return; + } + + for (counter = 0; counter < numberOfButtons; counter++) + { + if (buttons[counter].enabled == false) { + LOG_INFO("touchProcess %s disabled, ignor this\n", buttons[counter].name); + continue; + } + if (buttons[counter].used== false) { + LOG_INFO("touchProcess %s unused, ignor this\n", buttons[counter].name); + continue; + } + pCurrentButton = &buttons[counter]; + if (pCurrentButton==NULL) + { + LOG_DBG("ERROR!! current button at index: %d NULL!!!\n", counter); + return; // ERRORR!!!! + } + input = pCurrentButton->input_dev; + if (input==NULL) + { + LOG_DBG("ERROR!! current button input at index: %d NULL!!!\n", counter); + return; // ERRORR!!!! + } + + touchFlag = i & (pCurrentButton->ProxMask | pCurrentButton->BodyMask); + if (touchFlag == (pCurrentButton->ProxMask | pCurrentButton->BodyMask)) { + if (pCurrentButton->state == BODYACTIVE) + LOG_DBG(" %s already BODYACTIVE\n", pCurrentButton->name); + else { + input_report_abs(input, ABS_DISTANCE, 2); + input_sync(input); + pCurrentButton->state = BODYACTIVE; + LOG_DBG(" %s report 5mm BODYACTIVE\n", pCurrentButton->name); + } + } else if (touchFlag == pCurrentButton->ProxMask) { + if (pCurrentButton->state == PROXACTIVE) + LOG_DBG(" %s already PROXACTIVE\n", pCurrentButton->name); + else { + input_report_abs(input, ABS_DISTANCE, 1); + input_sync(input); + pCurrentButton->state = PROXACTIVE; + LOG_DBG(" %s report 15mm PROXACTIVE\n", pCurrentButton->name); + } + }else if (touchFlag == 0) { + if (pCurrentButton->state == IDLE) + LOG_DBG("%s already released.\n", pCurrentButton->name); + else { + input_report_abs(input, ABS_DISTANCE, 0); + input_sync(input); + pCurrentButton->state = IDLE; + LOG_DBG("%s report released.\n", pCurrentButton->name); + } + } + } + LOG_INFO("Leaving touchProcess()\n"); + } +} + +static int sx933x_parse_dt(struct sx933x_platform_data *pdata, struct device *dev) +{ + struct device_node *dNode = dev->of_node; + enum of_gpio_flags flags; + + if (dNode == NULL) + return -ENODEV; + + pdata->irq_gpio= of_get_named_gpio_flags(dNode, + "Semtech,nirq-gpio", 0, &flags); + irq_gpio_num = pdata->irq_gpio; + if (pdata->irq_gpio < 0) + { + LOG_DBG("%s - get irq_gpio error\n", __func__); + return -ENODEV; + } + + pdata->button_used_flag = 0; + of_property_read_u32(dNode,"Semtech,button-flag",&pdata->button_used_flag); + LOG_INFO("%s - used button 0x%x \n", __func__, pdata->button_used_flag); + +#ifdef USE_DTS_REG + // load in registers from device tree + of_property_read_u32(dNode,"Semtech,reg-num",&pdata->i2c_reg_num); + // layout is register, value, register, value.... + // if an extra item is after just ignore it. reading the array in will cause it to fail anyway + LOG_INFO("%s - size of elements %d \n", __func__,pdata->i2c_reg_num); + if (pdata->i2c_reg_num > 0) + { + // initialize platform reg data array + pdata->pi2c_reg = devm_kzalloc(dev,sizeof(struct smtc_reg_data)*pdata->i2c_reg_num, GFP_KERNEL); + if (unlikely(pdata->pi2c_reg == NULL)) + { + LOG_DBG("%s - size of elements %d alloc error\n", __func__,pdata->i2c_reg_num); + return -ENOMEM; + } + + // initialize the array + if (of_property_read_u32_array(dNode,"Semtech,reg-init",(u32*)&(pdata->pi2c_reg[0]),sizeof(struct smtc_reg_data)*pdata->i2c_reg_num/sizeof(u32))) + return -ENOMEM; + } +#endif + LOG_INFO("%s -[%d] parse_dt complete\n", __func__,pdata->irq_gpio); + return 0; +} + +/* get the NIRQ state (1->NIRQ-low, 0->NIRQ-high) */ +static int sx933x_init_platform_hw(struct i2c_client *client) +{ + psx93XX_t this = i2c_get_clientdata(client); + struct sx933x *pDevice = NULL; + struct sx933x_platform_data *pdata = NULL; + + int rc = 0; + + LOG_INFO("%s init_platform_hw start!",__func__); + + if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw)) + { + if (gpio_is_valid(pdata->irq_gpio)) + { + rc = gpio_request(pdata->irq_gpio, "sx933x_irq_gpio"); + if (rc < 0) + { + LOG_DBG("SX933x Request gpio. Fail![%d]\n", rc); + return rc; + } + rc = gpio_direction_input(pdata->irq_gpio); + if (rc < 0) + { + LOG_DBG("SX933x Set gpio direction. Fail![%d]\n", rc); + return rc; + } + this->irq = client->irq = gpio_to_irq(pdata->irq_gpio); + } + else + { + LOG_DBG("SX933x Invalid irq gpio num.(init)\n"); + } + } + else + { + LOG_DBG("%s - Do not init platform HW", __func__); + } + return rc; +} + +static void sx933x_exit_platform_hw(struct i2c_client *client) +{ + psx93XX_t this = i2c_get_clientdata(client); + struct sx933x *pDevice = NULL; + struct sx933x_platform_data *pdata = NULL; + + if (this && (pDevice = this->pDevice) && (pdata = pDevice->hw)) + { + if (gpio_is_valid(pdata->irq_gpio)) + { + gpio_free(pdata->irq_gpio); + } + else + { + LOG_DBG("Invalid irq gpio num.(exit)\n"); + } + } + return; +} + +static int capsensor_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + bool disableFlag = true; + int i = 0; + u32 temp = 0x0; + + for (i = 0; i < ARRAY_SIZE(psmtcButtons); i++) { + if (strcmp(sensors_cdev->name, psmtcButtons[i].name) == 0) { + if (enable == 1) { + LOG_DBG("enable cap sensor : %s\n", sensors_cdev->name); + sx933x_i2c_read_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, &temp); + temp = temp | 0x0000001F; + LOG_INFO("set reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp); + sx933x_i2c_write_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, temp); + psmtcButtons[i].enabled = true; + input_report_abs(psmtcButtons[i].input_dev, ABS_DISTANCE, 0); + input_sync(psmtcButtons[i].input_dev); + + manual_offset_calibration(global_sx933x); + } else if (enable == 0) { + LOG_DBG("disable cap sensor : %s\n", sensors_cdev->name); + psmtcButtons[i].enabled = false; + input_report_abs(psmtcButtons[i].input_dev, ABS_DISTANCE, -1); + input_sync(psmtcButtons[i].input_dev); + } else { + LOG_DBG("unknown enable symbol\n"); + } + } + } + + //if all chs disabled, then disable all + for (i = 0; i < ARRAY_SIZE(psmtcButtons); i++) { + if (psmtcButtons[i].enabled) { + disableFlag = false; + break; + } + } + if (disableFlag) { + LOG_DBG("disable all chs\n"); + sx933x_i2c_read_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, &temp); + LOG_INFO("read reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp); + temp = temp & 0xFFFFFFE0; + LOG_INFO("set reg 0x%x val 0x%x\n", SX933X_GNRLCTRL2_REG, temp); + sx933x_i2c_write_16bit(global_sx933x, SX933X_GNRLCTRL2_REG, temp); + } + return 0; +} + +/*! \fn static int sx933x_probe(struct i2c_client *client, const struct i2c_device_id *id) + * \brief Probe function + * \param client pointer to i2c_client + * \param id pointer to i2c_device_id + * \return Whether probe was successful + */ +static int sx933x_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int i = 0; + int err = 0; + + psx93XX_t this = 0; + psx933x_t pDevice = 0; + psx933x_platform_data_t pplatData = 0; + struct totalButtonInformation *pButtonInformationData = NULL; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + + LOG_DBG("sx933x_probe()\n"); + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) + { + LOG_DBG("Check i2c functionality.Fail!\n"); + err = -EIO; + return err; + } + + this = devm_kzalloc(&client->dev,sizeof(sx93XX_t), GFP_KERNEL); /* create memory for main struct */ + LOG_DBG("Initialized Main Memory: 0x%p\n",this); + + pButtonInformationData = devm_kzalloc(&client->dev , sizeof(struct totalButtonInformation), GFP_KERNEL); + if (!pButtonInformationData) + { + LOG_DBG("Failed to allocate memory(totalButtonInformation)\n"); + err = -ENOMEM; + return err; + } + + pButtonInformationData->buttonSize = ARRAY_SIZE(psmtcButtons); + pButtonInformationData->buttons = psmtcButtons; + pplatData = devm_kzalloc(&client->dev,sizeof(struct sx933x_platform_data), GFP_KERNEL); + if (!pplatData) + { + LOG_DBG("platform data is required!\n"); + return -EINVAL; + } + pplatData->get_is_nirq_low = sx933x_get_nirq_state; + pplatData->pbuttonInformation = pButtonInformationData; + + client->dev.platform_data = pplatData; + err = sx933x_parse_dt(pplatData, &client->dev); + if (err) + { + LOG_DBG("could not setup pin\n"); + return ENODEV; + } + + pplatData->init_platform_hw = sx933x_init_platform_hw; + LOG_INFO("SX933x init_platform_hw done!\n"); + + if (this) + { + LOG_INFO("SX933x initialize start!!"); + /* In case we need to reinitialize data + * (e.q. if suspend reset device) */ + this->init = initialize; + /* shortcut to read status of interrupt */ + this->refreshStatus = read_regStat; + /* pointer to function from platform data to get pendown + * (1->NIRQ=0, 0->NIRQ=1) */ + this->get_nirq_low = pplatData->get_is_nirq_low; + /* save irq in case we need to reference it */ + this->irq = client->irq; + /* do we need to create an irq timer after interrupt ? */ + this->useIrqTimer = 0; + + /* Setup function to call on corresponding reg irq source bit */ + if (MAX_NUM_STATUS_BITS>= 8) + { + this->statusFunc[0] = 0; /* TXEN_STAT */ + this->statusFunc[1] = 0; /* UNUSED */ + this->statusFunc[2] = touchProcess; /* body&table */ + this->statusFunc[3] = read_rawData; /* CONV_STAT */ + this->statusFunc[4] = 0; /* COMP_STAT */ + this->statusFunc[5] = touchProcess; /* RELEASE_STAT */ + this->statusFunc[6] = touchProcess; /* TOUCH_STAT */ + this->statusFunc[7] = 0; /* RESET_STAT */ + } + + /* setup i2c communication */ + this->bus = client; + i2c_set_clientdata(client, this); + + /* record device struct */ + this->pdev = &client->dev; + + /* create memory for device specific struct */ + this->pDevice = pDevice = devm_kzalloc(&client->dev,sizeof(sx933x_t), GFP_KERNEL); + LOG_INFO("initialized Device Specific Memory: 0x%p\n",pDevice); + + if (pDevice) + { + /* for accessing items in user data (e.g. calibrate) */ + err = sysfs_create_group(&client->dev.kobj, &sx933x_attr_group); + //sysfs_create_group(client, &sx933x_attr_group); + + /* Add Pointer to main platform data struct */ + pDevice->hw = pplatData; + + /* Check if we hava a platform initialization function to call*/ + if (pplatData->init_platform_hw) + pplatData->init_platform_hw(client); + + /* Initialize the button information initialized with keycodes */ + pDevice->pbuttonInformation = pplatData->pbuttonInformation; + + for (i = 0; i < pButtonInformationData->buttonSize; i++) + { + if (pplatData->button_used_flag>>i & 0x01) { + pButtonInformationData->buttons[i].used = true; + pButtonInformationData->buttons[i].state = IDLE; + pButtonInformationData->buttons[i].input_dev = input_allocate_device(); + if (!pButtonInformationData->buttons[i].input_dev) + return -ENOMEM; + pButtonInformationData->buttons[i].input_dev->name = pButtonInformationData->buttons[i].name; + /* Set all the keycodes */ + __set_bit(EV_ABS, pButtonInformationData->buttons[i].input_dev->evbit); + input_set_abs_params(pButtonInformationData->buttons[i].input_dev, ABS_DISTANCE, -1, 100, 0, 0); + + err = input_register_device(pButtonInformationData->buttons[i].input_dev); + /* report a unused val, then first val will report after enable */ + input_report_abs(pButtonInformationData->buttons[i].input_dev, ABS_DISTANCE, -1); + input_sync(pButtonInformationData->buttons[i].input_dev); + + pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensors_enable = capsensor_set_enable; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensors_poll_delay = NULL; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.name = pButtonInformationData->buttons[i].name; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.vendor = "semtech"; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.version = 1; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.type = SENSOR_TYPE_MOTO_CAPSENSE; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.max_range = "5"; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.resolution = "5.0"; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.sensor_power = "3"; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.min_delay = 0; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.fifo_reserved_event_count = 0; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.fifo_max_event_count = 0; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.delay_msec = 100; + pButtonInformationData->buttons[i].sensors_capsensor_cdev.enabled = 0; + pButtonInformationData->buttons[i].enabled = false; + + err = sensors_classdev_register(&pButtonInformationData->buttons[i].input_dev->dev, &pButtonInformationData->buttons[i].sensors_capsensor_cdev); + if (err < 0) + LOG_DBG("create %d cap sensor_class file failed (%d)\n", i, err); + } + } + } + + pplatData->cap_vdd = regulator_get(&client->dev, "cap_vdd"); + + if (IS_ERR(pplatData->cap_vdd)) { + if (PTR_ERR(pplatData->cap_vdd) == -EPROBE_DEFER) { + err = PTR_ERR(pplatData->cap_vdd); + return err; + } + LOG_DBG("%s: Failed to get regulator\n", + __func__); + } else { + err = regulator_enable(pplatData->cap_vdd); + if (err) { + regulator_put(pplatData->cap_vdd); + LOG_DBG("%s: Error %d enable regulator\n", + __func__, err); + return err; + } + pplatData->cap_vdd_en = true; + LOG_DBG("cap_vdd regulator is %s\n", + regulator_is_enabled(pplatData->cap_vdd) ? + "on" : "off"); + } + sx93XX_IRQ_init(this); + /* call init function pointer (this should initialize all registers */ + if (this->init) { + this->init(this); + } + else { + LOG_DBG("No init function!!!!\n"); + return -ENOMEM; + } + } else { + return -1; + } + + pplatData->exit_platform_hw = sx933x_exit_platform_hw; + + if (sx933x_Hardware_Check(this) != 0) { + LOG_DBG("sx933x_Hardware_CheckFail!\n"); + //return -1; + } + + global_sx933x = this; + LOG_INFO("sx933x_probe() Done\n"); + return 0; +} + +/*! \fn static int sx933x_remove(struct i2c_client *client) + * \brief Called when device is to be removed + * \param client Pointer to i2c_client struct + * \return Value 0 + */ +//static int __devexit sx933x_remove(struct i2c_client *client) +static int sx933x_remove(struct i2c_client *client) +{ + psx933x_platform_data_t pplatData =0; + psx933x_t pDevice = 0; + struct _buttonInfo *pCurrentbutton; + int i = 0; + psx93XX_t this = i2c_get_clientdata(client); + LOG_DBG("sx933x_remove"); + if (this && (pDevice = this->pDevice)) + { + free_irq(this->irq, this); + cancel_delayed_work_sync(&(this->dworker)); + + sysfs_remove_group(&client->dev.kobj, &sx933x_attr_group); + pplatData = client->dev.platform_data; + if (pplatData && pplatData->exit_platform_hw) + pplatData->exit_platform_hw(client); + if (pplatData->cap_vdd_en) { + regulator_disable(pplatData->cap_vdd); + regulator_put(pplatData->cap_vdd); + } + for (i = 0; i pbuttonInformation->buttonSize; i++) { + pCurrentbutton = &(pDevice->pbuttonInformation->buttons[i]); + if (pCurrentbutton->used == true) { + sensors_classdev_unregister(&(pCurrentbutton->sensors_capsensor_cdev)); + input_unregister_device(pCurrentbutton->input_dev); + } + } + } + return 0; +} + + +#if 1//def CONFIG_PM +/*====================================================*/ +/***** Kernel Suspend *****/ +static int sx933x_suspend(struct device *dev) +{ + psx93XX_t this = dev_get_drvdata(dev); + if (this) { + disable_irq(this->irq); + //sx933x_i2c_write_16bit(this,SX933X_CPS_CTRL0_REG,0x20);//make sx933x in Sleep mode + } + return 0; +} +/***** Kernel Resume *****/ +static int sx933x_resume(struct device *dev) +{ + psx93XX_t this = dev_get_drvdata(dev); + if (this) { + enable_irq(this->irq); + //sx933x_i2c_write_16bit(this,SX933X_CPS_CTRL0_REG,0x27);//Exit from Sleep mode + } + return 0; +} +/*====================================================*/ +#else +#define sx933x_suspend NULL +#define sx933x_resume NULL +#endif /* CONFIG_PM */ + +static struct i2c_device_id sx933x_idtable[] = +{ + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sx933x_idtable); +#ifdef CONFIG_OF +static struct of_device_id sx933x_match_table[] = +{ + { .compatible = "Semtech,sx933x",}, + { }, +}; +#else +#define sx933x_match_table NULL +#endif +static const struct dev_pm_ops sx933x_pm_ops = +{ + .suspend = sx933x_suspend, + .resume = sx933x_resume, +}; +static struct i2c_driver sx933x_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .of_match_table = sx933x_match_table, + .pm = &sx933x_pm_ops, + }, + .id_table = sx933x_idtable, + .probe = sx933x_probe, + .remove = sx933x_remove, +}; +static int __init sx933x_I2C_init(void) +{ + return i2c_add_driver(&sx933x_driver); +} +static void __exit sx933x_I2C_exit(void) +{ + i2c_del_driver(&sx933x_driver); +} + +module_init(sx933x_I2C_init); +module_exit(sx933x_I2C_exit); + +MODULE_AUTHOR("Semtech Corp. (http://www.semtech.com/)"); +MODULE_DESCRIPTION("SX933x Capacitive Proximity Controller Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1"); + +static void sx93XX_schedule_work(psx93XX_t this, unsigned long delay) +{ + unsigned long flags; + if (this) + { + LOG_INFO("sx93XX_schedule_work()\n"); + spin_lock_irqsave(&this->lock,flags); + /* Stop any pending penup queues */ + cancel_delayed_work(&this->dworker); + //after waiting for a delay, this put the job in the kernel-global workqueue. so no need to create new thread in work queue. + schedule_delayed_work(&this->dworker,delay); + spin_unlock_irqrestore(&this->lock,flags); + } + else + LOG_DBG("sx93XX_schedule_work, NULL psx93XX_t\n"); +} + +static irqreturn_t sx93XX_irq(int irq, void *pvoid) +{ + psx93XX_t this = 0; + if (pvoid) + { + this = (psx93XX_t)pvoid; + if ((!this->get_nirq_low) || this->get_nirq_low()) + { + LOG_INFO("sx93XX_irq - call sx93XX_schedule_work\n"); + sx93XX_schedule_work(this,0); + } + else + { + LOG_DBG("sx93XX_irq - nirq read high\n"); + } + } + else + { + LOG_DBG("sx93XX_irq, NULL pvoid\n"); + } + return IRQ_HANDLED; +} + +static void sx93XX_worker_func(struct work_struct *work) +{ + psx93XX_t this = 0; + int status = 0; + int counter = 0; + u8 nirqLow = 0; + if (work) + { + this = container_of(work,sx93XX_t,dworker.work); + + if (!this) + { + LOG_DBG("sx93XX_worker_func, NULL sx93XX_t\n"); + return; + } + if (unlikely(this->useIrqTimer)) + { + if ((!this->get_nirq_low) || this->get_nirq_low()) + { + nirqLow = 1; + } + } + /* since we are not in an interrupt don't need to disable irq. */ + status = this->refreshStatus(this); + counter = -1; + LOG_INFO("Worker_func - Refresh Status %d, use_timer_in_irq:%d\n", status, this->useIrqTimer); + + while((++counter) < MAX_NUM_STATUS_BITS) /* counter start from MSB */ + { + if (((status>>counter) & 0x01) && (this->statusFunc[counter])) + { + LOG_INFO("SX933x Function Pointer Found. Calling\n"); + this->statusFunc[counter](this); + } + } + if (unlikely(this->useIrqTimer && nirqLow)) + { + /* Early models and if RATE=0 for newer models require a penup timer */ + /* Queue up the function again for checking on penup */ + sx93XX_schedule_work(this,msecs_to_jiffies(this->irqTimeout)); + } + } + else + { + LOG_DBG("sx93XX_worker_func, NULL work_struct\n"); + } +} + +int sx93XX_IRQ_init(psx93XX_t this) +{ + int err = 0; + if (this && this->pDevice) + { + /* initialize spin lock */ + spin_lock_init(&this->lock); + /* initialize worker function */ + INIT_DELAYED_WORK(&this->dworker, sx93XX_worker_func); + /* initailize interrupt reporting */ + this->irq_disabled = 0; + err = request_irq(this->irq, sx93XX_irq, IRQF_TRIGGER_FALLING, + this->pdev->driver->name, this); + if (err) + { + LOG_DBG("irq %d busy?\n", this->irq); + return err; + } + LOG_DBG("registered with irq (%d)\n", this->irq); + } + return -ENOMEM; +} diff --git a/drivers/regulator/s2mpu09-regulator.c b/drivers/regulator/s2mpu09-regulator.c old mode 100644 new mode 100755 index 931d0d8bec5a..4add8f76d8a4 --- a/drivers/regulator/s2mpu09-regulator.c +++ b/drivers/regulator/s2mpu09-regulator.c @@ -733,6 +733,7 @@ static int s2mpu09_pmic_probe(struct platform_device *pdev) } } + s2mpu09_update_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_L25CTRL, 0xC0, 0xC0); pr_info("%s s2mpu09 pmic driver Loading end\n", __func__); s2mpu09_update_reg(s2mpu09->i2c, S2MPU09_PMIC_REG_RTCBUF, 0x4, 0x4); -- 2.20.1