diff --git a/Makefile b/Makefile index 8728559547db..8be31a14d44e 100644 --- a/Makefile +++ b/Makefile @@ -340,7 +340,7 @@ DEPMOD = /sbin/depmod PERL = perl CHECK = sparse -ifeq ($(CONFIG_FIPS_FMP_UFS),) +ifeq ($(CONFIG_FIPS_FMP),) READELF = $(CROSS_COMPILE)readelf export READELF endif @@ -695,6 +695,14 @@ KBUILD_CPPFLAGS += $(KCPPFLAGS) KBUILD_AFLAGS += $(KAFLAGS) KBUILD_CFLAGS += $(KCFLAGS) +ifeq ($(CONFIG_SENSORS_FINGERPRINT), y) +ifneq ($(CONFIG_SEC_FACTORY), true) +ifneq ($(SEC_BUILD_CONF_USE_FINGERPRINT_TZ), false) + export KBUILD_FP_SENSOR_CFLAGS := -DENABLE_SENSORS_FPRINT_SECURE +endif +endif +endif + # Use --build-id when available. LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ $(call cc-ldoption, -Wl$(comma)--build-id,)) diff --git a/arch/arm64/boot/dts/exynos7420-pinctrl.dtsi b/arch/arm64/boot/dts/exynos7420-pinctrl.dtsi index 603eced825fb..46b7a2935fa1 100644 --- a/arch/arm64/boot/dts/exynos7420-pinctrl.dtsi +++ b/arch/arm64/boot/dts/exynos7420-pinctrl.dtsi @@ -52,6 +52,27 @@ #interrupt-cells = <2>; }; + hrm_irq: hrm-irq { + samsung,pins = "gpa1-5"; + samsung,pin-function = <0>; + samsung,pin-pud = <1>; + samsung,pin-drv = <3>; + }; + + hrm_irqsleep: hrm-irqsleep { + samsung,pins = "gpa1-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <1>; + samsung,pin-drv = <3>; + }; + + hrm_irqidle: hrm-irqidle { + samsung,pins = "gpa1-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <1>; + samsung,pin-drv = <3>; + }; + bt_hostwake: bt-hostwake { samsung,pins = "gpa2-1"; samsung,pin-function = <0>; @@ -94,6 +115,13 @@ samsung,pin-function = <0>; samsung,pin-pud = <0>; }; + + grip_irq: grip-irq { + samsung,pins = "gpa3-4"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <3>; + }; }; pinctrl@114B0000 { @@ -1190,6 +1218,20 @@ samsung,pin-con-pdn = <3>; samsung,pin-pud-pdn = <0>; }; + + grip_i2c: grip-i2c { + samsung,pins = "gpr1-3", "gpr1-4"; + samsung,pin-function = <0x0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <3>; + }; + + grip_ldo: grip-ldo { + samsung,pins = "gpr1-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + samsung,pin-drv = <3>; + }; }; }; diff --git a/arch/arm64/boot/dts/exynos7420-zero_common.dtsi b/arch/arm64/boot/dts/exynos7420-zero_common.dtsi index 2244a394ae97..8af0463958ff 100644 --- a/arch/arm64/boot/dts/exynos7420-zero_common.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zero_common.dtsi @@ -403,9 +403,9 @@ normal_powermode_current_rd = <10>; low_powermode_current_rd = <2>; - br_ratio_r_rd = <90>; + br_ratio_r_rd = <180>; br_ratio_g_rd = <30>; - br_ratio_b_rd = <50>; + br_ratio_b_rd = <30>; }; hsi2c@13660000 { @@ -508,6 +508,10 @@ reg = <0x51>; interrupt-parent = <&gpa1>; interrupts = <5 0 0>; + pinctrl-names = "default", "sleep", "idle"; + pinctrl-0 = <&hrm_irq>; + pinctrl-1 = <&hrm_irqsleep>; + pinctrl-2 = <&hrm_irqidle>; max86900,hrm_int-gpio = <&gpa1 5 0>; max86900,vdd_1p8 = "HRM_VDD_1.8V"; max86900,led_3p3 = "V_HRM_3.3V"; @@ -849,7 +853,7 @@ ipa_pdata { compatible = "samsung,exynos-ipa"; - control_temp = <90>; + control_temp = <45>; temp_threshold = <10>; enabled = <1>; tdp = <3500>; @@ -1206,25 +1210,34 @@ ois@24{ compatible = "rumba,ois"; reg = <0x24>; + use_i2c_pinctrl; fimc_is_ois_pinname = "13470000.pinctrl"; fimc_is_ois_sda = "gpc2-4"; fimc_is_ois_scl = "gpc2-5"; + pinfunc_on = <0>; + pinfunc_off = <2>; }; af@0c{ compatible = "samsung,af"; reg = <0x0c>; + use_i2c_pinctrl; fimc_is_af_pinname = "13470000.pinctrl"; fimc_is_af_sda = "gpc2-4"; fimc_is_af_scl = "gpc2-5"; + pinfunc_on = <0>; + pinfunc_off = <2>; }; front_eeprom@51 { compatible = "samsung,front-eeprom-i2c"; reg = <0x51>; + use_i2c_pinctrl; fimc_is_front_eeprom_pinname = "13470000.pinctrl"; fimc_is_front_eeprom_sda = "gpb2-4"; fimc_is_front_eeprom_scl = "gpb2-5"; + pinfunc_on = <0>; + pinfunc_off = <2>; }; }; @@ -1324,6 +1337,26 @@ pinctrl-0 = <&fimc_is_flash_is &fimc_is_mclk0_out &fimc_is_mclk1_out &fimc_is_mclk2_out>; pinctrl-1 = <>; + total_camera_num = <2>; + camera_info0 { // 0 : rear + isp = <0>; /* 0 : INT , 1 : EXT , 2 : SOC */ + cal_memory = <1>; /* 0 : N , 1 : FROM , 2 : EEPROM , 3 : OTP */ + read_version = <0>; /* 0 : SYSFS , 1 : CAMON */ + core_voltage = <1>; /* 0 : N , 1 : Y */ + upgrade = <1>; /* 0 : N , 1 : SYSFS , 2 : CAMON */ + companion = <1>; /* 0 : N , 1 : Y */ + ois = <1>; /* 0 : N , 1 : Y */ + }; + camera_info1 { // 1 : front + isp = <0>; /* 0 : INT , 1 : EXT , 2 : SOC */ + cal_memory = <2>; /* 0 : N , 1 : FROM , 2 : EEPROM , 3 : OTP */ + read_version = <0>; /* 0 : SYSFS , 1 : CAMON */ + core_voltage = <0>; /* 0 : N , 1 : Y */ + upgrade = <0>; /* 0 : N , 1 : SYSFS , 2 : CAMON */ + companion = <1>; /* 0 : N , 1 : Y */ + ois = <0>; /* 0 : N , 1 : Y */ + }; + #define DVFS_INT_L0 560000 #define DVFS_INT_L1 550000 #define DVFS_INT_L2 540000 @@ -1993,10 +2026,9 @@ boot_device@3 { net_boost,label="P2P"; net_boost,node="p2p-wlan0-0"; - net_boost,table_size = <3>; + net_boost,table_size = <2>; net_boost,table= < - 30 1000000 0 800000 0 0 200000 0 0 0 - 50 1200000 0 1000000 0 0 200000 0 0 0 + 30 1200000 0 1200000 0 0 200000 0 0 0 90 1700000 0 1200000 0 543000 267000 0 0 1 >; }; @@ -2005,8 +2037,8 @@ net_boost,node="wlan0"; net_boost,table_size = <3>; net_boost,table= < - 60 1000000 0 800000 0 0 200000 0 0 0 - 100 1200000 0 1000000 0 0 200000 0 0 0 + 20 1000000 0 800000 0 0 200000 0 0 0 + 60 1500000 0 1200000 0 0 200000 0 0 0 180 1896000 0 1500000 0 543000 267000 1 1 1 >; }; diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_battery.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_battery.dtsi index 3c58f4c98032..ed7af4fdee36 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_battery.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_battery.dtsi @@ -73,7 +73,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; - /*battery,wpc_temp_check = <1>;*/ + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -87,7 +87,7 @@ battery,chg_temp_table_data = <700 650 630 600 580 550 500 450 430 400 350 300 250 200 150 100 50 0 (-30) (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2550 1000 2550 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -143,9 +143,9 @@ battery,chg_skip_capacity = <10>; battery,chg_skip_time = <600>; - battery,wpc_high_temp = <390>; - battery,wpc_high_temp_recovery = <200>; - battery,wpc_charging_limit_current = <700>; + battery,wpc_high_temp = <400>; + battery,wpc_high_temp_recovery = <390>; + battery,wpc_charging_limit_current = <450>; /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_battery_06.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_battery_06.dtsi index 8461fbb0e14c..00ce9291b268 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_battery_06.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_battery_06.dtsi @@ -73,7 +73,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; - /*battery,wpc_temp_check = <1>;*/ + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -95,10 +95,10 @@ battery,wireless_cc_cv = <86>; battery,inbat_voltage = <1>; - battery,inbat_voltage_table_adc = <2905 2873 2848 2819 2787 2762 2731 2677 2655 2619 - 2591 2565 2534 2504 2475 2445 2420 2401 2364 2343>; - battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 400 395 390 - 385 380 375 370 365 360 355 350 345 340>; + battery,inbat_voltage_table_adc = <3120 3101 3061 3038 3001 2956 2920 2887 2856 2814 + 2793 2754 2720 2677 2641 2613 2572 2531 2502 2467 2436>; + battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 405 400 395 + 390 385 380 375 370 365 360 355 350 345 340>; battery,adc_check_count = <5>; @@ -151,9 +151,9 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; - battery,wpc_high_temp = <390>; - battery,wpc_high_temp_recovery = <200>; - battery,wpc_charging_limit_current = <700>; + battery,wpc_high_temp = <420>; + battery,wpc_high_temp_recovery = <410>; + battery,wpc_charging_limit_current = <450>; /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | @@ -165,13 +165,13 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; battery,charging_reset_time = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; battery,self_discharging_en; battery,force_discharging_limit = <650>; @@ -345,7 +345,7 @@ battery,chg_polarity_en = <0>; battery,chg_gpio_status = <0>; battery,chg_polarity_status = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; }; }; diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_svcled.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_svcled.dtsi index 240c088ae91d..2587ab356a7b 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_svcled.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_svcled.dtsi @@ -44,8 +44,8 @@ normal_powermode_current_rd = <10>; low_powermode_current_rd = <2>; - br_ratio_r_bl = <450>; - br_ratio_g_bl = <230>; - br_ratio_b_bl = <830>; + br_ratio_r_rd = <450>; + br_ratio_g_rd = <230>; + br_ratio_b_rd = <830>; }; }; diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_05.dts b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_05.dts index 58805f574fcc..8160c27f07cb 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_05.dts +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_05.dts @@ -350,9 +350,8 @@ audio_pdata { compatible = "samsung,audio-pdata"; - aif_format = <0x00 0x13 0x00>; - /* I2S: 0x00, TDM: 0x10 */ - /* I2S: 0x0, Right-J: 0x1 Left-J: 0x2, DSP A: 0x3, DSP B: 0x4, */ + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; imp_table = < /* min max gain */ diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery.dtsi index 710de889516c..8ae4d54da7ae 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery.dtsi @@ -73,7 +73,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; - /*battery,wpc_temp_check = <1>;*/ + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -87,7 +87,7 @@ battery,chg_temp_table_data = <700 650 630 600 580 550 500 450 430 400 350 300 250 200 150 100 50 0 (-30) (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2550 1000 2550 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -143,9 +143,9 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; - battery,wpc_high_temp = <390>; - battery,wpc_high_temp_recovery = <200>; - battery,wpc_charging_limit_current = <700>; + battery,wpc_high_temp = <420>; + battery,wpc_high_temp_recovery = <410>; + battery,wpc_charging_limit_current = <450>; /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery_06.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery_06.dtsi index 6b2e90b17328..00d01433e6c4 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery_06.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_battery_06.dtsi @@ -72,7 +72,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; - /*battery,wpc_temp_check = <1>;*/ + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -86,7 +86,7 @@ battery,chg_temp_table_data = <700 650 630 600 580 550 500 450 430 400 350 300 250 200 150 100 50 0 (-30) (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2500 1000 2500 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -94,10 +94,10 @@ battery,wireless_cc_cv = <86>; battery,inbat_voltage = <1>; - battery,inbat_voltage_table_adc = <2905 2873 2848 2819 2787 2762 2731 2677 2655 2619 - 2591 2565 2534 2504 2475 2445 2420 2401 2364 2343>; - battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 400 395 390 - 385 380 375 370 365 360 355 350 345 340>; + battery,inbat_voltage_table_adc = <3120 3101 3061 3038 3001 2956 2920 2887 2856 2814 + 2793 2754 2720 2677 2641 2613 2572 2531 2502 2467 2436>; + battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 405 400 395 + 390 385 380 375 370 365 360 355 350 345 340>; battery,adc_check_count = <5>; @@ -150,9 +150,9 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; - battery,wpc_high_temp = <390>; - battery,wpc_high_temp_recovery = <200>; - battery,wpc_charging_limit_current = <700>; + battery,wpc_high_temp = <420>; + battery,wpc_high_temp_recovery = <410>; + battery,wpc_charging_limit_current = <450>; /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | @@ -164,13 +164,13 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; battery,charging_reset_time = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; battery,self_discharging_en; battery,force_discharging_limit = <650>; @@ -343,7 +343,7 @@ battery,chg_polarity_en = <0>; battery,chg_gpio_status = <0>; battery,chg_polarity_status = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; }; }; diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_03.dts b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_03.dts index f9f4a7f3672b..0c8f764601ef 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_03.dts +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_03.dts @@ -338,9 +338,8 @@ audio_pdata { compatible = "samsung,audio-pdata"; - aif_format = <0x00 0x13 0x00>; - /* I2S: 0x00, TDM: 0x10 */ - /* I2S: 0x0, Right-J: 0x1 Left-J: 0x2, DSP A: 0x3, DSP B: 0x4, */ + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; imp_table = < /* min max gain */ diff --git a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_battery_07.dtsi b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_battery_07.dtsi index 36bdf3ba2ea2..1d3f9e1281c4 100644 --- a/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_battery_07.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zeroflte_usa_cdma_battery_07.dtsi @@ -72,7 +72,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; - /*battery,wpc_temp_check = <1>;*/ + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -86,7 +86,7 @@ battery,chg_temp_table_data = <700 650 630 600 580 550 500 450 430 400 350 300 250 200 150 100 50 0 (-30) (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2500 1000 2500 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -94,10 +94,10 @@ battery,wireless_cc_cv = <86>; battery,inbat_voltage = <1>; - battery,inbat_voltage_table_adc = <2905 2873 2848 2819 2787 2762 2731 2677 2655 2619 - 2591 2565 2534 2504 2475 2445 2420 2401 2364 2343>; - battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 400 395 390 - 385 380 375 370 365 360 355 350 345 340>; + battery,inbat_voltage_table_adc = <3120 3101 3061 3038 3001 2956 2920 2887 2856 2814 + 2793 2754 2720 2677 2641 2613 2572 2531 2502 2467 2436>; + battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 405 400 395 + 390 385 380 375 370 365 360 355 350 345 340>; battery,adc_check_count = <5>; @@ -150,9 +150,9 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; - battery,wpc_high_temp = <390>; - battery,wpc_high_temp_recovery = <200>; - battery,wpc_charging_limit_current = <700>; + battery,wpc_high_temp = <420>; + battery,wpc_high_temp_recovery = <410>; + battery,wpc_charging_limit_current = <450>; /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | @@ -164,13 +164,13 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; battery,charging_reset_time = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; battery,self_discharging_en; battery,force_discharging_limit = <650>; @@ -343,7 +343,7 @@ battery,chg_polarity_en = <0>; battery,chg_gpio_status = <0>; battery,chg_polarity_status = <0>; - battery,chg_float_voltage = <4375>; + battery,chg_float_voltage = <4350>; }; }; diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_battery.dtsi b/arch/arm64/boot/dts/exynos7420-zerolte_battery.dtsi index b090d6519cc0..9a61254168bf 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_battery.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zerolte_battery.dtsi @@ -76,6 +76,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -93,7 +94,7 @@ 400 350 300 250 200 150 100 50 0 (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2600 1000 2600 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -149,6 +150,10 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; + battery,wpc_high_temp = <410>; + battery,wpc_high_temp_recovery = <400>; + battery,wpc_charging_limit_current = <450>; + /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | SEC_BATTERY_FULL_CONDITION_VCELL */ diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_battery_06.dtsi b/arch/arm64/boot/dts/exynos7420-zerolte_battery_06.dtsi index dbb1c62fa56c..b395acf87c40 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_battery_06.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zerolte_battery_06.dtsi @@ -73,6 +73,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -154,6 +155,10 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; + battery,wpc_high_temp = <410>; + battery,wpc_high_temp_recovery = <400>; + battery,wpc_charging_limit_current = <450>; + /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | SEC_BATTERY_FULL_CONDITION_VCELL */ @@ -164,7 +169,7 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; @@ -194,6 +199,36 @@ io-channel-names = "adc-temp", "chg-adc-temp", "in-bat-adc", "discharging-check-adc", "ntc-check-adc"; #io-channel-cells = <5>; io-channel-ranges; + + /***********************************************************/ + /* VE_SW for Battery Self Discharging(to prevent swelling) */ + /* Enable TYPE : sdchg_ic, sdchg_ap, sdchg_cs, sdchg_ldo, ... */ + /* The following line, "sdchg_type", is annotaed to support the dualization for Zero project. + In case of other projects, "sdchg_type" should be designated to decide the way of self-discharging. + In general cases, the default type is "sdchg_ic",which means self-discharging IC on PCB, + unless "sdchg_type" is not designated.*/ + /* + sdchg_type = "sdchg_ic"; + */ + sdchg_ap { + compatible = "samsung,sdchg_ap"; + sdchg,temperature_start = <600>; + sdchg,temperature_end = <550>; + sdchg,soc_start = <96>; + sdchg,soc_end = <92>; + sdchg,voltage_start = <4250>; + /* sdchg,voltage_end = <4200>; -> from battery,swelling_drop_float_voltage */ + }; + sdchg_cs { + compatible = "samsung,sdchg_cs"; + sdchg,temperature_start = <600>; + sdchg,temperature_end = <550>; + sdchg,soc_start = <96>; + sdchg,soc_end = <92>; + sdchg,voltage_start = <4250>; + /* sdchg,voltage_end = <4200>; -> from battery,swelling_drop_float_voltage */ + }; + /***********************************************************/ }; max77833-fuelgauge { diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_06.dts b/arch/arm64/boot/dts/exynos7420-zerolte_usa_06.dts index 7ee315700da9..39a6170946d0 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_usa_06.dts +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_06.dts @@ -348,9 +348,8 @@ audio_pdata { compatible = "samsung,audio-pdata"; - aif_format = <0x00 0x13 0x00>; - /* I2S: 0x00, TDM: 0x10 */ - /* I2S: 0x0, Right-J: 0x1 Left-J: 0x2, DSP A: 0x3, DSP B: 0x4, */ + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; imp_table = < /* min max gain */ @@ -847,7 +846,7 @@ 1912>; }; - sec_thermistor@1 { + sec_thermistor@2 { status = "okay"; adc_array = <202 212 223 234 244 255 265 276 287 297 diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_07.dts b/arch/arm64/boot/dts/exynos7420-zerolte_usa_07.dts new file mode 100644 index 000000000000..75f32948ff54 --- /dev/null +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_07.dts @@ -0,0 +1,904 @@ +/* + * SAMSUNG UNIVERSAL7420 board device tree source + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +#include "exynos7420-zero_common.dtsi" +#include "exynos7420-zerolte_usa_battery_05.dtsi" +#include "exynos7420-zerolte_gpio_usa_07.dtsi" +#include "exynos7420-zerolte_modem-shannon.dtsi" +#include "exynos7420-zerolte_fingerprint-sensor_00.dtsi" +#include "exynos7420-zerolte_mst.dtsi" + +/ { + model = "Samsung ZERO LTE USA rev06 board based on Exynos7420(EVT1), mPOP"; + model_info-chip = <7420>; + model_info-platform = "android"; + model_info-subtype = "samsung"; + model_info-hw_rev = <11>; + model_info-hw_rev_end = <255>; + compatible = "samsung,ZERO LTE USA EVT1 mPOP,r06", "samsung,exynos7420"; + + spi_0: spi@14d20000 { + /delete-property/ dma-mode; + /delete-property/ dmas; + /delete-property/ dma-names; + + num-cs = <1>; + status = "okay"; + + audio_codec: wm1840@0 { + compatible = "wlf,wm1840"; + reg = <0x0>; + spi-max-frequency = <20000000>; + interrupts = <5 0 0>; + interrupt-parent = <&gpa2>; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names ="default"; + pinctrl-0 = <&codec_reset &codec_irq>; + + wlf,reset = <&gpf4 0 0>; + wlf,init-mic-delay = <30>; + wlf,use-jd-gpio; + wlf,micd-clamp-mode = <0x8>; + wlf,micd-detect-debounce = <300>; + wlf,micd-pol-gpio = <0>; + wlf,micd-bias-start-time = <0x1>; + wlf,micd-rate = <0x7>; + wlf,micd-dbtime = <0x1>; + wlf,micd-timeout = <1000>; + wlf,micd-force-micbias; + wlf,hpdet-moisture-imp = <2000>; + wlf,hpdet-moisture-debounce = <40>; + wlf,hpdet-channel = <1>; + wlf,hpdet-ext-res = <33>; + wlf,hpdet-short-circuit-imp = <0>; + wlf,micd-ranges = < + 116 226 + 173 582 + 321 115 + 752 114 + 1257 217 + >; + + wlf,micd-configs = < + 0x0 2 0 + >; + + wlf,micbias1 = <1800 0 1 0 0>; + wlf,micbias2 = <2800 0 1 0 0>; + wlf,micbias3 = <1800 0 1 0 0>; + wlf,micbias4 = <1800 0 1 0 0>; + + wlf,gpio-defaults = < + 0xffffffff 0xffffffff /* GPIO1 */ + 0xffffffff 0xffffffff /* GPIO2 */ + 0xffffffff 0xffffffff /* GPIO3 */ + 0xffffffff 0xffffffff /* GPIO4 */ + 0xffffffff 0xffffffff /* GPIO5 */ + 0xffffffff 0xffffffff /* GPIO6 */ + 0xffffffff 0xffffffff /* GPIO7 */ + 0xffffffff 0xffffffff /* GPIO8 */ + 0xffffffff 0xffffffff /* MIF1SCLK / GPIO9 */ + 0xffffffff 0xffffffff /* MIF1SDA / GPIO10 */ + 0xffffffff 0xffffffff /* MIF2SCLK / GPIO11 */ + 0xffffffff 0xffffffff /* MIF2SDA / GPIO12 */ + 0xffffffff 0xffffffff /* MIF3SCLK / GPIO13 */ + 0xffffffff 0xffffffff /* MIF3SDA / GPIO14 */ + 0x00002000 0x00006000 /* AIF1TXDAT / GPIO15 */ + 0x00002000 0x00006000 /* AIF1BCLK / GPIO16 */ + 0x00002000 0x00006000 /* AIF1RXDAT / GPIO17 */ + 0x00002000 0x00006000 /* AIF1LRCLK / GPIO18 */ + 0x00002000 0x00006000 /* AIF2TXDAT / GPIO19 */ + 0x00002000 0x00006000 /* AIF2BCLK / GPIO20 */ + 0x00002000 0x00006000 /* AIF2RXDAT / GPIO21 */ + 0x00002000 0x00006000 /* AIF2LRCLK / GPIO22 */ + 0x00002000 0x00006000 /* AIF3TXDAT / GPIO23 */ + 0x00002000 0x00006000 /* AIF3BCLK / GPIO24 */ + 0x00002000 0x00006000 /* AIF3RXDAT / GPIO25 */ + 0x00002000 0x00006000 /* AIF3LRCLK / GPIO26 */ + 0x00002000 0x00006000 /* AIF4TXDAT / GPIO27 */ + 0x00002000 0x00006000 /* AIF4BCLK / GPIO28 */ + 0x00002000 0x00006000 /* AIF4RXDAT / GPIO29 */ + 0x00002000 0x00006000 /* AIF4LRCLK / GPIO30 */ + 0x00002000 0x0000e000 /* DMICCLK4 / GPIO31 */ + 0x00002000 0x0000e000 /* DMICDAT4 / GPIO32 */ + 0xffffffff 0xffffffff /* DMICCLK5 / GPIO33 */ + 0xffffffff 0xffffffff /* DMICDAT5 / GPIO34 */ + 0xffffffff 0xffffffff /* DMICCLK6 / GPIO35 */ + 0xffffffff 0xffffffff /* DMICDAT6 / GPIO36 */ + 0xffffffff 0xffffffff /* SPKCLK1 / GPIO37 */ + 0xffffffff 0xffffffff /* SPKCLK2 / GPIO38 */ + 0xffffffff 0xffffffff /* SPKDAT1 / GPIO39 */ + 0xffffffff 0xffffffff /* SPKDAT2 / GPIO40 */ + >; + + wlf,gpsw = <0x3>; + wlf,micd-software-compare; + wlf,micd-open-circuit-declare = <1>; + wlf,jd-wake-time = <5000>; + + wlf,max-channels-clocked = <2 0 0 0>; + /* 0:MICVDD 1:MICBIAS1 2:MICBIAS2 3:MICBIAS3 */ + wlf,dmic-ref = <1 2 1 0 0 0>; + /* 1st cell:IN1L 2rd cell:IN1R 3nd cell:IN2L 4th cell:IN2R... 12th cell:IN6R */ + wlf,inmode = <2 2 0 0 2 2 2 2 0 0 0 0>; + /* 1st cell:OUT1 2nd cell:OUT2 3rd cell:OUT3... 6th cell:OUT6 */ + wlf,out-mono = <0 1 1 0 0 0>; + + wlf,rev-specific-fw; + + DCVDD-supply = <&ldo26_reg>; + AVDD-supply = <&ldo16_reg>; + LDOVDD-supply = <&ldo16_reg>; + DBVDD1-supply = <&ldo16_reg>; + + CPVDD-supply = <&ldo16_reg>; + DBVDD2-supply = <&ldo16_reg>; + DBVDD3-supply = <&ldo16_reg>; + DBVDD4-supply = <&ldo16_reg>; + SPKVDDL-supply = <&ldo16_reg>; + SPKVDDR-supply = <&ldo16_reg>; + + adsps { + #address-cells = <1>; + #size-cells = <0>; + + adsp@0FFE00 { + reg = <0x0FFE00>; + firmware { + TRACE { + wlf,wmfw-file = "trace"; + wlf,bin-file = "None"; + wlf,compr-caps = <1 8 0x4 1 8000 16000 24000>; + }; + }; + }; + adsp@17FE00 { + reg = <0x17FE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "None"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "None"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_FB_MEETING { + wlf,wmfw-file = "tx-fb-meeting"; + wlf,bin-file = "tx-fb-meeting"; + }; + }; + }; + adsp@1FFE00 { + reg = <0x1FFE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "tx-nb"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "tx-wb"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-interview"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-conversation"; + }; + TX_WB_MEETING { + wlf,wmfw-file = "tx-wb-meeting"; + wlf,bin-file = "tx-wb-meeting"; + }; + }; + }; + adsp@27FE00 { + reg = <0x27FE00>; + firmware { + RX_NB { + wlf,wmfw-file = "rx-anc-nb"; + wlf,bin-file = "rx-anc-nb"; + }; + RX_WB { + wlf,wmfw-file = "rx-anc-wb"; + wlf,bin-file = "rx-anc-wb"; + }; + }; + }; + adsp@37FE00 { + reg = <0x37FE00>; + firmware { + VOICECONTROL { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "ez2-control"; + wlf,compr-caps = <1 1 0x4 1 16000>; + }; + LPSD { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "lpsd-control"; + }; + }; + }; + adsp@2FFE00 { + reg = <0x2FFE00>; + firmware { + DSM { + wlf,wmfw-file = "dsm"; + wlf,bin-file = "None"; + }; + }; + }; + }; + controller-data { + cs-gpio = <&gpd8 1 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + spi_1: spi@14d30000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi1_mosi_sck_ssn &spi1_miso>; + + num-cs = <1>; + status = "okay"; + + BCM4773@0 { + compatible = "ssp,BCM4773"; + reg = <0>; + spi-max-frequency = <26000000>; + spi-cpol; + spi-cpha; + pinctrl-names = "default"; + pinctrl-0 = <&ssp_host_req &ssp_mcu_req &ssp_mcu_resp>; + + gpio-controller; + #gpio-cells = <2>; + ssp-host-req = <&gpa3 6 0x01>; + ssp-mcu-req = <&gpf4 5 0x01>; + ssp-mcu-resp = <&gpf4 4 0x00>; + ssp-acc-position = <0>; + ssp-mag-position = <6>; + ssp-sns-combination = <0>; + ssp-acc-type = <1>; + ssp,prox-hi_thresh = <2000>; + ssp,prox-low_thresh = <1400>; + ssp-ap-rev = <1>; + ssp-mag-array = <9930 866 (-228) 263 9197 121 (-135) 387 10378>; + ssp-hw-rev = <3>; + ssp-glass-type = <1>; + + controller-data { + cs-gpio = <&gpd6 3 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + gps { + compatible = "samsung,exynos54xx-bcm4753"; + + pinctrl-names = "default"; + pinctrl-0 = <&ssp_gps_pwr_en &ssp_host_wake>; + + gpios = <&gpf4 7 0x1 + &gpa3 2 0xf>; + status = "okay"; + }; + + spi_3: spi@14d50000 { + spiclk-pindev-name = "14c90000.pinctrl"; + spiclk-pin-name = "gpg4-0"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default","ese-pwoff","clk-fix","clk-recover","ese-disable"; + pinctrl-0 = <&spi3_bus>; + pinctrl-1 = <&spi3_ese_pwoff>; + pinctrl-2 = <&spi3_clk_fix>; + pinctrl-3 = <&spi3_clk_recover>; + pinctrl-4 = <&spi3_ese_disable>; + samsung,ese-oberthur; + + ese_spi@0 { + compatible = "ese_p3"; + reg = <0>; + spi-max-frequency = <10000000>; + + gpio-controller; + #gpio-cells = <2>; + + p3-mosipin = <21>; + p3-misopin = <22>; + p3-cspin = <23>; + p3-clkpin = <24>; + p3-cs-gpio = <&gpg4 1 0>; + p3-vdd-1p8= "VDD_1.8V_ESE"; + + controller-data { + samsung,spi-chip-select-mode = <1>; + }; + }; + }; + + audio_pdata { + compatible = "samsung,audio-pdata"; + + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; + + imp_table = < + /* min max gain */ + 0 13 0 + 14 42 3 + 43 100 5 + 101 200 7 + 201 450 9 + 451 1000 10 + 1001 0x7fffffff 0 + >; + + seamless_voicewakeup; + status = "okay"; + }; + + antenna_switch { + status = "okay"; + compatible = "antenna_switch"; + pinctrl-names = "default"; + pinctrl-0 = <&antenna_switch_en>; + antenna_switch,gpio_antenna_switch = <&gpr3 6 0>; + }; + + pinctrl@10580000 { + codec_irq: codec-irq { + samsung,pins = "gpa2-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + }; + max98505_ctrl: max98505-ctl { + samsung,pins ="gpa2-0"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<2>; + samsung,pin-pud-pdn = <0>; + }; + }; + + pinctrl@13470000 { + es704_wakeup: es704-wakeup { + samsung,pins ="gpd0-1"; + samsung,pin-function = <1>; + samsung,pin-pud = <3>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <3>; + samsung,pin-val = <1>; + }; + max98505_i2c: max98505-i2c { + samsung,pins = "gpd2-0", "gpd2-1"; + samsung,pin-pud = <0>; + status = "okay"; + }; + es704_i2c: es704-i2c { + samsung,pins = "gpd2-7", "gpd2-6"; + samsung,pin-function = <0x3>; + samsung,pin-pud = <0x0>; + samsung,pin-drv = <0>; + }; + }; + + pinctrl@14870000 { + es704_reset: es704-reset { + samsung,pins ="gpf1-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <0>; + samsung,pin-val = <0>; + }; + codec_reset: codec-reset { + samsung,pins ="gpf4-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <1>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <1>; + samsung,pin-val = <0>; + }; + }; + + pinctrl@15690000 { + sub_pmic_irq: sub-pmic-irq { + samsung,pins ="gpr2-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + antenna_switch_en: antenna-switch-en { + samsung,pins = "gpr3-6"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-val = <0>; + }; + }; + + hsi2c@13640000 { + status = "okay"; + max98505@31 { + compatible = "maxim,max98505"; + reg = <0x31>; + pinctrl-names = "default"; + pinctrl-0 = <&max98505_i2c &max98505_ctrl>; + gpios = <&gpd2 1 0 + &gpd2 0 0 + >; + i2c-gpio,delay-us = <2>; + maxim,platform_type = <0>; + maxim,spk_vol = <0x14>; + maxim,sysclk = <12288000>; + }; + }; + + hsi2c@13650000{ + max77843@66 { + status = "okay"; + }; + }; + + hsi2c@13660000 { + s2mps15_pmic@66 { + regulators { + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_atlas"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck3_reg: BUCK3 { + regulator-name = "vdd_apollo"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck4_reg: BUCK4 { + regulator-name = "vdd_int"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck5_reg: BUCK5 { + regulator-name = "vdd_disp_cam0"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck6_reg: BUCK6 { + regulator-name = "vdd_g3d"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck8_reg: BUCK8 { + regulator-name = "vdd_lldo"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + buck9_reg: BUCK9 { + regulator-name = "vdd_mldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + ldo2_reg: LDO2 { + regulator-name = "vqmmc"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + regulator-boot-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "vdd_ldo8"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = <1>; + }; + + ldo15_reg: LDO15 { + regulator-name = "tsp_io"; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + ldo16_reg: LDO16 { + regulator-name = "VCC_1.8V_CODEC_PMIC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo17_reg: LDO17 { + regulator-name = "VCC_MOTOR_3.0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo18_reg: LDO18 { + regulator-name = "HRM_VDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1850000>; + }; + + ldo19_reg: LDO19 { + regulator-name = "MST_LEVEL_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo20_reg: LDO20 { + regulator-name = "VDD20_1P8_AP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo21_reg: LDO21 { + regulator-name = "key_led"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo22_reg: LDO22 { + regulator-name = "VDD22_1P1_2MIC"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-initial-mode = <3>; + }; + + ldo23_reg: LDO23 { + regulator-name = "VDD_1.8V_ESE"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo24_reg: LDO24 { + regulator-name = "V_HRM_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3350000>; + }; + + ldo25_reg: LDO25 { + regulator-name = "PROX_LED_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo26_reg: LDO26 { + regulator-name = "VDD_1.2V_CODEC"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + }; + }; + }; + + hsi2c@13670000 { + max77838@60 { + status = "disabled"; + }; + }; + + hsi2c@13680000 { + status = "okay"; + samsung,hs-mode; + clock-frequency = <1000000>; + earSmart@3e { + compatible = "earSmart"; + reg = <0x3e>; + clocks = <&clock 45>; + clock-names = "mclk"; + pinctrl-0 = <&es704_i2c &es704_reset &es704_wakeup>; + esxxx-reset-gpio = <&gpf1 0 0>; + esxxx-wakeup-gpio = <&gpd0 1 0>; + adnc,firmware_name = "audience-es804-fw.bin"; + }; + }; + + serial_0: uart@13630000 { + status = "okay"; + samsung,use-default-irq; + }; + + hsi2c@14E00000 { + sec-nfc@27 { + sec-nfc,i2c_1p8 = "VDD20_1P8_AP"; + }; + }; + + hsi2c@14E60000 { + status = "okay"; + /delete-node/ s2mpb01_pmic@59; + + s2mpb02@59 { + compatible = "samsung,s2mpb02"; + reg = <0x59>; + + s2mpb02,irq-gpio = <&gpr2 2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&sub_pmic_irq>; + + regulators { + _buck1_reg: s2mpb02-buck1 { + regulator-name = "VDD_1P6_DDR"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; + }; + + _buck2_reg: s2mpb02-buck2 { + regulator-name = "VDDD_CORE_0.8V_COMP"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <850000>; + }; + + _ldo1_reg: s2mpb02-ldo1 { + regulator-name = "VDDD_NORET_0.9V_COMP"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + }; + + _ldo2_reg: s2mpb02-ldo2 { + regulator-name = "VDDD_CORE_1.0V_COMP"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo3_reg: s2mpb02-ldo3 { + regulator-name = "VDDD_1.2V_CAM"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo4_reg: s2mpb02-ldo4 { + regulator-name = "VDDD_RET_1.0V_COMP"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo5_reg: s2mpb02-ldo5 { + regulator-name = "VDDD_1.2V_VT"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo6_reg: s2mpb02-ldo6 { + regulator-name = "VDDIO_1.8V_VT"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo7_reg: s2mpb02-ldo7 { + regulator-name = "VDDIO_1.8V_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo8_reg: s2mpb02-ldo8 { + regulator-name = "VDDIO_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo9_reg: s2mpb02-ldo9 { + regulator-name = "VDDA_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo10_reg: s2mpb02-ldo10 { + regulator-name = "VCC_DISPLAY_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo11_reg: s2mpb02-ldo11 { + regulator-name = "VDDA_2.9V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2950000>; + }; + + _ldo12_reg: s2mpb02-ldo12 { + regulator-name = "VDDAF_2.8V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo13_reg: s2mpb02-ldo13 { + regulator-name = "VDDA_2.9V_VT"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + + _ldo14_reg: s2mpb02-ldo14 { + regulator-name = "OIS_VM_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo15_reg: s2mpb02-ldo15 { + regulator-name = "OIS_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo16_reg: s2mpb02-ldo16 { + regulator-name = "VCC_3.0V_LCD"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + _ldo17_reg: s2mpb02-ldo17 { + regulator-name = "tsp_avdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + + torch { + status = "okay"; + leds1 { + ledname = "leds-sec1"; + /* S2MPB02_FLASH_LED_1 */ + id = <0>; + /* S2MPB02_FLASH_CURRENT */ + brightness = <0xF>; + /* S2MPB02_FLASH_TIMEOUT */ + timeout = <0x3>; + }; + + leds2 { + ledname = "torch-sec1"; + /* S2MPB02_TORCH_LED_1 */ + id = <1>; + /* S2MPB02_TORCH_CURRENT */ + brightness = <0x9>; + /* S2MPB02_TORCH_TIMEOUT */ + timeout = <0xF>; + }; + }; + }; + }; + + sec_thermistor@0 { + status = "okay"; + + adc_array = <202 212 223 234 244 255 265 276 287 297 + 307 317 327 337 348 359 369 380 390 400 + 410 425 440 455 470 486 501 517 532 547 + 562 575 588 600 613 625 645 665 686 707 + 728 749 770 790 811 832 855 878 902 925 + 948 964 980 996 1012 1028 1044 1060 1076 1092 + 1108 1134 1160 1186 1212 1237 1261 1286 1310 1335 + 1359 1378 1396 1414 1433 1452 1471 1489 1507 1525 + 1543 1560 1576 1593 1610 1626 1642 1658 1674 1690 + 1706 1717 1729 1742 1755 1768 1782 1796 1810 1824 + 1838 1847 1855 1864 1873 1882 1888 1894 1900 1906 + 1912>; + }; + + sec_thermistor@2 { + status = "okay"; + + adc_array = <202 212 223 234 244 255 265 276 287 297 + 307 317 327 337 348 359 369 380 390 400 + 410 425 440 455 470 486 501 517 532 547 + 562 575 588 600 613 625 645 665 686 707 + 728 749 770 790 811 832 855 878 902 925 + 948 964 980 996 1012 1028 1044 1060 1076 1092 + 1108 1134 1160 1186 1212 1237 1261 1286 1310 1335 + 1359 1378 1396 1414 1433 1452 1471 1489 1507 1525 + 1543 1560 1576 1593 1610 1626 1642 1658 1674 1690 + 1706 1717 1729 1742 1755 1768 1782 1796 1810 1824 + 1838 1847 1855 1864 1873 1882 1888 1894 1900 1906 + 1912>; + }; + + hsi2c@14E10000 { + touchscreen@20 { + stm,num_touchkey = <2>; + stm,regulator_tk_led = "key_led"; + }; + }; + + dwmmc0@15740000 { + status = "disabled"; + }; + + dwmmc2@15560000 { + vdd_vmmc-supply = <&ldo25_reg>; + vqmmc-supply = <&ldo2_reg>; + }; + + dsim_0: dsim@0x13900000 { + gpios = <&gpr3 0 0x1>; + regulator_30V = "VCC_3.0V_LCD"; + regulator_18V = "VCC_DISPLAY_1.8V"; + regulator_16V = "VDD_1P6_DDR"; + lcd_info = <&s6e3hf2_wqhd>; + }; + + s6e3hf2_wqhd: s6e3hf2_wqhd_panel { + mode = <2>; + resolution = <1440 2560>; + size = <63 112>; + timing,refresh = <60>; + timing,h-porch = <1 1 1>; + timing,v-porch = <15 1 1>; + timing,dsi-hs-clk = <1026>; + timing,dsi-escape-clk = <16>; + mic = <1>; + mic_ver = <2>; + type_of_ddi = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery.dtsi b/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery.dtsi index 6debd31708de..e969d799e134 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery.dtsi @@ -76,6 +76,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -93,7 +94,7 @@ 400 350 300 250 200 150 100 50 0 (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2600 1000 2600 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -149,6 +150,10 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; + battery,wpc_high_temp = <400>; + battery,wpc_high_temp_recovery = <390>; + battery,wpc_charging_limit_current = <450>; + /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | SEC_BATTERY_FULL_CONDITION_VCELL */ diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery_05.dtsi b/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery_05.dtsi index c30e6012c8c2..59820ffeb498 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery_05.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_battery_05.dtsi @@ -72,6 +72,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -89,7 +90,7 @@ 400 350 300 250 200 150 100 50 0 (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2550 1000 2550 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; @@ -97,10 +98,10 @@ battery,wireless_cc_cv = <90>; battery,inbat_voltage = <1>; - battery,inbat_voltage_table_adc = <2905 2873 2848 2819 2787 2762 2731 2677 2655 2619 - 2591 2565 2534 2504 2475 2445 2420 2401 2364 2343>; - battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 400 395 390 - 385 380 375 370 365 360 355 350 345 340>; + battery,inbat_voltage_table_adc = <3137 3113 3077 3045 3010 2976 2942 2904 2874 2832 + 2794 2763 2723 2693 2660 2623 2589 2552 2517 2481 2464>; + battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 405 400 395 + 390 385 380 375 370 365 360 355 350 345 340>; battery,adc_check_count = <5>; @@ -153,6 +154,10 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; + battery,wpc_high_temp = <400>; + battery,wpc_high_temp_recovery = <390>; + battery,wpc_charging_limit_current = <450>; + /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | SEC_BATTERY_FULL_CONDITION_VCELL */ @@ -163,7 +168,7 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_03.dts b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_03.dts index 898c8e251bf2..9aa617fe91a4 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_03.dts +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_03.dts @@ -23,7 +23,7 @@ model_info-platform = "android"; model_info-subtype = "samsung"; model_info-hw_rev = <10>; - model_info-hw_rev_end = <255>; + model_info-hw_rev_end = <10>; compatible = "samsung,ZERO LTE USA CDMA EVT1 mPOP,r07", "samsung,exynos7420"; spi_0: spi@14d20000 { @@ -337,9 +337,8 @@ audio_pdata { compatible = "samsung,audio-pdata"; - aif_format = <0x00 0x13 0x00>; - /* I2S: 0x00, TDM: 0x10 */ - /* I2S: 0x0, Right-J: 0x1 Left-J: 0x2, DSP A: 0x3, DSP B: 0x4, */ + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; imp_table = < /* min max gain */ @@ -732,7 +731,7 @@ _ldo3_reg: s2mpb02-ldo3 { regulator-name = "VDDD_1.2V_CAM"; regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1050000>; + regulator-max-microvolt = <1200000>; }; _ldo4_reg: s2mpb02-ldo4 { @@ -780,7 +779,7 @@ _ldo11_reg: s2mpb02-ldo11 { regulator-name = "VDDA_2.9V_CAM"; regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2900000>; + regulator-max-microvolt = <2950000>; }; _ldo12_reg: s2mpb02-ldo12 { @@ -873,7 +872,7 @@ 1912>; }; - sec_thermistor@1 { + sec_thermistor@2 { status = "okay"; adc_array = <205 216 227 238 249 260 271 282 293 303 diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_04.dts b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_04.dts new file mode 100644 index 000000000000..99d0cb7698dd --- /dev/null +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_04.dts @@ -0,0 +1,948 @@ +/* + * SAMSUNG UNIVERSAL7420 board device tree source + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +#include "exynos7420-zero_common.dtsi" +#include "exynos7420-zerolte_usa_cdma_battery_07.dtsi" +#include "exynos7420-zerolte_gpio_usa_cdma_04.dtsi" +#include "exynos7420-zerolte_modem-mdm9x35.dtsi" +#include "exynos7420-zerolte_fingerprint-sensor_00.dtsi" +#include "exynos7420-zerolte_mst.dtsi" + +/ { + model = "Samsung ZERO LTE USA CDMA rev08 board based on Exynos7420(EVT1), mPOP"; + model_info-chip = <7420>; + model_info-platform = "android"; + model_info-subtype = "samsung"; + model_info-hw_rev = <11>; + model_info-hw_rev_end = <11>; + compatible = "samsung,ZERO LTE USA CDMA EVT1 mPOP,r08", "samsung,exynos7420"; + + spi_0: spi@14d20000 { + /delete-property/ dma-mode; + /delete-property/ dmas; + /delete-property/ dma-names; + + num-cs = <1>; + status = "okay"; + + audio_codec: wm1840@0 { + compatible = "wlf,wm1840"; + reg = <0x0>; + spi-max-frequency = <20000000>; + interrupts = <5 0 0>; + interrupt-parent = <&gpa2>; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names ="default"; + pinctrl-0 = <&codec_reset &codec_irq>; + + wlf,reset = <&gpf4 0 0>; + wlf,init-mic-delay = <30>; + wlf,use-jd-gpio; + wlf,micd-clamp-mode = <0x8>; + wlf,micd-detect-debounce = <300>; + wlf,micd-pol-gpio = <0>; + wlf,micd-bias-start-time = <0x1>; + wlf,micd-rate = <0x7>; + wlf,micd-dbtime = <0x1>; + wlf,micd-timeout = <1000>; + wlf,micd-force-micbias; + wlf,hpdet-moisture-imp = <2000>; + wlf,hpdet-moisture-debounce = <40>; + wlf,hpdet-channel = <1>; + wlf,hpdet-ext-res = <33>; + wlf,hpdet-short-circuit-imp = <0>; + wlf,micd-ranges = < + 116 226 + 173 582 + 321 115 + 752 114 + 1257 217 + >; + + wlf,micd-configs = < + 0x0 2 0 + >; + + wlf,micbias1 = <1800 0 1 0 0>; + wlf,micbias2 = <2800 0 1 0 0>; + wlf,micbias3 = <1800 0 1 0 0>; + wlf,micbias4 = <1800 0 1 0 0>; + + wlf,gpio-defaults = < + 0xffffffff 0xffffffff /* GPIO1 */ + 0xffffffff 0xffffffff /* GPIO2 */ + 0xffffffff 0xffffffff /* GPIO3 */ + 0xffffffff 0xffffffff /* GPIO4 */ + 0xffffffff 0xffffffff /* GPIO5 */ + 0xffffffff 0xffffffff /* GPIO6 */ + 0xffffffff 0xffffffff /* GPIO7 */ + 0xffffffff 0xffffffff /* GPIO8 */ + 0xffffffff 0xffffffff /* MIF1SCLK / GPIO9 */ + 0xffffffff 0xffffffff /* MIF1SDA / GPIO10 */ + 0xffffffff 0xffffffff /* MIF2SCLK / GPIO11 */ + 0xffffffff 0xffffffff /* MIF2SDA / GPIO12 */ + 0xffffffff 0xffffffff /* MIF3SCLK / GPIO13 */ + 0xffffffff 0xffffffff /* MIF3SDA / GPIO14 */ + 0x00002000 0x00006000 /* AIF1TXDAT / GPIO15 */ + 0x00002000 0x00006000 /* AIF1BCLK / GPIO16 */ + 0x00002000 0x00006000 /* AIF1RXDAT / GPIO17 */ + 0x00002000 0x00006000 /* AIF1LRCLK / GPIO18 */ + 0x00002000 0x00006000 /* AIF2TXDAT / GPIO19 */ + 0x00002000 0x00006000 /* AIF2BCLK / GPIO20 */ + 0x00002000 0x00006000 /* AIF2RXDAT / GPIO21 */ + 0x00002000 0x00006000 /* AIF2LRCLK / GPIO22 */ + 0x00002000 0x00006000 /* AIF3TXDAT / GPIO23 */ + 0x00002000 0x00006000 /* AIF3BCLK / GPIO24 */ + 0x00002000 0x00006000 /* AIF3RXDAT / GPIO25 */ + 0x00002000 0x00006000 /* AIF3LRCLK / GPIO26 */ + 0x00002000 0x00006000 /* AIF4TXDAT / GPIO27 */ + 0x00002000 0x00006000 /* AIF4BCLK / GPIO28 */ + 0x00002000 0x00006000 /* AIF4RXDAT / GPIO29 */ + 0x00002000 0x00006000 /* AIF4LRCLK / GPIO30 */ + 0x00002000 0x0000e000 /* DMICCLK4 / GPIO31 */ + 0x00002000 0x0000e000 /* DMICDAT4 / GPIO32 */ + 0xffffffff 0xffffffff /* DMICCLK5 / GPIO33 */ + 0xffffffff 0xffffffff /* DMICDAT5 / GPIO34 */ + 0xffffffff 0xffffffff /* DMICCLK6 / GPIO35 */ + 0xffffffff 0xffffffff /* DMICDAT6 / GPIO36 */ + 0xffffffff 0xffffffff /* SPKCLK1 / GPIO37 */ + 0xffffffff 0xffffffff /* SPKCLK2 / GPIO38 */ + 0xffffffff 0xffffffff /* SPKDAT1 / GPIO39 */ + 0xffffffff 0xffffffff /* SPKDAT2 / GPIO40 */ + >; + + wlf,gpsw = <0x3>; + wlf,micd-software-compare; + wlf,micd-open-circuit-declare = <1>; + wlf,jd-wake-time = <5000>; + + wlf,max-channels-clocked = <2 0 0 0>; + /* 0:MICVDD 1:MICBIAS1 2:MICBIAS2 3:MICBIAS3 */ + wlf,dmic-ref = <1 2 1 0 0 0>; + /* 1st cell:IN1L 2rd cell:IN1R 3nd cell:IN2L 4th cell:IN2R... 12th cell:IN6R */ + wlf,inmode = <2 2 0 0 3 3 2 2 0 0 0 0>; + /* 1st cell:OUT1 2nd cell:OUT2 3rd cell:OUT3... 6th cell:OUT6 */ + wlf,out-mono = <0 1 1 0 0 0>; + + wlf,rev-specific-fw; + + DCVDD-supply = <&ldo26_reg>; + AVDD-supply = <&ldo16_reg>; + LDOVDD-supply = <&ldo16_reg>; + DBVDD1-supply = <&ldo16_reg>; + + CPVDD-supply = <&ldo16_reg>; + DBVDD2-supply = <&ldo16_reg>; + DBVDD3-supply = <&ldo16_reg>; + DBVDD4-supply = <&ldo16_reg>; + SPKVDDL-supply = <&ldo16_reg>; + SPKVDDR-supply = <&ldo16_reg>; + + adsps { + #address-cells = <1>; + #size-cells = <0>; + + adsp@0FFE00 { + reg = <0x0FFE00>; + firmware { + TRACE { + wlf,wmfw-file = "trace"; + wlf,bin-file = "None"; + wlf,compr-caps = <1 8 0x4 1 8000 16000 24000>; + }; + }; + }; + adsp@17FE00 { + reg = <0x17FE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "None"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "None"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_FB_MEETING { + wlf,wmfw-file = "tx-fb-meeting"; + wlf,bin-file = "tx-fb-meeting"; + }; + }; + }; + adsp@1FFE00 { + reg = <0x1FFE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "tx-nb"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "tx-wb"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-interview"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-conversation"; + }; + TX_WB_MEETING { + wlf,wmfw-file = "tx-wb-meeting"; + wlf,bin-file = "tx-wb-meeting"; + }; + }; + }; + adsp@27FE00 { + reg = <0x27FE00>; + firmware { + RX_NB { + wlf,wmfw-file = "rx-anc-nb"; + wlf,bin-file = "rx-anc-nb"; + }; + RX_WB { + wlf,wmfw-file = "rx-anc-wb"; + wlf,bin-file = "rx-anc-wb"; + }; + }; + }; + adsp@37FE00 { + reg = <0x37FE00>; + firmware { + VOICECONTROL { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "ez2-control"; + wlf,compr-caps = <1 1 0x4 1 16000>; + }; + LPSD { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "lpsd-control"; + }; + }; + }; + adsp@2FFE00 { + reg = <0x2FFE00>; + firmware { + DSM { + wlf,wmfw-file = "dsm"; + wlf,bin-file = "None"; + }; + }; + }; + }; + controller-data { + cs-gpio = <&gpd8 1 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + spi_1: spi@14d30000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi1_mosi_sck_ssn &spi1_miso>; + + num-cs = <1>; + status = "okay"; + + STM32F@0 { + compatible = "ssp,STM32F"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + pinctrl-names = "default"; + pinctrl-0 = <&ssp_rst &ssp_ap_int &ssp_mcu_int1 &ssp_mcu_int2>; + + gpio-controller; + #gpio-cells = <2>; + ssp,mcu_int1-gpio = <&gpa2 7 0x00>; + ssp,mcu_int2-gpio = <&gpf4 4 0x00>; + ssp,ap_int-gpio = <&gpf4 5 0x00>; + ssp,rst-gpio = <&gpa3 6 0x00>; + ssp,acc-position = <0>; + ssp,mag-position = <6>; + ssp,prox-hi_thresh = <2000>; + ssp,prox-low_thresh = <1400>; + ssp-glass-type = <1>; + ssp-acc-type = <1>; + ssp,mag-array = /bits/ 8 <136 83 231 111 14 248 254 139 209 54 + 186 156 35 179 2 179 253 51 136 143 + 189 0 222 132 13 5 194>; + + controller-data { + cs-gpio = <&gpd6 3 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + spi_3: spi@14d50000 { + spiclk-pindev-name = "14c90000.pinctrl"; + spiclk-pin-name = "gpg4-0"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default","ese-pwoff","clk-fix","clk-recover","ese-disable"; + pinctrl-0 = <&spi3_bus>; + pinctrl-1 = <&spi3_ese_pwoff>; + pinctrl-2 = <&spi3_clk_fix>; + pinctrl-3 = <&spi3_clk_recover>; + pinctrl-4 = <&spi3_ese_disable>; + samsung,ese-oberthur; + + ese_spi@0 { + compatible = "ese_p3"; + reg = <0>; + spi-max-frequency = <10000000>; + + gpio-controller; + #gpio-cells = <2>; + + p3-mosipin = <21>; + p3-misopin = <22>; + p3-cspin = <23>; + p3-clkpin = <24>; + p3-cs-gpio = <&gpg4 1 0>; + p3-vdd-1p8= "VDD_1.8V_ESE"; + + controller-data { + samsung,spi-chip-select-mode = <1>; + }; + }; + }; + + audio_pdata { + compatible = "samsung,audio-pdata"; + + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; + + imp_table = < + /* min max gain */ + 0 13 0 + 14 42 3 + 43 100 5 + 101 200 7 + 201 450 9 + 451 1000 10 + 1001 0x7fffffff 0 + >; + + seamless_voicewakeup; + status = "okay"; + }; + + antenna_switch { + status = "okay"; + compatible = "antenna_switch"; + pinctrl-names = "default"; + pinctrl-0 = <&antenna_switch_en>; + antenna_switch,gpio_antenna_switch = <&gpr3 6 0>; + }; + + pinctrl@10580000 { + codec_irq: codec-irq { + samsung,pins = "gpa2-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + }; + max98505_ctrl: max98505-ctl { + samsung,pins ="gpa2-0"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<2>; + samsung,pin-pud-pdn = <0>; + }; + ssp_mcu_int1: ssp-mcu-int1 { + samsung,pins = "gpa2-7"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + ssp_rst: ssp-rst { + samsung,pins = "gpa3-6"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <3>; + samsung,pin-drv = <3>; + }; + }; + + pinctrl@13470000 { + es704_wakeup: es704-wakeup { + samsung,pins ="gpd0-1"; + samsung,pin-function = <1>; + samsung,pin-pud = <3>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <3>; + samsung,pin-val = <1>; + }; + max98505_i2c: max98505-i2c { + samsung,pins = "gpd2-0", "gpd2-1"; + samsung,pin-pud = <0>; + status = "okay"; + }; + es704_i2c: es704-i2c { + samsung,pins = "gpd2-7", "gpd2-6"; + samsung,pin-function = <0x3>; + samsung,pin-pud = <0x0>; + samsung,pin-drv = <0>; + }; + }; + + pinctrl@14870000 { + es704_reset: es704-reset { + samsung,pins ="gpf1-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <0>; + samsung,pin-val = <0>; + }; + codec_reset: codec-reset { + samsung,pins ="gpf4-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <1>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <1>; + samsung,pin-val = <0>; + }; + ssp_mcu_int2: ssp-mcu-int2 { + samsung,pins = "gpf4-4"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + ssp_ap_int: ssp-ap-int { + samsung,pins = "gpf4-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <3>; + samsung,pin-drv = <3>; + }; + }; + + pinctrl@15690000 { + sub_pmic_irq: sub-pmic-irq { + samsung,pins ="gpr2-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + antenna_switch_en: antenna-switch-en { + samsung,pins = "gpr3-6"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-val = <0>; + }; + }; + + hsi2c@13640000 { + status = "okay"; + max98505@31 { + compatible = "maxim,max98505"; + reg = <0x31>; + pinctrl-names = "default"; + pinctrl-0 = <&max98505_i2c &max98505_ctrl>; + gpios = <&gpd2 1 0 + &gpd2 0 0 + >; + i2c-gpio,delay-us = <2>; + maxim,platform_type = <0>; + maxim,spk_vol = <0x14>; + maxim,sysclk = <12288000>; + }; + }; + + hsi2c@13650000{ + max77843@66 { + status = "okay"; + }; + }; + + muic { + muic,support-list = "OTG","Charging Cable","Jig USB On","Jig UART Off", + "Jig UART Off + VB","Jig UART On", + "TA","USB","CDP","Undefined Charging", + "Unofficial ID","Unofficial ID + TA","Unofficial ID + ANY TA", + "Smartdock","Smartdock + VB","Smartdock + TA","Smartdock + USB", + "Deskdock", "Deskdock + VB", + "Unofficial ID + USB","Unofficial ID + CDP", + "TA or AFC","AFC charger Prepare","AFC charger 5V","AFC charger 9V", + "Fuelgauge test","HMT","VZW Accessory","VZW Incompatible"; + }; + + hsi2c@13660000 { + s2mps15_pmic@66 { + regulators { + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_atlas"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck3_reg: BUCK3 { + regulator-name = "vdd_apollo"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck4_reg: BUCK4 { + regulator-name = "vdd_int"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck5_reg: BUCK5 { + regulator-name = "vdd_disp_cam0"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck6_reg: BUCK6 { + regulator-name = "vdd_g3d"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck8_reg: BUCK8 { + regulator-name = "vdd_lldo"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + buck9_reg: BUCK9 { + regulator-name = "vdd_mldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + ldo2_reg: LDO2 { + regulator-name = "vqmmc"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + regulator-boot-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "vdd_ldo8"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = <1>; + }; + + ldo15_reg: LDO15 { + regulator-name = "tsp_io"; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + ldo16_reg: LDO16 { + regulator-name = "VCC_1.8V_CODEC_PMIC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo17_reg: LDO17 { + regulator-name = "VCC_MOTOR_3.0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo18_reg: LDO18 { + regulator-name = "HRM_VDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1850000>; + }; + + ldo19_reg: LDO19 { + regulator-name = "MST_LEVEL_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo20_reg: LDO20 { + regulator-name = "VDD20_1P8_AP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo21_reg: LDO21 { + regulator-name = "key_led"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo22_reg: LDO22 { + regulator-name = "VDD22_1P1_2MIC"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-initial-mode = <3>; + }; + + ldo23_reg: LDO23 { + regulator-name = "VDD_1.8V_ESE"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo24_reg: LDO24 { + regulator-name = "V_HRM_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3350000>; + }; + + ldo25_reg: LDO25 { + regulator-name = "PROX_LED_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo26_reg: LDO26 { + regulator-name = "VDD_1.2V_CODEC"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + }; + }; + }; + + hsi2c@13680000 { + status = "okay"; + samsung,hs-mode; + clock-frequency = <1000000>; + earSmart@3e { + compatible = "earSmart"; + reg = <0x3e>; + clocks = <&clock 45>; + clock-names = "mclk"; + pinctrl-0 = <&es704_i2c &es704_reset &es704_wakeup>; + esxxx-reset-gpio = <&gpf1 0 0>; + esxxx-wakeup-gpio = <&gpd0 1 0>; + adnc,firmware_name = "audience-es804-fw.bin"; + }; + }; + + serial_0: uart@13630000 { + status = "okay"; + samsung,use-default-irq; + }; + + hsi2c@13670000 { + max77838@60 { + status = "disabled"; + }; + + s2mpb02@59 { + status = "okay"; + compatible = "samsung,s2mpb02"; + reg = <0x59>; + + s2mpb02,irq-gpio = <&gpr2 2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&sub_pmic_irq>; + + regulators { + _buck1_reg: s2mpb02-buck1 { + regulator-name = "VDD_1P6_DDR"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; + }; + + _buck2_reg: s2mpb02-buck2 { + regulator-name = "VDDD_CORE_0.8V_COMP"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <850000>; + }; + + _ldo1_reg: s2mpb02-ldo1 { + regulator-name = "VDDD_NORET_0.9V_COMP"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + }; + + _ldo2_reg: s2mpb02-ldo2 { + regulator-name = "VDDD_CORE_1.0V_COMP"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo3_reg: s2mpb02-ldo3 { + regulator-name = "VDDD_1.2V_CAM"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo4_reg: s2mpb02-ldo4 { + regulator-name = "VDDD_RET_1.0V_COMP"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo5_reg: s2mpb02-ldo5 { + regulator-name = "VDDD_1.2V_VT"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo6_reg: s2mpb02-ldo6 { + regulator-name = "VDDIO_1.8V_VT"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo7_reg: s2mpb02-ldo7 { + regulator-name = "VDDIO_1.8V_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo8_reg: s2mpb02-ldo8 { + regulator-name = "VDDIO_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo9_reg: s2mpb02-ldo9 { + regulator-name = "VDDA_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo10_reg: s2mpb02-ldo10 { + regulator-name = "VCC_DISPLAY_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo11_reg: s2mpb02-ldo11 { + regulator-name = "VDDA_2.9V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2950000>; + }; + + _ldo12_reg: s2mpb02-ldo12 { + regulator-name = "VDDAF_2.8V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo13_reg: s2mpb02-ldo13 { + regulator-name = "VDDA_2.9V_VT"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + + _ldo14_reg: s2mpb02-ldo14 { + regulator-name = "OIS_VM_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo15_reg: s2mpb02-ldo15 { + regulator-name = "OIS_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo16_reg: s2mpb02-ldo16 { + regulator-name = "VCC_3.0V_LCD"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + _ldo17_reg: s2mpb02-ldo17 { + regulator-name = "tsp_avdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + + torch { + status = "okay"; + leds1 { + ledname = "leds-sec1"; + /* S2MPB02_FLASH_LED_1 */ + id = <0>; + /* S2MPB02_FLASH_CURRENT */ + brightness = <0xF>; + /* S2MPB02_FLASH_TIMEOUT */ + timeout = <0x3>; + }; + + leds2 { + ledname = "torch-sec1"; + /* S2MPB02_TORCH_LED_1 */ + id = <1>; + /* S2MPB02_TORCH_CURRENT */ + brightness = <0x9>; + /* S2MPB02_TORCH_TIMEOUT */ + timeout = <0xF>; + }; + }; + }; + }; + + hsi2c@14E00000 { + sec-nfc@27 { + sec-nfc,i2c_1p8 = "VDD20_1P8_AP"; + }; + }; + + hsi2c@14E60000 { + status = "disable"; + /delete-node/ s2mpb01_pmic@59; + }; + + sec_thermistor@0 { + status = "okay"; + + adc_array = <205 216 227 238 249 260 271 282 293 303 + 314 324 335 346 356 366 377 388 398 408 + 418 436 454 472 489 506 520 534 548 561 + 575 588 602 619 636 655 674 697 720 737 + 754 775 796 819 842 857 872 904 936 953 + 974 993 1012 1031 1050 1070 1087 1104 1121 1138 + 1155 1175 1205 1232 1259 1286 1306 1326 1345 1365 + 1385 1403 1421 1439 1457 1475 1492 1509 1526 1543 + 1560 1579 1598 1616 1635 1654 1669 1684 1699 1713 + 1728 1740 1753 1766 1778 1790 1798 1806 1814 1822 + 1830 1839 1848 1856 1864 1872 1880 1888 1896 1904 + 1912>; + }; + + sec_thermistor@2 { + status = "okay"; + + adc_array = <205 216 227 238 249 260 271 282 293 303 + 314 324 335 346 356 366 377 388 398 408 + 418 436 454 472 489 506 520 534 548 561 + 575 588 602 619 636 655 674 697 720 737 + 754 775 796 819 842 857 872 904 936 953 + 974 993 1012 1031 1050 1070 1087 1104 1121 1138 + 1155 1175 1205 1232 1259 1286 1306 1326 1345 1365 + 1385 1403 1421 1439 1457 1475 1492 1509 1526 1543 + 1560 1579 1598 1616 1635 1654 1669 1684 1699 1713 + 1728 1740 1753 1766 1778 1790 1798 1806 1814 1822 + 1830 1839 1848 1856 1864 1872 1880 1888 1896 1904 + 1912>; + }; + + hsi2c@14E10000 { + touchscreen@20 { + stm,num_touchkey = <2>; + stm,regulator_tk_led = "key_led"; + }; + }; + + pcie0@155C0000 { + status = "okay"; + }; + + dwmmc0@15740000 { + status = "disabled"; + }; + + dwmmc2@15560000 { + vdd_vmmc-supply = <&ldo25_reg>; + vqmmc-supply = <&ldo2_reg>; + }; + + dsim_0: dsim@0x13900000 { + gpios = <&gpr3 0 0x1>; + regulator_30V = "VCC_3.0V_LCD"; + regulator_18V = "VCC_DISPLAY_1.8V"; + regulator_16V = "VDD_1P6_DDR"; + lcd_info = <&s6e3hf2_wqhd>; + }; + + s6e3hf2_wqxga: s6e3hf2_wqxga_panel { + mode = <2>; /* 0: video mode, 1: DP command mode, 2: MIPI command mode */ + resolution = <1440 2560>; + size = <70 121>; + timing,refresh = <60>; + timing,h-porch = <1 1 1>; + timing,v-porch = <15 1 1>; + timing,dsi-hs-clk = <1026>; + timing,dsi-escape-clk = <16>; + mic = <1>; /* 0: mic disable, 1: mic enable */ + mic_ver = <2>; /* 0: mic v1.1, 1: v1.2, 2: v2.0 */ + type_of_ddi = <0>; /* 0: Samsung Mobile, 1: MAGNA, 2: Normal(Etc) */ + }; + + s6e3hf2_wqhd: s6e3hf2_wqhd_panel { + mode = <2>; + resolution = <1440 2560>; + size = <70 121>; + timing,refresh = <60>; + timing,h-porch = <1 1 1>; + timing,v-porch = <15 1 1>; + timing,dsi-hs-clk = <1026>; + timing,dsi-escape-clk = <16>; + mic = <1>; + mic_ver = <2>; + type_of_ddi = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_05.dts b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_05.dts new file mode 100644 index 000000000000..bb80b965edb5 --- /dev/null +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_05.dts @@ -0,0 +1,948 @@ +/* + * SAMSUNG UNIVERSAL7420 board device tree source + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +#include "exynos7420-zero_common.dtsi" +#include "exynos7420-zerolte_usa_cdma_battery_07.dtsi" +#include "exynos7420-zerolte_gpio_usa_cdma_05.dtsi" +#include "exynos7420-zerolte_modem-mdm9x35.dtsi" +#include "exynos7420-zerolte_fingerprint-sensor_00.dtsi" +#include "exynos7420-zerolte_mst.dtsi" + +/ { + model = "Samsung ZERO LTE USA CDMA rev09 board based on Exynos7420(EVT1), mPOP"; + model_info-chip = <7420>; + model_info-platform = "android"; + model_info-subtype = "samsung"; + model_info-hw_rev = <12>; + model_info-hw_rev_end = <255>; + compatible = "samsung,ZERO LTE USA CDMA EVT1 mPOP,r09", "samsung,exynos7420"; + + spi_0: spi@14d20000 { + /delete-property/ dma-mode; + /delete-property/ dmas; + /delete-property/ dma-names; + + num-cs = <1>; + status = "okay"; + + audio_codec: wm1840@0 { + compatible = "wlf,wm1840"; + reg = <0x0>; + spi-max-frequency = <20000000>; + interrupts = <5 0 0>; + interrupt-parent = <&gpa2>; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names ="default"; + pinctrl-0 = <&codec_reset &codec_irq>; + + wlf,reset = <&gpf4 0 0>; + wlf,init-mic-delay = <30>; + wlf,use-jd-gpio; + wlf,micd-clamp-mode = <0x8>; + wlf,micd-detect-debounce = <300>; + wlf,micd-pol-gpio = <0>; + wlf,micd-bias-start-time = <0x1>; + wlf,micd-rate = <0x7>; + wlf,micd-dbtime = <0x1>; + wlf,micd-timeout = <1000>; + wlf,micd-force-micbias; + wlf,hpdet-moisture-imp = <2000>; + wlf,hpdet-moisture-debounce = <40>; + wlf,hpdet-channel = <1>; + wlf,hpdet-ext-res = <33>; + wlf,hpdet-short-circuit-imp = <0>; + wlf,micd-ranges = < + 116 226 + 173 582 + 321 115 + 752 114 + 1257 217 + >; + + wlf,micd-configs = < + 0x0 2 0 + >; + + wlf,micbias1 = <1800 0 1 0 0>; + wlf,micbias2 = <2800 0 1 0 0>; + wlf,micbias3 = <1800 0 1 0 0>; + wlf,micbias4 = <1800 0 1 0 0>; + + wlf,gpio-defaults = < + 0xffffffff 0xffffffff /* GPIO1 */ + 0xffffffff 0xffffffff /* GPIO2 */ + 0xffffffff 0xffffffff /* GPIO3 */ + 0xffffffff 0xffffffff /* GPIO4 */ + 0xffffffff 0xffffffff /* GPIO5 */ + 0xffffffff 0xffffffff /* GPIO6 */ + 0xffffffff 0xffffffff /* GPIO7 */ + 0xffffffff 0xffffffff /* GPIO8 */ + 0xffffffff 0xffffffff /* MIF1SCLK / GPIO9 */ + 0xffffffff 0xffffffff /* MIF1SDA / GPIO10 */ + 0xffffffff 0xffffffff /* MIF2SCLK / GPIO11 */ + 0xffffffff 0xffffffff /* MIF2SDA / GPIO12 */ + 0xffffffff 0xffffffff /* MIF3SCLK / GPIO13 */ + 0xffffffff 0xffffffff /* MIF3SDA / GPIO14 */ + 0x00002000 0x00006000 /* AIF1TXDAT / GPIO15 */ + 0x00002000 0x00006000 /* AIF1BCLK / GPIO16 */ + 0x00002000 0x00006000 /* AIF1RXDAT / GPIO17 */ + 0x00002000 0x00006000 /* AIF1LRCLK / GPIO18 */ + 0x00002000 0x00006000 /* AIF2TXDAT / GPIO19 */ + 0x00002000 0x00006000 /* AIF2BCLK / GPIO20 */ + 0x00002000 0x00006000 /* AIF2RXDAT / GPIO21 */ + 0x00002000 0x00006000 /* AIF2LRCLK / GPIO22 */ + 0x00002000 0x00006000 /* AIF3TXDAT / GPIO23 */ + 0x00002000 0x00006000 /* AIF3BCLK / GPIO24 */ + 0x00002000 0x00006000 /* AIF3RXDAT / GPIO25 */ + 0x00002000 0x00006000 /* AIF3LRCLK / GPIO26 */ + 0x00002000 0x00006000 /* AIF4TXDAT / GPIO27 */ + 0x00002000 0x00006000 /* AIF4BCLK / GPIO28 */ + 0x00002000 0x00006000 /* AIF4RXDAT / GPIO29 */ + 0x00002000 0x00006000 /* AIF4LRCLK / GPIO30 */ + 0x00002000 0x0000e000 /* DMICCLK4 / GPIO31 */ + 0x00002000 0x0000e000 /* DMICDAT4 / GPIO32 */ + 0xffffffff 0xffffffff /* DMICCLK5 / GPIO33 */ + 0xffffffff 0xffffffff /* DMICDAT5 / GPIO34 */ + 0xffffffff 0xffffffff /* DMICCLK6 / GPIO35 */ + 0xffffffff 0xffffffff /* DMICDAT6 / GPIO36 */ + 0xffffffff 0xffffffff /* SPKCLK1 / GPIO37 */ + 0xffffffff 0xffffffff /* SPKCLK2 / GPIO38 */ + 0xffffffff 0xffffffff /* SPKDAT1 / GPIO39 */ + 0xffffffff 0xffffffff /* SPKDAT2 / GPIO40 */ + >; + + wlf,gpsw = <0x3>; + wlf,micd-software-compare; + wlf,micd-open-circuit-declare = <1>; + wlf,jd-wake-time = <5000>; + + wlf,max-channels-clocked = <2 0 0 0>; + /* 0:MICVDD 1:MICBIAS1 2:MICBIAS2 3:MICBIAS3 */ + wlf,dmic-ref = <1 2 1 0 0 0>; + /* 1st cell:IN1L 2rd cell:IN1R 3nd cell:IN2L 4th cell:IN2R... 12th cell:IN6R */ + wlf,inmode = <2 2 0 0 3 3 2 2 0 0 0 0>; + /* 1st cell:OUT1 2nd cell:OUT2 3rd cell:OUT3... 6th cell:OUT6 */ + wlf,out-mono = <0 1 1 0 0 0>; + + wlf,rev-specific-fw; + + DCVDD-supply = <&ldo26_reg>; + AVDD-supply = <&ldo16_reg>; + LDOVDD-supply = <&ldo16_reg>; + DBVDD1-supply = <&ldo16_reg>; + + CPVDD-supply = <&ldo16_reg>; + DBVDD2-supply = <&ldo16_reg>; + DBVDD3-supply = <&ldo16_reg>; + DBVDD4-supply = <&ldo16_reg>; + SPKVDDL-supply = <&ldo16_reg>; + SPKVDDR-supply = <&ldo16_reg>; + + adsps { + #address-cells = <1>; + #size-cells = <0>; + + adsp@0FFE00 { + reg = <0x0FFE00>; + firmware { + TRACE { + wlf,wmfw-file = "trace"; + wlf,bin-file = "None"; + wlf,compr-caps = <1 8 0x4 1 8000 16000 24000>; + }; + }; + }; + adsp@17FE00 { + reg = <0x17FE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "None"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "None"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "None"; + }; + TX_FB_MEETING { + wlf,wmfw-file = "tx-fb-meeting"; + wlf,bin-file = "tx-fb-meeting"; + }; + }; + }; + adsp@1FFE00 { + reg = <0x1FFE00>; + firmware { + TX_NB { + wlf,wmfw-file = "tx-nb"; + wlf,bin-file = "tx-nb"; + }; + TX_WB { + wlf,wmfw-file = "tx-wb"; + wlf,bin-file = "tx-wb"; + }; + TX_SWB_INTERVIEW { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-interview"; + }; + TX_SWB_CONVERSATION { + wlf,wmfw-file = "tx-swb"; + wlf,bin-file = "tx-swb-conversation"; + }; + TX_WB_MEETING { + wlf,wmfw-file = "tx-wb-meeting"; + wlf,bin-file = "tx-wb-meeting"; + }; + }; + }; + adsp@27FE00 { + reg = <0x27FE00>; + firmware { + RX_NB { + wlf,wmfw-file = "rx-anc-nb"; + wlf,bin-file = "rx-anc-nb"; + }; + RX_WB { + wlf,wmfw-file = "rx-anc-wb"; + wlf,bin-file = "rx-anc-wb"; + }; + }; + }; + adsp@37FE00 { + reg = <0x37FE00>; + firmware { + VOICECONTROL { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "ez2-control"; + wlf,compr-caps = <1 1 0x4 1 16000>; + }; + LPSD { + wlf,wmfw-file = "ez2-control"; + wlf,bin-file = "lpsd-control"; + }; + }; + }; + adsp@2FFE00 { + reg = <0x2FFE00>; + firmware { + DSM { + wlf,wmfw-file = "dsm"; + wlf,bin-file = "None"; + }; + }; + }; + }; + controller-data { + cs-gpio = <&gpd8 1 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + spi_1: spi@14d30000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&spi1_mosi_sck_ssn &spi1_miso>; + + num-cs = <1>; + status = "okay"; + + STM32F@0 { + compatible = "ssp,STM32F"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + pinctrl-names = "default"; + pinctrl-0 = <&ssp_rst &ssp_ap_int &ssp_mcu_int1 &ssp_mcu_int2>; + + gpio-controller; + #gpio-cells = <2>; + ssp,mcu_int1-gpio = <&gpa2 7 0x00>; + ssp,mcu_int2-gpio = <&gpf4 4 0x00>; + ssp,ap_int-gpio = <&gpf4 5 0x00>; + ssp,rst-gpio = <&gpa3 6 0x00>; + ssp,acc-position = <1>; + ssp,mag-position = <6>; + ssp,prox-hi_thresh = <2000>; + ssp,prox-low_thresh = <1400>; + ssp-glass-type = <1>; + ssp-acc-type = <1>; + ssp,mag-array = /bits/ 8 <136 83 231 111 14 248 254 139 209 54 + 186 156 35 179 2 179 253 51 136 143 + 189 0 222 132 13 5 194>; + + controller-data { + cs-gpio = <&gpd6 3 0>; + samsung,spi-feedback-delay = <0>; + }; + }; + }; + + spi_3: spi@14d50000 { + spiclk-pindev-name = "14c90000.pinctrl"; + spiclk-pin-name = "gpg4-0"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default","ese-pwoff","clk-fix","clk-recover","ese-disable"; + pinctrl-0 = <&spi3_bus>; + pinctrl-1 = <&spi3_ese_pwoff>; + pinctrl-2 = <&spi3_clk_fix>; + pinctrl-3 = <&spi3_clk_recover>; + pinctrl-4 = <&spi3_ese_disable>; + samsung,ese-oberthur; + + ese_spi@0 { + compatible = "ese_p3"; + reg = <0>; + spi-max-frequency = <10000000>; + + gpio-controller; + #gpio-cells = <2>; + + p3-mosipin = <21>; + p3-misopin = <22>; + p3-cspin = <23>; + p3-clkpin = <24>; + p3-cs-gpio = <&gpg4 1 0>; + p3-vdd-1p8= "VDD_1.8V_ESE"; + + controller-data { + samsung,spi-chip-select-mode = <1>; + }; + }; + }; + + audio_pdata { + compatible = "samsung,audio-pdata"; + + aif_format = <0x1001 0x1004 0x1001>; + aif_format_tdm = <0x0 0x1047 0x0>; + + imp_table = < + /* min max gain */ + 0 13 0 + 14 42 3 + 43 100 5 + 101 200 7 + 201 450 9 + 451 1000 10 + 1001 0x7fffffff 0 + >; + + seamless_voicewakeup; + status = "okay"; + }; + + antenna_switch { + status = "okay"; + compatible = "antenna_switch"; + pinctrl-names = "default"; + pinctrl-0 = <&antenna_switch_en>; + antenna_switch,gpio_antenna_switch = <&gpr3 6 0>; + }; + + pinctrl@10580000 { + codec_irq: codec-irq { + samsung,pins = "gpa2-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <0>; + }; + max98505_ctrl: max98505-ctl { + samsung,pins ="gpa2-0"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<2>; + samsung,pin-pud-pdn = <0>; + }; + ssp_mcu_int1: ssp-mcu-int1 { + samsung,pins = "gpa2-7"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + ssp_rst: ssp-rst { + samsung,pins = "gpa3-6"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <3>; + samsung,pin-drv = <3>; + }; + }; + + pinctrl@13470000 { + es704_wakeup: es704-wakeup { + samsung,pins ="gpd0-1"; + samsung,pin-function = <1>; + samsung,pin-pud = <3>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <3>; + samsung,pin-val = <1>; + }; + max98505_i2c: max98505-i2c { + samsung,pins = "gpd2-0", "gpd2-1"; + samsung,pin-pud = <0>; + status = "okay"; + }; + es704_i2c: es704-i2c { + samsung,pins = "gpd2-7", "gpd2-6"; + samsung,pin-function = <0x3>; + samsung,pin-pud = <0x0>; + samsung,pin-drv = <0>; + }; + }; + + pinctrl@14870000 { + es704_reset: es704-reset { + samsung,pins ="gpf1-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <0>; + samsung,pin-val = <0>; + }; + codec_reset: codec-reset { + samsung,pins ="gpf4-0"; + samsung,pin-function = <1>; + samsung,pin-pud = <1>; + samsung,pin-con-pdn =<3>; + samsung,pin-pud-pdn = <1>; + samsung,pin-val = <0>; + }; + ssp_mcu_int2: ssp-mcu-int2 { + samsung,pins = "gpf4-4"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + ssp_ap_int: ssp-ap-int { + samsung,pins = "gpf4-5"; + samsung,pin-function = <0xf>; + samsung,pin-pud = <3>; + samsung,pin-drv = <3>; + }; + }; + + pinctrl@15690000 { + sub_pmic_irq: sub-pmic-irq { + samsung,pins ="gpr2-2"; + samsung,pin-function = <0>; + samsung,pin-pud = <0>; + samsung,pin-drv = <0>; + }; + antenna_switch_en: antenna-switch-en { + samsung,pins = "gpr3-6"; + samsung,pin-function = <1>; + samsung,pin-pud = <0>; + samsung,pin-val = <0>; + }; + }; + + hsi2c@13640000 { + status = "okay"; + max98505@31 { + compatible = "maxim,max98505"; + reg = <0x31>; + pinctrl-names = "default"; + pinctrl-0 = <&max98505_i2c &max98505_ctrl>; + gpios = <&gpd2 1 0 + &gpd2 0 0 + >; + i2c-gpio,delay-us = <2>; + maxim,platform_type = <0>; + maxim,spk_vol = <0x14>; + maxim,sysclk = <12288000>; + }; + }; + + hsi2c@13650000{ + max77843@66 { + status = "okay"; + }; + }; + + muic { + muic,support-list = "OTG","Charging Cable","Jig USB On","Jig UART Off", + "Jig UART Off + VB","Jig UART On", + "TA","USB","CDP","Undefined Charging", + "Unofficial ID","Unofficial ID + TA","Unofficial ID + ANY TA", + "Smartdock","Smartdock + VB","Smartdock + TA","Smartdock + USB", + "Deskdock", "Deskdock + VB", + "Unofficial ID + USB","Unofficial ID + CDP", + "TA or AFC","AFC charger Prepare","AFC charger 5V","AFC charger 9V", + "Fuelgauge test","HMT","VZW Accessory","VZW Incompatible"; + }; + + hsi2c@13660000 { + s2mps15_pmic@66 { + regulators { + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_atlas"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck3_reg: BUCK3 { + regulator-name = "vdd_apollo"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck4_reg: BUCK4 { + regulator-name = "vdd_int"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck5_reg: BUCK5 { + regulator-name = "vdd_disp_cam0"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck6_reg: BUCK6 { + regulator-name = "vdd_g3d"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + }; + + buck8_reg: BUCK8 { + regulator-name = "vdd_lldo"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + buck9_reg: BUCK9 { + regulator-name = "vdd_mldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + regulator-always-on; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <3>; + }; + + ldo2_reg: LDO2 { + regulator-name = "vqmmc"; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12000>; + regulator-initial-mode = <1>; + regulator-boot-on; + }; + + ldo8_reg: LDO8 { + regulator-name = "vdd_ldo8"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = <1>; + }; + + ldo15_reg: LDO15 { + regulator-name = "tsp_io"; + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + ldo16_reg: LDO16 { + regulator-name = "VCC_1.8V_CODEC_PMIC"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo17_reg: LDO17 { + regulator-name = "VCC_MOTOR_3.0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo18_reg: LDO18 { + regulator-name = "HRM_VDD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1850000>; + }; + + ldo19_reg: LDO19 { + regulator-name = "MST_LEVEL_3.0V"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo20_reg: LDO20 { + regulator-name = "VDD20_1P8_AP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo21_reg: LDO21 { + regulator-name = "key_led"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo22_reg: LDO22 { + regulator-name = "VDD22_1P1_2MIC"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + regulator-initial-mode = <3>; + }; + + ldo23_reg: LDO23 { + regulator-name = "VDD_1.8V_ESE"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo24_reg: LDO24 { + regulator-name = "V_HRM_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3350000>; + }; + + ldo25_reg: LDO25 { + regulator-name = "PROX_LED_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo26_reg: LDO26 { + regulator-name = "VDD_1.2V_CODEC"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + }; + }; + }; + + hsi2c@13680000 { + status = "okay"; + samsung,hs-mode; + clock-frequency = <1000000>; + earSmart@3e { + compatible = "earSmart"; + reg = <0x3e>; + clocks = <&clock 45>; + clock-names = "mclk"; + pinctrl-0 = <&es704_i2c &es704_reset &es704_wakeup>; + esxxx-reset-gpio = <&gpf1 0 0>; + esxxx-wakeup-gpio = <&gpd0 1 0>; + adnc,firmware_name = "audience-es804-fw.bin"; + }; + }; + + serial_0: uart@13630000 { + status = "okay"; + samsung,use-default-irq; + }; + + hsi2c@13670000 { + max77838@60 { + status = "disabled"; + }; + + s2mpb02@59 { + status = "okay"; + compatible = "samsung,s2mpb02"; + reg = <0x59>; + + s2mpb02,irq-gpio = <&gpr2 2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&sub_pmic_irq>; + + regulators { + _buck1_reg: s2mpb02-buck1 { + regulator-name = "VDD_1P6_DDR"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; + }; + + _buck2_reg: s2mpb02-buck2 { + regulator-name = "VDDD_CORE_0.8V_COMP"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <850000>; + }; + + _ldo1_reg: s2mpb02-ldo1 { + regulator-name = "VDDD_NORET_0.9V_COMP"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + }; + + _ldo2_reg: s2mpb02-ldo2 { + regulator-name = "VDDD_CORE_1.0V_COMP"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo3_reg: s2mpb02-ldo3 { + regulator-name = "VDDD_1.2V_CAM"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo4_reg: s2mpb02-ldo4 { + regulator-name = "VDDD_RET_1.0V_COMP"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1000000>; + }; + + _ldo5_reg: s2mpb02-ldo5 { + regulator-name = "VDDD_1.2V_VT"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + _ldo6_reg: s2mpb02-ldo6 { + regulator-name = "VDDIO_1.8V_VT"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo7_reg: s2mpb02-ldo7 { + regulator-name = "VDDIO_1.8V_CAM"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo8_reg: s2mpb02-ldo8 { + regulator-name = "VDDIO_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo9_reg: s2mpb02-ldo9 { + regulator-name = "VDDA_1.8V_COMP"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo10_reg: s2mpb02-ldo10 { + regulator-name = "VCC_DISPLAY_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + _ldo11_reg: s2mpb02-ldo11 { + regulator-name = "VDDA_2.9V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2950000>; + }; + + _ldo12_reg: s2mpb02-ldo12 { + regulator-name = "VDDAF_2.8V_CAM"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo13_reg: s2mpb02-ldo13 { + regulator-name = "VDDA_2.9V_VT"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <2900000>; + }; + + _ldo14_reg: s2mpb02-ldo14 { + regulator-name = "OIS_VM_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo15_reg: s2mpb02-ldo15 { + regulator-name = "OIS_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + _ldo16_reg: s2mpb02-ldo16 { + regulator-name = "VCC_3.0V_LCD"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + _ldo17_reg: s2mpb02-ldo17 { + regulator-name = "tsp_avdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + + torch { + status = "okay"; + leds1 { + ledname = "leds-sec1"; + /* S2MPB02_FLASH_LED_1 */ + id = <0>; + /* S2MPB02_FLASH_CURRENT */ + brightness = <0xF>; + /* S2MPB02_FLASH_TIMEOUT */ + timeout = <0x3>; + }; + + leds2 { + ledname = "torch-sec1"; + /* S2MPB02_TORCH_LED_1 */ + id = <1>; + /* S2MPB02_TORCH_CURRENT */ + brightness = <0x9>; + /* S2MPB02_TORCH_TIMEOUT */ + timeout = <0xF>; + }; + }; + }; + }; + + hsi2c@14E00000 { + sec-nfc@27 { + sec-nfc,i2c_1p8 = "VDD20_1P8_AP"; + }; + }; + + hsi2c@14E60000 { + status = "disable"; + /delete-node/ s2mpb01_pmic@59; + }; + + sec_thermistor@0 { + status = "okay"; + + adc_array = <205 216 227 238 249 260 271 282 293 303 + 314 324 335 346 356 366 377 388 398 408 + 418 436 454 472 489 506 520 534 548 561 + 575 588 602 619 636 655 674 697 720 737 + 754 775 796 819 842 857 872 904 936 953 + 974 993 1012 1031 1050 1070 1087 1104 1121 1138 + 1155 1175 1205 1232 1259 1286 1306 1326 1345 1365 + 1385 1403 1421 1439 1457 1475 1492 1509 1526 1543 + 1560 1579 1598 1616 1635 1654 1669 1684 1699 1713 + 1728 1740 1753 1766 1778 1790 1798 1806 1814 1822 + 1830 1839 1848 1856 1864 1872 1880 1888 1896 1904 + 1912>; + }; + + sec_thermistor@2 { + status = "okay"; + + adc_array = <205 216 227 238 249 260 271 282 293 303 + 314 324 335 346 356 366 377 388 398 408 + 418 436 454 472 489 506 520 534 548 561 + 575 588 602 619 636 655 674 697 720 737 + 754 775 796 819 842 857 872 904 936 953 + 974 993 1012 1031 1050 1070 1087 1104 1121 1138 + 1155 1175 1205 1232 1259 1286 1306 1326 1345 1365 + 1385 1403 1421 1439 1457 1475 1492 1509 1526 1543 + 1560 1579 1598 1616 1635 1654 1669 1684 1699 1713 + 1728 1740 1753 1766 1778 1790 1798 1806 1814 1822 + 1830 1839 1848 1856 1864 1872 1880 1888 1896 1904 + 1912>; + }; + + hsi2c@14E10000 { + touchscreen@20 { + stm,num_touchkey = <2>; + stm,regulator_tk_led = "key_led"; + }; + }; + + pcie0@155C0000 { + status = "okay"; + }; + + dwmmc0@15740000 { + status = "disabled"; + }; + + dwmmc2@15560000 { + vdd_vmmc-supply = <&ldo25_reg>; + vqmmc-supply = <&ldo2_reg>; + }; + + dsim_0: dsim@0x13900000 { + gpios = <&gpr3 0 0x1>; + regulator_30V = "VCC_3.0V_LCD"; + regulator_18V = "VCC_DISPLAY_1.8V"; + regulator_16V = "VDD_1P6_DDR"; + lcd_info = <&s6e3hf2_wqhd>; + }; + + s6e3hf2_wqxga: s6e3hf2_wqxga_panel { + mode = <2>; /* 0: video mode, 1: DP command mode, 2: MIPI command mode */ + resolution = <1440 2560>; + size = <70 121>; + timing,refresh = <60>; + timing,h-porch = <1 1 1>; + timing,v-porch = <15 1 1>; + timing,dsi-hs-clk = <1026>; + timing,dsi-escape-clk = <16>; + mic = <1>; /* 0: mic disable, 1: mic enable */ + mic_ver = <2>; /* 0: mic v1.1, 1: v1.2, 2: v2.0 */ + type_of_ddi = <0>; /* 0: Samsung Mobile, 1: MAGNA, 2: Normal(Etc) */ + }; + + s6e3hf2_wqhd: s6e3hf2_wqhd_panel { + mode = <2>; + resolution = <1440 2560>; + size = <70 121>; + timing,refresh = <60>; + timing,h-porch = <1 1 1>; + timing,v-porch = <15 1 1>; + timing,dsi-hs-clk = <1026>; + timing,dsi-escape-clk = <16>; + mic = <1>; + mic_ver = <2>; + type_of_ddi = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_battery_07.dtsi b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_battery_07.dtsi index 3d5cba697987..c2c598965d89 100644 --- a/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_battery_07.dtsi +++ b/arch/arm64/boot/dts/exynos7420-zerolte_usa_cdma_battery_07.dtsi @@ -71,6 +71,7 @@ battery,temp_adc_type = <1>; /* SEC_BATTERY_ADC_TYPE_AP */ battery,chg_temp_check = <1>; + battery,wpc_temp_check = <1>; battery,polling_time = <10 30 30 30 3600>; @@ -88,17 +89,17 @@ 400 350 300 250 200 150 100 50 0 (-50) (-100) (-150) (-200)>; - battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1500 1500>; - battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2600 1000 2600 80 1800 1000 1400 0 1000>; + battery,input_current_limit = <1800 0 0 1800 460 900 1000 460 1000 0 820 1900 1800 0 0 400 700 1300 300 1000 1500 0 1667 1000 1667 80 1800 1667 1400 1000 1000>; + battery,fast_charging_current = <2100 0 0 2100 460 1200 1000 460 1200 0 1200 1600 2100 0 0 400 700 1300 300 1000 1500 0 2550 1000 2550 80 1800 1000 1400 0 1000>; battery,full_check_current_1st = <275 0 0 275 275 275 275 275 275 0 275 275 275 0 0 275 275 275 275 275 275 0 275 275 275 0 275 275 275 0 275>; battery,full_check_current_2nd = <125 0 0 125 125 125 125 125 125 0 125 125 125 0 0 125 125 125 125 125 125 0 125 125 125 0 125 125 125 0 125>; battery,wireless_cc_cv = <90>; battery,inbat_voltage = <1>; - battery,inbat_voltage_table_adc = <2905 2873 2848 2819 2787 2762 2731 2677 2655 2619 - 2591 2565 2534 2504 2475 2445 2420 2401 2364 2343>; - battery,inbat_voltage_table_data = <438 435 430 425 420 415 410 400 395 390 + battery,inbat_voltage_table_adc = <2888 2861 2831 2801 2770 2741 2716 2659 2630 2604 + 2575 2544 2513 2484 2459 2428 2399 2367 2340 2311>; + battery,inbat_voltage_table_data = <440 435 430 425 420 415 410 400 395 390 385 380 375 370 365 360 355 350 345 340>; battery,adc_check_count = <5>; @@ -152,6 +153,10 @@ battery,chg_skip_check_capacity = <10>; battery,chg_skip_check_time = <600>; + battery,wpc_high_temp = <380>; + battery,wpc_high_temp_recovery = <370>; + battery,wpc_charging_limit_current = <450>; + /* SEC_BATTERY_FULL_CONDITION_SOC | SEC_BATTERY_FULL_CONDITION_NOTIMEFULL | SEC_BATTERY_FULL_CONDITION_VCELL */ @@ -162,7 +167,7 @@ battery,recharge_check_count = <2>; battery,recharge_condition_type = <4>; /* SEC_BATTERY_RECHARGE_CONDITION_VCELL */ battery,recharge_condition_soc = <98>; - battery,recharge_condition_vcell = <4350>; + battery,recharge_condition_vcell = <4325>; battery,charging_total_time = <21600>; battery,recharging_total_time = <5400>; diff --git a/arch/arm64/boot/dts/exynos7420.dtsi b/arch/arm64/boot/dts/exynos7420.dtsi index bf4838daed1c..03b5a71caa00 100644 --- a/arch/arm64/boot/dts/exynos7420.dtsi +++ b/arch/arm64/boot/dts/exynos7420.dtsi @@ -13,7 +13,7 @@ * published by the Free Software Foundation. */ -/memreserve/ 0xFF980000 0x680000; /* EL3 monitor, secure intepreter */ +/memreserve/ 0xFE800000 0x1800000; /* EL3 monitor, secure intepreter */ #include #include /include/ "exynos7420-pinctrl.dtsi" @@ -1092,8 +1092,8 @@ compatible = "arm,mali"; reg = <0x14AC0000 0x5000>; interrupts = <0 241 0>, <0 242 0>, <0 240 0>; - clocks = <&clock 1>, <&clock 10>, <&clock 160>, <&clock 161>, <&clock 162>, <&clock 163>; - clock-names = "fin_pll", "fout_g3d_pll", "aclk_g3d", "dout_aclk_g3d", "mout_g3d", "sclk_hpm_g3d"; + clocks = <&clock 1>, <&clock 10>, <&clock 160>, <&clock 161>, <&clock 162>, <&clock 163>, <&clock 300>, <&clock 301>; + clock-names = "fin_pll", "fout_g3d_pll", "aclk_g3d", "dout_aclk_g3d", "mout_g3d", "sclk_hpm_g3d", "aclk_lh_g3d0", "aclk_lh_g3d1"; samsung,power-domain = <&pd_g3d>; }; @@ -3383,4 +3383,10 @@ fips_fmp { compatible = "samsung,exynos-fips-fmp"; }; + + pmu_coremem_ratio { + compatible = "samsung,exynos-pmu_coremem"; + /* core:mem <100:0, 80:20, 60:40, 40:60, 20:80, 0:100> */ + const_lpki = <0 20948 41896 62844 83792 104740>; + }; }; diff --git a/arch/arm64/boot/dts/modem-ss333-pdata.dtsi b/arch/arm64/boot/dts/modem-ss333-pdata.dtsi index 14cec624e763..854a41e8ba4d 100644 --- a/arch/arm64/boot/dts/modem-ss333-pdata.dtsi +++ b/arch/arm64/boot/dts/modem-ss333-pdata.dtsi @@ -20,7 +20,7 @@ mif,modem_type = <15>; mif,use_handover = <0>; mif,ipc_version = <50>; - mif,link_types = <0x400>; /* LINKDEV_LLI */ + mif,link_types = <0x408>; /* LINKDEV_LLI | LINKDEV_SPI */ mif,link_name = "lli"; mif,link_attrs = <0x3C9>; /* DUMP_ALIGNED (0x200) | BOOT_ALIGNED (0x100) | MEM_DUMP (0x80) | MEM_BOOT (0x40) | DPRAM_MAGIC (0x08) | SBD_IPC (0x01) */ @@ -235,7 +235,8 @@ iod,id = <215>; iod,format = <4>; iod,io_type = <0>; - iod,links = <0x400>; + iod,links = <0x408>; + iod,tx_link = <10>; /* LINKDEV_LLI */ iod,attrs = <0x02>; /* ATTR_SIPC5 */ iod,app = "CBD"; }; diff --git a/arch/arm64/configs/exynos7420-zeroflte_tmo_defconfig b/arch/arm64/configs/exynos7420-zeroflte_tmo_defconfig new file mode 100644 index 000000000000..178bb73323b7 --- /dev/null +++ b/arch/arm64/configs/exynos7420-zeroflte_tmo_defconfig @@ -0,0 +1,4466 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm64 3.10.61 Kernel Configuration +# +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_ZONE_DMA is not set +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_NEED_DMA_MAP_STATE=y +# CONFIG_NEED_SG_DMA_LENGTH is not set +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SWIOTLB=y +CONFIG_IOMMU_HELPER=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_BUG=y +# CONFIG_SEC_FACTORY is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=0 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_DEFERRED_INITCALLS=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +CONFIG_BLOCK_COMPAT=y +CONFIG_BLOCK_SUPPORT_STLOG=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# Platform selection +# +# CONFIG_ARCH_VEXPRESS is not set +CONFIG_ARCH_EXYNOS=y +CONFIG_ARM_TRUSTZONE=y +CONFIG_PLAT_SAMSUNG=y +CONFIG_PLAT_S5P=y + +# +# Boot options +# +# CONFIG_S3C_BOOT_ERROR_RESET is not set +# CONFIG_S5P_CLOCK is not set +CONFIG_SAMSUNG_IRQ_VIC_TIMER=y +# CONFIG_S5P_IRQ is not set +CONFIG_SAMSUNG_GPIOLIB_4BIT=y +CONFIG_S5P_GPIO_DRVSTR=y +CONFIG_SAMSUNG_GPIO_EXTRA=0 +CONFIG_S3C_GPIO_SPACE=0 +CONFIG_S3C_GPIO_TRACK=y +# CONFIG_S3C_ADC is not set +CONFIG_S3C_DEV_RTC=y +# CONFIG_S3C24XX_PWM is not set +CONFIG_SAMSUNG_DMADEV=y + +# +# Power management +# +# CONFIG_SAMSUNG_PM_DEBUG is not set +# CONFIG_SAMSUNG_PM_CHECK is not set +CONFIG_S5P_PM=y +CONFIG_S5P_SLEEP=y +# CONFIG_SAMSUNG_CORE_TEST is not set + +# +# SAMSUNG EXYNOS SoCs Support +# +# CONFIG_ARCH_EXYNOS5 is not set +CONFIG_ARCH_EXYNOS7=y +CONFIG_SOC_EXYNOS7420=y +# CONFIG_SOC_EXYNOS7420_EVT_0 is not set +# CONFIG_SOC_EXYNOS7580 is not set +CONFIG_EXYNOS_ASV=y +# CONFIG_EXYNOS_ASV_DYNAMIC_ABB is not set +CONFIG_EXYNOS_ASV_SUPPORT_RCC=y +# CONFIG_EXYNOS_ASV_MARGIN_TEST is not set +# CONFIG_SKIP_HW_BREAKPOINT is not set +CONFIG_CAL_SYS_PWRDOWN=y +CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG=y +CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG_SLEEP_PREPARE=4 +CONFIG_EXYNOS_CONTENT_PATH_PROTECTION=y +CONFIG_EXYNOS5_SETUP_MIPIPHY=y +CONFIG_SAMSUNG_PRODUCT_SHIP=y + +# +# Flattened Device Tree based board for EXYNOS SoCs +# +# CONFIG_MACH_ESPRESSO7420 is not set +CONFIG_MACH_UNIVERSAL7420=y +# CONFIG_MACH_SMDK7580 is not set +# CONFIG_MACH_UNIVERSAL7580 is not set +CONFIG_EXYNOS_SPI_RESET_DURING_DSTOP=y +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_SUBSYSTEM_RESTART is not set +# CONFIG_MSM_SYSMON_COMM is not set +CONFIG_TIMA=y +CONFIG_TIMA_LKMAUTH=y +CONFIG_TIMA_RKP=y +CONFIG_RKP_DMAP_PROT=y +CONFIG_RKP_KDP=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +CONFIG_PCIE_DW=y +CONFIG_PCI_EXYNOS=y +# CONFIG_PCI_EXYNOS_TEST is not set +# CONFIG_PCI_EXYNOS_REDUCE_RESET_WAIT is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +CONFIG_PCIE_PME=y + +# +# Kernel Features +# +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y +CONFIG_SCHED_HMP=y +# CONFIG_SCHED_HMP_PRIO_FILTER is not set +CONFIG_HMP_FAST_CPU_MASK="4-7" +CONFIG_HMP_SLOW_CPU_MASK="0-3" +CONFIG_HMP_VARIABLE_SCALE=y +CONFIG_HMP_FREQUENCY_INVARIANT_SCALE=y +# CONFIG_SCHED_HMP_LITTLE_PACKING is not set +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_SWP_EMULATE=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_ARCH_NR_GPIO=1024 +CONFIG_HZ=100 +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_NO_BOOTMEM=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=0 +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +CONFIG_FRONTSWAP=y +CONFIG_ZSWAP=y +CONFIG_ZPOOL=y +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_DIRECT_RECLAIM_FILE_PAGES_ONLY=y +CONFIG_INCREASE_MAXIMUM_SWAPPINESS=y +CONFIG_FIX_INACTIVE_RATIO=y +CONFIG_TIGHT_PGDAT_BALANCE=y +# CONFIG_SWAP_ENABLE_READAHEAD is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +CONFIG_MIN_DIRTY_THRESH_PAGES=2560 +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ARMV7_COMPAT=y +CONFIG_ARMV7_COMPAT_CPUINFO=y +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set + +# +# Boot options +# +CONFIG_CMDLINE="" +# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_KEYS_COMPAT=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=100 +CONFIG_PM_WAKELOCKS_GC=y +CONFIG_PM_RUNTIME=y +CONFIG_PM_RUNTIME_TEST_SYSFS=y +# CONFIG_PM_DOMAIN_DEBUG is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_RUNTIME=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_MODE_AUTO_CHANGE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_GENERIC_CPUFREQ_CPU0 is not set + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_EXYNOS_CPUFREQ is not set +CONFIG_ARM_EXYNOS_MP_CPUFREQ=y +# CONFIG_ARM_EXYNOS_SMP_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5430_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5422_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5433_CPUFREQ is not set +CONFIG_ARM_EXYNOS7420_CPUFREQ=y +# CONFIG_ARM_EXYNOS5440_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_PMU_COREMEM_RATIO is not set + +# +# APM Driver +# +CONFIG_EXYNOS_APM=y +CONFIG_EXYNOS_MBOX=y + +# +# EXYNOS_CL_DVFS +# +CONFIG_EXYNOS_CL_DVFS_CPU=y +CONFIG_EXYNOS_CL_DVFS_G3D=y +CONFIG_EXYNOS_CL_DVFS_MIF=y +# CONFIG_EXYNOS_MBOX_DEFAULT_INTERRUPT is not set +CONFIG_EXYNOS_MBOX_DEFAULT_POLLING=y +# CONFIG_EXYNOS_MBOX_INTERRUPT is not set +CONFIG_EXYNOS_MBOX_POLLING=y +CONFIG_EXYNOS_APM_VOLTAGE_DEBUG=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM64_CPU_SUSPEND=y + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +CONFIG_OF_IDLE_STATES=y +CONFIG_CPU_IDLE_EXYNOS=y + +# +# ARM64 CPU Idle Drivers +# +# CONFIG_ARM64_CPUIDLE is not set +CONFIG_NET=y +CONFIG_COMPAT_NETLINK_MESSAGES=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_BIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="bic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_SEC_LOCALE_CHN is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +CONFIG_NETFILTER_XT_MATCH_SCTP=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +CONFIG_VPNCLIENT_SECURITY=y +CONFIG_VPNCLIENT_PROC_UID=1000 +CONFIG_VPNCLIENT_PROC_GID=1000 + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +CONFIG_NF_NAT_IPV6=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +# CONFIG_IP6_NF_TARGET_NPT is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_PHONET=y +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=y +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_RMNET_DATA is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +# CONFIG_BT_RFCOMM is not set +# CONFIG_BT_BNEP is not set +# CONFIG_BT_HIDP is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_UART_IN_AUDIO is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_BCM4358=y +# CONFIG_BT_BCM4359 is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_LIB80211 is not set +CONFIG_CFG80211_ALLOW_RECONNECT=y +CONFIG_CFG80211_REG_NOT_UPDATED=y +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +CONFIG_NFC=y +# CONFIG_NFC_NCI is not set +# CONFIG_NFC_HCI is not set + +# +# Near Field Communication (NFC) devices +# +# CONFIG_NFC_PN533 is not set +# CONFIG_SEC_NFC_I2C is not set +CONFIG_SEC_NFC=y +# CONFIG_SEC_NFC_PRODUCT_N3 is not set +CONFIG_SEC_NFC_PRODUCT_N5=y +# CONFIG_SEC_NFC_IF_UART is not set +CONFIG_SEC_NFC_IF_I2C=y +# CONFIG_SEC_NFC_IF_I2C_GPIO is not set +# CONFIG_SEC_NFC_CLK_REQ is not set +# CONFIG_SEC_NFC_MARGINTIME is not set +CONFIG_ESE_P3_LSI=y +# CONFIG_ESE_FACTORY_ONLY is not set +# CONFIG_NFC_PN547 is not set +# CONFIG_NFC_P61 is not set +CONFIG_SEC_NFC_LDO_CONTROL=y +# CONFIG_SEC_NFC_SENN3AB is not set +# CONFIG_NFC_DEBUG is not set +# CONFIG_NFC_EDC_TUNING is not set +# CONFIG_IPC_ROUTER is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_HAVE_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=0 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +CONFIG_KNOX_KAP=y +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_CHECK_SIMSLOT_COUNT is not set +CONFIG_TIMA_LOG=y +# CONFIG_SEC_FPGA_ICE40XX is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MIPI_LLI=y +# CONFIG_MIPI_LLI_BOOT_SPI is not set +CONFIG_EXYNOS_MIPI_LLI=y +CONFIG_EXYNOS_MIPI_LLI_MPHY=y + +# +# Samsung Mobile Modem Driver (SVNET2) V1 for Memory-type Interface +# +CONFIG_SEC_MODEM_V1=y +# CONFIG_BOOT_DEVICE_SPI is not set +CONFIG_LINK_DEVICE_SPI=y +CONFIG_LINK_DEVICE_MEMORY=y +CONFIG_LINK_POWER_MANAGEMENT=y +CONFIG_LINK_POWER_MANAGEMENT_WITH_FSM=y +# CONFIG_LINK_CONTROL_MSG_IOSM is not set +CONFIG_LINK_CONTROL_MSG_COMMAND=y +CONFIG_LINK_DEVICE_WITH_SBD_ARCH=y +# CONFIG_LINK_DEVICE_NAPI is not set +# CONFIG_SEC_MODEM_DEBUG is not set +# CONFIG_LINK_DEVICE_C2C is not set +CONFIG_LINK_DEVICE_LLI=y +# CONFIG_LINK_DEVICE_SHMEM is not set +# CONFIG_LINK_DEVICE_HSIC is not set +# CONFIG_LTE_MODEM_XMM7260 is not set +# CONFIG_UMTS_MODEM_SS222 is not set +# CONFIG_UMTS_MODEM_SH222AP is not set +# CONFIG_UMTS_MODEM_SS300 is not set +CONFIG_UMTS_MODEM_SS333=y +# CONFIG_SEC_MODEM_XMM7260_CAT6 is not set +# CONFIG_FM_RADIO is not set + +# +# NOTIFIER configs +# +CONFIG_VBUS_NOTIFIER=y + +# +# MUIC configs +# +CONFIG_USE_MUIC=y +CONFIG_USE_SAFEOUT=y +CONFIG_MUIC_NOTIFIER=y +# CONFIG_SAMSUNG_MUIC is not set +CONFIG_MUIC_ADCMODE_SWITCH_WA=y +CONFIG_MUIC_RUSTPROOF_ON_USER=y +# CONFIG_MUIC_FSA9480 is not set +CONFIG_MUIC_MAX77843=y +CONFIG_HV_MUIC_MAX77843_AFC=y +CONFIG_MUIC_MAX77843_IGNORE_ADCERR_WA=y +CONFIG_MUIC_MAX77843_RESET_WA=y +# CONFIG_MUIC_S2MM001 is not set +# CONFIG_MUIC_HV_FORCE_LIMIT is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_FMP=y +CONFIG_UFS_FMP_DM_CRYPT=y +CONFIG_UFS_FMP_ECRYPT_FS=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +CONFIG_SCSI_UFSHCD=y +CONFIG_UFS_DYNAMIC_H8=y +# CONFIG_SCSI_UFSHCD_PCI is not set +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_EXYNOS=y +CONFIG_FIPS_FMP_UFS=y +CONFIG_UFS_BKOPS_NODE_UID=1000 +CONFIG_UFS_BKOPS_NODE_GID=1001 +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_3COM=y +# CONFIG_TYPHOON is not set +CONFIG_NET_VENDOR_ADAPTEC=y +# CONFIG_ADAPTEC_STARFIRE is not set +CONFIG_NET_VENDOR_ALTEON=y +# CONFIG_ACENIC is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +CONFIG_NET_VENDOR_ATHEROS=y +# CONFIG_ATL2 is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL1C is not set +# CONFIG_ALX is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2X is not set +CONFIG_NET_VENDOR_BROCADE=y +# CONFIG_BNA is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +CONFIG_NET_VENDOR_CISCO=y +# CONFIG_ENIC is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_DEC=y +# CONFIG_NET_TULIP is not set +CONFIG_NET_VENDOR_DLINK=y +# CONFIG_DL2K is not set +# CONFIG_SUNDANCE is not set +CONFIG_NET_VENDOR_EMULEX=y +# CONFIG_BE2NET is not set +CONFIG_NET_VENDOR_EXAR=y +# CONFIG_S2IO is not set +# CONFIG_VXGE is not set +CONFIG_NET_VENDOR_HP=y +# CONFIG_HP100 is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +CONFIG_NET_VENDOR_MARVELL=y +# CONFIG_MVMDIO is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +CONFIG_NET_VENDOR_MELLANOX=y +# CONFIG_MLX4_EN is not set +# CONFIG_MLX4_CORE is not set +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +CONFIG_NET_VENDOR_MYRI=y +# CONFIG_MYRI10GE is not set +# CONFIG_FEALNX is not set +CONFIG_NET_VENDOR_NATSEMI=y +# CONFIG_NATSEMI is not set +# CONFIG_NS83820 is not set +CONFIG_NET_VENDOR_8390=y +# CONFIG_NE2K_PCI is not set +CONFIG_NET_VENDOR_NVIDIA=y +# CONFIG_FORCEDETH is not set +CONFIG_NET_VENDOR_OKI=y +# CONFIG_PCH_GBE is not set +# CONFIG_ETHOC is not set +CONFIG_NET_PACKET_ENGINE=y +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_NET_VENDOR_QLOGIC=y +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_NETXEN_NIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +CONFIG_NET_VENDOR_RDC=y +# CONFIG_R6040 is not set +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +# CONFIG_SC92031 is not set +CONFIG_NET_VENDOR_SIS=y +# CONFIG_SIS900 is not set +# CONFIG_SIS190 is not set +# CONFIG_SFC is not set +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC91X is not set +# CONFIG_EPIC100 is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_SUN=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NIU is not set +CONFIG_NET_VENDOR_TEHUTI=y +# CONFIG_TEHUTI is not set +CONFIG_NET_VENDOR_TI=y +# CONFIG_TLAN is not set +CONFIG_NET_VENDOR_VIA=y +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_CDC_PHONET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_ATH_CARDS is not set +CONFIG_BROADCOM_WIFI=y +# CONFIG_BCM4330 is not set +# CONFIG_BCM4343 is not set +# CONFIG_BCM4334 is not set +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set +CONFIG_BCM4358=y +# CONFIG_BCM4359 is not set +# CONFIG_BCM43241 is not set +# CONFIG_BCM4334W is not set +# CONFIG_BCM43455 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +# CONFIG_BCMDHD_PREALLOC_PKTIDMAP is not set +CONFIG_WLAN_REGION_CODE=100 +CONFIG_WLAIBSS=y +CONFIG_WL_RELMCAST=y +CONFIG_BCMDHD_PCIE=y +# CONFIG_BCM4358_A3 is not set +# CONFIG_WL_NAN is not set +# CONFIG_BCMDHD_DEBUG_PAGEALLOC is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_LIBERTAS is not set +# CONFIG_HERMES is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set +# CONFIG_LGUIWLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_KEYRESET is not set +CONFIG_GLOVE_TOUCH=y +CONFIG_HALL=y +# CONFIG_HALL_LOOPCHECK_WA is not set +CONFIG_CERTIFY_HALL=y +# CONFIG_CERTIFY_HALL_NFC_WA is not set +# CONFIG_INPUT_EXPANDED_ABS is not set +# CONFIG_INPUT_KEYCOMBO is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ABOV_TOUCH is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_20075 is not set +CONFIG_KEYBOARD_CYPRESS_TOUCH_MBR31X5=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_MXT540E is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX2 is not set +CONFIG_TOUCHSCREEN_FTS=y +# CONFIG_TOUCHSCREEN_FTS5AD56 is not set +# CONFIG_INPUT_WACOM is not set +# CONFIG_EPEN_WACOM_G5SP is not set +# CONFIG_EPEN_WACOM_G9PM is not set +# CONFIG_EPEN_WACOM_G9PL is not set +# CONFIG_EPEN_WACOM_G9PLL is not set +# CONFIG_EPEN_WACOM_G10PM is not set +# CONFIG_EPEN_WACOM_W9012 is not set +# CONFIG_EPEN_WACOM_W9014 is not set +# CONFIG_WACOM_LCD_FREQ_COMPENSATE is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ARIZONA_HAPTICS is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +CONFIG_INPUT_BOOSTER=y + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set + +# +# Diag Support +# +# CONFIG_DIAG_CHAR is not set + +# +# DIAG traffic over USB +# +# CONFIG_DIAG_OVER_USB is not set + +# +# HSIC/SMUX support for DIAG +# + +# +# Debug support for DIAG +# +# CONFIG_DIAG_MODE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_SAMSUNG=y +# CONFIG_SERIAL_SAMSUNG_DMA is not set +CONFIG_SERIAL_SAMSUNG_UARTS=6 +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_EXYNOS_SWD=y +CONFIG_EXYRNG_FIPS_COMPLIANCE=y +# CONFIG_EXYRNG_FAIL_POLICY_DISABLE is not set +CONFIG_EXYRNG_FAIL_POLICY_RESET=y +CONFIG_EXYRNG_USE_CRYPTOMANAGER=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# PCMCIA character devices +# +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +CONFIG_I2C_EXYNOS5=y +CONFIG_I2C_GPIO=y +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +CONFIG_HAVE_S3C2410_I2C=y +# CONFIG_I2C_S3C2410 is not set +CONFIG_HAVE_EXYNOS5_HSI2C=y +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +CONFIG_SPI_S3C64XX=y +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SENSORS_FP_SPI_NUMBER=4 + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PINCTRL_SAMSUNG=y +CONFIG_PINCTRL_EXYNOS=y +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_SEC_GPIO_DVS=y +CONFIG_MST_SECURE_GPIO=y +CONFIG_SENSORS_FP_SPI_GPIO="gpv7" +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +CONFIG_GPIO_ARIZONA=y +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_ANDROID is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24160 is not set +# CONFIG_FUELGAUGE_S2MG001 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_VEXPRESS is not set +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_SEC_THERMISTOR=y +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +CONFIG_CPU_THERMAL=y +# CONFIG_GPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_EXYNOS_THERMAL=y +# CONFIG_EXYNOS_SWTRIP is not set +CONFIG_CPU_THERMAL_IPA=y +CONFIG_CPU_THERMAL_IPA_CONTROL=y +# CONFIG_CPU_THERMAL_IPA_DEBUG is not set + +# +# Samsung thermal drivers +# +# CONFIG_EXYNOS_THERMAL_CORE is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_HAVE_S3C2410_WATCHDOG=y +CONFIG_S3C2410_WATCHDOG=y +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77804 is not set +# CONFIG_MFD_MAX77804K is not set +# CONFIG_MFD_MAX77823 is not set +# CONFIG_MFD_MAX77828 is not set +CONFIG_MFD_MAX77843=y +# CONFIG_MFD_MAX77833 is not set +# CONFIG_MFD_MAX77888 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_MFD_SEC_CORE=y +# CONFIG_MFD_S2MU003 is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_VX855 is not set +CONFIG_MFD_ARIZONA=y +CONFIG_MFD_ARIZONA_DEFERRED_RESUME=y +# CONFIG_MFD_ARIZONA_I2C is not set +CONFIG_MFD_ARIZONA_SPI=y +# CONFIG_MFD_WM5102 is not set +CONFIG_MFD_FLORIDA=y +# CONFIG_MFD_VEGAS is not set +# CONFIG_MFD_WM8997 is not set +CONFIG_MFD_CLEARWATER=y +# CONFIG_MFD_LARGO is not set +# CONFIG_MFD_MARLEY is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_MFD_S2MPB02=y +# CONFIG_VEXPRESS_CONFIG is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_ARIZONA=y +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_MAX77838=y +CONFIG_REGULATOR_MAX77843=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_S2MPS11 is not set +# CONFIG_REGULATOR_S2MPS13 is not set +CONFIG_REGULATOR_S2MPS15=y +# CONFIG_REGULATOR_S2MPU03 is not set +CONFIG_REGULATOR_S2MPB01=y +# CONFIG_REGULATOR_S5M8767 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_NCP6335B is not set +CONFIG_REGULATOR_S2MPB02=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_M2M1SHOT=y +# CONFIG_MEDIA_M2M1SHOT_TESTDEV is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_V4L2_MEM2MEM_DEV=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_ION=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +CONFIG_VIDEO_EXYNOS=y +CONFIG_EXYNOS_MEDIA_DEVICE=y +# CONFIG_VIDEO_EXYNOS_GSCALER_1_3 is not set +# CONFIG_VIDEO_EXYNOS_GSCALER is not set +CONFIG_VIDEO_EXYNOS_MFC=y +# CONFIG_EXYNOS_MFC_V6 is not set +# CONFIG_EXYNOS_MFC_V8 is not set +CONFIG_EXYNOS_MFC_V9=y +# CONFIG_VIDEO_EXYNOS_HEVC is not set +CONFIG_VIDEO_EXYNOS_FIMC_IS=y +CONFIG_USE_VENDER_FEATURE=y +CONFIG_ENABLE_HAL3_2_META_INTERFACE=y +# CONFIG_TORCH_CURRENT_CHANGE_SUPPORT is not set +# CONFIG_MODULE_ALL_INCLUDE is not set +# CONFIG_CAMERA_SENSOR_8B1 is not set +# CONFIG_CAMERA_SENSOR_6D1 is not set +# CONFIG_CAMERA_SENSOR_8B1_OBJ is not set +# CONFIG_CAMERA_SENSOR_6D1_OBJ is not set +# CONFIG_CAMERA_SENSOR_6B2_OBJ is not set +# CONFIG_CAMERA_SENSOR_6A3_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX135_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX134_OBJ is not set +# CONFIG_CAMERA_SENSOR_3L2_OBJ is not set +CONFIG_CAMERA_SENSOR_2P2_OBJ=y +# CONFIG_CAMERA_SENSOR_2P2_12M_OBJ is not set +# CONFIG_CAMERA_SENSOR_2T2_OBJ is not set +# CONFIG_CAMERA_SENSOR_2P3_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H5_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H7_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H7_SUNNY_OBJ is not set +# CONFIG_CAMERA_SENSOR_4E5_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX175_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX219_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX228_OBJ is not set +CONFIG_CAMERA_SENSOR_IMX240_OBJ=y +# CONFIG_CAMERA_SENSOR_4H5_OBJ is not set +# CONFIG_CAMERA_SENSOR_SR261_OBJ is not set +CONFIG_CAMERA_SENSOR_4E6_OBJ=y +CONFIG_CAMERA_SENSOR_4E6_C2_OBJ=y +# CONFIG_CSI_V3_2 is not set +CONFIG_CSI_V3_4=y +CONFIG_FIMC_IS_V4_0_0=y +# CONFIG_CAMERA_EEPROM_SUPPORT_REAR is not set +CONFIG_CAMERA_EEPROM_SUPPORT_FRONT=y +CONFIG_COMPANION_USE=y +# CONFIG_COMPANION_C1_USE is not set +CONFIG_COMPANION_C2_USE=y +CONFIG_COMPANION_DCDC_USE=y +CONFIG_COMPANION_STANDBY_USE=y +CONFIG_OIS_USE=y +CONFIG_OIS_FW_UPDATE_THREAD_USE=y +CONFIG_AF_HOST_CONTROL=y +CONFIG_CAMERA_ZERO=y +# CONFIG_CAMERA_MARINE is not set +# CONFIG_CAMERA_VLTE is not set +# CONFIG_CAMERA_NOBLE is not set +# CONFIG_CAMERA_ZENLTE is not set +CONFIG_VIDEO_EXYNOS_SCALER=y +# CONFIG_SCALER_NO_SOFTRST is not set +CONFIG_VIDEO_EXYNOS_FIMG2D=y +CONFIG_FIMG2D_CCI_SNOOP=y +# CONFIG_VIDEO_EXYNOS_JPEG is not set +# CONFIG_VIDEO_EXYNOS_HX_JPEG is not set +# CONFIG_VIDEO_EXYNOS_TV is not set +# CONFIG_VIDEO_EXYNOS_HDMI is not set +CONFIG_MEDIA_EXYNOS_JPEG=y +CONFIG_MEDIA_EXYNOS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS is not set +# CONFIG_VIDEO_SAMSUNG_S5P_TV is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_TDMB is not set +# CONFIG_ISDBT is not set +# CONFIG_ISDBT_F_TYPE_ANTENNA is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set + +# +# ARM GPU Configuration +# +# CONFIG_MALI_T6XX is not set +# CONFIG_MALI_GATOR_SUPPORT is not set +CONFIG_MALI_EXYNOS_TRACE=y +# CONFIG_MALI_FULL_TRACE is not set +CONFIG_MALI_EXPERT=y +# CONFIG_MALI_DEBUG_SHADER_SPLIT_FS is not set +# CONFIG_MALI_PLATFORM_FAKE is not set +CONFIG_MALI_PLATFORM_THIRDPARTY=y +CONFIG_MALI_PLATFORM_THIRDPARTY_NAME="7420" +# CONFIG_MALI_DEBUG is not set +# CONFIG_MALI_NO_MALI is not set +# CONFIG_MALI_TRACE_TIMELINE is not set +# CONFIG_MALI_SYSTEM_TRACE is not set +# CONFIG_MALI_GPU_TRACEPOINTS is not set +# CONFIG_MALI_MIDGARD is not set +# CONFIG_MALI_MIDGARD_WK04 is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI_T7XX=y +CONFIG_MALI_R5P0=y +CONFIG_MALI_RT_PM=y +CONFIG_MALI_ENABLE_TRACE=y +CONFIG_MALI_DEBUG_SYS=y +CONFIG_MALI_SEC_HWCNT=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_TMIO is not set +# CONFIG_DECON is not set +CONFIG_USE_VSYNC_SKIP=y +CONFIG_DECON_MIPI_DSI_PKTGO=y +# CONFIG_FB_S3C is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +CONFIG_S5P_LCD_INIT=y +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +CONFIG_FB_SIMPLE=y +CONFIG_EXYNOS_VIDEO=y +CONFIG_EXYNOS_MIPI_DSI=y +# CONFIG_EXYNOS_LCD_S6E8AX0 is not set +# CONFIG_EXYNOS_DP is not set +# CONFIG_EXYNOS_DECON_DISPLAY is not set +CONFIG_FB_WINDOW_UPDATE=y +# CONFIG_EXYNOS_DECON_TV_DISPLAY is not set +CONFIG_EXYNOS_DECON=y +CONFIG_EXYNOS_DECON_FB=y +# CONFIG_EXYNOS_DECON_MDNIE is not set +CONFIG_DECON_LPD_DISPLAY=y +CONFIG_DECON_BLOCKING_MODE=y +CONFIG_DECON_EVENT_LOG=y +CONFIG_EXYNOS_VPP=y +CONFIG_EXYNOS_DECON_LCD=y +CONFIG_EXYNOS_DECON_MDNIE_LITE=y +CONFIG_EXYNOS_DECON_LCD_SYSFS=y +# CONFIG_EXYNOS_DECON_LCD_MCD is not set +CONFIG_LCD_HMT=y +# CONFIG_LCD_ALPM is not set +CONFIG_LCD_HBM_INTERPOLATION=y +CONFIG_PANEL_AID_DIMMING=y +# CONFIG_EXYNOS_DECON_LCD_S6E3HA0 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HA2K is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HF2 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HF2_WQHD is not set +# CONFIG_PANEL_S6E3HF2_DYNAMIC is not set +CONFIG_PANEL_S6E3HA2_DYNAMIC=y +# CONFIG_PANEL_S6E3HA3_DYNAMIC is not set +# CONFIG_PANEL_S6E3HF3_DYNAMIC is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3FA0 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3FA2 is not set +# CONFIG_EXYNOS_DUAL_DECON is not set +# CONFIG_PANEL_S6E3FA3 is not set + +# +# Mhl device support +# +# CONFIG_SEC_MHL_SUPPORT is not set +# CONFIG_SEC_MHL_HDCP is not set +# CONFIG_SEC_MHL_EDID is not set +# CONFIG_SAMSUNG_MHL_8240 is not set +# CONFIG_SEC_MHL_SII8620 is not set +# CONFIG_MEDIA_DATA_TUNNEL_SUPPORT is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_PCI=y +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_SND_SAMSUNG_I2S=y +CONFIG_SND_SAMSUNG_AUDSS=y +CONFIG_SND_SAMSUNG_IOMMU=y +# CONFIG_SND_SAMSUNG_FAKEDMA is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994 is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF is not set +# CONFIG_SND_SOC_SMDK_WM8994_PCM is not set +# CONFIG_SND_SOC_SAMSUNG_ESPRESSO7420_WM5110 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL7420_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_ESPRESSO5433_WM5110 is not set +# CONFIG_SND_SOC_SAMSUNG_XYREF5430_ES515 is not set +# CONFIG_SND_SOC_SAMSUNG_XYREF5422_ES515 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_FLORIDA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_ARIZONA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_FLORIDA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_ARIZONA is not set +CONFIG_SND_SOC_SAMSUNG_ZERO_FLORIDA=y +CONFIG_SND_SOC_SAMSUNG_ZERO_CLEARWATER=y +CONFIG_SND_SOC_SAMSUNG_ARIZONA=y +# CONFIG_SND_SOC_SAMSUNG_ZERO_HDMI is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5430_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK5422_WM8994 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL7580_COD3022X is not set +# CONFIG_SND_SAMSUNG_AUX_HDMI is not set +# CONFIG_SND_SAMSUNG_AUX_SPDIF is not set +CONFIG_SND_SAMSUNG_SEIREN=y +# CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD is not set +# CONFIG_SND_SAMSUNG_SEIREN_DEBUG is not set +# CONFIG_SND_SAMSUNG_DEBUGFS is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_ARIZONA=y +CONFIG_SND_SOC_WM_ADSP=y +# CONFIG_SND_SOC_MAX98504 is not set +CONFIG_SND_SOC_MAX98504A=y +# CONFIG_SND_SOC_MAXIM_DSM_A is not set +CONFIG_SND_SOC_MAXIM_DSM=y +CONFIG_SND_SOC_MAXIM_DSM_CAL=y +CONFIG_SND_SOC_MAX98505=y +# CONFIG_SND_SOC_MAX98505A is not set +CONFIG_SND_SOC_FLORIDA=y +CONFIG_SND_SOC_CLEARWATER=y +CONFIG_SND_SOC_DUMMY_CODEC=y + +# +# Audience earSmart codecs +# +CONFIG_SND_SOC_ES705=y +# CONFIG_SND_SOC_ES704 is not set +# CONFIG_SND_SOC_ES804 is not set +CONFIG_SND_SOC_ES_I2C=y +# CONFIG_SND_SOC_ESXXX_UART_FW_DOWNLOAD is not set +# CONFIG_SND_SOC_ESXXX_UART_WAKEUP is not set +# CONFIG_SND_SOC_3MIC_SUPPORT is not set +# CONFIG_SND_SOC_VEQ_SUPPORT is not set +# CONFIG_SND_SOC_ESXXX_SEAMLESS_VOICE_WAKEUP is not set +# CONFIG_SND_SOC_ESXXX_RESTORE_STD_FW is not set +# CONFIG_SND_SOC_ESXXX_VEQ_FILTER is not set +# CONFIG_SND_SOC_ESXXX_VEQ_EXTENDEDVOLUME is not set +# CONFIG_SND_SOC_ESXXX_UPDATE_VEQ_TABLE is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +# CONFIG_HID_ACRUX_FF is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +CONFIG_HID_SYNAPTICS_BT=y +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZAGG=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set +CONFIG_HID_OVR=y + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_XHCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=y +# CONFIG_USB_XHCI_HCD_DEBUGGING is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Notify features +# +CONFIG_USB_HOST_NOTIFY=y +CONFIG_USB_NOTIFY_LAYER=y +CONFIG_USB_NOTIFIER=y +CONFIG_USB_DEBUG_DETAILED_LOG=y +CONFIG_USB_STORAGE_DETECT=y +CONFIG_USB_HMT_SAMSUNG_INPUT=y + +# +# USB DesignWare features +# +CONFIG_USB_DWC3=y +# CONFIG_USB_DWC3_HOST is not set +# CONFIG_USB_DWC3_GADGET is not set +CONFIG_USB_DWC3_DUAL_ROLE=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_EXYNOS=y +CONFIG_USB_DWC3_PCI=y + +# +# Debugging features +# +# CONFIG_USB_DWC3_DEBUG is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +CONFIG_SAMSUNG_USBPHY=y +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_DWC_USB2PHY is not set +CONFIG_SAMSUNG_USB2PHY_DUMMY=y +CONFIG_SAMSUNG_USB3PHY=y +CONFIG_SAMSUNG_USB3PHY_CAL=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_S3C_OTGD is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE=y +CONFIG_USB_ANDROID_SAMSUNG_MTP=y +CONFIG_USB_LOCK_SUPPORT_FOR_MDM=y +CONFIG_USB_DUN_SUPPORT=y +CONFIG_USB_NCM_SUPPORT_MTU_CHANGE=y +CONFIG_USB_RNDIS_MULTIPACKET=y +CONFIG_USBIRQ_BALANCING_LTE_HIGHTP=y +# CONFIG_USB_RNDIS_VZW_REQ is not set +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_MAX77843_RGB=y +CONFIG_LEDS_S2MPB02=y +CONFIG_LEDS_KTD2692=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGERS is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +CONFIG_SWITCH_ANTENNA=y +CONFIG_SWITCH_ANTENNA_IF=y +# CONFIG_SWITCH_ANTENNA_EARJACK is not set +# CONFIG_SWITCH_ANTENNA_EARJACK_IF is not set +CONFIG_SWITCH_ARIZONA=y +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +CONFIG_HAVE_S3C_RTC=y +# CONFIG_RTC_DRV_S3C is not set +# CONFIG_EXYNOS_PERSISTENT_CLOCK is not set +CONFIG_RTC_DRV_SEC=y +# CONFIG_RTC_ALARM_BOOT is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +# CONFIG_MHI is not set +CONFIG_MHI_RMNET_DUMP=y +# CONFIG_DEBUG_PKTLOG is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +# CONFIG_PL330TEST_LOG is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_ET131X is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8187SE is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_DX_SEP is not set + +# +# IIO staging drivers +# + +# +# Accelerometers +# +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_SCA3000 is not set + +# +# Analog to digital converters +# +# CONFIG_AD7291 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD799X is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7280 is not set + +# +# Analog digital bi-direction converters +# +# CONFIG_ADT7316 is not set + +# +# Capacitance to digital converters +# +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7746 is not set + +# +# Direct Digital Synthesis +# +# CONFIG_AD5930 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16260 is not set + +# +# Network Analyzer, Impedance Converters +# +# CONFIG_AD5933 is not set + +# +# Light sensors +# +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843 is not set + +# +# Active energy metering IC +# +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set + +# +# Triggers - standalone +# +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_GPIO_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_ZRAM is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_FB_XGI is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_SEC_OOM_KILLER=y +CONFIG_ION=y +CONFIG_ION_TEST=y +CONFIG_ION_EXYNOS=y +CONFIG_ION_EXYNOS_STAT_LOG=y +CONFIG_ION_EXYNOS_OF=y +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_NET_VENDOR_SILICOM=y +# CONFIG_SBYPASS is not set +# CONFIG_BPCTL is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Samsung TN Features +# +CONFIG_SEC_EXT=y +CONFIG_SEC_SYSFS=y +CONFIG_SEC_REBOOT=y +CONFIG_SEC_MISC=y +CONFIG_ARGOS=y +CONFIG_SEC_SLOW_MODE=y +CONFIG_SEC_DEBUG=y + +# +# BSP Feature +# +CONFIG_SEC_BSP=y + +# +# Samsung TN logging feature +# +CONFIG_SEC_AVC_LOG=y +CONFIG_SEC_DEBUG_TSP_LOG=y +CONFIG_SEC_DEBUG_LAST_KMSG=y +CONFIG_SEC_DEBUG_TIMA_LOG=y +# CONFIG_SEC_DEBUG_MDM_SEPERATE_CRASH is not set + +# +# Samsung TN Power Management Options +# +CONFIG_SEC_PM=y +CONFIG_SEC_PM_DEBUG=y +CONFIG_USER_RESET_DEBUG=y +CONFIG_VNSWAP=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_DEBUG is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_SI5351 is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_CLKSRC_EXYNOS_MCT=y +CONFIG_MAILBOX=y +# CONFIG_PL320_MBOX is not set +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_EXYNOS_IOMMU_V6=y +CONFIG_EXYNOS7_IOMMU_CHECK_DF=y +CONFIG_EXYNOS_IOVMM_V6=y +CONFIG_EXYNOS_IOMMU_NO_MASTER_CLKGATE=y +CONFIG_EXYNOS_IOMMU_EVENT_LOG=y +# CONFIG_EXYNOS_IOMMU_DEBUG is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +# CONFIG_DEVFREQ_GOV_SIMPLE_USAGE is not set +CONFIG_DEVFREQ_GOV_SIMPLE_EXYNOS=y +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set + +# +# DEVFREQ Drivers +# +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ=y +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET=y +# CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ODT_OFF is not set +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING=y +CONFIG_VIBETONZ=y +CONFIG_MOTOR_DRV_MAX77843=y +# CONFIG_MOTOR_DRV_ISA1200 is not set +# CONFIG_MOTOR_DRV_ISA1400 is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_HAPTIC_ISA1400 is not set +# CONFIG_HAPTIC is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_EXYNOS_MCOMP=y +CONFIG_IIO=y +CONFIG_IIO_BUFFER=y +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_KFIFO_BUF=y +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 + +# +# Accelerometers +# +# CONFIG_KXSD9 is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set + +# +# Analog to digital converters +# +# CONFIG_AD7266 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7887 is not set +CONFIG_EXYNOS_ADC=y +# CONFIG_MAX1363 is not set +# CONFIG_TI_ADC081C is not set + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Hid Sensor IIO Common +# + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5686 is not set +# CONFIG_MAX517 is not set +# CONFIG_MCP4725 is not set + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +# CONFIG_AD9523 is not set + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +# CONFIG_ADF4350 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADXRS450 is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_ITG3200 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_INV_MPU6050_IIO is not set + +# +# Light sensors +# +# CONFIG_ADJD_S311 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_VCNL4000 is not set + +# +# Magnetometer sensors +# +# CONFIG_AK8975 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_VME_BUS is not set +CONFIG_PWM=y +CONFIG_PWM_SAMSUNG=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +CONFIG_BATTERY_SAMSUNG=y +# CONFIG_CHARGING_VZWCONCEPT is not set +CONFIG_BATTERY_SWELLING=y +CONFIG_BATTERY_SWELLING_SELF_DISCHARGING=y +# CONFIG_BATTERY_SWELLING_SELF_DISCHARGING_ZERO_ONLY is not set +CONFIG_INBATTERY=y +CONFIG_CALC_TIME_TO_FULL=y +# CONFIG_BATTERY_AGE_FORECAST is not set +# CONFIG_FUELGAUGE_DUMMY is not set +# CONFIG_FUELGAUGE_MAX17042 is not set +# CONFIG_FUELGAUGE_MAX17048 is not set +# CONFIG_FUELGAUGE_MAX17050 is not set +# CONFIG_FUELGAUGE_MAX77823 is not set +CONFIG_FUELGAUGE_MAX77843=y +# CONFIG_FUELGAUGE_MAX77833 is not set +# CONFIG_CHARGER_DUMMY is not set +# CONFIG_CHARGER_SMB328 is not set +# CONFIG_CHARGER_BQ24157 is not set +# CONFIG_CHARGER_BQ24191 is not set +# CONFIG_CHARGER_BQ24260 is not set +# CONFIG_CHARGER_MAX77823 is not set +CONFIG_CHARGER_MAX77843=y +# CONFIG_CHARGER_MAX77833 is not set +CONFIG_WIRELESS_CHARGER_INBATTERY=y +CONFIG_WIRELESS_CHARGER_INBATTERY_CS100=y +# CONFIG_WIRELESS_CHARGER_INBATTERY_5V_FIX is not set +# CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE is not set +CONFIG_WIRELESS_CHARGER_BQ51221=y +# CONFIG_WIRELESS_CHARGER_P9027S is not set +# CONFIG_WIRELESS_CHARGER_P9220 is not set +# CONFIG_WIRELESS_CHARGER_MAX77900 is not set +CONFIG_AFC_CHARGER_MODE=y +CONFIG_SAMSUNG_LPM_MODE=y +# CONFIG_WIRELESS_CHARGER_THM is not set +# CONFIG_EN_OOPS is not set +CONFIG_DISABLE_SAVE_CAPACITY_MAX=y +# CONFIG_FIX_CHG_FQ_4MHZ is not set +# CONFIG_RESET_CONTROLLER is not set +CONFIG_SENSORS_SSP=y +# CONFIG_SENSORS_SSP_STM is not set +# CONFIG_SENSORS_MAX86900 is not set +CONFIG_SENSORS_MAX86902=y +CONFIG_SENSORS_MULTIPLE_GLASS_TYPE=y +CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA=y +# CONFIG_SENSORS_SX9310 is not set +# CONFIG_SENSORS_SSP_NOBLELTE is not set +# CONFIG_SENSORS_SSP_ZENLTE is not set +# CONFIG_SENSORS_SSP_VLTE is not set +# CONFIG_SENSORS_SSP_ATUC128L5HAR is not set +CONFIG_SENSORS_SSP_MPU6500=y +# CONFIG_SENSORS_SSP_BMI168 is not set +# CONFIG_SENSORS_SSP_BMP280 is not set +CONFIG_SENSORS_SSP_TMD4903=y +# CONFIG_SENSORS_SSP_TMG399X is not set +# CONFIG_SENSORS_SSP_AK09911 is not set +CONFIG_SENSORS_SSP_MOBEAM=y +CONFIG_SENSORS_MAX_NOTCHFILTER=y +CONFIG_SENSORS_SYSFS=y +# CONFIG_SENSORS_SSP_ATMEL is not set +# CONFIG_SENSORS_SSP_AK8963C is not set +# CONFIG_SENSORS_SSP_YAS532 is not set +CONFIG_SENSORS_SSP_ACCELEROMETER_POSITION=0 +CONFIG_SENSORS_SSP_GYROSCOPE_POSITION=0 +CONFIG_SENSORS_SSP_MAGNETOMETER_POSITION=0 +CONFIG_SENSORS_SSP_SENSORHUB=y +CONFIG_SENSORS_SSP_FACTORY=y +# CONFIG_SENSORS_SSP_C12SD is not set +# CONFIG_SENSORS_SSP_LSM330 is not set +# CONFIG_SENSORS_SSP_CM36651 is not set +# CONFIG_SENSORS_SSP_CM3320 is not set +# CONFIG_SENSORS_SSP_MAX88920 is not set +# CONFIG_SENSORS_SSP_MAX88921 is not set +CONFIG_SENSORS_SSP_LPS25H=y +# CONFIG_SENSORS_SSP_BMI058 is not set +# CONFIG_SENSORS_MPU6500_BMI058_DUAL is not set +# CONFIG_SENSORS_SSP_BMP182 is not set +# CONFIG_SENSORS_SSP_AT32UC3L0128 is not set +# CONFIG_SENSORS_SSP_SHTC1 is not set +CONFIG_SENSORS_SSP_BBD=y +# CONFIG_SENSORS_SSP_ICM20610 is not set +# CONFIG_SENSORS_SSP_K6DS3TR is not set +CONFIG_SENSORS_SSP_YAS537=y +# CONFIG_SENSORS_SSP_STM32F401 is not set +# CONFIG_SENSORS_MAX86902_LED_5V is not set +# CONFIG_SENSOR_SSP_PROXIMTY_FOR_WINDOW_TYPE is not set +# CONFIG_SENSORS_ADPD142 is not set +# CONFIG_SENSORS_SSP_TMG399x is not set +CONFIG_SENSORS_SSP_SX9306=y +CONFIG_SENSORS_SSP_INTERRUPT_GYRO_SENSOR=y +# CONFIG_SENSORS_CORE is not set +# CONFIG_SENSORS_BMI055 is not set +# CONFIG_SENSORS_AK8963C is not set +# CONFIG_SENSORS_AK09911C is not set +# CONFIG_SENSORS_CM3323 is not set +# CONFIG_SENSORS_CM36653 is not set +# CONFIG_SENSORS_TMD27723 is not set +# CONFIG_SENSORS_TMD3782 is not set +# CONFIG_SENSORS_ESD_DEFENCE is not set +# CONFIG_SENSORS_SX9500 is not set +# CONFIG_SENSORS_GP2A30 is not set +CONFIG_GPS_BCMxxxxx=y +# CONFIG_GPS_BCM4752 is not set +# CONFIG_GPS_BCM47521 is not set +# CONFIG_GPS_BCM4753 is not set +CONFIG_GPS_BCM47531=y +CONFIG_GPS_BCM4773=y +CONFIG_SENSORS_FINGERPRINT=y +CONFIG_SENSORS_FINGERPRINT_SYSFS=y +CONFIG_SENSORS_VFS7XXX=y +# CONFIG_SENSORS_FPRINT_SECURE is not set +# CONFIG_SENSORS_ET310 is not set +CONFIG_MOBICORE_DRIVER=y +# CONFIG_MOBICORE_DEBUG is not set +CONFIG_MOBICORE_API=y +CONFIG_SECURE_OS_CONTROL=y +CONFIG_SECURE_OS_BOOSTER_API=y +CONFIG_TRUSTONIC_TRUSTED_UI=y +CONFIG_TRUSTONIC_TRUSTED_UI_FB_BLANK=y +CONFIG_TRUSTED_UI_TOUCH_ENABLE=y +CONFIG_TRACE=y +CONFIG_EXYNOS_NOC_DEBUGGING=y +CONFIG_EXYNOS_SNAPSHOT=y +CONFIG_EXYNOS_SNAPSHOT_CALLSTACK=4 +CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT=y +CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT_THRESHOLD=0 +# CONFIG_EXYNOS_SNAPSHOT_IRQ_DISABLED is not set +CONFIG_EXYNOS_SNAPSHOT_CLK=y +CONFIG_EXYNOS_SNAPSHOT_FREQ=y +# CONFIG_EXYNOS_SNAPSHOT_HRTIMER is not set +CONFIG_EXYNOS_SNAPSHOT_SOFTIRQ=y +# CONFIG_EXYNOS_SNAPSHOT_REG is not set +CONFIG_EXYNOS_SNAPSHOT_MBOX=y +CONFIG_EXYNOS_SNAPSHOT_HOOK_LOGGER=y +CONFIG_EXYNOS_SNAPSHOT_PANIC_REBOOT=y +CONFIG_EXYNOS_SNAPSHOT_WATCHDOG_RESET=y +# CONFIG_EXYNOS_SNAPSHOT_MINIMIZED_MODE is not set +CONFIG_EXYNOS_CORESIGHT=y +CONFIG_EXYNOS_CORESIGHT_PC_INFO=y +CONFIG_PC_ITERATION=5 +# CONFIG_EXYNOS_CORESIGHT_MAINTAIN_DBG_REG is not set +# CONFIG_EXYNOS_CORESIGHT_ETM is not set +# CONFIG_EXYNOS_CORESIGHT_STM is not set +CONFIG_EXYNOS_BTS=y +CONFIG_EXYNOS7420_BTS=y + +# +# LED MATRIX FPGA +# +# CONFIG_ICE5_FPGA_LED_MATRIX is not set +CONFIG_SEC_NET_FILTER=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_SDCARD_FS=y +CONFIG_SDCARD_FS_CI_SEARCH=y +CONFIG_SDCARD_FS_XATTR=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_VIRTUAL_XATTR=y +CONFIG_FAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:sdcard_external:s0" +CONFIG_FAT_SUPPORT_STLOG=y +CONFIG_EXFAT_FS=y +CONFIG_EXFAT_VIRTUAL_XATTR=y +CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:sdcard_external:s0" +CONFIG_EXFAT_SUPPORT_STLOG=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_STLOG=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_ECRYPT_FS_MESSAGING is not set +CONFIG_WTL_ENCRYPTION_FILTER=y +CONFIG_ECRYPT_FS_VIRTUAL_FAT_XATTR=y +CONFIG_SDP=y +# CONFIG_SDP_KEY_DUMP is not set +CONFIG_SCFS=y +# CONFIG_SYSTEM_COMPRESSED is not set +CONFIG_SCFS_LOWER_PAGECACHE_INVALIDATION=y +# CONFIG_SCFS_USE_CRYPTO is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CORE_NUM is not set +CONFIG_PRINTK_PROCESS=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2064 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_PROBE_EVENTS is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Samsung Rooting Restriction Feature +# +CONFIG_SEC_RESTRICT_ROOTING=y +CONFIG_SEC_RESTRICT_SETUID=y +CONFIG_SEC_RESTRICT_FORK=y +CONFIG_SEC_RESTRICT_ROOTING_LOG=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_MST_NOBLE_TARGET is not set +# CONFIG_MST_ZEN_TARGET is not set +CONFIG_MST_LDO=y +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_FIPS=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_TEST=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_GHASH=y +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +# CONFIG_CRYPTO_SHA2_ARM64_CE is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM64_CE is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_DRBG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y + +# +# Samsung Crypto Accelerator +# +CONFIG_FIPS_FMP=y +CONFIG_NODE_FOR_SELFTEST_FAIL=y +# CONFIG_PANIC_FOR_SELFTEST_FAIL is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +CONFIG_ARM64_CRYPTO=y +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set +# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set +# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +# CONFIG_QMI_ENCDEC is not set diff --git a/arch/arm64/configs/exynos7420-zerolte_tmo_defconfig b/arch/arm64/configs/exynos7420-zerolte_tmo_defconfig new file mode 100644 index 000000000000..2aa11c4fa21d --- /dev/null +++ b/arch/arm64/configs/exynos7420-zerolte_tmo_defconfig @@ -0,0 +1,4472 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm64 3.10.61 Kernel Configuration +# +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_MMU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_ZONE_DMA is not set +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_NEED_DMA_MAP_STATE=y +# CONFIG_NEED_SG_DMA_LENGTH is not set +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_SWIOTLB=y +CONFIG_IOMMU_HELPER=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_GENERIC_BUG=y +# CONFIG_SEC_FACTORY is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y +# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +# CONFIG_IRQ_DOMAIN_DEBUG is not set +CONFIG_SPARSE_IRQ=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set + +# +# RCU Subsystem +# +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_FANOUT=64 +CONFIG_RCU_FANOUT_LEAF=16 +# CONFIG_RCU_FANOUT_EXACT is not set +# CONFIG_RCU_FAST_NO_HZ is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set +# CONFIG_RCU_NOCB_CPU is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=19 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_MEMCG is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_CHECKPOINT_RESTORE is not set +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +CONFIG_UIDGID_CONVERTED=y +# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HOTPLUG=y +CONFIG_PANIC_TIMEOUT=0 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_PCI_QUIRKS=y +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_DEFERRED_INITCALLS=y +# CONFIG_PROFILING is not set +CONFIG_TRACEPOINTS=y +# CONFIG_JUMP_LABEL is not set +CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_USE_GENERIC_SMP_HELPERS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_STOP_MACHINE=y +CONFIG_BLOCK=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +CONFIG_BLOCK_COMPAT=y +CONFIG_BLOCK_SUPPORT_STLOG=y + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_FREEZER=y + +# +# Platform selection +# +# CONFIG_ARCH_VEXPRESS is not set +CONFIG_ARCH_EXYNOS=y +CONFIG_ARM_TRUSTZONE=y +CONFIG_PLAT_SAMSUNG=y +CONFIG_PLAT_S5P=y + +# +# Boot options +# +# CONFIG_S3C_BOOT_ERROR_RESET is not set +# CONFIG_S5P_CLOCK is not set +CONFIG_SAMSUNG_IRQ_VIC_TIMER=y +# CONFIG_S5P_IRQ is not set +CONFIG_SAMSUNG_GPIOLIB_4BIT=y +CONFIG_S5P_GPIO_DRVSTR=y +CONFIG_SAMSUNG_GPIO_EXTRA=0 +CONFIG_S3C_GPIO_SPACE=0 +CONFIG_S3C_GPIO_TRACK=y +# CONFIG_S3C_ADC is not set +CONFIG_S3C_DEV_RTC=y +# CONFIG_S3C24XX_PWM is not set +CONFIG_SAMSUNG_DMADEV=y + +# +# Power management +# +# CONFIG_SAMSUNG_PM_DEBUG is not set +# CONFIG_SAMSUNG_PM_CHECK is not set +CONFIG_S5P_PM=y +CONFIG_S5P_SLEEP=y +# CONFIG_SAMSUNG_CORE_TEST is not set + +# +# SAMSUNG EXYNOS SoCs Support +# +# CONFIG_ARCH_EXYNOS5 is not set +CONFIG_ARCH_EXYNOS7=y +CONFIG_SOC_EXYNOS7420=y +# CONFIG_SOC_EXYNOS7420_EVT_0 is not set +# CONFIG_SOC_EXYNOS7580 is not set +CONFIG_EXYNOS_ASV=y +# CONFIG_EXYNOS_ASV_DYNAMIC_ABB is not set +CONFIG_EXYNOS_ASV_SUPPORT_RCC=y +# CONFIG_EXYNOS_ASV_MARGIN_TEST is not set +# CONFIG_SKIP_HW_BREAKPOINT is not set +CONFIG_CAL_SYS_PWRDOWN=y +CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG=y +CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG_SLEEP_PREPARE=4 +CONFIG_EXYNOS_CONTENT_PATH_PROTECTION=y +CONFIG_EXYNOS5_SETUP_MIPIPHY=y +CONFIG_SAMSUNG_PRODUCT_SHIP=y + +# +# Flattened Device Tree based board for EXYNOS SoCs +# +# CONFIG_MACH_ESPRESSO7420 is not set +CONFIG_MACH_UNIVERSAL7420=y +# CONFIG_MACH_SMDK7580 is not set +# CONFIG_MACH_UNIVERSAL7580 is not set +CONFIG_EXYNOS_SPI_RESET_DURING_DSTOP=y +# CONFIG_MSM_HSIC_SYSMON is not set +# CONFIG_MSM_SUBSYSTEM_RESTART is not set +# CONFIG_MSM_SYSMON_COMM is not set +CONFIG_TIMA=y +CONFIG_TIMA_LKMAUTH=y +CONFIG_TIMA_RKP=y +CONFIG_RKP_DMAP_PROT=y +CONFIG_RKP_KDP=y + +# +# Bus support +# +CONFIG_ARM_AMBA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_SYSCALL=y +CONFIG_ARCH_SUPPORTS_MSI=y +CONFIG_PCI_MSI=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set + +# +# PCI host controller drivers +# +CONFIG_PCIE_DW=y +CONFIG_PCI_EXYNOS=y +# CONFIG_PCI_EXYNOS_TEST is not set +# CONFIG_PCI_EXYNOS_REDUCE_RESET_WAIT is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIEAER=y +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +CONFIG_PCIE_PME=y + +# +# Kernel Features +# +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +# CONFIG_SCHED_SMT is not set +CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y +CONFIG_SCHED_HMP=y +# CONFIG_SCHED_HMP_PRIO_FILTER is not set +CONFIG_HMP_FAST_CPU_MASK="4-7" +CONFIG_HMP_SLOW_CPU_MASK="0-3" +CONFIG_HMP_VARIABLE_SCALE=y +CONFIG_HMP_FREQUENCY_INVARIANT_SCALE=y +# CONFIG_SCHED_HMP_LITTLE_PACKING is not set +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_LOCAL_TIMERS=y +CONFIG_SWP_EMULATE=y +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +CONFIG_ARCH_NR_GPIO=1024 +CONFIG_HZ=100 +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_NO_BOOTMEM=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_ZONE_DMA_FLAG=0 +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CLEANCACHE is not set +CONFIG_FRONTSWAP=y +CONFIG_ZSWAP=y +CONFIG_ZPOOL=y +# CONFIG_ZBUD is not set +CONFIG_ZSMALLOC=y +CONFIG_PGTABLE_MAPPING=y +CONFIG_DIRECT_RECLAIM_FILE_PAGES_ONLY=y +CONFIG_INCREASE_MAXIMUM_SWAPPINESS=y +CONFIG_FIX_INACTIVE_RATIO=y +CONFIG_TIGHT_PGDAT_BALANCE=y +# CONFIG_SWAP_ENABLE_READAHEAD is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +CONFIG_MIN_DIRTY_THRESH_PAGES=2560 +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ARMV7_COMPAT=y +CONFIG_ARMV7_COMPAT_CPUINFO=y +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set + +# +# Boot options +# +CONFIG_CMDLINE="" +# CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_HAVE_AOUT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_KEYS_COMPAT=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_WAKELOCK=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=100 +CONFIG_PM_WAKELOCKS_GC=y +CONFIG_PM_RUNTIME=y +CONFIG_PM_RUNTIME_TEST_SYSFS=y +# CONFIG_PM_DOMAIN_DEBUG is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +CONFIG_PM_ADVANCED_DEBUG=y +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +CONFIG_ARCH_HAS_OPP=y +CONFIG_PM_OPP=y +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_RUNTIME=y +CONFIG_CPU_PM=y +CONFIG_SUSPEND_TIME=y + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_MODE_AUTO_CHANGE=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_GENERIC_CPUFREQ_CPU0 is not set + +# +# ARM CPU frequency scaling drivers +# +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_EXYNOS_CPUFREQ is not set +CONFIG_ARM_EXYNOS_MP_CPUFREQ=y +# CONFIG_ARM_EXYNOS_SMP_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4210_CPUFREQ is not set +# CONFIG_ARM_EXYNOS4X12_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5250_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5430_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5422_CPUFREQ is not set +# CONFIG_ARM_EXYNOS5433_CPUFREQ is not set +CONFIG_ARM_EXYNOS7420_CPUFREQ=y +# CONFIG_ARM_EXYNOS5440_CPUFREQ is not set +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_PMU_COREMEM_RATIO is not set + +# +# APM Driver +# +CONFIG_EXYNOS_APM=y +CONFIG_EXYNOS_MBOX=y + +# +# EXYNOS_CL_DVFS +# +CONFIG_EXYNOS_CL_DVFS_CPU=y +CONFIG_EXYNOS_CL_DVFS_G3D=y +CONFIG_EXYNOS_CL_DVFS_MIF=y +# CONFIG_EXYNOS_MBOX_DEFAULT_INTERRUPT is not set +CONFIG_EXYNOS_MBOX_DEFAULT_POLLING=y +# CONFIG_EXYNOS_MBOX_INTERRUPT is not set +CONFIG_EXYNOS_MBOX_POLLING=y +CONFIG_EXYNOS_APM_VOLTAGE_DEBUG=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM64_CPU_SUSPEND=y + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +CONFIG_OF_IDLE_STATES=y +CONFIG_CPU_IDLE_EXYNOS=y + +# +# ARM64 CPU Idle Drivers +# +# CONFIG_ARM64_CPUIDLE is not set +CONFIG_NET=y +CONFIG_COMPAT_NETLINK_MESSAGES=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +# CONFIG_UNIX_DIAG is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_NET_IPVTI is not set +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BIC=y +CONFIG_TCP_CONG_CUBIC=y +CONFIG_TCP_CONG_WESTWOOD=m +CONFIG_TCP_CONG_HTCP=m +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_BIC=y +# CONFIG_DEFAULT_CUBIC is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="bic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_SEC_LOCALE_CHN is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +# CONFIG_IPV6_GRE is not set +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_NETLABEL is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +CONFIG_NETWORK_SECMARK=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_NF_NAT_TFTP=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NETMAP=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +CONFIG_NETFILTER_XT_TARGET_REDIRECT=y +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +CONFIG_NETFILTER_XT_MATCH_ECN=y +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +CONFIG_NETFILTER_XT_MATCH_SCTP=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set +CONFIG_VPNCLIENT_SECURITY=y +CONFIG_VPNCLIENT_PROC_UID=1000 +CONFIG_VPNCLIENT_PROC_GID=1000 + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +# CONFIG_IP_NF_MATCH_RPFILTER is not set +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT_IPV4=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP6_NF_SECURITY is not set +CONFIG_NF_NAT_IPV6=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +# CONFIG_IP6_NF_TARGET_NPT is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +CONFIG_PHONET=y +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +CONFIG_NET_SCH_HTB=y +# CONFIG_NET_SCH_HFSC is not set +CONFIG_NET_SCH_PRIO=y +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +CONFIG_NET_SCH_INGRESS=y +# CONFIG_NET_SCH_PLUG is not set + +# +# Classification +# +CONFIG_NET_CLS=y +CONFIG_NET_CLS_BASIC=y +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_DNS_RESOLVER is not set +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_RMNET_DATA is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_NETPRIO_CGROUP is not set +CONFIG_BQL=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +# CONFIG_BT_RFCOMM is not set +# CONFIG_BT_BNEP is not set +# CONFIG_BT_HIDP is not set + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_UART_IN_AUDIO is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_BCM4358=y +# CONFIG_BT_BCM4359 is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_REG_DEBUG is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_WEXT=y +# CONFIG_LIB80211 is not set +CONFIG_CFG80211_ALLOW_RECONNECT=y +CONFIG_CFG80211_REG_NOT_UPDATED=y +# CONFIG_MAC80211 is not set +# CONFIG_WIMAX is not set +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +CONFIG_NFC=y +# CONFIG_NFC_NCI is not set +# CONFIG_NFC_HCI is not set + +# +# Near Field Communication (NFC) devices +# +# CONFIG_NFC_PN533 is not set +# CONFIG_SEC_NFC_I2C is not set +CONFIG_SEC_NFC=y +# CONFIG_SEC_NFC_PRODUCT_N3 is not set +CONFIG_SEC_NFC_PRODUCT_N5=y +# CONFIG_SEC_NFC_IF_UART is not set +CONFIG_SEC_NFC_IF_I2C=y +# CONFIG_SEC_NFC_IF_I2C_GPIO is not set +# CONFIG_SEC_NFC_CLK_REQ is not set +# CONFIG_SEC_NFC_MARGINTIME is not set +CONFIG_ESE_P3_LSI=y +# CONFIG_ESE_FACTORY_ONLY is not set +# CONFIG_NFC_PN547 is not set +# CONFIG_NFC_P61 is not set +CONFIG_SEC_NFC_LDO_CONTROL=y +# CONFIG_SEC_NFC_SENN3AB is not set +# CONFIG_NFC_DEBUG is not set +# CONFIG_NFC_EDC_TUNING is not set +# CONFIG_IPC_ROUTER is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +CONFIG_FW_LOADER_USER_HELPER=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_HAVE_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=0 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 + +# +# Bus devices +# +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y + +# +# Device Tree and Open Firmware support +# +CONFIG_PROC_DEVICETREE=y +# CONFIG_OF_SELFTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_DEVICE=y +CONFIG_OF_I2C=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set + +# +# Misc devices +# +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_ATMEL_PWM is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +CONFIG_KNOX_KAP=y +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_UID_STAT is not set +# CONFIG_BMP085_I2C is not set +# CONFIG_BMP085_SPI is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_CHECK_SIMSLOT_COUNT is not set +CONFIG_TIMA_LOG=y +# CONFIG_SEC_FPGA_ICE40XX is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set +CONFIG_MIPI_LLI=y +# CONFIG_MIPI_LLI_BOOT_SPI is not set +CONFIG_EXYNOS_MIPI_LLI=y +CONFIG_EXYNOS_MIPI_LLI_MPHY=y + +# +# Samsung Mobile Modem Driver (SVNET2) V1 for Memory-type Interface +# +CONFIG_SEC_MODEM_V1=y +# CONFIG_BOOT_DEVICE_SPI is not set +CONFIG_LINK_DEVICE_SPI=y +CONFIG_LINK_DEVICE_MEMORY=y +CONFIG_LINK_POWER_MANAGEMENT=y +CONFIG_LINK_POWER_MANAGEMENT_WITH_FSM=y +# CONFIG_LINK_CONTROL_MSG_IOSM is not set +CONFIG_LINK_CONTROL_MSG_COMMAND=y +CONFIG_LINK_DEVICE_WITH_SBD_ARCH=y +# CONFIG_LINK_DEVICE_NAPI is not set +# CONFIG_SEC_MODEM_DEBUG is not set +# CONFIG_LINK_DEVICE_C2C is not set +CONFIG_LINK_DEVICE_LLI=y +# CONFIG_LINK_DEVICE_SHMEM is not set +# CONFIG_LINK_DEVICE_HSIC is not set +# CONFIG_LTE_MODEM_XMM7260 is not set +# CONFIG_UMTS_MODEM_SS222 is not set +# CONFIG_UMTS_MODEM_SH222AP is not set +# CONFIG_UMTS_MODEM_SS300 is not set +CONFIG_UMTS_MODEM_SS333=y +# CONFIG_SEC_MODEM_XMM7260_CAT6 is not set +# CONFIG_FM_RADIO is not set + +# +# NOTIFIER configs +# +CONFIG_VBUS_NOTIFIER=y + +# +# MUIC configs +# +CONFIG_USE_MUIC=y +CONFIG_USE_SAFEOUT=y +CONFIG_MUIC_NOTIFIER=y +# CONFIG_SAMSUNG_MUIC is not set +CONFIG_MUIC_ADCMODE_SWITCH_WA=y +CONFIG_MUIC_RUSTPROOF_ON_USER=y +# CONFIG_MUIC_FSA9480 is not set +CONFIG_MUIC_MAX77843=y +CONFIG_HV_MUIC_MAX77843_AFC=y +CONFIG_MUIC_MAX77843_IGNORE_ADCERR_WA=y +CONFIG_MUIC_MAX77843_RESET_WA=y +CONFIG_MUIC_MAX77833=y +CONFIG_HV_MUIC_MAX77833_AFC=y +CONFIG_MUIC_MAX77833_SHAKEID_WA=y +# CONFIG_MUIC_S2MM001 is not set +# CONFIG_MUIC_HV_FORCE_LIMIT is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_FMP=y +CONFIG_UFS_FMP_DM_CRYPT=y +CONFIG_UFS_FMP_ECRYPT_FS=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +CONFIG_SCSI_UFSHCD=y +CONFIG_UFS_DYNAMIC_H8=y +# CONFIG_SCSI_UFSHCD_PCI is not set +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_EXYNOS=y +CONFIG_FIPS_FMP_UFS=y +CONFIG_UFS_BKOPS_NODE_UID=1000 +CONFIG_UFS_BKOPS_NODE_GID=1001 +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_FCOE is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_LPFC is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_SRP is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +CONFIG_DM_VERITY=y +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_I2O is not set +CONFIG_NETDEVICES=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +CONFIG_MII=y +# CONFIG_IFB is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set +# CONFIG_ARCNET is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_3COM=y +# CONFIG_TYPHOON is not set +CONFIG_NET_VENDOR_ADAPTEC=y +# CONFIG_ADAPTEC_STARFIRE is not set +CONFIG_NET_VENDOR_ALTEON=y +# CONFIG_ACENIC is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +CONFIG_NET_VENDOR_ATHEROS=y +# CONFIG_ATL2 is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL1C is not set +# CONFIG_ALX is not set +CONFIG_NET_CADENCE=y +# CONFIG_ARM_AT91_ETHER is not set +# CONFIG_MACB is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +# CONFIG_TIGON3 is not set +# CONFIG_BNX2X is not set +CONFIG_NET_VENDOR_BROCADE=y +# CONFIG_BNA is not set +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_VENDOR_CHELSIO=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +CONFIG_NET_VENDOR_CISCO=y +# CONFIG_ENIC is not set +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_DEC=y +# CONFIG_NET_TULIP is not set +CONFIG_NET_VENDOR_DLINK=y +# CONFIG_DL2K is not set +# CONFIG_SUNDANCE is not set +CONFIG_NET_VENDOR_EMULEX=y +# CONFIG_BE2NET is not set +CONFIG_NET_VENDOR_EXAR=y +# CONFIG_S2IO is not set +# CONFIG_VXGE is not set +CONFIG_NET_VENDOR_HP=y +# CONFIG_HP100 is not set +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +CONFIG_NET_VENDOR_I825XX=y +# CONFIG_IP1000 is not set +# CONFIG_JME is not set +CONFIG_NET_VENDOR_MARVELL=y +# CONFIG_MVMDIO is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +CONFIG_NET_VENDOR_MELLANOX=y +# CONFIG_MLX4_EN is not set +# CONFIG_MLX4_CORE is not set +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_ENC28J60 is not set +CONFIG_NET_VENDOR_MYRI=y +# CONFIG_MYRI10GE is not set +# CONFIG_FEALNX is not set +CONFIG_NET_VENDOR_NATSEMI=y +# CONFIG_NATSEMI is not set +# CONFIG_NS83820 is not set +CONFIG_NET_VENDOR_8390=y +# CONFIG_NE2K_PCI is not set +CONFIG_NET_VENDOR_NVIDIA=y +# CONFIG_FORCEDETH is not set +CONFIG_NET_VENDOR_OKI=y +# CONFIG_PCH_GBE is not set +# CONFIG_ETHOC is not set +CONFIG_NET_PACKET_ENGINE=y +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_NET_VENDOR_QLOGIC=y +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_NETXEN_NIC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set +CONFIG_NET_VENDOR_RDC=y +# CONFIG_R6040 is not set +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +# CONFIG_SC92031 is not set +CONFIG_NET_VENDOR_SIS=y +# CONFIG_SIS900 is not set +# CONFIG_SIS190 is not set +# CONFIG_SFC is not set +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_SMC91X is not set +# CONFIG_EPIC100 is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_SUN=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NIU is not set +CONFIG_NET_VENDOR_TEHUTI=y +# CONFIG_TEHUTI is not set +CONFIG_NET_VENDOR_TI=y +# CONFIG_TLAN is not set +CONFIG_NET_VENDOR_VIA=y +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_AT803X_PHY is not set +# CONFIG_AMD_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +CONFIG_USB_USBNET=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_CDCETHER=y +# CONFIG_USB_NET_CDC_EEM is not set +CONFIG_USB_NET_CDC_NCM=y +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_DM9601 is not set +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +# CONFIG_USB_NET_GL620A is not set +CONFIG_USB_NET_NET1080=y +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +CONFIG_USB_NET_CDC_SUBSET=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_BELKIN=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_KC2190 is not set +CONFIG_USB_NET_ZAURUS=y +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_CDC_PHONET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +CONFIG_WLAN=y +# CONFIG_ATMEL is not set +# CONFIG_PRISM54 is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +CONFIG_WIFI_CONTROL_FUNC=y +# CONFIG_ATH_CARDS is not set +CONFIG_BROADCOM_WIFI=y +# CONFIG_BCM4330 is not set +# CONFIG_BCM4343 is not set +# CONFIG_BCM4334 is not set +# CONFIG_BCM4335 is not set +# CONFIG_BCM4339 is not set +# CONFIG_BCM4354 is not set +CONFIG_BCM4358=y +# CONFIG_BCM4359 is not set +# CONFIG_BCM43241 is not set +# CONFIG_BCM4334W is not set +# CONFIG_BCM43455 is not set +CONFIG_BCMDHD_FW_PATH="/system/etc/wifi/bcmdhd_sta.bin" +CONFIG_BCMDHD_NVRAM_PATH="/system/etc/wifi/nvram_net.txt" +CONFIG_BROADCOM_WIFI_RESERVED_MEM=y +# CONFIG_BCMDHD_PREALLOC_PKTIDMAP is not set +CONFIG_WLAN_REGION_CODE=100 +CONFIG_WLAIBSS=y +CONFIG_WL_RELMCAST=y +CONFIG_BCMDHD_PCIE=y +# CONFIG_BCM4358_A3 is not set +# CONFIG_WL_NAN is not set +# CONFIG_BCMDHD_DEBUG_PAGEALLOC is not set +# CONFIG_BRCMFMAC is not set +# CONFIG_HOSTAP is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_LIBERTAS is not set +# CONFIG_HERMES is not set +# CONFIG_WL_TI is not set +# CONFIG_MWIFIEX is not set +# CONFIG_LGUIWLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_VMXNET3 is not set +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_KEYRESET is not set +CONFIG_GLOVE_TOUCH=y +CONFIG_HALL=y +# CONFIG_HALL_LOOPCHECK_WA is not set +CONFIG_CERTIFY_HALL=y +# CONFIG_CERTIFY_HALL_NFC_WA is not set +# CONFIG_INPUT_EXPANDED_ABS is not set +# CONFIG_INPUT_KEYCOMBO is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ABOV_TOUCH is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_20075 is not set +# CONFIG_KEYBOARD_CYPRESS_TOUCH_MBR31X5 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_MXT540E is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX2 is not set +CONFIG_TOUCHSCREEN_FTS=y +# CONFIG_TOUCHSCREEN_FTS5AD56 is not set +# CONFIG_INPUT_WACOM is not set +# CONFIG_EPEN_WACOM_G5SP is not set +# CONFIG_EPEN_WACOM_G9PM is not set +# CONFIG_EPEN_WACOM_G9PL is not set +# CONFIG_EPEN_WACOM_G9PLL is not set +# CONFIG_EPEN_WACOM_G10PM is not set +# CONFIG_EPEN_WACOM_W9012 is not set +# CONFIG_EPEN_WACOM_W9014 is not set +# CONFIG_WACOM_LCD_FREQ_COMPENSATE is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ARIZONA_HAPTICS is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYCHORD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_GPIO is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +CONFIG_INPUT_BOOSTER=y + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set + +# +# Diag Support +# +# CONFIG_DIAG_CHAR is not set + +# +# DIAG traffic over USB +# +# CONFIG_DIAG_OVER_USB is not set + +# +# HSIC/SMUX support for DIAG +# + +# +# Debug support for DIAG +# +# CONFIG_DIAG_MODE is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_SAMSUNG=y +# CONFIG_SERIAL_SAMSUNG_DMA is not set +CONFIG_SERIAL_SAMSUNG_UARTS=6 +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_MFD_HSU is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +CONFIG_HW_RANDOM_EXYNOS_SWD=y +CONFIG_EXYRNG_FIPS_COMPLIANCE=y +# CONFIG_EXYRNG_FAIL_POLICY_DISABLE is not set +CONFIG_EXYRNG_FAIL_POLICY_RESET=y +CONFIG_EXYRNG_USE_CRYPTOMANAGER=y +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# PCMCIA character devices +# +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +CONFIG_DEVPORT=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_EG20T is not set +CONFIG_I2C_EXYNOS5=y +CONFIG_I2C_GPIO=y +# CONFIG_I2C_INTEL_MID is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +CONFIG_HAVE_S3C2410_I2C=y +# CONFIG_I2C_S3C2410 is not set +CONFIG_HAVE_EXYNOS5_HSI2C=y +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +CONFIG_SPI_S3C64XX=y +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set +CONFIG_SENSORS_FP_SPI_NUMBER=4 + +# +# Qualcomm MSM SSBI bus support +# +# CONFIG_SSBI is not set +# CONFIG_HSI is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +# CONFIG_PTP_1588_CLOCK_PCH is not set +CONFIG_PINCTRL=y + +# +# Pin controllers +# +CONFIG_PINMUX=y +CONFIG_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_SINGLE is not set +CONFIG_PINCTRL_SAMSUNG=y +CONFIG_PINCTRL_EXYNOS=y +# CONFIG_PINCTRL_EXYNOS5440 is not set +CONFIG_SEC_GPIO_DVS=y +CONFIG_MST_SECURE_GPIO=y +CONFIG_SENSORS_FP_SPI_GPIO="gpv7" +CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y +CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIO_DEVRES=y +CONFIG_GPIOLIB=y +CONFIG_OF_GPIO=y +CONFIG_DEBUG_GPIO=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_GRGPIO is not set + +# +# I2C GPIO expanders: +# +CONFIG_GPIO_ARIZONA=y +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_RDC321X is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# + +# +# USB GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_BQ27x00 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_ANDROID is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24160 is not set +# CONFIG_FUELGAUGE_S2MG001 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GOLDFISH is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_VEXPRESS is not set +# CONFIG_POWER_AVS is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_SENSORS_SEC_THERMISTOR=y +CONFIG_THERMAL=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_USER_SPACE is not set +CONFIG_CPU_THERMAL=y +# CONFIG_GPU_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +CONFIG_EXYNOS_THERMAL=y +# CONFIG_EXYNOS_SWTRIP is not set +CONFIG_CPU_THERMAL_IPA=y +CONFIG_CPU_THERMAL_IPA_CONTROL=y +# CONFIG_CPU_THERMAL_IPA_DEBUG is not set + +# +# Samsung thermal drivers +# +# CONFIG_EXYNOS_THERMAL_CORE is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +CONFIG_HAVE_S3C2410_WATCHDOG=y +CONFIG_S3C2410_WATCHDOG=y +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_AS3711 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77804 is not set +# CONFIG_MFD_MAX77804K is not set +# CONFIG_MFD_MAX77823 is not set +# CONFIG_MFD_MAX77828 is not set +CONFIG_MFD_MAX77843=y +CONFIG_MFD_MAX77833=y +# CONFIG_MFD_MAX77888 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_MFD_SEC_CORE=y +# CONFIG_MFD_S2MU003 is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_VX855 is not set +CONFIG_MFD_ARIZONA=y +CONFIG_MFD_ARIZONA_DEFERRED_RESUME=y +# CONFIG_MFD_ARIZONA_I2C is not set +CONFIG_MFD_ARIZONA_SPI=y +# CONFIG_MFD_WM5102 is not set +CONFIG_MFD_FLORIDA=y +# CONFIG_MFD_VEGAS is not set +# CONFIG_MFD_WM8997 is not set +CONFIG_MFD_CLEARWATER=y +# CONFIG_MFD_LARGO is not set +# CONFIG_MFD_MARLEY is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +CONFIG_MFD_S2MPB02=y +# CONFIG_VEXPRESS_CONFIG is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_AD5398 is not set +CONFIG_REGULATOR_ARIZONA=y +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +CONFIG_REGULATOR_MAX77838=y +CONFIG_REGULATOR_MAX77843=y +CONFIG_REGULATOR_MAX77833=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_S2MPS11 is not set +# CONFIG_REGULATOR_S2MPS13 is not set +CONFIG_REGULATOR_S2MPS15=y +# CONFIG_REGULATOR_S2MPU03 is not set +CONFIG_REGULATOR_S2MPB01=y +# CONFIG_REGULATOR_S5M8767 is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_NCP6335B is not set +CONFIG_REGULATOR_S2MPB02=y +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +CONFIG_MEDIA_M2M1SHOT=y +# CONFIG_MEDIA_M2M1SHOT_TESTDEV is not set +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=y +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_V4L2_MEM2MEM_DEV=y +CONFIG_VIDEOBUF2_CORE=y +CONFIG_VIDEOBUF2_MEMOPS=y +CONFIG_VIDEOBUF2_ION=y +# CONFIG_VIDEO_V4L2_INT_DEVICE is not set +# CONFIG_TTPCI_EEPROM is not set + +# +# Media drivers +# +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +CONFIG_V4L_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CAFE_CCIC is not set +CONFIG_VIDEO_EXYNOS=y +CONFIG_EXYNOS_MEDIA_DEVICE=y +# CONFIG_VIDEO_EXYNOS_GSCALER_1_3 is not set +# CONFIG_VIDEO_EXYNOS_GSCALER is not set +CONFIG_VIDEO_EXYNOS_MFC=y +# CONFIG_EXYNOS_MFC_V6 is not set +# CONFIG_EXYNOS_MFC_V8 is not set +CONFIG_EXYNOS_MFC_V9=y +# CONFIG_VIDEO_EXYNOS_HEVC is not set +CONFIG_VIDEO_EXYNOS_FIMC_IS=y +CONFIG_USE_VENDER_FEATURE=y +CONFIG_ENABLE_HAL3_2_META_INTERFACE=y +# CONFIG_TORCH_CURRENT_CHANGE_SUPPORT is not set +# CONFIG_MODULE_ALL_INCLUDE is not set +# CONFIG_CAMERA_SENSOR_8B1 is not set +# CONFIG_CAMERA_SENSOR_6D1 is not set +# CONFIG_CAMERA_SENSOR_8B1_OBJ is not set +# CONFIG_CAMERA_SENSOR_6D1_OBJ is not set +# CONFIG_CAMERA_SENSOR_6B2_OBJ is not set +# CONFIG_CAMERA_SENSOR_6A3_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX135_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX134_OBJ is not set +# CONFIG_CAMERA_SENSOR_3L2_OBJ is not set +CONFIG_CAMERA_SENSOR_2P2_OBJ=y +# CONFIG_CAMERA_SENSOR_2P2_12M_OBJ is not set +# CONFIG_CAMERA_SENSOR_2T2_OBJ is not set +# CONFIG_CAMERA_SENSOR_2P3_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H5_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H7_OBJ is not set +# CONFIG_CAMERA_SENSOR_3H7_SUNNY_OBJ is not set +# CONFIG_CAMERA_SENSOR_4E5_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX175_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX219_OBJ is not set +# CONFIG_CAMERA_SENSOR_IMX228_OBJ is not set +CONFIG_CAMERA_SENSOR_IMX240_OBJ=y +# CONFIG_CAMERA_SENSOR_4H5_OBJ is not set +# CONFIG_CAMERA_SENSOR_SR261_OBJ is not set +CONFIG_CAMERA_SENSOR_4E6_OBJ=y +CONFIG_CAMERA_SENSOR_4E6_C2_OBJ=y +# CONFIG_CSI_V3_2 is not set +CONFIG_CSI_V3_4=y +CONFIG_FIMC_IS_V4_0_0=y +# CONFIG_CAMERA_EEPROM_SUPPORT_REAR is not set +CONFIG_CAMERA_EEPROM_SUPPORT_FRONT=y +CONFIG_COMPANION_USE=y +# CONFIG_COMPANION_C1_USE is not set +CONFIG_COMPANION_C2_USE=y +CONFIG_COMPANION_DCDC_USE=y +CONFIG_COMPANION_STANDBY_USE=y +CONFIG_OIS_USE=y +CONFIG_OIS_FW_UPDATE_THREAD_USE=y +CONFIG_AF_HOST_CONTROL=y +CONFIG_CAMERA_ZERO=y +# CONFIG_CAMERA_MARINE is not set +# CONFIG_CAMERA_VLTE is not set +# CONFIG_CAMERA_NOBLE is not set +# CONFIG_CAMERA_ZENLTE is not set +CONFIG_VIDEO_EXYNOS_SCALER=y +# CONFIG_SCALER_NO_SOFTRST is not set +CONFIG_VIDEO_EXYNOS_FIMG2D=y +CONFIG_FIMG2D_CCI_SNOOP=y +# CONFIG_VIDEO_EXYNOS_JPEG is not set +# CONFIG_VIDEO_EXYNOS_HX_JPEG is not set +# CONFIG_VIDEO_EXYNOS_TV is not set +# CONFIG_VIDEO_EXYNOS_HDMI is not set +CONFIG_MEDIA_EXYNOS_JPEG=y +CONFIG_MEDIA_EXYNOS=y +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS is not set +# CONFIG_VIDEO_SAMSUNG_S5P_TV is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set + +# +# Supported MMC/SDIO adapters +# +# CONFIG_CYPRESS_FIRMWARE is not set + +# +# Media ancillary drivers (tuners, sensors, i2c, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y + +# +# Audio decoders, processors and mixers +# + +# +# RDS decoders +# + +# +# Video decoders +# + +# +# Video and audio decoders +# + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Miscelaneous helper chips +# + +# +# Sensors used on soc_camera driver +# + +# +# Tools to develop new frontends +# +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_TDMB is not set +# CONFIG_ISDBT is not set +# CONFIG_ISDBT_F_TYPE_ANTENNA is not set + +# +# Graphics support +# +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +# CONFIG_DRM is not set + +# +# ARM GPU Configuration +# +# CONFIG_MALI_T6XX is not set +# CONFIG_MALI_GATOR_SUPPORT is not set +CONFIG_MALI_EXYNOS_TRACE=y +# CONFIG_MALI_FULL_TRACE is not set +CONFIG_MALI_EXPERT=y +# CONFIG_MALI_DEBUG_SHADER_SPLIT_FS is not set +# CONFIG_MALI_PLATFORM_FAKE is not set +CONFIG_MALI_PLATFORM_THIRDPARTY=y +CONFIG_MALI_PLATFORM_THIRDPARTY_NAME="7420" +# CONFIG_MALI_DEBUG is not set +# CONFIG_MALI_NO_MALI is not set +# CONFIG_MALI_TRACE_TIMELINE is not set +# CONFIG_MALI_SYSTEM_TRACE is not set +# CONFIG_MALI_GPU_TRACEPOINTS is not set +# CONFIG_MALI_MIDGARD is not set +# CONFIG_MALI_MIDGARD_WK04 is not set +CONFIG_MALI_DVFS=y +CONFIG_MALI_T7XX=y +CONFIG_MALI_R5P0=y +CONFIG_MALI_RT_PM=y +CONFIG_MALI_ENABLE_TRACE=y +CONFIG_MALI_DEBUG_SYS=y +CONFIG_MALI_SEC_HWCNT=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_TMIO is not set +# CONFIG_DECON is not set +CONFIG_USE_VSYNC_SKIP=y +CONFIG_DECON_MIPI_DSI_PKTGO=y +# CONFIG_FB_S3C is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +CONFIG_S5P_LCD_INIT=y +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_AUO_K190X is not set +CONFIG_FB_SIMPLE=y +CONFIG_EXYNOS_VIDEO=y +CONFIG_EXYNOS_MIPI_DSI=y +# CONFIG_EXYNOS_LCD_S6E8AX0 is not set +# CONFIG_EXYNOS_DP is not set +# CONFIG_EXYNOS_DECON_DISPLAY is not set +CONFIG_FB_WINDOW_UPDATE=y +# CONFIG_EXYNOS_DECON_TV_DISPLAY is not set +CONFIG_EXYNOS_DECON=y +CONFIG_EXYNOS_DECON_FB=y +# CONFIG_EXYNOS_DECON_MDNIE is not set +CONFIG_DECON_LPD_DISPLAY=y +CONFIG_DECON_BLOCKING_MODE=y +CONFIG_DECON_EVENT_LOG=y +CONFIG_EXYNOS_VPP=y +CONFIG_EXYNOS_DECON_LCD=y +CONFIG_EXYNOS_DECON_MDNIE_LITE=y +CONFIG_EXYNOS_DECON_LCD_SYSFS=y +CONFIG_EXYNOS_DECON_LCD_MCD=y +CONFIG_LCD_HMT=y +CONFIG_LCD_ALPM=y +CONFIG_LCD_HBM_INTERPOLATION=y +CONFIG_PANEL_AID_DIMMING=y +# CONFIG_EXYNOS_DECON_LCD_S6E3HA0 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HA2K is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HF2 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3HF2_WQHD is not set +CONFIG_PANEL_S6E3HF2_DYNAMIC=y +# CONFIG_PANEL_S6E3HA2_DYNAMIC is not set +# CONFIG_PANEL_S6E3HA3_DYNAMIC is not set +# CONFIG_PANEL_S6E3HF3_DYNAMIC is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3FA0 is not set +# CONFIG_EXYNOS_DECON_LCD_S6E3FA2 is not set +# CONFIG_EXYNOS_DUAL_DECON is not set +# CONFIG_PANEL_S6E3FA3 is not set + +# +# Mhl device support +# +# CONFIG_SEC_MHL_SUPPORT is not set +# CONFIG_SEC_MHL_HDCP is not set +# CONFIG_SEC_MHL_EDID is not set +# CONFIG_SAMSUNG_MHL_8240 is not set +# CONFIG_SEC_MHL_SII8620 is not set +# CONFIG_MEDIA_DATA_TUNNEL_SUPPORT is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_HX8357 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_ADF is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_LOGO is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_RAWMIDI=y +CONFIG_SND_COMPRESS_OFFLOAD=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_PCI=y +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_SND_SAMSUNG_I2S=y +CONFIG_SND_SAMSUNG_AUDSS=y +CONFIG_SND_SAMSUNG_IOMMU=y +# CONFIG_SND_SAMSUNG_FAKEDMA is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994 is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF is not set +# CONFIG_SND_SOC_SMDK_WM8994_PCM is not set +# CONFIG_SND_SOC_SAMSUNG_ESPRESSO7420_WM5110 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL7420_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_ESPRESSO5433_WM5110 is not set +# CONFIG_SND_SOC_SAMSUNG_XYREF5430_ES515 is not set +# CONFIG_SND_SOC_SAMSUNG_XYREF5422_ES515 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_FLORIDA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_ARIZONA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_FLORIDA is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_ARIZONA is not set +CONFIG_SND_SOC_SAMSUNG_ZERO_FLORIDA=y +CONFIG_SND_SOC_SAMSUNG_ZERO_CLEARWATER=y +CONFIG_SND_SOC_SAMSUNG_ARIZONA=y +# CONFIG_SND_SOC_SAMSUNG_ZERO_HDMI is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5430_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5433_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL5422_DUMMY is not set +# CONFIG_SND_SOC_SAMSUNG_SMDK5422_WM8994 is not set +# CONFIG_SND_SOC_SAMSUNG_UNIVERSAL7580_COD3022X is not set +# CONFIG_SND_SAMSUNG_AUX_HDMI is not set +# CONFIG_SND_SAMSUNG_AUX_SPDIF is not set +CONFIG_SND_SAMSUNG_SEIREN=y +# CONFIG_SND_SAMSUNG_SEIREN_OFFLOAD is not set +# CONFIG_SND_SAMSUNG_SEIREN_DEBUG is not set +# CONFIG_SND_SAMSUNG_DEBUGFS is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_ARIZONA=y +CONFIG_SND_SOC_WM_ADSP=y +# CONFIG_SND_SOC_MAX98504 is not set +CONFIG_SND_SOC_MAX98504A=y +# CONFIG_SND_SOC_MAXIM_DSM_A is not set +CONFIG_SND_SOC_MAXIM_DSM=y +CONFIG_SND_SOC_MAXIM_DSM_CAL=y +CONFIG_SND_SOC_MAX98505=y +# CONFIG_SND_SOC_MAX98505A is not set +CONFIG_SND_SOC_FLORIDA=y +CONFIG_SND_SOC_CLEARWATER=y +CONFIG_SND_SOC_DUMMY_CODEC=y + +# +# Audience earSmart codecs +# +CONFIG_SND_SOC_ES705=y +# CONFIG_SND_SOC_ES704 is not set +# CONFIG_SND_SOC_ES804 is not set +CONFIG_SND_SOC_ES_I2C=y +# CONFIG_SND_SOC_ESXXX_UART_FW_DOWNLOAD is not set +# CONFIG_SND_SOC_ESXXX_UART_WAKEUP is not set +# CONFIG_SND_SOC_3MIC_SUPPORT is not set +# CONFIG_SND_SOC_VEQ_SUPPORT is not set +# CONFIG_SND_SOC_ESXXX_SEAMLESS_VOICE_WAKEUP is not set +# CONFIG_SND_SOC_ESXXX_RESTORE_STD_FW is not set +# CONFIG_SND_SOC_ESXXX_VEQ_FILTER is not set +# CONFIG_SND_SOC_ESXXX_VEQ_EXTENDEDVOLUME is not set +# CONFIG_SND_SOC_ESXXX_UPDATE_VEQ_TABLE is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SOUND_PRIME is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +# CONFIG_HID_ACRUX_FF is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +# CONFIG_DRAGONRISE_FF is not set +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +# CONFIG_HID_HOLTEK is not set +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +# CONFIG_HID_LENOVO_TPKBD is not set +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +# CONFIG_PANTHERLORD_FF is not set +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +# CONFIG_HID_PICOLCD_FB is not set +# CONFIG_HID_PICOLCD_BACKLIGHT is not set +# CONFIG_HID_PICOLCD_LCD is not set +# CONFIG_HID_PICOLCD_LEDS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PS3REMOTE is not set +CONFIG_HID_ROCCAT=y +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +# CONFIG_GREENASIA_FF is not set +CONFIG_HID_SMARTJOYPLUS=y +# CONFIG_SMARTJOYPLUS_FF is not set +CONFIG_HID_SYNAPTICS_BT=y +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +CONFIG_HID_THRUSTMASTER=y +# CONFIG_THRUSTMASTER_FF is not set +CONFIG_HID_WACOM=y +# CONFIG_HID_WIIMOTE is not set +CONFIG_HID_ZAGG=y +CONFIG_HID_ZEROPLUS=y +# CONFIG_ZEROPLUS_FF is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set +CONFIG_HID_OVR=y + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB_ARCH_HAS_XHCI=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=y +# CONFIG_USB_XHCI_HCD_DEBUGGING is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_RENESAS_USBHS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB Notify features +# +CONFIG_USB_HOST_NOTIFY=y +CONFIG_USB_NOTIFY_LAYER=y +CONFIG_USB_NOTIFIER=y +CONFIG_USB_DEBUG_DETAILED_LOG=y +CONFIG_USB_STORAGE_DETECT=y +CONFIG_USB_HMT_SAMSUNG_INPUT=y + +# +# USB DesignWare features +# +CONFIG_USB_DWC3=y +# CONFIG_USB_DWC3_HOST is not set +# CONFIG_USB_DWC3_GADGET is not set +CONFIG_USB_DWC3_DUAL_ROLE=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_EXYNOS=y +CONFIG_USB_DWC3_PCI=y + +# +# Debugging features +# +# CONFIG_USB_DWC3_DEBUG is not set +# CONFIG_USB_CHIPIDEA is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=y +# CONFIG_USB_SERIAL_CONSOLE is not set +# CONFIG_USB_SERIAL_GENERIC is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_FUNSOFT is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MOTOROLA is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=y +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_HP4X is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIEMENS_MPI is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_ZIO is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_ZTE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_CSVT is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_QCOM_DIAG_BRIDGE is not set +# CONFIG_USB_QCOM_MDM_BRIDGE is not set +# CONFIG_USB_QCOM_KS_BRIDGE is not set +# CONFIG_USB_QCOM_IPC_BRIDGE is not set +CONFIG_USB_PHY=y +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_OMAP_CONTROL_USB is not set +# CONFIG_OMAP_USB3 is not set +CONFIG_SAMSUNG_USBPHY=y +# CONFIG_SAMSUNG_USB2PHY is not set +# CONFIG_SAMSUNG_DWC_USB2PHY is not set +CONFIG_SAMSUNG_USB2PHY_DUMMY=y +CONFIG_SAMSUNG_USB3PHY=y +CONFIG_SAMSUNG_USB3PHY_CAL=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_ULPI is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_S3C_OTGD is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_AMD5536UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_DUMMY_HCD is not set +CONFIG_USB_LIBCOMPOSITE=y +CONFIG_USB_F_ACM=y +CONFIG_USB_U_SERIAL=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +CONFIG_USB_ANDROID_SAMSUNG_COMPOSITE=y +CONFIG_USB_ANDROID_SAMSUNG_MTP=y +CONFIG_USB_LOCK_SUPPORT_FOR_MDM=y +CONFIG_USB_DUN_SUPPORT=y +CONFIG_USB_NCM_SUPPORT_MTU_CHANGE=y +CONFIG_USB_RNDIS_MULTIPACKET=y +CONFIG_USBIRQ_BALANCING_LTE_HIGHTP=y +# CONFIG_USB_RNDIS_VZW_REQ is not set +# CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_UWB is not set +# CONFIG_MMC is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA9633 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_RENESAS_TPU is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_MAX77833_RGB=y +CONFIG_LEDS_MAX77843_RGB=y +CONFIG_LEDS_S2MPB02=y +CONFIG_LEDS_KTD2692=y + +# +# LED Triggers +# +# CONFIG_LEDS_TRIGGERS is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +CONFIG_SWITCH_ANTENNA=y +CONFIG_SWITCH_ANTENNA_IF=y +# CONFIG_SWITCH_ANTENNA_EARJACK is not set +# CONFIG_SWITCH_ANTENNA_EARJACK_IF is not set +CONFIG_SWITCH_ARIZONA=y +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_RX4581 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_DS2404 is not set + +# +# on-CPU RTC drivers +# +CONFIG_HAVE_S3C_RTC=y +# CONFIG_RTC_DRV_S3C is not set +# CONFIG_EXYNOS_PERSISTENT_CLOCK is not set +CONFIG_RTC_DRV_SEC=y +# CONFIG_RTC_ALARM_BOOT is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_SNVS is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_ESOC is not set +# CONFIG_MHI is not set +CONFIG_MHI_RMNET_DUMP=y +# CONFIG_DEBUG_PKTLOG is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +# CONFIG_AMBA_PL08X is not set +# CONFIG_DW_DMAC is not set +# CONFIG_TIMB_DMA is not set +CONFIG_PL330_DMA=y +# CONFIG_PL330TEST_LOG is not set +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set + +# +# Virtio drivers +# +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTIO_MMIO is not set + +# +# Microsoft Hyper-V guest support +# +CONFIG_STAGING=y +# CONFIG_ET131X is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_PRISM2_USB is not set +# CONFIG_ECHO is not set +# CONFIG_COMEDI is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8187SE is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTLLIB is not set +# CONFIG_R8712U is not set +# CONFIG_RTS5139 is not set +# CONFIG_TRANZPORT is not set +# CONFIG_LINE6_USB is not set +# CONFIG_USB_SERIAL_QUATECH2 is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_DX_SEP is not set + +# +# IIO staging drivers +# + +# +# Accelerometers +# +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16204 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16220 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_SCA3000 is not set + +# +# Analog to digital converters +# +# CONFIG_AD7291 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD799X is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7280 is not set + +# +# Analog digital bi-direction converters +# +# CONFIG_ADT7316 is not set + +# +# Capacitance to digital converters +# +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7746 is not set + +# +# Direct Digital Synthesis +# +# CONFIG_AD5930 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_AD9850 is not set +# CONFIG_AD9852 is not set +# CONFIG_AD9910 is not set +# CONFIG_AD9951 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16060 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16260 is not set + +# +# Network Analyzer, Impedance Converters +# +# CONFIG_AD5933 is not set + +# +# Light sensors +# +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2x7x is not set + +# +# Magnetometer sensors +# +# CONFIG_SENSORS_HMC5843 is not set + +# +# Active energy metering IC +# +# CONFIG_ADE7753 is not set +# CONFIG_ADE7754 is not set +# CONFIG_ADE7758 is not set +# CONFIG_ADE7759 is not set +# CONFIG_ADE7854 is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set + +# +# Triggers - standalone +# +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_GPIO_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_ZRAM is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_CRYSTALHD is not set +# CONFIG_FB_XGI is not set +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_SPEAKUP is not set +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set +# CONFIG_STAGING_MEDIA is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_TIMED_OUTPUT=y +# CONFIG_ANDROID_TIMED_GPIO is not set +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES=y +CONFIG_ANDROID_INTF_ALARM_DEV=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y +# CONFIG_SW_SYNC_USER is not set +CONFIG_SEC_OOM_KILLER=y +CONFIG_ION=y +CONFIG_ION_TEST=y +CONFIG_ION_EXYNOS=y +CONFIG_ION_EXYNOS_STAT_LOG=y +CONFIG_ION_EXYNOS_OF=y +# CONFIG_FIQ_DEBUGGER is not set +# CONFIG_FIQ_WATCHDOG is not set +# CONFIG_USB_WPAN_HCD is not set +# CONFIG_WIMAX_GDM72XX is not set +CONFIG_NET_VENDOR_SILICOM=y +# CONFIG_SBYPASS is not set +# CONFIG_BPCTL is not set +# CONFIG_CED1401 is not set +# CONFIG_DGRP is not set + +# +# Samsung TN Features +# +CONFIG_SEC_EXT=y +CONFIG_SEC_SYSFS=y +CONFIG_SEC_REBOOT=y +CONFIG_SEC_MISC=y +CONFIG_ARGOS=y +CONFIG_SEC_SLOW_MODE=y +CONFIG_SEC_DEBUG=y + +# +# BSP Feature +# +CONFIG_SEC_BSP=y + +# +# Samsung TN logging feature +# +CONFIG_SEC_AVC_LOG=y +CONFIG_SEC_DEBUG_TSP_LOG=y +CONFIG_SEC_DEBUG_LAST_KMSG=y +CONFIG_SEC_DEBUG_TIMA_LOG=y +# CONFIG_SEC_DEBUG_MDM_SEPERATE_CRASH is not set + +# +# Samsung TN Power Management Options +# +CONFIG_SEC_PM=y +CONFIG_SEC_PM_DEBUG=y +CONFIG_USER_RESET_DEBUG=y +CONFIG_VNSWAP=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +# CONFIG_COMMON_CLK_DEBUG is not set +# CONFIG_COMMON_CLK_VERSATILE is not set +# CONFIG_COMMON_CLK_SI5351 is not set + +# +# Hardware Spinlock drivers +# +CONFIG_CLKSRC_OF=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_CLKSRC_EXYNOS_MCT=y +CONFIG_MAILBOX=y +# CONFIG_PL320_MBOX is not set +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y +CONFIG_OF_IOMMU=y +CONFIG_EXYNOS_IOMMU_V6=y +CONFIG_EXYNOS7_IOMMU_CHECK_DF=y +CONFIG_EXYNOS_IOVMM_V6=y +CONFIG_EXYNOS_IOMMU_NO_MASTER_CLKGATE=y +CONFIG_EXYNOS_IOMMU_EVENT_LOG=y +# CONFIG_EXYNOS_IOMMU_DEBUG is not set + +# +# Remoteproc drivers +# +# CONFIG_STE_MODEM_RPROC is not set + +# +# Rpmsg drivers +# +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +# CONFIG_DEVFREQ_GOV_SIMPLE_USAGE is not set +CONFIG_DEVFREQ_GOV_SIMPLE_EXYNOS=y +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set + +# +# DEVFREQ Drivers +# +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ=y +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET=y +# CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ODT_OFF is not set +CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING=y +CONFIG_VIBETONZ=y +CONFIG_MOTOR_DRV_MAX77833=y +CONFIG_MOTOR_DRV_MAX77843=y +# CONFIG_MOTOR_DRV_ISA1200 is not set +# CONFIG_MOTOR_DRV_ISA1400 is not set +# CONFIG_HAPTIC_ISA1200 is not set +# CONFIG_HAPTIC_ISA1400 is not set +# CONFIG_HAPTIC is not set +# CONFIG_EXTCON is not set +CONFIG_MEMORY=y +CONFIG_EXYNOS_MCOMP=y +CONFIG_IIO=y +CONFIG_IIO_BUFFER=y +# CONFIG_IIO_BUFFER_CB is not set +CONFIG_IIO_KFIFO_BUF=y +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 + +# +# Accelerometers +# +# CONFIG_KXSD9 is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set + +# +# Analog to digital converters +# +# CONFIG_AD7266 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7887 is not set +CONFIG_EXYNOS_ADC=y +# CONFIG_MAX1363 is not set +# CONFIG_TI_ADC081C is not set + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Hid Sensor IIO Common +# + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5686 is not set +# CONFIG_MAX517 is not set +# CONFIG_MCP4725 is not set + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +# CONFIG_AD9523 is not set + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +# CONFIG_ADF4350 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADXRS450 is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_ITG3200 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_INV_MPU6050_IIO is not set + +# +# Light sensors +# +# CONFIG_ADJD_S311 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_VCNL4000 is not set + +# +# Magnetometer sensors +# +# CONFIG_AK8975 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_VME_BUS is not set +CONFIG_PWM=y +CONFIG_PWM_SAMSUNG=y +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +# CONFIG_IPACK_BUS is not set +CONFIG_BATTERY_SAMSUNG=y +# CONFIG_CHARGING_VZWCONCEPT is not set +CONFIG_BATTERY_SWELLING=y +CONFIG_BATTERY_SWELLING_SELF_DISCHARGING=y +# CONFIG_BATTERY_SWELLING_SELF_DISCHARGING_ZERO_ONLY is not set +CONFIG_INBATTERY=y +CONFIG_CALC_TIME_TO_FULL=y +# CONFIG_BATTERY_AGE_FORECAST is not set +# CONFIG_FUELGAUGE_DUMMY is not set +# CONFIG_FUELGAUGE_MAX17042 is not set +# CONFIG_FUELGAUGE_MAX17048 is not set +# CONFIG_FUELGAUGE_MAX17050 is not set +# CONFIG_FUELGAUGE_MAX77823 is not set +CONFIG_FUELGAUGE_MAX77843=y +CONFIG_FUELGAUGE_MAX77833=y +# CONFIG_CHARGER_DUMMY is not set +# CONFIG_CHARGER_SMB328 is not set +# CONFIG_CHARGER_BQ24157 is not set +# CONFIG_CHARGER_BQ24191 is not set +# CONFIG_CHARGER_BQ24260 is not set +# CONFIG_CHARGER_MAX77823 is not set +CONFIG_CHARGER_MAX77843=y +CONFIG_CHARGER_MAX77833=y +CONFIG_WIRELESS_CHARGER_INBATTERY=y +CONFIG_WIRELESS_CHARGER_INBATTERY_CS100=y +# CONFIG_WIRELESS_CHARGER_INBATTERY_5V_FIX is not set +# CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE is not set +CONFIG_WIRELESS_CHARGER_BQ51221=y +# CONFIG_WIRELESS_CHARGER_P9027S is not set +# CONFIG_WIRELESS_CHARGER_P9220 is not set +# CONFIG_WIRELESS_CHARGER_MAX77900 is not set +CONFIG_AFC_CHARGER_MODE=y +CONFIG_SAMSUNG_LPM_MODE=y +# CONFIG_WIRELESS_CHARGER_THM is not set +# CONFIG_EN_OOPS is not set +CONFIG_DISABLE_SAVE_CAPACITY_MAX=y +CONFIG_FIX_CHG_FQ_4MHZ=y +# CONFIG_RESET_CONTROLLER is not set +CONFIG_SENSORS_SSP=y +# CONFIG_SENSORS_SSP_STM is not set +# CONFIG_SENSORS_MAX86900 is not set +CONFIG_SENSORS_MAX86902=y +CONFIG_SENSORS_MULTIPLE_GLASS_TYPE=y +CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA=y +# CONFIG_SENSORS_SX9310 is not set +# CONFIG_SENSORS_SSP_NOBLELTE is not set +# CONFIG_SENSORS_SSP_ZENLTE is not set +# CONFIG_SENSORS_SSP_VLTE is not set +# CONFIG_SENSORS_SSP_ATUC128L5HAR is not set +CONFIG_SENSORS_SSP_MPU6500=y +# CONFIG_SENSORS_SSP_BMI168 is not set +# CONFIG_SENSORS_SSP_BMP280 is not set +CONFIG_SENSORS_SSP_TMD4903=y +# CONFIG_SENSORS_SSP_TMG399X is not set +# CONFIG_SENSORS_SSP_AK09911 is not set +CONFIG_SENSORS_SSP_MOBEAM=y +CONFIG_SENSORS_MAX_NOTCHFILTER=y +CONFIG_SENSORS_SYSFS=y +# CONFIG_SENSORS_SSP_ATMEL is not set +# CONFIG_SENSORS_SSP_AK8963C is not set +# CONFIG_SENSORS_SSP_YAS532 is not set +CONFIG_SENSORS_SSP_ACCELEROMETER_POSITION=0 +CONFIG_SENSORS_SSP_GYROSCOPE_POSITION=0 +CONFIG_SENSORS_SSP_MAGNETOMETER_POSITION=0 +CONFIG_SENSORS_SSP_SENSORHUB=y +CONFIG_SENSORS_SSP_FACTORY=y +# CONFIG_SENSORS_SSP_C12SD is not set +# CONFIG_SENSORS_SSP_LSM330 is not set +# CONFIG_SENSORS_SSP_CM36651 is not set +# CONFIG_SENSORS_SSP_CM3320 is not set +# CONFIG_SENSORS_SSP_MAX88920 is not set +# CONFIG_SENSORS_SSP_MAX88921 is not set +CONFIG_SENSORS_SSP_LPS25H=y +# CONFIG_SENSORS_SSP_BMI058 is not set +# CONFIG_SENSORS_MPU6500_BMI058_DUAL is not set +# CONFIG_SENSORS_SSP_BMP182 is not set +# CONFIG_SENSORS_SSP_AT32UC3L0128 is not set +# CONFIG_SENSORS_SSP_SHTC1 is not set +CONFIG_SENSORS_SSP_BBD=y +# CONFIG_SENSORS_SSP_ICM20610 is not set +# CONFIG_SENSORS_SSP_K6DS3TR is not set +CONFIG_SENSORS_SSP_YAS537=y +# CONFIG_SENSORS_SSP_STM32F401 is not set +# CONFIG_SENSORS_MAX86902_LED_5V is not set +# CONFIG_SENSOR_SSP_PROXIMTY_FOR_WINDOW_TYPE is not set +# CONFIG_SENSORS_ADPD142 is not set +# CONFIG_SENSORS_SSP_TMG399x is not set +CONFIG_SENSORS_SSP_SX9306=y +CONFIG_SENSORS_SSP_INTERRUPT_GYRO_SENSOR=y +# CONFIG_SENSORS_CORE is not set +# CONFIG_SENSORS_BMI055 is not set +# CONFIG_SENSORS_AK8963C is not set +# CONFIG_SENSORS_AK09911C is not set +# CONFIG_SENSORS_CM3323 is not set +# CONFIG_SENSORS_CM36653 is not set +# CONFIG_SENSORS_TMD27723 is not set +# CONFIG_SENSORS_TMD3782 is not set +# CONFIG_SENSORS_ESD_DEFENCE is not set +# CONFIG_SENSORS_SX9500 is not set +# CONFIG_SENSORS_GP2A30 is not set +CONFIG_GPS_BCMxxxxx=y +# CONFIG_GPS_BCM4752 is not set +# CONFIG_GPS_BCM47521 is not set +# CONFIG_GPS_BCM4753 is not set +CONFIG_GPS_BCM47531=y +CONFIG_GPS_BCM4773=y +CONFIG_SENSORS_FINGERPRINT=y +CONFIG_SENSORS_FINGERPRINT_SYSFS=y +CONFIG_SENSORS_VFS7XXX=y +# CONFIG_SENSORS_FPRINT_SECURE is not set +# CONFIG_SENSORS_ET310 is not set +CONFIG_MOBICORE_DRIVER=y +# CONFIG_MOBICORE_DEBUG is not set +CONFIG_MOBICORE_API=y +CONFIG_SECURE_OS_CONTROL=y +CONFIG_SECURE_OS_BOOSTER_API=y +CONFIG_TRUSTONIC_TRUSTED_UI=y +CONFIG_TRUSTONIC_TRUSTED_UI_FB_BLANK=y +CONFIG_TRUSTED_UI_TOUCH_ENABLE=y +CONFIG_TRACE=y +CONFIG_EXYNOS_NOC_DEBUGGING=y +CONFIG_EXYNOS_SNAPSHOT=y +CONFIG_EXYNOS_SNAPSHOT_CALLSTACK=4 +CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT=y +CONFIG_EXYNOS_SNAPSHOT_IRQ_EXIT_THRESHOLD=0 +# CONFIG_EXYNOS_SNAPSHOT_IRQ_DISABLED is not set +CONFIG_EXYNOS_SNAPSHOT_CLK=y +CONFIG_EXYNOS_SNAPSHOT_FREQ=y +# CONFIG_EXYNOS_SNAPSHOT_HRTIMER is not set +CONFIG_EXYNOS_SNAPSHOT_SOFTIRQ=y +# CONFIG_EXYNOS_SNAPSHOT_REG is not set +CONFIG_EXYNOS_SNAPSHOT_MBOX=y +CONFIG_EXYNOS_SNAPSHOT_HOOK_LOGGER=y +CONFIG_EXYNOS_SNAPSHOT_PANIC_REBOOT=y +CONFIG_EXYNOS_SNAPSHOT_WATCHDOG_RESET=y +# CONFIG_EXYNOS_SNAPSHOT_MINIMIZED_MODE is not set +CONFIG_EXYNOS_CORESIGHT=y +CONFIG_EXYNOS_CORESIGHT_PC_INFO=y +CONFIG_PC_ITERATION=5 +# CONFIG_EXYNOS_CORESIGHT_MAINTAIN_DBG_REG is not set +# CONFIG_EXYNOS_CORESIGHT_ETM is not set +# CONFIG_EXYNOS_CORESIGHT_STM is not set +CONFIG_EXYNOS_BTS=y +CONFIG_EXYNOS7420_BTS=y + +# +# LED MATRIX FPGA +# +# CONFIG_ICE5_FPGA_LED_MATRIX is not set +CONFIG_SEC_NET_FILTER=y + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +CONFIG_EXT2_FS_SECURITY=y +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_DEFAULTS_TO_ORDERED=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_POSIX_ACL is not set +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_SDCARD_FS=y +CONFIG_SDCARD_FS_CI_SEARCH=y +CONFIG_SDCARD_FS_XATTR=y +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_FS_POSIX_ACL is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +CONFIG_FUSE_FS=y +# CONFIG_CUSE is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +CONFIG_FAT_VIRTUAL_XATTR=y +CONFIG_FAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:sdcard_external:s0" +CONFIG_FAT_SUPPORT_STLOG=y +CONFIG_EXFAT_FS=y +CONFIG_EXFAT_VIRTUAL_XATTR=y +CONFIG_EXFAT_VIRTUAL_XATTR_SELINUX_LABEL="u:object_r:sdcard_external:s0" +CONFIG_EXFAT_SUPPORT_STLOG=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_STLOG=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_ECRYPT_FS=y +# CONFIG_ECRYPT_FS_MESSAGING is not set +CONFIG_WTL_ENCRYPTION_FILTER=y +CONFIG_ECRYPT_FS_VIRTUAL_FAT_XATTR=y +CONFIG_SDP=y +# CONFIG_SDP_KEY_DUMP is not set +CONFIG_SCFS=y +# CONFIG_SYSTEM_COMPRESSED is not set +CONFIG_SCFS_LOWER_PAGECACHE_INVALIDATION=y +# CONFIG_SCFS_USE_CRYPTO is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NFS_FS is not set +# CONFIG_NFSD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CORE_NUM is not set +CONFIG_PRINTK_PROCESS=y +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2064 +CONFIG_MAGIC_SYSRQ=y +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SHIRQ is not set +CONFIG_LOCKUP_DETECTOR=y +CONFIG_HARDLOCKUP_DETECTOR_OTHER_CPU=y +CONFIG_HARDLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=1 +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=1 +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHEDSTATS is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_RT_MUTEX_TESTER is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +CONFIG_STACKTRACE=y +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_WRITECOUNT is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_FRAME_POINTER=y +# CONFIG_BOOT_PRINTK_DELAY is not set + +# +# RCU Debugging +# +# CONFIG_PROVE_RCU_DELAY is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_CPU_STALL_VERBOSE=y +# CONFIG_RCU_CPU_STALL_INFO is not set +# CONFIG_RCU_TRACE is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_LKDTM is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_NOP_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_PROBE_EVENTS is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_EARLY_PRINTK is not set +# CONFIG_PID_IN_CONTEXTIDR is not set + +# +# Samsung Rooting Restriction Feature +# +CONFIG_SEC_RESTRICT_ROOTING=y +CONFIG_SEC_RESTRICT_SETUID=y +CONFIG_SEC_RESTRICT_FORK=y +CONFIG_SEC_RESTRICT_ROOTING_LOG=y + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_ENCRYPTED_KEYS is not set +CONFIG_KEYS_DEBUG_PROC_KEYS=y +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_MST_NOBLE_TARGET is not set +# CONFIG_MST_ZEN_TARGET is not set +CONFIG_MST_LDO=y +# CONFIG_IMA is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="selinux" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_FIPS=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_TEST=y + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_SEQIV=y + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_CMAC is not set +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +CONFIG_CRYPTO_GHASH=y +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +# CONFIG_CRYPTO_SHA2_ARM64_CE is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_ARM64_CE is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_DRBG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y + +# +# Samsung Crypto Accelerator +# +CONFIG_FIPS_FMP=y +CONFIG_NODE_FOR_SELFTEST_FAIL=y +# CONFIG_PANIC_FOR_SELFTEST_FAIL is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +CONFIG_ARM64_CRYPTO=y +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set +# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set +# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_GENERIC_IO=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +# CONFIG_CRC8 is not set +CONFIG_AUDIT_GENERIC=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_NLATTR=y +CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y +# CONFIG_AVERAGE is not set +# CONFIG_CORDIC is not set +# CONFIG_DDR is not set +# CONFIG_QMI_ENCDEC is not set diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h index 9de30808899d..5c83eca07d83 100644 --- a/arch/arm64/include/asm/pgalloc.h +++ b/arch/arm64/include/asm/pgalloc.h @@ -68,7 +68,7 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) if (boot_mode_security) #endif //CONFIG_KNOX_KAP rkp_do = 1; - if( rkp_do && (unsigned long)pmd >= (unsigned long)RKP_RBUF_VA && (unsigned long)pmd < ((unsigned long)RKP_RBUF_VA + (1UL << 23)) /*8MB */) + if( rkp_do && (unsigned long)pmd >= (unsigned long)RKP_RBUF_VA && (unsigned long)pmd < ((unsigned long)RKP_RBUF_VA + TIMA_ROBUF_SIZE)) rkp_ro_free((void*)pmd); else free_page((unsigned long)pmd); diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 72170c84ba5b..34230aab6413 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -185,11 +185,19 @@ static inline pte_t pte_mkspecial(pte_t pte) pte_val(pte) |= PTE_SPECIAL; return pte; } - +#ifdef CONFIG_TIMA_RKP +extern int printk(const char *s, ...); +extern void panic(const char *fmt, ...); +#endif /* CONFIG_TIMA_RKP */ static inline void set_pte(pte_t *ptep, pte_t pte) { #ifdef CONFIG_TIMA_RKP - if (rkp_is_pg_protected((u64)ptep)) { + if (rkp_is_pg_dbl_mapped((u64)ptep)) { + printk("\n Trying to double map the page \n"); + panic("TIMA RKP : Double mapping Detected"); + return; + } + else if (rkp_is_pg_protected((u64)ptep)) { rkp_call(RKP_PTE_SET, (unsigned long)ptep, pte_val(pte), 0, 0, 0); } else { asm volatile("mov x1, %0\n" diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h index 5aaec544f206..41fefb828e6f 100644 --- a/arch/arm64/include/asm/tlb.h +++ b/arch/arm64/include/asm/tlb.h @@ -192,7 +192,7 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, if (boot_mode_security) #endif //CONFIG_KNOX_KAP rkp_do = 1; - if (rkp_do && (unsigned long)pmdp >= (unsigned long)RKP_RBUF_VA && (unsigned long)pmdp < ((unsigned long)RKP_RBUF_VA + (1UL << 23)) /* 8MB */) + if (rkp_do && (unsigned long)pmdp >= (unsigned long)RKP_RBUF_VA && (unsigned long)pmdp < ((unsigned long)RKP_RBUF_VA + TIMA_ROBUF_SIZE)) rkp_ro_free((void*)pmdp); else { tlb_add_flush(tlb, addr); diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 3083a08f9622..14e1e5292369 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -98,11 +98,55 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, dsb(ish); } +static inline void __flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48; + unsigned long addr; + start = asid | (start >> 12); + end = asid | (end >> 12); + + dsb(ishst); + for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) + asm("tlbi vae1is, %0" : : "r"(addr)); + dsb(ish); +} + +static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + unsigned long addr; + start >>= 12; + end >>= 12; + + dsb(ishst); + for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) + asm("tlbi vaae1is, %0" : : "r"(addr)); + dsb(ish); + isb(); +} + /* - * Convert calls to our calling convention. + * This is meant to avoid soft lock-ups on large TLB flushing ranges and not + * necessarily a performance improvement. */ -#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma) -#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e) +#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT) + +static inline void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + if ((end - start) <= MAX_TLB_RANGE) + __flush_tlb_range(vma, start, end); + else + flush_tlb_mm(vma->vm_mm); +} + +static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + if ((end - start) <= MAX_TLB_RANGE) + __flush_tlb_kernel_range(start, end); + else + flush_tlb_all(); +} /* * On AArch64, the cache coherency is handled via the set_pte_at() function. diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 6de3460ede4c..e6390c25577a 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -78,6 +78,16 @@ int hw_breakpoint_slots(int type) } } +#ifdef CONFIG_SKIP_HW_BREAKPOINT +static int skip_hw_breakpoint; +static int __init skip_hw_breakpoint_func(char *str) +{ + get_option(&str, &skip_hw_breakpoint); + return 0; +} +early_param("hw_breakpoint", skip_hw_breakpoint_func); +#endif + #define READ_WB_REG_CASE(OFF, N, REG, VAL) \ case (OFF + N): \ AARCH64_DBG_READ(N, REG, VAL); \ @@ -907,6 +917,13 @@ static inline void cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) */ static int __init arch_hw_breakpoint_init(void) { +#if defined(CONFIG_SKIP_HW_BREAKPOINT) + if (skip_hw_breakpoint) { + pr_info("skip arch_hw_breakpoint init\n"); + return 0; + } +#endif + core_num_brps = get_num_brps(); core_num_wrps = get_num_wrps(); diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 9a4e7dd5fcf5..2de2ab02f4d5 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -68,6 +68,10 @@ SECTIONS rkp_pgt_bitmap = .; . = rkp_pgt_bitmap + 0x18000; } + .rkp.dblmap : { + rkp_map_bitmap = .; + . = rkp_map_bitmap + 0x18000; + } #ifdef CONFIG_RKP_KDP /* Creating a new section to store task credentials */ . = ALIGN(PAGE_SIZE); diff --git a/arch/arm64/mach-exynos/Kconfig b/arch/arm64/mach-exynos/Kconfig index 84fe4213f4e9..932e0f84288b 100644 --- a/arch/arm64/mach-exynos/Kconfig +++ b/arch/arm64/mach-exynos/Kconfig @@ -44,30 +44,6 @@ config SOC_EXYNOS7420_EVT_0 help Enable EXYNOS7420 EVT0 SoC support -config SOC_EXYNOS7580 - bool "SAMSUNG EXYNOS7580" - depends on ARCH_EXYNOS7 - select SAMSUNG_DMADEV - select CAL_SYS_PWRDOWN - select ARCH_HAS_OPP - select ARCH_HAS_BANDGAP - help - Enable EXYNOS7580 SoC support - -config SOC_EXYNOS5433 - bool "SAMSUNG EXYNOS5433" - default n - depends on ARCH_EXYNOS5 - select PM_GENERIC_DOMAINS if PM - select S5P_PM if PM - select S5P_SLEEP if SUSPEND - select SAMSUNG_DMADEV - select EXYNOS_HSI2C_RESET_DURING_DSTOP if CPU_IDLE - select EXYNOS_SPI_RESET_DURING_DSTOP if CPU_IDLE - select CAL_SYS_PWRDOWN - help - Enable EXYNOS5433 SoC support - config EXYNOS_ASV bool "ENABLE EXYNOS ASV" default n @@ -88,6 +64,12 @@ config EXYNOS_ASV_MARGIN_TEST default n depends on EXYNOS_ASV +config SKIP_HW_BREAKPOINT + bool "support skip hw breakpoint" + default n + help + Support early param for T32 onchip breakpoint + config CAL_SYS_PWRDOWN bool "Enable CAL for system level power down" @@ -103,17 +85,19 @@ config EXYNOS_ATAGS config EXYNOS5_DYNAMIC_CPU_HOTPLUG bool "Dynamic CPU Hotplug support" - depends on !SOC_EXYNOS7580 depends on CPU_FREQ help Enable Dynamic CPU Hotplug -config EXYNOS7580_DYNAMIC_CLUSTER_HOTPLUG - bool "Dynamic CLUSTER Hotplug support" - depends on SOC_EXYNOS7580 - depends on CPU_FREQ - help - Enable Dynamic CLUSTER Hotplug +config EXYNOS5_DYNAMIC_CPU_HOTPLUG_SLEEP_PREPARE + int "Activate number of cores when sleep" + depends on EXYNOS5_DYNAMIC_CPU_HOTPLUG + default 1 + help + When gose to sleep, activate some cores for performace + during sleep/wakeup sequence. + This config set the number of activate cores. + defaut value is "4" to activate all cores in cluster0. config EXYNOS_CONTENT_PATH_PROTECTION bool "Exynos Content Path Protection" @@ -225,21 +209,6 @@ endif comment "Flattened Device Tree based board for EXYNOS SoCs" -config MACH_UNIVERSAL5433 - bool "SAMSUNG UNIVERSAL5433 Machine using device tree" - default y - depends on ARCH_EXYNOS5 && SOC_EXYNOS5433 - select ARM_AMBA - select CLKSRC_OF - select PINCTRL - select PINCTRL_EXYNOS - select USE_OF - select MIGHT_HAVE_PCI - select PCI_DOMAINS if PCI - help - Machine support for Samsung EXYNOS5433 machine with device tree enabled. - Select this if a fdt blob is available for the EXYNOS5433 SoC based board. - config MACH_ESPRESSO7420 bool "SAMSUNG ESPRESSO7420 Machine using device tree" select ARM_AMBA @@ -267,27 +236,6 @@ config MACH_UNIVERSAL7420 help Machine support for Samsung EXYNOS7420 machine with device tree enabled. Select this if a fdt blob is available for the EXYNOS7420 SoC based board. - -config MACH_SMDK7580 - bool "SAMSUNG SMDK7580 Machine using device tree" - select ARM_AMBA - select USE_OF - select PINCTRL - select PINCTRL_EXYNOS - help - Machine support for Samsung EXYNOS7580 machine with device tree enabled. - Select this if a fdt blob is available for the EXYNOS7580 SoC based board. - -config MACH_UNIVERSAL7580 - bool "SAMSUNG UNIVERSAL7580 Machine using device tree" - select ARM_AMBA - select USE_OF - select PINCTRL - select PINCTRL_EXYNOS - select PM_OPP - help - Machine support for Samsung EXYNOS7580 machine with device tree enabled. - Select this if a fdt blob is available for the EXYNOS7580 SoC based board. endmenu # Reset IPs during LPA/DSTOP @@ -343,10 +291,15 @@ config TIMA_RKP help this enables realtime kernel protection +config RKP_DMAP_PROT + bool "Page Double Mapping protection" + depends on TIMA_RKP + default n + help + Prevents unauthorized cred modification. config RKP_KDP bool "Protection for cred structure" - depends on TIMA + depends on TIMA_RKP default n help Prevents unauthorized cred modification. - diff --git a/arch/arm64/mach-exynos/Makefile b/arch/arm64/mach-exynos/Makefile index f5ef72295f74..2dacbc4cc258 100644 --- a/arch/arm64/mach-exynos/Makefile +++ b/arch/arm64/mach-exynos/Makefile @@ -14,35 +14,23 @@ obj- := obj-$(CONFIG_ARCH_EXYNOS) += common.o obj-$(CONFIG_SOC_EXYNOS7420) += pm_domains-exynos7420.o -obj-$(CONFIG_SOC_EXYNOS7580) += pm_domains-exynos7580.o -obj-$(CONFIG_SOC_EXYNOS5433) += pm_domains-exynos5433.o obj-$(CONFIG_CPU_IDLE) += exynos-pm.o obj-$(CONFIG_PM_RUNTIME) += pm_domains.o obj-$(CONFIG_PM_RUNTIME_TEST_SYSFS) += pm_domains_sysfs.o obj-$(CONFIG_ARCH_EXYNOS) += pmu.o pmu_cal_sys.o -ifneq ($(CONFIG_SOC_EXYNOS7580),y) obj-$(CONFIG_ARCH_EXYNOS) += exynos-powermode.o -else -obj-$(CONFIG_ARCH_EXYNOS) += exynos-powermode-smp.o -endif obj-$(CONFIG_SUSPEND) += pm.o ifeq ($(CONFIG_CAL_SYS_PWRDOWN),y) -obj-$(CONFIG_SOC_EXYNOS5433) += pmu_cal_sys_exynos5433.o obj-$(CONFIG_SOC_EXYNOS7420) += pmu_cal_sys_exynos7420.o -obj-$(CONFIG_SOC_EXYNOS7580) += pmu_cal_sys_exynos7580.o endif -obj-$(CONFIG_SOC_EXYNOS7580) += pmu-cp.o # machine support obj-$(CONFIG_EXYNOS_ASV) += asv-exynos.o asv-exynos_cal.o -obj-$(CONFIG_MACH_UNIVERSAL5433) += mach-universal5433.o asv-exynos5433_cal.o otp.o obj-$(CONFIG_MACH_ESPRESSO7420) += mach-espresso7420.o asv-exynos7420_cal.o obj-$(CONFIG_MACH_UNIVERSAL7420) += mach-universal7420.o asv-exynos7420_cal.o -obj-$(CONFIG_MACH_SMDK7580) += mach-smdk7580.o asv-exynos7580_cal.o -obj-$(CONFIG_MACH_UNIVERSAL7580) += mach-universal7580.o asv-exynos7580_cal.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS) += setup-fimc-is.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_IS) += setup-fimc-is-sensor.o @@ -53,9 +41,7 @@ obj-$(CONFIG_COMPANION_USE) += setup-fimc-is-companion.o obj-$(CONFIG_EXYNOS5_SETUP_MIPIPHY) += setup-exynos5-mipiphy.o -ifneq ($(CONFIG_SOC_EXYNOS7580),y) obj-$(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION) += secmem.o -endif obj-$(CONFIG_MSM_HSIC_SYSMON) += hsic_sysmon.o obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o diff --git a/arch/arm64/mach-exynos/asv-exynos7420_cal.c b/arch/arm64/mach-exynos/asv-exynos7420_cal.c index 46bf32ce5d86..3dd0144596d3 100644 --- a/arch/arm64/mach-exynos/asv-exynos7420_cal.c +++ b/arch/arm64/mach-exynos/asv-exynos7420_cal.c @@ -199,6 +199,16 @@ static void cal_print_asv_info(void) } #ifdef CONFIG_SEC_FACTORY +u32 set_table_ver2, table_ver2_1st, table_ver2_2nd; +static int __init asv_table_ver2_setup(char *str) +{ + set_table_ver2 = (u32)simple_strtoul(str,NULL,0); + table_ver2_1st = set_table_ver2 & 0x000000FF; + table_ver2_2nd = (set_table_ver2 & 0x0000FF00) >> 8; + return 1; +} +__setup("asv_table_version2=", asv_table_ver2_setup); + static ssize_t exynos7420_show_asv_info(struct device *dev, struct device_attribute *attr, char *buf) @@ -207,7 +217,10 @@ static ssize_t exynos7420_show_asv_info(struct device *dev, /* Set asv group info to buf */ count += sprintf(&buf[count], "%u ", gasv_table_info.dvfs_asv_table_version); - count += sprintf(&buf[count], "%02x ", gasv_table_info.bigcpu_asv_group); + count += sprintf(&buf[count], "%03x ", gasv_table_info.bigcpu_asv_group); + count += sprintf(&buf[count], "%03x ", gasv_table_info.g3d_asv_group); + count += sprintf(&buf[count], "%u ", table_ver2_1st); + count += sprintf(&buf[count], "%u ", table_ver2_2nd); count += sprintf(&buf[count], "\n"); return count; @@ -268,12 +281,12 @@ u32 cal_get_table_ver(void) u32 cal_get_ids(void) { - return __raw_readl(CHIPID_ASV_INFO + 0x01C0) & 0xff;; + return 0; } u32 cal_get_hpm(void) { - return (__raw_readl(CHIPID_ASV_INFO + 0x01C4) >> 24) & 0xff; + return 0; } void cal_init(void) diff --git a/arch/arm64/mach-exynos/exynos-powermode.c b/arch/arm64/mach-exynos/exynos-powermode.c index 64029828fd7b..6aeb32a61ed1 100644 --- a/arch/arm64/mach-exynos/exynos-powermode.c +++ b/arch/arm64/mach-exynos/exynos-powermode.c @@ -200,16 +200,16 @@ static int is_lpc_available(unsigned int target_residency) if (check_reg_status(check_reg_lpc, ARRAY_SIZE(check_reg_lpc))) return false; - if (exynos_lpc_prepare()) + if (exynos_check_aud_pwr() > AUD_PWR_LPA) return false; if (is_dll_on()) return false; - if (exynos_check_aud_pwr() > AUD_PWR_LPA) + if (pwm_check_enable_cnt()) return false; - if (pwm_check_enable_cnt()) + if (exynos_lpc_prepare()) return false; return true; diff --git a/arch/arm64/mach-exynos/include/mach/cpufreq.h b/arch/arm64/mach-exynos/include/mach/cpufreq.h index 3c45b4d3f03e..d3d227b0d3b8 100644 --- a/arch/arm64/mach-exynos/include/mach/cpufreq.h +++ b/arch/arm64/mach-exynos/include/mach/cpufreq.h @@ -14,6 +14,7 @@ #define __ARCH_CPUFREQ_H __FILE__ #include +#include /* * Common definitions and structures @@ -67,6 +68,7 @@ struct exynos_dvfs_info { unsigned int boot_cpu_max_qos_timeout; #ifdef CONFIG_SEC_PM unsigned int jig_boot_cpu_max_qos; + unsigned int low_boot_cpu_max_qos; /* low freq */ #endif unsigned int resume_freq; int boot_freq_idx; @@ -78,6 +80,10 @@ struct exynos_dvfs_info { const unsigned int *max_op_freqs; struct cpufreq_frequency_table *freq_table; struct regulator *regulator; +#ifdef CONFIG_PMU_COREMEM_RATIO + int (*region_bus_table)[6]; + int region; +#endif void (*set_freq)(unsigned int, unsigned int); void (*set_ema)(unsigned int); bool (*need_apll_change)(unsigned int, unsigned int); @@ -213,5 +219,14 @@ static inline bool is_cluster1_hotplugged(void) {return 0;} #else #warning "Should define CONFIG_ARM_EXYNOS_(MP_)CPUFREQ\n" #endif +#if defined(CONFIG_PMU_COREMEM_RATIO) +void coremem_region_bus_lock(int region, struct cpufreq_policy *policy); +#else +static inline +void coremem_region_bus_lock(int region, struct cpufreq_policy *policy) +{ + return; +} +#endif /* CONFIG_PMU_COREMEM_RATIO */ #endif #endif /* __ARCH_CPUFREQ_H */ diff --git a/arch/arm64/mach-exynos/include/mach/devfreq.h b/arch/arm64/mach-exynos/include/mach/devfreq.h index 2ce589abf14e..5b02b47ab964 100644 --- a/arch/arm64/mach-exynos/include/mach/devfreq.h +++ b/arch/arm64/mach-exynos/include/mach/devfreq.h @@ -67,6 +67,11 @@ void exynos7_int_notify_power_status(const char* pd_name, unsigned int turn_on); void exynos7_isp_notify_power_status(const char* pd_name, unsigned int turn_on); void exynos7_disp_notify_power_status(const char* pd_name, unsigned int turn_on); unsigned long vpp_get_int_freq(unsigned long freq); +#if defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) +extern void exynos7_devfreq_mif_thermal_set_polling_period(uint32_t target_freq, uint32_t cl, bool big_alive); +#else +static inline void exynos7_devfreq_mif_thermal_set_polling_period(uint32_t target_freq, uint32_t cl, bool big_alive) { return; } +#endif #elif defined(CONFIG_ARM_EXYNOS7580_BUS_DEVFREQ) void exynos7_int_notify_power_status(const char* pd_name, unsigned int turn_on); void exynos7_isp_notify_power_status(const char* pd_name, unsigned int turn_on); diff --git a/arch/arm64/mach-exynos/include/mach/exynos-fimc-is-sensor.h b/arch/arm64/mach-exynos/include/mach/exynos-fimc-is-sensor.h index 24c7ab4a07f1..8464f50b1297 100644 --- a/arch/arm64/mach-exynos/include/mach/exynos-fimc-is-sensor.h +++ b/arch/arm64/mach-exynos/include/mach/exynos-fimc-is-sensor.h @@ -75,6 +75,7 @@ enum exynos_sensor_id { SENSOR_NAME_IMX134 = 102, SENSOR_NAME_IMX175 = 103, SENSOR_NAME_IMX240 = 104, + SENSOR_NAME_IMX228 = 106, SENSOR_NAME_IMX219 = 107, SENSOR_NAME_SR261 = 201, /* 201 ~ 300 Other vendor sensors */ diff --git a/arch/arm64/mach-exynos/pmu.c b/arch/arm64/mach-exynos/pmu.c index 65fdea734b1b..2d6629a89ff0 100644 --- a/arch/arm64/mach-exynos/pmu.c +++ b/arch/arm64/mach-exynos/pmu.c @@ -24,6 +24,7 @@ #endif #include #include +#include #define CPU_RESET_UP_CONFIG 0x7 static void exynos_cpu_up(unsigned int cpu_id) @@ -249,6 +250,8 @@ static void exynos7580_pmu_init(void) int __init exynos_pmu_init(void) { unsigned int tmp; + struct device_node *np; + int drv_val; exynos_enable_hw_trip(); @@ -268,6 +271,19 @@ int __init exynos_pmu_init(void) #else tmp |= CLKOUT_SEL_TCXO; #endif + +#if defined(CONFIG_SOC_EXYNOS7420) + /* To set drive strength for Audio */ + np = of_find_node_with_property(NULL, "drv_strength"); + + if(np) { + of_property_read_u32(np, "drv_strength", &drv_val); + pr_err("The value of drv_strength : %d\n", drv_val); + + if(drv_val <= 7 && drv_val >=0) + tmp |= (drv_val << 4); + } +#endif __raw_writel(tmp, EXYNOS_PMU_PMU_DEBUG); #if defined(CONFIG_SOC_EXYNOS7580) diff --git a/arch/arm64/mach-exynos/pmu_cal_sys_exynos7420.c b/arch/arm64/mach-exynos/pmu_cal_sys_exynos7420.c index 9dabf2c0f83d..4b18d6373d84 100644 --- a/arch/arm64/mach-exynos/pmu_cal_sys_exynos7420.c +++ b/arch/arm64/mach-exynos/pmu_cal_sys_exynos7420.c @@ -416,10 +416,13 @@ static void init_pmu_cpu_option(void) #define USE_STANDBYWFI (0x1 << 16) #define USE_SC_FEEDBACK (0x1 << 1) #define USE_SC_COUNTER (0x1 << 0) +#define USE_MEMPWRDOWN (0x1 << 2) /* use both sc_counter and sc_feedback */ /* enable to wait for low SMP-bit at sys power down */ for (cpu = 0; cpu < 8; cpu++) { tmp = __raw_readl(CPU_OPTION(cpu)); + if (cpu < 4) + tmp |= USE_MEMPWRDOWN; tmp |= (USE_SC_FEEDBACK | USE_SC_COUNTER); tmp |= USE_SMPEN; tmp |= USE_STANDBYWFI; diff --git a/arch/arm64/mach-exynos/setup-fimc-is-module.c b/arch/arm64/mach-exynos/setup-fimc-is-module.c index 208cb96b4a1f..bdad9b06040d 100644 --- a/arch/arm64/mach-exynos/setup-fimc-is-module.c +++ b/arch/arm64/mach-exynos/setup-fimc-is-module.c @@ -249,8 +249,9 @@ static int exynos_fimc_is_module_pin_debug(struct platform_device *pdev, int voltage; regulator = regulator_get(&pdev->dev, name); - if (IS_ERR(regulator)) { + if (IS_ERR_OR_NULL(regulator)) { pr_err("%s : regulator_get(%s) fail\n", __func__, name); + regulator_put(regulator); return PTR_ERR(regulator); } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 6df935dbbd9d..7d656b01869e 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -208,7 +208,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, if (!virt_addr_valid(current_thread_info()) || !virt_addr_valid(current)) { sec_debug_disable_printk_process(); pr_emerg("sec_debug: safe panic handler due to invalid 'current' \n"); - sec_debug_panic_handler(NULL, false); + sec_debug_panic_handler("sec_debug: safe panic handler", false); } #endif diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 873e08afebf8..aa8f966f7cc9 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -152,7 +152,7 @@ static void __init *early_alloc(unsigned long sz) /* Extra memory needed by VMM */ void* vmm_extra_mem = 0; spinlock_t ro_rkp_pages_lock = __SPIN_LOCK_UNLOCKED(); -char ro_pages_stat[1 << RO_PAGES_ORDER] = {0}; +char ro_pages_stat[RO_PAGES] = {0}; unsigned ro_alloc_last = 0; int rkp_ro_mapped = 0; @@ -165,8 +165,8 @@ void *rkp_ro_alloc(void) spin_lock_irqsave(&ro_rkp_pages_lock,flags); - for (i = 0, j = ro_alloc_last; i < (1 << RO_PAGES_ORDER) ; i++) { - j = (j+i) %( 1UL << RO_PAGES_ORDER); + for (i = 0, j = ro_alloc_last; i < (RO_PAGES) ; i++) { + j = (j+i) %(RO_PAGES); if (!ro_pages_stat[j]) { ro_pages_stat[j] = 1; ro_alloc_last = j+1; @@ -193,8 +193,8 @@ void rkp_ro_free(void *free_addr) unsigned int is_rkp_ro_page(u64 addr) { - if( (addr >= (u64)RKP_RBUF_VA) - && (addr <= (u64)(RKP_RBUF_VA+(1 << RO_PAGES_ORDER)))) + if( (addr >= (u64)RKP_RBUF_VA) + && (addr < (u64)(RKP_RBUF_VA+ TIMA_ROBUF_SIZE))) return 1; else return 0; } @@ -402,7 +402,7 @@ static void __init map_mem(void) #endif if( rkp_do ){ create_mapping(start, __phys_to_virt(start), mid - start); - memset((void*)RKP_RBUF_VA, 0, 0x800000); + memset((void*)RKP_RBUF_VA, 0, TIMA_ROBUF_SIZE); create_mapping(mid, __phys_to_virt(mid), end - mid); }else{ create_mapping(start, __phys_to_virt(start), end - start); diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c index c6a94f394ca4..79d6d7d1700d 100644 --- a/arch/arm64/mm/pgd.c +++ b/arch/arm64/mm/pgd.c @@ -84,7 +84,7 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd) if (rkp_do) rkp_call(RKP_PGD_FREE, (unsigned long)pgd, 0, 0, 0, 0); /* if pgd memory come from read only buffer, the put it back */ /*TODO: use a macro*/ - if( rkp_do && (unsigned long)pgd >= (unsigned long)RKP_RBUF_VA && (unsigned long)pgd < ((unsigned long)RKP_RBUF_VA + (1UL << 23)) /*8MB */) + if( rkp_do && (unsigned long)pgd >= (unsigned long)RKP_RBUF_VA && (unsigned long)pgd < ((unsigned long)RKP_RBUF_VA + TIMA_ROBUF_SIZE)) rkp_ro_free((void*)pgd); else { diff --git a/crypto/aead.c b/crypto/aead.c index 547491e35c63..eddb6fc0c68d 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -527,6 +527,13 @@ struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) struct crypto_tfm *tfm; int err; +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : aead.c:crypto_alloc_aead FIPS in Error!!!\n"); + return ERR_PTR(-EACCES); + } +#endif + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); type |= CRYPTO_ALG_TYPE_AEAD; mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); diff --git a/crypto/drbg.c b/crypto/drbg.c index 2c094a9c5f10..56fbb8b192b0 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -99,6 +99,10 @@ #include +#ifdef CONFIG_CRYPTO_FIPS +#include "internal.h" //For FIPS_FUNC_TEST macros +#endif + /*************************************************************** * Backend cipher definitions available to DRBG ***************************************************************/ @@ -256,7 +260,22 @@ static bool drbg_fips_continuous_test(struct drbg_state *drbg, /* return false due to priming, i.e. another round is needed */ return false; } + +#if FIPS_FUNC_TEST == 94 + printk(KERN_ERR "FIPS : drbg.c:drbg_fips_continuous_test Intentionally failing drbg_fips_continuous_test!!!\n"); + memcpy(drbg->prev, buf, drbg_blocklen(drbg)); +#endif + ret = memcmp(drbg->prev, buf, drbg_blocklen(drbg)); + + if (ret == 0 ) { + printk(KERN_ERR "FIPS : drbg.c:drbg_fips_continuous_test failed !!!\n"); + set_in_fips_err(); + if (in_fips_err()) + printk(KERN_ERR "FIPS : drbg.c:drbg_fips_continuous_test FIPS in Error!!!\n"); + return false; + } + memcpy(drbg->prev, buf, drbg_blocklen(drbg)); /* the test shall pass when the two compared values are not equal */ return ret != 0; @@ -619,6 +638,13 @@ static int drbg_ctr_generate(struct drbg_state *drbg, struct drbg_string data; unsigned char prefix = DRBG_PREFIX1; +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_ctr_generate FIPS in Error!!!\n"); + return -EACCES; + } +#endif + memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); /* 10.2.1.5.2 step 2 */ @@ -642,6 +668,13 @@ static int drbg_ctr_generate(struct drbg_state *drbg, outlen = (drbg_blocklen(drbg) < (buflen - len)) ? drbg_blocklen(drbg) : (buflen - len); if (!drbg_fips_continuous_test(drbg, drbg->scratchpad)) { +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_ctr_generate FIPS in Error!!!\n"); + len = -EACCES; + goto out; + } +#endif /* 10.2.1.5.2 step 6 */ drbg_add_buf(drbg->V, drbg_blocklen(drbg), &prefix, 1); continue; @@ -745,6 +778,13 @@ static int drbg_hmac_generate(struct drbg_state *drbg, struct drbg_string data; LIST_HEAD(datalist); +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_hmac_generate FIPS in Error!!!\n"); + return -EACCES; + } +#endif + /* 10.1.2.5 step 2 */ if (addtl && !list_empty(addtl)) { ret = drbg_hmac_update(drbg, addtl, 1); @@ -762,8 +802,15 @@ static int drbg_hmac_generate(struct drbg_state *drbg, return ret; outlen = (drbg_blocklen(drbg) < (buflen - len)) ? drbg_blocklen(drbg) : (buflen - len); - if (!drbg_fips_continuous_test(drbg, drbg->V)) + if (!drbg_fips_continuous_test(drbg, drbg->V)) { +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_hmac_generate FIPS in Error!!!\n"); + return -EACCES; + } +#endif continue; + } /* 10.1.2.5 step 4.2 */ memcpy(buf + len, drbg->V, outlen); @@ -944,6 +991,13 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, LIST_HEAD(datalist); unsigned char prefix = DRBG_PREFIX1; +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_hash_hashgen FIPS in Error!!!\n"); + return -EACCES; + } +#endif + memset(src, 0, drbg_statelen(drbg)); memset(dst, 0, drbg_blocklen(drbg)); @@ -963,6 +1017,13 @@ static int drbg_hash_hashgen(struct drbg_state *drbg, outlen = (drbg_blocklen(drbg) < (buflen - len)) ? drbg_blocklen(drbg) : (buflen - len); if (!drbg_fips_continuous_test(drbg, dst)) { +#ifdef CONFIG_CRYPTO_FIPS + if (unlikely(in_fips_err())) { + printk(KERN_ERR "FIPS : drbg.c:drbg_hmac_generate FIPS in Error!!!\n"); + len = -EACCES; + goto out; + } +#endif drbg_add_buf(src, drbg_statelen(drbg), &prefix, 1); continue; } diff --git a/crypto/fips_integrity.c b/crypto/fips_integrity.c index 61f343e34ce0..d03b6786ac00 100644 --- a/crypto/fips_integrity.c +++ b/crypto/fips_integrity.c @@ -27,11 +27,9 @@ static const char * symtab[][3] = {{".text", "first_crypto_text", "last_crypto_text" }, {".rodata", "first_crypto_rodata", "last_crypto_rodata"}, {".init.text", "first_crypto_init", "last_crypto_init" }, - {".exit.text", "first_crypto_exit", "last_crypto_exit" }, {"asm.text", "first_crypto_asm_text", "last_crypto_asm_text" }, {"asm.rodata", "first_crypto_asm_rodata", "last_crypto_asm_rodata"}, - {"asm.init.text", "first_crypto_asm_init", "last_crypto_asm_init" }, - {"asm.exit.text", "first_crypto_asm_exit", "last_crypto_asm_exit" }}; + {"asm.init.text", "first_crypto_asm_init", "last_crypto_asm_init" }}; extern const char * get_builtime_crypto_hmac(void); diff --git a/crypto/internal.h b/crypto/internal.h index 52b31b91f010..99fa5f4f41c8 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -39,6 +39,11 @@ * FIPS_FUNC_TEST 6 will make the SHA1 test fail * FIPS_FUNC_TEST 7 will make the TDES test fail * FIPS_FUNC_TEST 8 will make the RNG test fail + * FIPS_FUNC_TEST 91 will make the drbg_pr_ctr_aes128 test fail + * FIPS_FUNC_TEST 92 will make the drbg_pr_sha256 test fail + * FIPS_FUNC_TEST 93 will make the drbg_pr_hmac_sha256 test fail + * FIPS_FUNC_TEST 94 will make the continous PRNG test fail for DRBG + * FIPS_FUNC_TEST 100 will make the AES GCM self test fail */ #define FIPS_FUNC_TEST 0 diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 22f68a048a62..2a76a72cc122 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1954,7 +1954,11 @@ static int __init tcrypt_mod_init(void) } #else } else { - do_integrity_check(); + if (do_integrity_check() != 0) + { + printk(KERN_ERR "tcrypt: CRYPTO API FIPS Integrity Check failed!!!\n"); + set_in_fips_err(); + } if(in_fips_err()) { printk(KERN_ERR "tcrypt: CRYPTO API in FIPS Error!!!\n"); } else { diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 107d19bbfdee..853bfcb0067e 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1761,6 +1761,12 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, static int alg_test_null(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { +#ifdef CONFIG_CRYPTO_FIPS + if (desc && desc->fips_allowed) { + if (unlikely(in_fips_err())) + return -1; + } +#endif return 0; } diff --git a/crypto/testmgr.h b/crypto/testmgr.h index f85ac361912b..314c5227b898 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -17658,7 +17658,11 @@ static struct aead_testvec aes_gcm_enc_tv_template[] = { .rlen = 32, }, { .key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c" +#if FIPS_FUNC_TEST == 100 + "\x6c\x6a\x8f\x94\x67\x30\x83\x08", +#else "\x6d\x6a\x8f\x94\x67\x30\x83\x08", +#endif .klen = 16, .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad" "\xde\xca\xf8\x88", @@ -19175,7 +19179,11 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = { static struct drbg_testvec drbg_pr_sha256_tv_template[] = { { .entropy = (unsigned char *) +#if FIPS_FUNC_TEST == 92 + "\x71\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" +#else "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" +#endif "\xc1\xeb\xd2\x4e\x36\x14\xab\x18\xc4\x9c\xc9\xcf" "\x1a\xe8\xf7\x7b\x02\x49\x73\xd7\xf1\x42\x7d\xc6" "\x3f\x29\x2d\xec\xd3\x66\x51\x3f\x1d\x8d\x5b\x4e", @@ -19333,7 +19341,11 @@ static struct drbg_testvec drbg_pr_sha256_tv_template[] = { static struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { { .entropy = (unsigned char *) +#if FIPS_FUNC_TEST == 93 + "\x98\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" +#else "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" +#endif "\x7e\x5c\x0e\xae\x0d\x3e\x30\x95\x59\xe9\xfe\x96" "\xb0\x67\x6d\x49\xd5\x91\xea\x4d\x07\xd2\x0d\x46" "\xd0\x64\x75\x7d\x30\x23\xca\xc2\x37\x61\x27\xab", @@ -19491,7 +19503,11 @@ static struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { static struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { { .entropy = (unsigned char *) +#if FIPS_FUNC_TEST == 91 + "\xd2\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" +#else "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" +#endif "\x94\xd7\x28\x9c\x43\x77\x19\x29\x1a\x6d\xc3\xa2", .entropylen = 24, .entpra = (unsigned char *) diff --git a/drivers/Kconfig b/drivers/Kconfig index dcffaee50de5..2b76bfccbb6b 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -199,6 +199,8 @@ source "drivers/trace/Kconfig" source "drivers/bts/Kconfig" +source "drivers/ledmatrix/Kconfig" + source "drivers/secfilter/Kconfig" source "drivers/soc/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index f11dfd8fbf9c..19b5ad1d35b3 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -178,6 +178,9 @@ obj-$(CONFIG_SENSORS_FINGERPRINT) += fingerprint/ obj-$(CONFIG_MHI) += mhi/ obj-$(CONFIG_ESOC) += esoc/ +#LED MATRIX FGPA Driver +obj-$(CONFIG_ICE5_FPGA_LED_MATRIX) += ledmatrix/ + # SecFilter Driver obj-$(CONFIG_SEC_NET_FILTER) += secfilter/ diff --git a/drivers/battery/Kconfig b/drivers/battery/Kconfig index 502688e9fec6..0b657e244b4c 100644 --- a/drivers/battery/Kconfig +++ b/drivers/battery/Kconfig @@ -23,6 +23,16 @@ config BATTERY_SWELLING_SELF_DISCHARGING bool "prevent battery swelling with self discharging" help Say Y to include support for prevent battery swelling with self discharging + If you want to get debugging code for no chip, ask to VE GROUP. + +config BATTERY_SWELLING_SELF_DISCHARGING_ZERO_ONLY + bool "prevent battery swelling with self discharging only in zero" + default n + depends on BATTERY_SWELLING_SELF_DISCHARGING + help + Say Y to include supporting feature regarding preventing battery swelling. + It's only eligible for Zero projects, and it autonomously chooses the way of discharging + between AP policy method and discharging IC one. config INBATTERY bool "prevent inbattery" @@ -38,6 +48,13 @@ config CALC_TIME_TO_FULL help Say Y to use calc time to full function. +config BATTERY_AGE_FORECAST + tristate "battery age forecast" + default n + depends on BATTERY_SWELLING + help + Say Y to use calc time to full function. + # Fuel Gauge config FUELGAUGE_DUMMY @@ -318,6 +335,20 @@ config WIRELESS_CHARGER_INBATTERY_CS100 Say Y here to enable support for the wireless charger charger driver. +config WIRELESS_CHARGER_INBATTERY_5V_FIX + tristate "wireless charger in battery had 5.0V voreg" + depends on BATTERY_SAMSUNG && I2C + help + Say Y here to enable support for the wireless charger charger + driver. + +config WIRELESS_CHARGER_HIGH_VOLTAGE + tristate "high voltage wireless charger" + depends on BATTERY_SAMSUNG && I2C + help + Say Y here to enable support for the wireless charger charger + driver. + config WIRELESS_CHARGER_BQ51221 tristate "bq51221 battery charger support" depends on BATTERY_SAMSUNG && I2C @@ -325,10 +356,38 @@ config WIRELESS_CHARGER_BQ51221 Say Y here to enable support for the bq51221 charger bq51221 wireless charger driver. +config WIRELESS_CHARGER_P9027S + tristate "p9027s battery charger support" + depends on BATTERY_SAMSUNG && I2C + help + Say Y here to enable support for the p9027s charger + p9027s wireless charger driver. + +config WIRELESS_CHARGER_P9220 + tristate "p9220 battery charger support" + depends on BATTERY_SAMSUNG && I2C + help + Say Y here to enable support for the p9220 charger + p9220 wireless charger driver. + +config WIRELESS_FIRMWARE_UPDATE + tristate "p9220 battery charger support" + depends on WIRELESS_CHARGER_P9220 + help + Say Y here to enable support for the p9220 charger firmware update + p9220 wireless charger IC firmware update. + +config WIRELESS_CHARGER_MAX77900 + tristate "max77900 battery charger support" + depends on BATTERY_SAMSUNG && I2C + help + Say Y here to enable support for the max77900 charger + max77900 wireless charger driver. + config AFC_CHARGER_MODE bool "afc charging support in sec battery driver" default n - depends on CHARGER_MAX77843 + depends on BATTERY_SAMSUNG help Say Y to include support for sec afc charging support @@ -341,6 +400,12 @@ config SAMSUNG_LPM_MODE Before enable this feature, implemet power off charging in the bootloader. +config WIRELESS_CHARGER_THM + bool "Support wpc thermistor in sec battery driver" + default n + help + Say Y to include support for wpc thermistor + config EN_OOPS bool "enable oops filter" default n @@ -362,4 +427,4 @@ config FIX_CHG_FQ_4MHZ default n depends on CHARGER_MAX77843 help - Say Y to fix charging frequency 4MHz \ No newline at end of file + Say Y to fix charging frequency 4MHz diff --git a/drivers/battery/Makefile b/drivers/battery/Makefile index 2d39a4b6a3a1..bcd83af1eab7 100644 --- a/drivers/battery/Makefile +++ b/drivers/battery/Makefile @@ -22,3 +22,12 @@ obj-$(CONFIG_CHARGER_MAX77888) += max77888_charger.o obj-$(CONFIG_CHARGER_MAX77833) += max77833_charger.o obj-$(CONFIG_CHARGER_S2MU003) += s2mu003_charger.o obj-$(CONFIG_WIRELESS_CHARGER_BQ51221) += bq51221_charger.o +obj-$(CONFIG_WIRELESS_CHARGER_P9220) += p9220_charger.o +obj-$(CONFIG_WIRELESS_CHARGER_MAX77900) += max77900_charger.o +ifeq ($(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING),y) +obj-y += sec_batt_selfdchg_common.o sec_batt_selfdchg_ic_use.o +ifeq ($(CONFIG_MACH_UNIVERSAL7420),y) +obj-y += sec_batt_selfdchg_exynos7420_ap_use.o +#obj-y += sec_batt_selfdchg_exynos7420_cs_use.o +endif +endif diff --git a/drivers/battery/bq51221_charger.c b/drivers/battery/bq51221_charger.c index b11148f30b64..10f4dd39efb4 100644 --- a/drivers/battery/bq51221_charger.c +++ b/drivers/battery/bq51221_charger.c @@ -191,6 +191,10 @@ int bq51221_set_voreg(struct i2c_client *client, int default_value) union power_supply_propval value; struct bq51221_charger_data *charger = i2c_get_clientdata(client); +#if defined(CONFIG_WIRELESS_CHARGER_INBATTERY_5V_FIX) + return 0; +#endif + if (charger->pdata->pad_mode == BQ51221_PAD_MODE_PMA) { pr_info("%s PMA MODE, do not set Voreg \n", __func__); return 0; @@ -241,51 +245,84 @@ int bq51221_set_voreg(struct i2c_client *client, int default_value) return ret; } -int bq51221_set_over_temperuture_info(struct i2c_client *client) +int bq51221_set_end_power_transfer(struct i2c_client *client, int ept_mode) { + int pad_mode = 0; int data = 0; int ret = 0; pr_info("%s\n", __func__); - /* read pad mode PMA = 1, WPC = 0 (Status bit)*/ - pad_mode = bq51221_reg_read(client, BQ51221_REG_INDICATOR); + switch(ept_mode) + { + case END_POWER_TRANSFER_CODE_OVER_TEMPERATURE: + /* read pad mode PMA = 1, WPC = 0 (Status bit)*/ + pad_mode = bq51221_reg_read(client, BQ51221_REG_INDICATOR); + pr_info("%s pad_mode = %d \n", __func__,pad_mode); - pr_info("%s pad_mode = %d \n", __func__,pad_mode); + if(pad_mode > 0) + pad_mode &= BQ51221_POWER_MODE_MASK; - if(pad_mode > 0) - pad_mode &= BQ51221_POWER_MODE_MASK; + if(pad_mode) { + pr_info("%s PMA MODE, send EOC \n", __func__); - if(pad_mode) { - pr_info("%s PMA MODE, send EOC \n", __func__); + data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); + data |= BQ51221_SEND_EOC_MASK; + ret = bq51221_reg_write(client, BQ51221_REG_MAILBOX, data); + } else { + pr_info("%s WPC MODE, send EPT-OT \n", __func__); - data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); - data |= BQ51221_SEND_EOC_MASK; - ret = bq51221_reg_write(client, BQ51221_REG_MAILBOX, data); - } else { - pr_info("%s WPC MODE, send EPT-OT \n", __func__); + ret = bq51221_reg_write(client, BQ51221_REG_USER_HEADER, BQ51221_EPT_HEADER_EPT); + ret = bq51221_reg_write(client, BQ51221_REG_PROP_PACKET_PAYLOAD, BQ51221_EPT_CODE_OVER_TEMPERATURE); - ret = bq51221_reg_write(client, BQ51221_REG_USER_HEADER, BQ51221_EPT_HEADER_EPT); - ret = bq51221_reg_write(client, BQ51221_REG_PROP_PACKET_PAYLOAD, BQ51221_EPT_CODE_OVER_TEMPERATURE); + /* send end packet */ + data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); + data &= !BQ51221_SEND_USER_PKT_DONE_MASK; + ret = bq51221_reg_write(client, BQ51221_REG_MAILBOX, data); - /* send end packet */ - data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); - data &= !BQ51221_SEND_USER_PKT_DONE_MASK; - ret = bq51221_reg_write(client, BQ51221_REG_MAILBOX, data); + /* check packet error */ + data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); + data &= BQ51221_SEND_USER_PKT_ERR_MASK; + data = data >> 5; - /* check packet error */ - data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); - data &= BQ51221_SEND_USER_PKT_ERR_MASK; - data = data >> 5; + pr_info("%s error pkt = 0x%x \n",__func__, data); - pr_info("%s error pkt = 0x%x \n",__func__, data); + if(data != BQ51221_PTK_ERR_NO_ERR) { + pr_err("%s can not send ept! err pkt = 0x%x\n",__func__, data); + ret = -1; + } + } + break; + case END_POWER_TRANSFER_CODE_RECONFIGURE: + pr_info("%s send EPT-Reconfigure \n", __func__); - if(data != BQ51221_PTK_ERR_NO_ERR) { - pr_err("%s can not send CS100! err pkt = 0x%x\n",__func__, data); + ret = bq51221_reg_write(client, BQ51221_REG_USER_HEADER, BQ51221_EPT_HEADER_EPT); + ret = bq51221_reg_write(client, BQ51221_REG_PROP_PACKET_PAYLOAD, BQ51221_EPT_CODE_RECONFIGURE); + + /* send end packet */ + data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); + data &= !BQ51221_SEND_USER_PKT_DONE_MASK; + ret = bq51221_reg_write(client, BQ51221_REG_MAILBOX, data); + + /* check packet error */ + data = bq51221_reg_read(client, BQ51221_REG_MAILBOX); + data &= BQ51221_SEND_USER_PKT_ERR_MASK; + data = data >> 5; + + pr_info("%s error pkt = 0x%x \n",__func__, data); + + if(data != BQ51221_PTK_ERR_NO_ERR) { + pr_err("%s can not send ept! err pkt = 0x%x\n",__func__, data); + ret = -1; + } + break; + default: + pr_info("%s this ept mode is not reserved \n",__func__); ret = -1; - } + break; } + return ret; } @@ -386,10 +423,13 @@ static int bq51221_chg_set_property(struct power_supply *psy, bq51221_set_voreg(charger->client, val->intval); break; case POWER_SUPPLY_PROP_HEALTH: - if(val->intval == POWER_SUPPLY_HEALTH_OVERHEAT || POWER_SUPPLY_HEALTH_OVERHEATLIMIT) { - bq51221_set_over_temperuture_info(charger->client); - } - break; + if(val->intval == POWER_SUPPLY_HEALTH_OVERHEAT || + val->intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT || + val->intval == POWER_SUPPLY_HEALTH_COLD) + bq51221_set_end_power_transfer(charger->client, END_POWER_TRANSFER_CODE_OVER_TEMPERATURE); + else if(val->intval == POWER_SUPPLY_HEALTH_UNDERVOLTAGE) + bq51221_set_end_power_transfer(charger->client, END_POWER_TRANSFER_CODE_RECONFIGURE); + break; case POWER_SUPPLY_PROP_ONLINE: if(val->intval == POWER_SUPPLY_TYPE_WIRELESS) { charger->pdata->pad_mode = BQ51221_PAD_MODE_WPC; diff --git a/drivers/battery/max17048_fuelgauge.c b/drivers/battery/max17048_fuelgauge.c index 72291ddacbec..7920cf02463e 100644 --- a/drivers/battery/max17048_fuelgauge.c +++ b/drivers/battery/max17048_fuelgauge.c @@ -524,10 +524,10 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: val->intval = max17048_get_avg_vcell(client); break; - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = max17048_get_ocv(client); break; } diff --git a/drivers/battery/max17050_fuelgauge.c b/drivers/battery/max17050_fuelgauge.c index 0539e911aa12..b848d6e46786 100644 --- a/drivers/battery/max17050_fuelgauge.c +++ b/drivers/battery/max17050_fuelgauge.c @@ -406,10 +406,10 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: val->intval = max17050_get_avgvcell(client); break; - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = max17050_get_vfocv(client); break; } @@ -1065,10 +1065,10 @@ static int fg_read_current(struct i2c_client *client, int unit) /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: i_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: i_current = temp * 15625 / 100000; } @@ -1121,10 +1121,10 @@ static int fg_read_avg_current(struct i2c_client *client, int unit) /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: avg_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: avg_current = temp * 15625 / 100000; } @@ -1150,8 +1150,8 @@ int fg_reset_soc(struct i2c_client *client) fg_read_vfsoc(client), fg_read_soc(client)); dev_info(&client->dev, "%s: Before quick-start - current(%d), avg current(%d)\n", - __func__, fg_read_current(client, SEC_BATTEY_CURRENT_MA), - fg_read_avg_current(client, SEC_BATTEY_CURRENT_MA)); + __func__, fg_read_current(client, SEC_BATTERY_CURRENT_MA), + fg_read_avg_current(client, SEC_BATTERY_CURRENT_MA)); if (!fuelgauge->pdata->check_jig_status()) { dev_info(&client->dev, @@ -1184,8 +1184,8 @@ int fg_reset_soc(struct i2c_client *client) fg_read_vfsoc(client), fg_read_soc(client)); dev_info(&client->dev, "%s: After quick-start - current(%d), avg current(%d)\n", - __func__, fg_read_current(client, SEC_BATTEY_CURRENT_MA), - fg_read_avg_current(client, SEC_BATTEY_CURRENT_MA)); + __func__, fg_read_current(client, SEC_BATTERY_CURRENT_MA), + fg_read_avg_current(client, SEC_BATTERY_CURRENT_MA)); fg_write_register(client, CYCLES_REG, 0x00a0); /* P8 is not turned off by Quickstart @3.4V @@ -1361,11 +1361,11 @@ int get_fuelgauge_value(struct i2c_client *client, int data) break; case FG_CURRENT: - ret = fg_read_current(client, SEC_BATTEY_CURRENT_MA); + ret = fg_read_current(client, SEC_BATTERY_CURRENT_MA); break; case FG_CURRENT_AVG: - ret = fg_read_avg_current(client, SEC_BATTEY_CURRENT_MA); + ret = fg_read_avg_current(client, SEC_BATTERY_CURRENT_MA); break; case FG_CHECK_STATUS: @@ -1825,7 +1825,7 @@ int low_batt_compensation(struct i2c_client *client, /* Not charging, Under low battery comp voltage */ if (fg_vcell <= get_battery_data(fuelgauge).low_battery_comp_voltage) { fg_avg_current = fg_read_avg_current(client, - SEC_BATTEY_CURRENT_MA); + SEC_BATTERY_CURRENT_MA); fg_min_current = min(fg_avg_current, fg_current); table_size = @@ -2262,10 +2262,10 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = fg_read_vfocv(client); break; - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: default: val->intval = fg_read_avg_vcell(client); break; @@ -2274,11 +2274,11 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Current */ case POWER_SUPPLY_PROP_CURRENT_NOW: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = - fg_read_current(client, SEC_BATTEY_CURRENT_UA); + fg_read_current(client, SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: val->intval = get_fuelgauge_value(client, FG_CURRENT); break; @@ -2287,12 +2287,12 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Average Current */ case POWER_SUPPLY_PROP_CURRENT_AVG: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = fg_read_avg_current(client, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: val->intval = get_fuelgauge_value(client, FG_CURRENT_AVG); @@ -2302,16 +2302,16 @@ bool sec_hal_fg_get_property(struct i2c_client *client, /* Full Capacity */ case POWER_SUPPLY_PROP_ENERGY_NOW: switch (val->intval) { - case SEC_BATTEY_CAPACITY_DESIGNED: + case SEC_BATTERY_CAPACITY_DESIGNED: val->intval = get_fuelgauge_value(client, FG_FULLCAP); break; - case SEC_BATTEY_CAPACITY_ABSOLUTE: + case SEC_BATTERY_CAPACITY_ABSOLUTE: val->intval = get_fuelgauge_value(client, FG_MIXCAP); break; - case SEC_BATTEY_CAPACITY_TEMPERARY: + case SEC_BATTERY_CAPACITY_TEMPERARY: val->intval = get_fuelgauge_value(client, FG_AVCAP); break; - case SEC_BATTEY_CAPACITY_CURRENT: + case SEC_BATTERY_CAPACITY_CURRENT: val->intval = get_fuelgauge_value(client, FG_REPCAP); break; } diff --git a/drivers/battery/max77823_fuelgauge.c b/drivers/battery/max77823_fuelgauge.c index cd2bd9820103..d21b896a2d5f 100644 --- a/drivers/battery/max77823_fuelgauge.c +++ b/drivers/battery/max77823_fuelgauge.c @@ -714,10 +714,10 @@ static int fg_read_current(struct max77823_fuelgauge_data *fuelgauge, int unit) /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: i_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: i_current = temp * 15625 / 100000; } @@ -771,10 +771,10 @@ static int fg_read_avg_current(struct max77823_fuelgauge_data *fuelgauge, int un /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: avg_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: avg_current = temp * 15625 / 100000; } @@ -797,8 +797,8 @@ int fg_reset_soc(struct max77823_fuelgauge_data *fuelgauge) __func__, fg_read_vcell(fuelgauge), fg_read_vfocv(fuelgauge), fg_read_vfsoc(fuelgauge), fg_read_soc(fuelgauge)); pr_info("%s: Before quick-start - current(%d), avg current(%d)\n", - __func__, fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); if (fuelgauge->pdata->check_jig_status || !fuelgauge->pdata->check_jig_status()) { @@ -830,8 +830,8 @@ int fg_reset_soc(struct max77823_fuelgauge_data *fuelgauge) __func__, fg_read_vcell(fuelgauge), fg_read_vfocv(fuelgauge), fg_read_vfsoc(fuelgauge), fg_read_soc(fuelgauge)); pr_info("%s: After quick-start - current(%d), avg current(%d)\n", - __func__, fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); max77823_write_word(fuelgauge->i2c, CYCLES_REG, 0x00a0); @@ -950,11 +950,11 @@ int get_fuelgauge_value(struct max77823_fuelgauge_data *fuelgauge, int data) break; case FG_CURRENT: - ret = fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case FG_CURRENT_AVG: - ret = fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case FG_CHECK_STATUS: @@ -1400,7 +1400,7 @@ int low_batt_compensation(struct max77823_fuelgauge_data *fuelgauge, /* Not charging, Under low battery comp voltage */ if (fg_vcell <= fuelgauge->battery_data->low_battery_comp_voltage) { fg_avg_current = fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_MA); + SEC_BATTERY_CURRENT_MA); fg_min_current = min(fg_avg_current, fg_current); table_size = @@ -1899,10 +1899,10 @@ static int max77823_fg_get_property(strcut power_supply *psy, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: val->intval = max77823_get_avgvcell(fuelgauge); break; - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = max77823_get_vfocv(fuelgauge); break; } @@ -2043,10 +2043,10 @@ static int max77823_fg_get_property(struct power_supply *psy, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = fg_read_vfocv(fuelgauge); break; - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: default: val->intval = fg_read_avg_vcell(fuelgauge); break; @@ -2055,12 +2055,12 @@ static int max77823_fg_get_property(struct power_supply *psy, /* Current */ case POWER_SUPPLY_PROP_CURRENT_NOW: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = fg_read_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: val->intval = get_fuelgauge_value(fuelgauge, FG_CURRENT); @@ -2070,12 +2070,12 @@ static int max77823_fg_get_property(struct power_supply *psy, /* Average Current */ case POWER_SUPPLY_PROP_CURRENT_AVG: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: val->intval = get_fuelgauge_value(fuelgauge, @@ -2086,19 +2086,19 @@ static int max77823_fg_get_property(struct power_supply *psy, /* Full Capacity */ case POWER_SUPPLY_PROP_ENERGY_NOW: switch (val->intval) { - case SEC_BATTEY_CAPACITY_DESIGNED: + case SEC_BATTERY_CAPACITY_DESIGNED: val->intval = get_fuelgauge_value(fuelgauge, FG_FULLCAP); break; - case SEC_BATTEY_CAPACITY_ABSOLUTE: + case SEC_BATTERY_CAPACITY_ABSOLUTE: val->intval = get_fuelgauge_value(fuelgauge, FG_MIXCAP); break; - case SEC_BATTEY_CAPACITY_TEMPERARY: + case SEC_BATTERY_CAPACITY_TEMPERARY: val->intval = get_fuelgauge_value(fuelgauge, FG_AVCAP); break; - case SEC_BATTEY_CAPACITY_CURRENT: + case SEC_BATTERY_CAPACITY_CURRENT: val->intval = get_fuelgauge_value(fuelgauge, FG_REPCAP); break; diff --git a/drivers/battery/max77833_charger.c b/drivers/battery/max77833_charger.c index c728f88b6c91..cb6865baa4ff 100644 --- a/drivers/battery/max77833_charger.c +++ b/drivers/battery/max77833_charger.c @@ -19,6 +19,12 @@ #ifdef CONFIG_USB_HOST_NOTIFY #include #endif +#if defined(CONFIG_VBUS_NOTIFIER) +#include +#endif +#include + +extern unsigned int lpcharge; #define ENABLE 1 #define DISABLE 0 @@ -35,12 +41,13 @@ static enum power_supply_property max77833_charger_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, POWER_SUPPLY_PROP_USB_HC, -#if defined(CONFIG_BATTERY_SWELLING) +#if defined(CONFIG_BATTERY_SWELLING) || defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) POWER_SUPPLY_PROP_VOLTAGE_MAX, #endif #if defined(CONFIG_AFC_CHARGER_MODE) POWER_SUPPLY_PROP_AFC_CHARGER_MODE, #endif + POWER_SUPPLY_PROP_CHARGE_NOW, }; static struct device_attribute max77833_charger_attrs[] = { @@ -95,7 +102,7 @@ static void max77833_test_read(struct max77833_charger_data *charger) { u8 data = 0; u32 addr = 0; - for (addr = 0x80; addr <= 0x9D; addr++) { + for (addr = 0x81; addr <= 0x9D; addr++) { max77833_read_reg(charger->i2c, addr, &data); pr_debug("MAX77833 addr : 0x%02x data : 0x%02x\n", addr, data); } @@ -104,16 +111,25 @@ static void max77833_test_read(struct max77833_charger_data *charger) static int max77833_get_vbus_state(struct max77833_charger_data *charger) { u8 reg_data; + union power_supply_propval value; max77833_read_reg(charger->i2c, MAX77833_CHG_REG_DTLS_00, ®_data); - if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) + psy_do_property("battery", get, POWER_SUPPLY_PROP_ONLINE, + value); + +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) + reg_data = ((reg_data & MAX77833_CHGIN_DTLS) >> + MAX77833_CHGIN_DTLS_SHIFT); +#else + if (value.intval == POWER_SUPPLY_TYPE_WIRELESS) reg_data = ((reg_data & MAX77833_WCIN_DTLS) >> - MAX77833_WCIN_DTLS_SHIFT); + MAX77833_WCIN_DTLS_SHIFT); else reg_data = ((reg_data & MAX77833_CHGIN_DTLS) >> - MAX77833_CHGIN_DTLS_SHIFT); + MAX77833_CHGIN_DTLS_SHIFT); +#endif switch (reg_data) { case 0x00: @@ -226,6 +242,10 @@ static int max77833_get_charging_health(struct max77833_charger_data *charger) break; } +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) + return (int)state; +#endif + if (state == POWER_SUPPLY_HEALTH_GOOD) { union power_supply_propval value; psy_do_property("battery", get, @@ -282,13 +302,17 @@ static int max77833_get_charging_health(struct max77833_charger_data *charger) } else state = POWER_SUPPLY_HEALTH_GOOD; } - } else if (((vbus_state == 0x0) || (vbus_state == 0x01)) || \ - ((chg_dtls & 0x08) && \ - (chg_cnfg_00 & MAX77833_MODE_BUCK) && \ - (chg_cnfg_00 & MAX77833_MODE_CHGR) && \ - (charger->cable_type != POWER_SUPPLY_TYPE_WIRELESS))) { + } else if (((vbus_state == 0x0) || (vbus_state == 0x01)) && (chg_dtls & 0x08) && \ + (chg_cnfg_00 & MAX77833_MODE_BUCK) && \ + (chg_cnfg_00 & MAX77833_MODE_CHGR) && \ + (charger->cable_type != POWER_SUPPLY_TYPE_WIRELESS)) { pr_info("%s: vbus is under\n", __func__); state = POWER_SUPPLY_HEALTH_UNDERVOLTAGE; + } else if ((value.intval == POWER_SUPPLY_HEALTH_UNDERVOLTAGE) && \ + ((vbus_state == 0x0) || (vbus_state == 0x01)) && \ + (charger->cable_type != POWER_SUPPLY_TYPE_WIRELESS)) { + pr_info("%s: keep under-voltage\n", __func__); + state = POWER_SUPPLY_HEALTH_UNDERVOLTAGE; } } @@ -314,6 +338,18 @@ static int max77833_get_input_current(struct max77833_charger_data *charger) u8 reg_data; int get_current = 0; +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) + max77833_read_reg(charger->i2c, + MAX77833_CHG_REG_CNFG_16, ®_data); + /* AND operation for removing the formal 1bit */ + + if (reg_data <= 0x3) + get_current = 75; + else if (reg_data >= 0xA0) + get_current = 4000; + else + get_current = reg_data * 25; +#else if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { max77833_read_reg(charger->i2c, MAX77833_CHG_REG_CNFG_17, ®_data); @@ -338,7 +374,7 @@ static int max77833_get_input_current(struct max77833_charger_data *charger) else get_current = reg_data * 25; } - +#endif return get_current; } @@ -371,8 +407,7 @@ static void max77833_set_buck(struct max77833_charger_data *charger, if (enable) { max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, - CHG_CNFG_00_BUCK_MASK, - CHG_CNFG_00_OTG_CTRL | CHG_CNFG_00_BUCK_MASK); + CHG_CNFG_00_BUCK_MASK, CHG_CNFG_00_BUCK_MASK); } else { max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, 0, CHG_CNFG_00_BUCK_MASK); @@ -381,11 +416,68 @@ static void max77833_set_buck(struct max77833_charger_data *charger, pr_debug("%s : CHG_CNFG_00(0x%02x)\n", __func__, reg_data); } +static void max77833_check_slow_charging(struct max77833_charger_data *charger, + int input_current) +{ + /* under 400mA considered as slow charging concept for VZW */ + if (input_current <= SLOW_CHARGING_CURRENT_STANDARD && + charger->cable_type != POWER_SUPPLY_TYPE_BATTERY) { + union power_supply_propval value; + + charger->aicl_on = true; + pr_info("%s: slow charging on : input current(%dmA), cable type(%d)\n", + __func__, input_current, charger->cable_type); + + psy_do_property("battery", set, + POWER_SUPPLY_PROP_CHARGE_TYPE, value); + } + else + charger->aicl_on = false; +} + +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) static void max77833_set_input_current(struct max77833_charger_data *charger, int input_current) { u8 set_reg, reg_data; + mutex_lock(&charger->charger_mutex); + + set_reg = MAX77833_CHG_REG_CNFG_16; + max77833_read_reg(charger->i2c, + set_reg, ®_data); + + if (input_current <= 0) + max77833_set_buck(charger, DISABLE); + else + max77833_set_buck(charger, ENABLE); + + if (!input_current) { + max77833_write_reg(charger->i2c, + set_reg, reg_data); + } else { + input_current = (input_current > charger->charging_current_max) ? + charger->charging_current_max : input_current; + + if (input_current >= 4000) + reg_data = 0xA0; + else + reg_data = input_current / 25; + max77833_write_reg(charger->i2c, + set_reg, reg_data); + } + + mutex_unlock(&charger->charger_mutex); + pr_info("[%s] REG(0x%02x) DATA(0x%02x)\n", + __func__, set_reg, reg_data); +} +#else +static void max77833_set_input_current(struct max77833_charger_data *charger, + int input_current) +{ + u8 set_reg, reg_data; + + mutex_lock(&charger->charger_mutex); if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { set_reg = MAX77833_CHG_REG_CNFG_17; max77833_read_reg(charger->i2c, @@ -413,6 +505,9 @@ static void max77833_set_input_current(struct max77833_charger_data *charger, max77833_write_reg(charger->i2c, set_reg, reg_data); } else { + input_current = (input_current > charger->charging_current_max) ? + charger->charging_current_max : input_current; + if (input_current >= 4000) reg_data = 0xA0; else @@ -421,29 +516,11 @@ static void max77833_set_input_current(struct max77833_charger_data *charger, set_reg, reg_data); } + mutex_unlock(&charger->charger_mutex); pr_info("[%s] REG(0x%02x) DATA(0x%02x)\n", __func__, set_reg, reg_data); } - -static void afc_detect_work(struct work_struct *work) -{ - struct max77833_charger_data *charger = container_of(work, - struct max77833_charger_data, - afc_work.work); - int set_input_current; - - pr_info("%s\n", __func__); - - if (charger->cable_type == POWER_SUPPLY_TYPE_MAINS) { - charger->afc_detect = false; - if (charger->siop_level < 100) - set_input_current = SIOP_INPUT_LIMIT_CURRENT; - else - set_input_current = charger->charging_current_max; - - max77833_set_input_current(charger, set_input_current); - } -} +#endif static void max77833_set_charge_current(struct max77833_charger_data *charger, int fast_charging_current) @@ -456,7 +533,7 @@ static void max77833_set_charge_current(struct max77833_charger_data *charger, if (!fast_charging_current) { max77833_write_reg(charger->i2c, - MAX77833_CHG_REG_CNFG_05, 0x00); + MAX77833_CHG_REG_CNFG_05, 0x08); } else { reg_data = fast_charging_current / curr_step; max77833_write_reg(charger->i2c,MAX77833_CHG_REG_CNFG_05, reg_data); @@ -467,6 +544,88 @@ static void max77833_set_charge_current(struct max77833_charger_data *charger, reg_data, fast_charging_current); } +static int max77833_check_aicl_state(struct max77833_charger_data *charger) +{ + u8 aicl_state; + if (!max77833_read_reg(charger->i2c, MAX77833_CHG_REG_INT_OK, &aicl_state)) { + pr_info("%s aicl state \n", __func__); + return !(aicl_state & 0x80); + } + return 0; +} + +static void max77833_set_current(struct max77833_charger_data *charger) +{ + int current_now = charger->charging_current, + current_max = charger->charging_current_max; + int usb_charging_current = charger->pdata->charging_current[ + POWER_SUPPLY_TYPE_USB].fast_charging_current; + + pr_info("%s: siop_level=%d, afc_detec=%d, current_max=%d, current_now=%d\n", + __func__, charger->siop_level, charger->afc_detect, current_max, current_now); + + if (charger->is_charging) { + /* decrease the charging current according to siop level */ + current_now = current_now * charger->siop_level / 100; + + /* do forced set charging current */ + if (current_now > 0 && current_now < usb_charging_current) + current_now = usb_charging_current; + + if (charger->siop_level < 100) { + if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { + current_max = SIOP_WIRELESS_INPUT_LIMIT_CURRENT; + if (current_now > SIOP_WIRELESS_CHARGING_LIMIT_CURRENT) + current_now = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT; + } else if (charger->cable_type == POWER_SUPPLY_TYPE_HV_MAINS || + charger->cable_type == POWER_SUPPLY_TYPE_HV_ERR){ + if (current_max > SIOP_HV_INPUT_LIMIT_CURRENT) + current_max = SIOP_HV_INPUT_LIMIT_CURRENT; + if (current_now > SIOP_HV_CHARGING_LIMIT_CURRENT) + current_now = SIOP_HV_CHARGING_LIMIT_CURRENT; + } else { + if (current_max > SIOP_INPUT_LIMIT_CURRENT) + current_max = SIOP_INPUT_LIMIT_CURRENT; + if (current_now > SIOP_CHARGING_LIMIT_CURRENT) + current_now = SIOP_CHARGING_LIMIT_CURRENT; + } + } + } + + pr_info("%s: siop_level=%d, afc_detec=%d, current_max=%d, current_now=%d\n", + __func__, charger->siop_level, charger->afc_detect, current_max, current_now); + + if (max77833_check_aicl_state(charger)) { + wake_lock(&charger->aicl_wake_lock); + queue_delayed_work(charger->wqueue, &charger->aicl_work, + msecs_to_jiffies(50)); + } + + max77833_set_charge_current(charger, current_now); + max77833_set_input_current(charger, current_max); + + max77833_test_read(charger); +} + +static void afc_detect_work(struct work_struct *work) +{ + struct max77833_charger_data *charger = container_of(work, + struct max77833_charger_data, + afc_work.work); + pr_info("%s\n", __func__); + + if ((charger->cable_type == POWER_SUPPLY_TYPE_MAINS) && charger->is_charging && charger->afc_detect) { + charger->afc_detect = false; + + if (charger->charging_current_max >= INPUT_CURRENT_TA) { + charger->charging_current_max = charger->pdata->charging_current[ + POWER_SUPPLY_TYPE_MAINS].input_current_limit; + } + pr_info("%s: current_max(%d)\n", __func__, charger->charging_current_max); + max77833_set_current(charger); + } +} + static void max77833_set_topoff_current(struct max77833_charger_data *charger, int termination_current, int termination_time) @@ -474,13 +633,13 @@ static void max77833_set_topoff_current(struct max77833_charger_data *charger, int curr_base, curr_step; u8 reg_data; - curr_base = 125; - curr_step = 75; + curr_base = 150; + curr_step = 50; if (termination_current < curr_base) termination_current = curr_base; - else if (termination_current > 650) - termination_current = 650; + else if (termination_current > 500) + termination_current = 500; reg_data = (termination_current - curr_base) / curr_step; max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_02, @@ -499,7 +658,7 @@ static void max77833_set_charger_state(struct max77833_charger_data *charger, if (enable) { max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, - CHG_CNFG_00_CHG_MASK, CHG_CNFG_00_OTG_CTRL | CHG_CNFG_00_CHG_MASK); + CHG_CNFG_00_CHG_MASK, CHG_CNFG_00_CHG_MASK); } else { max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, 0, CHG_CNFG_00_CHG_MASK); @@ -508,30 +667,55 @@ static void max77833_set_charger_state(struct max77833_charger_data *charger, pr_debug("%s : CHG_CNFG_00(0x%02x)\n", __func__, reg_data); } +static void reduce_input_current(struct max77833_charger_data *charger, int cur) +{ + u8 set_value; + unsigned int min_input_current = 0; + + min_input_current = MINIMUM_INPUT_CURRENT; + if (!max77833_read_reg(charger->i2c, MAX77833_CHG_REG_CNFG_16, &set_value)) { + if ((set_value <= (min_input_current / charger->input_curr_limit_step)) || + (set_value <= (cur / charger->input_curr_limit_step))) + return; + set_value -= (cur / charger->input_curr_limit_step); + set_value = (set_value < (min_input_current / charger->input_curr_limit_step)) ? + (min_input_current / charger->input_curr_limit_step) : set_value; + max77833_write_reg(charger->i2c, MAX77833_CHG_REG_CNFG_16, set_value); + charger->charging_current_max = max77833_get_input_current(charger); + pr_info("%s: set current: reg:(0x%x), val:(0x%x), input_current(%d)\n", + __func__, MAX77833_CHG_REG_CNFG_16, set_value, charger->charging_current_max); + } +} static void max77833_charger_function_control( struct max77833_charger_data *charger) { - const int usb_charging_current = charger->pdata->charging_current[ - POWER_SUPPLY_TYPE_USB].fast_charging_current; - int set_charging_current, set_charging_current_max; u8 chg_cnfg_00 = 0; union power_supply_propval value; union power_supply_propval chg_mode; + union power_supply_propval swelling_state; psy_do_property("battery", get, POWER_SUPPLY_PROP_HEALTH, value); + pr_info("####%s####\n", __func__); + if (charger->cable_type == POWER_SUPPLY_TYPE_BATTERY || charger->cable_type == POWER_SUPPLY_TYPE_OTG) { charger->is_charging = false; charger->afc_detect = false; charger->aicl_on = false; charger->is_mdock = false; - set_charging_current = 0; - set_charging_current_max = - charger->pdata->charging_current[ - POWER_SUPPLY_TYPE_USB].input_current_limit; + charger->charging_current = 0; + + if ((charger->status == POWER_SUPPLY_STATUS_DISCHARGING) || + (value.intval == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) || + (value.intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) { + charger->charging_current_max = + ((value.intval == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) || \ + (value.intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) ? + 0 : charger->pdata->charging_current[POWER_SUPPLY_TYPE_USB].input_current_limit; + } if (charger->cable_type == POWER_SUPPLY_TYPE_OTG) { chg_cnfg_00 |= (CHG_CNFG_00_OTG_MASK @@ -556,13 +740,12 @@ static void max77833_charger_function_control( (CHG_CNFG_00_CHG_MASK | CHG_CNFG_00_OTG_MASK | CHG_CNFG_00_BOOST_MASK)); - - set_charging_current_max = - charger->pdata->charging_current[ - POWER_SUPPLY_TYPE_USB].input_current_limit; } } else { - charger->is_charging = true; + if (charger->cable_type == POWER_SUPPLY_TYPE_HMT_CONNECTED) + charger->is_charging = false; + else + charger->is_charging = true; charger->afc_detect = false; charger->charging_current_max = charger->pdata->charging_current @@ -591,39 +774,34 @@ static void max77833_charger_function_control( charger->is_mdock = true; } - /* decrease the charging current according to siop level */ - set_charging_current = - charger->charging_current * charger->siop_level / 100; - if (set_charging_current > 0 && - set_charging_current < usb_charging_current) - set_charging_current = usb_charging_current; - - set_charging_current_max = - charger->charging_current_max; - - if (charger->siop_level < 100) { - if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { - if (set_charging_current_max > SIOP_WIRELESS_INPUT_LIMIT_CURRENT) { - set_charging_current_max = SIOP_WIRELESS_INPUT_LIMIT_CURRENT; - if (set_charging_current > SIOP_WIRELESS_CHARGING_LIMIT_CURRENT) - set_charging_current = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT; - } - } else { - if (set_charging_current_max > SIOP_INPUT_LIMIT_CURRENT) { - set_charging_current_max = SIOP_INPUT_LIMIT_CURRENT; - if (set_charging_current > SIOP_CHARGING_LIMIT_CURRENT) - set_charging_current = SIOP_CHARGING_LIMIT_CURRENT; - } - } + if (charger->cable_type == POWER_SUPPLY_TYPE_MAINS) { + charger->afc_detect = true; + charger->charging_current_max = INPUT_CURRENT_TA; + queue_delayed_work(charger->wqueue, &charger->afc_work, msecs_to_jiffies(2000)); + wake_lock_timeout(&charger->afc_wake_lock, HZ * 3); } } + pr_info("charging = %d, fc = %d, il = %d, t1 = %d, t2 = %d, cable = %d\n", + charger->is_charging, + charger->charging_current, + charger->charging_current_max, + charger->pdata->charging_current[charger->cable_type].full_check_current_1st, + charger->pdata->charging_current[charger->cable_type].full_check_current_2nd, + charger->cable_type); + if (charger->pdata->full_check_type_2nd == SEC_BATTERY_FULLCHARGED_CHGPSY) { psy_do_property("battery", get, POWER_SUPPLY_PROP_CHARGE_NOW, chg_mode); - - if (chg_mode.intval == SEC_BATTERY_CHARGING_2ND) { +#if defined(CONFIG_BATTERY_SWELLING) + psy_do_property("battery", get, + POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, + swelling_state); +#else + swelling_state.intval = 0; +#endif + if (chg_mode.intval == SEC_BATTERY_CHARGING_2ND || swelling_state.intval) { max77833_set_charger_state(charger, 0); max77833_set_topoff_current(charger, charger->pdata->charging_current[ @@ -645,30 +823,6 @@ static void max77833_charger_function_control( max77833_set_charger_state(charger, charger->is_charging); - /* if battery full, only disable charging */ - if ((charger->status == POWER_SUPPLY_STATUS_CHARGING) || - (charger->status == POWER_SUPPLY_STATUS_DISCHARGING) || - (value.intval == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) || - (value.intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) { - /* current setting */ - max77833_set_charge_current(charger, - set_charging_current); - /* if battery is removed, disable input current and reenable input current - * to enable buck always */ - if ((value.intval == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) || - (value.intval == POWER_SUPPLY_HEALTH_OVERHEATLIMIT)) { - max77833_set_input_current(charger, 0); - } else if (charger->cable_type == POWER_SUPPLY_TYPE_MAINS) { - pr_info("TA!!!\n"); - charger->afc_detect = true; - max77833_set_input_current(charger, 1000); - queue_delayed_work(charger->wqueue, &charger->afc_work, - msecs_to_jiffies(2000)); - } else { - max77833_set_input_current(charger, - set_charging_current_max); - } - } pr_info("charging = %d, fc = %d, il = %d, t1 = %d, t2 = %d, cable = %d\n", charger->is_charging, @@ -715,20 +869,31 @@ static void max77833_charger_initialize(struct max77833_charger_data *charger) * MINVSYS 3.6V(default) */ reg_data = max77833_get_float_voltage_data(charger->pdata->chg_float_voltage); - max77833_write_word(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); + max77833_write_reg(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); + /* + * CHGIN falling AICL threshold 4.3V(default) + */ + reg_data = 0x03; + max77833_write_reg(charger->i2c, MAX77833_CHG_REG_CNFG_11, reg_data); + pr_info("%s: CHGIN AICL threshold 0x%x\n", __func__, reg_data); + + /* SYS_OCP_ACT = 0 */ + max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_15, 0, 1); + max77833_test_read(charger); } -#if defined(CONFIG_BATTERY_SWELLING) +#if defined(CONFIG_BATTERY_SWELLING) || defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) static void max77833_set_float_voltage(struct max77833_charger_data *charger, int float_voltage) { u8 reg_data = 0; reg_data = max77833_get_float_voltage_data(float_voltage); - max77833_write_word(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); - pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); + max77833_write_reg(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); + charger->pdata->chg_float_voltage = float_voltage; + pr_info("%s: battery cv voltage 0x%x, chg_float_voltage = %dmV \n", __func__, reg_data, charger->pdata->chg_float_voltage); } static u8 max77833_get_float_voltage(struct max77833_charger_data *charger) @@ -736,7 +901,7 @@ static u8 max77833_get_float_voltage(struct max77833_charger_data *charger) u8 reg_data = 0; max77833_read_reg(charger->i2c, MAX77833_CHG_REG_CNFG_06, ®_data); - pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); + pr_info("%s: battery cv voltage 0x%x, chg_float_voltage = %dmV \n", __func__, reg_data, charger->pdata->chg_float_voltage); return reg_data; } @@ -764,17 +929,12 @@ static int max77833_chg_create_attrs(struct device *dev) ssize_t max77833_chg_show_attrs(struct device *dev, struct device_attribute *attr, char *buf) { - struct power_supply *psy = dev_get_drvdata(dev); - struct max77833_charger_data *charger = - container_of(psy, struct max77833_charger_data, psy_chg); const ptrdiff_t offset = attr - max77833_charger_attrs; int i = 0; switch(offset) { - case MAX77833_CHIP_ID: - i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", - (charger->pmic_ver >= 0x1 && charger->pmic_ver <= 0x03) ? - "MAX77833" : "Unknown"); + case CHIP_ID: + i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n", "MAX77833"); break; default: return -EINVAL; @@ -790,7 +950,7 @@ ssize_t max77833_chg_store_attrs(struct device *dev, int ret = 0; switch(offset) { - case MAX77833_CHIP_ID: + case CHIP_ID: ret = count; break; default: @@ -814,7 +974,7 @@ static void max77833_chg_otype_check(struct max77833_charger_data *charger) max77833_write_reg(charger->i2c, MAX77833_CHG_REG_PROTECT, reg_data); reg_data = max77833_get_float_voltage_data(charger->pdata->chg_float_voltage); - max77833_write_word(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); + max77833_write_reg(charger->i2c, MAX77833_CHG_REG_CNFG_06, reg_data); pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); if (!charger->is_charging) { @@ -882,7 +1042,7 @@ static int max77833_chg_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: break; -#if defined(CONFIG_BATTERY_SWELLING) +#if defined(CONFIG_BATTERY_SWELLING) || defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = max77833_get_float_voltage(charger); break; @@ -895,6 +1055,28 @@ static int max77833_chg_get_property(struct power_supply *psy, return -ENODATA; case POWER_SUPPLY_PROP_USB_HC: return -ENODATA; + case POWER_SUPPLY_PROP_CHARGE_NOW: + max77833_read_reg(charger->i2c, + MAX77833_CHG_REG_DTLS_01, ®_data); + reg_data &= 0x0F; + switch (reg_data) { + case 0x01: + val->strval = "CC Mode"; + break; + case 0x02: + val->strval = "CV Mode"; + break; + case 0x03: + val->strval = "EOC"; + break; + case 0x04: + val->strval = "DONE"; + break; + default: + val->strval = "NONE"; + break; + } + break; default: return -EINVAL; } @@ -908,10 +1090,8 @@ static int max77833_chg_set_property(struct power_supply *psy, struct max77833_charger_data *charger = container_of(psy, struct max77833_charger_data, psy_chg); union power_supply_propval value; - int set_charging_current_max; - const int usb_charging_current = charger->pdata->charging_current[ - POWER_SUPPLY_TYPE_USB].fast_charging_current; u8 chg_cnfg_00 = 0; + static u8 chg_int_state; switch (psp) { /* val->intval : type */ @@ -936,6 +1116,7 @@ static int max77833_chg_set_property(struct power_supply *psy, charger->cable_type = val->intval; max77833_charger_function_control(charger); + max77833_set_current(charger); break; /* val->intval : input charging current */ case POWER_SUPPLY_PROP_CURRENT_MAX: @@ -944,6 +1125,12 @@ static int max77833_chg_set_property(struct power_supply *psy, break; /* val->intval : charging current */ case POWER_SUPPLY_PROP_CURRENT_AVG: +#if defined(CONFIG_BATTERY_SWELLING) + if (val->intval > charger->pdata->charging_current + [charger->cable_type].fast_charging_current) { + break; + } +#endif charger->charging_current = val->intval; max77833_set_charge_current(charger, val->intval); @@ -957,10 +1144,10 @@ static int max77833_chg_set_property(struct power_supply *psy, break; #if defined(CONFIG_AFC_CHARGER_MODE) case POWER_SUPPLY_PROP_AFC_CHARGER_MODE: -// max77833_hv_muic_charger_init(); + // max77833_hv_muic_charger_init(); break; #endif -#if defined(CONFIG_BATTERY_SWELLING) +#if defined(CONFIG_BATTERY_SWELLING) || defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) case POWER_SUPPLY_PROP_VOLTAGE_MAX: pr_info("%s: float voltage(%d)\n", __func__, val->intval); max77833_set_float_voltage(charger, val->intval); @@ -968,68 +1155,7 @@ static int max77833_chg_set_property(struct power_supply *psy, #endif case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: charger->siop_level = val->intval; - if (charger->is_charging) { - /* decrease the charging current according to siop level */ - int current_now = - charger->charging_current * val->intval / 100; - - /* do forced set charging current */ - if (current_now > 0 && - current_now < usb_charging_current) - current_now = usb_charging_current; - - if ((charger->cable_type == POWER_SUPPLY_TYPE_MAINS) || - (charger->cable_type == POWER_SUPPLY_TYPE_HV_MAINS) || - (charger->cable_type == POWER_SUPPLY_TYPE_HV_ERR)) { - if (charger->afc_detect) - set_charging_current_max = 1000; - else if (charger->siop_level < 100 ) - set_charging_current_max = SIOP_INPUT_LIMIT_CURRENT; - else - set_charging_current_max = - charger->charging_current_max; - - pr_info("%s: siop_level=%d, afc_detec=%d, current_max=%d, current_now=%d\n", - __func__, - charger->siop_level, charger->afc_detect, - set_charging_current_max, current_now); - if (charger->siop_level < 100 && - current_now > SIOP_CHARGING_LIMIT_CURRENT) - current_now = SIOP_CHARGING_LIMIT_CURRENT; - max77833_set_input_current(charger, - set_charging_current_max); - } else if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { - if (charger->siop_level < 100) - set_charging_current_max = SIOP_WIRELESS_INPUT_LIMIT_CURRENT; - else - set_charging_current_max = charger->charging_current_max; - - if (charger->siop_level < 100 && - current_now > SIOP_WIRELESS_CHARGING_LIMIT_CURRENT) - current_now = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT; - - max77833_set_input_current(charger, - set_charging_current_max); - } else { - if (charger->siop_level < 100) { - set_charging_current_max = - charger->charging_current_max * val->intval / 100; - if (set_charging_current_max > SIOP_INPUT_LIMIT_CURRENT) { - set_charging_current_max = SIOP_INPUT_LIMIT_CURRENT; - if (current_now > SIOP_CHARGING_LIMIT_CURRENT) - current_now = SIOP_CHARGING_LIMIT_CURRENT; - } - } else { - set_charging_current_max = - charger->charging_current_max; - } - max77833_set_input_current(charger, - set_charging_current_max); - } - - max77833_set_charge_current(charger, current_now); - - } + max77833_set_current(charger); break; case POWER_SUPPLY_PROP_USB_HC: /* set input/charging current for usb up to TA's current */ @@ -1056,29 +1182,45 @@ static int max77833_chg_set_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: if (val->intval) { - chg_cnfg_00 &= ~(CHG_CNFG_00_CHG_MASK - | CHG_CNFG_00_BUCK_MASK); - chg_cnfg_00 |= (CHG_CNFG_00_OTG_MASK - | CHG_CNFG_00_BOOST_MASK); - max77833_update_reg(charger->i2c, - MAX77833_CHG_REG_CNFG_00, - chg_cnfg_00, - (CHG_CNFG_00_CHG_MASK - | CHG_CNFG_00_OTG_MASK - | CHG_CNFG_00_BUCK_MASK - | CHG_CNFG_00_BOOST_MASK)); + max77833_read_reg(charger->i2c, MAX77833_CHG_REG_INT_MASK, + &chg_int_state); + + /* OTG_EN set to HIGH */ + if (charger->pdata->otg_en) + gpio_direction_output(charger->pdata->otg_en, 1); + + /* eable charger interrupt: CHG_I, CHGIN_I */ + /* enable charger interrupt: BYP_I */ + max77833_update_reg(charger->i2c, MAX77833_CHG_REG_INT_MASK, + 0, + MAX77833_CHG_IM | MAX77833_CHGIN_IM | MAX77833_BYP_IM); + + /* OTG on, boost on */ + max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, + CHG_CNFG_00_OTG_CTRL, CHG_CNFG_00_OTG_CTRL); + } else { - chg_cnfg_00 = ~(CHG_CNFG_00_OTG_MASK - | CHG_CNFG_00_BOOST_MASK); - chg_cnfg_00 |= CHG_CNFG_00_BUCK_MASK; - max77833_update_reg(charger->i2c, - MAX77833_CHG_REG_CNFG_00, - chg_cnfg_00, - (CHG_CNFG_00_OTG_MASK - | CHG_CNFG_00_BUCK_MASK - | CHG_CNFG_00_BOOST_MASK)); + /* OTG_EN set to LOW */ + if (charger->pdata->otg_en) + gpio_direction_output(charger->pdata->otg_en, 0); + + /* OTG off, boost off, (buck on) */ + max77833_update_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, + CHG_CNFG_00_BUCK_MASK, CHG_CNFG_00_BUCK_MASK | CHG_CNFG_00_OTG_CTRL); + + + /* enable charger interrupt */ + max77833_write_reg(charger->i2c, + MAX77833_CHG_REG_INT_MASK, chg_int_state); } + max77833_read_reg(charger->i2c, MAX77833_CHG_REG_INT_MASK, + &chg_int_state); + max77833_read_reg(charger->i2c, MAX77833_CHG_REG_CNFG_00, + &chg_cnfg_00); + pr_info("%s: INT_MASK(0x%x), CHG_CNFG_00(0x%x)\n", + __func__, chg_int_state, chg_cnfg_00); break; + case POWER_SUPPLY_PROP_CHARGE_NOW: default: return -EINVAL; } @@ -1188,6 +1330,35 @@ static void max77833_chg_isr_work(struct work_struct *work) } } +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) +static irqreturn_t max77833_chg_irq_thread(int irq, void *irq_data) +{ + struct max77833_charger_data *charger = irq_data; + unsigned long delay; + union power_supply_propval value; + + pr_info("%s: Charger interrupt occured \n", __func__); + + value.intval = 1; +#if defined(CONFIG_WIRELESS_CHARGER_MAX77900) + psy_do_property("max77900-charger", set, + POWER_SUPPLY_PROP_STATUS, value); +#endif + +#ifdef CONFIG_SAMSUNG_BATTERY_FACTORY + delay = msecs_to_jiffies(0); +#else + if (charger->wc_w_state) + delay = msecs_to_jiffies(500); + else + delay = msecs_to_jiffies(500); +#endif + queue_delayed_work(charger->wqueue, &charger->wpc_work, + delay); + + return IRQ_HANDLED; +} +#else static irqreturn_t max77833_chg_irq_thread(int irq, void *irq_data) { struct max77833_charger_data *charger = irq_data; @@ -1202,7 +1373,68 @@ static irqreturn_t max77833_chg_irq_thread(int irq, void *irq_data) return IRQ_HANDLED; } +#endif +#if defined(CONFIG_WIRELESS_CHARGER_HIGH_VOLTAGE) +static void wpc_detect_work(struct work_struct *work) +{ + struct max77833_charger_data *charger = container_of(work, + struct max77833_charger_data, + wpc_work.work); + int wc_w_state; + //int retry_cnt; + union power_supply_propval value; + u8 reg_data; + + pr_info("%s\n", __func__); + + /* check and unlock */ + check_charger_unlock_state(charger); +#if defined(CONFIG_WIRELESS_CHARGER_P9220) + wc_w_state = !gpio_get_value(charger->pdata->irq_gpio); +#else + wc_w_state = gpio_get_value(charger->pdata->wpc_det); +#endif + pr_info("%s wc_w_state = %d \n", __func__, wc_w_state); + + if ((charger->wc_w_state == 0) && (wc_w_state == 1)) { + value.intval = 1; + psy_do_property("wireless", set, + POWER_SUPPLY_PROP_ONLINE, value); + value.intval = POWER_SUPPLY_TYPE_WIRELESS; +#if defined(CONFIG_WIRELESS_CHARGER_MAX77900) + psy_do_property("max77900-charger", set, + POWER_SUPPLY_PROP_ONLINE, value); +#else + psy_do_property("p9220-charger", set, + POWER_SUPPLY_PROP_ONLINE, value); +#endif + pr_info("%s: wpc activated, set V_INT as PN\n", + __func__); + } else if ((charger->wc_w_state == 1) && (wc_w_state == 0)) { + if (!charger->is_charging) + max77833_set_charger_state(charger, true); + + pr_info("%s: reg_data: 0x%x, charging: %d\n", __func__, + reg_data, charger->is_charging); + if (!charger->is_charging) + max77833_set_charger_state(charger, false); + + value.intval = 0; + psy_do_property("wireless", set, + POWER_SUPPLY_PROP_ONLINE, value); + pr_info("%s: wpc deactivated, set V_INT as PD\n", + __func__); + } + + pr_info("%s: w(%d to %d)\n", __func__, + charger->wc_w_state, wc_w_state); + + charger->wc_w_state = wc_w_state; + + wake_unlock(&charger->wpc_wake_lock); +} +#else static void wpc_detect_work(struct work_struct *work) { struct max77833_charger_data *charger = container_of(work, @@ -1278,6 +1510,7 @@ static void wpc_detect_work(struct work_struct *work) wake_unlock(&charger->wpc_wake_lock); } +#endif static irqreturn_t wpc_charger_irq(int irq, void *data) { @@ -1383,6 +1616,53 @@ static irqreturn_t max77833_bypass_irq(int irq, void *data) return IRQ_HANDLED; } +static void max77833_aicl_work(struct work_struct *work) +{ + struct max77833_charger_data *charger = container_of(work, + struct max77833_charger_data, aicl_work.work); + + charger->afc_detect = false; + + if ((charger->is_charging) && + (charger->cable_type != POWER_SUPPLY_TYPE_WIRELESS)) { + int now_count = 0, + max_count = charger->charging_current_max / REDUCE_CURRENT_STEP; + int prev_current_max = charger->charging_current_max; + + mutex_lock(&charger->charger_mutex); + check_charger_unlock_state(charger); + + while (max77833_check_aicl_state(charger) && + (now_count++ < max_count) && (charger->is_charging) && + (charger->cable_type != POWER_SUPPLY_TYPE_WIRELESS)) { + reduce_input_current(charger, REDUCE_CURRENT_STEP); + msleep(50); + } + pr_info("%s: charging_current_max(%d --> %d)\n", + __func__, prev_current_max, charger->charging_current_max); + + if (prev_current_max > charger->charging_current_max) { + max77833_check_slow_charging(charger, charger->charging_current_max); + } + mutex_unlock(&charger->charger_mutex); + } + + wake_unlock(&charger->aicl_wake_lock); +} + +static irqreturn_t max77833_aicl_irq(int irq, void *data) +{ + struct max77833_charger_data *charger = data; + + pr_info("%s: irq(%d)\n", __func__, irq); + + wake_lock(&charger->aicl_wake_lock); + queue_delayed_work(charger->wqueue, &charger->aicl_work, + msecs_to_jiffies(50)); + + return IRQ_HANDLED; +} + static void max77833_chgin_isr_work(struct work_struct *work) { struct max77833_charger_data *charger = container_of(work, @@ -1423,6 +1703,22 @@ static void max77833_chgin_isr_work(struct work_struct *work) else stable_count = 0; if (stable_count > 10) { +#if defined(CONFIG_VBUS_NOTIFIER) + switch (chgin_dtls) { + case 0x03: + vbus_notifier_handle(STATUS_VBUS_HIGH); + break; + case 0x00: + case 0x01: + case 0x02: + vbus_notifier_handle(STATUS_VBUS_LOW); + break; + default: + pr_err("%s: unknown chgin_dtls(0x%x)\n", __func__, chgin_dtls); + vbus_notifier_handle(STATUS_VBUS_UNKNOWN); + break; + } +#endif pr_info("%s: irq(%d), chgin(0x%x), chg_dtls(0x%x) prev 0x%x\n", __func__, charger->irq_chgin, chgin_dtls, chg_dtls, prev_chgin_dtls); @@ -1516,6 +1812,7 @@ static int max77833_charger_parse_dt(struct max77833_charger_data *charger) int ret = 0; int i, len; const u32 *p; + u32 irq_gpio_flags; if (np == NULL) { pr_err("%s np NULL\n", __func__); @@ -1528,6 +1825,25 @@ static int max77833_charger_parse_dt(struct max77833_charger_data *charger) if (!np) { pr_err("%s np NULL\n", __func__); } else { + + ret = pdata->irq_gpio = of_get_named_gpio_flags(np, "battery,irq_gpio", + 0, &irq_gpio_flags); + if (ret < 0) + pr_err("%s : can't get irq-gpio \n", __FUNCTION__); + else { + pr_info("%s : irq_gpio = %d \n",__func__, pdata->irq_gpio); + pdata->chg_irq = gpio_to_irq(pdata->irq_gpio); + pr_info("%s : chg_irq = 0x%x \n",__func__, pdata->chg_irq); + } + + pdata->wpc_det = of_get_named_gpio(np, "battery,wpc_det", 0); + if (pdata->wpc_det < 0) + pdata->wpc_det = 0; + + pdata->otg_en = of_get_named_gpio(np, "battery,otg_en", 0); + if (pdata->otg_en < 0) + pdata->otg_en = 0; + ret = of_property_read_u32(np, "battery,full_check_type_2nd", &pdata->full_check_type_2nd); if (ret) @@ -1568,6 +1884,7 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) struct max77833_charger_data *charger; int ret = 0; u8 reg_data; + union power_supply_propval value; pr_info("%s: Max77833 Charger Driver Loading\n", __func__); @@ -1581,6 +1898,7 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) goto err_free; } + mutex_init(&charger->charger_mutex); charger->dev = &pdev->dev; charger->i2c = max77833->i2c; charger->pdata = pdata->charger_data; @@ -1588,7 +1906,9 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) charger->afc_detect = false; charger->is_mdock = false; charger->siop_level = 100; + charger->charging_current_max = 500; charger->max77833_pdata = pdata; + charger->input_curr_limit_step = 25; #if defined(CONFIG_OF) ret = max77833_charger_parse_dt(charger); @@ -1610,6 +1930,14 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) max77833_charger_initialize(charger); + if (charger->pdata->otg_en) { + ret = gpio_request(charger->pdata->otg_en, "OTG_EN"); + if (ret) { + pr_err("failed to request GPIO %u\n", charger->pdata->otg_en); + goto err_gpio; + } + } + if (max77833_read_reg(max77833->i2c, MAX77833_PMIC_REG_PMICREV, ®_data) < 0) { pr_err("device not found on this channel (this is not an error)\n"); ret = -ENOMEM; @@ -1634,9 +1962,15 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&charger->chgin_init_work, max77833_chgin_init_work); wake_lock_init(&charger->wpc_wake_lock, WAKE_LOCK_SUSPEND, "charger-wpc"); + wake_lock_init(&charger->afc_wake_lock, WAKE_LOCK_SUSPEND, + "charger-afc"); INIT_DELAYED_WORK(&charger->wpc_work, wpc_detect_work); INIT_DELAYED_WORK(&charger->afc_work, afc_detect_work); + wake_lock_init(&charger->aicl_wake_lock, WAKE_LOCK_SUSPEND, + "charger-aicl"); + INIT_DELAYED_WORK(&charger->aicl_work, max77833_aicl_work); + ret = power_supply_register(&pdev->dev, &charger->psy_chg); if (ret) { pr_err("%s: Failed to Register psy_chg\n", __func__); @@ -1648,7 +1982,8 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) ret = request_threaded_irq(charger->pdata->chg_irq, NULL, max77833_chg_irq_thread, - charger->pdata->chg_irq_attr, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "charger-irq", charger); if (ret) { pr_err("%s: Failed to Request IRQ\n", __func__); @@ -1696,9 +2031,24 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) ret = request_threaded_irq(charger->irq_batp, NULL, max77833_batp_irq, 0, "batp-irq", charger); - if (ret < 0) - pr_err("%s: fail to request bypass IRQ: %d: %d\n", + if (ret < 0) { + pr_err("%s: fail to request batp IRQ: %d: %d\n", __func__, charger->irq_batp, ret); + } else { + max77833_update_reg(charger->i2c, + MAX77833_CHG_REG_INT_MASK, 0, MAX77833_BATP_IM); + } + + charger->irq_aicl = pdata->irq_base + MAX77833_CHG_IRQ_AICL_I; + ret = request_threaded_irq(charger->irq_aicl, NULL, + max77833_aicl_irq, 0, "aicl-irq", charger); + if (ret < 0) { + pr_err("%s: fail to request aicl IRQ: %d: %d\n", + __func__, charger->irq_aicl, ret); + } else { + max77833_update_reg(charger->i2c, + MAX77833_CHG_REG_INT_MASK, 0, MAX77833_AICL_IM); + } ret = max77833_chg_create_attrs(charger->psy_chg.dev); if (ret) { @@ -1708,6 +2058,18 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) } pr_info("%s: MAX77833 Charger Driver Loaded\n", __func__); + if(lpcharge) { + if (gpio_get_value(charger->pdata->irq_gpio) == 0) { + pr_info("%s: Charger interrupt occured during lpm \n", __func__); + + value.intval = 1; + psy_do_property("max77900-charger", set, + POWER_SUPPLY_PROP_STATUS, value); + queue_delayed_work(charger->wqueue, &charger->wpc_work, + 500); + } + } + return 0; err_wc_irq: @@ -1717,7 +2079,11 @@ static int __devinit max77833_charger_probe(struct platform_device *pdev) err_power_supply_register: destroy_workqueue(charger->wqueue); err_pdata_free: + if (charger->pdata->otg_en) + gpio_free(charger->pdata->otg_en); +err_gpio: kfree(pdata->charger_data); + mutex_destroy(&charger->charger_mutex); err_free: kfree(charger); @@ -1733,6 +2099,7 @@ static int __devexit max77833_charger_remove(struct platform_device *pdev) free_irq(charger->wc_w_irq, NULL); free_irq(charger->pdata->chg_irq, NULL); power_supply_unregister(&charger->psy_chg); + mutex_destroy(&charger->charger_mutex); kfree(charger); return 0; diff --git a/drivers/battery/max77833_fuelgauge.c b/drivers/battery/max77833_fuelgauge.c index 3585157a16b9..4962dcf4f251 100644 --- a/drivers/battery/max77833_fuelgauge.c +++ b/drivers/battery/max77833_fuelgauge.c @@ -20,6 +20,9 @@ static enum power_supply_property max77833_fuelgauge_props[] = { POWER_SUPPLY_PROP_STATUS, +#if defined(CONFIG_BATTERY_AGE_FORECAST) + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, +#endif POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_AVG, POWER_SUPPLY_PROP_CURRENT_NOW, @@ -32,6 +35,9 @@ static enum power_supply_property max77833_fuelgauge_props[] = { #if defined(CONFIG_EN_OOPS) POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, #endif + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, }; #if !defined(CONFIG_SEC_FACTORY) @@ -73,8 +79,8 @@ static void max77833_fg_read_time(struct max77833_fuelgauge_data *fuelgauge) static void max77833_fg_test_print(struct max77833_fuelgauge_data *fuelgauge) { +#ifdef BATTERY_LOG_MESSAGE u16 reg_data; -// u16 reg_addr; max77833_read_fg(fuelgauge->i2c, FULLCAP_REG, ®_data); pr_info("%s: FULLCAP(%d), data(0x%04x)\n", __func__, @@ -95,112 +101,58 @@ static void max77833_fg_test_print(struct max77833_fuelgauge_data *fuelgauge) max77833_read_fg(fuelgauge->i2c, CONFIG_REG, ®_data); pr_info("%s: CONFIG_REG(0x%02x), data(0x%04x)\n", __func__, CONFIG_REG, reg_data); +#endif -#if 0 - /* Print Log for FG register values */ - pr_info("%s: [FG]\n", __func__); - pr_info("%s: 0x0000~0x009C: ", __func__); - reg_addr = 0x0; - while (reg_addr <= 0x9C) + max77833_fg_read_time(fuelgauge); +} + +static void max77833_fg_periodic_read(struct max77833_fuelgauge_data *fuelgauge) +{ + u16 reg_data; + u16 reg_addr; + char *str = NULL; + + str = kzalloc(sizeof(char)*1024, GFP_KERNEL); + if (!str) + return; + + /* 0x0000~0x009E : 2 step */ + reg_addr = 0x0000; + while (reg_addr <= 0x009E) { max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); + sprintf(str+strlen(str), "%04xh,", reg_data); reg_addr += 0x02; } - - pr_info("\n%s: 0x00C0, 0x00C4, 0x00C6: ", __func__); - reg_addr = 0xC0; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0xC4; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0xC6; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - pr_info("\n%s: 0x0160, 0x0164, 0x0166, 0x016A: ", __func__); - reg_addr = 0x160; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0x164; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0x166; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0x16A; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - pr_info("\n%s: 0x016C~0x017E: ", __func__); - reg_addr = 0x16C; + /* 0x0160~0x017E : 2 step */ + reg_addr = 0x0160; while (reg_addr <= 0x017E) { max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); + sprintf(str+strlen(str), "%04xh,", reg_data); reg_addr += 0x02; } - - pr_info("\n%s: 0x01A0~0x01DE: ", __func__); - reg_addr = 0x1A0; - while (reg_addr <= 0x01DE) + /* 0x01A0~0x01BE : 2 step */ + reg_addr = 0x01A0; + while (reg_addr <= 0x01BE) { max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); + sprintf(str+strlen(str), "%04xh,", reg_data); reg_addr += 0x02; } - - pr_info("\n%s: 0x02C6~0x02CC: ", __func__); - reg_addr = 0x2C6; - while (reg_addr <= 0x02CC) + /* 0x07C0~0x07FE : 2 step */ + reg_addr = 0x07C0; + while (reg_addr <= 0x07FE) { max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); + sprintf(str+strlen(str), "%04xh,", reg_data); reg_addr += 0x02; } - pr_info("\n%s: 0x02D4, 0x02D6, 0x02DC: ", __func__); - reg_addr = 0x2D4; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); + pr_info("[FG] %s\n", str); - reg_addr = 0x2D6; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0x2DC; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - pr_info("\n%s: 0x02E8~0x02FE: ", __func__); - reg_addr = 0x2E8; - while (reg_addr <= 0x02FE) - { - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - reg_addr += 0x02; - } - - pr_info("\n%s: 0x07F6, 0x07FE: ", __func__); - reg_addr = 0x7F6; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - - reg_addr = 0x7FE; - max77833_read_fg(fuelgauge->i2c, reg_addr, ®_data); - pr_info("0x%04x, ", reg_data); - pr_info("\n"); - -#endif - max77833_fg_read_time(fuelgauge); + kfree(str); } - #endif static int max77833_fg_read_vcell(struct max77833_fuelgauge_data *fuelgauge) @@ -222,9 +174,11 @@ static int max77833_fg_read_vcell(struct max77833_fuelgauge_data *fuelgauge) temp2 = temp / 1000000; vcell += (temp2 << 4); - if (!(fuelgauge->info.pr_cnt % PRINT_COUNT)) + if (!(fuelgauge->info.pr_cnt++ % PRINT_COUNT)) { + fuelgauge->info.pr_cnt = 1; pr_info("%s: VCELL(%d), data(0x%04x)\n", __func__, vcell, data); + } return vcell; } @@ -248,6 +202,11 @@ static int max77833_fg_read_vfocv(struct max77833_fuelgauge_data *fuelgauge) temp2 = temp / 1000000; vfocv += (temp2 << 4); +#if !defined(CONFIG_SEC_FACTORY) + max77833_fg_test_print(fuelgauge); + max77833_fg_periodic_read(fuelgauge); +#endif + return vfocv; } @@ -294,6 +253,41 @@ static int max77833_fg_check_battery_present(struct max77833_fuelgauge_data *fue return ret; } +static void max77833_fg_low_temp_compensation(struct max77833_fuelgauge_data *fuelgauge, bool en) +{ + u16 data; + u16 reg_data; + + if (!fuelgauge->using_temp_compensation) + return; + + if (en) { + /* Reset VALRT Threshold setting (disable) */ + reg_data = 0xFFA2; + if (max77833_write_fg(fuelgauge->i2c, VALRT_THRESHOLD_REG, + reg_data) < 0) { + pr_info("%s: Failed to write VALRT_THRESHOLD_REG\n", __func__); + return; + } + + max77833_read_fg(fuelgauge->i2c, VALRT_THRESHOLD_REG, &data); + pr_info("%s: VALRT_THRESHOLD_REG is (0x%x)\n", + __func__, data); + } else { + /* Reset VALRT Threshold setting (disable) */ + reg_data = 0xFFA5; + if (max77833_write_fg(fuelgauge->i2c, VALRT_THRESHOLD_REG, + reg_data) < 0) { + pr_info("%s: Failed to write VALRT_THRESHOLD_REG\n", __func__); + return; + } + + max77833_read_fg(fuelgauge->i2c, VALRT_THRESHOLD_REG, &data); + pr_info("%s: VALRT_THRESHOLD_REG is (0x%x)\n", + __func__, data); + } +} + static int max77833_fg_write_temp(struct max77833_fuelgauge_data *fuelgauge, int temperature) { @@ -454,6 +448,39 @@ static int max77833_fg_read_fullcap(struct max77833_fuelgauge_data *fuelgauge) return (int)data; } +static int max77833_fg_read_fullcaprep(struct max77833_fuelgauge_data *fuelgauge) +{ + u8 data[2]; + int ret; + + if (max77833_bulk_read(fuelgauge->i2c, FULLCAPREP_REG, + 2, data) < 0) { + pr_err("%s: Failed to read FULLCAP\n", __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + + +static int max77833_fg_read_fullcapnom(struct max77833_fuelgauge_data *fuelgauge) +{ + u8 data[2]; + int ret; + + if (max77833_bulk_read(fuelgauge->i2c, FULLCAP_NOM_REG, + 2, data) < 0) { + pr_err("%s: Failed to read FULLCAP\n", __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + static int max77833_fg_read_mixcap(struct max77833_fuelgauge_data *fuelgauge) { u16 data; @@ -495,26 +522,17 @@ static int max77833_fg_read_repcap(struct max77833_fuelgauge_data *fuelgauge) static int max77833_fg_read_current(struct max77833_fuelgauge_data *fuelgauge, int unit) { - u16 data1, data2; + u16 data1; u32 temp, sign; s32 i_current; - s32 avg_current; - int vcell; - static int cnt; if (max77833_read_fg(fuelgauge->i2c, CURRENT_REG, &data1) <0) { pr_err("%s: Failed to read CURRENT\n", __func__); return -1; } - if (max77833_read_fg(fuelgauge->i2c, AVG_CURRENT_REG, &data2) <0) { - pr_err("%s: Failed to read AVERAGE CURRENT\n", __func__); - return -1; - } - temp = data1 & 0xFFFF; /* Debug log for abnormal current case */ - pr_info("%s: CURRENT_REG(0x%04x)\n", __func__, temp); if (temp & (0x1 << 15)) { sign = MAX77833_NEGATIVE; temp = (~temp & 0xFFFF) + 1; @@ -523,10 +541,10 @@ static int max77833_fg_read_current(struct max77833_fuelgauge_data *fuelgauge, i /* 1.5625uV/0.0O5hm(Rsense) = 312.5uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: i_current = temp * 15625 / 50; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: i_current = temp * 15625 / 50000; } @@ -534,28 +552,6 @@ static int max77833_fg_read_current(struct max77833_fuelgauge_data *fuelgauge, i if (sign) i_current *= -1; - temp = data2 & 0xFFFF; - if (temp & (0x1 << 15)) { - sign = MAX77833_NEGATIVE; - temp = (~temp & 0xFFFF) + 1; - } else - sign = MAX77833_POSITIVE; - - /* 1.5625uV/0.005hm(Rsense) = 312.5uA */ - avg_current = temp * 15625 / 50000; - if (sign) - avg_current *= -1; - - vcell = max77833_fg_read_vcell(fuelgauge); - if ((vcell < 3500) && (cnt < 10) && (i_current < 0) && - fuelgauge->is_charging) { - i_current = 1; - cnt++; - } - -#if !defined(CONFIG_SEC_FACTORY) - max77833_fg_test_print(fuelgauge); -#endif return i_current; } @@ -582,10 +578,10 @@ static int max77833_fg_read_avg_current(struct max77833_fuelgauge_data *fuelgaug /* 1.5625uV/0.005hm(Rsense) = 312.5uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: avg_current = temp * 15625 / 50; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: avg_current = temp * 15625 / 50000; } @@ -603,6 +599,22 @@ static int max77833_fg_read_avg_current(struct max77833_fuelgauge_data *fuelgaug return avg_current; } +static int max77833_fg_read_cycle(struct max77833_fuelgauge_data *fuelgauge) +{ + u8 data[2]; + int ret; + + if (max77833_bulk_read(fuelgauge->i2c, CYCLES_REG, + 2, data) < 0) { + pr_err("%s: Failed to read FULLCAPCYCLE\n", __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + int max77833_fg_reset_soc(struct max77833_fuelgauge_data *fuelgauge) { u16 reg_data, fullcap; @@ -615,8 +627,8 @@ int max77833_fg_reset_soc(struct max77833_fuelgauge_data *fuelgauge) __func__, max77833_fg_read_vcell(fuelgauge), max77833_fg_read_vfocv(fuelgauge), max77833_fg_read_vfsoc(fuelgauge), max77833_fg_read_soc(fuelgauge)); pr_info("%s: Before quick-start - current(%d), avg current(%d)\n", - __func__, max77833_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - max77833_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, max77833_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + max77833_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); if (fuelgauge->pdata->check_jig_status && !fuelgauge->pdata->check_jig_status()) { @@ -646,8 +658,8 @@ int max77833_fg_reset_soc(struct max77833_fuelgauge_data *fuelgauge) __func__, max77833_fg_read_vcell(fuelgauge), max77833_fg_read_vfocv(fuelgauge), max77833_fg_read_vfsoc(fuelgauge), max77833_fg_read_soc(fuelgauge)); pr_info("%s: After quick-start - current(%d), avg current(%d)\n", - __func__, max77833_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - max77833_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, max77833_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + max77833_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); max77833_write_fg(fuelgauge->i2c, CYCLES_REG, 0x00A0); @@ -745,11 +757,11 @@ int max77833_get_fuelgauge_value(struct max77833_fuelgauge_data *fuelgauge, int break; case MAX77833_FG_CURRENT: - ret = max77833_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = max77833_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case MAX77833_FG_CURRENT_AVG: - ret = max77833_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = max77833_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case MAX77833_FG_CHECK_STATUS: @@ -772,6 +784,14 @@ int max77833_get_fuelgauge_value(struct max77833_fuelgauge_data *fuelgauge, int ret = max77833_fg_read_fullcap(fuelgauge); break; + case MAX77833_FG_FULLCAPNOM: + ret = max77833_fg_read_fullcapnom(fuelgauge); + break; + + case MAX77833_FG_FULLCAPREP: + ret = max77833_fg_read_fullcaprep(fuelgauge); + break; + case MAX77833_FG_MIXCAP: ret = max77833_fg_read_mixcap(fuelgauge); break; @@ -784,6 +804,10 @@ int max77833_get_fuelgauge_value(struct max77833_fuelgauge_data *fuelgauge, int ret = max77833_fg_read_repcap(fuelgauge); break; + case MAX77833_FG_CYCLE: + ret = max77833_fg_read_cycle(fuelgauge); + break; + default: ret = -1; break; @@ -792,6 +816,46 @@ int max77833_get_fuelgauge_value(struct max77833_fuelgauge_data *fuelgauge, int return ret; } +#if defined(CONFIG_BATTERY_AGE_FORECAST) +int max77833_get_age_forecast(struct max77833_fuelgauge_data *fuelgauge) +{ + int fullcapnom = 0; + int cycle = 0; + int chg_float_voltage = 0; + + fullcapnom = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_FULLCAPNOM); + fullcapnom = fullcapnom / 2; + cycle = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_CYCLE); + cycle = cycle / 100; + + pr_info("%s [FG] : cycle(%d), fullcapnom(%d)\n", + __func__, cycle, fullcapnom); + + if (cycle < 50) { + return 4400; + } else if (fullcapnom > 2545) { + return 4400; + } else if (fullcapnom > 2475) { + chg_float_voltage = 4375; + } else if (fullcapnom > 2360) { + chg_float_voltage = 4350; + } else if (fullcapnom > 2246) { + chg_float_voltage = 4325; + } else if (fullcapnom > 2132) { + chg_float_voltage = 4300; + } else if (fullcapnom > 2017) { + chg_float_voltage = 4275; + } else { + chg_float_voltage = 4250; + } + + pr_info("%s [FG] : chg_float_voltage(%d)\n", + __func__, chg_float_voltage); + + return chg_float_voltage; +} +#endif + int max77833_fg_alert_init(struct max77833_fuelgauge_data *fuelgauge, int soc) { #if 0 @@ -999,7 +1063,7 @@ int max77833_low_batt_compensation(struct max77833_fuelgauge_data *fuelgauge, /* Not charging, Under low battery comp voltage */ if (fg_vcell <= fuelgauge->battery_data->low_battery_comp_voltage) { fg_avg_current = max77833_fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_MA); + SEC_BATTERY_CURRENT_MA); fg_min_current = min(fg_avg_current, fg_current); table_size = @@ -1178,6 +1242,14 @@ bool max77833_fg_init(struct max77833_fuelgauge_data *fuelgauge) } } + /* Enable OCP (0xFF : 10.24A/256) */ + data = 0x00FF; + max77833_write_fg(fuelgauge->i2c, ISYSTH_REG, data); + pr_info("%s: Enable OCP - IsysTH 0x%x\n", __func__, data); + +#if !defined(CONFIG_SEC_FACTORY) + max77833_fg_periodic_read(fuelgauge); +#endif return true; } @@ -1235,13 +1307,22 @@ static void max77833_fg_get_scaled_capacity( struct max77833_fuelgauge_data *fuelgauge, union power_supply_propval *val) { - union power_supply_propval value; + union power_supply_propval value, chg_val, chg_val2; + int max_temp; psy_do_property("battery", get, POWER_SUPPLY_PROP_ONLINE, value); - pr_info("%s : CABLE TYPE(%d)\n", __func__, value.intval); - -#if 0 - if (value.intval != POWER_SUPPLY_TYPE_BATTERY) { + psy_do_property("max77833-charger", get, POWER_SUPPLY_PROP_CURRENT_NOW, + chg_val); + psy_do_property("max77833-charger", get, POWER_SUPPLY_PROP_CHARGE_NOW, + chg_val2); + pr_info("%s : CABLE TYPE(%d) INPUT CURRENT(%d) CHARGINGE MODE(%s)\n", + __func__, value.intval, chg_val.intval, chg_val2.strval); + + max_temp = fuelgauge->capacity_max; + + if ((value.intval != POWER_SUPPLY_TYPE_BATTERY) && + (!strcmp(chg_val2.strval, "CV Mode")) && + (chg_val.intval >= 1000)) { int temp, sample; int curr; int topoff; @@ -1252,65 +1333,67 @@ static void max77833_fg_get_scaled_capacity( topoff = fuelgauge->pdata->charging_current[value.intval].full_check_current_1st; capacity_threshold = topoff + CAPACITY_MAX_CONTROL_THRESHOLD; - pr_info("%s : curr(%d) topoff(%d)\n", __func__, curr, topoff); + pr_info("%s : curr(%d) topoff(%d) capacity_max(%d)\n", __func__, curr, topoff, max_temp); if ((curr < capacity_threshold) && (curr > topoff)) { if (!cnt) { cnt = 1; - val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / + fuelgauge->standard_capacity = (val->intval < fuelgauge->pdata->capacity_min) ? + 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 999 / (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); - fuelgauge->standard_capacity = val->intval; - } else { + } else if (fuelgauge->standard_capacity < 999) { temp = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / + 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 999 / (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); - sample = ((capacity_threshold - curr) * (1000 - fuelgauge->standard_capacity)) / + sample = ((capacity_threshold - curr) * (999 - fuelgauge->standard_capacity)) / (capacity_threshold - topoff); - pr_info("%s : %d = ((%d - %d) * (1000 - %d)) / (%d - %d)\n", + pr_info("%s : %d = ((%d - %d) * (999 - %d)) / (%d - %d)\n", __func__, sample, capacity_threshold, curr, fuelgauge->standard_capacity, capacity_threshold, topoff); if ((temp - fuelgauge->standard_capacity) >= sample) { pr_info("%s : TEMP > SAMPLE\n", __func__); - val->intval = temp; } else if ((sample - (temp - fuelgauge->standard_capacity)) < 5) { pr_info("%s : TEMP < SAMPLE && GAP UNDER 5\n", __func__); - fuelgauge->capacity_max -= (sample - (temp - fuelgauge->standard_capacity)); - val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / - (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); + max_temp -= (sample - (temp - fuelgauge->standard_capacity)); } else { pr_info("%s : TEMP > SAMPLE && GAP OVER 5\n", __func__); - fuelgauge->capacity_max -= 5; - val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / - (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); + max_temp -= 5; } - - pr_info("%s : TEMP(%d) SAMPLE(%d) CPAPCITY_MAX(%d)\n", + pr_info("%s : TEMP(%d) SAMPLE(%d) CAPACITY_MAX(%d)\n", __func__, temp, sample, fuelgauge->capacity_max); } } else { cnt = 0; - val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / - (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); } - } else { -#endif - val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? - 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / - (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); -// } + } - pr_info("%s : PRE SOC(%d), SOC(%d)\n", - __func__, fuelgauge->pre_soc, val->intval); + if (max_temp < + fuelgauge->pdata->capacity_max - + fuelgauge->pdata->capacity_max_margin) { + fuelgauge->capacity_max = + fuelgauge->pdata->capacity_max - + fuelgauge->pdata->capacity_max_margin; + pr_debug("%s: capacity_max (%d)", __func__, + fuelgauge->capacity_max); + } else { + fuelgauge->capacity_max = + (max_temp > + fuelgauge->pdata->capacity_max + + fuelgauge->pdata->capacity_max_margin) ? + (fuelgauge->pdata->capacity_max + + fuelgauge->pdata->capacity_max_margin) : + max_temp; + pr_debug("%s: capacity_max (%d)", __func__, + fuelgauge->capacity_max); + } - fuelgauge->pre_soc = val->intval; + val->intval = (val->intval < fuelgauge->pdata->capacity_min) ? + 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / + (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); pr_info("%s: scaled capacity (%d.%d)\n", __func__, val->intval/10, val->intval%10); @@ -1437,6 +1520,75 @@ static void max77833_set_full_value(struct max77833_fuelgauge_data *fuelgauge, } #endif +static int calc_ttf(struct max77833_fuelgauge_data *fuelgauge, union power_supply_propval *val) +{ + union power_supply_propval chg_val2; + int i; + int cc_time = 0; + + int soc = fuelgauge->raw_capacity; + int current_now = fuelgauge->current_now; + int current_avg = fuelgauge->current_avg; + int charge_current = (current_avg > 0)? current_avg : current_now; + struct cv_slope *cv_data = fuelgauge->cv_data; + int design_cap = fuelgauge->battery_data->Capacity / 2; + + if(!cv_data || (val->intval <= 0)) { + pr_info("%s: no cv_data or val: %d\n", __func__, val->intval); + return -1; + } + /* To prevent overflow if charge current is 30 under, change value*/ + if (charge_current <= 30) { +#if 1 + charge_current = val->intval; +#else + pr_info("%s: current: %d, current_avg: %d \n", __func__, current_now, current_avg); + return -1; +#endif + + } + psy_do_property("max77833-charger", get, POWER_SUPPLY_PROP_CHARGE_NOW, + chg_val2); + if (!strcmp(chg_val2.strval, "CC Mode") || !strcmp(chg_val2.strval, "NONE")) { //CC mode || NONE + charge_current = val->intval; + } + for (i = 0; i < fuelgauge->cv_data_lenth ;i++) { + if (charge_current >= cv_data[i].fg_current) + break; + } + if (cv_data[i].soc < soc) { + for (i = 0; i < fuelgauge->cv_data_lenth; i++) { + if (soc <= cv_data[i].soc) + break; + } + } else if (!strcmp(chg_val2.strval, "CC Mode") || !strcmp(chg_val2.strval, "NONE")) { //CC mode || NONE + cc_time = design_cap * (cv_data[i].soc - soc)\ + / val->intval * 3600 / 1000; + pr_debug("%s: cc_time: %d\n", __func__, cc_time); + if (cc_time < 0) { + + cc_time = 0; + } + } + + pr_debug("%s: soc: %4d, T: %6d, now: %4d, avg: %4d, cv soc: %4d, i: %4d, val: %d, %s\n", + __func__, soc, cv_data[i].time + cc_time, current_now, current_avg, cv_data[i].soc, i, val->intval, chg_val2.strval); + return cv_data[i].time + cc_time + 60; //minimum 1minutes +} + +static void max77833_fg_set_vempty(struct max77833_fuelgauge_data *fuelgauge, bool en) +{ + if (en) { + pr_info("%s : Low Capacity HW V EMPTY Enable\n", __func__); + max77833_write_fg(fuelgauge->i2c, VEMPTY_REG, fuelgauge->battery_data->V_empty); + fuelgauge->sw_v_empty = MAX77833_NORMAL_MODE; + fuelgauge->hw_v_empty = true; + } else { + max77833_write_fg(fuelgauge->i2c, VEMPTY_REG, fuelgauge->battery_data->V_empty_origin); + fuelgauge->hw_v_empty = false; + } +} + static int max77833_fg_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -1445,8 +1597,14 @@ static int max77833_fg_get_property(struct power_supply *psy, container_of(psy, struct max77833_fuelgauge_data, psy_fg); static int abnormal_current_cnt = 0; union power_supply_propval value; + u16 data; switch (psp) { +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = max77833_get_age_forecast(fuelgauge); + break; +#endif /* Cell voltage (VCELL, mV) */ case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_VOLTAGE); @@ -1454,10 +1612,10 @@ static int max77833_fg_get_property(struct power_supply *psy, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = max77833_fg_read_vfocv(fuelgauge); break; - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: default: val->intval = max77833_fg_read_avg_vcell(fuelgauge); break; @@ -1466,14 +1624,22 @@ static int max77833_fg_get_property(struct power_supply *psy, /* Current */ case POWER_SUPPLY_PROP_CURRENT_NOW: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = max77833_fg_read_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: - val->intval = max77833_get_fuelgauge_value(fuelgauge, + /* Print System current use Isys, AvgISys register */ + if (max77833_read_fg(fuelgauge->i2c, ISYS_REG, &data) < 0) + pr_err("%s: Failed to read ISYS_REG\n", __func__); + pr_info("%s: System current - ISYS_REG(0x%x, %d)\n", __func__, data, data); + if (max77833_read_fg(fuelgauge->i2c, AVGISYS_REG, &data) < 0) + pr_err("%s: Failed to read AVGISYS_REG\n", __func__); + pr_info("%s: System current - AVGISYS_REG(0x%x, %d)\n", __func__, data, data); + + fuelgauge->current_now = val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_CURRENT); psy_do_property("battery", get, POWER_SUPPLY_PROP_STATUS, value); @@ -1500,12 +1666,12 @@ static int max77833_fg_get_property(struct power_supply *psy, /* Average Current */ case POWER_SUPPLY_PROP_CURRENT_AVG: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = max77833_fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: val->intval = max77833_get_fuelgauge_value(fuelgauge, @@ -1516,22 +1682,30 @@ static int max77833_fg_get_property(struct power_supply *psy, /* Full Capacity */ case POWER_SUPPLY_PROP_ENERGY_NOW: switch (val->intval) { - case SEC_BATTEY_CAPACITY_DESIGNED: + case SEC_BATTERY_CAPACITY_DESIGNED: val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_FULLCAP); break; - case SEC_BATTEY_CAPACITY_ABSOLUTE: + case SEC_BATTERY_CAPACITY_ABSOLUTE: val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_MIXCAP); break; - case SEC_BATTEY_CAPACITY_TEMPERARY: + case SEC_BATTERY_CAPACITY_TEMPERARY: val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_AVCAP); break; - case SEC_BATTEY_CAPACITY_CURRENT: + case SEC_BATTERY_CAPACITY_CURRENT: val->intval = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_REPCAP); break; + case SEC_BATTERY_CAPACITY_AGEDCELL: + val->intval = max77833_get_fuelgauge_value(fuelgauge, + MAX77833_FG_FULLCAPNOM); + break; + case SEC_BATTERY_CAPACITY_CYCLE: + val->intval = max77833_get_fuelgauge_value(fuelgauge, + MAX77833_FG_CYCLE); + break; } break; /* SOC (%) */ @@ -1542,6 +1716,8 @@ static int max77833_fg_get_property(struct power_supply *psy, } else { val->intval = max77833_get_fuelgauge_soc(fuelgauge); + fuelgauge->raw_capacity = val->intval; + if (fuelgauge->pdata->capacity_calculation_type & (SEC_FUELGAUGE_CAPACITY_TYPE_SCALE | SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE)) @@ -1558,6 +1734,25 @@ static int max77833_fg_get_property(struct power_supply *psy, /* get only integer part */ val->intval /= 10; + if (fuelgauge->using_hw_vempty) { + if ((fuelgauge->raw_capacity <= 50) && + !fuelgauge->hw_v_empty){ + max77833_fg_set_vempty(fuelgauge, true); + } else if ((fuelgauge->raw_capacity > 50) && + fuelgauge->hw_v_empty){ + max77833_fg_set_vempty(fuelgauge, false); + } + } + + if (!fuelgauge->is_charging && + !fuelgauge->hw_v_empty && (fuelgauge->sw_v_empty == MAX77833_VEMPTY_MODE)) { + pr_info("%s : SW V EMPTY. Decrease SOC\n", __func__); + val->intval = 0; + } else if ((fuelgauge->sw_v_empty == MAX77833_VEMPTY_RECOVERY_MODE) && + (val->intval == fuelgauge->capacity_old)) { + fuelgauge->sw_v_empty = MAX77833_NORMAL_MODE; + } + /* check whether doing the wake_unlock */ if ((val->intval > fuelgauge->pdata->fuel_alert_soc) && fuelgauge->is_fuel_alerted) { @@ -1597,6 +1792,23 @@ static int max77833_fg_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: return -ENODATA; #endif + case POWER_SUPPLY_PROP_ENERGY_FULL: + { + int fullcap = max77833_get_fuelgauge_value(fuelgauge, MAX77833_FG_FULLCAPNOM); + val->intval = fullcap * 100 / fuelgauge->battery_data->Capacity; + pr_info("%s: asoc(%d), fullcap(0x%x)\n", + __func__, val->intval, fullcap); +#if !defined(CONFIG_SEC_FACTORY) + max77833_fg_periodic_read(fuelgauge); +#endif + } + break; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + val->intval = fuelgauge->capacity_max; + break; + case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: + val->intval = calc_ttf(fuelgauge, val); + break; default: return -EINVAL; } @@ -1613,6 +1825,10 @@ static int max77833_fg_set_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: break; +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + break; +#endif case POWER_SUPPLY_PROP_CHARGE_FULL: if (fuelgauge->pdata->capacity_calculation_type & SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE) { @@ -1654,6 +1870,15 @@ static int max77833_fg_set_property(struct power_supply *psy, break; } case POWER_SUPPLY_PROP_TEMP: + if (!fuelgauge->low_temp_compensation_en && + (val->intval <= (int)fuelgauge->low_temp_limit)) { + max77833_fg_low_temp_compensation(fuelgauge, true); + fuelgauge->low_temp_compensation_en = true; + } else if (fuelgauge->low_temp_compensation_en && + (val->intval >= (int)fuelgauge->low_temp_recovery)) { + max77833_fg_low_temp_compensation(fuelgauge, false); + fuelgauge->low_temp_compensation_en = false; + } max77833_fg_write_temp(fuelgauge, val->intval); max77833_fg_check_qrtable(fuelgauge); break; @@ -1662,6 +1887,11 @@ static int max77833_fg_set_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ENERGY_NOW: max77833_fg_reset_capacity_by_jig_connection(fuelgauge); break; + case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + pr_info("%s: capacity_max changed, %d -> %d\n", + __func__, fuelgauge->capacity_max, val->intval); + fuelgauge->capacity_max = val->intval; + break; default: return -EINVAL; } @@ -1739,13 +1969,6 @@ static int max77833_fuelgauge_parse_dt(struct max77833_fuelgauge_data *fuelgauge if (ret < 0) pr_err("%s error reading capacity_max %d\n", __func__, ret); - ret = of_property_read_u32(np, "fuelgauge,capacity_max_hv", - &pdata->capacity_max_hv); - if (ret < 0) { - pr_err("%s error reading capacity_max_hv %d\n", __func__, ret); - fuelgauge->pdata->capacity_max_hv = fuelgauge->pdata->capacity_max; - } - ret = of_property_read_u32(np, "fuelgauge,capacity_max_margin", &pdata->capacity_max_margin); if (ret < 0) @@ -1769,6 +1992,39 @@ static int max77833_fuelgauge_parse_dt(struct max77833_fuelgauge_data *fuelgauge pdata->repeated_fuelalert = of_property_read_bool(np, "fuelgauge,repeated_fuelalert"); + fuelgauge->using_temp_compensation = of_property_read_bool(np, + "fuelgauge,using_temp_compensation"); + if (fuelgauge->using_temp_compensation) { + ret = of_property_read_u32(np, "fuelgauge,low_temp_limit", + &fuelgauge->low_temp_limit); + if (ret < 0) + pr_err("%s error reading low temp limit %d\n", __func__, ret); + + ret = of_property_read_u32(np, "fuelgauge,low_temp_recovery", + &fuelgauge->low_temp_recovery); + if (ret < 0) + pr_err("%s error reading low temp recovery %d\n", __func__, ret); + + pr_info("%s : LOW TEMP LIMIT(%d) RECOVERY(%d)\n", + __func__, fuelgauge->low_temp_limit, fuelgauge->low_temp_recovery); + } + + fuelgauge->using_hw_vempty = of_property_read_bool(np, + "fuelgauge,using_hw_vempty"); + if (fuelgauge->using_hw_vempty) { + ret = of_property_read_u32(np, "fuelgauge,v_empty", + &fuelgauge->battery_data->V_empty); + if (ret < 0) + pr_err("%s error reading v_empty %d\n", + __func__, ret); + + ret = of_property_read_u32(np, "fuelgauge,v_empty_origin", + &fuelgauge->battery_data->V_empty_origin); + if(ret < 0) + pr_err("%s error reading v_empty_origin %d\n", + __func__, ret); + } + ret = of_property_read_u32(np, "fuelgauge,qrtable20", &fuelgauge->battery_data->QResidual20); if (ret < 0) @@ -1841,6 +2097,29 @@ static int max77833_fuelgauge_parse_dt(struct max77833_fuelgauge_data *fuelgauge if ((i%3) == 2) pr_info("\n"); } + p = of_get_property(np, "fuelgauge,cv_data", &len); + if (p) { + fuelgauge->cv_data = kzalloc(len, + GFP_KERNEL); + fuelgauge->cv_data_lenth = len / sizeof(struct cv_slope); + pr_err("%s len: %ld, lenth: %d, %d\n", + __func__, sizeof(int) * len, len, fuelgauge->cv_data_lenth); + ret = of_property_read_u32_array(np, "fuelgauge,cv_data", + (u32 *)fuelgauge->cv_data, len/sizeof(u32)); + for(i = 0; i < fuelgauge->cv_data_lenth; i++) { + pr_err("%s %5d, %5d, %5d\n", + __func__, fuelgauge->cv_data[i].fg_current, + fuelgauge->cv_data[i].soc, fuelgauge->cv_data[i].time); + } + if (ret) { + pr_err("%s failed to read fuelgauge->cv_data: %d\n", + __func__, ret); + kfree(fuelgauge->cv_data); + fuelgauge->cv_data = NULL; + } + } else { + pr_err("%s there is not cv_data\n", __func__); + } np = of_find_node_by_name(NULL, "battery"); ret = of_property_read_u32(np, "battery,thermal_source", @@ -1875,7 +2154,7 @@ static int max77833_fuelgauge_parse_dt(struct max77833_fuelgauge_data *fuelgauge pr_info("%s fg_irq: %d, capacity_max: %d\n" "qrtable20: 0x%x, qrtable30 : 0x%x\n" - "cpacity_max_margin: %d, capacity_min: %d\n" + "capacity_max_margin: %d, capacity_min: %d\n" "calculation_type: 0x%x, fuel_alert_soc: %d,\n" "repeated_fuelalert: %d\n", __func__, pdata->fg_irq, pdata->capacity_max, @@ -2051,6 +2330,10 @@ static int max77833_fuelgauge_resume(struct device *dev) static void max77833_fuelgauge_shutdown(struct device *dev) { + struct max77833_fuelgauge_data *fuelgauge = dev_get_drvdata(dev); + + if (fuelgauge->using_hw_vempty) + max77833_fg_set_vempty(fuelgauge, false); } static SIMPLE_DEV_PM_OPS(max77833_fuelgauge_pm_ops, max77833_fuelgauge_suspend, diff --git a/drivers/battery/max77843_charger.c b/drivers/battery/max77843_charger.c index 9ee3bd5f7b87..c9ba898111b5 100644 --- a/drivers/battery/max77843_charger.c +++ b/drivers/battery/max77843_charger.c @@ -44,6 +44,10 @@ static enum power_supply_property max77843_charger_props[] = { POWER_SUPPLY_PROP_CHARGE_NOW, }; +static enum power_supply_property max77843_otg_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + static struct device_attribute max77843_charger_attrs[] = { MAX77843_CHARGER_ATTR(chip_id), }; @@ -528,6 +532,16 @@ static void max77843_set_input_current(struct max77843_charger_data *charger, max77843_write_reg(charger->i2c, set_reg, reg_data); + + if ((charger->cable_type == POWER_SUPPLY_TYPE_BATTERY) && + (charger->status == POWER_SUPPLY_STATUS_DISCHARGING)) { + pre_current_max = charger->pdata->charging_current + [POWER_SUPPLY_TYPE_USB].input_current_limit; + reg_data = charger->pdata->charging_current + [POWER_SUPPLY_TYPE_USB].input_current_limit / 20; + max77843_write_reg(charger->i2c, + MAX77843_CHG_REG_CNFG_10, reg_data); + } } mutex_unlock(&charger->charger_mutex); @@ -589,9 +603,15 @@ static void max77843_set_current(struct max77843_charger_data *charger) if (charger->siop_level < 100) { if (charger->cable_type == POWER_SUPPLY_TYPE_WIRELESS) { - current_max = SIOP_WIRELESS_INPUT_LIMIT_CURRENT; - if (current_now > SIOP_WIRELESS_CHARGING_LIMIT_CURRENT) - current_now = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT; + + if(charger->siop_level == 7) { /* for dcm model, 7 is a reseved word */ + current_max = 200; + current_now = 0; + } else { + current_max = SIOP_WIRELESS_INPUT_LIMIT_CURRENT; + if (current_now > SIOP_WIRELESS_CHARGING_LIMIT_CURRENT) + current_now = SIOP_WIRELESS_CHARGING_LIMIT_CURRENT; + } } else { if (current_max > SIOP_INPUT_LIMIT_CURRENT) current_max = SIOP_INPUT_LIMIT_CURRENT; @@ -875,9 +895,6 @@ static void max77843_charger_function_control( charger->pdata->charging_current[charger->cable_type].full_check_current_1st, charger->pdata->charging_current[charger->cable_type].full_check_current_2nd, charger->cable_type); - - max77843_test_read(charger); - } static void max77843_charger_initialize(struct max77843_charger_data *charger) @@ -934,12 +951,14 @@ static void max77843_set_float_voltage(struct max77843_charger_data *charger, in { u8 reg_data = 0; + /* change MINVSYS */ reg_data = max77843_get_float_voltage_data(float_voltage); max77843_update_reg(charger->i2c, MAX77843_CHG_REG_CNFG_04, (reg_data << CHG_CNFG_04_CHG_CV_PRM_SHIFT), CHG_CNFG_04_CHG_CV_PRM_MASK); max77843_read_reg(charger->i2c, MAX77843_CHG_REG_CNFG_04, ®_data); - pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); + charger->pdata->chg_float_voltage = float_voltage; + pr_info("%s: battery cv voltage 0x%x, chg_float_voltage = %dmV \n", __func__, reg_data, charger->pdata->chg_float_voltage); } static u8 max77843_get_float_voltage(struct max77843_charger_data *charger) @@ -948,7 +967,7 @@ static u8 max77843_get_float_voltage(struct max77843_charger_data *charger) max77843_read_reg(charger->i2c, MAX77843_CHG_REG_CNFG_04, ®_data); reg_data &= 0x3F; - pr_info("%s: battery cv voltage 0x%x\n", __func__, reg_data); + pr_info("%s: battery cv voltage 0x%x, chg_float_voltage = %dmV \n", __func__, reg_data, charger->pdata->chg_float_voltage); return reg_data; } @@ -1260,6 +1279,93 @@ static int max77843_chg_set_property(struct power_supply *psy, return 0; } +static int max77843_otg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max77843_charger_data *charger = + container_of(psy, struct max77843_charger_data, psy_otg); + u8 reg_data; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + max77843_read_reg(charger->i2c, MAX77843_CHG_REG_CNFG_00, + ®_data); + if ((reg_data & CHG_CNFG_00_OTG_CTRL) == CHG_CNFG_00_OTG_CTRL) + val->intval = 1; + else + val->intval = 0; + break; + default: + return -EINVAL; + } + return 0; +} + +static int max77843_otg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max77843_charger_data *charger = + container_of(psy, struct max77843_charger_data, psy_otg); + union power_supply_propval value; + static u8 chg_int_state; + u8 chg_cnfg_00; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: +#if defined(CONFIG_WIRELESS_CHARGER_INBATTERY) + value.intval = val->intval; + psy_do_property("wireless", set, + POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value); +#endif + pr_info("%s: OTG %s\n", __func__, val->intval > 0 ? "on" : "off"); + + if (val->intval) { + max77843_read_reg(charger->i2c, MAX77843_CHG_REG_INT_MASK, + &chg_int_state); + + /* disable charger interrupt: CHG_I, CHGIN_I */ + /* enable charger interrupt: BYP_I */ + max77843_update_reg(charger->i2c, MAX77843_CHG_REG_INT_MASK, + MAX77843_CHG_IM | MAX77843_CHGIN_IM, + MAX77843_CHG_IM | MAX77843_CHGIN_IM | MAX77843_BYP_IM); + + /* OTG on, boost on */ + max77843_update_reg(charger->i2c, MAX77843_CHG_REG_CNFG_00, + CHG_CNFG_00_OTG_CTRL, CHG_CNFG_00_OTG_CTRL); + + /* Update CHG_CNFG_11 to 0x50(5V) */ + max77843_write_reg(charger->i2c, + MAX77843_CHG_REG_CNFG_11, 0x50); + } else { + /* OTG off, boost off, (buck on) */ + max77843_update_reg(charger->i2c, MAX77843_CHG_REG_CNFG_00, + CHG_CNFG_00_BUCK_MASK, CHG_CNFG_00_BUCK_MASK | CHG_CNFG_00_OTG_CTRL); + + /* Update CHG_CNFG_11 to 0x00(3V) */ + max77843_write_reg(charger->i2c, + MAX77843_CHG_REG_CNFG_11, 0x00); + mdelay(50); + + /* enable charger interrupt */ + max77843_write_reg(charger->i2c, + MAX77843_CHG_REG_INT_MASK, chg_int_state); + } + max77843_read_reg(charger->i2c, MAX77843_CHG_REG_INT_MASK, + &chg_int_state); + max77843_read_reg(charger->i2c, MAX77843_CHG_REG_CNFG_00, + &chg_cnfg_00); + pr_info("%s: INT_MASK(0x%x), CHG_CNFG_00(0x%x)\n", + __func__, chg_int_state, chg_cnfg_00); + break; + default: + return -EINVAL; + } + + return 0; +} + static int max77843_debugfs_show(struct seq_file *s, void *data) { struct max77843_charger_data *charger = s->private; @@ -1402,7 +1508,8 @@ static void wpc_detect_work(struct work_struct *work) MAX77843_CHG_REG_INT_OK, ®_data); wc_w_state = (reg_data & MAX77843_WCIN_OK) >> MAX77843_WCIN_OK_SHIFT; - msleep(50); + if (wc_w_state == 0) + msleep(50); } while((retry_cnt++ < 2) && (wc_w_state == 0)); if ((charger->wc_w_state == 0) && (wc_w_state == 1)) { @@ -1438,6 +1545,13 @@ static void wpc_detect_work(struct work_struct *work) value.intval = 0; psy_do_property("wireless", set, POWER_SUPPLY_PROP_ONLINE, value); + +#if defined(CONFIG_WIRELESS_CHARGER_INBATTERY) && defined(CONFIG_WIRELESS_CHARGER_INBATTERY_CS100) + /* this code is for preventing reactivated wireless charger on outside of pad*/ + value.intval = POWER_SUPPLY_HEALTH_UNDERVOLTAGE; + psy_do_property("bq51221-charger", set, + POWER_SUPPLY_PROP_HEALTH, value); +#endif pr_info("%s: wpc deactivated, set V_INT as PD\n", __func__); } @@ -1458,13 +1572,9 @@ static irqreturn_t wpc_charger_irq(int irq, void *data) { struct max77843_charger_data *charger = data; unsigned long delay; - u8 reg_data; - max77843_read_reg(charger->i2c, - MAX77843_CHG_REG_INT_MASK, ®_data); - reg_data |= (1 << 5); - max77843_write_reg(charger->i2c, - MAX77843_CHG_REG_INT_MASK, reg_data); + max77843_update_reg(charger->i2c, MAX77843_CHG_REG_INT_MASK, + MAX77843_WCIN_IM, MAX77843_WCIN_IM); wake_lock(&charger->wpc_wake_lock); #ifdef CONFIG_SAMSUNG_BATTERY_FACTORY @@ -1811,6 +1921,7 @@ static int __devinit max77843_charger_probe(struct platform_device *pdev) charger->afc_detect = false; charger->is_mdock = false; charger->siop_level = 100; + charger->charging_current_max = 500; charger->max77843_pdata = pdata; charger->input_curr_limit_step = 33; @@ -1830,6 +1941,12 @@ static int __devinit max77843_charger_probe(struct platform_device *pdev) charger->psy_chg.set_property = max77843_chg_set_property; charger->psy_chg.properties = max77843_charger_props; charger->psy_chg.num_properties = ARRAY_SIZE(max77843_charger_props); + charger->psy_otg.name = "otg"; + charger->psy_otg.type = POWER_SUPPLY_TYPE_OTG; + charger->psy_otg.get_property = max77843_otg_get_property; + charger->psy_otg.set_property = max77843_otg_set_property; + charger->psy_otg.properties = max77843_otg_props; + charger->psy_otg.num_properties = ARRAY_SIZE(max77843_otg_props); charger_chip_name = charger->psy_chg.name; max77843_charger_initialize(charger); @@ -1870,7 +1987,13 @@ static int __devinit max77843_charger_probe(struct platform_device *pdev) ret = power_supply_register(&pdev->dev, &charger->psy_chg); if (ret) { pr_err("%s: Failed to Register psy_chg\n", __func__); - goto err_power_supply_register; + goto err_power_supply_register_chg; + } + + ret = power_supply_register(&pdev->dev, &charger->psy_otg); + if (ret) { + pr_err("%s: Failed to Register psy_otg\n", __func__); + goto err_power_supply_register_otg; } if (charger->pdata->chg_irq) { @@ -1958,8 +2081,10 @@ static int __devinit max77843_charger_probe(struct platform_device *pdev) err_wc_irq: free_irq(charger->pdata->chg_irq, NULL); err_irq: + power_supply_unregister(&charger->psy_otg); +err_power_supply_register_otg: power_supply_unregister(&charger->psy_chg); -err_power_supply_register: +err_power_supply_register_chg: destroy_workqueue(charger->wqueue); err_pdata_free: kfree(pdata->charger_data); diff --git a/drivers/battery/max77843_fuelgauge.c b/drivers/battery/max77843_fuelgauge.c index d8f88d937a60..70cbd4bdf41a 100644 --- a/drivers/battery/max77843_fuelgauge.c +++ b/drivers/battery/max77843_fuelgauge.c @@ -22,6 +22,9 @@ bool max77843_fg_fuelalert_init(struct max77843_fuelgauge_data *fuelgauge, int s static enum power_supply_property max77843_fuelgauge_props[] = { POWER_SUPPLY_PROP_STATUS, +#if defined(CONFIG_BATTERY_AGE_FORECAST) + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, +#endif POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_AVG, POWER_SUPPLY_PROP_CURRENT_NOW, @@ -571,10 +574,10 @@ static int max77843_fg_read_current(struct max77843_fuelgauge_data *fuelgauge, i /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: i_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: i_current = temp * 15625 / 100000; } @@ -609,10 +612,10 @@ static int max77843_fg_read_avg_current(struct max77843_fuelgauge_data *fuelgaug /* 1.5625uV/0.01Ohm(Rsense) = 156.25uA */ switch (unit) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: avg_current = temp * 15625 / 100; break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: avg_current = temp * 15625 / 100000; } @@ -630,6 +633,22 @@ static int max77843_fg_read_avg_current(struct max77843_fuelgauge_data *fuelgaug return avg_current; } +static int max77843_fg_read_cycle(struct max77843_fuelgauge_data *fuelgauge) +{ + u8 data[2]; + int ret; + + if (max77843_bulk_read(fuelgauge->i2c, CYCLES_REG, + 2, data) < 0) { + pr_err("%s: Failed to read FULLCAPCYCLE\n", __func__); + return -1; + } + + ret = (data[1] << 8) + data[0]; + + return ret; +} + int max77843_fg_reset_soc(struct max77843_fuelgauge_data *fuelgauge) { u8 data[2]; @@ -642,8 +661,8 @@ int max77843_fg_reset_soc(struct max77843_fuelgauge_data *fuelgauge) __func__, max77843_fg_read_vcell(fuelgauge), max77843_fg_read_vfocv(fuelgauge), max77843_fg_read_vfsoc(fuelgauge), max77843_fg_read_soc(fuelgauge)); pr_info("%s: Before quick-start - current(%d), avg current(%d)\n", - __func__, max77843_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - max77843_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, max77843_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + max77843_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); if (fuelgauge->pdata->check_jig_status && !fuelgauge->pdata->check_jig_status()) { @@ -675,8 +694,8 @@ int max77843_fg_reset_soc(struct max77843_fuelgauge_data *fuelgauge) __func__, max77843_fg_read_vcell(fuelgauge), max77843_fg_read_vfocv(fuelgauge), max77843_fg_read_vfsoc(fuelgauge), max77843_fg_read_soc(fuelgauge)); pr_info("%s: After quick-start - current(%d), avg current(%d)\n", - __func__, max77843_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA), - max77843_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA)); + __func__, max77843_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA), + max77843_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA)); max77843_write_word(fuelgauge->i2c, CYCLES_REG, 0x00a0); @@ -777,11 +796,11 @@ int max77843_get_fuelgauge_value(struct max77843_fuelgauge_data *fuelgauge, int break; case FG_CURRENT: - ret = max77843_fg_read_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = max77843_fg_read_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case FG_CURRENT_AVG: - ret = max77843_fg_read_avg_current(fuelgauge, SEC_BATTEY_CURRENT_MA); + ret = max77843_fg_read_avg_current(fuelgauge, SEC_BATTERY_CURRENT_MA); break; case FG_CHECK_STATUS: @@ -824,6 +843,10 @@ int max77843_get_fuelgauge_value(struct max77843_fuelgauge_data *fuelgauge, int ret = max77843_fg_read_repcap(fuelgauge); break; + case FG_CYCLE: + ret = max77843_fg_read_cycle(fuelgauge); + break; + default: ret = -1; break; @@ -832,6 +855,46 @@ int max77843_get_fuelgauge_value(struct max77843_fuelgauge_data *fuelgauge, int return ret; } +#if defined(CONFIG_BATTERY_AGE_FORECAST) +int max77843_get_age_forecast(struct max77843_fuelgauge_data *fuelgauge) +{ + int fullcapnom = 0; + int cycle = 0; + int chg_float_voltage = 0; + + fullcapnom = max77843_get_fuelgauge_value(fuelgauge, FG_FULLCAPNOM); + fullcapnom = fullcapnom / 2; + cycle = max77843_get_fuelgauge_value(fuelgauge, FG_CYCLE); + cycle = cycle / 100; + + pr_info("%s [FG] : cycle(%d), fullcapnom(%d)\n", + __func__, cycle, fullcapnom); + + if (cycle < 50) { + return 4400; + } else if (fullcapnom > 2545) { + return 4400; + } else if (fullcapnom > 2475) { + chg_float_voltage = 4375; + } else if (fullcapnom > 2360) { + chg_float_voltage = 4350; + } else if (fullcapnom > 2246) { + chg_float_voltage = 4325; + } else if (fullcapnom > 2132) { + chg_float_voltage = 4300; + } else if (fullcapnom > 2017) { + chg_float_voltage = 4275; + } else { + chg_float_voltage = 4250; + } + + pr_info("%s [FG] : chg_float_voltage(%d)\n", + __func__, chg_float_voltage); + + return chg_float_voltage; +} +#endif + int max77843_fg_alert_init(struct max77843_fuelgauge_data *fuelgauge, int soc) { u8 misccgf_data[2]; @@ -1039,7 +1102,7 @@ int max77843_low_batt_compensation(struct max77843_fuelgauge_data *fuelgauge, /* Not charging, Under low battery comp voltage */ if (fg_vcell <= fuelgauge->battery_data->low_battery_comp_voltage) { fg_avg_current = max77843_fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_MA); + SEC_BATTERY_CURRENT_MA); fg_min_current = min(fg_avg_current, fg_current); table_size = @@ -1291,7 +1354,9 @@ static void max77843_fg_get_scaled_capacity( struct max77843_fuelgauge_data *fuelgauge, union power_supply_propval *val) { +#if defined(CONFIG_DISABLE_SAVE_CAPACITY_MAX) u16 reg_data; +#endif union power_supply_propval value, chg_val, chg_val2; int max_temp; @@ -1380,6 +1445,7 @@ static void max77843_fg_get_scaled_capacity( 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 / (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min)); +#if defined(CONFIG_DISABLE_SAVE_CAPACITY_MAX) reg_data = max77843_read_word(fuelgauge->i2c, 0xD0); if (reg_data != fuelgauge->capacity_max) { pr_info("%s : 0xD0 Register Update (%d) -> (%d)\n", @@ -1387,6 +1453,7 @@ static void max77843_fg_get_scaled_capacity( reg_data = fuelgauge->capacity_max; max77843_write_word(fuelgauge->i2c, 0xD0, reg_data); } +#endif pr_info("%s: scaled capacity (%d.%d)\n", __func__, val->intval/10, val->intval%10); @@ -1602,6 +1669,11 @@ static int max77843_fg_get_property(struct power_supply *psy, union power_supply_propval value; switch (psp) { +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = max77843_get_age_forecast(fuelgauge); + break; +#endif /* Cell voltage (VCELL, mV) */ case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_VOLTAGE); @@ -1609,10 +1681,10 @@ static int max77843_fg_get_property(struct power_supply *psy, /* Additional Voltage Information (mV) */ case POWER_SUPPLY_PROP_VOLTAGE_AVG: switch (val->intval) { - case SEC_BATTEY_VOLTAGE_OCV: + case SEC_BATTERY_VOLTAGE_OCV: val->intval = max77843_fg_read_vfocv(fuelgauge); break; - case SEC_BATTEY_VOLTAGE_AVERAGE: + case SEC_BATTERY_VOLTAGE_AVERAGE: default: val->intval = max77843_fg_read_avg_vcell(fuelgauge); break; @@ -1621,12 +1693,12 @@ static int max77843_fg_get_property(struct power_supply *psy, /* Current */ case POWER_SUPPLY_PROP_CURRENT_NOW: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = max77843_fg_read_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: fuelgauge->current_now = val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_CURRENT); @@ -1655,12 +1727,12 @@ static int max77843_fg_get_property(struct power_supply *psy, /* Average Current */ case POWER_SUPPLY_PROP_CURRENT_AVG: switch (val->intval) { - case SEC_BATTEY_CURRENT_UA: + case SEC_BATTERY_CURRENT_UA: val->intval = max77843_fg_read_avg_current(fuelgauge, - SEC_BATTEY_CURRENT_UA); + SEC_BATTERY_CURRENT_UA); break; - case SEC_BATTEY_CURRENT_MA: + case SEC_BATTERY_CURRENT_MA: default: fuelgauge->current_avg = val->intval = max77843_get_fuelgauge_value(fuelgauge, @@ -1671,22 +1743,29 @@ static int max77843_fg_get_property(struct power_supply *psy, /* Full Capacity */ case POWER_SUPPLY_PROP_ENERGY_NOW: switch (val->intval) { - case SEC_BATTEY_CAPACITY_DESIGNED: + case SEC_BATTERY_CAPACITY_DESIGNED: val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_FULLCAP); break; - case SEC_BATTEY_CAPACITY_ABSOLUTE: + case SEC_BATTERY_CAPACITY_ABSOLUTE: val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_MIXCAP); break; - case SEC_BATTEY_CAPACITY_TEMPERARY: + case SEC_BATTERY_CAPACITY_TEMPERARY: val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_AVCAP); break; - case SEC_BATTEY_CAPACITY_CURRENT: + case SEC_BATTERY_CAPACITY_CURRENT: val->intval = max77843_get_fuelgauge_value(fuelgauge, FG_REPCAP); + case SEC_BATTERY_CAPACITY_AGEDCELL: + val->intval = max77843_get_fuelgauge_value(fuelgauge, + FG_FULLCAPNOM); break; + case SEC_BATTERY_CAPACITY_CYCLE: + val->intval = max77843_get_fuelgauge_value(fuelgauge, + FG_CYCLE); + break; } break; /* SOC (%) */ @@ -1806,6 +1885,10 @@ static int max77843_fg_set_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: break; +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + break; +#endif case POWER_SUPPLY_PROP_CHARGE_FULL: if (fuelgauge->pdata->capacity_calculation_type & SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE) { @@ -2187,7 +2270,9 @@ static int __devinit max77843_fuelgauge_probe(struct platform_device *pdev) struct max77843_fuelgauge_data *fuelgauge; int ret = 0; union power_supply_propval raw_soc_val; +#if defined(CONFIG_DISABLE_SAVE_CAPACITY_MAX) u16 reg_data; +#endif pr_info("%s: MAX77843 Fuelgauge Driver Loading\n", __func__); @@ -2236,6 +2321,7 @@ static int __devinit max77843_fuelgauge_probe(struct platform_device *pdev) fuelgauge->capacity_max = fuelgauge->pdata->capacity_max; raw_soc_val.intval = max77843_get_fuelgauge_value(fuelgauge, FG_RAW_SOC) / 10; +#if defined(CONFIG_DISABLE_SAVE_CAPACITY_MAX) reg_data = max77843_read_word(fuelgauge->i2c, 0xD0); if (reg_data >= 900 && reg_data <= 1000 && reg_data != fuelgauge->capacity_max) { @@ -2248,6 +2334,7 @@ static int __devinit max77843_fuelgauge_probe(struct platform_device *pdev) reg_data = fuelgauge->capacity_max; max77843_write_word(fuelgauge->i2c, 0xD0, reg_data); } +#endif if (raw_soc_val.intval > fuelgauge->capacity_max) max77843_fg_calculate_dynamic_scale(fuelgauge, 100); @@ -2347,7 +2434,8 @@ static void max77843_fuelgauge_shutdown(struct device *dev) { struct max77843_fuelgauge_data *fuelgauge = dev_get_drvdata(dev); - max77843_fg_set_vempty(fuelgauge, false); + if (fuelgauge->using_hw_vempty) + max77843_fg_set_vempty(fuelgauge, false); } static SIMPLE_DEV_PM_OPS(max77843_fuelgauge_pm_ops, max77843_fuelgauge_suspend, diff --git a/drivers/battery/max77900_charger.c b/drivers/battery/max77900_charger.c new file mode 100644 index 000000000000..95c72cd6cd54 --- /dev/null +++ b/drivers/battery/max77900_charger.c @@ -0,0 +1,629 @@ +/* + * max77900_charger.c + * Samsung max77900 Charger Driver + * + * Copyright (C) 2015 Samsung Electronics + * Yeongmi Ha + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENABLE 1 +#define DISABLE 0 + +static enum power_supply_property sec_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, +}; + +static int max77900_read_device(struct i2c_client *client, + u8 reg, u8 bytes, void *dest) +{ + int ret; + if (bytes > 1) { + ret = i2c_smbus_read_i2c_block_data(client, reg, bytes, dest); + } else { + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + return ret; + *(unsigned char *)dest = (unsigned char)ret; + } + return ret; +} + +static int max77900_reg_read(struct i2c_client *client, u8 reg, u8 * data) +{ + struct max77900_charger_data *charger = i2c_get_clientdata(client); + int ret = 0; + + mutex_lock(&charger->io_lock); + ret = max77900_read_device(client, reg, 1, data); + mutex_unlock(&charger->io_lock); + + if (ret < 0) { + pr_err("%s: can't read reg(0x%x), ret(%d)\n", __func__, reg, *data); + return ret; + } else + pr_err("%s: read reg(0x%x), ret(%d)\n", __func__, reg, *data); + + return ret; +} + +static int max77900_reg_write(struct i2c_client *client, u8 reg, u8 data) +{ + struct max77900_charger_data *charger = i2c_get_clientdata(client); + int ret = 0; + + mutex_lock(&charger->io_lock); + ret = i2c_smbus_write_byte_data(client, reg, data); + mutex_unlock(&charger->io_lock); + + if (ret < 0) + pr_err("%s: can't write reg(0x%x), ret(%d)\n", __func__, reg, ret); + else + max77900_reg_read(client,reg,&data); + return ret; +} + +/******************************************************************************* + * LDO Section + ******************************************************************************/ + +/* + * Setup the LDO¡¯s output voltage + * the LDO output voltage by writing the LDO_VOUT register and setting the VOUTSET_OVERRIDE bit to ¡®1¡¯ + * + * In TX mode, to convert the MAX77900 to peer-to-peer wireless power transmitter mode, + * the first operation is to apply a voltage (3.3V to 5V) at the output of the LDO (OUT). + * The LDO¡¯s output voltage can be targeted to any value between 3.65V and 10V with 50mV/LSB. + * + * Default Reset value 0x00 means 3.65V + * +*During power-up, the LDO is held off until the VRECT-TARGET threshold 1 converges. +*The voltage control loop ensures that the output voltage is maintained at VOUT-REG to power the system. +*/ +static void max77900_set_ldo_vout(struct max77900_charger_data *charger, u32 input_value) +{ + u8 read_value=0; + u8 write_value=0; + u32 ldo_vout=0; + + ldo_vout=(u8)input_value; + pr_info("%s ldo_vout 0x%X\n",__func__,ldo_vout); // 0x1B + max77900_reg_read(charger->client,0x0d,&read_value); + + pr_info("%s read_value 0x%X\n",__func__,read_value); // 0x9B + + // default value was overrided. + write_value = /*VOUTSET_OVERRIDE || */(read_value & ~0x3F )| ldo_vout; //0x1B <-- check out + max77900_reg_write(charger->client,0x0f,write_value); + + pr_info("%s write_value 0x%X\n",__func__,write_value); //0x9B +} + +static u32 max77900_get_ldo_vout(struct max77900_charger_data *charger) +{ + u8 vout_valh=0; + u8 vout_vall=0; + u16 vout_val=0; + u32 vout=0; + + pr_info("%s\n",__func__); + + max77900_reg_read(charger->client,0x14,&vout_valh); + max77900_reg_read(charger->client,0x15,&vout_vall); + pr_info("%s vout_valh 0x%X vout_vall 0x%X\n",__func__,vout_valh,vout_vall); + + vout_val = vout_valh << 4 | vout_vall; + vout = DIV_ROUND_UP((( 8 * 1250 * vout_val / 4095 ) ),1) ; // 4095, 1250 mV + + pr_info("vout_val %d vout %d mV\n", vout_val, vout); + return vout; +} + +static u32 max77900_get_vrect(struct max77900_charger_data *charger) +{ + u8 ldo_vrecth=0; + u8 ldo_vrectl=0; + u16 vrect_val=0; + u32 vrect=0; + int ret = 0; + + pr_info("%s\n",__func__); + + ret = max77900_reg_read(charger->client,0x12,&ldo_vrecth);//VRECTVAL[7:0] + if( ret > 0 ) + ret = max77900_reg_read(charger->client,0x13,&ldo_vrectl);//VRECTVAL[3:0] + if( ret > 0 ) + pr_info("%s ldo_vrecth 0x%X ldo_vrectl 0x%X\n",__func__,ldo_vrecth,ldo_vrectl); + + vrect_val = (ldo_vrecth << 4)| ldo_vrectl; //VRECTVAL[11:0 ] + pr_info("vrect_val %d\n", vrect_val); //4009 + + /* vrect = 12* 1.25 * vrecval /4095 */ + vrect = DIV_ROUND_UP(( 12* 1250 * vrect_val / 4095 ),1);//mV + + pr_info("%s [vrect] %d mV\n", __func__, vrect); + + return vrect; +} + +static PVRECT_T max77900_get_vrect_target(struct max77900_charger_data *charger) +{ + u8 vrect_x[8] ={0}; + u8 vrect_y_wpc[8] ={0}; + u8 vrect_y_pma[8] ={0}; + + u8 vrect[8][3] = {{0,0,0}}; + u8 (*vrect_p)[3]; + + int i =0; + int j =0; + vrect_p = vrect; + + /* read the register values */ + for( i=0; i < 8 ; i++ ) { + max77900_reg_read(charger->client,VRECT_TARGET_X0+3*i ,&vrect_x[i]); + max77900_reg_read(charger->client,VRECT_TARGET_Y0_WPC+3*i,&vrect_y_wpc[i]); + max77900_reg_read(charger->client,VRECT_TARGET_Y0_PMA+3*i,&vrect_y_pma[i]); + } + + /* move to array */ + for( i=0; i < 8 ; i++ ) { + *(*(vrect+i)+0) = vrect_x[i]; + *(*(vrect+i)+1) = vrect_y_wpc[i]; + *(*(vrect+i)+2) = vrect_y_pma[i]; + } + + /* print all elements */ + for(i=0; i < 8 ; i++ ) { + for(j=0; j < 3 ; j++ ) + { + pr_info(" vrect_target[%d][%d] 0x%X",i,j, *(*(vrect_p+i)+j)); + } + pr_info("\n"); + + } + return vrect_p; +} + +void max77900_wireless_chg_init(struct max77900_charger_data *charger) +{ + u32 vrect_mv = 0; + + pr_info("%s -------------------------------------------------- \n", __func__); + max77900_reg_write(charger->client, 0x18, 0x02); // ldo out enable + + vrect_mv = max77900_get_vrect(charger); + pr_info("%s (before) vrect_mv %d mV\n",__func__,vrect_mv); + max77900_get_vrect_target(charger); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x65, 0xa4); // 9V + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x68, 0xa4); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x6b, 0xa4); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x6e, 0xa4); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x71, 0xa3); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x74, 0xa3); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x77, 0xa3); + msleep(5); + + max77900_reg_write(charger->client, 0x7c, 87); + max77900_reg_write(charger->client, 0x7d, 80); + max77900_reg_write(charger->client, 0x7e, 48); + max77900_reg_write(charger->client, 0x7f, 49); + max77900_reg_write(charger->client, 0x7a, 0xa3); + msleep(500); + + vrect_mv = max77900_get_vrect(charger); + pr_info("%s (after) vrect_mv %d mV \n",__func__,vrect_mv); + max77900_get_vrect_target(charger); + + max77900_get_ldo_vout(charger); + max77900_set_ldo_vout(charger, 0xf5); // 0xeb 9V + max77900_get_ldo_vout(charger); + + max77900_reg_write(charger->client, 0x0e, 0x9a); // 0x99 - 1A + + pr_info("%s -------------------------------------------------- \n", __func__); +} + +static void max77900_detect_work( + struct work_struct *work) +{ + struct max77900_charger_data *charger = + container_of(work, struct max77900_charger_data, wpc_work.work); + + pr_info("%s\n", __func__); + + max77900_wireless_chg_init(charger); +} + +static int max77900_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + //struct max77900_charger_data *charger = + // container_of(psy, struct max77900_charger_data, psy_chg); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_CHARGE_TYPE: + case POWER_SUPPLY_PROP_HEALTH: + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: + return -ENODATA; + default: + return -EINVAL; + } + return 0; +} + +static int max77900_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct max77900_charger_data *charger = + container_of(psy, struct max77900_charger_data, psy_chg); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + max77900_reg_write(charger->client, 0x18, 0x02); // ldo out enable + break; + case POWER_SUPPLY_PROP_ONLINE: + if(val->intval == POWER_SUPPLY_TYPE_WIRELESS) { + max77900_wireless_chg_init(charger); + } + break; + default: + return -EINVAL; + } + + return 0; +} + +#if 0 +static void max77900_wpc_isr_work(struct work_struct *work) +{ + //struct bq51221_charger_data *charger = + // container_of(work, struct bq51221_charger_data, isr_work.work); + + pr_info("%s \n",__func__); +} + +static irqreturn_t max77900_wpc_irq_thread(int irq, void *irq_data) +{ + struct max77900_charger_data *charger = irq_data; + + pr_info("%s \n",__func__); + schedule_delayed_work(&charger->isr_work, 0); + + return IRQ_HANDLED; +} +#endif + +static int max77900_chg_parse_dt(struct device *dev, + max77900_charger_platform_data_t *pdata) +{ + int ret = 0; + struct device_node *np = dev->of_node; +// enum of_gpio_flags irq_gpio_flags; + + if (!np) { + pr_info("%s: np NULL\n", __func__); + return 1; + } + + np = of_find_node_by_name(NULL, "battery"); + if (!np) { + pr_err("%s np NULL\n", __func__); + } else { + + ret = of_property_read_string(np, + "battery,wirelss_charger_name", (char const **)&pdata->wireless_charger_name); + if (ret) + pr_info("%s: Vendor is Empty\n", __func__); + } + +#if 0 + ret = pdata->irq_gpio = of_get_named_gpio_flags(np, "max77900-charger,irq-gpio", + 0, &irq_gpio_flags); + if (ret < 0) { + dev_err(dev, "%s : can't get irq-gpio\r\n", __FUNCTION__); + return ret; + } + pr_info("%s irq_gpio = %d \n",__func__, pdata->irq_gpio); + pdata->irq_base = gpio_to_irq(pdata->irq_gpio); + +#endif + + return ret; +} + +static int max77900_charger_probe( + struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *of_node = client->dev.of_node; + struct max77900_charger_data *charger; + max77900_charger_platform_data_t *pdata = client->dev.platform_data; + int ret = 0; + + dev_info(&client->dev, + "%s: max77900 Charger Driver Loading\n", __func__); + + if (of_node) { + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + ret = max77900_chg_parse_dt(&client->dev, pdata); + if (ret < 0) + goto err_parse_dt; + } else { + pdata = client->dev.platform_data; + } + + charger = kzalloc(sizeof(*charger), GFP_KERNEL); + if (charger == NULL) { + dev_err(&client->dev, "Memory is not enough.\n"); + ret = -ENOMEM; + goto err_wpc_nomem; + } + charger->dev = &client->dev; + + ret = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); + if (!ret) { + ret = i2c_get_functionality(client->adapter); + dev_err(charger->dev, "I2C functionality is not supported.\n"); + ret = -ENOSYS; + goto err_i2cfunc_not_support; + } + + charger->client = client; + charger->pdata = pdata; + + pr_info("%s: %s\n", __func__, charger->pdata->wireless_charger_name ); + +#if 0 + /* if board-init had already assigned irq_base (>=0) , + no need to allocate it; + assign -1 to let this driver allocate resource by itself*/ + + if (pdata->irq_base < 0) + pdata->irq_base = irq_alloc_descs(-1, 0, MAX77900_EVENT_IRQ, 0); + if (pdata->irq_base < 0) { + pr_err("%s: irq_alloc_descs Fail! ret(%d)\n", + __func__, pdata->irq_base); + ret = -EINVAL; + goto irq_base_err; + } else { + charger->irq_base = pdata->irq_base; + pr_info("%s: irq_base = %d\n", + __func__, charger->irq_base); + +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,4,0)) + irq_domain_add_legacy(of_node, MAX77900_EVENT_IRQ, charger->irq_base, 0, + &irq_domain_simple_ops, NULL); +#endif /*(LINUX_VERSION_CODE>=KERNEL_VERSION(3,4,0))*/ + } +#endif + + i2c_set_clientdata(client, charger); + + charger->psy_chg.name = pdata->wireless_charger_name; + charger->psy_chg.type = POWER_SUPPLY_TYPE_UNKNOWN; + charger->psy_chg.get_property = max77900_chg_get_property; + charger->psy_chg.set_property = max77900_chg_set_property; + charger->psy_chg.properties = sec_charger_props; + charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props); + + mutex_init(&charger->io_lock); + +#if 0 + if (charger->wpc_irq) { + INIT_DELAYED_WORK( + &charger->isr_work, max77900_wpc_isr_work); + + ret = request_threaded_irq(charger->wpc_irq, + NULL, max77900_wpc_irq_thread, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "charger-irq", charger); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Reqeust IRQ\n", __func__); + goto err_supply_unreg; + } + + ret = enable_irq_wake(charger->wpc_irq); + if (ret < 0) + dev_err(&client->dev, + "%s: Failed to Enable Wakeup Source(%d)\n", + __func__, ret); + } +#endif + + ret = power_supply_register(&client->dev, &charger->psy_chg); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Register psy_chg\n", __func__); + goto err_supply_unreg; + } + + charger->wqueue = create_workqueue("max77900_workqueue"); + if (!charger->wqueue) { + pr_err("%s: Fail to Create Workqueue\n", __func__); + goto err_pdata_free; + } + + wake_lock_init(&(charger->wpc_wake_lock), WAKE_LOCK_SUSPEND, + "wpc_wakelock"); + INIT_DELAYED_WORK(&charger->wpc_work, max77900_detect_work); + + dev_info(&client->dev, + "%s: max77900 Charger Driver Loaded\n", __func__); + + return 0; + +err_pdata_free: + power_supply_unregister(&charger->psy_chg); +err_supply_unreg: + mutex_destroy(&charger->io_lock); +err_i2cfunc_not_support: +//irq_base_err: + kfree(charger); +err_wpc_nomem: +err_parse_dt: + kfree(pdata); + return ret; +} + +static int max77900_charger_remove(struct i2c_client *client) +{ + return 0; +} + +#if defined CONFIG_PM +static int max77900_charger_suspend(struct i2c_client *client, + pm_message_t state) +{ + + + return 0; +} + +static int max77900_charger_resume(struct i2c_client *client) +{ + + + return 0; +} +#else +#define max77900_charger_suspend NULL +#define max77900_charger_resume NULL +#endif + +static void max77900_charger_shutdown(struct i2c_client *client) +{ + +} + +static const struct i2c_device_id max77900_charger_id_table[] = { + { "max77900-charger", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max77900_id_table); + +#ifdef CONFIG_OF +static struct of_device_id max77900_charger_match_table[] = { + { .compatible = "maxim,max77900-charger",}, + {}, +}; +#else +#define max77900_charger_match_table NULL +#endif + +static struct i2c_driver max77900_charger_driver = { + .driver = { + .name = "max77900-charger", + .owner = THIS_MODULE, + .of_match_table = max77900_charger_match_table, + }, + .shutdown = max77900_charger_shutdown, + .suspend = max77900_charger_suspend, + .resume = max77900_charger_resume, + .probe = max77900_charger_probe, + .remove = max77900_charger_remove, + .id_table = max77900_charger_id_table, +}; + +static int __init max77900_charger_init(void) +{ + pr_info("%s \n",__func__); + return i2c_add_driver(&max77900_charger_driver); +} + +static void __exit max77900_charger_exit(void) +{ + pr_info("%s \n",__func__); + i2c_del_driver(&max77900_charger_driver); +} + +module_init(max77900_charger_init); +module_exit(max77900_charger_exit); + +MODULE_DESCRIPTION("Samsung max77900 Charger Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/battery/p9220_charger.c b/drivers/battery/p9220_charger.c new file mode 100644 index 000000000000..25e47e7c83c9 --- /dev/null +++ b/drivers/battery/p9220_charger.c @@ -0,0 +1,896 @@ +/* + * p9220_charger.c + * Samsung p9220 Charger Driver + * + * Copyright (C) 2015 Samsung Electronics + * Yeongmi Ha + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENABLE 1 +#define DISABLE 0 + +static enum power_supply_property sec_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, + POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL, +}; + +static struct i2c_client *p9220_i2c; +static const u8 OTPBootloader[] = { +0x00, 0x04, 0x00, 0x20, 0x57, 0x01, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xFE, 0xE7, 0x00, 0x00, 0x80, 0x00, 0x00, 0xE0, 0x00, 0xBF, 0x40, 0x1E, 0xFC, 0xD2, 0x70, 0x47, +0x00, 0xB5, 0x6F, 0x4A, 0x6F, 0x4B, 0x01, 0x70, 0x01, 0x20, 0xFF, 0xF7, 0xF3, 0xFF, 0x52, 0x1E, +0x02, 0xD0, 0x18, 0x8B, 0x00, 0x06, 0xF7, 0xD4, 0x00, 0xBD, 0xF7, 0xB5, 0x05, 0x46, 0x6A, 0x48, +0x81, 0xB0, 0x00, 0x21, 0x94, 0x46, 0x81, 0x81, 0x66, 0x48, 0x31, 0x21, 0x01, 0x80, 0x04, 0x21, +0x81, 0x80, 0x06, 0x21, 0x01, 0x82, 0x28, 0x20, 0xFF, 0xF7, 0xDC, 0xFF, 0x00, 0x24, 0x15, 0xE0, +0x02, 0x99, 0x28, 0x5D, 0x09, 0x5D, 0x02, 0x46, 0x8A, 0x43, 0x01, 0xD0, 0x10, 0x20, 0x50, 0xE0, +0x81, 0x43, 0x0A, 0xD0, 0x5D, 0x4E, 0xB0, 0x89, 0x08, 0x27, 0x38, 0x43, 0xB0, 0x81, 0x28, 0x19, +0xFF, 0xF7, 0xCE, 0xFF, 0xB0, 0x89, 0xB8, 0x43, 0xB0, 0x81, 0x64, 0x1C, 0x64, 0x45, 0xE7, 0xD3, +0x54, 0x48, 0x36, 0x21, 0x01, 0x82, 0x00, 0x24, 0x38, 0xE0, 0x02, 0x98, 0x00, 0x27, 0x06, 0x5D, +0x52, 0x48, 0x82, 0x89, 0x08, 0x21, 0x0A, 0x43, 0x82, 0x81, 0x28, 0x19, 0x00, 0x90, 0x4D, 0x4A, +0x08, 0x20, 0x90, 0x80, 0x02, 0x20, 0xFF, 0xF7, 0xAD, 0xFF, 0x28, 0x5D, 0x33, 0x46, 0x83, 0x43, +0x15, 0xD0, 0x48, 0x49, 0x04, 0x20, 0x88, 0x80, 0x02, 0x20, 0xFF, 0xF7, 0xA3, 0xFF, 0x19, 0x46, +0x00, 0x98, 0xFF, 0xF7, 0xA5, 0xFF, 0x43, 0x49, 0x0F, 0x20, 0x88, 0x80, 0x02, 0x20, 0xFF, 0xF7, +0x99, 0xFF, 0x28, 0x5D, 0xB0, 0x42, 0x02, 0xD0, 0x7F, 0x1C, 0x0A, 0x2F, 0xDF, 0xD3, 0x3F, 0x48, +0x82, 0x89, 0x08, 0x21, 0x8A, 0x43, 0x82, 0x81, 0x0A, 0x2F, 0x06, 0xD3, 0x3C, 0x48, 0x29, 0x19, +0x41, 0x80, 0x29, 0x5D, 0xC1, 0x80, 0x04, 0x20, 0x03, 0xE0, 0x64, 0x1C, 0x64, 0x45, 0xC4, 0xD3, +0x02, 0x20, 0x34, 0x49, 0x11, 0x22, 0x0A, 0x80, 0x04, 0x22, 0x8A, 0x80, 0x32, 0x49, 0xFF, 0x22, +0x8A, 0x81, 0x04, 0xB0, 0xF0, 0xBD, 0x34, 0x49, 0x32, 0x48, 0x08, 0x60, 0x2F, 0x4D, 0x00, 0x22, +0xAA, 0x81, 0x2E, 0x4E, 0x20, 0x3E, 0xB2, 0x83, 0x2A, 0x80, 0x2B, 0x48, 0x5A, 0x21, 0x40, 0x38, +0x01, 0x80, 0x81, 0x15, 0x81, 0x80, 0x0B, 0x21, 0x01, 0x81, 0x2C, 0x49, 0x81, 0x81, 0x14, 0x20, +0xFF, 0xF7, 0x60, 0xFF, 0x2A, 0x4B, 0x01, 0x20, 0x18, 0x80, 0x02, 0x20, 0xFF, 0xF7, 0x5A, 0xFF, +0x8D, 0x20, 0x18, 0x80, 0x9A, 0x80, 0xFF, 0x20, 0x98, 0x82, 0x03, 0x20, 0x00, 0x02, 0x18, 0x82, +0xFC, 0x20, 0x98, 0x83, 0x22, 0x49, 0x95, 0x20, 0x20, 0x31, 0x08, 0x80, 0x1C, 0x4C, 0x0C, 0x20, +0x22, 0x80, 0xA8, 0x81, 0x20, 0x20, 0xB0, 0x83, 0x28, 0x80, 0xAA, 0x81, 0x04, 0x26, 0xA8, 0x89, +0x30, 0x43, 0xA8, 0x81, 0x20, 0x88, 0x01, 0x28, 0x1B, 0xD1, 0x61, 0x88, 0x80, 0x03, 0xA2, 0x88, +0x08, 0x18, 0x51, 0x18, 0x8B, 0xB2, 0x00, 0x21, 0x04, 0xE0, 0x0F, 0x19, 0x3F, 0x7A, 0xFB, 0x18, +0x9B, 0xB2, 0x49, 0x1C, 0x8A, 0x42, 0xF8, 0xD8, 0xE1, 0x88, 0x27, 0x46, 0x99, 0x42, 0x01, 0xD0, +0x08, 0x20, 0x0B, 0xE0, 0x00, 0x2A, 0x08, 0xD0, 0x09, 0x49, 0x08, 0x31, 0xFF, 0xF7, 0x35, 0xFF, +0x38, 0x80, 0xA8, 0x89, 0xB0, 0x43, 0xA8, 0x81, 0xD9, 0xE7, 0x02, 0x20, 0x20, 0x80, 0xD6, 0xE7, +0x10, 0x27, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x40, 0x40, 0x30, 0x00, 0x40, 0x20, 0x6C, 0x00, 0x40, +0x00, 0x04, 0x00, 0x20, 0xFF, 0x0F, 0x00, 0x00, 0x80, 0xE1, 0x00, 0xE0, 0x04, 0x1D, 0x00, 0x00, +0x00, 0x64, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static int p9220_reg_read(struct i2c_client *client, u16 reg, u8 *val) +{ + int ret; + struct i2c_msg msg[2]; + u8 wbuf[2]; + u8 rbuf[2]; + + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = 2; + msg[0].buf = wbuf; + + wbuf[0] = (reg & 0xFF00) >> 8; + wbuf[1] = (reg & 0xFF); + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = rbuf; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + pr_err("%s: i2c transfer fail", __func__); + pr_err("%s: reg = 0x%x, val = 0x%x\n", __func__, reg, rbuf[0]); + *val = rbuf[0]; + + return ret; +} + +static int p9220_reg_multi_read(struct i2c_client *client, u16 reg, u8 *val, int size) +{ + int ret; + struct i2c_msg msg[2]; + u8 wbuf[2]; + + pr_err("%s: reg = 0x%x, size = 0x%x\n", __func__, reg, size); + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = 2; + msg[0].buf = wbuf; + + wbuf[0] = (reg & 0xFF00) >> 8; + wbuf[1] = (reg & 0xFF); + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = size; + msg[1].buf = val; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + pr_err("%s: i2c transfer fail", __func__); + + return ret; +} + +static int p9220_reg_write(struct i2c_client *client, u16 reg, u8 val) +{ + int ret; + unsigned char data[3] = { reg >> 8, reg & 0xff, val }; + + ret = i2c_master_send(client, data, 3); + if (ret < 3) { + dev_err(&client->dev, "%s: i2c write error, reg: 0x%x, ret: %d\n", + __func__, reg, ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} +#if 0 +static int p9220_reg_multi_read(struct i2c_client *client, u16 reg, u8 *val, int size) +{ + int ret; + /* We have 16-bit i2c addresses - care for endianess */ + unsigned char data[2] = { reg >> 8, reg & 0xff }; + + ret = i2c_master_send(client, data, 2); + if (ret < 2) { + dev_err(&client->dev, "%s: i2c read error, reg: %x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + + ret = i2c_master_recv(client, val, size); + if (ret < size) { + dev_err(&client->dev, "%s: i2c read error, reg: %x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + return 0; +} +#endif +static int p9220_reg_multi_write(struct i2c_client *client, u16 reg, const u8 * val, int size) +{ + int ret; + const int sendsz = 16; + unsigned char data[sendsz]; + int cnt = 0; + + dev_err(&client->dev, "%s: size: 0x%x\n", + __func__, size); + while(size > sendsz) { + data[0] = (reg+cnt) >>8; + data[1] = (reg+cnt) & 0xff; + memcpy(data+2, val+cnt, sendsz); + dev_err(&client->dev, "%s: addr: 0x%x, cnt: 0x%x\n", __func__, reg+cnt, cnt); + ret = i2c_master_send(client, data, sendsz+2); + if (ret < sendsz+2) { + dev_err(&client->dev, "%s: i2c write error, reg: 0x%x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + cnt = cnt + sendsz; + size = size - sendsz; + } + if (size > 0) { + data[0] = (reg+cnt) >>8; + data[1] = (reg+cnt) & 0xff; + memcpy(data+2, val+cnt, size); + dev_err(&client->dev, "%s: addr: 0x%x, cnt: 0x%x, size: 0x%x\n", __func__, reg+cnt, cnt, size); + ret = i2c_master_send(client, data, size+2); + if (ret < size+2) { + dev_err(&client->dev, "%s: i2c write error, reg: 0x%x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + } + + return 0; +} +/* +static int p9220_reg_multi_write(struct i2c_client *client, u16 reg, const u8 * val, int size) +{ + int ret; + unsigned char * data = kmalloc(size, GFP_KERNEL); + + if (data == NULL) { + dev_err(&client->dev, "%s: kmalloc fail\n", + __func__); + return -1; + } + dev_err(&client->dev, "%s: size: 0x%x\n", + __func__, size); + data[0] = reg >>8; + data[1] = reg & 0xff; + memcpy(data+2, val, size); + ret = i2c_master_send(client, data, size+2); + kfree(data); + if (ret < size+2) { + dev_err(&client->dev, "%s: i2c write error, reg: 0x%x\n", + __func__, reg); + return ret < 0 ? ret : -EIO; + } + + return 0; +} +*/ + +static int datacmp(const char *cs, const char *ct, int count) +{ + unsigned char c1, c2; + + while (count) { + c1 = *cs++; + c2 = *ct++; + if (c1 != c2) { + pr_err("%s, cnt %d", __func__, count); + return c1 < c2 ? -1 : 1; + } + count--; + } + return 0; +} +static int LoadOTPLoaderInRAM(u16 addr) +{ + int i, size; + u8 data[1024]; + if (p9220_reg_multi_write(p9220_i2c, addr, OTPBootloader, sizeof(OTPBootloader)) < 0) { + pr_err("%s,fail", __func__); + } + size = sizeof(OTPBootloader); + i = 0; + while(size > 0) { + pr_err("%s, 0x%x: , 0x%x", __func__, addr+i, size); + if (p9220_reg_multi_read(p9220_i2c, addr+i, data+i, 16) < 0) { + pr_err("%s, read failed(%d)", __func__, addr+i); + return 0; + } + i += 16; + size -= 16; + } + i = 0; + for (i = 0 ; i < sizeof(OTPBootloader); i++) { + if (i%16 == 0) + pr_err("addr = 0x%x : ", addr+i); + pr_err(" 0x%x,", data[i]); + if (i%16 == 15) + pr_err("\n"); + } + + if (datacmp(data, OTPBootloader, sizeof(OTPBootloader))) { + pr_err("%s, data is not matched", __func__); + return 0; + } + return 1; +} +static int PgmOTPwRAM(unsigned short OtpAddr, const u8 * srcData, int srcOffs, int size) +{ + //DateTime pgmSt = DateTime.Now; + int i, j, cnt; + + pr_info("%s Start ---------------------------------------- \n",__func__); + if (!p9220_i2c) { + pr_err("%s: i2c is not probed\n", __func__); + return false; // write key + } + /* + if (!ConvertStr2Num(comboBoxDeviceI2cAddr.Text, out i2cDeviceAddr)) + { + addText("ERROR: I2C Device Address Invalid"); + return false; + } + addText(""); + */ + //ignoreNAK = false; // restore to default in case previous call did not finish + // configure the system + if (p9220_reg_write(p9220_i2c, 0x3000, 0x5a) < 0) { + pr_err("%s: write key error\n", __func__); + return false; // write key + } + if (p9220_reg_write(p9220_i2c, 0x3040, 0x10) < 0) { + pr_err("%s: halt M0 error\n", __func__); + return false; // halt M0 + } + if (!LoadOTPLoaderInRAM(0x1c00)){ + pr_err("%s: LoadOTPLoaderInRAM error\n", __func__); + return false; // make sure load address and 1KB size are OK + } + + if (p9220_reg_write(p9220_i2c, 0x3048, 0x80) < 0) { + pr_err("%s: map RAM to OTP error\n", __func__); + return false; // map RAM to OTP + } + //if (!Write9220Byte(0x3008, 0x20)) {return false; // ahb lower + //ignoreNAK = true; + //if (!Write9220Byte(0x3040, 0x80)) return false; // run M0 + p9220_reg_write(p9220_i2c, 0x3040, 0x80); + /* + if (p9220_reg_write(p9220_i2c, 0x3040, 0x80) < 0) { + pr_err("%s: run M0 error\n", __func__); + return false; // halt M0 + } + */ + //ignoreNAK = false; + + msleep(100); + + for (i = 0; i < size; i += 128) // program pages of 128 bytes + { + u8 sBuf[136] = {0,}; + u16 StartAddr = (u16)i; + u16 CheckSum = StartAddr; + u16 CodeLength = 128; + //Array.Copy(srcData, i + srcOffs, sBuf, 8, 128); //(src, srcoffset, dst, dstoffset, size) + memcpy(sBuf + 8, srcData + i + srcOffs, 128); + + for (j = 127; j >= 0; j--) + { + if (sBuf[j + 8] != 0) + break; + else + CodeLength--; + } + if (CodeLength == 0) + continue; // skip programming if nothing to program + for (; j >= 0; j--) + CheckSum += sBuf[j + 8]; // add the non zero values + CheckSum += CodeLength; // finish calculation of the check sum + + //Array.Copy(BitConverter.GetBytes(StartAddr), 0, sBuf, 2, 2); + memcpy(sBuf+2, &StartAddr,2); + //Array.Copy(BitConverter.GetBytes(CodeLength), 0, sBuf, 4, 2); + memcpy(sBuf+4, &CodeLength,2); + //Array.Copy(BitConverter.GetBytes(CheckSum), 0, sBuf, 6, 2); + memcpy(sBuf+6, &CheckSum,2); + + //typedef struct { // write to structure at address 0x400 + // u16 Status; + // u16 StartAddr; + // u16 CodeLength; + // u16 DataChksum; + // u8 DataBuf[128]; + //} P9220PgmStrType; + + // read status is guaranteed to be != 1 at this point + + //if (!Xfer9220i2c(p9220_i2c, 0x400, 0x100, sBuf, 0, CodeLength + 8,ReadWrite.WRITE)) + if (p9220_reg_multi_write(p9220_i2c, 0x400, sBuf, CodeLength + 8) < 0) + { + pr_err("ERROR: on writing to OTP buffer"); + return false; + } + sBuf[0] = 1; + //if (!Xfer9220i2c(i2cDeviceAddr, 0x400, 0x100, sBuf, 0, 1, ReadWrite.WRITE)) + if (p9220_reg_write(p9220_i2c, 0x400, sBuf[0]) < 0) + { + pr_err("ERROR: on OTP buffer validation"); + return false; + } + + //DateTime startT = DateTime.Now; + cnt = 0; + do + { + msleep(20); + //if (!Xfer9220i2c(i2cDeviceAddr, 0x400, 0x100, sBuf, 0, 1, ReadWrite.READ)) + if (p9220_reg_read(p9220_i2c, 0x400, sBuf) < 0) + { + pr_err("ERROR: on readign OTP buffer status(%d)", cnt); + return false; + } + /* + TimeSpan pas = DateTime.Now - startT; + if (pas.TotalMilliseconds > 5000) + { + pr_err("ERROR: time out on buffer program to OTP"); + return false; + } + */ + if (cnt > 1000) { + pr_err("ERROR: time out on buffer program to OTP"); + break; + } + cnt++; + } while (sBuf[0] == 1); + + // check status + if (sBuf[0] != 2) // not OK + { + pr_err("ERROR: buffer write to OTP returned status %d ",sBuf[0]); + return false; + } + } + + // restore system + if (p9220_reg_write(p9220_i2c, 0x3000, 0x5a) < 0) { + pr_err("%s: write key error..\n", __func__); + return false; // write key + } + if (p9220_reg_write(p9220_i2c, 0x3048, 0x00) < 0) { + pr_err("%s: remove code remapping error..\n", __func__); + return false; // remove code remapping + } + //if (!Write9220Byte(0x3040, 0x80)) return false; // reset M0 + + // TimeSpan pgmSp = DateTime.Now - pgmSt; + pr_err("OTP Programming finished in"); + pr_info("%s------------------------------------------------- \n", __func__); + return true; +} + +#define P9220S_FW_SDCARD_BIN_PATH "sdcard/p9220_otp.bin" +#define P9220S_FW_HEX_PATH "idt/p9220_otp.fw" +#define SDCARD 0 +#define BUILT_IN 1 + +int p9220_otp_update = 0; + +int p9220_firmware_update(struct p9220_charger_data *charger, int cmd) +{ + struct file *fp; + mm_segment_t old_fs; + long fsize, nread; + int ret = 0; + const u8 *fw_img; + + pr_info("%s firmware update mode is = %d \n", __func__, cmd); + + switch(cmd) { + case SDCARD: + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(P9220S_FW_SDCARD_BIN_PATH, O_RDONLY, S_IRUSR); + + if (IS_ERR(fp)) { + pr_err("%s: failed to open %s\n", __func__, P9220S_FW_SDCARD_BIN_PATH); + ret = -ENOENT; + set_fs(old_fs); + return ret; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + pr_err("%s: start, file path %s, size %ld Bytes\n", + __func__, P9220S_FW_SDCARD_BIN_PATH, fsize); + + fw_img = kmalloc(fsize, GFP_KERNEL); + + if (fw_img == NULL) { + pr_err("%s, kmalloc failed\n", __func__); + ret = -EFAULT; + goto malloc_error; + } + + nread = vfs_read(fp, (char __user *)fw_img, + fsize, &fp->f_pos); + pr_err("nread %ld Bytes\n", nread); + if (nread != fsize) { + pr_err("failed to read firmware file, nread %ld Bytes\n", nread); + ret = -EIO; + goto read_err; + } + + filp_close(fp, current->files); + set_fs(old_fs); + p9220_otp_update = 1; + PgmOTPwRAM(0 ,fw_img, 0, fsize); + p9220_otp_update = 0; + + kfree(fw_img); + break; + case BUILT_IN: + dev_err(&p9220_i2c->dev, "%s, request_firmware\n", __func__); + ret = request_firmware(&charger->firm_data_bin, P9220S_FW_HEX_PATH, + &p9220_i2c->dev); + if ( ret < 0) { + dev_err(&p9220_i2c->dev, "%s: failed to request firmware %s (%d) \n", __func__, P9220S_FW_HEX_PATH, ret); + return -EINVAL; + } + pr_info("%s data size = %ld \n", __func__, charger->firm_data_bin->size); + p9220_otp_update = 1; + PgmOTPwRAM(0 ,charger->firm_data_bin->data, 0, charger->firm_data_bin->size); + p9220_otp_update = 0; + release_firmware(charger->firm_data_bin); + break; + default: + return -1; + break; + } + + pr_info("%s --------------------------------------------------------------- \n", __func__); + + return 0; + +read_err: + kfree(fw_img); +malloc_error: + filp_close(fp, current->files); + set_fs(old_fs); + return ret; +} + +void p9220_wireless_chg_init(struct p9220_charger_data *charger) +{ + pr_info("%s ------------wireless chg init------------- \n", __func__); + +} + +static void p9220_detect_work( + struct work_struct *work) +{ + struct p9220_charger_data *charger = + container_of(work, struct p9220_charger_data, wpc_work.work); + + pr_info("%s\n", __func__); + + p9220_wireless_chg_init(charger); +} + +static int p9220_chg_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + //struct p9220_charger_data *charger = + // container_of(psy, struct p9220_charger_data, psy_chg); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_CHARGE_TYPE: + case POWER_SUPPLY_PROP_HEALTH: + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: + case POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL: + return -ENODATA; + default: + return -EINVAL; + } + return 0; +} + +static int p9220_chg_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct p9220_charger_data *charger = + container_of(psy, struct p9220_charger_data, psy_chg); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + break; + case POWER_SUPPLY_PROP_ONLINE: + if(val->intval == POWER_SUPPLY_TYPE_WIRELESS) { + p9220_wireless_chg_init(charger); + } + break; + case POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL: + p9220_firmware_update(charger, val->intval); + break; + default: + return -EINVAL; + } + + return 0; +} + +#if 0 +static void p9220_wpc_isr_work(struct work_struct *work) +{ + //struct bq51221_charger_data *charger = + // container_of(work, struct bq51221_charger_data, isr_work.work); + + pr_info("%s \n",__func__); +} + +static irqreturn_t p9220_wpc_irq_thread(int irq, void *irq_data) +{ + struct p9220_charger_data *charger = irq_data; + + pr_info("%s \n",__func__); + schedule_delayed_work(&charger->isr_work, 0); + + return IRQ_HANDLED; +} +#endif + +static int p9220_chg_parse_dt(struct device *dev, + p9220_charger_platform_data_t *pdata) +{ + int ret = 0; + struct device_node *np = dev->of_node; +// enum of_gpio_flags irq_gpio_flags; + + if (!np) { + pr_info("%s: np NULL\n", __func__); + return 1; + } + + np = of_find_node_by_name(NULL, "battery"); + if (!np) { + pr_err("%s np NULL\n", __func__); + } else { + + ret = of_property_read_string(np, + "battery,wirelss_charger_name", (char const **)&pdata->wireless_charger_name); + if (ret) + pr_info("%s: Vendor is Empty\n", __func__); + } + +#if 0 + ret = pdata->irq_gpio = of_get_named_gpio_flags(np, "p9220-charger,irq-gpio", + 0, &irq_gpio_flags); + if (ret < 0) { + dev_err(dev, "%s : can't get irq-gpio\r\n", __FUNCTION__); + return ret; + } + pr_info("%s irq_gpio = %d \n",__func__, pdata->irq_gpio); + pdata->irq_base = gpio_to_irq(pdata->irq_gpio); + +#endif + + return ret; +} + +static int p9220_charger_probe( + struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *of_node = client->dev.of_node; + struct p9220_charger_data *charger; + p9220_charger_platform_data_t *pdata = client->dev.platform_data; + int ret = 0; + + dev_info(&client->dev, + "%s: p9220 Charger Driver Loading\n", __func__); + + if (of_node) { + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + ret = p9220_chg_parse_dt(&client->dev, pdata); + if (ret < 0) + goto err_parse_dt; + } else { + pdata = client->dev.platform_data; + } + + charger = kzalloc(sizeof(*charger), GFP_KERNEL); + if (charger == NULL) { + dev_err(&client->dev, "Memory is not enough.\n"); + ret = -ENOMEM; + goto err_wpc_nomem; + } + charger->dev = &client->dev; + + ret = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK); + if (!ret) { + ret = i2c_get_functionality(client->adapter); + dev_err(charger->dev, "I2C functionality is not supported.\n"); + ret = -ENOSYS; + goto err_i2cfunc_not_support; + } + + charger->client = client; + p9220_i2c = client; + charger->pdata = pdata; + + pr_info("%s: %s\n", __func__, charger->pdata->wireless_charger_name ); + +#if 0 + /* if board-init had already assigned irq_base (>=0) , + no need to allocate it; + assign -1 to let this driver allocate resource by itself*/ + + if (pdata->irq_base < 0) + pdata->irq_base = irq_alloc_descs(-1, 0, p9220_EVENT_IRQ, 0); + if (pdata->irq_base < 0) { + pr_err("%s: irq_alloc_descs Fail! ret(%d)\n", + __func__, pdata->irq_base); + ret = -EINVAL; + goto irq_base_err; + } else { + charger->irq_base = pdata->irq_base; + pr_info("%s: irq_base = %d\n", + __func__, charger->irq_base); + +#if (LINUX_VERSION_CODE>=KERNEL_VERSION(3,4,0)) + irq_domain_add_legacy(of_node, p9220_EVENT_IRQ, charger->irq_base, 0, + &irq_domain_simple_ops, NULL); +#endif /*(LINUX_VERSION_CODE>=KERNEL_VERSION(3,4,0))*/ + } +#endif + + i2c_set_clientdata(client, charger); + + charger->psy_chg.name = pdata->wireless_charger_name; + charger->psy_chg.type = POWER_SUPPLY_TYPE_UNKNOWN; + charger->psy_chg.get_property = p9220_chg_get_property; + charger->psy_chg.set_property = p9220_chg_set_property; + charger->psy_chg.properties = sec_charger_props; + charger->psy_chg.num_properties = ARRAY_SIZE(sec_charger_props); + + mutex_init(&charger->io_lock); + +#if 0 + if (charger->wpc_irq) { + INIT_DELAYED_WORK( + &charger->isr_work, p9220_wpc_isr_work); + + ret = request_threaded_irq(charger->wpc_irq, + NULL, p9220_wpc_irq_thread, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "charger-irq", charger); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Reqeust IRQ\n", __func__); + goto err_supply_unreg; + } + + ret = enable_irq_wake(charger->wpc_irq); + if (ret < 0) + dev_err(&client->dev, + "%s: Failed to Enable Wakeup Source(%d)\n", + __func__, ret); + } +#endif + + ret = power_supply_register(&client->dev, &charger->psy_chg); + if (ret) { + dev_err(&client->dev, + "%s: Failed to Register psy_chg\n", __func__); + goto err_supply_unreg; + } + + charger->wqueue = create_workqueue("p9220_workqueue"); + if (!charger->wqueue) { + pr_err("%s: Fail to Create Workqueue\n", __func__); + goto err_pdata_free; + } + + wake_lock_init(&(charger->wpc_wake_lock), WAKE_LOCK_SUSPEND, + "wpc_wakelock"); + INIT_DELAYED_WORK(&charger->wpc_work, p9220_detect_work); + + dev_info(&client->dev, + "%s: p9220 Charger Driver Loaded\n", __func__); + + return 0; + +err_pdata_free: + power_supply_unregister(&charger->psy_chg); +err_supply_unreg: + mutex_destroy(&charger->io_lock); +err_i2cfunc_not_support: +//irq_base_err: + kfree(charger); +err_wpc_nomem: +err_parse_dt: + kfree(pdata); + return ret; +} + +static int p9220_charger_remove(struct i2c_client *client) +{ + return 0; +} + +#if defined CONFIG_PM +static int p9220_charger_suspend(struct i2c_client *client, + pm_message_t state) +{ + + + return 0; +} + +static int p9220_charger_resume(struct i2c_client *client) +{ + + + return 0; +} +#else +#define p9220_charger_suspend NULL +#define p9220_charger_resume NULL +#endif + +static void p9220_charger_shutdown(struct i2c_client *client) +{ + int dummy; + u8 dummmmy; + + dummy = 0; + if (dummy) { + dummy = p9220_reg_write(client, 0x05, 0x05); + dummy = p9220_reg_read(client, 0x05, &dummmmy); + } + +} + +static const struct i2c_device_id p9220_charger_id_table[] = { + { "p9220-charger", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, p9220_id_table); + +#ifdef CONFIG_OF +static struct of_device_id p9220_charger_match_table[] = { + { .compatible = "idt,p9220-charger",}, + {}, +}; +#else +#define p9220_charger_match_table NULL +#endif + +static struct i2c_driver p9220_charger_driver = { + .driver = { + .name = "p9220-charger", + .owner = THIS_MODULE, + .of_match_table = p9220_charger_match_table, + }, + .shutdown = p9220_charger_shutdown, + .suspend = p9220_charger_suspend, + .resume = p9220_charger_resume, + .probe = p9220_charger_probe, + .remove = p9220_charger_remove, + .id_table = p9220_charger_id_table, +}; + +static int __init p9220_charger_init(void) +{ + pr_info("%s \n",__func__); + return i2c_add_driver(&p9220_charger_driver); +} + +static void __exit p9220_charger_exit(void) +{ + pr_info("%s \n",__func__); + i2c_del_driver(&p9220_charger_driver); +} + +module_init(p9220_charger_init); +module_exit(p9220_charger_exit); + +MODULE_DESCRIPTION("Samsung p9220 Charger Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/battery/sec_adc.c b/drivers/battery/sec_adc.c index 8c8c2f8392f3..6a1d6dcb1836 100644 --- a/drivers/battery/sec_adc.c +++ b/drivers/battery/sec_adc.c @@ -55,6 +55,7 @@ static int sec_bat_adc_ap_read(int channel) else pr_debug("INBAT ADC(%d)\n", data); break; +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING case SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK: ret = iio_read_channel_raw(&temp_adc[3], &data); if (ret < 0) @@ -69,6 +70,14 @@ static int sec_bat_adc_ap_read(int channel) else pr_debug("DISCHARGING NTC(%d)\n", data); break; +#endif + case SEC_BAT_ADC_CHANNEL_WPC_TEMP: + ret = iio_read_channel_raw(&temp_adc[5], &data); + if (ret < 0) + pr_info("read channel error[%d]\n", ret); + else + pr_info("WPC TEMP(%d)\n", data); + break; default: break; } @@ -109,12 +118,16 @@ static int adc_read_type(struct sec_battery_info *battery, int channel) { int adc = 0; - if ((!battery->pdata->self_discharging_en) && - ((channel == SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK) || - (channel == SEC_BAT_ADC_CHANNEL_DISCHARGING_NTC))) { - pr_info("%s : Doesn't enable Self Discharging Algorithm\n", __func__); - return 0; +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (battery->pdata->sdchg_info && battery->pdata->sdchg_info->chip) { + if ((!battery->pdata->sdchg_info->chip->sdchg_en) && + ((channel == SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK) || + (channel == SEC_BAT_ADC_CHANNEL_DISCHARGING_NTC))) { + pr_info("%s : Doesn't enable Self Discharging Algorithm\n", __func__); + return 0; + } } +#endif switch (battery->pdata->temp_adc_type) { diff --git a/drivers/battery/sec_batt_selfdchg_common.c b/drivers/battery/sec_batt_selfdchg_common.c new file mode 100644 index 000000000000..a57d4adf3b10 --- /dev/null +++ b/drivers/battery/sec_batt_selfdchg_common.c @@ -0,0 +1,79 @@ +/* + * Samsung Mobile VE Group. + * + * drivers/battery/sec_batt_selfdchg_common.c + * + * Common functions for samsung batter self discharging. + * + * Copyright (C) 2015, Samsung Electronics. + * + * 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 + */ + +#include + +#include + +struct list_head sdchg_info_head = LIST_HEAD_INIT(sdchg_info_head); +bool sdchg_nochip_support; + +/****************************************************************/ +static __kernel_time_t start_sec; +static __kernel_time_t curr_sec; +static __kernel_time_t target_sec; +static unsigned long target_time; +static bool sdchg_set_polling; + + +// true : runned sdchg polling time, false : other polling time at monitor work +bool sdchg_check_polling_time(__kernel_time_t curr) +{ + curr_sec = curr; + if (sdchg_set_polling) + if ((unsigned long)curr_sec >= (unsigned long)(target_sec - 10)) { + sdchg_set_polling = false; + return true; + } + return false; +} + + +void sdchg_set_polling_time(int polling_time) +{ + if (polling_time == 0) { + sdchg_set_polling = false; + goto out; + } + + start_sec = curr_sec; + target_time = polling_time; + target_sec = start_sec + polling_time; + + sdchg_set_polling = true; +out: + return; +} + + +unsigned int sdchg_get_polling_time(unsigned int cur_polling_time) +{ + unsigned int new_polling_time = cur_polling_time; + unsigned long elapse_time, remain_time; + + if (!sdchg_set_polling || target_time == 1 ) + goto out; + + elapse_time = (unsigned long)(curr_sec - start_sec); + remain_time = target_time - elapse_time; + + if (remain_time < new_polling_time) + new_polling_time = remain_time; +out: + //pr_info("[SDCHG][%s] new polling time = %u\n", __func__, new_polling_time); + return new_polling_time; +} + + +/****************************************************************/ diff --git a/drivers/battery/sec_batt_selfdchg_exynos7420_ap_use.c b/drivers/battery/sec_batt_selfdchg_exynos7420_ap_use.c new file mode 100644 index 000000000000..9896bb5b05e4 --- /dev/null +++ b/drivers/battery/sec_batt_selfdchg_exynos7420_ap_use.c @@ -0,0 +1,846 @@ +/* + * Samsung Mobile VE Group. + * + * drivers/battery/sec_batt_selfdchg_exynos7420_ap_use.c + * + * Drivers for samsung batter self discharging by S/W Policy, with no IC. + * For only Exynos 7420 + * + * Copyright (C) 2015, Samsung Electronics. + * + * 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 + */ + +/****************************************************************/ +/* Check to Compile Time */ +/****************************************************************/ +/* Common Feature */ +#ifndef CONFIG_OF +#error "[SDCHG] CONFIG_OF is not defined, Check policy!" +#endif + +#ifndef CONFIG_FB +#error "[SDCHG] CONFIG_FB is not defined, Check policy!" +#endif + +#ifndef CONFIG_PM_SLEEP +#error "[SDCHG] CONFIG_PM_SLEEP is not defined, Check policy!" +#endif + +#ifndef CONFIG_BATTERY_SAMSUNG +#error "[SDCHG] CONFIG_BATTERY_SAMSUNG is not defined, Check policy!" +#endif + +/* Exynos Feature */ +#ifndef CONFIG_ARM_EXYNOS_MP_CPUFREQ +#error "CONFIG_ARM_EXYNOS_MP_CPUFREQ is not defined, Check policy!" +#endif + +#ifndef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ +#error "CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ is not defined, Check policy!" +#endif +/****************************************************************/ + +//#define SDCHG_SUB_POLICY_SET // AP Policy Only + +#include + +/******************************************/ +// Samsung Custom Header +#ifdef CONFIG_ARM_EXYNOS_MP_CPUFREQ +#include +#endif + +#ifdef CONFIG_BATTERY_SAMSUNG +#include +#endif +/******************************************/ + +/******************************************/ +/* Code Control Feature (for no discharging IC) */ +/******************************************/ +#ifdef SDCHG_SELF_TEST +#define SDCHG_BATT_CHECK_DELAY_NORMAL 60 +#define SDCHG_BATT_CHECK_DELAY_IMMINENT 60 +#define SDCHG_TEMP_FOR_BATT_CHECK_DELAY 400 +#else +#define SDCHG_BATT_CHECK_DELAY_NORMAL 600 +#define SDCHG_BATT_CHECK_DELAY_IMMINENT 300 +#define SDCHG_TEMP_FOR_BATT_CHECK_DELAY 400 +#endif +#define SDCHG_DISCHARGING_FIRST_START_DELAY 1 +/******************************************/ +/* Extra Feature (for no discharging IC) */ +/******************************************/ +#define SDCHG_STATE_MACHINE_RETRY_AT_END_COND +/******************************************/ +/* AP Policy Feature */ +/******************************************/ +#define SDCHG_POLICY_CL0_FREQ_MIN_LIMIT BIT(0) +#define SDCHG_POLICY_CL1_FREQ_MIN_LIMIT BIT(1) +#define SDCHG_POLICY_CPU_IDLE_POLL_CTRL BIT(2) +#define SDCHG_POLICY_CPU_IDLE_POLL_AUTO_CTRL BIT(3) +#define SDCHG_POLICY_PM_QOS_DMA_CTRL BIT(4) +#define SDCHG_POLICY_PM_QOS_BUS_CTRL BIT(5) +#define SDCHG_POLICY_PM_QOS_DEVICE_CTRL BIT(6) +/******************************************/ +struct sdchg_info_personal_t +{ + struct pm_qos_request pm_qos_req_cl0_min; + struct pm_qos_request pm_qos_req_mif; + struct pm_qos_request pm_qos_req_int; +}; +struct sdchg_info_personal_t sdchg_info_personal; +/******************************************/ +static char sdchg_state_str[SDCHG_STATE_MAX][20] = + { "NONE", "SET", "SET(DISP ON)", +#ifdef SDCHG_SUB_POLICY_SET + "SET LOW", "SET LOW(DISP ON)" +#endif + }; +/******************************************/ + +static struct sdchg_info_t *sdchg_info; +static char sdchg_type[] = "sdchg_ap"; + +extern bool bsdchg_cl0_idle_policy_set; + +static unsigned int policy_state[SDCHG_STATE_MAX] = { + /*************************************/ + /* SDCHG_STATE_NONE */ + 0, + /*************************************/ + /* SDCHG_STATE_SET */ + SDCHG_POLICY_CL0_FREQ_MIN_LIMIT | + SDCHG_POLICY_CPU_IDLE_POLL_CTRL | +#ifndef SDCHG_SUB_POLICY_SET + SDCHG_POLICY_PM_QOS_BUS_CTRL | SDCHG_POLICY_PM_QOS_DEVICE_CTRL | +#endif + 0, + /*************************************/ + /* SDCHG_STATE_SET_DISPLAY_ON */ + SDCHG_POLICY_CL0_FREQ_MIN_LIMIT | + //SDCHG_POLICY_CPU_IDLE_POLL_CTRL | +#ifndef SDCHG_SUB_POLICY_SET + SDCHG_POLICY_PM_QOS_BUS_CTRL | SDCHG_POLICY_PM_QOS_DEVICE_CTRL | +#endif + 0, + /*************************************/ +#ifdef SDCHG_SUB_POLICY_SET + /*************************************/ + /* SDCHG_STATE_SET_LOW */ + SDCHG_POLICY_CL0_FREQ_MIN_LIMIT | + SDCHG_POLICY_CPU_IDLE_POLL_CTRL | + SDCHG_POLICY_PM_QOS_BUS_CTRL | SDCHG_POLICY_PM_QOS_DEVICE_CTRL | + 0, + /*************************************/ + /* SDCHG_STATE_SET_LOW_DISPLAY_ON */ + //SDCHG_POLICY_CL0_FREQ_MIN_LIMIT | + //SDCHG_POLICY_PM_QOS_BUS_CTRL | SDCHG_POLICY_PM_QOS_DEVICE_CTRL | + 0, + /*************************************/ +#endif +}; + +#define SDCHG_MIN_FREQ 900000 +#define SDCHG_MIF_THROUGHPUT 825000 // ex. 1264000(max) +#define SDCHG_INT_THROUGHPUT 400000 // ex. 543000(max?) + +static void sdchg_policy_set(struct sdchg_info_nochip_t *info) +{ + static unsigned int policy_mask = 0; + static unsigned int policy_mask_prev = 0; + struct sdchg_info_personal_t *pData = info->pData; + + pr_info("[SDCHG][%s] state set (%s -> %s)\n", __func__, + sdchg_state_str[info->set_state], sdchg_state_str[info->need_state]); + + policy_mask = policy_state[info->need_state]; + /*********************************************/ + if (policy_mask & SDCHG_POLICY_PM_QOS_BUS_CTRL) { + if (!(policy_mask_prev & SDCHG_POLICY_PM_QOS_BUS_CTRL)) { + // enable max : 1552000 + pm_qos_update_request(&pData->pm_qos_req_mif, SDCHG_MIF_THROUGHPUT); + } + } else { + if (policy_mask_prev & SDCHG_POLICY_PM_QOS_BUS_CTRL) { + pm_qos_update_request(&pData->pm_qos_req_mif, PM_QOS_DEFAULT_VALUE); + } + } + /*********************************************/ + if (policy_mask & SDCHG_POLICY_PM_QOS_DEVICE_CTRL) { + if (!(policy_mask_prev & SDCHG_POLICY_PM_QOS_DEVICE_CTRL)) { + pm_qos_update_request(&pData->pm_qos_req_int, SDCHG_INT_THROUGHPUT); + } + } else { + if (policy_mask_prev & SDCHG_POLICY_PM_QOS_DEVICE_CTRL) { + pm_qos_update_request(&pData->pm_qos_req_int, PM_QOS_DEFAULT_VALUE); + } + } + /*********************************************/ + if (policy_mask & SDCHG_POLICY_CL0_FREQ_MIN_LIMIT) { + if ( !(policy_mask_prev & SDCHG_POLICY_CL0_FREQ_MIN_LIMIT)) { + pm_qos_update_request(&pData->pm_qos_req_cl0_min, SDCHG_MIN_FREQ); + } + } else { + if ( policy_mask_prev & SDCHG_POLICY_CL0_FREQ_MIN_LIMIT) { + pm_qos_update_request(&pData->pm_qos_req_cl0_min, PM_QOS_DEFAULT_VALUE); + } + } + /*********************************************/ + if (policy_mask & SDCHG_POLICY_CPU_IDLE_POLL_CTRL) { + if (!(policy_mask_prev & SDCHG_POLICY_CPU_IDLE_POLL_CTRL)) { + bsdchg_cl0_idle_policy_set = true; + } + } else { + if (policy_mask_prev & SDCHG_POLICY_CPU_IDLE_POLL_CTRL) { + bsdchg_cl0_idle_policy_set = false; + } + } + /*********************************************/ + policy_mask_prev = policy_mask; + info->set_state = info->need_state; + + pr_info("[SDCHG][%s] state set end!\n", __func__); + return; +} + +static bool sdchg_ta_attach(struct sec_battery_info *battery) +{ + if (battery->wc_status || battery->ps_status) + return true; + + if (battery->wire_status != POWER_SUPPLY_TYPE_BATTERY) + return true; + + return false; +} + +static void sdchg_exynos7420_ap_use_monitor(void *arg, + __kernel_time_t curr_sec, bool skip_monitor) +{ + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + int temperature = 0; + static int battcond = 0; + bool need_set_state = false; + bool need_set_alarm = false; + int set_alarm_time = 0; + + bool runned_by_sdchg_poll; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + static bool state_machine_retry = false; +#endif + +#if defined(SDCHG_SUB_POLICY_SET) && defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) + int i = 0; + int cpu_CL0_online_num = 0; +#endif // #ifdef SDCHG_SUB_POLICY_SET + + /******************************************/ + runned_by_sdchg_poll = sdchg_check_polling_time(curr_sec); + + temperature = battery->temperature; + + if (skip_monitor) { +#ifdef SDCHG_CHECK_TYPE_SOC + value.intval = SEC_BATTERY_CURRENT_MA; + psy_do_property(battery->pdata->fuelgauge_name, get, + POWER_SUPPLY_PROP_CURRENT_NOW, value); + battcond = value.intval; +#else + battcond = battery->voltage_now; +#endif + } + else { +#ifdef SDCHG_CHECK_TYPE_SOC + battcond = battery->current_now; +#else + battcond = battery->voltage_avg; +#endif + } + + /******************************************/ + + if ( temperature >= (int)sdchg_info->temp_start + && battcond >= SDCHG_BATTCOND_START) + { + /******************************************/ + if (!info->wake_lock_set) { + wake_lock(&info->wake_lock); + info->wake_lock_set = true; + } + /******************************************/ +#if defined(SDCHG_SUB_POLICY_SET) && defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) + for (i = 0; i < NR_CLUST0_CPUS; i++) { + if (cpu_online(i)) { + cpu_CL0_online_num++; + } + } + if (cpu_CL0_online_num < 3) { + info->need_state = SDCHG_STATE_SET_LOW; + } else +#endif + { + info->need_state = SDCHG_STATE_SET; + } + } + /******************************************/ + else if (temperature <= (int)sdchg_info->temp_end + || battcond <= SDCHG_BATTCOND_END) + { + info->need_state = SDCHG_STATE_NONE; + } + /******************************************/ + else { + if (info->need_state != SDCHG_STATE_NONE) { +#if defined(SDCHG_SUB_POLICY_SET) && defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) + for (i = 0; i < NR_CLUST0_CPUS; i++) { + if (cpu_online(i)) { + cpu_CL0_online_num++; + } + } + if (cpu_CL0_online_num < 3) { + info->need_state = SDCHG_STATE_SET_LOW; + } else +#endif + { + info->need_state = SDCHG_STATE_SET; + } + } + } + /******************************************/ +#if defined(SDCHG_SUB_POLICY_SET) && \ + defined(CONFIG_SCHED_HMP) && defined(CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG) + if (!info->display_on && info->need_state == SDCHG_STATE_SET_LOW) { + SDCHG_LOG("[SDCHG][%s] cluster0_core1_hotplug_in() ++\n", __func__); + cluster0_core1_hotplug_in(true); + SDCHG_LOG("[SDCHG][%s] cluster0_core1_hotplug_in() --\n", __func__); + mdelay(5); +#if defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) + for (i = 0; i < NR_CLUST0_CPUS; i++) { + if (cpu_online(i)) { + cpu_CL0_online_num++; + } + } + if (cpu_CL0_online_num < 4) + info->need_state = SDCHG_STATE_SET_LOW; + else + info->need_state = SDCHG_STATE_SET; +#endif + } +#endif + + /****************************************/ + if (info->display_on) { + if (info->need_state == SDCHG_STATE_SET) + info->need_state = SDCHG_STATE_SET_DISPLAY_ON; +#ifdef SDCHG_SUB_POLICY_SET + if (info->need_state == SDCHG_STATE_SET_LOW) + info->need_state = SDCHG_STATE_SET_LOW_DISPLAY_ON; +#endif + } + +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + if (info->need_state != SDCHG_STATE_NONE) + state_machine_retry = false; +#endif + + /****************************************/ + if (info->set_state != info->need_state) { + need_set_state = true; + + if (info->set_state == SDCHG_STATE_NONE) { // none -> discharing + { + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } else { // prev : discharging + if (info->need_state == SDCHG_STATE_NONE) { // discharging -> none + if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + state_machine_retry = false; +#endif + } else { +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND +#ifdef SDCHG_SELF_TEST + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#else + if (state_machine_retry) { + if (runned_by_sdchg_poll) { + need_set_alarm = info->state_machine_run = false; + state_machine_retry = false; + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + } + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + state_machine_retry = true; + } +#endif // #ifdef SDCHG_SELF_TEST +#else + need_set_alarm = info->state_machine_run = false; +#endif // #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + } + } else { // discharging -> discharging + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } + } + /****************************************/ + else { +//KEEP_GOING: + need_set_state = false; + + if (info->need_state == SDCHG_STATE_NONE) { // prev : none + if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + state_machine_retry = false; +#endif + } else { +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND +#ifdef SDCHG_SELF_TEST + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#else + if (state_machine_retry) { + if (runned_by_sdchg_poll) { + need_set_alarm = info->state_machine_run = false; + state_machine_retry = false; + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + } + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + state_machine_retry = true; + } +#endif // #ifdef SDCHG_SELF_TEST + +#else + need_set_alarm = info->state_machine_run = false; +#endif // #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + } + } else { // prev : discharging + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } + /****************************************/ + if (need_set_state) { + sdchg_policy_set(info); + } + + if (need_set_alarm) + sdchg_set_polling_time(set_alarm_time); + else + sdchg_set_polling_time(0); + +#ifdef SDCHG_CHECK_TYPE_SOC + pr_info("[SDCHG][%s] soc : %d , temp : %d, state : %s\n", + __func__, battcond, temperature, sdchg_state_str[info->set_state]); +#else + pr_info("[SDCHG][%s] volt : %d , temp : %d, state : %s\n", + __func__, battcond, temperature, sdchg_state_str[info->set_state]); +#endif + + if (info->set_state == SDCHG_STATE_NONE) + { + if (info->wake_lock_set) { + wake_lock_timeout(&info->end_wake_lock, HZ * 10); + wake_unlock(&info->wake_lock); + info->wake_lock_set = false; + } + } + + return; +} + +/*************************************************************************/ +static int sdchg_fb_notifier_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct fb_event *evdata = data; + struct fb_info *fb_info = evdata->info; + struct sdchg_info_nochip_t *info = + (struct sdchg_info_nochip_t *)container_of(nb, struct sdchg_info_nochip_t, fb_nb); + + int blank; + + if (val != FB_EVENT_BLANK) + return 0; + + /* + * If FBNODE is not zero, it is not primary display(LCD) + * and don't need to process these scheduling. + */ + if (fb_info->node) + return NOTIFY_OK; + + blank = *(int *)evdata->data; + + switch (blank) { + /**************************************/ + case FB_BLANK_POWERDOWN: + case FB_BLANK_NORMAL: + info->display_on = false; + break; + /**************************************/ + case FB_BLANK_UNBLANK: + info->display_on = true; + break; + default: + return NOTIFY_OK; + } + + return NOTIFY_OK; +} + + +/*************************************************************************/ +static void init_info_data(struct sdchg_info_nochip_t *info) +{ + struct sdchg_info_personal_t *pData = info->pData; + + info->need_state = SDCHG_STATE_NONE; + info->set_state = SDCHG_STATE_NONE; + + wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, + "sdchg"); + info->wake_lock_set =false; + + wake_lock_init(&info->end_wake_lock, WAKE_LOCK_SUSPEND, + "sdchg_end"); + + info->state_machine_run = false; + +#ifdef CONFIG_FB + info->display_on = false; + info->fb_nb.notifier_call = sdchg_fb_notifier_callback; + fb_register_client(&info->fb_nb); +#endif + + pm_qos_add_request(&pData->pm_qos_req_cl0_min, + PM_QOS_CLUSTER0_FREQ_MIN, + PM_QOS_DEFAULT_VALUE); + + pm_qos_add_request(&pData->pm_qos_req_mif, + PM_QOS_BUS_THROUGHPUT, + PM_QOS_DEFAULT_VALUE); + + pm_qos_add_request(&pData->pm_qos_req_int, + PM_QOS_DEVICE_THROUGHPUT, + PM_QOS_DEFAULT_VALUE); + + return; +} + +static void remove_info_data(struct sdchg_info_nochip_t *info) +{ + struct sdchg_info_personal_t *pData = info->pData; + + pm_qos_remove_request(&pData->pm_qos_req_cl0_min); + pm_qos_remove_request(&pData->pm_qos_req_mif); + pm_qos_remove_request(&pData->pm_qos_req_int); + + fb_unregister_client(&info->fb_nb); +} + +/*************************************************************************/ +static void sdchg_exynos7420_ap_use_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *data_np; + + data_np = of_get_child_by_name(np, sdchg_type); + +#ifdef SDCHG_SELF_TEST + sdchg_info->temp_start = SDCHG_TEMP_START; + sdchg_info->temp_end = SDCHG_TEMP_END; + sdchg_info->soc_start = SDCHG_SOC_START; + sdchg_info->soc_end = SDCHG_SOC_END; + sdchg_info->voltage_start = SDCHG_VOLTAGE_START; + sdchg_info->voltage_end = SDCHG_VOLTAGE_END; +#else + if (of_property_read_u32(data_np, "sdchg,temperature_start", + &sdchg_info->temp_start)) { + sdchg_info->temp_start = SDCHG_TEMP_START; + pr_info("[SDCHG][%s] temp_start dt is Empty (defalut:%d)", + __func__, sdchg_info->temp_start); + } + + if (of_property_read_u32(data_np, "sdchg,temperature_end", + &sdchg_info->temp_end)) { + sdchg_info->temp_end = SDCHG_TEMP_END; + pr_info("[SDCHG][%s] temp_end dt is Empty (defalut:%d)", + __func__, sdchg_info->temp_end); + } + + if (of_property_read_u32(data_np, "sdchg,soc_start", + &sdchg_info->soc_start)) { + sdchg_info->soc_start = SDCHG_SOC_START; + pr_info("[SDCHG][%s] soc_start dt is Empty (defalut:%d)", + __func__, sdchg_info->soc_start); + } + + if (of_property_read_u32(data_np, "sdchg,soc_end", + &sdchg_info->soc_end)) { + sdchg_info->soc_end = SDCHG_SOC_END; + pr_info("[SDCHG][%s] soc_end dt is Empty (defalut:%d)", + __func__, sdchg_info->soc_end); + } + + if (of_property_read_u32(data_np, "sdchg,voltage_start", + &sdchg_info->voltage_start)) { + sdchg_info->voltage_start = SDCHG_VOLTAGE_START; + pr_info("[SDCHG][%s] voltage_start dt is Empty (defalut:%d)", + __func__, sdchg_info->voltage_start); + } + + // voltage_end : using swelling_drop_float_voltage value + if (of_property_read_u32(np, "battery,swelling_drop_float_voltage", + &sdchg_info->voltage_end)) { + sdchg_info->voltage_end = SDCHG_VOLTAGE_END; + pr_info("[SDCHG][%s] voltage_end dt is Empty (defalut:%d)", + __func__, sdchg_info->voltage_end); + } +#endif + pr_info("[SDCHG][%s] temp_start = %u\n", __func__, sdchg_info->temp_start); + pr_info("[SDCHG][%s] temp_end = %u\n", __func__, sdchg_info->temp_end); + pr_info("[SDCHG][%s] soc_start = %u\n", __func__, sdchg_info->soc_start); + pr_info("[SDCHG][%s] soc_end = %u\n", __func__, sdchg_info->soc_end); + pr_info("[SDCHG][%s] voltage_start = %u\n", __func__, sdchg_info->voltage_start); + pr_info("[SDCHG][%s] voltage_end = %u\n", __func__, sdchg_info->voltage_end); + + return; + } + +/* prev func : sec_bat_self_discharging_check */ + static void sdchg_exynos7420_ap_use_adc_check(void *arg) + { + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (battery->force_discharging) { + battery->self_discharging_adc = 2100; + battery->self_discharging = true; + } + else { + battery->self_discharging_adc = 0; + battery->self_discharging = false; + } + + pr_info("%s : SELF_DISCHARGING(%d) SELF_DISCHARGING_ADC(%d)\n", + __func__, battery->self_discharging, battery->self_discharging_adc); + return; + } + + +/* prev func : sec_bat_self_discharging_ntc_check */ +static void sdchg_exynos7420_ap_use_ntc_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + battery->discharging_ntc_adc = 0; + battery->discharging_ntc = false; + + pr_info("%s : DISCHARGING_NTC(%d) DISCHARGING_NTC_ADC(%d)\n", + __func__,battery->discharging_ntc, battery->discharging_ntc_adc); + + return; +} + + /* prev func : sec_bat_self_discharging_control */ + static void sdchg_exynos7420_ap_use_force_control(void *arg, bool dis_en) + { + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (dis_en) { + battery->force_discharging = true; + } else { + battery->force_discharging = false; + } + + return; + } + + /* prev func : sec_bat_discharging_check */ + static void sdchg_exynos7420_ap_use_discharging_check(void *arg) + { + return; + } + +static int sdchg_exynos7420_ap_use_force_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + return (int)battery->force_discharging; +} + + + +static int sdchg_exynos7420_ap_use_probe(void *battery) +{ + int ret = 0; + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + pr_info("[SDCHG][%s] ++\n", __func__); + + sdchg_info->battery = battery; + + init_info_data(info); + + pr_info("[SDCHG][%s] --(%d)\n", __func__, ret); + + return ret; +} + +static int sdchg_exynos7420_ap_use_remove(void) +{ + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + pr_info("[SDCHG][%s] ++\n", __func__); + + if (info->set_state != SDCHG_STATE_NONE) { + info->need_state = SDCHG_STATE_NONE; + + sdchg_policy_set(info); + info->state_machine_run = false; + + /**************************************/ + if (info->wake_lock_set) { + /* if you active this code, use additional lock for wake_lock_set */ + wake_unlock(&info->wake_lock); + info->wake_lock_set = false; + } + /**************************************/ + } + + /* need to run after sdchg_policy_set */ + remove_info_data(info); + + pr_info("[SDCHG][%s] --\n", __func__); + + return 0; +} + + static int __init sdchg_exynos7420_ap_use_init(void) + { + int ret; + + pr_info("[SDCHG][%s] ++\n", __func__); + + sdchg_info = kzalloc(sizeof(struct sdchg_info_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate memory for self discharging\n"); + ret = -ENOMEM; + goto fail_out; + } + sdchg_info->type = sdchg_type; + + /*****************************************/ + sdchg_info->nochip = kzalloc(sizeof(struct sdchg_info_nochip_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate nochip memory for self discharging\n"); + ret = -ENOMEM; + goto after_alloc_info; + } + sdchg_info->nochip->pinfo = sdchg_info; + sdchg_info->nochip->pData = (void *)&sdchg_info_personal; + + sdchg_info->nochip->sdchg_monitor = sdchg_exynos7420_ap_use_monitor; + /*****************************************/ + sdchg_info->sdchg_probe = sdchg_exynos7420_ap_use_probe; + sdchg_info->sdchg_remove = sdchg_exynos7420_ap_use_remove; + sdchg_info->sdchg_parse_dt = sdchg_exynos7420_ap_use_parse_dt; + + sdchg_info->sdchg_adc_check = sdchg_exynos7420_ap_use_adc_check; + sdchg_info->sdchg_ntc_check = sdchg_exynos7420_ap_use_ntc_check; + sdchg_info->sdchg_force_control = sdchg_exynos7420_ap_use_force_control; + sdchg_info->sdchg_discharging_check = sdchg_exynos7420_ap_use_discharging_check; + + sdchg_info->sdchg_force_check = sdchg_exynos7420_ap_use_force_check; + /*****************************************/ + + list_add(&sdchg_info->info_list, &sdchg_info_head); + + pr_info("[SDCHG][%s] --\n", __func__); + + return 0; + +after_alloc_info: + if (sdchg_info) { + kfree(sdchg_info); + sdchg_info = NULL; + } +fail_out: + pr_info("[SDCHG][%s] --(%d)\n", __func__, ret); + + return ret; + } + + +static void __exit sdchg_exynos7420_ap_use_exit(void) +{ + pr_info("[SDCHG][%s] ++\n", __func__); + + if (sdchg_info) { + if (sdchg_info->nochip) { + kfree(sdchg_info->nochip); + sdchg_info->nochip = NULL; + } + kfree(sdchg_info); + sdchg_info = NULL; + } + pr_info("[SDCHG][%s] --\n", __func__); + + return; +} + +arch_initcall(sdchg_exynos7420_ap_use_init); +module_exit(sdchg_exynos7420_ap_use_exit); + +MODULE_AUTHOR("jeeon.park@samsung.com"); +MODULE_DESCRIPTION("Samsung Electronics Co. Battery Self Discharging \ + for Preventing Swelling by S/W Policy, with no IC"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/battery/sec_batt_selfdchg_exynos7420_cs_use.c b/drivers/battery/sec_batt_selfdchg_exynos7420_cs_use.c new file mode 100644 index 000000000000..e08efa44d098 --- /dev/null +++ b/drivers/battery/sec_batt_selfdchg_exynos7420_cs_use.c @@ -0,0 +1,685 @@ +/* + * Samsung Mobile VE Group. + * + * drivers/battery/sec_batt_selfdchg_exynos7420_cs_use.c + * + * Drivers for samsung batter self discharging by using current source, with no IC. + * For only Exynos 7420 + * + * Copyright (C) 2015, Samsung Electronics. + * + * 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 + */ + +/****************************************************************/ +/* Check to Compile Time */ +/****************************************************************/ +/* Common Feature */ +#ifndef CONFIG_OF +#error "[SDCHG] CONFIG_OF is not defined, Check policy!" +#endif + +#ifndef CONFIG_FB +#error "[SDCHG] CONFIG_FB is not defined, Check policy!" +#endif + +#ifndef CONFIG_PM_SLEEP +#error "[SDCHG] CONFIG_PM_SLEEP is not defined, Check policy!" +#endif + +#ifndef CONFIG_BATTERY_SAMSUNG +#error "[SDCHG] CONFIG_BATTERY_SAMSUNG is not defined, Check policy!" +#endif + +/* Exynos Feature */ +/****************************************************************/ + +#include + +/******************************************/ +// Samsung Custom Header + +#ifdef CONFIG_BATTERY_SAMSUNG +#include +#endif +/******************************************/ + +/******************************************/ +/* Code Control Feature (for no discharging IC) */ +/******************************************/ +#ifdef SDCHG_SELF_TEST +#define SDCHG_BATT_CHECK_DELAY_NORMAL 60 +#define SDCHG_BATT_CHECK_DELAY_IMMINENT 60 +#define SDCHG_TEMP_FOR_BATT_CHECK_DELAY 400 +#else +#define SDCHG_BATT_CHECK_DELAY_NORMAL 600 +#define SDCHG_BATT_CHECK_DELAY_IMMINENT 300 +#define SDCHG_TEMP_FOR_BATT_CHECK_DELAY 400 +#endif +#define SDCHG_DISCHARGING_FIRST_START_DELAY 1 +/******************************************/ +/* Extra Feature (for no discharging IC) */ +/******************************************/ +#define SDCHG_STATE_MACHINE_RETRY_AT_END_COND +/******************************************/ +static char sdchg_state_str[SDCHG_STATE_MAX][20] = + { "NONE", "SET", "SET(DISP ON)"}; +/******************************************/ + +static struct sdchg_info_t *sdchg_info; +static char sdchg_type[] = "sdchg_cs"; + + +/*******************************************************************/ +/* Define this function in accordance with the specification of each Current Source */ +extern int sdchg_current_source_enable(void); +extern int sdchg_current_source_disable(void); +/*******************************************************************/ + +static int current_source_set(struct sdchg_info_nochip_t *info) +{ + static bool enabled = false; + int ret = 0; + + pr_info("[SDCHG][%s] state set (%s -> %s)\n", __func__, + sdchg_state_str[info->set_state], sdchg_state_str[info->need_state]); + + // cs set : SDCHG_STATE_SET + // cs no set : SDCHG_STATE_NONE , SDCHG_STATE_SET_DISPLAY_ON + if (info->need_state == SDCHG_STATE_SET ) { + if (!enabled) { + // the current source value applied by this function + // shoud be maintained in suspend state. + ret = sdchg_current_source_enable(); // example + if (ret) + goto error; + enabled = true; + } + } else { + if (enabled) { + // the current source value applied by this function + // shoud be maintained in suspend state. + ret = sdchg_current_source_disable(); // example + if (ret) + goto error; + enabled = false; + } + } + info->set_state = info->need_state; + + pr_info("[SDCHG][%s] state set end!\n", __func__); + return 0; +error: + pr_err("[SDCHG][%s] Error to policy set!\n", __func__); + return ret; +} + +static bool sdchg_ta_attach(struct sec_battery_info *battery) +{ + if (battery->wc_status || battery->ps_status) + return true; + + if (battery->wire_status != POWER_SUPPLY_TYPE_BATTERY) + return true; + + return false; +} + +static void sdchg_exynos7420_cs_use_monitor(void *arg, + __kernel_time_t curr_sec, bool skip_monitor) +{ + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + int temperature = 0; + static int battcond = 0; + bool need_set_state = false; + bool need_set_alarm = false; + int set_alarm_time = 0; + + bool runned_by_sdchg_poll; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + static bool state_machine_retry = false; +#endif + + + /******************************************/ + runned_by_sdchg_poll = sdchg_check_polling_time(curr_sec); + + temperature = battery->temperature; + + if (skip_monitor) { +#ifdef SDCHG_CHECK_TYPE_SOC + value.intval = SEC_BATTERY_CURRENT_MA; + psy_do_property(battery->pdata->fuelgauge_name, get, + POWER_SUPPLY_PROP_CURRENT_NOW, value); + battcond = value.intval; +#else + battcond = battery->voltage_now; +#endif + } + else { +#ifdef SDCHG_CHECK_TYPE_SOC + battcond = (short)battery->current_now; +#else + battcond = (short)battery->voltage_avg; +#endif + } + + /******************************************/ + + if ( temperature >= sdchg_info->temp_start + && battcond >= SDCHG_BATTCOND_START) + { + /******************************************/ + if (!info->wake_lock_set) { + wake_lock(&info->wake_lock); + info->wake_lock_set = true; + } + /******************************************/ + info->need_state = SDCHG_STATE_SET; + } + /******************************************/ + else if (temperature <= sdchg_info->temp_end + || battcond <= SDCHG_BATTCOND_END) + { + info->need_state = SDCHG_STATE_NONE; + } + /******************************************/ + else { + if (info->need_state != SDCHG_STATE_NONE) { + info->need_state = SDCHG_STATE_SET; + } + } + /******************************************/ + /****************************************/ + if (info->display_on) { + if (info->need_state == SDCHG_STATE_SET) + info->need_state = SDCHG_STATE_SET_DISPLAY_ON; + } + +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + if (info->need_state != SDCHG_STATE_NONE) + state_machine_retry = false; +#endif + + /****************************************/ + if (info->set_state != info->need_state) { + need_set_state = true; + + if (info->set_state == SDCHG_STATE_NONE) { // none -> discharing + { + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } else { // prev : discharging + if (info->need_state == SDCHG_STATE_NONE) { // discharging -> none + if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + state_machine_retry = false; +#endif + } else { +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND +#ifdef SDCHG_SELF_TEST + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#else + if (state_machine_retry) { + if (runned_by_sdchg_poll) { + need_set_alarm = info->state_machine_run = false; + state_machine_retry = false; + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + } + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + state_machine_retry = true; + } +#endif // #ifdef SDCHG_SELF_TEST +#else + need_set_alarm = info->state_machine_run = false; +#endif // #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + } + } else { // discharging -> discharging + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } + } + /****************************************/ + else { +//KEEP_GOING: + need_set_state = false; + + if (info->need_state == SDCHG_STATE_NONE) { // prev : none + if (sdchg_ta_attach(battery) || battcond >= SDCHG_BATTCOND_START) { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + state_machine_retry = false; +#endif + } else { +#ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND +#ifdef SDCHG_SELF_TEST + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; +#else + if (state_machine_retry) { + if (runned_by_sdchg_poll) { + need_set_alarm = info->state_machine_run = false; + state_machine_retry = false; + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + } + } else { + need_set_alarm = info->state_machine_run = true; + if (temperature < SDCHG_TEMP_FOR_BATT_CHECK_DELAY) + set_alarm_time = SDCHG_BATT_CHECK_DELAY_NORMAL; + else + set_alarm_time = SDCHG_BATT_CHECK_DELAY_IMMINENT; + state_machine_retry = true; + } +#endif // #ifdef SDCHG_SELF_TEST + +#else + need_set_alarm = info->state_machine_run = false; +#endif // #ifdef SDCHG_STATE_MACHINE_RETRY_AT_END_COND + } + } else { // prev : discharging + //need_set_alarm = info->state_machine_run = true; + //set_alarm_time = SDCHG_DISCHARGING_DELAY; + need_set_alarm = false; // in discharing, according to original monitor work time + info->state_machine_run = true; + } + } + /****************************************/ + if (need_set_state) { + current_source_set(info); + } + + if (need_set_alarm) + sdchg_set_polling_time(set_alarm_time); + else + sdchg_set_polling_time(0); + +#ifdef SDCHG_CHECK_TYPE_SOC + pr_info("[SDCHG][%s] soc : %d , temp : %d, state : %s\n", + __func__, battcond, temperature, sdchg_state_str[info->set_state]); +#else + pr_info("[SDCHG][%s] volt : %d , temp : %d, state : %s\n", + __func__, battcond, temperature, sdchg_state_str[info->set_state]); +#endif + + if (info->set_state == SDCHG_STATE_NONE) + { + if (info->wake_lock_set) { + wake_lock_timeout(&info->wake_lock, HZ * 10); + wake_unlock(&info->wake_lock); + info->wake_lock_set = false; + } + } + + return; +} + +/*************************************************************************/ +static int sdchg_fb_notifier_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct fb_event *evdata = data; + struct fb_info *fb_info = evdata->info; + struct sdchg_info_nochip_t *info = + (struct sdchg_info_nochip_t *)container_of(nb, struct sdchg_info_nochip_t, fb_nb); + + int blank; + + if (val != FB_EVENT_BLANK) + return 0; + + /* + * If FBNODE is not zero, it is not primary display(LCD) + * and don't need to process these scheduling. + */ + if (fb_info->node) + return NOTIFY_OK; + + blank = *(int *)evdata->data; + + switch (blank) { + /**************************************/ + case FB_BLANK_POWERDOWN: + case FB_BLANK_NORMAL: + info->display_on = false; + break; + /**************************************/ + case FB_BLANK_UNBLANK: + info->display_on = true; + break; + default: + return NOTIFY_OK; + } + + return NOTIFY_OK; +} + + +/*************************************************************************/ +static void init_info_data(struct sdchg_info_nochip_t *info) +{ + //struct sdchg_info_personal_t *pData = info->pData; + + info->need_state = SDCHG_STATE_NONE; + info->set_state = SDCHG_STATE_NONE; + + wake_lock_init(&info->wake_lock, WAKE_LOCK_SUSPEND, + "sdchg"); + info->wake_lock_set =false; + + wake_lock_init(&info->end_wake_lock, WAKE_LOCK_SUSPEND, + "sdchg_end"); + + info->state_machine_run = false; + +#ifdef CONFIG_FB + info->display_on = false; + info->fb_nb.notifier_call = sdchg_fb_notifier_callback; + fb_register_client(&info->fb_nb); +#endif + + return; +} + +static void remove_info_data(struct sdchg_info_nochip_t *info) +{ + //struct sdchg_info_personal_t *pData = info->pData; + + fb_unregister_client(&info->fb_nb); +} + +/*************************************************************************/ +static void sdchg_exynos7420_cs_use_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct device_node *data_np; + + data_np = of_get_child_by_name(np, sdchg_type); + +#ifdef SDCHG_SELF_TEST + sdchg_info->temp_start = SDCHG_TEMP_START; + sdchg_info->temp_end = SDCHG_TEMP_END; + sdchg_info->soc_start = SDCHG_SOC_START; + sdchg_info->soc_end = SDCHG_SOC_END; + sdchg_info->voltage_start = SDCHG_VOLTAGE_START; + sdchg_info->voltage_end = SDCHG_VOLTAGE_END; +#else + if (of_property_read_u32(data_np, "sdchg,temperature_start", + &sdchg_info->temp_start)) { + sdchg_info->temp_start = SDCHG_TEMP_START; + pr_info("[SDCHG][%s] temp_start dt is Empty (defalut:%d)", + __func__, sdchg_info->temp_start); + } + + if (of_property_read_u32(data_np, "sdchg,temperature_end", + &sdchg_info->temp_end)) { + sdchg_info->temp_end = SDCHG_TEMP_END; + pr_info("[SDCHG][%s] temp_end dt is Empty (defalut:%d)", + __func__, sdchg_info->temp_end); + } + + if (of_property_read_u32(data_np, "sdchg,soc_start", + &sdchg_info->soc_start)) { + sdchg_info->soc_start = SDCHG_SOC_START; + pr_info("[SDCHG][%s] soc_start dt is Empty (defalut:%d)", + __func__, sdchg_info->soc_start); + } + + if (of_property_read_u32(data_np, "sdchg,soc_end", + &sdchg_info->soc_end)) { + sdchg_info->soc_end = SDCHG_SOC_END; + pr_info("[SDCHG][%s] soc_end dt is Empty (defalut:%d)", + __func__, sdchg_info->soc_end); + } + + if (of_property_read_u32(data_np, "sdchg,voltage_start", + &sdchg_info->voltage_start)) { + sdchg_info->voltage_start = SDCHG_VOLTAGE_START; + pr_info("[SDCHG][%s] voltage_start dt is Empty (defalut:%d)", + __func__, sdchg_info->voltage_start); + } + + // voltage_end : using swelling_drop_float_voltage value + if (of_property_read_u32(np, "battery,swelling_drop_float_voltage", + &sdchg_info->voltage_end)) { + sdchg_info->voltage_end = SDCHG_VOLTAGE_END; + pr_info("[SDCHG][%s] voltage_end dt is Empty (defalut:%d)", + __func__, sdchg_info->voltage_end); + } +#endif + pr_info("[SDCHG][%s] temp_start = %u\n", __func__, sdchg_info->temp_start); + pr_info("[SDCHG][%s] temp_end = %u\n", __func__, sdchg_info->temp_end); + pr_info("[SDCHG][%s] soc_start = %u\n", __func__, sdchg_info->soc_start); + pr_info("[SDCHG][%s] soc_end = %u\n", __func__, sdchg_info->soc_end); + pr_info("[SDCHG][%s] voltage_start = %u\n", __func__, sdchg_info->voltage_start); + pr_info("[SDCHG][%s] voltage_end = %u\n", __func__, sdchg_info->voltage_end); + + return; + } + +/* prev func : sec_bat_self_discharging_check */ + static void sdchg_exynos7420_cs_use_adc_check(void *arg) + { + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (battery->force_discharging) { + battery->self_discharging_adc = 2100; + battery->self_discharging = true; + } + else { + battery->self_discharging_adc = 0; + battery->self_discharging = false; + } + + pr_info("%s : SELF_DISCHARGING(%d) SELF_DISCHARGING_ADC(%d)\n", + __func__, battery->self_discharging, battery->self_discharging_adc); + return; + } + + +/* prev func : sec_bat_self_discharging_ntc_check */ +static void sdchg_exynos7420_cs_use_ntc_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + battery->discharging_ntc_adc = 0; + battery->discharging_ntc = false; + + pr_info("%s : DISCHARGING_NTC(%d) DISCHARGING_NTC_ADC(%d)\n", + __func__,battery->discharging_ntc, battery->discharging_ntc_adc); + + return; +} + + /* prev func : sec_bat_self_discharging_control */ + static void sdchg_exynos7420_cs_use_force_control(void *arg, bool dis_en) + { + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (dis_en) { + battery->force_discharging = true; + } else { + battery->force_discharging = false; + } + + return; + } + + /* prev func : sec_bat_discharging_check */ + static void sdchg_exynos7420_cs_use_discharging_check(void *arg) + { + return; + } + +static int sdchg_exynos7420_cs_use_force_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + return (int)battery->force_discharging; +} + + + +static int sdchg_exynos7420_cs_use_probe(void *battery) +{ + int ret = 0; + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + pr_info("[SDCHG][%s] ++\n", __func__); + + sdchg_info->battery = battery; + + init_info_data(info); + + pr_info("[SDCHG][%s] --(%d)\n", __func__, ret); + + return ret; +} + +static int sdchg_exynos7420_cs_use_remove(void) +{ + struct sdchg_info_nochip_t *info = sdchg_info->nochip; + pr_info("[SDCHG][%s] ++\n", __func__); + + if (info->set_state != SDCHG_STATE_NONE) { + info->need_state = SDCHG_STATE_NONE; + + current_source_set(info); + info->state_machine_run = false; + + /**************************************/ + if (info->wake_lock_set) { + /* if you active this code, use additional lock for wake_lock_set */ + wake_unlock(&info->wake_lock); + info->wake_lock_set = false; + } + /**************************************/ + } + + /* need to run after sdchg_policy_set */ + remove_info_data(info); + + pr_info("[SDCHG][%s] --\n", __func__); + + return 0; +} + + static int __init sdchg_exynos7420_cs_use_init(void) + { + int ret; + + pr_info("[SDCHG][%s] ++\n", __func__); + + sdchg_info = kzalloc(sizeof(struct sdchg_info_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate memory for self discharging\n"); + ret = -ENOMEM; + goto fail_out; + } + sdchg_info->type = sdchg_type; + + /*****************************************/ + sdchg_info->nochip = kzalloc(sizeof(struct sdchg_info_nochip_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate nochip memory for self discharging\n"); + ret = -ENOMEM; + goto after_alloc_info; + } + sdchg_info->nochip->pinfo = sdchg_info; + + sdchg_info->nochip->sdchg_monitor = sdchg_exynos7420_cs_use_monitor; + /*****************************************/ + sdchg_info->sdchg_probe = sdchg_exynos7420_cs_use_probe; + sdchg_info->sdchg_remove = sdchg_exynos7420_cs_use_remove; + sdchg_info->sdchg_parse_dt = sdchg_exynos7420_cs_use_parse_dt; + + sdchg_info->sdchg_adc_check = sdchg_exynos7420_cs_use_adc_check; + sdchg_info->sdchg_ntc_check = sdchg_exynos7420_cs_use_ntc_check; + sdchg_info->sdchg_force_control = sdchg_exynos7420_cs_use_force_control; + sdchg_info->sdchg_discharging_check = sdchg_exynos7420_cs_use_discharging_check; + + sdchg_info->sdchg_force_check = sdchg_exynos7420_cs_use_force_check; + /*****************************************/ + + list_add(&sdchg_info->info_list, &sdchg_info_head); + + pr_info("[SDCHG][%s] --\n", __func__); + + return 0; + +after_alloc_info: + if (sdchg_info) { + kfree(sdchg_info); + sdchg_info = NULL; + } +fail_out: + pr_info("[SDCHG][%s] --(%d)\n", __func__, ret); + + return ret; + } + + +static void __exit sdchg_exynos7420_cs_use_exit(void) +{ + pr_info("[SDCHG][%s] ++\n", __func__); + + if (sdchg_info) { + if (sdchg_info->nochip) { + kfree(sdchg_info->nochip); + sdchg_info->nochip = NULL; + } + kfree(sdchg_info); + sdchg_info = NULL; + } + pr_info("[SDCHG][%s] --\n", __func__); + + return; +} + +arch_initcall(sdchg_exynos7420_cs_use_init); +module_exit(sdchg_exynos7420_cs_use_exit); + +MODULE_AUTHOR("jeeon.park@samsung.com yonghune.an@samsung.com"); +MODULE_DESCRIPTION("Samsung Electronics Co. Battery Self Discharging \ + for Preventing Swelling by using Current Source, with no IC"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/battery/sec_batt_selfdchg_ic_use.c b/drivers/battery/sec_batt_selfdchg_ic_use.c new file mode 100644 index 000000000000..6f163b1d5d10 --- /dev/null +++ b/drivers/battery/sec_batt_selfdchg_ic_use.c @@ -0,0 +1,328 @@ +/* + * Samsung Mobile VE Group. + * + * drivers/battery/sec_batt_selfdchg_ic_use.c + * + * Drivers for samsung batter self discharging with IC. + * + * Copyright (C) 2015, Samsung Electronics. + * + * 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 + */ + + /******************************************/ + +#include + + /******************************************/ + // Samsung Custom Header +#ifdef CONFIG_BATTERY_SAMSUNG +#include +#endif +/******************************************/ + +static struct sdchg_info_t *sdchg_info; +static char sdchg_type[] = "sdchg_ic"; + +static void sdchg_ic_use_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + int ret; + u32 temp; + + sdchg_info->chip->factory_discharging = + of_get_named_gpio(np, "battery,factory_discharging", 0); + if (sdchg_info->chip->factory_discharging < 0) { + pr_info("%s : Force Discharging pin is Empty(%d)\n", + __func__, sdchg_info->chip->factory_discharging); + sdchg_info->chip->factory_discharging = 0; + } + /**************************************/ + sdchg_info->chip->sdchg_en = of_property_read_bool(np, + "battery,self_discharging_en"); + /**************************************/ + ret = of_property_read_u32(np, "battery,force_discharging_limit", + &temp); + sdchg_info->temp_start = (int)temp; + if (ret) + pr_info("%s : Force Discharging limit is Empty", __func__); + /**************************************/ + ret = of_property_read_u32(np, "battery,force_discharging_recov", + &temp); + sdchg_info->temp_end = (int)temp; + if (ret) + pr_info("%s : Force Discharging recov is Empty", __func__); + /**************************************/ + pr_info("%s : FORCE_DISCHARGING_LIMT(%d), FORCE_DISCHARGING_RECOV(%d)\n", + __func__, sdchg_info->temp_start, sdchg_info->temp_end); + /**************************************/ + ret = of_property_read_u32(np, "battery,discharging_adc_min", + (unsigned int *)&sdchg_info->chip->adc_min); + if (ret) + pr_info("%s : Discharging ADC Min is Empty", __func__); + /**************************************/ + ret = of_property_read_u32(np, "battery,discharging_adc_max", + (unsigned int *)&sdchg_info->chip->adc_max); + if (ret) + pr_info("%s : Discharging ADC Max is Empty", __func__); + /**************************************/ + ret = of_property_read_u32(np, "battery,self_discharging_voltage_limit", + (unsigned int *)&sdchg_info->voltage_start); + if (ret) + pr_info("%s : Force Discharging recov is Empty", __func__); + /**************************************/ + // voltage_end : using swelling_drop_float_voltage value + if (of_property_read_u32(np, "battery,swelling_drop_float_voltage", + &sdchg_info->voltage_end)) + pr_err("%s : Force Discharging voltage recov is Empty", __func__); + /**************************************/ + ret = of_property_read_u32(np, "battery,discharging_ntc_limit", + (unsigned int *)&sdchg_info->chip->ntc_limit); + if (ret) + pr_info("%s : Discharging NTC LIMIT is Empty", __func__); + /**************************************/ + + return; +} + +// prev func : sec_bat_self_discharging_check +extern int sec_bat_get_adc_value_using_sdchg + (struct sec_battery_info *battery, int channel); +static void sdchg_ic_use_adc_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + unsigned int dis_adc; + + dis_adc = sec_bat_get_adc_value_using_sdchg + (battery, SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK); + if (dis_adc) + battery->self_discharging_adc = dis_adc; + else + battery->self_discharging_adc = 0; + + if ((dis_adc >= (int)sdchg_info->chip->adc_min) && + (dis_adc <= (int)sdchg_info->chip->adc_max)) + battery->self_discharging = true; + else + battery->self_discharging = false; + + pr_info("%s : SELF_DISCHARGING(%d) SELF_DISCHARGING_ADC(%d)\n", + __func__, battery->self_discharging, battery->self_discharging_adc); + + return; +} + + +// prev func : sec_bat_self_discharging_ntc_check +static void sdchg_ic_use_ntc_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + int ntc_adc; + + ntc_adc = sec_bat_get_adc_value_using_sdchg + (battery, SEC_BAT_ADC_CHANNEL_DISCHARGING_NTC); + if (ntc_adc) + battery->discharging_ntc_adc = ntc_adc; + else + battery->discharging_ntc_adc = 0; + + if (ntc_adc > (int)sdchg_info->chip->ntc_limit) + battery->discharging_ntc = true; + else + battery->discharging_ntc = false; + + pr_info("%s : DISCHARGING_NTC(%d) DISCHARGING_NTC_ADC(%d)\n", + __func__,battery->discharging_ntc, battery->discharging_ntc_adc); + + return; +} + + +// prev func : sec_bat_self_discharging_control +static void sdchg_ic_use_force_control(void *arg, bool dis_en) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (!sdchg_info->chip->factory_discharging) { + pr_info("Can't control Self Discharging IC (No Factory Discharging Pin).\n"); + return; + } + + if (dis_en) { + dev_info(battery->dev, + "%s : Self Discharging IC doesn't act until (%d) degree & (%d) voltage. " + "Auto Discharging IC ENABLE\n", __func__, + battery->temperature, battery->voltage_now); + gpio_direction_output(sdchg_info->chip->factory_discharging, 1); + battery->force_discharging = true; + } else { + dev_info(battery->dev, "%s : Self Discharging IC disable.\n", __func__); + gpio_direction_output(sdchg_info->chip->factory_discharging, 0); + battery->force_discharging = false; + } + + return; +} + + +// prev func : sec_bat_discharging_check +static void sdchg_ic_use_discharging_check(void *arg) +{ + struct sec_battery_info *battery = (struct sec_battery_info *)arg; + + if (!sdchg_info->chip->sdchg_en) { + pr_info("[SDCHG][%s] --(sdchg_en false)\n", __func__); + return; + } + + sdchg_ic_use_adc_check(battery); + + if(battery->factory_self_discharging_mode_on) { + dev_info(battery->dev, + "%s: It is Factory mode by self discharging mode, Auto_DIS(%d), Force_DIS(%d)\n", + __func__, battery->self_discharging, battery->force_discharging); + return; + } + + if (!battery->self_discharging && + (battery->temperature >= (int)sdchg_info->temp_start) && + (battery->voltage_now >= (int)sdchg_info->voltage_start)) { + sdchg_ic_use_force_control((void *)battery, true); + } else if(battery->force_discharging && + ((battery->temperature <= (int)sdchg_info->temp_end) || + (battery->voltage_now <= (int)sdchg_info->voltage_end))) { + sdchg_ic_use_force_control((void *)battery, false); + } + dev_info(battery->dev, + "%s: Auto_DIS(%d), Force_DIS(%d)\n", + __func__, battery->self_discharging, battery->force_discharging); + + return; +} + + +static int sdchg_ic_use_force_check(void *arg) +{ + int ret = 0; + + if (!sdchg_info->chip->factory_discharging) { + pr_info("Can't control Self Discharging IC (No Factory Discharging Pin).\n"); + goto out; + } + + ret = gpio_get_value(sdchg_info->chip->factory_discharging); +out: + return ret; +} + +static int sdchg_ic_use_probe(void *battery) +{ + int ret = 0; + + sdchg_info->battery = battery; + + if (sdchg_info->chip->factory_discharging) { + ret = gpio_request((unsigned)sdchg_info->chip->factory_discharging, + "FACTORY_DISCHARGING"); + if (ret) { + pr_err("[SDCHG][%s] failed to request GPIO %d\n", + __func__, sdchg_info->chip->factory_discharging); + goto err_gpio; + } + } + +err_gpio: + return ret; +} + +static int sdchg_ic_use_remove(void) +{ + if (sdchg_info->chip->factory_discharging) + gpio_free(sdchg_info->chip->factory_discharging); + + return 0; +} + +static int __init sdchg_ic_use_init(void) +{ + int ret; + + pr_info("[SDCHG][%s] ++\n", __func__); + + sdchg_info = kzalloc(sizeof(struct sdchg_info_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate memory for self discharging\n"); + ret = -ENOMEM; + goto fail_out; + } + sdchg_info->type = sdchg_type; + + /*****************************************/ + sdchg_info->chip = kzalloc(sizeof(struct sdchg_info_chip_t), GFP_KERNEL); + if (!sdchg_info) { + pr_err("Failed to allocate nochip memory for self discharging\n"); + ret = -ENOMEM; + goto after_alloc_info; + } + + sdchg_info->chip->pinfo = sdchg_info; + /*****************************************/ + sdchg_info->sdchg_probe = sdchg_ic_use_probe; + sdchg_info->sdchg_remove = sdchg_ic_use_remove; + sdchg_info->sdchg_parse_dt = sdchg_ic_use_parse_dt; + + sdchg_info->sdchg_adc_check = sdchg_ic_use_adc_check; + sdchg_info->sdchg_ntc_check = sdchg_ic_use_ntc_check; + sdchg_info->sdchg_force_control = sdchg_ic_use_force_control; + sdchg_info->sdchg_discharging_check = sdchg_ic_use_discharging_check; + + sdchg_info->sdchg_force_check = sdchg_ic_use_force_check; + /*****************************************/ + + list_add(&sdchg_info->info_list, &sdchg_info_head); + + pr_info("[SDCHG][%s] --\n", __func__); + + return 0; + +after_alloc_info: + if (sdchg_info) { + kfree(sdchg_info); + sdchg_info = NULL; + } +fail_out: + pr_info("[SDCHG][%s] --(%d)\n", __func__, ret); + + return ret; + } + + +static void __exit sdchg_ic_use_exit(void) +{ + pr_info("[SDCHG][%s] ++\n", __func__); + + if (sdchg_info) { + if (sdchg_info->chip) { + kfree(sdchg_info->chip); + sdchg_info->chip = NULL; + } + kfree(sdchg_info); + sdchg_info = NULL; + } + + pr_info("[SDCHG][%s] --\n", __func__); + + return; +} + +arch_initcall(sdchg_ic_use_init); +module_exit(sdchg_ic_use_exit); + +MODULE_AUTHOR("jeeon.park@samsung.com"); +MODULE_DESCRIPTION("Samsung Electronics Co. Battery Self Discharging \ + for Preventing Swelling with Self Discharging IC"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/battery/sec_battery.c b/drivers/battery/sec_battery.c index 86fac626e6e9..f1b1f260d900 100644 --- a/drivers/battery/sec_battery.c +++ b/drivers/battery/sec_battery.c @@ -13,6 +13,20 @@ const char *charger_chip_name; +/**************************************************************/ +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING_ZERO_ONLY +static int zero_sdchg_ic_exist = 1; // default : ic exist +static int __init zero_sdchg_ic_exist_setup(char *str) +{ + zero_sdchg_ic_exist = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("zero_sdchg_ic=", zero_sdchg_ic_exist_setup); +#endif +#endif +/**************************************************************/ static struct device_attribute sec_battery_attrs[] = { SEC_BATTERY_ATTR(batt_reset_soc), SEC_BATTERY_ATTR(batt_read_raw_soc), @@ -92,6 +106,17 @@ static struct device_attribute sec_battery_attrs[] = { #endif SEC_BATTERY_ATTR(hmt_ta_connected), SEC_BATTERY_ATTR(hmt_ta_charge), +#if defined(CONFIG_BATTERY_AGE_FORECAST) + SEC_BATTERY_ATTR(fg_cycle), + SEC_BATTERY_ATTR(fg_full_voltage), +#endif +#if defined(CONFIG_WIRELESS_CHARGER_THM) + SEC_BATTERY_ATTR(batt_wpc_temp), + SEC_BATTERY_ATTR(batt_wpc_temp_adc), +#endif +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + SEC_BATTERY_ATTR(batt_wireless_firmware_update), +#endif }; static enum power_supply_property sec_battery_props[] = { @@ -340,6 +365,14 @@ static int sec_bat_get_adc_value( return adc; } +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING +int sec_bat_get_adc_value_using_sdchg( + struct sec_battery_info *battery, int channel) +{ + return sec_bat_get_adc_value(battery, channel); +} +EXPORT_SYMBOL(sec_bat_get_adc_value_using_sdchg); +#endif static int sec_bat_get_charger_type_adc (struct sec_battery_info *battery) @@ -906,6 +939,13 @@ static bool sec_bat_get_temperature_by_adc( battery->pdata->chg_temp_adc_table_size; battery->chg_temp_adc = temp_adc; break; + case SEC_BAT_ADC_CHANNEL_WPC_TEMP: + temp_adc_table = battery->pdata->wpc_temp_adc_table; + temp_adc_table_size = + battery->pdata->chg_temp_adc_table_size; + battery->wpc_temp_adc = temp_adc; + pr_info("%s wpc_temp_adc = %d \n",__func__, battery->wpc_temp_adc); + break; default: dev_err(battery->dev, "%s: Invalid Property\n", __func__); @@ -1021,7 +1061,7 @@ static void sec_bat_swelling_check(struct sec_battery_info *battery, int tempera battery->charging_block, val.intval, temperature); /* swelling_mode - under voltage over voltage, battery missing */ + under voltage over voltage, battery missing */ if ((battery->status == POWER_SUPPLY_STATUS_DISCHARGING) ||\ (battery->status == POWER_SUPPLY_STATUS_NOT_CHARGING)) { pr_info("%s: DISCHARGING or NOT-CHARGING. stop swelling mode\n", __func__); @@ -1092,6 +1132,44 @@ static void sec_bat_swelling_check(struct sec_battery_info *battery, int tempera } #endif +#if defined(CONFIG_BATTERY_AGE_FORECAST) +static void sec_bat_aging_check(struct sec_battery_info *battery) +{ + union power_supply_propval value; + + if(battery->swelling_mode) { + pr_info("%s: swelling mode. skip to check aging \n", __func__); + return; + } + + psy_do_property(battery->pdata->fuelgauge_name, get, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, value); + + dev_info(battery->dev, + "%s [FG] : should set (%d)\n", + __func__, value.intval); + + if(battery->pdata->chg_float_voltage > value.intval) { + psy_do_property(battery->pdata->charger_name, set, + POWER_SUPPLY_PROP_VOLTAGE_MAX, value); + //batt_set_data(BATT_FILE_PATH_CYCLE, value.intval); + + battery->pdata->chg_float_voltage = value.intval; + battery->pdata->full_condition_vcell = battery->pdata->chg_float_voltage - 100; + battery->pdata->recharge_condition_vcell = battery->pdata->chg_float_voltage - 50; + battery->pdata->swelling_normal_float_voltage = battery->pdata->chg_float_voltage; + + dev_info(battery->dev, + "%s: float_voltage(%d), full_condition_vcell(%d), recharge_condition_vcell(%d), swelling_normal_float_voltage(%d)\n", __func__, + battery->pdata->chg_float_voltage, + battery->pdata->full_condition_vcell, + battery->pdata->recharge_condition_vcell, + battery->pdata->swelling_normal_float_voltage); + } +} +#endif + + static bool sec_bat_temperature_check( struct sec_battery_info *battery) { @@ -1306,96 +1384,6 @@ static bool sec_bat_temperature_check( return true; } -#if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) -static void sec_bat_self_discharging_check(struct sec_battery_info *battery) -{ - unsigned int dis_adc; - - dis_adc = sec_bat_get_adc_value(battery, SEC_BAT_ADC_CHANNEL_DISCHARGING_CHECK); - if (dis_adc) - battery->self_discharging_adc = dis_adc; - else - battery->self_discharging_adc = 0; - - if ((dis_adc >= (int)battery->pdata->discharging_adc_min) && - (dis_adc <= (int)battery->pdata->discharging_adc_max)) - battery->self_discharging = true; - else - battery->self_discharging = false; - - pr_info("%s : SELF_DISCHARGING(%d) SELF_DISCHARGING_ADC(%d)\n", - __func__, battery->self_discharging, battery->self_discharging_adc); -} - -static void sec_bat_self_discharging_ntc_check(struct sec_battery_info *battery) -{ - int ntc_adc; - - ntc_adc = sec_bat_get_adc_value(battery, SEC_BAT_ADC_CHANNEL_DISCHARGING_NTC); - if (ntc_adc) - battery->discharging_ntc_adc = ntc_adc; - else - battery->discharging_ntc_adc = 0; - - if (ntc_adc > battery->pdata->discharging_ntc_limit) - battery->discharging_ntc = true; - else - battery->discharging_ntc = false; - - pr_info("%s : DISCHARGING_NTC(%d) DISCHARGING_NTC_ADC(%d)\n", - __func__,battery->discharging_ntc, battery->discharging_ntc_adc); -} - -static void sec_bat_self_discharging_control(struct sec_battery_info *battery, bool dis_en) -{ - if (!battery->pdata->factory_discharging) { - pr_info("Can't control Self Discharging IC (No Factory Discharging Pin).\n"); - return; - } - - if (dis_en) { - dev_info(battery->dev, - "%s : Self Discharging IC doesn't act until (%d) degree & (%d) voltage. " - "Auto Discharging IC ENABLE\n", __func__, - battery->temperature, battery->voltage_now); - gpio_direction_output(battery->pdata->factory_discharging, 1); - battery->force_discharging = true; - } else { - dev_info(battery->dev, "%s : Self Discharging IC disable.\n", __func__); - gpio_direction_output(battery->pdata->factory_discharging, 0); - battery->force_discharging = false; - } -} - -static void sec_bat_discharging_check(struct sec_battery_info *battery) -{ - if (!battery->pdata->self_discharging_en) - return; - - sec_bat_self_discharging_check(battery); - - if(battery->factory_self_discharging_mode_on) { - dev_info(battery->dev, - "%s: It is Factory mode by self discharging mode, Auto_DIS(%d), Force_DIS(%d)\n", - __func__, battery->self_discharging, battery->force_discharging); - return; - } - - if (!battery->self_discharging && - (battery->temperature >= battery->pdata->force_discharging_limit) && - (battery->voltage_now >= battery->pdata->self_discharging_voltage_limit)) { - sec_bat_self_discharging_control(battery, true); - } else if(battery->force_discharging && - ((battery->temperature <= battery->pdata->force_discharging_recov) || - (battery->voltage_now <= battery->pdata->swelling_drop_float_voltage))) { - sec_bat_self_discharging_control(battery, false); - } - dev_info(battery->dev, - "%s: Auto_DIS(%d), Force_DIS(%d)\n", - __func__, battery->self_discharging, battery->force_discharging); -} -#endif - #if !defined(CONFIG_SEC_FACTORY) static void sec_bat_chg_temperature_check( struct sec_battery_info *battery) @@ -1757,7 +1745,8 @@ static bool sec_bat_time_management( if (battery->pdata->chg_temp_check && battery->skip_chg_temp_check) { if ((battery->cable_type == POWER_SUPPLY_TYPE_HV_MAINS || - battery->cable_type == POWER_SUPPLY_TYPE_HV_ERR) && + battery->cable_type == POWER_SUPPLY_TYPE_HV_ERR || + battery->cable_type == POWER_SUPPLY_TYPE_WIRELESS) && battery->charging_passed_time >= battery->pdata->chg_skip_check_time) { battery->skip_chg_temp_check = false; dev_info(battery->dev, @@ -2142,6 +2131,13 @@ static void sec_bat_get_temperature_info( battery->temper_amb = value.intval; psy_do_property(battery->pdata->fuelgauge_name, set, POWER_SUPPLY_PROP_TEMP_AMBIENT, value); + +#if defined(CONFIG_WIRELESS_CHARGER_THM) + sec_bat_get_temperature_by_adc(battery, + SEC_BAT_ADC_CHANNEL_WPC_TEMP, &value); + battery->wpc_temp = value.intval; + pr_info("%s wpc temp = %d \n",__func__, battery->wpc_temp ); +#endif break; default: break; @@ -2179,22 +2175,22 @@ static void sec_bat_get_battery_info( POWER_SUPPLY_PROP_VOLTAGE_NOW, value); battery->voltage_now = value.intval; - value.intval = SEC_BATTEY_VOLTAGE_AVERAGE; + value.intval = SEC_BATTERY_VOLTAGE_AVERAGE; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_VOLTAGE_AVG, value); battery->voltage_avg = value.intval; - value.intval = SEC_BATTEY_VOLTAGE_OCV; + value.intval = SEC_BATTERY_VOLTAGE_OCV; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_VOLTAGE_AVG, value); battery->voltage_ocv = value.intval; - value.intval = SEC_BATTEY_CURRENT_MA; + value.intval = SEC_BATTERY_CURRENT_MA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_NOW, value); battery->current_now = value.intval; - value.intval = SEC_BATTEY_CURRENT_MA; + value.intval = SEC_BATTERY_CURRENT_MA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_AVG, value); battery->current_avg = value.intval; @@ -2228,12 +2224,24 @@ static void sec_bat_get_battery_info( battery->capacity = value.intval; #endif + if (battery->capacity > 5 && battery->ignore_siop && + (battery->r_siop_level != battery->siop_level)) { + battery->siop_level = battery->r_siop_level; + battery->ignore_siop = false; + if (battery->cable_type == POWER_SUPPLY_TYPE_WIRELESS) + queue_delayed_work_on(0, battery->monitor_wqueue, &battery->siop_work, + msecs_to_jiffies(1200)); + else + queue_delayed_work_on(0, battery->monitor_wqueue, &battery->siop_work, 0); + } + dev_info(battery->dev, - "%s:Vnow(%dmV),Inow(%dmA),Imax(%dmA),SOC(%d%%),Tbat(%d),Tchg(%d),is_hc_usb(%d)\n", + "%s:Vnow(%dmV),Inow(%dmA),Imax(%dmA),SOC(%d%%),Tbat(%d),Tchg(%d),Twpc(%d),is_hc_usb(%d)\n", __func__, battery->voltage_now, battery->current_now, battery->current_max, battery->capacity, - battery->temperature, battery->chg_temp, battery->is_hc_usb); + battery->temperature, battery->chg_temp, + battery->wpc_temp, battery->is_hc_usb); dev_dbg(battery->dev, "%s,Vavg(%dmV),Vocv(%dmV),Tamb(%d)," "Iavg(%dmA),Iadc(%d)\n", @@ -2327,6 +2335,11 @@ static unsigned int sec_bat_get_polling_time( battery->status == POWER_SUPPLY_STATUS_CHARGING) battery->polling_time = 46; +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (battery->pdata->sdchg_info && battery->pdata->sdchg_info->nochip) + battery->polling_time = sdchg_get_polling_time(battery->polling_time); +#endif + return battery->polling_time; } @@ -2527,9 +2540,38 @@ static void sec_bat_siop_work(struct work_struct *work) pr_info("%s : set current by siop level(%d)\n",__func__, battery->siop_level); psy_do_property(battery->pdata->charger_name, set, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, value); + +#if !defined(CONFIG_SEC_FACTORY) + if (battery->pdata->chg_temp_check && battery->siop_level >= 100) + sec_bat_chg_temperature_check(battery); +#endif + wake_unlock(&battery->siop_wake_lock); } +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) +static void sec_bat_fw_update_work(struct sec_battery_info *battery, int mode) +{ + union power_supply_propval value; + + dev_info(battery->dev, + "%s: update firmware work()\n", __func__); + + wake_lock_timeout(&battery->vbus_wake_lock, HZ * 10); + + psy_do_property(battery->pdata->charger_name, set, + POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value); + + value.intval = mode; + psy_do_property("p9220-charger", set, + POWER_SUPPLY_PROP_CHARGE_POWERED_OTG_CONTROL, value); + + value.intval = false; + psy_do_property(battery->pdata->charger_name, set, + POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value); +} + +#endif static void sec_bat_monitor_work( struct work_struct *work) { @@ -2552,8 +2594,21 @@ static void sec_bat_monitor_work( if ((battery->status == POWER_SUPPLY_STATUS_DISCHARGING) && (battery->ps_enable != true)) { if ((unsigned long)(c_ts.tv_sec - old_ts.tv_sec) < 10 * 60) { - pr_info("Skip monitor_work(%ld)\n", - c_ts.tv_sec - old_ts.tv_sec); + union power_supply_propval value; + + psy_do_property(battery->pdata->fuelgauge_name, get, + POWER_SUPPLY_PROP_VOLTAGE_NOW, value); + battery->voltage_now = value.intval; + sec_bat_get_temperature_info(battery); + power_supply_changed(&battery->psy_bat); + pr_info("Skip monitor work(%ld, Vnow:%dmV, Tbat:%d)\n", + c_ts.tv_sec - old_ts.tv_sec, battery->voltage_now, battery->temperature); + +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (battery->pdata->sdchg_info && + battery->pdata->sdchg_info->nochip) + battery->pdata->sdchg_info->nochip->sdchg_monitor(battery, c_ts.tv_sec, true); +#endif goto skip_monitor; } } @@ -2563,6 +2618,11 @@ static void sec_bat_monitor_work( sec_bat_get_battery_info(battery); +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (battery->pdata->sdchg_info && battery->pdata->sdchg_info->nochip) + battery->pdata->sdchg_info->nochip->sdchg_monitor(battery, c_ts.tv_sec, false); +#endif + #if defined(CONFIG_CALC_TIME_TO_FULL) /* time to full check */ sec_bat_calc_time_to_full(battery); @@ -2602,7 +2662,8 @@ static void sec_bat_monitor_work( goto continue_monitor; #if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) - sec_bat_discharging_check(battery); + if (battery->pdata->sdchg_info) + battery->pdata->sdchg_info->sdchg_discharging_check(battery); #endif #if defined(CONFIG_BATTERY_SWELLING) @@ -2617,6 +2678,9 @@ static void sec_bat_monitor_work( sec_bat_fullcharged_check(battery); #endif /* CONFIG_BATTERY_SWELLING */ +#if defined(CONFIG_BATTERY_AGE_FORECAST) + sec_bat_aging_check(battery); +#endif /* 6. additional check */ if (battery->pdata->monitor_additional_check) battery->pdata->monitor_additional_check(); @@ -2748,6 +2812,9 @@ static void sec_bat_cable_work(struct work_struct *work) #endif battery->cable_type = current_cable_type; + if (battery->cable_type == POWER_SUPPLY_TYPE_WIRELESS) + power_supply_changed(&battery->psy_bat); + if (battery->pdata->check_cable_result_callback) battery->pdata->check_cable_result_callback( battery->cable_type); @@ -2772,6 +2839,7 @@ static void sec_bat_cable_work(struct work_struct *work) battery->complete_timetofull = false; cancel_delayed_work(&battery->timetofull_work); #endif + battery->skip_chg_temp_check = false; if (sec_bat_set_charge(battery, false)) goto end_of_cable_work; } else if (battery->slate_mode == true) { @@ -2832,7 +2900,8 @@ static void sec_bat_cable_work(struct work_struct *work) if (battery->pdata->chg_temp_check && (battery->cable_type == POWER_SUPPLY_TYPE_HV_MAINS || - battery->cable_type == POWER_SUPPLY_TYPE_HV_ERR) && + battery->cable_type == POWER_SUPPLY_TYPE_HV_ERR || + battery->cable_type == POWER_SUPPLY_TYPE_WIRELESS ) && battery->capacity <= battery->pdata->chg_skip_check_capacity) { battery->skip_chg_temp_check = true; dev_info(battery->dev, @@ -2924,7 +2993,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, { union power_supply_propval value; - value.intval = SEC_BATTEY_CURRENT_UA; + value.intval = SEC_BATTERY_CURRENT_UA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_NOW, value); @@ -2936,7 +3005,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, { union power_supply_propval value; - value.intval = SEC_BATTEY_CURRENT_UA; + value.intval = SEC_BATTERY_CURRENT_UA; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_CURRENT_AVG, value); @@ -3042,7 +3111,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, union power_supply_propval value; value.intval = - SEC_BATTEY_CAPACITY_DESIGNED; + SEC_BATTERY_CAPACITY_DESIGNED; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_ENERGY_NOW, value); @@ -3050,7 +3119,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, value.intval); value.intval = - SEC_BATTEY_CAPACITY_ABSOLUTE; + SEC_BATTERY_CAPACITY_ABSOLUTE; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_ENERGY_NOW, value); @@ -3058,7 +3127,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, value.intval); value.intval = - SEC_BATTEY_CAPACITY_TEMPERARY; + SEC_BATTERY_CAPACITY_TEMPERARY; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_ENERGY_NOW, value); @@ -3066,7 +3135,7 @@ ssize_t sec_bat_show_attrs(struct device *dev, value.intval); value.intval = - SEC_BATTEY_CAPACITY_CURRENT; + SEC_BATTERY_CAPACITY_CURRENT; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_ENERGY_NOW, value); @@ -3239,24 +3308,43 @@ ssize_t sec_bat_show_attrs(struct device *dev, break; #if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) case BATT_DISCHARGING_CHECK: - sec_bat_self_discharging_check(battery); - i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", - battery->self_discharging); + { + int ret; + if (battery->pdata->sdchg_info) { + ret = battery->pdata->sdchg_info->sdchg_force_check(battery); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + ret); + } else { + pr_info("[SDCHG][%s] discharging info structure is null!!\n", __func__); + } + } break; case BATT_DISCHARGING_CHECK_ADC: - sec_bat_self_discharging_check(battery); - i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", - battery->self_discharging_adc); + if (battery->pdata->sdchg_info) { + battery->pdata->sdchg_info->sdchg_adc_check(battery); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->self_discharging_adc); + } else { + pr_info("[SDCHG][%s] discharging info structure is null!!\n", __func__); + } break; case BATT_DISCHARGING_NTC: - sec_bat_self_discharging_ntc_check(battery); - i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", - battery->discharging_ntc); + if (battery->pdata->sdchg_info) { + battery->pdata->sdchg_info->sdchg_ntc_check(battery); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->discharging_ntc); + } else { + pr_info("[SDCHG][%s] discharging info structure is null!!\n", __func__); + } break; case BATT_DISCHARGING_NTC_ADC: - sec_bat_self_discharging_ntc_check(battery); - i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", - battery->discharging_ntc_adc); + if (battery->pdata->sdchg_info) { + battery->pdata->sdchg_info->sdchg_ntc_check(battery); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->discharging_ntc_adc); + } else { + pr_info("[SDCHG][%s] discharging info structure is null!!\n", __func__); + } break; case BATT_SELF_DISCHARGING_CONTROL: break; @@ -3266,8 +3354,8 @@ ssize_t sec_bat_show_attrs(struct device *dev, psy_do_property(battery->pdata->wireless_charger_name, get, POWER_SUPPLY_PROP_STATUS, value); i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval); -#endif break; +#endif case HMT_TA_CONNECTED: i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", (battery->cable_type == POWER_SUPPLY_TYPE_HMT_CONNECTED) ? 1 : 0); @@ -3276,6 +3364,40 @@ ssize_t sec_bat_show_attrs(struct device *dev, i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", (battery->cable_type == POWER_SUPPLY_TYPE_HMT_CHARGE) ? 1 : 0); break; +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case FG_CYCLE: + value.intval = SEC_BATTERY_CAPACITY_CYCLE; + psy_do_property(battery->pdata->fuelgauge_name, get, + POWER_SUPPLY_PROP_ENERGY_NOW, value); + value.intval = value.intval/10; + dev_info(battery->dev, "fg cycle(%d)\n", value.intval); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", value.intval); + break; + case FG_FULL_VOLTAGE: + dev_info(battery->dev, "current float voltage(%d)\n", battery->pdata->chg_float_voltage); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->pdata->chg_float_voltage); + break; +#endif +#if defined(CONFIG_WIRELESS_CHARGER_THM) + case BATT_WPC_TEMP: + sec_bat_get_temperature_by_adc(battery, + SEC_BAT_ADC_CHANNEL_WPC_TEMP, &value); + pr_info("%s wpc temp = %d \n",__func__, value.intval); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + value.intval); + + break; + case BATT_WPC_TEMP_ADC: + pr_info("%s wpc_temp_adc = %d \n",__func__, battery->wpc_temp_adc); + i += scnprintf(buf + i, PAGE_SIZE - i, "%d\n", + battery->wpc_temp_adc); + break; +#endif +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + case BATT_WIRELESS_FIRMWARE_UPDATE: + break; +#endif default: i = -EINVAL; } @@ -3314,6 +3436,7 @@ ssize_t sec_bat_store_attrs( int ret = -EINVAL; int x = 0; int t[12]; + switch (offset) { case BATT_RESET_SOC: /* Do NOT reset fuel gauge in charging mode */ @@ -3332,6 +3455,9 @@ ssize_t sec_bat_store_attrs( /* update battery info */ sec_bat_get_battery_info(battery); } +#if defined(CONFIG_SEC_FACTORY) && defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + sec_bat_fw_update_work(battery, 1); +#endif ret = count; break; case BATT_READ_RAW_SOC: @@ -3393,7 +3519,9 @@ ssize_t sec_bat_store_attrs( break; case SIOP_LEVEL: if (sscanf(buf, "%d\n", &x) == 1) { +#if defined(CONFIG_WIRELESS_CHARGER_INBATTERY) union power_supply_propval value; +#endif dev_info(battery->dev, "%s: siop level: %d\n", __func__, x); battery->chg_limit = SEC_BATTERY_CHG_TEMP_NONE; @@ -3402,10 +3530,12 @@ ssize_t sec_bat_store_attrs( dev_info(battery->dev, "%s: skip same siop level: %d\n", __func__, x); return count; - } else if (x >= 0 && x <= 100) + } else if (x >= 0 && x <= 100) { battery->siop_level = x; - else + } else { battery->siop_level = 100; + } + battery->r_siop_level = battery->siop_level; #if defined(CONFIG_WIRELESS_CHARGER_INBATTERY) value.intval = battery->siop_level; @@ -3428,8 +3558,12 @@ ssize_t sec_bat_store_attrs( POWER_SUPPLY_PROP_CHARGE_TYPE, value); } #endif - if (battery->capacity <= 5) + if (battery->capacity <= 5) { battery->siop_level = 100; + battery->ignore_siop = true; + } else if (battery->ignore_siop) { + battery->ignore_siop = false; + } if (battery->cable_type == POWER_SUPPLY_TYPE_WIRELESS) queue_delayed_work_on(0, battery->monitor_wqueue, &battery->siop_work, @@ -3718,19 +3852,23 @@ ssize_t sec_bat_store_attrs( case BATT_DISCHARGING_NTC_ADC: break; case BATT_SELF_DISCHARGING_CONTROL: - if (sscanf(buf, "%d\n", &x) == 1) { - dev_err(battery->dev, - "%s: BATT_SELF_DISCHARGING_CONTROL(%d)\n", __func__, x); - if (x) { - battery->factory_self_discharging_mode_on = true; - pr_info("SELF DISCHARGING IC ENABLE\n"); - sec_bat_self_discharging_control(battery, true); - } else { - battery->factory_self_discharging_mode_on = false; - pr_info("SELF DISCHARGING IC DISENABLE\n"); - sec_bat_self_discharging_control(battery, false); + if (battery->pdata->sdchg_info) { + if (sscanf(buf, "%d\n", &x) == 1) { + dev_err(battery->dev, + "%s: BATT_SELF_DISCHARGING_CONTROL(%d)\n", __func__, x); + if (x) { + battery->factory_self_discharging_mode_on = true; + pr_info("SELF DISCHARGING IC ENABLE\n"); + battery->pdata->sdchg_info->sdchg_force_control(battery, true); + } else { + battery->factory_self_discharging_mode_on = false; + pr_info("SELF DISCHARGING IC DISENABLE\n"); + battery->pdata->sdchg_info->sdchg_force_control(battery, false); + } + ret = count; } - ret = count; + } else { + pr_info("[SDCHG][%s] discharging info structure is null!!\n", __func__); } break; #endif @@ -3816,6 +3954,62 @@ ssize_t sec_bat_store_attrs( ret = count; } break; +#if defined(CONFIG_BATTERY_AGE_FORECAST) + case FG_CYCLE: + break; + case FG_FULL_VOLTAGE: + if (sscanf(buf, "%d\n", &x) == 1) { + union power_supply_propval value; + dev_info(battery->dev, + "%s: FG_FULL_VOLTAGE(%d)\n", __func__, x); + + if (x >= 4200 && x <= 4400) { + value.intval = x; + psy_do_property(battery->pdata->charger_name, set, + POWER_SUPPLY_PROP_VOLTAGE_MAX, value); // needs to check + + //batt_set_data(BATT_FILE_PATH_CYCLE, x); + battery->pdata->chg_float_voltage = x; + battery->pdata->full_condition_vcell = battery->pdata->chg_float_voltage - 100; + battery->pdata->recharge_condition_vcell = battery->pdata->chg_float_voltage - 50; + battery->pdata->swelling_normal_float_voltage = battery->pdata->chg_float_voltage; + + dev_info(battery->dev, + "%s: float_voltage(%d), full_condition_vcell(%d), recharge_condition_vcell(%d), swelling_normal_float_voltage(%d)\n", __func__, + battery->pdata->chg_float_voltage, + battery->pdata->full_condition_vcell, + battery->pdata->recharge_condition_vcell, + battery->pdata->swelling_normal_float_voltage); + + ret = count; + } + } + break; +#endif +#if defined(CONFIG_WIRELESS_CHARGER_THM) + case BATT_WPC_TEMP: + case BATT_WPC_TEMP_ADC: + break; +#endif +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + case BATT_WIRELESS_FIRMWARE_UPDATE: + if (sscanf(buf, "%d\n", &x) == 1) { + if (x == 0) { + pr_info("%s fw mode is SDCARD \n", __func__); + sec_bat_fw_update_work(battery, 0); + } else if (x == 1) { + pr_info("%s fw mode is BUILD IN \n", __func__); + sec_bat_fw_update_work(battery, 1); + } + else { + dev_info(battery->dev, "%s: wireless firmware unknown command\n", __func__); + return -EINVAL; + } + ret = count; + } + break; +#endif + default: ret = -EINVAL; } @@ -4036,7 +4230,7 @@ static int sec_bat_get_property(struct power_supply *psy, break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: #ifdef CONFIG_SEC_FACTORY - value.intval = SEC_BATTEY_VOLTAGE_AVERAGE; + value.intval = SEC_BATTERY_VOLTAGE_AVERAGE; psy_do_property(battery->pdata->fuelgauge_name, get, POWER_SUPPLY_PROP_VOLTAGE_AVG, value); battery->voltage_avg = value.intval; @@ -4091,6 +4285,12 @@ static int sec_bat_get_property(struct power_supply *psy, break; #if defined(CONFIG_CALC_TIME_TO_FULL) case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: +#if defined(CONFIG_CHARGING_VZWCONCEPT) + if (battery->capacity == 100) { + val->intval = -1; + break; + } +#endif if (battery->status == POWER_SUPPLY_STATUS_CHARGING && battery->complete_timetofull && !battery->swelling_mode) val->intval = battery->timetofull; @@ -4219,8 +4419,6 @@ static int sec_wireless_set_property(struct power_supply *psy, struct sec_battery_info *battery = container_of(psy, struct sec_battery_info, psy_wireless); - union power_supply_propval value; - switch (psp) { case POWER_SUPPLY_PROP_ONLINE: battery->wc_status = val->intval; @@ -4232,6 +4430,7 @@ static int sec_wireless_set_property(struct power_supply *psy, #if defined(CONFIG_WIRELESS_CHARGER_INBATTERY) case POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL: if (battery->wc_status) { + union power_supply_propval value; value.intval = val->intval; psy_do_property(battery->pdata->wireless_charger_name, set, POWER_SUPPLY_PROP_CHARGE_OTG_CONTROL, value); @@ -4765,6 +4964,36 @@ static int sec_bat_parse_dt(struct device *dev, pr_info("%s : Temp_amb_adc_table(data) is Empty\n", __func__); } + + /* wpc temp adc */ + p = of_get_property(np, "battery,wpc_temp_table_adc", &len); + if (!p) { + pr_info("%s : discharge_Temp_adc_table(adc) is Empty\n",__func__); + } else { + len = len / sizeof(u32); + + pdata->wpc_temp_adc_table_size = len; + + pdata->wpc_temp_adc_table = + kzalloc(sizeof(sec_bat_adc_table_data_t) * + pdata->wpc_temp_adc_table_size, GFP_KERNEL); + + for(i = 0; i < pdata->wpc_temp_adc_table_size; i++) { + ret = of_property_read_u32_index(np, + "battery,wpc_temp_table_adc", i, &temp); + pdata->wpc_temp_adc_table[i].adc = (int)temp; + if (ret) + pr_info("%s : WPC_Temp_adc_table(adc) is Empty\n", + __func__); + + ret = of_property_read_u32_index(np, + "battery,wpc_temp_table_data", i, &temp); + pdata->wpc_temp_adc_table[i].data = (int)temp; + if (ret) + pr_info("%s : WPC_Temp_adc_table(data) is Empty\n", + __func__); + } + } } ret = of_property_read_u32(np, "battery,chg_temp_check", @@ -4817,7 +5046,7 @@ static int sec_bat_parse_dt(struct device *dev, pr_info("%s : wpc_temp_check is Empty\n", __func__); if (pdata->wpc_temp_check) { - ret = of_property_read_u32(np, "wpc_high_temp", + ret = of_property_read_u32(np, "battery,wpc_high_temp", &temp); pdata->wpc_high_temp = (int)temp; if (ret) @@ -5217,47 +5446,38 @@ static int sec_bat_parse_dt(struct device *dev, if (ret) pr_info("%s : Charging reset time is Empty\n", __func__); #if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) - pdata->factory_discharging = of_get_named_gpio(np, "battery,factory_discharging", 0); - if (pdata->factory_discharging < 0) - pdata->factory_discharging = 0; - - pdata->self_discharging_en = of_property_read_bool(np, - "battery,self_discharging_en"); - - ret = of_property_read_u32(np, "battery,force_discharging_limit", - &temp); - pdata->force_discharging_limit = (int)temp; - if (ret) - pr_info("%s : Force Discharging limit is Empty", __func__); - - ret = of_property_read_u32(np, "battery,force_discharging_recov", - &temp); - pdata->force_discharging_recov = (int)temp; - if (ret) - pr_info("%s : Force Discharging recov is Empty", __func__); - - pr_info("%s : FORCE_DISCHARGING_LIMT(%d), FORCE_DISCHARGING_RECOV(%d)\n", - __func__, pdata->force_discharging_limit, pdata->force_discharging_recov); - - ret = of_property_read_u32(np, "battery,discharging_adc_min", - (unsigned int *)&pdata->discharging_adc_min); - if (ret) - pr_info("%s : Discharging ADC Min is Empty", __func__); - - ret = of_property_read_u32(np, "battery,discharging_adc_max", - (unsigned int *)&pdata->discharging_adc_max);; - if (ret) - pr_info("%s : Discharging ADC Max is Empty", __func__); - - ret = of_property_read_u32(np, "battery,self_discharging_voltage_limit", - (unsigned int *)&pdata->self_discharging_voltage_limit); - if (ret) - pr_info("%s : Force Discharging recov is Empty", __func__); - - ret = of_property_read_u32(np, "battery,discharging_ntc_limit", - (unsigned int *)&pdata->discharging_ntc_limit); +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING_ZERO_ONLY + if (zero_sdchg_ic_exist == 0) + pdata->sdchg_type = kstrdup("sdchg_ap", GFP_KERNEL); + else + pdata->sdchg_type = kstrdup("sdchg_ic", GFP_KERNEL); +#else + ret = of_property_read_string(np, + "sdchg_type", (char const **)&pdata->sdchg_type); if (ret) - pr_info("%s : Discharging NTC LIMIT is Empty", __func__); + pdata->sdchg_type = kstrdup("sdchg_ic", GFP_KERNEL); +#endif + { + struct sdchg_info_t *pinfo; + // find info from list_head + list_for_each_entry(pinfo, &sdchg_info_head, info_list) { + if (!strcmp(pinfo->type, pdata->sdchg_type)) { + pdata->sdchg_info = pinfo; + if (pinfo->nochip) + sdchg_nochip_support = true; + pr_info("[SDCHG][%s] Battery Self Discharging Type : %s\n", + __func__, pdata->sdchg_type); + break; + } + } + if (!pinfo) { + pr_info("[SDCHG][%s] %s info is not found! \n" \ + "!! Caution : This Model don't support Battery"\ + " Swelling Self Discharging !!\n", __func__, pdata->sdchg_type); + } else { + pdata->sdchg_info->sdchg_parse_dt(dev); + } + } #endif #if defined(CONFIG_BATTERY_SWELLING) @@ -5324,6 +5544,14 @@ static int sec_bat_parse_dt(struct device *dev, pdata->swelling_chg_current); #endif + +#if defined(CONFIG_BATTERY_AGE_FORECAST) + ret = of_property_read_u32(np, "battery,chg_float_voltage", + (unsigned int *)&pdata->chg_float_voltage); + if (ret) + pr_info("%s: chg_float_voltage is Empty\n", __func__); +#endif + return ret; } #endif @@ -5434,6 +5662,7 @@ static int __devinit sec_battery_probe(struct platform_device *pdev) battery->charging_next_time = 0; battery->charging_fullcharged_time = 0; battery->siop_level = 100; + battery->r_siop_level = 100; battery->wc_enable = 1; battery->pre_chg_temp = 0; #if defined(CONFIG_SAMSUNG_BATTERY_ENG_TEST) @@ -5480,6 +5709,7 @@ static int __devinit sec_battery_probe(struct platform_device *pdev) battery->store_mode = false; battery->slate_mode = false; battery->is_hc_usb = false; + battery->ignore_siop = false; battery->skip_chg_temp_check = false; #if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) @@ -5498,7 +5728,8 @@ static int __devinit sec_battery_probe(struct platform_device *pdev) if (charger_chip_name != NULL && !strcmp(charger_chip_name,"max77843-charger")) { battery->pdata->charger_name = "max77843-charger"; battery->pdata->fuelgauge_name = "max77843-fuelgauge"; - } else if (!strcmp(charger_chip_name, "max77833-charger")) { + //} else if (!strcmp(charger_chip_name, "max77833-charger")) { + } else { battery->pdata->charger_name = "max77833-charger"; battery->pdata->fuelgauge_name = "max77833-fuelgauge"; } @@ -5551,12 +5782,12 @@ static int __devinit sec_battery_probe(struct platform_device *pdev) pr_info("%s : GPIO %d\n", __func__, gpio_get_value(battery->pdata->wchg_ctl)); } -#if defined (CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) - if (battery->pdata->factory_discharging) { - ret = gpio_request(battery->pdata->factory_discharging, "FACTORY_DISCHARGING"); +#if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) + if (battery->pdata->sdchg_info) { + ret = battery->pdata->sdchg_info->sdchg_probe((void *)battery); if (ret) { - pr_err("failed to request GPIO %u\n", battery->pdata->factory_discharging); - goto err_gpio; + pr_err("%s : Error! failed to sdchg_probe(%u)\n", __func__, ret); + goto err_sdchg_init; } } #endif @@ -5728,9 +5959,9 @@ static int __devinit sec_battery_probe(struct platform_device *pdev) destroy_workqueue(battery->monitor_wqueue); err_irq: #if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) - if (battery->pdata->factory_discharging) - gpio_free(battery->pdata->factory_discharging); -err_gpio: + if (battery->pdata->sdchg_info) + battery->pdata->sdchg_info->sdchg_remove(); +err_sdchg_init: #endif gpio_free(battery->pdata->wchg_ctl); err_wake_lock: @@ -5787,6 +6018,11 @@ static int __devexit sec_battery_remove(struct platform_device *pdev) power_supply_unregister(&battery->psy_usb); power_supply_unregister(&battery->psy_bat); +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (battery->pdata->sdchg_info) + battery->pdata->sdchg_info->sdchg_remove(); +#endif + dev_dbg(battery->dev, "%s: End\n", __func__); kfree(battery); @@ -5861,12 +6097,17 @@ static void sec_battery_complete(struct device *dev) static void sec_battery_shutdown(struct device *dev) { +#if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) struct sec_battery_info *battery = dev_get_drvdata(dev); if (battery->force_discharging) { - pr_info("SELF DISCHARGING IC DISENABLE\n"); - sec_bat_self_discharging_control(battery, false); + if (battery->pdata->sdchg_info) { + pr_info("SELF DISCHARGING IC DISENABLE\n"); + battery->pdata->sdchg_info->sdchg_force_control(battery, false); + } } +#endif + return; } #ifdef CONFIG_OF diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4c32ee5fca63..57332b09c6f0 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -255,4 +255,11 @@ config BT_BCM4358 help Adds BCM4358 RFKILL driver for Broadcom BCM4358 chipset for exynos54xx. default is n. + +config BT_BCM4359 + bool "Enable BCM4359 driver" + default n + help + Adds BCM4359 RFKILL driver for Broadcom BCM4359 chipset for exynos54xx. + default is n. endmenu diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 3e9655a89170..137441cbc595 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -31,3 +31,4 @@ hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-objs := $(hci_uart-y) obj-$(CONFIG_BT_BCM4358) += bcm4358.o +obj-$(CONFIG_BT_BCM4359) += bcm4359.o \ No newline at end of file diff --git a/drivers/bluetooth/bcm4359.c b/drivers/bluetooth/bcm4359.c new file mode 100644 index 000000000000..bf7e86219b75 --- /dev/null +++ b/drivers/bluetooth/bcm4359.c @@ -0,0 +1,397 @@ +/* + * Bluetooth Broadcom GPIO and Low Power Mode control + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Google, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include <../../arch/arm/include/asm/mach-types.h> + +//#include <../../arch/arm/mach-exynos/include/mach/gpio.h> +#include + +#define BT_LPM_ENABLE + +#define BT_UPORT 4 + +extern s3c_wake_peer_t s3c2410_serial_wake_peer[CONFIG_SERIAL_SAMSUNG_UARTS]; + +static struct rfkill *bt_rfkill; +#ifdef BT_LPM_ENABLE +static int bt_wake_state = -1; +#endif + +struct bcm_bt_lpm { + int host_wake; + int dev_wake; + + struct hrtimer enter_lpm_timer; + ktime_t enter_lpm_delay; + + struct uart_port *uport; + + struct wake_lock host_wake_lock; + struct wake_lock bt_wake_lock; +} bt_lpm; + +struct bcm_bt_gpio { + int bt_en; + int bt_wake; + int bt_hostwake; + int irq; +} bt_gpio; + +int bt_is_running=0; + +int check_bt_op(void) +{ + return bt_is_running; +} +EXPORT_SYMBOL(check_bt_op); + +static int bcm4359_bt_rfkill_set_power(void *data, bool blocked) +{ + /* rfkill_ops callback. Turn transmitter on when blocked is false */ + if (!blocked) { + pr_info("[BT] Bluetooth Power On.\n"); + +#ifdef BT_LPM_ENABLE + if ( irq_set_irq_wake(bt_gpio.irq, 1)) { + pr_err("[BT] Set_irq_wake failed.\n"); + return -1; + } +#endif + +#ifndef BT_LPM_ENABLE + gpio_set_value(bt_gpio.bt_wake, 1); +#endif + gpio_set_value(bt_gpio.bt_en, 1); + bt_is_running = 1; + msleep(100); + + } else { + pr_info("[BT] Bluetooth Power Off.\n"); + +#ifdef BT_LPM_ENABLE + if (gpio_get_value(bt_gpio.bt_en) && irq_set_irq_wake(bt_gpio.irq, 0)) { + pr_err("[BT] Release_irq_wake failed.\n"); + return -1; + } +#endif + bt_is_running = 0; + gpio_set_value(bt_gpio.bt_en, 0); + } + return 0; +} + +static const struct rfkill_ops bcm4359_bt_rfkill_ops = { + .set_block = bcm4359_bt_rfkill_set_power, +}; + +#ifdef BT_LPM_ENABLE +static void set_wake_locked(int wake) +{ +#ifdef CONFIG_BT_UART_IN_AUDIO + struct uart_port *port = bt_lpm.uport; +#endif + + if (wake) + wake_lock(&bt_lpm.bt_wake_lock); + + gpio_set_value(bt_gpio.bt_wake, wake); + bt_lpm.dev_wake = wake; + + if (bt_wake_state != wake) + { +#ifdef CONFIG_BT_UART_IN_AUDIO + if(bt_lpm.host_wake) + { + if(wake) + port->ops->set_wake(port, wake); + } + else + { + port->ops->set_wake(port, wake); + } +#endif + pr_err("[BT] set_wake_locked value = %d\n", wake); + bt_wake_state = wake; + } +} + +static enum hrtimer_restart enter_lpm(struct hrtimer *timer) +{ + if (bt_lpm.uport != NULL) + set_wake_locked(0); + + bt_is_running = 0; + + wake_lock_timeout(&bt_lpm.bt_wake_lock, HZ/2); + + return HRTIMER_NORESTART; +} + +void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport) +{ + bt_lpm.uport = uport; + + hrtimer_try_to_cancel(&bt_lpm.enter_lpm_timer); + bt_is_running = 1; + set_wake_locked(1); + +// pr_info("[BT] bcm_bt_lpm_exit_lpm_locked\n"); + hrtimer_start(&bt_lpm.enter_lpm_timer, bt_lpm.enter_lpm_delay, + HRTIMER_MODE_REL); +} + +static void update_host_wake_locked(int host_wake) +{ + if (host_wake == bt_lpm.host_wake) + return; + + bt_lpm.host_wake = host_wake; + + bt_is_running = 1; + + if (host_wake) { + wake_lock(&bt_lpm.host_wake_lock); + } else { + /* Take a timed wakelock, so that upper layers can take it. + * The chipset deasserts the hostwake lock, when there is no + * more data to send. + */ + pr_err("[BT] update_host_wake_locked host_wake is deasserted. release wakelock in 1s\n"); + wake_lock_timeout(&bt_lpm.host_wake_lock, HZ); + } +} + +static irqreturn_t host_wake_isr(int irq, void *dev) +{ +#ifdef CONFIG_BT_UART_IN_AUDIO + struct uart_port *port = bt_lpm.uport; +#endif + int host_wake; + + host_wake = gpio_get_value(bt_gpio.bt_hostwake); + irq_set_irq_type(irq, host_wake ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING); + + if (!bt_lpm.uport) { + bt_lpm.host_wake = host_wake; + pr_err("[BT] host_wake_isr uport is null\n"); + return IRQ_HANDLED; + } + +#ifdef CONFIG_BT_UART_IN_AUDIO + if(bt_lpm.dev_wake) + { + if(host_wake) + port->ops->set_wake(port, host_wake); + } + else + { + port->ops->set_wake(port, host_wake); + } +#endif + update_host_wake_locked(host_wake); + + return IRQ_HANDLED; +} + +static int bcm_bt_lpm_init(struct platform_device *pdev) +{ + int ret; + + hrtimer_init(&bt_lpm.enter_lpm_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + bt_lpm.enter_lpm_delay = ktime_set(5, 0); /* 1 sec */ /*1->3*//*3->4*/ + bt_lpm.enter_lpm_timer.function = enter_lpm; + + bt_lpm.host_wake = 0; + + wake_lock_init(&bt_lpm.host_wake_lock, WAKE_LOCK_SUSPEND, + "BT_host_wake"); + wake_lock_init(&bt_lpm.bt_wake_lock, WAKE_LOCK_SUSPEND, + "BT_bt_wake"); + + s3c2410_serial_wake_peer[BT_UPORT] = (s3c_wake_peer_t) bcm_bt_lpm_exit_lpm_locked; + + bt_gpio.irq = gpio_to_irq(bt_gpio.bt_hostwake); + ret = request_irq(bt_gpio.irq, host_wake_isr, IRQF_TRIGGER_RISING, + "bt_host_wake", NULL); + if (ret) { + pr_err("[BT] Request_host wake irq failed.\n"); + return ret; + } + + return 0; +} +#endif + +static int bcm4359_bluetooth_probe(struct platform_device *pdev) +{ + int rc = 0; +#ifdef BT_LPM_ENABLE + int ret; +#endif + pr_info("[BT] bcm4359_bluetooth_probe.\n"); + + bt_gpio.bt_en = of_get_gpio(pdev->dev.of_node, 0); + + if (!gpio_is_valid(bt_gpio.bt_en)) { + pr_err("[BT] bt_gpio.bt_en get gpio failed.\n"); + return -EINVAL; + } + + rc = gpio_request(bt_gpio.bt_en, "bten_gpio"); + + if (unlikely(rc)) { + pr_err("[BT] bt_gpio.bt_en request failed.\n"); + return rc; + } + + bt_gpio.bt_wake =of_get_gpio(pdev->dev.of_node, 1); + + if (!gpio_is_valid(bt_gpio.bt_wake)) { + pr_err("[BT] bt_gpio.bt_wake get gpio failed.\n"); + return -EINVAL; + } + + rc = gpio_request(bt_gpio.bt_wake, "btwake_gpio"); + + if (unlikely(rc)) { + pr_err("[BT] bt_gpio.bt_wake request failed.\n"); + gpio_free(bt_gpio.bt_en); + return rc; + } + + bt_gpio.bt_hostwake =of_get_gpio(pdev->dev.of_node, 2); + + if (!gpio_is_valid(bt_gpio.bt_hostwake)) { + pr_err("[BT] bt_gpio.bt_hostwake get gpio failed.\n"); + return -EINVAL; + } + + rc = gpio_request(bt_gpio.bt_hostwake,"bthostwake_gpio"); + + if (unlikely(rc)) { + pr_err("[BT] bt_gpio.bt_hostwake request failed.\n"); + gpio_free(bt_gpio.bt_wake); + gpio_free(bt_gpio.bt_en); + return rc; + } + + gpio_direction_input(bt_gpio.bt_hostwake); + gpio_direction_output(bt_gpio.bt_wake, 0); + gpio_direction_output(bt_gpio.bt_en, 0); + + bt_rfkill = rfkill_alloc("bcm4359 Bluetooth", &pdev->dev, + RFKILL_TYPE_BLUETOOTH, &bcm4359_bt_rfkill_ops, + NULL); + + if (unlikely(!bt_rfkill)) { + pr_err("[BT] bt_rfkill alloc failed.\n"); + gpio_free(bt_gpio.bt_hostwake); + gpio_free(bt_gpio.bt_wake); + gpio_free(bt_gpio.bt_en); + return -ENOMEM; + } + + rfkill_init_sw_state(bt_rfkill, 0); + + rc = rfkill_register(bt_rfkill); + + if (unlikely(rc)) { + pr_err("[BT] bt_rfkill register failed.\n"); + rfkill_destroy(bt_rfkill); + gpio_free(bt_gpio.bt_hostwake); + gpio_free(bt_gpio.bt_wake); + gpio_free(bt_gpio.bt_en); + return -1; + } + + rfkill_set_sw_state(bt_rfkill, true); + +#ifdef BT_LPM_ENABLE + ret = bcm_bt_lpm_init(pdev); + if (ret) { + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + + gpio_free(bt_gpio.bt_hostwake); + gpio_free(bt_gpio.bt_wake); + gpio_free(bt_gpio.bt_en); + } +#endif + pr_info("[BT] bcm4359_bluetooth_probe End \n"); + return rc; +} + +static int bcm4359_bluetooth_remove(struct platform_device *pdev) +{ + rfkill_unregister(bt_rfkill); + rfkill_destroy(bt_rfkill); + + gpio_free(bt_gpio.bt_en); + gpio_free(bt_gpio.bt_wake); + gpio_free(bt_gpio.bt_hostwake); + + wake_lock_destroy(&bt_lpm.host_wake_lock); + wake_lock_destroy(&bt_lpm.bt_wake_lock); + + return 0; +} + +#if defined (CONFIG_OF) +static const struct of_device_id exynos_bluetooth_match[] = { + { + .compatible = "broadcom,bcm4359", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_bluetooth_match); + +static struct platform_driver bcm4359_bluetooth_platform_driver = { + .probe = bcm4359_bluetooth_probe, + .remove = bcm4359_bluetooth_remove, + .driver = { + .name = "bcm4359_bluetooth", + .owner = THIS_MODULE, + .of_match_table = exynos_bluetooth_match, + }, +}; + +module_platform_driver(bcm4359_bluetooth_platform_driver); +#endif +MODULE_ALIAS("platform:bcm4359"); +MODULE_DESCRIPTION("bcm4359_bluetooth"); +MODULE_LICENSE("GPL"); diff --git a/drivers/bts/bts-exynos7420.c b/drivers/bts/bts-exynos7420.c index 2caa7cf30820..a210a39571b8 100644 --- a/drivers/bts/bts-exynos7420.c +++ b/drivers/bts/bts-exynos7420.c @@ -365,7 +365,7 @@ static struct bts_info exynos7_bts[] = { .pd_name = "fsys0", .table[BS_DEFAULT].fn = BF_SETQOS_MO, .table[BS_DEFAULT].priority = 0x44444444, - .table[BS_DEFAULT].mo = 1, + .table[BS_DEFAULT].mo = 1, .cur_scen = BS_DISABLE, .on = false, .enable = true, @@ -385,10 +385,12 @@ static struct bts_info exynos7_bts[] = { .name = "wifi1", .pa_base = EXYNOS7420_PA_BTS_WIFI1, .pd_name = "fsys1", - .table[BS_DEFAULT].fn = BF_NOP, + .table[BS_DEFAULT].fn = BF_SETQOS_MO, + .table[BS_DEFAULT].priority = 0x44444444, + .table[BS_DEFAULT].mo = 1, .cur_scen = BS_DISABLE, .on = false, - .enable = false, + .enable = true, }, [BTS_IDX_EMBEDDED] = { .id = BTS_EMBEDDED, diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 1f33720f4aa6..607f1e5508ec 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -122,7 +122,7 @@ static void create_dci_event_mask_tbl(unsigned char *tbl_buf) memset(tbl_buf, 0, DCI_EVENT_MASK_SIZE); } -static void dci_drain_data(unsigned long data) +void dci_drain_data(unsigned long data) { queue_work(driver->diag_dci_wq, &dci_data_drain_work); } @@ -131,7 +131,7 @@ static void dci_check_drain_timer(void) { if (!dci_timer_in_progress) { dci_timer_in_progress = 1; - mod_timer(&dci_drain_timer, jiffies + msecs_to_jiffies(500)); + mod_timer(&dci_drain_timer, jiffies + msecs_to_jiffies(500)); } } @@ -183,7 +183,7 @@ static inline int diag_dci_check_buffer(struct diag_dci_buffer_t *buf, int len) } static void dci_add_buffer_to_list(struct diag_dci_client_tbl *client, - struct diag_dci_buffer_t *buf) + struct diag_dci_buffer_t *buf, const char *str) { if (!buf || !client || !buf->data) return; @@ -192,6 +192,8 @@ static void dci_add_buffer_to_list(struct diag_dci_client_tbl *client, return; mutex_lock(&client->write_buf_mutex); + pr_err("diag: addding to list, called from %s, buf: %p buf_track: %p, HEAD: %p\n", + str, buf, &buf->buf_track, &client->list_write_buf); list_add_tail(&buf->buf_track, &client->list_write_buf); /* * In the case of DCI, there can be multiple packets in one read. To @@ -224,7 +226,7 @@ static int diag_dci_get_buffer(struct diag_dci_client_tbl *client, if (curr && diag_dci_check_buffer(curr, len) == 1) return 0; - dci_add_buffer_to_list(client, curr); + dci_add_buffer_to_list(client, curr,__func__); client->buffers[data_source].buf_curr = NULL; if (diag_dci_check_buffer(buf_primary, len) == 1) { @@ -288,21 +290,21 @@ void dci_data_drain_work_fn(struct work_struct *work) for (i = 0; i < entry->num_buffers; i++) { proc_buf = &entry->buffers[i]; + mutex_lock(&proc_buf->buf_mutex); buf_temp = proc_buf->buf_primary; if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp)) - dci_add_buffer_to_list(entry, buf_temp); + dci_add_buffer_to_list(entry, buf_temp,__func__); buf_temp = proc_buf->buf_cmd; if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp)) - dci_add_buffer_to_list(entry, buf_temp); + dci_add_buffer_to_list(entry, buf_temp, __func__); buf_temp = proc_buf->buf_curr; if (DCI_CAN_ADD_BUF_TO_LIST(buf_temp)) { - dci_add_buffer_to_list(entry, buf_temp); - mutex_lock(&proc_buf->buf_mutex); + dci_add_buffer_to_list(entry, buf_temp, __func__); proc_buf->buf_curr = NULL; - mutex_unlock(&proc_buf->buf_mutex); } + mutex_unlock(&proc_buf->buf_mutex); } if (!list_empty(&entry->list_write_buf) && !entry->in_service) { mutex_lock(&entry->write_buf_mutex); @@ -647,8 +649,6 @@ static struct dci_pkt_req_entry_t *diag_register_dci_transaction(int uid, entry->client_id = client_id; entry->uid = uid; entry->tag = driver->dci_tag; - DIAG_LOG(DIAG_DEBUG_HIGH, "diag: Registering DCI cmd req, client_id: %d, uid: %d, tag:%d\n", - entry->client_id, entry->uid, entry->tag); list_add_tail(&entry->track, &driver->dci_req_list); driver->num_dci_cmd++; mutex_unlock(&driver->dci_mutex); @@ -856,6 +856,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, if (delete_flag < 0) return; + mutex_lock(&entry->buffers[data_source].buf_mutex); rsp_buf = entry->buffers[data_source].buf_cmd; mutex_lock(&rsp_buf->data_mutex); @@ -872,6 +873,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, if (!temp_buf) { pr_err("diag: DCI realloc failed\n"); mutex_unlock(&rsp_buf->data_mutex); + mutex_unlock(&entry->buffers[data_source].buf_mutex); return; } else { rsp_buf->data = temp_buf; @@ -910,7 +912,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, * userspace as these shouldn't be buffered and shouldn't wait * for log and event buffers to be full */ - dci_add_buffer_to_list(entry, rsp_buf); + dci_add_buffer_to_list(entry, rsp_buf, __func__); + mutex_unlock(&entry->buffers[data_source].buf_mutex); } static void copy_dci_event(unsigned char *buf, int len, diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index 85a449a27288..c0e94c9e7904 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -258,7 +258,7 @@ int diag_dci_set_real_time(struct diag_dci_client_tbl *entry, uint8_t real_time); int diag_dci_copy_health_stats(struct diag_dci_health_stats_proc *stats_proc); int diag_dci_write_proc(int peripheral, int pkt_type, char *buf, int len); - +void dci_drain_data(unsigned long data); #ifdef CONFIG_DIAGFWD_BRIDGE_CODE int diag_send_dci_log_mask_remote(int token); int diag_send_dci_event_mask_remote(int token); diff --git a/drivers/clk/samsung/clk-exynos7420.c b/drivers/clk/samsung/clk-exynos7420.c index 3dc042649362..66e78e9acb43 100644 --- a/drivers/clk/samsung/clk-exynos7420.c +++ b/drivers/clk/samsung/clk-exynos7420.c @@ -64,9 +64,15 @@ enum exynos7420_clks { um_decon1_vclk, m_decon1_vclk, d_decon1_vclk, aclk_lh_disp0 = 230, aclk_lh_disp1, aclk_disp, pclk_disp, rgb_vclk0, rgb_vclk1, mipi1_rx, mipi1_bit, +#ifdef CONFIG_EXYNOS_DUAL_DECON + mout_sclk_decon_int_eclk = 240, mout_bus0_pll_top0, dout_sclk_decon_int_eclk, + um_decon0_eclk, mout_sclk_decon_ext_eclk, dout_sclk_decon_ext_eclk, +#endif disp_last = 299, /* number for ccore 300 */ + aclk_lh_g3d0 = 300, aclk_lh_g3d1, + /* number for audio starts from 400 */ aclk_dmac = 400, aclk_sramc, aclk_audnp_133, aclk_acel_lh_async_si_top_133, aclk_smmu_aud, @@ -1010,10 +1016,18 @@ static struct samsung_composite_mux exynos7420_mux_clks[] __refdata = { MUX(none, "mout_aclk_mfc_532", topc_group1, \ EXYNOS7420_MUX_SEL_TOPC3, 8, 2, \ EXYNOS7420_MUX_STAT_TOPC3, 8, 4, 0, "mout_aclk_mfc_532"), +#ifdef CONFIG_EXYNOS_DUAL_DECON + /* top0 block */ + MUX(mout_bus0_pll_top0, "mout_bus0_pll_top0", mout_bus0_pll_top0_p, \ + EXYNOS7420_MUX_SEL_TOP01, 16, 1, \ + EXYNOS7420_MUX_STAT_TOP01, 16, 3, 0, "mout_bus0_pll_top0"), +#else /* top0 block */ MUX(none, "mout_bus0_pll_top0", mout_bus0_pll_top0_p, \ EXYNOS7420_MUX_SEL_TOP01, 16, 1, \ EXYNOS7420_MUX_STAT_TOP01, 16, 3, 0, "mout_bus0_pll_top0"), +#endif + MUX(none, "mout_bus1_pll_top0", mout_bus1_pll_top0_p, \ EXYNOS7420_MUX_SEL_TOP01, 12, 1, \ EXYNOS7420_MUX_STAT_TOP01, 12, 3, 0, "mout_bus1_pll_top0"), @@ -1115,12 +1129,21 @@ static struct samsung_composite_mux exynos7420_mux_clks[] __refdata = { MUX(none, "mout_sclk_uart3", top0_group1, \ EXYNOS7420_MUX_SEL_TOP0_PERIC3, 4, 2, \ EXYNOS7420_MUX_STAT_TOP0_PERIC3, 4, 4, 0, NULL), +#ifdef CONFIG_EXYNOS_DUAL_DECON + MUX(mout_sclk_decon_int_eclk, "mout_sclk_decon_int_eclk", top0_group1, \ + EXYNOS7420_MUX_SEL_TOP0_DISP, 28, 2, \ + EXYNOS7420_MUX_STAT_TOP0_DISP, 28, 4, 0, "m_sclk_decon0_eclk"), + MUX(mout_sclk_decon_ext_eclk, "mout_sclk_decon_ext_eclk", top0_group1, \ + EXYNOS7420_MUX_SEL_TOP0_DISP, 24, 2, \ + EXYNOS7420_MUX_STAT_TOP0_DISP, 24, 4, 0, NULL), +#else MUX(none, "mout_sclk_decon_int_eclk", top0_group1, \ EXYNOS7420_MUX_SEL_TOP0_DISP, 28, 2, \ EXYNOS7420_MUX_STAT_TOP0_DISP, 28, 4, 0, "m_sclk_decon0_eclk"), MUX(none, "mout_sclk_decon_ext_eclk", top0_group1, \ EXYNOS7420_MUX_SEL_TOP0_DISP, 24, 2, \ EXYNOS7420_MUX_STAT_TOP0_DISP, 24, 4, 0, NULL), +#endif MUX(none, "mout_sclk_decon_vclk", top0_group1, \ EXYNOS7420_MUX_SEL_TOP0_DISP, 20, 2, \ EXYNOS7420_MUX_STAT_TOP0_DISP, 20, 4, 0, NULL), @@ -1446,12 +1469,21 @@ static struct samsung_composite_divider exynos7420_div_clks[] __refdata = { DIV(baud3, "dout_sclk_uart3", "mout_sclk_uart3", \ EXYNOS7420_DIV_TOP0_PERIC3, 4, 4, \ EXYNOS7420_DIV_STAT_TOP0_PERIC3, 4, 1, 0, NULL), +#ifdef CONFIG_EXYNOS_DUAL_DECON + DIV(dout_sclk_decon_int_eclk, "dout_sclk_decon_int_eclk", "mout_sclk_decon_int_eclk", \ + EXYNOS7420_DIV_TOP0_DISP, 28, 4, \ + EXYNOS7420_DIV_STAT_TOP0_DISP, 28, 1, 0, "dout_sclk_decon_int_eclk"), + DIV(dout_sclk_decon_ext_eclk, "dout_sclk_decon_ext_eclk", "mout_sclk_decon_ext_eclk", \ + EXYNOS7420_DIV_TOP0_DISP, 24, 4, \ + EXYNOS7420_DIV_STAT_TOP0_DISP, 24, 1, 0, "dout_sclk_decon_ext_eclk"), +#else DIV(none, "dout_sclk_decon_int_eclk", "mout_sclk_decon_int_eclk", \ EXYNOS7420_DIV_TOP0_DISP, 28, 4, \ EXYNOS7420_DIV_STAT_TOP0_DISP, 28, 1, 0, "dout_sclk_decon_int_eclk"), DIV(none, "dout_sclk_decon_ext_eclk", "mout_sclk_decon_ext_eclk", \ EXYNOS7420_DIV_TOP0_DISP, 24, 4, \ EXYNOS7420_DIV_STAT_TOP0_DISP, 24, 1, 0, "dout_sclk_decon_ext_eclk"), +#endif DIV(none, "dout_sclk_decon_vclk", "mout_sclk_decon_vclk", \ EXYNOS7420_DIV_TOP0_DISP, 20, 4, \ EXYNOS7420_DIV_STAT_TOP0_DISP, 20, 1, 0, "dout_sclk_decon_vclk"), @@ -1792,9 +1824,15 @@ static struct samsung_usermux exynos7420_usermux_clks[] __initdata = { USERMUX(none, "usermux_sclk_dsd", "top_sclk_dsd", \ EXYNOS7420_MUX_SEL_DISP1, 16, \ EXYNOS7420_MUX_STAT_DISP1, 16, 0, NULL), +#ifdef CONFIG_EXYNOS_DUAL_DECON + USERMUX(um_decon0_eclk, "usermux_sclk_decon_int_eclk", "top_sclk_decon_int_eclk", \ + EXYNOS7420_MUX_SEL_DISP1, 28, \ + EXYNOS7420_MUX_STAT_DISP1, 28, 0, "um_decon0_eclk"), +#else USERMUX(none, "usermux_sclk_decon_int_eclk", "top_sclk_decon_int_eclk", \ EXYNOS7420_MUX_SEL_DISP1, 28, \ EXYNOS7420_MUX_STAT_DISP1, 28, 0, "um_decon0_eclk"), +#endif USERMUX(none, "usermux_sclk_decon_vclk", "top_sclk_decon_vclk", \ EXYNOS7420_MUX_SEL_DISP1, 20, \ EXYNOS7420_MUX_STAT_DISP1, 20, 0, NULL), @@ -2346,7 +2384,7 @@ static struct samsung_gate exynos7420_gate_clks[] __initdata = { GATE(pclk_spi3, "pclk_spi3", "usermux_aclk_peric1_66", \ EXYNOS7420_ENABLE_PCLK_PERIC1, 15, 0, NULL), GATE(pclk_spi4, "pclk_spi4", "usermux_aclk_peric1_66", \ - EXYNOS7420_ENABLE_PCLK_PERIC1, 16, 0, NULL), + EXYNOS7420_ENABLE_PCLK_PERIC1, 16, 0, "fp-spi-pclk"), GATE(pclk_spi5, "pclk_spi5", "usermux_aclk_peric1_66", \ EXYNOS7420_ENABLE_PCLK_PERIC1, 20, 0, NULL), GATE(pclk_i2s1, "pclk_i2s1", "usermux_aclk_peric1_66", \ @@ -2368,7 +2406,7 @@ static struct samsung_gate exynos7420_gate_clks[] __initdata = { GATE(sclk_spi3, "sclk_spi3", "usermux_sclk_spi3", \ EXYNOS7420_ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, NULL), GATE(sclk_spi4, "sclk_spi4", "usermux_sclk_spi4", \ - EXYNOS7420_ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, NULL), + EXYNOS7420_ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, "fp-spi-sclk"), GATE(sclk_spi5, "sclk_spi5", "usermux_sclk_spi5", \ EXYNOS7420_ENABLE_SCLK_PERIC10, 20, CLK_SET_RATE_PARENT, NULL), GATE(none, "sclk_spdif", "top_sclk_spdif", \ @@ -2737,6 +2775,10 @@ static struct samsung_gate exynos7420_gate_clks[] __initdata = { /* ccore */ GATE(none, "aclk_cci", "usermux_aclk_ccore_532", \ EXYNOS7420_ENABLE_ACLK_CCORE0, 0, CLK_GATE_ENABLE, NULL), + GATE(aclk_lh_g3d0, "aclk_lh_g3d0", "usermux_aclk_ccore_532", \ + EXYNOS7420_ENABLE_ACLK_CCORE0, 22, CLK_IGNORE_UNUSED, NULL), + GATE(aclk_lh_g3d1, "aclk_lh_g3d1", "usermux_aclk_ccore_532", \ + EXYNOS7420_ENABLE_ACLK_CCORE0, 23, CLK_IGNORE_UNUSED, NULL), GATE(rtc, "pclk_rtc", "usermux_aclk_ccore_133", \ EXYNOS7420_ENABLE_PCLK_CCORE, 8, 0, NULL), GATE(none, "aclk_noc_p_ccore", "usermux_aclk_ccore_133", \ diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 7d03d238b6bc..db78dd47ec74 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -106,8 +106,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset) __raw_writel(value, reg_base + offset); if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { - stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; - switch (offset & EXYNOS4_MCT_L_MASK) { + stat_addr = (offset & EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; + switch (offset & ~EXYNOS4_MCT_L_MASK) { case MCT_L_TCON_OFFSET: mask = 1 << 3; /* L_TCON write status */ break; diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index e3054557a707..0407f8824522 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -201,3 +201,9 @@ config ARM_SPEAR_CPUFREQ default y help This adds the CPUFreq driver support for SPEAr SOCs. + +config PMU_COREMEM_RATIO + bool "support coremem ratio by pmu count" + depends on ARCH_EXYNOS + help + This supports coremem ratio region by pmu count diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index e57698c7f154..26a557163510 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARCH_TEGRA) += tegra-cpufreq.o +obj-$(CONFIG_PMU_COREMEM_RATIO) += pmu_count.o coremem_ratio.o ################################################################################## # PowerPC platform drivers diff --git a/drivers/cpufreq/coremem_ratio.c b/drivers/cpufreq/coremem_ratio.c new file mode 100644 index 000000000000..fc51fef87554 --- /dev/null +++ b/drivers/cpufreq/coremem_ratio.c @@ -0,0 +1,98 @@ +/* linux/drivers/cpufreq/coremem_ratio.c + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CPU Support + * + * 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. + */ + +#include +#include +#include +#include "pmu_func.h" + +#define SHIFT_LF 20 + +#define LPKI_COND_CM_100_000 0 // INT(L2M*(1< #endif #include "cpu_load_metric.h" +#ifdef CONFIG_PMU_COREMEM_RATIO +#include "pmu_func.h" +#endif #define CREATE_TRACE_POINTS #include @@ -66,6 +69,10 @@ struct cpufreq_interactive_cpuinfo { u64 hispeed_validate_time; struct rw_semaphore enable_sem; int governor_enabled; +#ifdef CONFIG_PMU_COREMEM_RATIO + int region; + int prev_region; +#endif }; static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); @@ -73,6 +80,10 @@ static DEFINE_PER_CPU(struct cpufreq_interactive_cpuinfo, cpuinfo); static cpumask_t speedchange_cpumask; static spinlock_t speedchange_cpumask_lock; static struct mutex gov_lock; +#ifdef CONFIG_PMU_COREMEM_RATIO +static cpumask_t regionchange_cpumask; +static spinlock_t regionchange_cpumask_lock; +#endif /* Target load. Lower values result in higher CPU speeds. */ #define DEFAULT_TARGET_LOAD 90 @@ -169,6 +180,13 @@ struct cpufreq_interactive_tunables { #define TASK_NAME_LEN 15 /* realtime thread handles frequency scaling */ struct task_struct *speedchange_task; +#ifdef CONFIG_PMU_COREMEM_RATIO + struct task_struct *regionchange_task; + unsigned int prev_max_region; + unsigned int max_region; + u64 region_time_in_state[6]; + u64 region_last_stat; +#endif /* handle for get cpufreq_policy */ unsigned int *policy; @@ -268,7 +286,11 @@ static void cpufreq_interactive_timer_resched( unsigned long expires; unsigned long flags; +#ifdef CONFIG_PMU_COREMEM_RATIO + if (!tunables->speedchange_task || !tunables->regionchange_task) +#else if (!tunables->speedchange_task) +#endif return; spin_lock_irqsave(&pcpu->load_lock, flags); @@ -302,7 +324,11 @@ static void cpufreq_interactive_timer_start( usecs_to_jiffies(tunables->timer_rate); unsigned long flags; +#ifdef CONFIG_PMU_COREMEM_RATIO + if (!tunables->speedchange_task || !tunables->regionchange_task) +#else if (!tunables->speedchange_task) +#endif return; pcpu->cpu_timer.expires = expires; @@ -650,6 +676,10 @@ static void cpufreq_interactive_timer(unsigned long data) bool boosted; #ifdef CONFIG_MODE_AUTO_CHANGE unsigned int new_mode; +#endif +#ifdef CONFIG_PMU_COREMEM_RATIO + struct pmu_count_value pmu_data; + int region = 0; #endif if (!down_read_trylock(&pcpu->enable_sem)) return; @@ -686,6 +716,24 @@ static void cpufreq_interactive_timer(unsigned long data) cpu_load = loadadjfreq / pcpu->target_freq; boosted = tunables->boost_val || now < tunables->boostpulse_endtime; +#ifdef CONFIG_PMU_COREMEM_RATIO + /* Get crypto load information from PMU */ + pmu_data.core_num = data; + pmu_data.valid = 0; + + read_pmu_one(&pmu_data); + + pcpu->prev_region = pcpu->region; + region = coremem_ratio(pmu_data.pmnc1, pmu_data.pmnc2); + if (region != pcpu->prev_region) { + pcpu->region = region; + spin_lock_irqsave(®ionchange_cpumask_lock, flags); + cpumask_set_cpu(data, ®ionchange_cpumask); + spin_unlock_irqrestore(®ionchange_cpumask_lock, flags); + wake_up_process(tunables->regionchange_task); + } +#endif + if (cpu_load >= tunables->go_hispeed_load || boosted) { if (pcpu->target_freq < tunables->hispeed_freq) { new_freq = tunables->hispeed_freq; @@ -847,6 +895,88 @@ static void cpufreq_interactive_idle_end(void) up_read(&pcpu->enable_sem); } +#ifdef CONFIG_PMU_COREMEM_RATIO +static void region_update_status(struct cpufreq_interactive_tunables *tunables) +{ + unsigned long cur_time; + + cur_time = jiffies; + tunables->region_time_in_state[tunables->prev_max_region] += + cur_time - tunables->region_last_stat; + tunables->region_last_stat = cur_time; +} + +static int cpufreq_interactive_regionchange_task(void *data) +{ + unsigned int cpu; + cpumask_t tmp_mask; + cpumask_t policy_mask; + unsigned long flags; + struct cpufreq_interactive_cpuinfo *pcpu; + + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(®ionchange_cpumask_lock, flags); + + pcpu = &per_cpu(cpuinfo, smp_processor_id()); + cpumask_and(&policy_mask, ®ionchange_cpumask, pcpu->policy->related_cpus); + if (cpumask_empty(&policy_mask)) { + spin_unlock_irqrestore(®ionchange_cpumask_lock, flags); + + if (kthread_should_stop()) + break; + + schedule(); + + if (kthread_should_stop()) + break; + + spin_lock_irqsave(®ionchange_cpumask_lock, flags); + } + + set_current_state(TASK_RUNNING); + cpumask_and(&tmp_mask, ®ionchange_cpumask, pcpu->policy->related_cpus); + cpumask_andnot(®ionchange_cpumask, ®ionchange_cpumask, pcpu->policy->related_cpus); + spin_unlock_irqrestore(®ionchange_cpumask_lock, flags); + + for_each_cpu(cpu, &tmp_mask) { + unsigned int j; + unsigned int max_region = 0; + struct cpufreq_interactive_tunables *tunables; + + pcpu = &per_cpu(cpuinfo, cpu); + tunables = pcpu->policy->governor_data; + + if (!down_read_trylock(&pcpu->enable_sem)) + continue; + if (!pcpu->governor_enabled) { + up_read(&pcpu->enable_sem); + continue; + } + + tunables->prev_max_region = tunables->max_region; + for_each_cpu(j, pcpu->policy->cpus) { + struct cpufreq_interactive_cpuinfo *pjcpu = + &per_cpu(cpuinfo, j); + + if (pjcpu->region > max_region) + max_region = pjcpu->region; + } + + if (tunables->prev_max_region != max_region) { + tunables->max_region = max_region; + coremem_region_bus_lock(max_region, pcpu->policy); + region_update_status(tunables); + } + + up_read(&pcpu->enable_sem); + } + } + + return 0; +} +#endif + static int cpufreq_interactive_speedchange_task(void *data) { unsigned int cpu; @@ -1727,6 +1857,22 @@ static ssize_t store_multi_cluster0_min_freq(struct cpufreq_interactive_tunables return count; } #endif +#ifdef CONFIG_PMU_COREMEM_RATIO +static ssize_t show_region_time_in_state(struct cpufreq_interactive_tunables *tunables, + char *buf) +{ + int i; + ssize_t len = 0; + + region_update_status(tunables); + + for (i = 0; i < 6; i++) + len += snprintf(buf + len, PAGE_SIZE, "region %2d: %20llu\n", + i, tunables->region_time_in_state[i]); + + return len; +} +#endif /* * Create show/store routines * - sys: One governor instance for complete SYSTEM @@ -1774,6 +1920,7 @@ show_store_gov_pol_sys(boost); store_gov_pol_sys(boostpulse); show_store_gov_pol_sys(boostpulse_duration); show_store_gov_pol_sys(io_is_busy); + #ifdef CONFIG_MODE_AUTO_CHANGE show_store_gov_pol_sys(mode); show_store_gov_pol_sys(enforced_mode); @@ -1790,6 +1937,9 @@ show_store_gov_pol_sys(single_cluster0_min_freq); show_store_gov_pol_sys(multi_cluster0_min_freq); show_gov_pol_sys(cpu_util); #endif +#ifdef CONFIG_PMU_COREMEM_RATIO +show_gov_pol_sys(region_time_in_state); +#endif #define gov_sys_attr_rw(_name) \ static struct global_attr _name##_gov_sys = \ __ATTR(_name, 0660, show_##_name##_gov_sys, store_##_name##_gov_sys) @@ -1840,6 +1990,14 @@ static struct global_attr cpu_util_gov_sys = static struct freq_attr cpu_util_gov_pol = __ATTR(cpu_util, 0444, show_cpu_util_gov_pol, NULL); #endif +#ifdef CONFIG_PMU_COREMEM_RATIO +static struct global_attr region_time_in_state_gov_sys = + __ATTR(region_time_in_state, 0440, show_region_time_in_state_gov_sys, NULL); + +static struct freq_attr region_time_in_state_gov_pol = + __ATTR(region_time_in_state, 0440, show_region_time_in_state_gov_pol, NULL); +#endif + /* One Governor instance for entire system */ static struct attribute *interactive_attributes_gov_sys[] = { &target_loads_gov_sys.attr, @@ -1868,6 +2026,9 @@ static struct attribute *interactive_attributes_gov_sys[] = { &single_cluster0_min_freq_gov_sys.attr, &multi_cluster0_min_freq_gov_sys.attr, &cpu_util_gov_sys.attr, +#endif +#ifdef CONFIG_PMU_COREMEM_RATIO + ®ion_time_in_state_gov_sys.attr, #endif NULL, }; @@ -1905,6 +2066,9 @@ static struct attribute *interactive_attributes_gov_pol[] = { &single_cluster0_min_freq_gov_pol.attr, &multi_cluster0_min_freq_gov_pol.attr, &cpu_util_gov_pol.attr, +#endif +#ifdef CONFIG_PMU_COREMEM_RATIO + ®ion_time_in_state_gov_pol.attr, #endif NULL, }; @@ -1943,6 +2107,9 @@ static const char *interactive_sysfs[] = { "multi_cluster0_min_freq", "cpu_util", #endif +#ifdef CONFIG_PMU_COREMEM_RATIO + "region_time_in_state", +#endif }; #endif @@ -1954,16 +2121,46 @@ static struct attribute_group *get_sysfs_attr(void) return &interactive_attr_group_gov_sys; } +#ifdef CONFIG_PMU_COREMEM_RATIO +void pmu_suspend_cpu(int cpu) +{ + int ret; + + ret = stop_counter_cpu(cpu); + if (ret) + pr_err("%s: Fail to stop counter. cpu: %d\n", __func__, cpu); +} + +void pmu_resume_cpu(int cpu) +{ + int ret; + + ret = start_counter_cpu(cpu); + if (ret) + pr_err("%s: Fail to start counter. cpu: %d\n", __func__, cpu); +} +#endif + static int cpufreq_interactive_idle_notifier(struct notifier_block *nb, unsigned long val, void *data) { +#ifdef CONFIG_PMU_COREMEM_RATIO + int cpu = smp_processor_id(); +#endif + switch (val) { case IDLE_START: cpufreq_interactive_idle_start(); +#ifdef CONFIG_PMU_COREMEM_RATIO + pmu_suspend_cpu(cpu); +#endif break; case IDLE_END: cpufreq_interactive_idle_end(); +#ifdef CONFIG_PMU_COREMEM_RATIO + pmu_resume_cpu(cpu); +#endif break; } @@ -1974,6 +2171,29 @@ static struct notifier_block cpufreq_interactive_idle_nb = { .notifier_call = cpufreq_interactive_idle_notifier, }; +#ifdef CONFIG_PMU_COREMEM_RATIO +static int __cpuinit exynos_pmu_cpu_notifier(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + int cpu = (unsigned long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_STARTING: + case CPU_DOWN_FAILED: + pmu_resume_cpu(cpu); + break; + case CPU_DYING: + pmu_suspend_cpu(cpu); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata exynos_pmu_cpu_notifier_block = { + .notifier_call = exynos_pmu_cpu_notifier, +}; +#endif + #ifdef CONFIG_ANDROID static void change_sysfs_owner(struct cpufreq_policy *policy) { @@ -2031,6 +2251,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; char speedchange_task_name[TASK_NAME_LEN]; unsigned long flags; +#ifdef CONFIG_PMU_COREMEM_RATIO + char regionchange_task_name[TASK_NAME_LEN]; +#endif if (have_governor_per_policy()) tunables = policy->governor_data; @@ -2079,6 +2302,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, tunables->multi_cluster0_min_freq = DEFAULT_MULTI_CLUSTER0_MIN_FREQ; cpufreq_param_set_init(tunables); +#endif +#ifdef CONFIG_PMU_COREMEM_RATIO + tunables->region_last_stat = jiffies; #endif } else { memcpy(tunables, tuned_parameters[policy->cpu], sizeof(*tunables)); @@ -2114,6 +2340,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, if (!policy->governor->initialized) { idle_notifier_register(&cpufreq_interactive_idle_nb); +#ifdef CONFIG_PMU_COREMEM_RATIO + register_cpu_notifier(&exynos_pmu_cpu_notifier_block); +#endif cpufreq_register_notifier(&cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } @@ -2125,6 +2354,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, if (policy->governor->initialized == 1) { cpufreq_unregister_notifier(&cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +#ifdef CONFIG_PMU_COREMEM_RATIO + unregister_cpu_notifier(&exynos_pmu_cpu_notifier_block); +#endif idle_notifier_unregister(&cpufreq_interactive_idle_nb); } @@ -2190,12 +2422,35 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, sched_setscheduler_nocheck(tunables->speedchange_task, SCHED_FIFO, ¶m); get_task_struct(tunables->speedchange_task); +#ifdef CONFIG_PMU_COREMEM_RATIO + snprintf(regionchange_task_name, TASK_NAME_LEN, "region%d", + policy->cpu); + + tunables->regionchange_task = + kthread_create(cpufreq_interactive_regionchange_task, NULL, + regionchange_task_name); + if (IS_ERR(tunables->regionchange_task)) { + kthread_stop(tunables->regionchange_task); + mutex_unlock(&gov_lock); + return PTR_ERR(tunables->regionchange_task); + } + + sched_setscheduler_nocheck(tunables->regionchange_task, SCHED_FIFO, ¶m); + get_task_struct(tunables->regionchange_task); +#endif + #if defined(CONFIG_ARM_EXYNOS_MP_CPUFREQ) || defined(CONFIG_ARM_EXYNOS_SMP_CPUFREQ) kthread_bind(tunables->speedchange_task, policy->cpu); +#ifdef CONFIG_PMU_COREMEM_RATIO + kthread_bind(tunables->regionchange_task, policy->cpu); +#endif #endif /* NB: wake up so the thread does not look hung to the freezer */ wake_up_process(tunables->speedchange_task); +#ifdef CONFIG_PMU_COREMEM_RATIO + wake_up_process(tunables->regionchange_task); +#endif mutex_unlock(&gov_lock); break; @@ -2215,6 +2470,12 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, put_task_struct(tunables->speedchange_task); tunables->speedchange_task = NULL; +#ifdef CONFIG_PMU_COREMEM_RATIO + kthread_stop(tunables->regionchange_task); + put_task_struct(tunables->regionchange_task); + tunables->regionchange_task = NULL; +#endif + mutex_unlock(&gov_lock); break; @@ -2513,6 +2774,9 @@ static int __init cpufreq_interactive_init(void) } spin_lock_init(&speedchange_cpumask_lock); +#ifdef CONFIG_PMU_COREMEM_RATIO + spin_lock_init(®ionchange_cpumask_lock); +#endif mutex_init(&gov_lock); #ifdef CONFIG_ARCH_EXYNOS diff --git a/drivers/cpufreq/dm_cpu_hotplug.c b/drivers/cpufreq/dm_cpu_hotplug.c index f12fe4d3a02f..f0d2e7d57863 100644 --- a/drivers/cpufreq/dm_cpu_hotplug.c +++ b/drivers/cpufreq/dm_cpu_hotplug.c @@ -80,6 +80,7 @@ static unsigned int cluster1_min_freq; static unsigned int cluster0_max_freq; #endif int disable_dm_hotplug_before_suspend = 0; +int nr_sleep_prepare_cpus = CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG_SLEEP_PREPARE; enum hotplug_cmd { CMD_NORMAL, @@ -89,6 +90,7 @@ enum hotplug_cmd { CMD_CLUST0_IN, CMD_CLUST0_ONE_IN, CMD_CLUST0_ONE_OUT, + CMD_SLEEP_PREPARE, }; static int on_run(void *data); @@ -496,7 +498,23 @@ static int __ref __cpu_hotplug(bool out_flag, enum hotplug_cmd cmd) if (do_disable_hotplug) goto blk_out; - if (cmd == CMD_CLUST1_OUT && !in_low_power_mode) { + if (cmd == CMD_SLEEP_PREPARE) { + for (i = setup_max_cpus - 1; i >= NR_CLUST0_CPUS; i--) { + if (cpu_online(i)) { + ret = cpu_down(i); + if (ret) + goto blk_out; + } + } + for (i = 1; i < nr_sleep_prepare_cpus; i++) { + if (!cpu_online(i)) { + ret = cpu_up(i); + if (ret) + goto blk_out; + } + } + } + else if (cmd == CMD_CLUST1_OUT && !in_low_power_mode) { for (i = setup_max_cpus - 1; i >= NR_CLUST0_CPUS; i--) { if (cpu_online(i)) { ret = cpu_down(i); @@ -644,6 +662,7 @@ static int dynamic_hotplug(enum hotplug_cmd cmd) break; case CMD_CLUST0_ONE_OUT: case CMD_CLUST1_OUT: + case CMD_SLEEP_PREPARE: ret = __cpu_hotplug(true, cmd); break; case CMD_CLUST0_ONE_IN: @@ -794,8 +813,15 @@ static int exynos_dm_hotplug_notifier(struct notifier_block *notifier, case PM_SUSPEND_PREPARE: mutex_lock(&thread_lock); in_suspend_prepared = true; - if (!dynamic_hotplug(CMD_LOW_POWER)) - prev_cmd = CMD_LOW_POWER; + if(nr_sleep_prepare_cpus > 1) { + pr_info("%s, %d : dynamic_hotplug CMD_SLEEP_PREPARE\n", __func__, __LINE__); + if (!dynamic_hotplug(CMD_SLEEP_PREPARE)) + prev_cmd = CMD_LOW_POWER; + } + else { + if (!dynamic_hotplug(CMD_LOW_POWER)) + prev_cmd = CMD_LOW_POWER; + } exynos_dm_hotplug_disable(); if (dm_hotplug_task) { kthread_stop(dm_hotplug_task); diff --git a/drivers/cpufreq/exynos-mp-cpufreq.c b/drivers/cpufreq/exynos-mp-cpufreq.c index db87f1084dd4..316111b45e12 100644 --- a/drivers/cpufreq/exynos-mp-cpufreq.c +++ b/drivers/cpufreq/exynos-mp-cpufreq.c @@ -51,6 +51,11 @@ #include #endif #include +#ifdef CONFIG_PMU_COREMEM_RATIO +#include "pmu_func.h" +#endif + +#include #ifdef CONFIG_SOC_EXYNOS5422_REV_0 #define POWER_COEFF_15P 57 /* percore param */ @@ -123,12 +128,16 @@ static struct pm_qos_request core_min_qos[CL_END]; static struct pm_qos_request core_max_qos[CL_END]; static struct pm_qos_request core_min_qos_real[CL_END]; static struct pm_qos_request core_max_qos_real[CL_END]; -static struct pm_qos_request exynos_mif_qos[CL_END]; static struct pm_qos_request ipa_max_qos[CL_END]; static struct pm_qos_request reboot_max_qos[CL_END]; #ifdef CONFIG_SEC_PM static struct pm_qos_request jig_boot_max_qos[CL_END]; #endif +#if defined(CONFIG_PMU_COREMEM_RATIO) +static struct pm_qos_request exynos_region_mif_qos[CL_END]; +#else +static struct pm_qos_request exynos_mif_qos[CL_END]; +#endif static struct workqueue_struct *cluster_monitor_wq; static struct delayed_work monitor_cluster_on; @@ -240,6 +249,29 @@ static void cluster_onoff_monitor(struct work_struct *work) if (exynos_info[cl]->is_alive) cluster_on[cl] = exynos_info[cl]->is_alive(); +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (exynos_info[cl]->region_bus_table && exynos_info[cl]->is_alive) { + if (!exynos_info[cl]->is_alive() && cluster_status[cl]) { + pm_qos_update_request(&exynos_region_mif_qos[cl], 0); + cluster_status[cl] = false; + } else if (exynos_info[cl]->is_alive() && !cluster_status[cl]) { + freq_table = exynos_info[cl]->freq_table; + for (i = 0; (freq_table[i].frequency != CPUFREQ_TABLE_END); i++) { + freq = freq_table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + if (freqs[cl]->old == freq) { + old_index = i; + break; + } + } + + pm_qos_update_request(&exynos_region_mif_qos[cl], + exynos_info[cl]->region_bus_table[old_index][exynos_info[cl]->region]); + cluster_status[cl] = true; + } + } +#else if (exynos_info[cl]->bus_table && exynos_info[cl]->is_alive) { if (!exynos_info[cl]->is_alive() && cluster_status[cl]) { pm_qos_update_request(&exynos_mif_qos[cl], 0); @@ -261,6 +293,7 @@ static void cluster_onoff_monitor(struct work_struct *work) cluster_status[cl] = true; } } +#endif } queue_delayed_work_on(0, cluster_monitor_wq, &monitor_cluster_on, msecs_to_jiffies(100)); @@ -513,18 +546,32 @@ static int exynos_cpufreq_scale(unsigned int target_freq, exynos_info[cur]->set_ema(safe_volt); } + exynos7_devfreq_mif_thermal_set_polling_period(target_freq, cur, exynos_info[CL_ONE]->is_alive()); + if (old_index > new_index) { +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (pm_qos_request_active(&exynos_region_mif_qos[cur])) + pm_qos_update_request(&exynos_region_mif_qos[cur], + exynos_info[cur]->region_bus_table[new_index][exynos_info[cur]->region]); +#else if (pm_qos_request_active(&exynos_mif_qos[cur])) pm_qos_update_request(&exynos_mif_qos[cur], exynos_info[cur]->bus_table[new_index]); +#endif } exynos_info[cur]->set_freq(old_index, new_index); if (old_index < new_index) { +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (pm_qos_request_active(&exynos_region_mif_qos[cur])) + pm_qos_update_request(&exynos_region_mif_qos[cur], + exynos_info[cur]->region_bus_table[new_index][exynos_info[cur]->region]); +#else if (pm_qos_request_active(&exynos_mif_qos[cur])) pm_qos_update_request(&exynos_mif_qos[cur], exynos_info[cur]->bus_table[new_index]); +#endif } #ifdef CONFIG_SMP @@ -572,6 +619,32 @@ static int exynos_cpufreq_scale(unsigned int target_freq, return ret; } +#ifdef CONFIG_PMU_COREMEM_RATIO +void coremem_region_bus_lock(int region, struct cpufreq_policy *policy) +{ + unsigned int cur = get_cur_cluster(policy->cpu); + unsigned int index; + + if (region > REGION_C020_M080_C000_M100) + return; + + exynos_info[cur]->region = region; + + if (exynos5_frequency_table_target(policy, exynos_info[cur]->freq_table, + policy->cur, CPUFREQ_RELATION_L, &index)) + return; + + if (exynos_info[cur]->region_bus_table) { + if (pm_qos_request_active(&exynos_region_mif_qos[cur])) + pm_qos_update_request(&exynos_region_mif_qos[cur], + exynos_info[cur]->region_bus_table[index][exynos_info[cur]->region]); + } + + pr_debug("cur:%u, region:%u, index:%u, mif_lock:%u\n", cur, region, index, + exynos_info[cur]->region_bus_table[index][exynos_info[cur]->region]); +} +#endif + void exynos_set_max_freq(int max_freq, unsigned int cpu) { cluster_type cluster = get_cur_cluster(cpu); @@ -1345,6 +1418,34 @@ inline ssize_t store_core_freq(const char *buf, size_t count, return count; } +inline ssize_t set_boot_low_freq(const char *buf, size_t count) +{ + int input; + unsigned int set_freq = 0; + + if (!sscanf(buf, "%8d", &input)) + return -EINVAL; + + if (exynos_info[CL_ONE]->low_boot_cpu_max_qos) + set_freq = exynos_info[CL_ONE]->low_boot_cpu_max_qos; + else + set_freq = PM_QOS_DEFAULT_VALUE; + + if (input) { + /* only big core limit, default 1800s */ + pr_info("%s: low boot freq[%d], cl[%d]\n", __func__, + set_freq, CL_ONE); + pm_qos_update_request_timeout(&boot_max_qos[CL_ONE], + set_freq, 1800 * USEC_PER_SEC); + } else { + pr_info("%s: release low boot freq\n", __func__); + pm_qos_update_request(&boot_max_qos[CL_ONE], + PM_QOS_DEFAULT_VALUE); + } + + return count; +} + static size_t get_freq_table_size(struct cpufreq_frequency_table *freq_table) { size_t tbl_sz = 0; @@ -1496,6 +1597,12 @@ static ssize_t show_cluster0_max_freq(struct kobject *kobj, return show_core_freq(buf, CL_ZERO, true); } +static ssize_t show_boot_low_freq(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return 0; +} + static ssize_t store_cluster0_min_freq(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { @@ -1508,6 +1615,12 @@ static ssize_t store_cluster0_max_freq(struct kobject *kobj, struct attribute *a return store_core_freq(buf, count, CL_ZERO, true); } +static ssize_t store_boot_low_freq(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) +{ + return set_boot_low_freq(buf, count); +} + static ssize_t show_cluster0_volt_table(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -1528,6 +1641,7 @@ define_one_global_ro(cluster0_freq_table); define_one_global_rw(cluster0_min_freq); define_one_global_rw(cluster0_max_freq); define_one_global_rw(cluster0_volt_table); +define_one_global_rw(boot_low_freq); static struct attribute *mp_attributes[] = { &cluster1_freq_table.attr, @@ -1538,6 +1652,7 @@ static struct attribute *mp_attributes[] = { &cluster0_min_freq.attr, &cluster0_max_freq.attr, &cluster0_volt_table.attr, + &boot_low_freq.attr, NULL }; @@ -2005,8 +2120,13 @@ static int __init exynos_cpufreq_init(void) exynos_info[cluster]->boot_cpu_max_qos_timeout); } +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (exynos_info[cluster]->region_bus_table) + pm_qos_add_request(&exynos_region_mif_qos[cluster], PM_QOS_BUS_THROUGHPUT, 0); +#else if (exynos_info[cluster]->bus_table) pm_qos_add_request(&exynos_mif_qos[cluster], PM_QOS_BUS_THROUGHPUT, 0); +#endif } /* unblock frequency scale */ @@ -2064,7 +2184,11 @@ static int __init exynos_cpufreq_init(void) } #endif +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (exynos_info[CL_ZERO]->region_bus_table || exynos_info[CL_ONE]->region_bus_table) { +#else if (exynos_info[CL_ZERO]->bus_table || exynos_info[CL_ONE]->bus_table) { +#endif INIT_DELAYED_WORK(&monitor_cluster_on, cluster_onoff_monitor); cluster_monitor_wq = create_workqueue("cluster_monitor"); @@ -2096,9 +2220,15 @@ static int __init exynos_cpufreq_init(void) err_mp_attr: for (cluster = 0; cluster < CL_END; cluster++) { if (exynos_info[cluster]) { +#if defined(CONFIG_PMU_COREMEM_RATIO) + if (exynos_info[cluster]->region_bus_table && + pm_qos_request_active(&exynos_region_mif_qos[cluster])) + pm_qos_remove_request(&exynos_region_mif_qos[cluster]); +#else if (exynos_info[cluster]->bus_table && pm_qos_request_active(&exynos_mif_qos[cluster])) pm_qos_remove_request(&exynos_mif_qos[cluster]); +#endif if (pm_qos_request_active(&boot_max_qos[cluster])) pm_qos_remove_request(&boot_max_qos[cluster]); diff --git a/drivers/cpufreq/exynos7420-apollo-cpufreq.c b/drivers/cpufreq/exynos7420-apollo-cpufreq.c index 746c211ca427..4ebc816c94cf 100644 --- a/drivers/cpufreq/exynos7420-apollo-cpufreq.c +++ b/drivers/cpufreq/exynos7420-apollo-cpufreq.c @@ -118,6 +118,29 @@ static const unsigned int asv_voltage_7420_CA53[CPUFREQ_LEVEL_END_CA53] = { }; /* Minimum memory throughput in megabytes per second */ +#if defined(CONFIG_PMU_COREMEM_RATIO) +static int exynos7420_region_bus_table_CA53[CPUFREQ_LEVEL_END_CA53][6] = { + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 2.0 GHz */ + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 1.9 GHz */ + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 1.8 GHz */ + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 1.7 GHz */ + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 1.6 GHz */ + { 0, 828000, 828000, 828000, 1264000, 1264000 }, /* 1.5 GHz */ + { 0, 632000, 632000, 828000, 1264000, 1264000 }, /* 1.4 GHz */ + { 0, 543000, 632000, 828000, 1026000, 1264000 }, /* 1.3 GHz */ + { 0, 543000, 632000, 828000, 1026000, 1264000 }, /* 1.2 GHz */ + { 0, 543000, 632000, 828000, 828000, 1026000 }, /* 1.1 GHz */ + { 0, 416000, 632000, 828000, 828000, 1026000 }, /* 1.0 GHz */ + { 0, 348000, 543000, 632000, 828000, 1026000 }, /* 900 MHz */ + { 0, 348000, 543000, 632000, 828000, 1026000 }, /* 800 MHz */ + { 0, 276000, 416000, 632000, 828000, 1026000 }, /* 700 MHz */ + { 0, 167000, 348000, 543000, 632000, 828000 }, /* 600 MHz */ + { 0, 133000, 276000, 543000, 543000, 828000 }, /* 500 MHz */ + { 0, 133000, 167000, 348000, 543000, 632000 }, /* 400 MHz */ + { 0, 100000, 167000, 348000, 543000, 543000 }, /* 300 MHz */ + { 0, 100000, 133000, 276000, 416000, 543000 }, /* 200 MHz */ +}; +#else static int exynos7420_bus_table_CA53[CPUFREQ_LEVEL_END_CA53] = { 1026000, /* 2.0 GHz */ 1026000, /* 1.9 GHz */ @@ -139,6 +162,7 @@ static int exynos7420_bus_table_CA53[CPUFREQ_LEVEL_END_CA53] = { 0, /* 300 MHz */ 0, /* 200 MHz */ }; +#endif static void exynos7420_set_clkdiv_CA53(unsigned int div_index) { @@ -346,7 +370,11 @@ int __init exynos_cpufreq_cluster0_init(struct exynos_dvfs_info *info) /* booting frequency is 1.4GHz */ info->boot_cpu_min_qos = exynos7420_freq_table_CA53[L6].frequency; info->boot_cpu_max_qos = exynos7420_freq_table_CA53[L6].frequency; - info->bus_table = exynos7420_bus_table_CA53; +#if defined(CONFIG_PMU_COREMEM_RATIO) + info->region_bus_table = exynos7420_region_bus_table_CA53; +#else + info->bus_table = exynos7420_bus_table_CA53; +#endif info->cpu_clk = mout_apollo_pll; info->volt_table = exynos7420_volt_table_CA53; diff --git a/drivers/cpufreq/exynos7420-atlas-cpufreq.c b/drivers/cpufreq/exynos7420-atlas-cpufreq.c index 322b0335789c..92ed14f5a41a 100644 --- a/drivers/cpufreq/exynos7420-atlas-cpufreq.c +++ b/drivers/cpufreq/exynos7420-atlas-cpufreq.c @@ -154,6 +154,34 @@ static const unsigned int asv_voltage_7420_CA57[CPUFREQ_LEVEL_END_CA57] = { }; /* minimum memory throughput in megabytes per second */ +#if defined(CONFIG_PMU_COREMEM_RATIO) +static int exynos7420_region_bus_table_CA57[CPUFREQ_LEVEL_END_CA57][6] = { + { 0, 1264000, 1264000, 1456000, 1456000, 1552000 }, /* 2.5 GHz */ + { 0, 1264000, 1264000, 1456000, 1456000, 1552000 }, /* 2.4 GHz */ + { 0, 1264000, 1264000, 1456000, 1456000, 1552000 }, /* 2.3 GHz */ + { 0, 1264000, 1264000, 1456000, 1456000, 1552000 }, /* 2.2 GHz */ + { 0, 1264000, 1264000, 1456000, 1456000, 1552000 }, /* 2.1 GHz */ + { 0, 1026000, 1026000, 1456000, 1456000, 1552000 }, /* 2.0 GHz */ + { 0, 1026000, 1026000, 1456000, 1456000, 1552000 }, /* 1.9 GHz */ + { 0, 1026000, 1026000, 1264000, 1456000, 1552000 }, /* 1.8 GHz */ + { 0, 828000, 1026000, 1264000, 1456000, 1552000 }, /* 1.7 MHz */ + { 0, 632000, 828000, 1264000, 1456000, 1552000 }, /* 1.6 GHz */ + { 0, 632000, 828000, 1264000, 1456000, 1552000 }, /* 1.5 GHz */ + { 0, 632000, 828000, 1264000, 1456000, 1552000 }, /* 1.4 GHz */ + { 0, 543000, 828000, 1264000, 1456000, 1552000 }, /* 1.3 GHz */ + { 0, 543000, 828000, 1026000, 1264000, 1456000 }, /* 1.2 GHz */ + { 0, 416000, 828000, 1026000, 1264000, 1456000 }, /* 1.1 GHz */ + { 0, 416000, 632000, 1026000, 1264000, 1456000 }, /* 1.0 GHz */ + { 0, 416000, 632000, 828000, 1026000, 1456000 }, /* 900 MHz */ + { 0, 416000, 632000, 828000, 1026000, 1264000 }, /* 800 MHz */ + { 0, 416000, 632000, 828000, 1026000, 1026000 }, /* 700 MHz */ + { 0, 348000, 632000, 632000, 828000, 1026000 }, /* 600 MHz */ + { 0, 276000, 543000, 632000, 828000, 828000 }, /* 500 MHz */ + { 0, 276000, 416000, 543000, 632000, 632000 }, /* 400 MHz */ + { 0, 0, 0, 0, 0, 0 }, /* 300 MHz */ + { 0, 0, 0, 0, 0, 0 }, /* 200 MHz */ +}; +#else static int exynos7420_bus_table_CA57[CPUFREQ_LEVEL_END_CA57] = { 1552000, /* 2.5 GHz */ 1552000, /* 2.4 GHz */ @@ -180,6 +208,7 @@ static int exynos7420_bus_table_CA57[CPUFREQ_LEVEL_END_CA57] = { 0, /* 300 MHz */ 0, /* 200 MHz */ }; +#endif static int exynos7420_cpufreq_smpl_warn_notifier_call( struct notifier_block *notifer, @@ -371,11 +400,11 @@ static bool exynos7420_is_alive_CA57(void) { unsigned int tmp; - tmp = __raw_readl(EXYNOS7420_ATLAS_PLL_CON1); - tmp &= EXYNOS7420_PLL_BYPASS_MASK; - tmp >>= EXYNOS7420_PLL_BYPASS_SHIFT; + tmp = __raw_readl(EXYNOS_PMU_ATLAS_L2_STATUS) & + __raw_readl(EXYNOS_PMU_ATLAS_NONCPU_STATUS) & + POWER_ON_STATUS; - return !tmp ? true : false; + return tmp ? true : false; } static void exynos7420_set_ema_CA57(unsigned int volt) @@ -433,8 +462,15 @@ int __init exynos_cpufreq_cluster1_init(struct exynos_dvfs_info *info) #ifdef CONFIG_SEC_PM /* booting max frequency is 1.5GHz when JIG cable is attached */ info->jig_boot_cpu_max_qos = exynos7420_freq_table_CA57[L10].frequency; + + /* This low freq used for FOTA(dex2oat) update */ + info->low_boot_cpu_max_qos = exynos7420_freq_table_CA57[L12].frequency; +#endif +#if defined(CONFIG_PMU_COREMEM_RATIO) + info->region_bus_table = exynos7420_region_bus_table_CA57; +#else + info->bus_table = exynos7420_bus_table_CA57; #endif - info->bus_table = exynos7420_bus_table_CA57; info->cpu_clk = mout_atlas_pll; /* reboot limit frequency is 800MHz */ diff --git a/drivers/cpufreq/pmu_count.c b/drivers/cpufreq/pmu_count.c new file mode 100644 index 000000000000..7c7e0f842331 --- /dev/null +++ b/drivers/cpufreq/pmu_count.c @@ -0,0 +1,285 @@ +/* linux/drivers/cpufreq/pmu_count.c + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CPU Support + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pmu_func.h" + +static int start_counter(void *data); +static int stop_counter(void *data); + +static DEFINE_MUTEX(pmu_counter_lock); +static int enable_pmu_mon = 1; +static int run; +static int events[7] = {0x77, 0x08, 0x17, }; +static int alive_cpu[8]; +static struct kobject *pmu_kobj; + +static ssize_t event_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%x %x %x %x %x %x %x\n", + events[0], + events[1], + events[2], + events[3], + events[4], + events[5], + events[6]); +} + +static ssize_t event_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int i; + + pr_info("%s\n", buf); + sscanf(buf, "%x %x %x %x %x %x %x", + &events[0], + &events[1], + &events[2], + &events[3], + &events[4], + &events[5], + &events[6]); + + for (i=0; i<7; i++) + pr_info("%d:[%x] ", i, events[i]); + + return count; +} + +static struct kobj_attribute event_attribute = __ATTR(event, 0640, event_show, event_store); + +static ssize_t run_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d: %s\n", run, run ? "run" : "no run"); +} + +static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + int cpu; + struct task_struct *task; + + sscanf(buf, "%d", &run); + + if (run == 1) { + for_each_online_cpu(cpu) { + task = kthread_create(start_counter, NULL, "t_%u", cpu); + kthread_bind(task, cpu); + wake_up_process(task); + } + } else { + for_each_online_cpu(cpu) { + task = kthread_create(stop_counter, NULL, "t_%u", cpu); + kthread_bind(task, cpu); + wake_up_process(task); + } + } + + return count; +} + +static struct kobj_attribute run_attribute = __ATTR(run, 0640, run_show, run_store); + +static ssize_t enable_pmu_monitor_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d: %s\n", enable_pmu_mon, + enable_pmu_mon ? "enabled" : "disabled"); +} + +static ssize_t enable_pmu_monitor_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + sscanf(buf, "%d", &enable_pmu_mon); + + return count; +} + +static struct kobj_attribute enable_pmu_monitor_attribute = + __ATTR(enable_pmu_monitor, 0640, enable_pmu_monitor_show, enable_pmu_monitor_store); + +static ssize_t pmu_count_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "ccnt %llu, instcnt %u, l2refill %u\n", + read_ccnt(), pmnc_read2(1), pmnc_read2(2)); +} + +static struct kobj_attribute pmu_count_attribute = __ATTR(pmu_count, 0440, pmu_count_show, NULL); + +/* create group */ +static struct attribute *attrs[] = { + &run_attribute.attr, + &event_attribute.attr, + &enable_pmu_monitor_attribute.attr, + &pmu_count_attribute.attr, + NULL, +}; + +/* if a name, subdir will be created */ +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static int start_counter(void *data) +{ + int i; + + if (!enable_pmu_mon) + return 0; + + __start_timer(); + + for (i = 0; i < 7; i++) { + pmu_enable_counter(i); + pmnc_config(i, events[i]); + pr_info("%s: %d = %u\n", __func__, i, events[i]); + } + + pmnc_reset(); + pr_info("pmu enabled\n"); + + return 0; +} + +static int stop_counter(void *data) +{ + int i; + u32 v[7] = {0, }; + u64 ccnt = read_ccnt(); + + if (!enable_pmu_mon) + return 0; + + for (i = 0; i < 7; i++) { + v[i] = pmnc_read2(i); + pr_info("[%d] = %u, ccnt = %lu\n", i, v[i], (unsigned long)ccnt); + } + + return 0; +} + +int is_alive_cpu(int cpu) +{ + return alive_cpu[cpu]; +} + +int start_counter_cpu(int cpu) +{ + int i; + + if (!enable_pmu_mon) + return 0; + + __start_timer(); + + for (i = 0; i < 7; i++) { + pmu_enable_counter(i); + pmnc_config(i, events[i]); + } + + alive_cpu[cpu] = 1; + + return 0; +} + +int stop_counter_cpu(int cpu) +{ + if (!enable_pmu_mon) + return 0; + + alive_cpu[cpu] = 0; + + return 0; +} + +int read_pmu_one(void *data) +{ + struct pmu_count_value *p = (struct pmu_count_value *)data; + + if (!enable_pmu_mon) + return 0; + + p->ccnt = read_ccnt(); + p->pmnc0 = pmnc_read2(0); + p->pmnc1 = pmnc_read2(1); + p->pmnc2 = pmnc_read2(2); + p->pmnc3 = pmnc_read2(3); + p->pmnc4 = pmnc_read2(4); + p->pmnc5 = pmnc_read2(5); + p->pmnc6 = pmnc_read2(6); + p->valid = 1; + + reset_ccnt(); + pmnc_reset(); + + return 0; +} + +void read_counter_value(struct pmu_count_value *data) +{ + int i; + struct task_struct *task; + + mutex_lock(&pmu_counter_lock); + + for (i = 0; i < 8 ; i++) { + if (alive_cpu[i] == 1) { + task = kthread_create(read_pmu_one, &data[i], "t_%u", i); + kthread_bind(task, i); + wake_up_process(task); + } else { + data[i].valid = 0; + } + } + + mutex_unlock(&pmu_counter_lock); +} + +static int __init pmu_init(void) +{ + int ret; + + /* location: /sys/kernel/pmu_count */ + pmu_kobj = kobject_create_and_add("pmu_count", kernel_kobj); + if (!pmu_kobj) { + pr_info("%s: failed kobject_create_and_add\n", __func__); + return -ENOMEM; + } + + ret = sysfs_create_group(pmu_kobj, &attr_group); + if (ret) { + pr_info("%s: failed create sysfs group\n", __func__); + kobject_put(pmu_kobj); + } + + return ret; +} + +static void __exit pmu_exit(void) +{ + sysfs_remove_group(pmu_kobj, &attr_group); + kobject_put(pmu_kobj); +} + +module_init(pmu_init); +module_exit(pmu_exit); diff --git a/drivers/cpufreq/pmu_func.h b/drivers/cpufreq/pmu_func.h new file mode 100644 index 000000000000..592515709831 --- /dev/null +++ b/drivers/cpufreq/pmu_func.h @@ -0,0 +1,294 @@ +/* linux/drivers/cpufreq/pmu_func.h + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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 __PMU_FUNC_H_ +#define __PMU_FUNC_H_ __FILE__ + +#if defined(CONFIG_ARM64) +static inline void pmu_enable_counter(u32 val) +{ + val = 1 << val; + asm volatile("msr PMCNTENSET_EL0, %0" : : "r" (val)); +} + +static inline void pmu_disable_counter(u32 val) +{ + val = 1 << val; + asm volatile("msr PMCNTENCLR_EL0, %0" : : "r" (val)); +} + +static inline void pmnc_config(u32 counter, u32 event) +{ + counter = counter & 0x1F; + asm volatile("msr PMSELR_EL0, %0" : : "r" (counter)); + asm volatile("msr PMXEVTYPER_EL0, %0" : : "r" (event)); +} + +static inline void pmnc_reset(void) +{ + u32 val; + asm volatile("mrs %0, PMCR_EL0" : "=r"(val)); + val = val | 0x2; + asm volatile("msr PMCR_EL0, %0" : : "r"(val)); +} + +static inline u32 pmnc_read2(u32 counter) +{ + u32 ret; + counter = counter & 0x1F; + asm volatile("msr PMSELR_EL0, %0" : : "r" (counter)); + asm volatile("mrs %0, PMXEVCNTR_EL0" : "=r"(ret)); + return ret; +} + +static inline u32 pmnc_read_evt(u32 counter) +{ + u32 ret; + counter = counter & 0x1F; + asm volatile("msr PMSELR_EL0, %0" : : "r" (counter)); + asm volatile("mrs %0, PMXEVTYPER_EL0" : "=r"(ret)); + return ret; +} + +static inline void pmnc_write(u32 counter, u32 val) +{ + counter = counter & 0x1F; + asm volatile("msr PMSELR_EL0, %0" : : "r" (counter)); + asm volatile("msr PMXEVCNTR_EL0, %0" : : "r" (val)); +} + +static inline void enable_pmu(void) +{ + u32 val; + + asm volatile("mrs %0, PMCR_EL0" : "=r"(val)); + val = val | 0x1; // set E bit + asm volatile("msr PMCR_EL0, %0" : : "r"(val)); +} + +static inline void disable_pmu(void) +{ + u32 val; + asm volatile("mrs %0, PMCR_EL0" : "=r"(val)); + val = val & ~0x1; // clear E bit + asm volatile("msr PMCR_EL0, %0" : : "r"(val)); +} + +static inline u32 read_pmnc(void) +{ + u32 val; + asm volatile("mrs %0, PMCR_EL0" : "=r"(val)); + return val; +} + +static inline void disable_ccnt(void) +{ + u32 val = 0x80000000; + asm volatile("msr PMCNTENCLR_EL0, %0" : : "r" (val)); +} + +static inline void enable_ccnt(void) +{ + u32 val = 0x80000000; + asm volatile("msr PMCNTENSET_EL0, %0" : : "r" (val)); +} + +static inline void reset_ccnt(void) +{ + u32 val; + asm volatile("mrs %0, PMCR_EL0" : "=r"(val)); + val = val | 0x4; // set C bit + asm volatile("msr PMCR_EL0, %0" : : "r"(val)); +} + +static inline u64 read_ccnt(void) +{ + u64 val; + asm volatile("mrs %0, PMCCNTR_EL0" : "=r"(val)); + return val; +} + +static inline void write_ccnt(u64 val) +{ + asm volatile("msr PMCCNTR_EL0, %0" : : "r"(val)); +} +#else +static inline void pmu_enable_counter(u32 val) +{ + val = 1 << val; + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); +} + +static inline void pmu_disable_counter(u32 val) +{ + val = 1 << val; + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); +} + +static inline u32 pmu_select_counter(u32 idx) +{ + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (idx)); + return idx; +} + +static inline u32 pmnc_read(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + return val; +} + +static inline void pmnc_write(u32 val) +{ + val &= 0x3f; + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline void pmnc_config(u32 counter, u32 event) +{ + counter = counter & 0x1F; + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(counter)); + asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r"(event)); +} + +static inline void pmnc_reset(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + val = val | 0x2; + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline u32 pmnc_read2(u32 counter) +{ + u32 ret; + counter = counter & 0x1F; + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r"(counter)); + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r"(ret)); + return ret; +} + +static inline void enable_pmu(void) +{ + u32 val; + + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + val = val | 0x1; // set E bit + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline void disable_pmu(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + val = val & ~0x1; // clear E bit + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline u32 read_pmnc(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + return val; +} + +static inline void disable_ccnt(void) +{ + u32 val = 0x80000000; + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r"(val)); +} + +static inline void enable_ccnt(void) +{ + u32 val = 0x80000000; + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r"(val)); +} + +static inline void reset_ccnt(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val)); + val = val | 0x4; // set C bit + asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val)); +} + +static inline u32 read_ccnt(void) +{ + u32 val; + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(val)); + return val; +} +#endif + +struct pmu_count_value { + u64 ccnt; + u32 pmnc0; + u32 pmnc1; + u32 pmnc2; + u32 pmnc3; + u32 pmnc4; + u32 pmnc5; + u32 pmnc6; + + int core_num; + + int valid; +}; + +#define __start_timer(x) (enable_pmu(), disable_ccnt(), reset_ccnt(), enable_ccnt()) +#define __start_timer_resume(x) (enable_pmu(), enable_ccnt()) +#define __stop_timer(x) read_ccnt() + +#if defined(CONFIG_PMU_COREMEM_RATIO) +int is_alive_cpu(int cpu); +int start_counter_cpu(int cpu); +int stop_counter_cpu(int cpu); +int read_pmu_one(void *data); +void read_counter_value(struct pmu_count_value *data); +int coremem_ratio (u32 instcnt, u32 linefcnt); +#else +static inline int is_alive_cpu(int cpu) +{ + return 1; +} + +static inline int start_counter_cpu(int cpu) +{ + return 0; +} + +static inline int stop_counter_cpu(int cpu) +{ + return 0; +} + +static inline int read_pmu_one(void *data) +{ + return 0; +} + +static inline void read_counter_value(struct pmu_count_value *data); +{ + return; +} + +static inline int coremem_ratio (u32 instcnt, u32 linefcnt) +{ + return 0; +} +#endif + +#define REGION_C100_M000_C080_M020 0x1 +#define REGION_C080_M020_C060_M040 0x2 +#define REGION_C060_M040_C040_M060 0x3 +#define REGION_C040_M060_C020_M080 0x4 +#define REGION_C020_M080_C000_M100 0x5 + +#endif /* __PMU_FUNC_H_ */ diff --git a/drivers/cpuidle/cpuidle_profiler.c b/drivers/cpuidle/cpuidle_profiler.c index 70d9a2a7c826..956a207ddac3 100644 --- a/drivers/cpuidle/cpuidle_profiler.c +++ b/drivers/cpuidle/cpuidle_profiler.c @@ -436,11 +436,121 @@ static ssize_t store_cpuidle_profile(struct kobject *kobj, return count; } +static ssize_t show_cpuidle_result(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int ret = 0; + int i, cpu; + struct cpuidle_profile_info *info; + + if (profile_ongoing) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "CPUIDLE profile is ongoing\n"); + return ret; + } + + if (profile_time == 0) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "CPUIDLE profiler has not started yet\n"); + return ret; + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "#######################################################################\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "Profiling Time : %lluus\n", profile_time); + + for (i = 0; i < state_count; i++) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "[state%d]\n", i); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "#cpu #entry #early #time #ratio\n"); + for_each_possible_cpu(cpu) { + info = &per_cpu(profile_info, cpu); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "cpu%d %5u %5u %10lluus %3u%%\n", cpu, + info->usage[i].entry_count, + info->usage[i].early_wakeup_count, + info->usage[i].time, + calculate_percent(info->usage[i].time)); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\n"); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "[CPD] - Cluster Power Down\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "#cluster #entry #early #time #ratio\n"); + for (i = 0; i < NUM_CLUSTER; i++) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "cluster%d %5u %5u %10lluus %3u%%\n", i, + cpd_info[i].usage->entry_count, + cpd_info[i].usage->early_wakeup_count, + cpd_info[i].usage->time, + calculate_percent(cpd_info[i].usage->time)); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\n"); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "[LPC] - Low Power mode with Clock down\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + " #entry #early #time #ratio\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "system %5u %5u %10lluus %3u%%\n", + lpc_info.usage->entry_count, + lpc_info.usage->early_wakeup_count, + lpc_info.usage->time, + calculate_percent(lpc_info.usage->time)); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\n"); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "[LPM] - Low Power Mode\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "#mode #entry #early #time #ratio\n"); + for (i = 0; i < NUM_SYS_POWERDOWN; i++) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "%-9s %5u %5u %10lluus %3u%%\n", + get_sys_powerdown_str(i), + lpm_info.usage[i].entry_count, + lpm_info.usage[i].early_wakeup_count, + lpm_info.usage[i].time, + calculate_percent(lpm_info.usage[i].time)); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\n"); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "[LPA blockers]\n"); + for (i = 0; i < MAX_NUM_BLOCKER; i++) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "%-9s: %d\n", get_lpa_blocker_str(i), lpa_blocker[i]); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\n"); + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "#######################################################################\n"); + + return ret; +} + static struct kobj_attribute cpuidle_profile_attr = __ATTR(profile, 0644, show_cpuidle_profile, store_cpuidle_profile); +static struct kobj_attribute cpuidle_result_attr = + __ATTR(result, 0444, show_cpuidle_result, NULL); + + static struct attribute *cpuidle_profile_attrs[] = { &cpuidle_profile_attr.attr, + &cpuidle_result_attr.attr, NULL, }; diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index c925acf7aaa5..ca61df18ea72 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -479,4 +479,6 @@ config CRYPTO_DEV_ATMEL_SHA To compile this driver as a module, choose M here: the module will be called atmel-sha. +source "drivers/crypto/fmp/Kconfig" + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index c642867c60c2..36c8710317ae 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o obj-$(CONFIG_CRYPTO_S5P_DEV_ACE) += ace.o +obj-$(CONFIG_FIPS_FMP) += fmp/ diff --git a/drivers/crypto/fmp/Kconfig b/drivers/crypto/fmp/Kconfig new file mode 100644 index 000000000000..833c84e5b2bd --- /dev/null +++ b/drivers/crypto/fmp/Kconfig @@ -0,0 +1,28 @@ +config FIPS_FMP + tristate "Samsung EXYNOS FMP Test for FIPS" + depends on FMP + ---help--- + This selects Samsung EXYNOS FMP Test driver for FIPS. + + If you have a controller with this interface, say Y here. + + If unsure, say N. + +choice + prompt "Option for self-test failure" + depends on FIPS_FMP + default NODE_FOR_SELFTEST_FAIL + +config NODE_FOR_SELFTEST_FAIL + bool "Set fips fmp node when self-test fails" + depends on FIPS_FMP + help + This select that fips fmp node was set to zero when FMP self-test fails. + +config PANIC_FOR_SELFTEST_FAIL + bool "Panic when self-test fails" + depends on FIPS_FMP + help + This select that kernel panic occurs when FMP self-test fails. + +endchoice diff --git a/drivers/crypto/fmp/Makefile b/drivers/crypto/fmp/Makefile new file mode 100644 index 000000000000..dda904299790 --- /dev/null +++ b/drivers/crypto/fmp/Makefile @@ -0,0 +1,6 @@ +# Exynos FMP makefile +obj-$(CONFIG_FIPS_FMP) += first_file.o +obj-$(CONFIG_FIPS_FMP) += fmpdev.o fmp_integrity.o fmplib.o +obj-$(CONFIG_FIPS_FMP) += hmac_fmp.o sha256_fmp.o +obj-$(CONFIG_FIPS_FMP) += last_file.o +obj-$(CONFIG_UFS_FMP_ECRYPT_FS) += fmp_derive_iv.o diff --git a/drivers/crypto/fmp/first_file.c b/drivers/crypto/fmp/first_file.c new file mode 100644 index 000000000000..194161b1ef74 --- /dev/null +++ b/drivers/crypto/fmp/first_file.c @@ -0,0 +1,41 @@ +/* + * First file for Exynos FMP FIPS integrity check + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +/* Keep this on top */ +static const char +builtime_fmp_hmac[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + +const int first_fmp_rodata = 10; +int first_fmp_data = 20; + + +void first_fmp_text(void) __attribute__((unused)); +void first_fmp_text(void) +{ +} + +const char *get_builtime_fmp_hmac(void) +{ + return builtime_fmp_hmac; +} + +void __init first_fmp_init(void) __attribute__((unused)); +void __init first_fmp_init(void) +{ +} + +void __exit first_fmp_exit(void) __attribute__((unused)); +void __exit first_fmp_exit(void) +{ +} diff --git a/drivers/crypto/fmp/fmp_derive_iv.c b/drivers/crypto/fmp/fmp_derive_iv.c new file mode 100644 index 000000000000..186a91f7f66a --- /dev/null +++ b/drivers/crypto/fmp/fmp_derive_iv.c @@ -0,0 +1,148 @@ +/* + * Exynos FMP derive iv for eCryptfs + * + * Copyright (C) 2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#define FMP_MAX_IV_BYTES 16 +#define FMP_MAX_OFFSET_BYTES 16 +#define DEFAULT_HASH "md5" +#define SHA256_HASH "sha256" + +static DEFINE_SPINLOCK(fmp_tfm_lock); + +int calculate_sha256(struct crypto_hash *hash_tfm, char *dst, char *src, int len) +{ + int ret = -1; + unsigned long flag; + struct scatterlist sg; + struct hash_desc desc = { + .tfm = hash_tfm, + .flags = 0 + }; + + spin_lock_irqsave(&fmp_tfm_lock, flag); + sg_init_one(&sg, (u8 *)src, len); + + if (!desc.tfm) { + desc.tfm = crypto_alloc_hash(SHA256_HASH, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) { + printk(KERN_ERR "%s: Error attemping to allocate crypto context\n", __func__); + goto out; + } + hash_tfm = desc.tfm; + } + + ret = crypto_hash_init(&desc); + if (ret) { + printk(KERN_ERR + "%s: Error initializing crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + ret = crypto_hash_update(&desc, &sg, len); + if (ret) { + printk(KERN_ERR + "%s: Error updating crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + ret = crypto_hash_final(&desc, dst); + if (ret) { + printk(KERN_ERR + "%s: Error finalizing crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + +out: + spin_unlock_irqrestore(&fmp_tfm_lock, flag); + return ret; +} + +int calculate_md5(struct crypto_hash *hash_tfm, char *dst, char *src, int len) +{ + int ret = -1; + unsigned long flag; + struct scatterlist sg; + struct hash_desc desc = { + .tfm = hash_tfm, + .flags = 0 + }; + + spin_lock_irqsave(&fmp_tfm_lock, flag); + sg_init_one(&sg, (u8 *)src, len); + + if (!desc.tfm) { + desc.tfm = crypto_alloc_hash(DEFAULT_HASH, 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR(desc.tfm)) { + printk(KERN_ERR "%s: Error attemping to allocate crypto context\n", __func__); + goto out; + } + hash_tfm = desc.tfm; + } + + ret = crypto_hash_init(&desc); + if (ret) { + printk(KERN_ERR + "%s: Error initializing crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + ret = crypto_hash_update(&desc, &sg, len); + if (ret) { + printk(KERN_ERR + "%s: Error updating crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + ret = crypto_hash_final(&desc, dst); + if (ret) { + printk(KERN_ERR + "%s: Error finalizing crypto hash; ret = [%d]\n", + __func__, ret); + goto out; + } + +out: + spin_unlock_irqrestore(&fmp_tfm_lock, flag); + return ret; +} + +int file_enc_derive_iv(struct address_space *mapping, loff_t offset, char *extent_iv) +{ + char src[FMP_MAX_IV_BYTES + FMP_MAX_OFFSET_BYTES]; + int ret; + + memcpy(src, mapping->iv, FMP_MAX_IV_BYTES); + memset(src + FMP_MAX_IV_BYTES, 0, FMP_MAX_OFFSET_BYTES); + snprintf(src + FMP_MAX_IV_BYTES, FMP_MAX_OFFSET_BYTES, "%lld", offset); + +#ifdef CONFIG_CRYPTO_FIPS + if (mapping->cc_enable) + ret = calculate_sha256(mapping->hash_tfm, extent_iv, src, FMP_MAX_IV_BYTES + FMP_MAX_OFFSET_BYTES); + else +#endif + ret = calculate_md5(mapping->hash_tfm, extent_iv, src, FMP_MAX_IV_BYTES + FMP_MAX_OFFSET_BYTES); + if (ret) { + printk(KERN_ERR "%s: Error attempting to compute generating IV for a page; ret = [%d]\n", __func__, ret); + goto out; + } + +out: + return ret; +} + diff --git a/drivers/crypto/fmp/fmp_derive_iv.h b/drivers/crypto/fmp/fmp_derive_iv.h new file mode 100644 index 000000000000..ea3256a2771e --- /dev/null +++ b/drivers/crypto/fmp/fmp_derive_iv.h @@ -0,0 +1,22 @@ +/* + * Exynos FMP derive iv for eCryptfs + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _FMP_DERIVE_IV_H_ +#define _FMP_DERIVE_IV_H_ + +#define SHA256_HASH_SIZE 32 +#define MD5_DIGEST_SIZE 16 + +int calculate_sha256(struct crypto_hash *hash_tfm, char *dst, char *src, int len); +int calculate_md5(struct crypto_hash *hash_tfm, char *dst, char *src, int len); +int file_enc_derive_iv(struct address_space *mapping, loff_t offset, char *extent_iv); + +#endif diff --git a/drivers/crypto/fmp/fmp_integrity.c b/drivers/crypto/fmp/fmp_integrity.c new file mode 100644 index 000000000000..720aef8f6455 --- /dev/null +++ b/drivers/crypto/fmp/fmp_integrity.c @@ -0,0 +1,283 @@ +/* + * Perform FIPS Integrity test on Kernel Crypto API + * + * At build time, hmac(sha256) of crypto code, avaiable in different ELF sections + * of vmlinux file, is generated. vmlinux file is updated with built-time hmac + * in a read-only data variable, so that it is available at run-time + * + * At run time, hmac(sha256) is again calculated using crypto bytes of a running + * At run time, hmac-fmp(sha256-fmp) is again calculated using crypto bytes of a running + * kernel. + * Run time hmac is compared to built time hmac to verify the integrity. + * + * + * Author : Rohit Kothari (r.kothari@samsung.com) + * Date : 11 Feb 2014 + * + * Copyright (c) 2014 Samsung Electronics + * + */ + +#include +#include +#include +#include +#include + +//#define FIPS_DEBUG +#define FIPS_FUNC_TEST 0 + +static const char *symtab[][3] = + {{".text", "first_fmp_text", "last_fmp_text" }, + {".rodata", "first_fmp_rodata", "last_fmp_rodata"}, + {".init.text", "first_fmp_init", "last_fmp_init" }}; + +extern const char *get_builtime_fmp_hmac(void); + +#ifdef FIPS_DEBUG +static int +dump_bytes(const char *section_name, const char *first_symbol, const char *last_symbol) +{ + u8 *start_addr = (u8 *)kallsyms_lookup_name(first_symbol); + u8 *end_addr = (u8 *)kallsyms_lookup_name(last_symbol); + + if (!start_addr || !end_addr || start_addr >= end_addr) { + printk(KERN_ERR "FIPS(%s): Error Invalid Addresses in Section : %s, Start_Addr : %p , End_Addr : %p", + __FUNCTION__, section_name, start_addr, end_addr); + return -1; + } + + printk(KERN_INFO "FIPS CRYPTO RUNTIME : Section - %s, %s : %p, %s : %p \n", section_name, first_symbol, start_addr, last_symbol, end_addr); + print_hex_dump_bytes("FIPS CRYPTO RUNTIME : ", DUMP_PREFIX_NONE, start_addr, end_addr - start_addr); + + return 0; +} +#endif + +static int query_symbol_addresses(const char *first_symbol, const char *last_symbol, + unsigned long *start_addr,unsigned long *end_addr) +{ + unsigned long start = kallsyms_lookup_name(first_symbol); + unsigned long end = kallsyms_lookup_name(last_symbol); + +#ifdef FIPS_DEBUG + printk(KERN_INFO "FIPS CRYPTO RUNTIME : %s : %p, %s : %p\n", first_symbol, (u8*)start, last_symbol, (u8*)end); +#endif + + if (!start || !end || start >= end) { + printk(KERN_ERR "FIPS(%s): Error Invalid Addresses.", __FUNCTION__); + return -1; + } + + *start_addr = start; + *end_addr = end; + + return 0; +} + +static int init_hash(struct hash_desc *desc) +{ + struct crypto_hash *tfm = NULL; + int ret = -1; + + /* Same as build time */ + const unsigned char *key = "The quick brown fox jumps over the lazy dog"; + + tfm = crypto_alloc_hash("hmac-fmp(sha256-fmp)", 0, 0); + if (IS_ERR(tfm)) { + printk(KERN_ERR "FIPS(%s): integrity failed to allocate tfm %ld", __FUNCTION__, PTR_ERR(tfm)); + return -1; + } + + ret = crypto_hash_setkey (tfm, key, strlen(key)); + if (ret) { + printk(KERN_ERR "FIPS(%s): fail at crypto_hash_setkey", __FUNCTION__); + return -1; + } + + desc->tfm = tfm; + desc->flags = 0; + + ret = crypto_hash_init(desc); + if (ret) { + printk(KERN_ERR "FIPS(%s): fail at crypto_hash_init", __FUNCTION__); + return -1; + } + + return 0; +} + +static int finalize_hash(struct hash_desc *desc, unsigned char *out, unsigned int out_size) +{ + int ret = -1; + + if (!desc || !desc->tfm || !out || !out_size) { + printk(KERN_ERR "FIPS(%s): Invalid args", __FUNCTION__); + return ret; + } + + if (crypto_hash_digestsize(desc->tfm) > out_size) { + printk(KERN_ERR "FIPS(%s): Not enough space for digest", __FUNCTION__); + return ret; + } + + ret = crypto_hash_final(desc, out); + if (ret) { + printk(KERN_ERR "FIPS(%s): crypto_hash_final failed", __FUNCTION__); + return -1; + } + + return 0; +} + +static int update_hash(struct hash_desc *desc, unsigned char *start_addr, unsigned int size) +{ + struct scatterlist sg; + unsigned char *buf = NULL; + unsigned char *cur = NULL; + unsigned int bytes_remaining; + unsigned int bytes; + int ret = -1; +#if FIPS_FUNC_TEST == 2 + static int total = 0; +#endif + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "FIPS(%s): kmalloc failed", __FUNCTION__); + return ret; + } + + bytes_remaining = size; + cur = start_addr; + + while (bytes_remaining > 0) { + if (bytes_remaining >= PAGE_SIZE) + bytes = PAGE_SIZE; + else + bytes = bytes_remaining; + + memcpy(buf, cur, bytes); + + sg_init_one(&sg, buf, bytes); + +#if FIPS_FUNC_TEST == 2 + if (total == 0) { + printk(KERN_INFO "FIPS : Failing Integrity Test"); + buf[bytes / 2] += 1; + } +#endif + + ret = crypto_hash_update(desc, &sg, bytes); + if (ret) { + printk(KERN_ERR "FIPS(%s): crypto_hash_update failed", __FUNCTION__); + kfree(buf); + buf = 0; + return -1; + } + + cur += bytes; + bytes_remaining -= bytes; + +#if FIPS_FUNC_TEST == 2 + total += bytes; +#endif + } + + if (buf) { + kfree(buf); + buf = 0; + } + + return 0; +} + +int do_fmp_fw_integrity_check(void) +{ + int err = 0; + + err = exynos_smc(SMC_CMD_FMP, FMP_FW_INTEGRITY, 0, 0); + if (err) { + printk(KERN_ERR "Fail to check integrity for FMP F/W. err = 0x%x\n", err); + return -1; + } + + return 0; +} + +int do_fips_fmp_integrity_check(void) +{ + int i, rows, err; + unsigned long start_addr = 0; + unsigned long end_addr = 0; + unsigned char runtime_hmac[32]; + struct hash_desc desc; + const char *builtime_hmac = 0; + unsigned int size = 0; + + err = do_fmp_fw_integrity_check(); + if (err) { + printk(KERN_ERR "FIPS(%s): FMP FW Integrity Check Failed", __FUNCTION__); + return -1; + } + + err = init_hash(&desc); + if (err) { + printk(KERN_ERR "FIPS(%s): init_hash failed", __FUNCTION__); + return -1; + } + + rows = (unsigned int)sizeof(symtab) / sizeof(symtab[0]); + + for (i = 0; i < rows; i++) { + err = query_symbol_addresses(symtab[i][1], symtab[i][2], &start_addr, &end_addr); + if (err) { + printk (KERN_ERR "FIPS(%s): Error to get start / end addresses", __FUNCTION__); + crypto_free_hash(desc.tfm); + return -1; + } + +#ifdef FIPS_DEBUG + dump_bytes(symtab[i][0], symtab[i][1], symtab[i][2]); +#endif + size = end_addr - start_addr; + + err = update_hash(&desc, (unsigned char *)start_addr, size); + if (err) { + printk(KERN_ERR "FIPS(%s): Error to update hash", __FUNCTION__); + crypto_free_hash(desc.tfm); + return -1; + } + } + + err = finalize_hash(&desc, runtime_hmac, sizeof(runtime_hmac)); + if (err) { + printk(KERN_ERR "FIPS(%s): Error in finalize", __FUNCTION__); + crypto_free_hash(desc.tfm); + return -1; + } + + crypto_free_hash(desc.tfm); + builtime_hmac = get_builtime_fmp_hmac(); + if (!builtime_hmac) { + printk(KERN_ERR "FIPS(%s): Unable to retrieve builtime_hmac", __FUNCTION__); + return -1; + } + +#ifdef FIPS_DEBUG + print_hex_dump_bytes("FIPS CRYPTO RUNTIME : runtime hmac = ", DUMP_PREFIX_NONE, runtime_hmac, sizeof(runtime_hmac)); + print_hex_dump_bytes("FIPS CRYPTO RUNTIME : builtime_hmac = ", DUMP_PREFIX_NONE, builtime_hmac , sizeof(runtime_hmac)); +#endif + + if (!memcmp(builtime_hmac, runtime_hmac, sizeof(runtime_hmac))) { + printk(KERN_INFO "FIPS: Integrity Check Passed"); + return 0; + } else { + printk(KERN_ERR "FIPS(%s): Integrity Check Failed", __FUNCTION__); + return -1; + } + + return -1; +} + +EXPORT_SYMBOL_GPL(do_fips_fmp_integrity_check); diff --git a/drivers/crypto/fmp/fmp_integrity.h b/drivers/crypto/fmp/fmp_integrity.h new file mode 100644 index 000000000000..47b9d62e4920 --- /dev/null +++ b/drivers/crypto/fmp/fmp_integrity.h @@ -0,0 +1,17 @@ +/* + * Exynos FMP integrity header + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __FMP_INTEGRITY_H__ +#define __FMP_INTEGRITY_H__ + +int do_fips_fmp_integrity_check(void); + +#endif diff --git a/drivers/crypto/fmp/fmpdev.c b/drivers/crypto/fmp/fmpdev.c new file mode 100644 index 000000000000..dcc452a2fd07 --- /dev/null +++ b/drivers/crypto/fmp/fmpdev.c @@ -0,0 +1,2377 @@ +/* + * Exynos FMP test driver for FIPS + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "fmpdev_int.h" +#include "fmp_integrity.h" +#include "fmplib.h" + +static int fips_fmp_result; +static const char pass[] = "passed"; +static const char fail[] = "failed"; + +static const char *ALG_SHA256_FMP = "sha256-fmp"; +static const char *ALG_HMAC_SHA256_FMP = "hmac-fmp(sha256-fmp)"; + +extern int fips_fmp_init(struct device *dev); +extern struct fips_fmp_ops fips_fmp_fops; +static const struct of_device_id exynos_fips_fmp_match[]; + +struct platform_device *pdev; + +#define FMP_FIPS_ERR 1 +#define FMP_FIPS_NO_ERR 0 +static int IN_FMP_FIPS_ERROR = FMP_FIPS_NO_ERR; + +bool in_fmp_fips_err(void) +{ + return (IN_FMP_FIPS_ERROR == FMP_FIPS_ERR); +} +EXPORT_SYMBOL_GPL(in_fmp_fips_err); + +static void set_in_fmp_fips_err(void) +{ + IN_FMP_FIPS_ERROR = FMP_FIPS_ERR; +} + +#define AES_XTS_ENC_TEST_VECTORS 5 +#define AES_CBC_ENC_TEST_VECTORS 4 + +/* + * Indexes into the xbuf to simulate cross-page access. + */ +#define IDX1 32 +#define IDX2 32400 +#define IDX3 1 +#define IDX4 8193 +#define IDX5 22222 +#define IDX6 17101 +#define IDX7 27333 +#define IDX8 3000 + +static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; + +/* ====== Compile-time config ====== */ + +/* Default (pre-allocated) and maximum size of the job queue. + * These are free, pending and done items all together. */ +#define DEF_COP_RINGSIZE 16 +#define MAX_COP_RINGSIZE 64 + +static struct cipher_testvec aes_xts_enc_tv_template[] = { + /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */ + { /* XTS-AES 1 */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .ilen = 32, + .result = "\x91\x7c\xf6\x9e\xbd\x68\xb2\xec" + "\x9b\x9f\xe9\xa3\xea\xdd\xa6\x92" + "\xcd\x43\xd2\xf5\x95\x98\xed\x85" + "\x8c\x02\xc2\x65\x2f\xbf\x92\x2e", + .rlen = 32, + }, { /* XTS-AES 2 */ + .key = "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x11\x11\x11\x11\x11\x11\x11\x11" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\xc4\x54\x18\x5e\x6a\x16\x93\x6e" + "\x39\x33\x40\x38\xac\xef\x83\x8b" + "\xfb\x18\x6f\xff\x74\x80\xad\xc4" + "\x28\x93\x82\xec\xd6\xd3\x94\xf0", + .rlen = 32, + }, { /* XTS-AES 3 */ + .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" + "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" + "\x22\x22\x22\x22\x22\x22\x22\x22" + "\x22\x22\x22\x22\x22\x22\x22\x22", + .klen = 32, + .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44" + "\x44\x44\x44\x44\x44\x44\x44\x44", + .ilen = 32, + .result = "\xaf\x85\x33\x6b\x59\x7a\xfc\x1a" + "\x90\x0b\x2e\xb2\x1e\xc9\x49\xd2" + "\x92\xdf\x4c\x04\x7e\x0b\x21\x53" + "\x21\x86\xa5\x97\x1a\x22\x7a\x89", + .rlen = 32, + }, { /* XTS-AES 4 */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95", + .klen = 32, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\x27\xa7\x47\x9b\xef\xa1\xd4\x76" + "\x48\x9f\x30\x8c\xd4\xcf\xa6\xe2" + "\xa9\x6e\x4b\xbe\x32\x08\xff\x25" + "\x28\x7d\xd3\x81\x96\x16\xe8\x9c" + "\xc7\x8c\xf7\xf5\xe5\x43\x44\x5f" + "\x83\x33\xd8\xfa\x7f\x56\x00\x00" + "\x05\x27\x9f\xa5\xd8\xb5\xe4\xad" + "\x40\xe7\x36\xdd\xb4\xd3\x54\x12" + "\x32\x80\x63\xfd\x2a\xab\x53\xe5" + "\xea\x1e\x0a\x9f\x33\x25\x00\xa5" + "\xdf\x94\x87\xd0\x7a\x5c\x92\xcc" + "\x51\x2c\x88\x66\xc7\xe8\x60\xce" + "\x93\xfd\xf1\x66\xa2\x49\x12\xb4" + "\x22\x97\x61\x46\xae\x20\xce\x84" + "\x6b\xb7\xdc\x9b\xa9\x4a\x76\x7a" + "\xae\xf2\x0c\x0d\x61\xad\x02\x65" + "\x5e\xa9\x2d\xc4\xc4\xe4\x1a\x89" + "\x52\xc6\x51\xd3\x31\x74\xbe\x51" + "\xa1\x0c\x42\x11\x10\xe6\xd8\x15" + "\x88\xed\xe8\x21\x03\xa2\x52\xd8" + "\xa7\x50\xe8\x76\x8d\xef\xff\xed" + "\x91\x22\x81\x0a\xae\xb9\x9f\x91" + "\x72\xaf\x82\xb6\x04\xdc\x4b\x8e" + "\x51\xbc\xb0\x82\x35\xa6\xf4\x34" + "\x13\x32\xe4\xca\x60\x48\x2a\x4b" + "\xa1\xa0\x3b\x3e\x65\x00\x8f\xc5" + "\xda\x76\xb7\x0b\xf1\x69\x0d\xb4" + "\xea\xe2\x9c\x5f\x1b\xad\xd0\x3c" + "\x5c\xcf\x2a\x55\xd7\x05\xdd\xcd" + "\x86\xd4\x49\x51\x1c\xeb\x7e\xc3" + "\x0b\xf1\x2b\x1f\xa3\x5b\x91\x3f" + "\x9f\x74\x7a\x8a\xfd\x1b\x13\x0e" + "\x94\xbf\xf9\x4e\xff\xd0\x1a\x91" + "\x73\x5c\xa1\x72\x6a\xcd\x0b\x19" + "\x7c\x4e\x5b\x03\x39\x36\x97\xe1" + "\x26\x82\x6f\xb6\xbb\xde\x8e\xcc" + "\x1e\x08\x29\x85\x16\xe2\xc9\xed" + "\x03\xff\x3c\x1b\x78\x60\xf6\xde" + "\x76\xd4\xce\xcd\x94\xc8\x11\x98" + "\x55\xef\x52\x97\xca\x67\xe9\xf3" + "\xe7\xff\x72\xb1\xe9\x97\x85\xca" + "\x0a\x7e\x77\x20\xc5\xb3\x6d\xc6" + "\xd7\x2c\xac\x95\x74\xc8\xcb\xbc" + "\x2f\x80\x1e\x23\xe5\x6f\xd3\x44" + "\xb0\x7f\x22\x15\x4b\xeb\xa0\xf0" + "\x8c\xe8\x89\x1e\x64\x3e\xd9\x95" + "\xc9\x4d\x9a\x69\xc9\xf1\xb5\xf4" + "\x99\x02\x7a\x78\x57\x2a\xee\xbd" + "\x74\xd2\x0c\xc3\x98\x81\xc2\x13" + "\xee\x77\x0b\x10\x10\xe4\xbe\xa7" + "\x18\x84\x69\x77\xae\x11\x9f\x7a" + "\x02\x3a\xb5\x8c\xca\x0a\xd7\x52" + "\xaf\xe6\x56\xbb\x3c\x17\x25\x6a" + "\x9f\x6e\x9b\xf1\x9f\xdd\x5a\x38" + "\xfc\x82\xbb\xe8\x72\xc5\x53\x9e" + "\xdb\x60\x9e\xf4\xf7\x9c\x20\x3e" + "\xbb\x14\x0f\x2e\x58\x3c\xb2\xad" + "\x15\xb4\xaa\x5b\x65\x50\x16\xa8" + "\x44\x92\x77\xdb\xd4\x77\xef\x2c" + "\x8d\x6c\x01\x7d\xb7\x38\xb1\x8d" + "\xeb\x4a\x42\x7d\x19\x23\xce\x3f" + "\xf2\x62\x73\x57\x79\xa4\x18\xf2" + "\x0a\x28\x2d\xf9\x20\x14\x7b\xea" + "\xbe\x42\x1e\xe5\x31\x9d\x05\x68", + .rlen = 512, + }, { /* XTS-AES 10, XTS-AES-256, data unit 512 bytes */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" + "\x62\x49\x77\x57\x24\x70\x93\x69" + "\x99\x59\x57\x49\x66\x96\x76\x27" + "\x31\x41\x59\x26\x53\x58\x97\x93" + "\x23\x84\x62\x64\x33\x83\x27\x95" + "\x02\x88\x41\x97\x16\x93\x99\x37" + "\x51\x05\x82\x09\x74\x94\x45\x92", + .klen = 64, + .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27" + "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37" + "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47" + "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57" + "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67" + "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77" + "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97" + "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" + "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" + "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" + "\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" + "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", + .ilen = 512, + .result = "\x1c\x3b\x3a\x10\x2f\x77\x03\x86" + "\xe4\x83\x6c\x99\xe3\x70\xcf\x9b" + "\xea\x00\x80\x3f\x5e\x48\x23\x57" + "\xa4\xae\x12\xd4\x14\xa3\xe6\x3b" + "\x5d\x31\xe2\x76\xf8\xfe\x4a\x8d" + "\x66\xb3\x17\xf9\xac\x68\x3f\x44" + "\x68\x0a\x86\xac\x35\xad\xfc\x33" + "\x45\xbe\xfe\xcb\x4b\xb1\x88\xfd" + "\x57\x76\x92\x6c\x49\xa3\x09\x5e" + "\xb1\x08\xfd\x10\x98\xba\xec\x70" + "\xaa\xa6\x69\x99\xa7\x2a\x82\xf2" + "\x7d\x84\x8b\x21\xd4\xa7\x41\xb0" + "\xc5\xcd\x4d\x5f\xff\x9d\xac\x89" + "\xae\xba\x12\x29\x61\xd0\x3a\x75" + "\x71\x23\xe9\x87\x0f\x8a\xcf\x10" + "\x00\x02\x08\x87\x89\x14\x29\xca" + "\x2a\x3e\x7a\x7d\x7d\xf7\xb1\x03" + "\x55\x16\x5c\x8b\x9a\x6d\x0a\x7d" + "\xe8\xb0\x62\xc4\x50\x0d\xc4\xcd" + "\x12\x0c\x0f\x74\x18\xda\xe3\xd0" + "\xb5\x78\x1c\x34\x80\x3f\xa7\x54" + "\x21\xc7\x90\xdf\xe1\xde\x18\x34" + "\xf2\x80\xd7\x66\x7b\x32\x7f\x6c" + "\x8c\xd7\x55\x7e\x12\xac\x3a\x0f" + "\x93\xec\x05\xc5\x2e\x04\x93\xef" + "\x31\xa1\x2d\x3d\x92\x60\xf7\x9a" + "\x28\x9d\x6a\x37\x9b\xc7\x0c\x50" + "\x84\x14\x73\xd1\xa8\xcc\x81\xec" + "\x58\x3e\x96\x45\xe0\x7b\x8d\x96" + "\x70\x65\x5b\xa5\xbb\xcf\xec\xc6" + "\xdc\x39\x66\x38\x0a\xd8\xfe\xcb" + "\x17\xb6\xba\x02\x46\x9a\x02\x0a" + "\x84\xe1\x8e\x8f\x84\x25\x20\x70" + "\xc1\x3e\x9f\x1f\x28\x9b\xe5\x4f" + "\xbc\x48\x14\x57\x77\x8f\x61\x60" + "\x15\xe1\x32\x7a\x02\xb1\x40\xf1" + "\x50\x5e\xb3\x09\x32\x6d\x68\x37" + "\x8f\x83\x74\x59\x5c\x84\x9d\x84" + "\xf4\xc3\x33\xec\x44\x23\x88\x51" + "\x43\xcb\x47\xbd\x71\xc5\xed\xae" + "\x9b\xe6\x9a\x2f\xfe\xce\xb1\xbe" + "\xc9\xde\x24\x4f\xbe\x15\x99\x2b" + "\x11\xb7\x7c\x04\x0f\x12\xbd\x8f" + "\x6a\x97\x5a\x44\xa0\xf9\x0c\x29" + "\xa9\xab\xc3\xd4\xd8\x93\x92\x72" + "\x84\xc5\x87\x54\xcc\xe2\x94\x52" + "\x9f\x86\x14\xdc\xd2\xab\xa9\x91" + "\x92\x5f\xed\xc4\xae\x74\xff\xac" + "\x6e\x33\x3b\x93\xeb\x4a\xff\x04" + "\x79\xda\x9a\x41\x0e\x44\x50\xe0" + "\xdd\x7a\xe4\xc6\xe2\x91\x09\x00" + "\x57\x5d\xa4\x01\xfc\x07\x05\x9f" + "\x64\x5e\x8b\x7e\x9b\xfd\xef\x33" + "\x94\x30\x54\xff\x84\x01\x14\x93" + "\xc2\x7b\x34\x29\xea\xed\xb4\xed" + "\x53\x76\x44\x1a\x77\xed\x43\x85" + "\x1a\xd7\x7f\x16\xf5\x41\xdf\xd2" + "\x69\xd5\x0d\x6a\x5f\x14\xfb\x0a" + "\xab\x1c\xbb\x4c\x15\x50\xbe\x97" + "\xf7\xab\x40\x66\x19\x3c\x4c\xaa" + "\x77\x3d\xad\x38\x01\x4b\xd2\x09" + "\x2f\xa7\x55\xc8\x24\xbb\x5e\x54" + "\xc4\xf3\x6f\xfd\xa9\xfc\xea\x70" + "\xb9\xc6\xe6\x93\xe1\x48\xc1\x51", + .rlen = 512, + } +}; + +static struct cipher_testvec aes_cbc_enc_tv_template[] = { + { /* From RFC 3602 */ + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", + .klen = 16, + .iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30" + "\xb4\x22\xda\x80\x2c\x9f\xac\x41", + .input = "Single block msg", + .ilen = 16, + .result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8" + "\x27\x08\x94\x2d\xbe\x77\x18\x1a", + .rlen = 16, + }, { + .key = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0" + "\x61\x1b\xbb\x3e\x20\x25\xa4\x5a", + .klen = 16, + .iv = "\x56\x2e\x17\x99\x6d\x09\x3d\x28" + "\xdd\xb3\xba\x69\x5a\x2e\x6f\x58", + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17" + "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + .ilen = 32, + .result = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a" + "\x3a\x86\x30\x28\xb5\xe1\xdc\x0a" + "\x75\x86\x60\x2d\x25\x3c\xff\xf9" + "\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1", + .rlen = 32, + }, { + .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" + "\x2b\x73\xae\xf0\x85\x7d\x77\x81" + "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" + "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", + .klen = 32, + .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" + "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" + "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" + "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" + "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" + "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" + "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", + .ilen = 64, + .result = "\xf5\x8c\x4c\x04\xd6\xe5\xf1\xba" + "\x77\x9e\xab\xfb\x5f\x7b\xfb\xd6" + "\x9c\xfc\x4e\x96\x7e\xdb\x80\x8d" + "\x67\x9f\x77\x7b\xc6\x70\x2c\x7d" + "\x39\xf2\x33\x69\xa9\xd9\xba\xcf" + "\xa5\x30\xe2\x63\x04\x23\x14\x61" + "\xb2\xeb\x05\xe2\xc3\x9b\xe9\xfc" + "\xda\x6c\x19\x07\x8c\x6a\x9d\x1b", + .rlen = 64, + }, { /* Generated with Crypto++ */ + .key = "\xC9\x83\xA6\xC9\xEC\x0F\x32\x55" + "\x0F\x32\x55\x78\x9B\xBE\x78\x9B" + "\xBE\xE1\x04\x27\xE1\x04\x27\x4A" + "\x6D\x90\x4A\x6D\x90\xB3\xD6\xF9", + .klen = 32, + .iv = "\xE7\x82\x1D\xB8\x53\x11\xAC\x47" + "\xE2\x7D\x18\xD6\x71\x0C\xA7\x42", + .input = "\x50\xB9\x22\xAE\x17\x80\x0C\x75" + "\xDE\x47\xD3\x3C\xA5\x0E\x9A\x03" + "\x6C\xF8\x61\xCA\x33\xBF\x28\x91" + "\x1D\x86\xEF\x58\xE4\x4D\xB6\x1F" + "\xAB\x14\x7D\x09\x72\xDB\x44\xD0" + "\x39\xA2\x0B\x97\x00\x69\xF5\x5E" + "\xC7\x30\xBC\x25\x8E\x1A\x83\xEC" + "\x55\xE1\x4A\xB3\x1C\xA8\x11\x7A" + "\x06\x6F\xD8\x41\xCD\x36\x9F\x08" + "\x94\xFD\x66\xF2\x5B\xC4\x2D\xB9" + "\x22\x8B\x17\x80\xE9\x52\xDE\x47" + "\xB0\x19\xA5\x0E\x77\x03\x6C\xD5" + "\x3E\xCA\x33\x9C\x05\x91\xFA\x63" + "\xEF\x58\xC1\x2A\xB6\x1F\x88\x14" + "\x7D\xE6\x4F\xDB\x44\xAD\x16\xA2" + "\x0B\x74\x00\x69\xD2\x3B\xC7\x30" + "\x99\x02\x8E\xF7\x60\xEC\x55\xBE" + "\x27\xB3\x1C\x85\x11\x7A\xE3\x4C" + "\xD8\x41\xAA\x13\x9F\x08\x71\xFD" + "\x66\xCF\x38\xC4\x2D\x96\x22\x8B" + "\xF4\x5D\xE9\x52\xBB\x24\xB0\x19" + "\x82\x0E\x77\xE0\x49\xD5\x3E\xA7" + "\x10\x9C\x05\x6E\xFA\x63\xCC\x35" + "\xC1\x2A\x93\x1F\x88\xF1\x5A\xE6" + "\x4F\xB8\x21\xAD\x16\x7F\x0B\x74" + "\xDD\x46\xD2\x3B\xA4\x0D\x99\x02" + "\x6B\xF7\x60\xC9\x32\xBE\x27\x90" + "\x1C\x85\xEE\x57\xE3\x4C\xB5\x1E" + "\xAA\x13\x7C\x08\x71\xDA\x43\xCF" + "\x38\xA1\x0A\x96\xFF\x68\xF4\x5D" + "\xC6\x2F\xBB\x24\x8D\x19\x82\xEB" + "\x54\xE0\x49\xB2\x1B\xA7\x10\x79" + "\x05\x6E\xD7\x40\xCC\x35\x9E\x07" + "\x93\xFC\x65\xF1\x5A\xC3\x2C\xB8" + "\x21\x8A\x16\x7F\xE8\x51\xDD\x46" + "\xAF\x18\xA4\x0D\x76\x02\x6B\xD4" + "\x3D\xC9\x32\x9B\x04\x90\xF9\x62" + "\xEE\x57\xC0\x29\xB5\x1E\x87\x13" + "\x7C\xE5\x4E\xDA\x43\xAC\x15\xA1" + "\x0A\x73\xFF\x68\xD1\x3A\xC6\x2F" + "\x98\x01\x8D\xF6\x5F\xEB\x54\xBD" + "\x26\xB2\x1B\x84\x10\x79\xE2\x4B" + "\xD7\x40\xA9\x12\x9E\x07\x70\xFC" + "\x65\xCE\x37\xC3\x2C\x95\x21\x8A" + "\xF3\x5C\xE8\x51\xBA\x23\xAF\x18" + "\x81\x0D\x76\xDF\x48\xD4\x3D\xA6" + "\x0F\x9B\x04\x6D\xF9\x62\xCB\x34" + "\xC0\x29\x92\x1E\x87\xF0\x59\xE5" + "\x4E\xB7\x20\xAC\x15\x7E\x0A\x73" + "\xDC\x45\xD1\x3A\xA3\x0C\x98\x01" + "\x6A\xF6\x5F\xC8\x31\xBD\x26\x8F" + "\x1B\x84\xED\x56\xE2\x4B\xB4\x1D" + "\xA9\x12\x7B\x07\x70\xD9\x42\xCE" + "\x37\xA0\x09\x95\xFE\x67\xF3\x5C" + "\xC5\x2E\xBA\x23\x8C\x18\x81\xEA" + "\x53\xDF\x48\xB1\x1A\xA6\x0F\x78" + "\x04\x6D\xD6\x3F\xCB\x34\x9D\x06" + "\x92\xFB\x64\xF0\x59\xC2\x2B\xB7" + "\x20\x89\x15\x7E\xE7\x50\xDC\x45" + "\xAE\x17\xA3\x0C\x75\x01\x6A\xD3" + "\x3C\xC8\x31\x9A\x03\x8F\xF8\x61" + "\xED\x56\xBF\x28\xB4\x1D\x86\x12", + .ilen = 496, + .result = "\xEA\x65\x8A\x19\xB0\x66\xC1\x3F" + "\xCE\xF1\x97\x75\xC1\xFD\xB5\xAF" + "\x52\x65\xF7\xFF\xBC\xD8\x2D\x9F" + "\x2F\xB9\x26\x9B\x6F\x10\xB7\xB8" + "\x26\xA1\x02\x46\xA2\xAD\xC6\xC0" + "\x11\x15\xFF\x6D\x1E\x82\x04\xA6" + "\xB1\x74\xD1\x08\x13\xFD\x90\x7C" + "\xF5\xED\xD3\xDB\x5A\x0A\x0C\x2F" + "\x0A\x70\xF1\x88\x07\xCF\x21\x26" + "\x40\x40\x8A\xF5\x53\xF7\x24\x4F" + "\x83\x38\x43\x5F\x08\x99\xEB\xE3" + "\xDC\x02\x64\x67\x50\x6E\x15\xC3" + "\x01\x1A\xA0\x81\x13\x65\xA6\x73" + "\x71\xA6\x3B\x91\x83\x77\xBE\xFA" + "\xDB\x71\x73\xA6\xC1\xAE\x43\xC3" + "\x36\xCE\xD6\xEB\xF9\x30\x1C\x4F" + "\x80\x38\x5E\x9C\x6E\xAB\x98\x2F" + "\x53\xAF\xCF\xC8\x9A\xB8\x86\x43" + "\x3E\x86\xE7\xA1\xF4\x2F\x30\x40" + "\x03\xA8\x6C\x50\x42\x9F\x77\x59" + "\x89\xA0\xC5\xEC\x9A\xB8\xDD\x99" + "\x16\x24\x02\x07\x48\xAE\xF2\x31" + "\x34\x0E\xC3\x85\xFE\x1C\x95\x99" + "\x87\x58\x98\x8B\xE7\xC6\xC5\x70" + "\x73\x81\x07\x7C\x56\x2F\xD8\x1B" + "\xB7\xB9\x2B\xAB\xE3\x01\x87\x0F" + "\xD8\xBB\xC0\x0D\xAC\x2C\x2F\x98" + "\x3C\x0B\xA2\x99\x4A\x8C\xF7\x04" + "\xE0\xE0\xCF\xD1\x81\x5B\xFE\xF5" + "\x24\x04\xFD\xB8\xDF\x13\xD8\xCD" + "\xF1\xE3\x3D\x98\x50\x02\x77\x9E" + "\xBC\x22\xAB\xFA\xC2\x43\x1F\x66" + "\x20\x02\x23\xDA\xDF\xA0\x89\xF6" + "\xD8\xF3\x45\x24\x53\x6F\x16\x77" + "\x02\x3E\x7B\x36\x5F\xA0\x3B\x78" + "\x63\xA2\xBD\xB5\xA4\xCA\x1E\xD3" + "\x57\xBC\x0B\x9F\x43\x51\x28\x4F" + "\x07\x50\x6C\x68\x12\x07\xCF\xFA" + "\x6B\x72\x0B\xEB\xF8\x88\x90\x2C" + "\x7E\xF5\x91\xD1\x03\xD8\xD5\xBD" + "\x22\x39\x7B\x16\x03\x01\x69\xAF" + "\x3D\x38\x66\x28\x0C\xBE\x5B\xC5" + "\x03\xB4\x2F\x51\x8A\x56\x17\x2B" + "\x88\x42\x6D\x40\x68\x8F\xD0\x11" + "\x19\xF9\x1F\x43\x79\x95\x31\xFA" + "\x28\x7A\x3D\xF7\x66\xEB\xEF\xAC" + "\x06\xB2\x01\xAD\xDB\x68\xDB\xEC" + "\x8D\x53\x6E\x72\x68\xA3\xC7\x63" + "\x43\x2B\x78\xE0\x04\x29\x8F\x72" + "\xB2\x2C\xE6\x84\x03\x30\x6D\xCD" + "\x26\x92\x37\xE1\x2F\xBB\x8B\x9D" + "\xE4\x4C\xF6\x93\xBC\xD9\xAD\x44" + "\x52\x65\xC7\xB0\x0E\x3F\x0E\x61" + "\x56\x5D\x1C\x6D\xA7\x05\x2E\xBC" + "\x58\x08\x15\xAB\x12\xAB\x17\x4A" + "\x5E\x1C\xF2\xCD\xB8\xA2\xAE\xFB" + "\x9B\x2E\x0E\x85\x34\x80\x0E\x3F" + "\x4C\xB8\xDB\xCE\x1C\x90\xA1\x61" + "\x6C\x69\x09\x35\x9E\xD4\xF4\xAD" + "\xBC\x06\x41\xE3\x01\xB4\x4E\x0A" + "\xE0\x1F\x91\xF8\x82\x96\x2D\x65" + "\xA3\xAA\x13\xCC\x50\xFF\x7B\x02", + .rlen = 496, + }, +}; + +/* + * SHA256 test vectors from from NIST + */ +#define SHA256_TEST_VECTORS 2 + +static struct hash_testvec sha256_tv_template[] = { + { + .plaintext = "abc", + .psize = 3, + .digest = "\xba\x78\x16\xbf\x8f\x01\xcf\xea" + "\x41\x41\x40\xde\x5d\xae\x22\x23" + "\xb0\x03\x61\xa3\x96\x17\x7a\x9c" + "\xb4\x10\xff\x61\xf2\x00\x15\xad", + }, { + .plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .psize = 56, + .digest = "\x24\x8d\x6a\x61\xd2\x06\x38\xb8" + "\xe5\xc0\x26\x93\x0c\x3e\x60\x39" + "\xa3\x3c\xe4\x59\x64\xff\x21\x67" + "\xf6\xec\xed\xd4\x19\xdb\x06\xc1", + .np = 2, + .tap = { 28, 28 } + }, +}; + +/* + * HMAC-SHA256 test vectors from + * draft-ietf-ipsec-ciph-sha-256-01.txt + */ +#define HMAC_SHA256_TEST_VECTORS 10 + +static struct hash_testvec hmac_sha256_tv_template[] = { + { + .key = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20", + .ksize = 32, + .plaintext = "abc", + .psize = 3, + .digest = "\xa2\x1b\x1f\x5d\x4c\xf4\xf7\x3a" + "\x4d\xd9\x39\x75\x0f\x7a\x06\x6a" + "\x7f\x98\xcc\x13\x1c\xb1\x6a\x66" + "\x92\x75\x90\x21\xcf\xab\x81\x81", + }, { + .key = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20", + .ksize = 32, + .plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .psize = 56, + .digest = "\x10\x4f\xdc\x12\x57\x32\x8f\x08" + "\x18\x4b\xa7\x31\x31\xc5\x3c\xae" + "\xe6\x98\xe3\x61\x19\x42\x11\x49" + "\xea\x8c\x71\x24\x56\x69\x7d\x30", + }, { + .key = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20", + .ksize = 32, + .plaintext = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .psize = 112, + .digest = "\x47\x03\x05\xfc\x7e\x40\xfe\x34" + "\xd3\xee\xb3\xe7\x73\xd9\x5a\xab" + "\x73\xac\xf0\xfd\x06\x04\x47\xa5" + "\xeb\x45\x95\xbf\x33\xa9\xd1\xa3", + }, { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b", + .ksize = 32, + .plaintext = "Hi There", + .psize = 8, + .digest = "\x19\x8a\x60\x7e\xb4\x4b\xfb\xc6" + "\x99\x03\xa0\xf1\xcf\x2b\xbd\xc5" + "\xba\x0a\xa3\xf3\xd9\xae\x3c\x1c" + "\x7a\x3b\x16\x96\xa0\xb6\x8c\xf7", + }, { + .key = "Jefe", + .ksize = 4, + .plaintext = "what do ya want for nothing?", + .psize = 28, + .digest = "\x5b\xdc\xc1\x46\xbf\x60\x75\x4e" + "\x6a\x04\x24\x26\x08\x95\x75\xc7" + "\x5a\x00\x3f\x08\x9d\x27\x39\x83" + "\x9d\xec\x58\xb9\x64\xec\x38\x43", + .np = 2, + .tap = { 14, 14 } + }, { + .key = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + .ksize = 32, + .plaintext = "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + .psize = 50, + .digest = "\xcd\xcb\x12\x20\xd1\xec\xcc\xea" + "\x91\xe5\x3a\xba\x30\x92\xf9\x62" + "\xe5\x49\xfe\x6c\xe9\xed\x7f\xdc" + "\x43\x19\x1f\xbd\xe4\x5c\x30\xb0", + }, { + .key = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + "\x21\x22\x23\x24\x25", + .ksize = 37, + .plaintext = "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + .psize = 50, + .digest = "\xd4\x63\x3c\x17\xf6\xfb\x8d\x74" + "\x4c\x66\xde\xe0\xf8\xf0\x74\x55" + "\x6e\xc4\xaf\x55\xef\x07\x99\x85" + "\x41\x46\x8e\xb4\x9b\xd2\xe9\x17", + }, { + .key = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" + "\x0c\x0c\x0c\x0c\x0c\x0c", + .ksize = 32, + .plaintext = "Test With Truncation", + .psize = 20, + .digest = "\x75\x46\xaf\x01\x84\x1f\xc0\x9b" + "\x1a\xb9\xc3\x74\x9a\x5f\x1c\x17" + "\xd4\xf5\x89\x66\x8a\x58\x7b\x27" + "\x00\xa9\xc9\x7c\x11\x93\xcf\x42", + }, { + .key = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa", + .ksize = 80, + .plaintext = "Test Using Larger Than Block-Size Key - Hash Key First", + .psize = 54, + .digest = "\x69\x53\x02\x5e\xd9\x6f\x0c\x09" + "\xf8\x0a\x96\xf7\x8e\x65\x38\xdb" + "\xe2\xe7\xb8\x20\xe3\xdd\x97\x0e" + "\x7d\xdd\x39\x09\x1b\x32\x35\x2f", + }, { + .key = "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + "\xaa\xaa", + .ksize = 80, + .plaintext = "Test Using Larger Than Block-Size Key and Larger Than " + "One Block-Size Data", + .psize = 73, + .digest = "\x63\x55\xac\x22\xe8\x90\xd0\xa3" + "\xc8\x48\x1a\x5c\xa4\x82\x5b\xc8" + "\x84\xd3\xe7\xa1\xff\x98\xa2\xfc" + "\x2a\xc7\xd8\xe0\x64\xc3\xb2\xe6", + }, +}; + +static void hexdump(uint8_t *buf, uint32_t len) +{ + print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, + 16, 1, + buf, len, false); +} + +static int alloc_buf(char *buf[XBUFSIZE]) +{ + int i; + + for (i = 0; i < XBUFSIZE; i++) { + buf[i] = (void *)__get_free_page(GFP_KERNEL); + if (!buf[i]) + goto err_free_buf; + } + + return 0; + +err_free_buf: + while (i-- > 0) + free_page((unsigned long)buf[i]); + + return -ENOMEM; +} + +static void free_buf(char *buf[XBUFSIZE]) +{ + int i; + + for (i = 0; i < XBUFSIZE; i++) + free_page((unsigned long)buf[i]); +} + +static int aes_init(struct device *dev, int mode) +{ + int ret = 0; + const struct fips_fmp_ops *ops; + const struct of_device_id *match; + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + ops = (struct fips_fmp_ops *)match->data; + + ret = ops->init(dev, mode); + if (ret) { + dev_err(dev, "Fail to init aes. ret = %d\n", ret); + return ret; + } + + return ret; +} + +static int aes_set_iv(struct device *dev, int mode, uint8_t *iv, uint32_t iv_len) +{ + int ret = 0; + const struct fips_fmp_ops *ops; + const struct of_device_id *match; + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + ops = match->data; + + if (iv_len != 16) { + dev_err(dev, "Invalied iv length : %d\n", iv_len); + return -EINVAL; + } + + ret = ops->set_iv(dev, mode, iv, iv_len); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + return ret; + } + + return ret; +} + +static int aes_set_key(struct device *dev, int mode, uint8_t *in_key, uint32_t key_len) +{ + int ret = 0; + const struct fips_fmp_ops *ops; + const struct of_device_id *match; + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + ops = match->data; + + ret = ops->set_key(dev, mode, in_key, key_len); + if (ret) { + dev_err(dev, "Fail to set aes key, ret = %d\n", ret); + return ret; + } + + return ret; +} + +static int aes_run(struct device *dev, uint32_t mode, uint8_t *data, uint32_t len, uint32_t write) +{ + int ret = 0; + const struct fips_fmp_ops *ops; + const struct of_device_id *match; + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + ops = match->data; + + ret = ops->run(dev, mode, data, len, write); + if (ret) { + dev_err(dev, "Fail to encrypt. ret = %d\n", ret); + return ret; + } + + return ret; +} + +static int aes_exit(struct device *dev) +{ + int ret = 0; + const struct fips_fmp_ops *ops; + const struct of_device_id *match; + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + ops = (struct fips_fmp_ops *)match->data; + + ret = ops->exit(); + if (ret) { + dev_err(dev, "Fail to exit aes. ret = %d\n", ret); + return ret; + } + + return ret; +} + +static int fmp_aes_run(struct device *dev, struct cipher_testvec *template, const int idx, + uint8_t *data, uint32_t len, const int mode, uint32_t write) +{ + int ret; + + ret = aes_init(dev, mode); + if (ret) { + dev_err(dev, "Fail to init. ret = %d\n", ret); + goto err_init; + } + + ret = aes_set_key(dev, mode, template->key, template->klen); + if (ret) { + dev_err(dev, "Fail to set aes key. ret = %d\n", ret); + goto err_set_key; + } + + ret = aes_set_iv(dev, mode, template->iv, 16); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_set_iv; + } + + ret = aes_run(dev, mode, data, len, write); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_aes_set; + } + + ret = aes_exit(dev); + if (ret) { + dev_err(dev, "Fail to exit. ret = %d\n", ret); + goto err_exit; + } + + return 0; + +err_set_key: +err_set_iv: +err_aes_set: + aes_exit(dev); +err_init: +err_exit: + return -1; +} + +int fips_fmp_cipher_init(struct device *dev, uint8_t *enckey, uint8_t *twkey, uint32_t key_len, uint32_t mode) +{ + int ret; + uint8_t *key; + + ret = aes_init(dev, mode); + if (ret) { + dev_err(dev, "Fail to init. ret = %d\n", ret); + goto err_init; + } + + if (twkey) { + key = (uint8_t *)kmalloc(key_len * 2, GFP_KERNEL); + memcpy(key, enckey, key_len); + memcpy(key + key_len, twkey, key_len); + key_len *= 2; + } else { + key = (uint8_t *)kmalloc(key_len, GFP_KERNEL); + memcpy(key, enckey, key_len); + } + + ret = aes_set_key(dev, mode, key, key_len); + if (ret) { + dev_err(dev, "Fail to set aes key. ret = %d\n", ret); + goto err_set_key; + } + + return 0; + +err_set_key: + aes_exit(dev); +err_init: + return -1; +} +EXPORT_SYMBOL_GPL(fips_fmp_cipher_init); + +int fips_fmp_cipher_set_iv(struct device *dev, uint8_t *iv, uint32_t mode) +{ + int ret; + + ret = aes_set_iv(dev, mode, iv, 16); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_set_iv; + } + + return 0; + +err_set_iv: + return -1; +} +EXPORT_SYMBOL_GPL(fips_fmp_cipher_set_iv); + +int fips_fmp_cipher_run(struct device *dev, uint8_t *src, uint8_t *dst, uint32_t len, uint32_t mode, uint32_t enc) +{ + int ret; + + if (enc == ENCRYPT) { + ret = aes_run(dev, mode, src, len, WRITE_MODE); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_aes_set; + } + + ret = aes_run(dev, BYPASS_MODE, dst, len, READ_MODE); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_aes_set; + } + } else { + ret = aes_run(dev, BYPASS_MODE, src, len, WRITE_MODE); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_aes_set; + } + + ret = aes_run(dev, mode, dst, len, READ_MODE); + if (ret) { + dev_err(dev, "Fail to set aes iv. ret = %d\n", ret); + goto err_aes_set; + } + } + + return 0; + +err_aes_set: + return -1; +} +EXPORT_SYMBOL_GPL(fips_fmp_cipher_run); + +int fips_fmp_cipher_exit(struct device *dev) +{ + int ret; + + ret = aes_exit(dev); + if (ret) { + dev_err(dev, "Fail to exit. ret = %d\n", ret); + goto err_exit; + } + + return 0; +err_exit: + return -1; +} +EXPORT_SYMBOL_GPL(fips_fmp_cipher_exit); + +static int test_cipher(struct device *dev, int mode, struct cipher_testvec *template, uint32_t tcount) +{ + int ret; + uint32_t idx; + char *inbuf[XBUFSIZE]; + char *outbuf[XBUFSIZE]; + void *indata, *outdata; + + if (alloc_buf(inbuf)) { + dev_err(dev, "Fail to alloc input buf.\n"); + goto err_alloc_inbuf; + } + + if (alloc_buf(outbuf)) { + dev_err(dev, "Fail to alloc output buf.\n"); + goto err_alloc_outbuf; + } + + for (idx = 0; idx < tcount; idx++) { + if (template[idx].np) + continue; + + if (WARN_ON(template[idx].ilen > PAGE_SIZE)) { + dev_err(dev, "Invalid input length. ilen = %d\n", template[idx].ilen); + goto err_ilen; + } + + indata = inbuf[0]; + outdata = outbuf[0]; + memset(indata, 0, FMP_BLK_SIZE); + memcpy(indata, template[idx].input, template[idx].ilen); + + if (template[idx].ilen > PAGE_SIZE) { + dev_err(dev, "Fail to fmp aes cipher due to invalid input length = %d\n", template[idx].ilen); + goto err_aes_run; + } + + ret = fmp_aes_run(dev, &template[idx], idx, indata, template[idx].ilen, mode, WRITE_MODE); + if (ret) { + dev_err(dev, "Fail to set aes encrypt run. ret = %d\n", ret); + goto err_aes_run; + } + + memset(outdata, 0, FMP_BLK_SIZE); + ret = fmp_aes_run(dev, &template[idx], idx, outdata, template[idx].ilen, BYPASS_MODE, READ_MODE); + if (ret) { + dev_err(dev, "Fail to set aes bypass run. ret = %d\n", ret); + goto err_aes_run; + } + + if (memcmp(outdata, template[idx].result, template[idx].rlen)) { + dev_err(dev, "Fail to compare encrypted result.\n"); + hexdump(outdata, template[idx].rlen); + goto err_cmp; + } + } + + free_buf(inbuf); + free_buf(outbuf); + + return 0; + +err_ilen: +err_aes_run: +err_cmp: + free_buf(outbuf); +err_alloc_outbuf: + free_buf(inbuf); +err_alloc_inbuf: + + return -1; +} + +struct fmp_test_result { + struct completion completion; + int err; +}; + +static int do_one_async_hash_op(struct ahash_request *req, + struct fmp_test_result *tr, + int ret) +{ + if (ret == -EINPROGRESS || ret == -EBUSY) { + ret = wait_for_completion_interruptible(&tr->completion); + if (!ret) + ret = tr->err; + INIT_COMPLETION(tr->completion); + } + return ret; +} + +static void test_complete(struct crypto_async_request *req, int err) +{ + struct fmp_test_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + unsigned int tcount, bool use_digest) +{ + const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); + unsigned int i, j, k, temp; + struct scatterlist sg[8]; + char result[64]; + struct ahash_request *req; + struct fmp_test_result tresult; + void *hash_buff; + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + + if (alloc_buf(xbuf)) + goto out_nobuf; + + init_completion(&tresult.completion); + + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk(KERN_ERR "alg: hash: Failed to allocate request for " + "%s\n", algo); + goto out_noreq; + } + ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + test_complete, &tresult); + + j = 0; + for (i = 0; i < tcount; i++) { + if (template[i].np) + continue; + + j++; + memset(result, 0, 64); + + hash_buff = xbuf[0]; + + memcpy(hash_buff, template[i].plaintext, template[i].psize); + sg_init_one(&sg[0], hash_buff, template[i].psize); + + if (template[i].ksize) { + crypto_ahash_clear_flags(tfm, ~0); + ret = crypto_ahash_setkey(tfm, template[i].key, + template[i].ksize); + if (ret) { + printk(KERN_ERR "alg: hash: setkey failed on " + "test %d for %s: ret=%d\n", j, algo, + -ret); + goto out; + } + } + + ahash_request_set_crypt(req, sg, result, template[i].psize); + if (use_digest) { + ret = do_one_async_hash_op(req, &tresult, + crypto_ahash_digest(req)); + if (ret) { + pr_err("alg: hash: digest failed on test %d " + "for %s: ret=%d\n", j, algo, -ret); + goto out; + } + } else { + ret = do_one_async_hash_op(req, &tresult, + crypto_ahash_init(req)); + if (ret) { + pr_err("alt: hash: init failed on test %d " + "for %s: ret=%d\n", j, algo, -ret); + goto out; + } + ret = do_one_async_hash_op(req, &tresult, + crypto_ahash_update(req)); + if (ret) { + pr_err("alt: hash: update failed on test %d " + "for %s: ret=%d\n", j, algo, -ret); + goto out; + } + ret = do_one_async_hash_op(req, &tresult, + crypto_ahash_final(req)); + if (ret) { + pr_err("alt: hash: final failed on test %d " + "for %s: ret=%d\n", j, algo, -ret); + goto out; + } + } + + if (memcmp(result, template[i].digest, + crypto_ahash_digestsize(tfm))) { + printk(KERN_ERR "alg: hash: Test %d failed for %s\n", + j, algo); + hexdump(result, crypto_ahash_digestsize(tfm)); + ret = -EINVAL; + goto out; + } + } + + j = 0; + for (i = 0; i < tcount; i++) { + if (template[i].np) { + j++; + memset(result, 0, 64); + + temp = 0; + sg_init_table(sg, template[i].np); + ret = -EINVAL; + for (k = 0; k < template[i].np; k++) { + if (WARN_ON(offset_in_page(IDX[k]) + + template[i].tap[k] > PAGE_SIZE)) + goto out; + sg_set_buf(&sg[k], + memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + + offset_in_page(IDX[k]), + template[i].plaintext + temp, + template[i].tap[k]), + template[i].tap[k]); + temp += template[i].tap[k]; + } + + if (template[i].ksize) { + crypto_ahash_clear_flags(tfm, ~0); + ret = crypto_ahash_setkey(tfm, template[i].key, + template[i].ksize); + + if (ret) { + printk(KERN_ERR "alg: hash: setkey " + "failed on chunking test %d " + "for %s: ret=%d\n", j, algo, + -ret); + goto out; + } + } + + ahash_request_set_crypt(req, sg, result, + template[i].psize); + ret = crypto_ahash_digest(req); + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &tresult.completion); + if (!ret && !(ret = tresult.err)) { + INIT_COMPLETION(tresult.completion); + break; + } + /* fall through */ + default: + printk(KERN_ERR "alg: hash: digest failed " + "on chunking test %d for %s: " + "ret=%d\n", j, algo, -ret); + goto out; + } + + if (memcmp(result, template[i].digest, + crypto_ahash_digestsize(tfm))) { + printk(KERN_ERR "alg: hash: Chunking test %d " + "failed for %s\n", j, algo); + hexdump(result, crypto_ahash_digestsize(tfm)); + ret = -EINVAL; + goto out; + } + } + } + + ret = 0; + +out: + ahash_request_free(req); +out_noreq: + free_buf(xbuf); +out_nobuf: + return ret; +} + +static int alg_test_hash(const struct hash_test_suite *suite, const char *driver, u32 type, u32 mask) +{ + struct crypto_ahash *tfm; + int err; + + tfm = crypto_alloc_ahash(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: hash: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + + err = test_hash(tfm, suite->vecs, suite->count, true); + if (!err) + err = test_hash(tfm, suite->vecs, suite->count, false); + + crypto_free_ahash(tfm); + return err; +} + +static int do_fmp_fw_selftest(void) +{ + int err = 0; + + err = exynos_smc(SMC_CMD_FMP, FMP_FW_SELFTEST, 0, 0); + if (err) { + printk(KERN_ERR "Fail to check selftest for FMP F/W. err = 0x%x\n", err); + return -1; + } + + return 0; +} + +static int do_fips_fmp_selftest(struct device *dev) +{ + int ret; + struct cipher_test_suite xts_cipher; + struct cipher_test_suite cbc_cipher; + struct hash_test_suite test_hmac_sha256; + struct hash_test_suite test_sha256; + + /* Self test for AES XTS mode */ + xts_cipher.enc.vecs = aes_xts_enc_tv_template; + xts_cipher.enc.count = AES_XTS_ENC_TEST_VECTORS; + ret = test_cipher(dev, XTS_MODE, xts_cipher.enc.vecs, xts_cipher.enc.count); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for UFSFMP aes-xts failed\n"); + goto err_xts_cipher; + } + printk(KERN_INFO "FIPS: self-tests for UFSFMP aes-xts passed\n"); + + /* Self test for AES CBC mode */ + cbc_cipher.enc.vecs = aes_cbc_enc_tv_template; + cbc_cipher.enc.count = AES_CBC_ENC_TEST_VECTORS; + ret = test_cipher(dev, CBC_MODE, cbc_cipher.enc.vecs, cbc_cipher.enc.count); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for UFSFMP aes-cbc failed\n"); + goto err_cbc_cipher; + } + printk(KERN_INFO "FIPS: self-tests for UFSFMP aes-cbc passed\n"); + + test_sha256.vecs = sha256_tv_template; + test_sha256.count = SHA256_TEST_VECTORS; + ret = alg_test_hash(&test_sha256, ALG_SHA256_FMP, 0, 0); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for UFSFMP %s failed\n", ALG_SHA256_FMP); + goto err_xts_cipher; + } + printk(KERN_INFO "FIPS: self-tests for UFSFMP %s passed\n", ALG_SHA256_FMP); + + test_hmac_sha256.vecs = hmac_sha256_tv_template; + test_hmac_sha256.count = HMAC_SHA256_TEST_VECTORS; + ret = alg_test_hash(&test_hmac_sha256, ALG_HMAC_SHA256_FMP, 0, 0); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for UFSFMP %s failed\n", ALG_HMAC_SHA256_FMP); + goto err_xts_cipher; + } + printk(KERN_INFO "FIPS: self-tests for UFSFMP %s passed\n", ALG_HMAC_SHA256_FMP); + + ret = do_fmp_fw_selftest(); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for FMP FW failed\n"); + goto err_fw_selftest; + } + printk(KERN_INFO "FIPS: self-tests for FMP FW passed\n"); + + return 0; + +err_cbc_cipher: +err_xts_cipher: +err_fw_selftest: + return -1; +} + +static ssize_t fips_fmp_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", fips_fmp_result ? pass : fail); +} + +static DEVICE_ATTR(fips_fmp_status, 0444, fips_fmp_status_show, NULL); + +static struct attribute *fips_fmp_attr[] = { + &dev_attr_fips_fmp_status.attr, + NULL, +}; + +static struct attribute_group fips_fmp_attr_group = { + .name = "fips-fmp", + .attrs = fips_fmp_attr, +}; + +static int fmp_create_session(struct fmp_info *info, + struct fcrypt *fcr, struct session_op *sop) +{ + int ret = 0; + struct device *dev = info->dev; + struct csession *ses_new = NULL, *ses_ptr; + const char *alg_name = NULL; + const char *hash_name = NULL; + int hmac_mode = 1; + int fw_mode = 0; + + /* + * With composite aead ciphers, only ckey is used and it can cover all the + * structure space; otherwise both keys may be used simultaneously but they + * are confined to their spaces + */ + struct { + uint8_t mkey[FMP_HMAC_MAX_KEY_LEN]; + /* padding space for aead keys */ + uint8_t pad[RTA_SPACE(sizeof(struct crypto_authenc_key_param))]; + } keys; + + if (unlikely(!sop->cipher && !sop->mac)) { + dev_err(dev, "Both 'cipher' and 'mac' unset.\n"); + return -EINVAL; + } + + switch (sop->cipher) { + case 0: + break; + case FMP_AES_CBC: + alg_name = "cbc(aes-fmp)"; + break; + case FMP_AES_XTS: + alg_name = "xts(aes-fmp)"; + break; + default: + dev_err(dev, "Invalid cipher : %d\n", sop->cipher); + return -EINVAL; + } + + switch (sop->mac) { + case 0: + break; + case FMP_SHA2_256_HMAC: + hash_name = "hmac-fmp(sha256-fmp)"; + break; + case FMP_SHA2_256: + hash_name = "sha256-fmp"; + hmac_mode = 0; + break; + case FMPFW_SHA2_256_HMAC: + hash_name = "hmac-fmpfw(sha256-fmp)"; + fw_mode = 1; + break; + case FMPFW_SHA2_256: + hash_name = "sha256-fmpfw"; + fw_mode = 1; + hmac_mode = 0; + break; + default: + dev_err(dev, "Invalid mac : %d\n", sop->mac); + return -EINVAL; + } + + /* Create a session and put it to the list. */ + ses_new = kzalloc(sizeof(*ses_new), GFP_KERNEL); + if (!ses_new) { + dev_err(dev, "Fail to allocate session buffer\n"); + return -ENOMEM; + } + + /* Set-up crypto transform. */ + if (alg_name) { + uint8_t keyp[FMP_CIPHER_MAX_KEY_LEN]; + if (unlikely(sop->keylen > FMP_CIPHER_MAX_KEY_LEN)) { + dev_err(dev, "Setting key failed for %s-%zu.\n", + alg_name, (size_t)sop->keylen*8); + ret = -EINVAL; + goto error_cipher; + } + if (unlikely(copy_from_user(keyp, sop->key, sop->keylen))) { + ret = -EFAULT; + goto error_cipher; + } + + if (!strcmp(alg_name, "xts(aes-fmp)")) + ret = fmpdev_cipher_init(info, &ses_new->cdata, alg_name, \ + keyp, keyp + (sop->keylen >> 1), sop->keylen >> 1); + else + ret = fmpdev_cipher_init(info, &ses_new->cdata, alg_name, \ + keyp, NULL, sop->keylen); + if (ret < 0) { + dev_err(dev, "%s: Fail to load cipher for %s\n", + __func__, alg_name); + ret = -EINVAL; + goto error_cipher; + } + info->init_status = 1; + } + + if (hash_name) { + if (unlikely(sop->mackeylen > FMP_HMAC_MAX_KEY_LEN)) { + dev_err(dev, "Setting key failed for %s-%zu.", + hash_name, (size_t)sop->mackeylen*8); + ret = -EINVAL; + goto error_hash; + } + + if (sop->mackey && unlikely(copy_from_user(keys.mkey, sop->mackey, + sop->mackeylen))) { + ret = -EFAULT; + goto error_hash; + } + + if (fw_mode) + ret = fmpfw_hash_init(info, &ses_new->hdata, hash_name, + hmac_mode, keys.mkey, + sop->mackeylen); + else + ret = fmpdev_hash_init(info, &ses_new->hdata, hash_name, + hmac_mode, keys.mkey, + sop->mackeylen); + if (ret != 0) { + dev_err(dev, "Failed to load hash for %s", hash_name); + ret = -EINVAL; + goto error_hash; + } + } + + ses_new->alignmask = max(ses_new->cdata.alignmask, + ses_new->hdata.alignmask); + ses_new->array_size = DEFAULT_PREALLOC_PAGES; + ses_new->pages = kzalloc(ses_new->array_size * + sizeof(struct page *), GFP_KERNEL); + ses_new->sg = kzalloc(ses_new->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + if (ses_new->sg == NULL || ses_new->pages == NULL) { + dev_err(dev, "Memory error\n"); + ret = -ENOMEM; + goto error_hash; + } + + /* put the new session to the list */ + get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); + mutex_init(&ses_new->sem); + + mutex_lock(&fcr->sem); +restart: + list_for_each_entry(ses_ptr, &fcr->list, entry) { + /* Check for duplicate SID */ + if (unlikely(ses_new->sid == ses_ptr->sid)) { + get_random_bytes(&ses_new->sid, sizeof(ses_new->sid)); + /* Unless we have a broken RNG this + shouldn't loop forever... ;-) */ + goto restart; + } + } + + list_add(&ses_new->entry, &fcr->list); + mutex_unlock(&fcr->sem); + + /* Fill in some values for the user. */ + sop->ses = ses_new->sid; + + return 0; + +error_hash: + fmpdev_cipher_deinit(&ses_new->cdata); + kfree(ses_new->sg); + kfree(ses_new->pages); +error_cipher: + kfree(ses_new); + return ret; +} + +static inline void fmp_destroy_session(struct fmp_info *info, struct csession *ses_ptr) +{ + struct device *dev = info->dev; + + if (!mutex_trylock(&ses_ptr->sem)) { + dev_err(dev, "Waiting for semaphore of sid=0x%08X\n", ses_ptr->sid); + mutex_lock(&ses_ptr->sem); + } + fmpdev_cipher_deinit(&ses_ptr->cdata); + if (!ses_ptr->hdata.fmpfw_info) + fmpdev_hash_deinit(&ses_ptr->hdata); + else + fmpfw_hash_deinit(&ses_ptr->hdata); + kfree(ses_ptr->pages); + kfree(ses_ptr->sg); + mutex_unlock(&ses_ptr->sem); + mutex_destroy(&ses_ptr->sem); + kfree(ses_ptr); +} + +/* Look up a session by ID and remove. */ +static int fmp_finish_session(struct fmp_info *info, struct fcrypt *fcr, uint32_t sid) +{ + struct device *dev = info->dev; + struct csession *tmp, *ses_ptr; + struct list_head *head; + int ret = 0; + + mutex_lock(&fcr->sem); + head = &fcr->list; + + if (info->init_status) { + ret = fmpdev_cipher_exit(info); + if (ret < 0) { + dev_err(dev, "Fail to exit fmp dev. sid = %d\n", sid); + ret = -ENOENT; + } + info->init_status = 0; + } + + list_for_each_entry_safe(ses_ptr, tmp, head, entry) { + if (ses_ptr->sid == sid) { + list_del(&ses_ptr->entry); + fmp_destroy_session(info, ses_ptr); + break; + } + } + + if (unlikely(!ses_ptr)) { + dev_err(dev, "Session with sid=0x%08X not found!\n", sid); + ret = -ENOENT; + } + mutex_unlock(&fcr->sem); + + return ret; +} + +/* Remove all sessions when closing the file */ +static int fmp_finish_all_sessions(struct fmp_info *info, struct fcrypt *fcr) +{ + struct csession *tmp, *ses_ptr; + struct list_head *head; + + mutex_lock(&fcr->sem); + + head = &fcr->list; + list_for_each_entry_safe(ses_ptr, tmp, head, entry) { + list_del(&ses_ptr->entry); + fmp_destroy_session(info, ses_ptr); + } + mutex_unlock(&fcr->sem); + + return 0; +} + +/* Look up session by session ID. The returned session is locked. */ +struct csession *fmp_get_session_by_sid(struct fcrypt *fcr, uint32_t sid) +{ + struct csession *ses_ptr, *retval = NULL; + + if (unlikely(fcr == NULL)) + return NULL; + + mutex_lock(&fcr->sem); + list_for_each_entry(ses_ptr, &fcr->list, entry) { + if (ses_ptr->sid == sid) { + mutex_lock(&ses_ptr->sem); + retval = ses_ptr; + break; + } + } + mutex_unlock(&fcr->sem); + + return retval; +} + +static void fmptask_routine(struct work_struct *work) +{ + struct fmp_info *info = container_of(work, struct fmp_info, fmptask); + struct device *dev = info->dev; + struct todo_list_item *item; + LIST_HEAD(tmp); + + /* fetch all pending jobs into the temporary list */ + mutex_lock(&info->todo.lock); + list_cut_position(&tmp, &info->todo.list, info->todo.list.prev); + mutex_unlock(&info->todo.lock); + + /* handle each job locklessly */ + list_for_each_entry(item, &tmp, __hook) { + item->result = fmp_run(info, &info->fcrypt, &item->kcop); + if (unlikely(item->result)) + dev_err(dev, "%s: crypto_run() failed: %d\n", + __func__, item->result); + } + + /* push all handled jobs to the done list at once */ + mutex_lock(&info->done.lock); + list_splice_tail(&tmp, &info->done.list); + mutex_unlock(&info->done.lock); + + /* wake for POLLIN */ + wake_up_interruptible(&info->user_waiter); +} + +static int find_fmp_device_by_node(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL, "samsung,exynos-fips-fmp"); + if (!np) { + printk("Fail to find device node for fmp\n"); + return -ENODEV; + } + + pdev = of_find_device_by_node(np); + if (!pdev) { + printk("Fail to find pdev for fmp\n"); + return -ENODEV; + } + + return 0; +} + +static int fmpdev_open(struct inode *inode, struct file *file) +{ + int i, ret; + struct fmp_info *info; + struct todo_list_item *tmp; + struct device *dev; + + ret = find_fmp_device_by_node(); + if (ret) { + printk("Fail to find fmp device by node\n"); + return -1; + } + + dev = &pdev->dev; + printk("fmp fips driver name : %s\n", dev_name(dev)); + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(dev, "fail to alloc fmp private data\n"); + return -ENOMEM; + } + memset(info, 0, sizeof(*info)); + + mutex_init(&info->fcrypt.sem); + INIT_LIST_HEAD(&info->fcrypt.list); + + INIT_LIST_HEAD(&info->free.list); + INIT_LIST_HEAD(&info->todo.list); + INIT_LIST_HEAD(&info->done.list); + INIT_WORK(&info->fmptask, fmptask_routine); + mutex_init(&info->free.lock); + mutex_init(&info->todo.lock); + mutex_init(&info->done.lock); + init_waitqueue_head(&info->user_waiter); + + for (i = 0; i < DEF_COP_RINGSIZE; i++) { + tmp = kzalloc(sizeof(struct todo_list_item), GFP_KERNEL); + info->itemcount++; + dev_info(dev, "%s: allocated new item at %lx\n", + __func__, (unsigned long)tmp); + list_add(&tmp->__hook, &info->free.list); + } + + info->dev = dev; + file->private_data = info; + + dev_info(dev, "%s opened.\n", dev_name(dev)); + + return 0; +} + +/* this function has to be called from process context */ +static int fill_kcop_from_cop(struct fmp_info *info, + struct kernel_crypt_op *kcop, struct fcrypt *fcr) +{ + struct device *dev = info->dev; + struct crypt_op *cop = &kcop->cop; + struct csession *ses_ptr; + int rc; + + /* this also enters ses_ptr->sem */ + ses_ptr = fmp_get_session_by_sid(fcr, cop->ses); + if (unlikely(!ses_ptr)) { + dev_err(dev, "invalid session ID=0x%08X\n", cop->ses); + return -EINVAL; + } + kcop->digestsize = 0; /* will be updated during operation */ + + fmp_put_session(ses_ptr); + + kcop->task = current; + kcop->mm = current->mm; + + if (cop->iv) { + kcop->ivlen = ses_ptr->cdata.ivsize; + rc = copy_from_user(kcop->iv, cop->iv, kcop->ivlen); + if (unlikely(rc)) { + dev_err(dev, + "error copying IV (%d bytes), copy_from_user returned %d for address %lx\n", + kcop->ivlen, rc, (unsigned long)cop->iv); + return -EFAULT; + } + } else { + kcop->ivlen = 0; + } + + return 0; +} + +/* this function has to be called from process context */ +static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr) +{ + int ret; + + if (kcop->digestsize) { + ret = copy_to_user(kcop->cop.mac, + kcop->hash_output, kcop->digestsize); + if (unlikely(ret)) + return -EFAULT; + } + if (kcop->ivlen && kcop->cop.flags & COP_FLAG_WRITE_IV) { + ret = copy_to_user(kcop->cop.iv, + kcop->iv, kcop->ivlen); + if (unlikely(ret)) + return -EFAULT; + } + return 0; +} + + +static int kcop_from_user(struct fmp_info *info, struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + if (unlikely(copy_from_user(&kcop->cop, arg, sizeof(kcop->cop)))) + return -EFAULT; + + return fill_kcop_from_cop(info, kcop, fcr); +} + +static int kcop_to_user(struct fmp_info *info, struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + int ret; + struct device *dev = info->dev; + + ret = fill_cop_from_kcop(kcop, fcr); + if (unlikely(ret)) { + dev_err(dev, "Error in fill_cop_from_kcop\n"); + return ret; + } + + if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop)))) { + dev_err(dev, "Cannot copy to userspace\n"); + return -EFAULT; + } + return 0; +} + +static inline void tfm_info_to_alg_info(struct alg_info *dst, struct crypto_tfm *tfm) +{ + snprintf(dst->cra_name, FMPDEV_MAX_ALG_NAME, + "%s", crypto_tfm_alg_name(tfm)); + snprintf(dst->cra_driver_name, FMPDEV_MAX_ALG_NAME, + "%s", crypto_tfm_alg_driver_name(tfm)); +} + +static int get_session_info(struct fmp_info *info, + struct fcrypt *fcr, struct session_info_op *siop) +{ + struct csession *ses_ptr; + struct device *dev = info->dev; + struct crypto_tfm *tfm; + + /* this also enters ses_ptr->sem */ + ses_ptr = fmp_get_session_by_sid(fcr, siop->ses); + if (unlikely(!ses_ptr)) { + dev_err(dev, "invalid session ID=0x%08X\n", siop->ses); + return -EINVAL; + } + + siop->flags = 0; + + if (ses_ptr->hdata.init && !ses_ptr->hdata.fmpfw_info) { + tfm = crypto_ahash_tfm(ses_ptr->hdata.async.s); + tfm_info_to_alg_info(&siop->hash_info, tfm); +#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY + if (tfm->__crt_alg->cra_flags & CRYPTO_ALG_KERN_DRIVER_ONLY) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#else + if (is_known_accelerated(tfm)) + siop->flags |= SIOP_FLAG_KERNEL_DRIVER_ONLY; +#endif + } + + siop->alignmask = ses_ptr->alignmask; + fmp_put_session(ses_ptr); + + return 0; +} + +static long fmpdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg_) +{ + int ret; + struct session_op sop; + struct kernel_crypt_op kcop; + struct fmp_info *info = file->private_data; + struct device *dev = info->dev; + void __user *arg = (void __user *)arg_; + struct fcrypt *fcr; + struct session_info_op siop; + uint32_t ses; + + if (unlikely(!info)) + BUG(); + + fcr = &info->fcrypt; + + switch (cmd) { + case FMPGSESSION: + if (unlikely(copy_from_user(&sop, arg, sizeof(sop)))) + return -EFAULT; + + ret = fmp_create_session(info, fcr, &sop); + if (unlikely(ret)) { + dev_err(dev, "Fail to create fmp session. ret = %d\n", ret); + return ret; + } + ret = copy_to_user(arg, &sop, sizeof(sop)); + if (unlikely(ret)) { + fmp_finish_session(info, fcr, sop.ses); + return -EFAULT; + } + return ret; + case FMPFSESSION: + ret = get_user(ses, (uint32_t __user *)arg); + if (unlikely(ret)) + return ret; + ret = fmp_finish_session(info, fcr, ses); + if (unlikely(ret)) + dev_err(dev, "Fail to finish fmp session. ret = %d\n", ret); + return ret; + case FMPGSESSIONINFO: + if (unlikely(copy_from_user(&siop, arg, sizeof(siop)))) + return -EFAULT; + + ret = get_session_info(info, fcr, &siop); + if (unlikely(ret)) { + dev_err(dev, "Fail to get fmp session. ret = %d\n", ret); + return ret; + } + return copy_to_user(arg, &siop, sizeof(siop)); + case FMPCRYPT: + if (unlikely(ret = kcop_from_user(info, &kcop, fcr, arg))) + return ret; + + if (unlikely(in_fmp_fips_err())) { + dev_err(dev, "Fail to run fmp due to fips in error."); + return -EPERM; + } + + ret = fmp_run(info, fcr, &kcop); + if (unlikely(ret)) { + dev_err(dev, "Fail to run fmp crypt. ret = %d\n", ret); + return ret; + } + return kcop_to_user(info, &kcop, fcr, arg); + case FMP_AES_CBC_MCT: + if (unlikely(ret = kcop_from_user(info, &kcop, fcr, arg))) { + dev_err(dev, "Error copying from user"); + return ret; + } + + if (unlikely(in_fmp_fips_err())) { + dev_err(dev, "Fail to run fmp due to fips in error."); + return -EPERM; + } + + ret = fmp_run_AES_CBC_MCT(info, fcr, &kcop); + if (unlikely(ret)) { + dev_err(dev, "Error in fmp_run_AES_CBC_MCT"); + return ret; + } + return kcop_to_user(info, &kcop, fcr, arg); + default: + dev_err(dev, "Invalid command : 0x%x\n", cmd); + return -EINVAL; + } +} + +/* compatibility code for 32bit userlands */ +#ifdef CONFIG_COMPAT +static inline void compat_to_session_op(struct compat_session_op *compat, + struct session_op *sop) +{ + sop->cipher = compat->cipher; + sop->mac = compat->mac; + sop->keylen = compat->keylen; + + sop->key = compat_ptr(compat->key); + sop->mackeylen = compat->mackeylen; + sop->mackey = compat_ptr(compat->mackey); + sop->ses = compat->ses; +} + +static inline void session_op_to_compat(struct session_op *sop, + struct compat_session_op *compat) +{ + compat->cipher = sop->cipher; + compat->mac = sop->mac; + compat->keylen = sop->keylen; + + compat->key = ptr_to_compat(sop->key); + compat->mackeylen = sop->mackeylen; + compat->mackey = ptr_to_compat(sop->mackey); + compat->ses = sop->ses; +} + +static inline void compat_to_crypt_op(struct compat_crypt_op *compat, + struct crypt_op *cop) +{ + cop->ses = compat->ses; + cop->op = compat->op; + cop->flags = compat->flags; + cop->len = compat->len; + + cop->src = compat_ptr(compat->src); + cop->dst = compat_ptr(compat->dst); + cop->mac = compat_ptr(compat->mac); + cop->iv = compat_ptr(compat->iv); + cop->secondLastEncodedData = compat_ptr(compat->secondLastEncodedData); + cop->thirdLastEncodedData = compat_ptr(compat->thirdLastEncodedData); +} + +static inline void crypt_op_to_compat(struct crypt_op *cop, + struct compat_crypt_op *compat) +{ + compat->ses = cop->ses; + compat->op = cop->op; + compat->flags = cop->flags; + compat->len = cop->len; + + compat->src = ptr_to_compat(cop->src); + compat->dst = ptr_to_compat(cop->dst); + compat->mac = ptr_to_compat(cop->mac); + compat->iv = ptr_to_compat(cop->iv); + compat->secondLastEncodedData = ptr_to_compat(cop->secondLastEncodedData); + compat->thirdLastEncodedData = ptr_to_compat(cop->thirdLastEncodedData); +} + +static int compat_kcop_from_user(struct fmp_info *info, + struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + struct compat_crypt_op compat_cop; + + if (unlikely(copy_from_user(&compat_cop, arg, sizeof(compat_cop)))) + return -EFAULT; + compat_to_crypt_op(&compat_cop, &kcop->cop); + + return fill_kcop_from_cop(info, kcop, fcr); +} + +static int compat_kcop_to_user(struct fmp_info *info, + struct kernel_crypt_op *kcop, + struct fcrypt *fcr, void __user *arg) +{ + int ret; + struct device *dev = info->dev; + struct compat_crypt_op compat_cop; + + ret = fill_cop_from_kcop(kcop, fcr); + if (unlikely(ret)) { + dev_err(dev, "Error in fill_cop_from_kcop"); + return ret; + } + crypt_op_to_compat(&kcop->cop, &compat_cop); + + if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop)))) { + dev_err(dev, "Error copying to user"); + return -EFAULT; + } + return 0; +} + +static long fmpdev_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg_) +{ + int ret; + struct session_op sop; + struct compat_session_op compat_sop; + struct kernel_crypt_op kcop; + struct fmp_info *info = file->private_data; + struct device *dev = info->dev; + void __user *arg = (void __user *)arg_; + struct fcrypt *fcr; + + if (unlikely(info)) + BUG(); + + fcr = &info->fcrypt; + + switch (cmd) { + case FMPFSESSION: + case FMPGSESSIONINFO: + return fmpdev_ioctl(file, cmd, arg_); + + case COMPAT_FMPGSESSION: + if (unlikely(copy_from_user(&compat_sop, arg, sizeof(compat_sop)))) + return -EFAULT; + compat_to_session_op(&compat_sop, &sop); + + ret = fmp_create_session(info, fcr, &sop); + if (unlikely(ret)) { + dev_err(dev, "Fail to create fmp session. ret = %d\n", ret); + return ret; + } + + session_op_to_compat(&sop, &compat_sop); + ret = copy_to_user(arg, &compat_sop, sizeof(compat_sop)); + if (unlikely(ret)) { + fmp_finish_session(info, fcr, sop.ses); + return -EFAULT; + } + case COMPAT_FMPCRYPT: + if (unlikely(ret = compat_kcop_from_user(info, &kcop, fcr, arg))) + return ret; + + if (unlikely(in_fmp_fips_err())) { + dev_err(dev, "Fail to run fmp due to fips in error."); + return -EPERM; + } + + ret = fmp_run(info, fcr, &kcop); + if (unlikely(ret)) { + dev_err(dev, "Fail to run fmp crypt. ret = %d\n", ret); + return ret; + } + return compat_kcop_to_user(info, &kcop, fcr, arg); + case COMPAT_FMP_AES_CBC_MCT: + if (unlikely(ret = compat_kcop_from_user(info, &kcop, fcr, arg))) { + dev_err(dev, "Error copying from user"); + return ret; + } + + if (unlikely(in_fmp_fips_err())) { + dev_err(dev, "Fail to run fmp due to fips in error."); + return -EPERM; + } + + ret = fmp_run_AES_CBC_MCT(info, fcr, &kcop); + if (unlikely(ret)) { + dev_err(dev, "Error in fmp_run_AES_CBC_MCT"); + return ret; + } + return compat_kcop_to_user(info, &kcop, fcr, arg); + default: + dev_err(dev, "Invalid command : 0x%x\n", cmd); + return -EINVAL; + } +} +#endif /* CONFIG_COMPAT */ + +static int fmpdev_release(struct inode *inode, struct file *file) +{ + struct fmp_info *info = file->private_data; + struct device *dev = info->dev; + struct todo_list_item *item, *item_safe; + int items_freed = 0; + + if (!info) { + dev_err(dev, "fmp info is already free.\n"); + return -ENOMEM; + } + + cancel_work_sync(&info->fmptask); + + mutex_destroy(&info->todo.lock); + mutex_destroy(&info->done.lock); + mutex_destroy(&info->free.lock); + + list_splice_tail(&info->todo.list, &info->free.list); + list_splice_tail(&info->done.list, &info->free.list); + + list_for_each_entry_safe(item, item_safe, &info->free.list, __hook) { + dev_err(dev, "%s: freeing item at %lx\n", + __func__, (unsigned long)item); + list_del(&item->__hook); + kfree(item); + items_freed++; + } + if (items_freed != info->itemcount) + dev_err(dev, "%s: freed %d items, but %d should exist!\n", + __func__, items_freed, info->itemcount); + + fmp_finish_all_sessions(info, &info->fcrypt); + kfree(info); + file->private_data = NULL; + + dev_info(dev, "%s released.\n", dev_name(dev)); + + return 0; +} + +static const struct file_operations fmpdev_fops = { + .owner = THIS_MODULE, + .open = fmpdev_open, + .release = fmpdev_release, + .unlocked_ioctl = fmpdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fmpdev_compat_ioctl, +#endif +}; + +static struct miscdevice exynos_fmpdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "fmp", + .fops = &fmpdev_fops, +}; + +static int exynos_fips_fmp_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + + ret = misc_register(&exynos_fmpdev); + if (ret) { + dev_err(dev, "Fail to register misc device. ret = %d\n", ret); + goto misc_err; + } + + ret = sysfs_create_group(&dev->kobj, &fips_fmp_attr_group); + if (ret) { + dev_err(dev, "Fail to create sysfs for fips fmp\n"); + goto sysfs_err; + } + + match = of_match_node(exynos_fips_fmp_match, dev->of_node); + if (!match) { + dev_err(dev, "Fail to get match from device node\n"); + goto err; + } + + ret = fips_fmp_init(dev); + if (ret) { + dev_err(dev, "Fail to initialize fmp driver for selftest. ret = %d\n", ret); + goto err; + } + + ret = do_fips_fmp_selftest(dev); + if (ret) { + printk(KERN_ERR "FIPS: self-tests for UFSFMP failed\n"); + goto err; + } else { + printk(KERN_INFO "FIPS: self-tests for UFSFMP passed\n"); + } + + ret = do_fips_fmp_integrity_check(); + if (ret) { + printk(KERN_ERR "FIPS: integrity check for UFSFMP failed\n"); + goto err; + } else { + printk(KERN_INFO "FIPS: integrity check for UFSFMP passed\n"); + } + + fips_fmp_result = 1; + + return 0; + +err: +#if defined(CONFIG_NODE_FOR_SELFTEST_FAIL) + set_in_fmp_fips_err(); + fips_fmp_result = 0; + return 0; +#else + panic("Panic due to FMP self test for FIPS KAT"); +#endif + +sysfs_err: +misc_err: + return -1; +} + +static int exynos_fips_fmp_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + sysfs_remove_group(&dev->kobj, &fips_fmp_attr_group); + misc_deregister(&exynos_fmpdev); + + return 0; +} + +static const struct of_device_id exynos_fips_fmp_match[] = { + { .compatible = "samsung,exynos-fips-fmp", + .data = &fips_fmp_fops, }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_fips_fmp_match); + +static struct platform_driver exynos_fips_fmp_driver = { + .driver = { + .name = "exynos-fips-fmp", + .owner = THIS_MODULE, + .pm = NULL, + .of_match_table = exynos_fips_fmp_match, + }, + .probe = exynos_fips_fmp_probe, + .remove = exynos_fips_fmp_remove, +}; + +static int __init exynos_fips_fmp_init(void) +{ + return platform_driver_register(&exynos_fips_fmp_driver); +} +late_initcall(exynos_fips_fmp_init); + +static void __exit exynos_fips_fmp_exit(void) +{ + platform_driver_unregister(&exynos_fips_fmp_driver); +} +module_exit(exynos_fips_fmp_exit); + +MODULE_DESCRIPTION("FIPS KAT for Exynos FMP AES module"); diff --git a/drivers/crypto/fmp/fmpdev.h b/drivers/crypto/fmp/fmpdev.h new file mode 100644 index 000000000000..902ed8560d72 --- /dev/null +++ b/drivers/crypto/fmp/fmpdev.h @@ -0,0 +1,22 @@ +/* + * Exynos FMP test driver for FIPS + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _FIPS_FMP_H_ +#define _FIPS_FMP_H_ + +#define FMP_DRV_VERSION "1.1" + +int fips_fmp_cipher_init(struct device *dev, uint8_t *enckey, uint8_t *twkey, uint32_t key_len, uint32_t mode); +int fips_fmp_cipher_set_iv(struct device *dev, uint8_t *iv, uint32_t mode); +int fips_fmp_cipher_run(struct device *dev, uint8_t *src, uint8_t *dst, uint32_t len, uint32_t mode, uint32_t enc); +int fips_fmp_cipher_exit(struct device *dev); + +#endif diff --git a/drivers/crypto/fmp/fmpdev_info.h b/drivers/crypto/fmp/fmpdev_info.h new file mode 100644 index 000000000000..5574434a8163 --- /dev/null +++ b/drivers/crypto/fmp/fmpdev_info.h @@ -0,0 +1,133 @@ +/* + * Exynos FMP device information for FIPS + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _FIPS_FMP_INFO_H_ +#define _FIPS_FMP_INFO_H_ + +#define FMP_BLK_SIZE (4096) + +#define BYPASS_MODE 0 +#define CBC_MODE 1 +#define XTS_MODE 2 + +#define ENCRYPT 1 +#define DECRYPT 2 + +#define WRITE_MODE 1 +#define READ_MODE 2 + +/* API extensions for linux */ +#define FMP_HMAC_MAX_KEY_LEN 512 +#define FMP_CIPHER_MAX_KEY_LEN 64 + +enum fmpdev_crypto_op_t { + FMP_AES_CBC = 1, + FMP_AES_XTS = 2, + FMP_SHA2_256_HMAC = 3, + FMP_SHA2_256 = 4, + FMPFW_SHA2_256_HMAC = 5, + FMPFW_SHA2_256 = 6, + FMP_ALGORITHM_ALL, /* Keep updated - see below */ +}; +#define FMP_ALGORITHM_MAX (FMP_ALGORITHM_ALL - 1) + +/* the maximum of the above */ +#define EALG_MAX_BLOCK_LEN 16 + +/* Values for hashes/MAC */ +#define AALG_MAX_RESULT_LEN 64 + +/* maximum length of verbose alg names (depends on CRYPTO_MAX_ALG_NAME) */ +#define FMPDEV_MAX_ALG_NAME 64 + +#define DEFAULT_PREALLOC_PAGES 32 + +/* input of FMPGSESSION */ +struct session_op { + __u32 cipher; /* cryptodev_crypto_op_t */ + __u32 mac; /* cryptodev_crypto_op_t */ + + __u32 keylen; + __u8 __user *key; + __u32 mackeylen; + __u8 __user *mackey; + + __u32 ses; /* session identifier */ +}; + +struct session_info_op { + __u32 ses; /* session identifier */ + + /* verbose names for the requested ciphers */ + struct alg_info { + char cra_name[FMPDEV_MAX_ALG_NAME]; + char cra_driver_name[FMPDEV_MAX_ALG_NAME]; + } cipher_info, hash_info; + + __u16 alignmask; /* alignment constraints */ + __u32 flags; /* SIOP_FLAGS_* */ +}; + +/* If this flag is set then this algorithm uses + * a driver only available in kernel (software drivers, + * or drivers based on instruction sets do not set this flag). + * + * If multiple algorithms are involved (as in AEAD case), then + * if one of them is kernel-driver-only this flag will be set. + */ +#define SIOP_FLAG_KERNEL_DRIVER_ONLY 1 + +#define COP_ENCRYPT 0 +#define COP_DECRYPT 1 + +/* input of FMPCRYPT */ +struct crypt_op { + __u32 ses; /* session identifier */ + __u16 op; /* COP_ENCRYPT or COP_DECRYPT */ + __u16 flags; /* see COP_FLAG_* */ + __u32 len; /* length of source data */ + __u8 __user *src; /* source data */ + __u8 __user *dst; /* pointer to output data */ + /* pointer to output data for hash/MAC operations */ + __u8 __user *mac; + /* initialization vector for encryption operations */ + __u8 __user *iv; + + __u32 data_unit_len; + __u32 data_unit_seqnumber; + + __u8 __user *secondLastEncodedData; + __u8 __user *thirdLastEncodedData; +}; + +#define COP_FLAG_NONE (0 << 0) /* totally no flag */ +#define COP_FLAG_UPDATE (1 << 0) /* multi-update hash mode */ +#define COP_FLAG_FINAL (1 << 1) /* multi-update final hash mode */ +#define COP_FLAG_WRITE_IV (1 << 2) /* update the IV during operation */ +#define COP_FLAG_NO_ZC (1 << 3) /* do not zero-copy */ +#define COP_FLAG_AEAD_TLS_TYPE (1 << 4) /* authenticate and encrypt using the + * TLS protocol rules */ +#define COP_FLAG_AEAD_SRTP_TYPE (1 << 5) /* authenticate and encrypt using the + * SRTP protocol rules */ +#define COP_FLAG_RESET (1 << 6) /* multi-update reset the state. + * should be used in combination + * with COP_FLAG_UPDATE */ +#define COP_FLAG_AES_CBC (1 << 7) +#define COP_FLAG_AES_XTS (1 << 8) +#define COP_FLAG_AES_CBC_MCT (1 << 9) + +#define FMPGSESSION _IOWR('c', 200, struct session_op) +#define FMPFSESSION _IOWR('c', 201, __u32) +#define FMPGSESSIONINFO _IOWR('c', 202, struct session_info_op) +#define FMPCRYPT _IOWR('c', 203, struct crypt_op) +#define FMP_AES_CBC_MCT _IOWR('c', 204, struct crypt_op) + +#endif diff --git a/drivers/crypto/fmp/fmpdev_int.h b/drivers/crypto/fmp/fmpdev_int.h new file mode 100644 index 000000000000..c0444e9c9f06 --- /dev/null +++ b/drivers/crypto/fmp/fmpdev_int.h @@ -0,0 +1,238 @@ +/* + * Exynos FMP device header for FIPS + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __FMPDEV_INT_H__ +#define __FMPDEV_INT_H__ + +#define reinit_completion(x) INIT_COMPLETION(*(x)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fmpdev_info.h" + +struct fcrypt { + struct list_head list; + struct mutex sem; +}; + +/* kernel-internal extension to struct crypt_op */ +struct kernel_crypt_op { + struct crypt_op cop; + + int ivlen; + __u8 iv[EALG_MAX_BLOCK_LEN]; + + int digestsize; + uint8_t hash_output[AALG_MAX_RESULT_LEN]; + + struct task_struct *task; + struct mm_struct *mm; +}; + +struct todo_list_item { + struct list_head __hook; + struct kernel_crypt_op kcop; + int result; +}; + +struct locked_list { + struct list_head list; + struct mutex lock; +}; + +struct fmp_info { + int init_status; + struct device *dev; + struct fcrypt fcrypt; + struct locked_list free, todo, done; + int itemcount; + struct work_struct fmptask; + wait_queue_head_t user_waiter; +}; + +/* compatibility stuff */ +#ifdef CONFIG_COMPAT +#include + +/* input of FMPGSESSION */ +struct compat_session_op { + /* Specify either cipher or mac + */ + uint32_t cipher; /* cryptodev_crypto_op_t */ + uint32_t mac; /* cryptodev_crypto_op_t */ + + uint32_t keylen; + compat_uptr_t key; /* pointer to key data */ + uint32_t mackeylen; + compat_uptr_t mackey; /* pointer to mac key data */ + + uint32_t ses; /* session identifier */ +}; + +/* input of FMPCRYPT */ + struct compat_crypt_op { + uint32_t ses; /* session identifier */ + uint16_t op; /* COP_ENCRYPT or COP_DECRYPT */ + uint16_t flags; /* see COP_FLAG_* */ + uint32_t len; /* length of source data */ + compat_uptr_t src; /* source data */ + compat_uptr_t dst; /* pointer to output data */ + compat_uptr_t mac;/* pointer to output data for hash/MAC operations */ + compat_uptr_t iv;/* initialization vector for encryption operations */ + compat_uptr_t secondLastEncodedData; + compat_uptr_t thirdLastEncodedData; +}; + +#define COMPAT_FMPGSESSION _IOWR('c', 100, struct compat_session_op) +#define COMPAT_FMPCRYPT _IOWR('c', 101, struct compat_crypt_op) +#define COMPAT_FMP_AES_CBC_MCT _IOWR('c', 102, struct compat_crypt_op) +#endif + +/* the maximum of the above */ +#define EALG_MAX_BLOCK_LEN 16 + +struct cipher_data { + int init; /* 0 uninitialized */ + int blocksize; + int aead; + int stream; + int ivsize; + int alignmask; + struct { + /* block ciphers */ + struct crypto_ablkcipher *s; + struct ablkcipher_request *request; + + /* AEAD ciphers */ + struct crypto_aead *as; + struct aead_request *arequest; + + struct fmpdev_result *result; + uint8_t iv[EALG_MAX_BLOCK_LEN]; + } async; + int mode; +}; + +/* Hash */ +struct sha256_fmpfw_info { + uint32_t input; + uint32_t input_len; + uint32_t output; + uint32_t step; +}; + +struct hmac_sha256_fmpfw_info { + struct sha256_fmpfw_info s; + uint32_t key; + uint32_t key_len; + uint32_t hmac_mode; + uint32_t dummy; +}; + +struct hash_data { + int init; /* 0 uninitialized */ + int digestsize; + int alignmask; + struct { + struct crypto_ahash *s; + struct fmpdev_result *result; + struct ahash_request *request; + } async; + struct hmac_sha256_fmpfw_info *fmpfw_info; +}; + +struct fmpdev_result { + struct completion completion; + int err; +}; + +/* other internal structs */ +struct csession { + struct list_head entry; + struct mutex sem; + struct cipher_data cdata; + struct hash_data hdata; + uint32_t sid; + uint32_t alignmask; + + unsigned int array_size; + unsigned int used_pages; /* the number of pages that are used */ + /* the number of pages marked as writable (first are the readable) */ + unsigned int readable_pages; + struct page **pages; + struct scatterlist *sg; +}; + +struct csession *fmp_get_session_by_sid(struct fcrypt *fcr, uint32_t sid); + +inline static void fmp_put_session(struct csession *ses_ptr) +{ + mutex_unlock(&ses_ptr->sem); +} +int adjust_sg_array(struct csession *ses, int pagecount); + +#define MAX_TAP 8 +#define XBUFSIZE 8 + +struct cipher_testvec { + char *key; + char *iv; + char *input; + char *result; + unsigned short tap[MAX_TAP]; + int np; + unsigned char also_non_np; + unsigned char klen; + unsigned short ilen; + unsigned short rlen; +}; + +struct hash_testvec { + /* only used with keyed hash algorithms */ + char *key; + char *plaintext; + char *digest; + unsigned char tap[MAX_TAP]; + unsigned short psize; + unsigned char np; + unsigned char ksize; +}; + +struct cipher_test_suite { + struct { + struct cipher_testvec *vecs; + unsigned int count; + } enc; +}; + +struct hash_test_suite { + struct hash_testvec *vecs; + unsigned int count; +}; + +struct fips_fmp_ops { + int (*init)(struct device *dev, uint32_t mode); + int (*set_key)(struct device *dev, uint32_t mode, uint8_t *key, uint32_t key_len); + int (*set_iv)(struct device *dev, uint32_t mode, uint8_t *iv, uint32_t iv_len); + int (*run)(struct device *dev, uint32_t mode, uint8_t *data, uint32_t len, uint32_t write); + int (*exit)(void); +}; + +#endif diff --git a/drivers/crypto/fmp/fmplib.c b/drivers/crypto/fmp/fmplib.c new file mode 100644 index 000000000000..ca503b0f7749 --- /dev/null +++ b/drivers/crypto/fmp/fmplib.c @@ -0,0 +1,785 @@ +/* + * Exynos FMP libary for FIPS + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "fmpdev_int.h" +#include "fmpdev.h" + +#define BYPASS_MODE 0 +#define CBC_MODE 1 +#define XTS_MODE 2 + +#define INIT 0 +#define UPDATE 1 +#define FINAL 2 + +static void fmpdev_complete(struct crypto_async_request *req, int err) +{ + struct fmpdev_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + +static inline int waitfor(struct fmp_info *info, struct fmpdev_result *cr, + ssize_t ret) +{ + struct device *dev = info->dev; + + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + wait_for_completion(&cr->completion); + /* At this point we known for sure the request has finished, + * because wait_for_completion above was not interruptible. + * This is important because otherwise hardware or driver + * might try to access memory which will be freed or reused for + * another request. */ + + if (unlikely(cr->err)) { + dev_err(dev, "error from async request: %d\n", cr->err); + return cr->err; + } + + break; + default: + return ret; + } + + return 0; +} + +/* + * FMP library to call FMP driver + * + * This file is part of linux fmpdev + */ + +int fmpdev_cipher_init(struct fmp_info *info, struct cipher_data *out, + const char *alg_name, + uint8_t *enckey, uint8_t *twkey, size_t keylen) +{ + int ret; + struct device *dev = info->dev; + + memset(out, 0, sizeof(*out)); + + if (!strcmp(alg_name, "cbc(aes-fmp)")) + out->mode = CBC_MODE; + else if (!strcmp(alg_name, "xts(aes-fmp)")) + out->mode = XTS_MODE; + else { + dev_err(dev, "Invalid mode\n"); + return -1; + } + + out->blocksize = 16; + out->ivsize = 16; + ret = fips_fmp_cipher_init(dev, enckey, twkey, keylen, out->mode); + if (ret) { + dev_err(dev, "Fail to initialize fmp cipher\n"); + return -1; + } + + out->init = 1; + return 0; +} + +void fmpdev_cipher_deinit(struct cipher_data *cdata) +{ + if (cdata->init) + cdata->init = 0; +} + +int fmpdev_cipher_set_iv(struct fmp_info *info, struct cipher_data *cdata, + uint8_t *iv, size_t iv_size) +{ + int ret; + struct device *dev = info->dev; + + ret = fips_fmp_cipher_set_iv(dev, iv, cdata->mode); + if (ret) { + dev_err(dev, "Fail to set fmp iv\n"); + return -1; + } + + return 0; +} + +int fmpdev_cipher_exit(struct fmp_info *info) +{ + int ret; + struct device *dev = info->dev; + + ret = fips_fmp_cipher_exit(dev); + if (ret) { + dev_err(dev, "Fail to exit fmp\n"); + return -1; + } + + return 0; +} + +static int fmpdev_cipher_encrypt(struct fmp_info *info, + struct cipher_data *cdata, + struct scatterlist *src, + struct scatterlist *dst, size_t len) +{ + int ret; + struct device *dev = info->dev; + + ret = fips_fmp_cipher_run(dev, sg_virt(src), sg_virt(dst), + len, cdata->mode, ENCRYPT); + if (ret) { + dev_err(dev, "Fail to encrypt using fmp\n"); + return -1; + } + + return 0; +} + +static int fmpdev_cipher_decrypt(struct fmp_info *info, + struct cipher_data *cdata, + struct scatterlist *src, + struct scatterlist *dst, size_t len) +{ + int ret; + struct device *dev = info->dev; + + ret = fips_fmp_cipher_run(dev, sg_virt(src), sg_virt(dst), + len, cdata->mode, DECRYPT); + if (ret) { + dev_err(dev, "Fail to encrypt using fmp\n"); + return -1; + } + + return 0; +} + +/* Hash functions */ +int fmpfw_hash_init(struct fmp_info *info, struct hash_data *hdata, + const char *alg_name, int hmac_mode, + void *mackey, size_t mackeylen) +{ + int ret; + unsigned long addr; + struct device *dev = info->dev; + struct hmac_sha256_fmpfw_info *fmpfw_info; + + fmpfw_info = (struct hmac_sha256_fmpfw_info *)kzalloc(sizeof(*fmpfw_info), GFP_KERNEL); + if (unlikely(!fmpfw_info)) { + dev_err(dev, "Fail to alloc fmpfw info\n"); + ret = ENOMEM; + goto error_alloc_info; + } + + if (hmac_mode != 0) { + fmpfw_info->s.step = INIT; + fmpfw_info->hmac_mode = 1; + fmpfw_info->key = (uint32_t)virt_to_phys(mackey); + __flush_dcache_area(mackey, mackeylen); + fmpfw_info->key_len = mackeylen; + __flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); + addr = virt_to_phys(fmpfw_info); + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, (uint32_t)addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 init. ret = 0x%x\n", ret); + ret = -EFAULT; + goto error_hmac_smc; + } + } else { + fmpfw_info->s.step = INIT; + fmpfw_info->hmac_mode = 0; + fmpfw_info->key = 0; + fmpfw_info->key_len = 0; + __flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); + addr = virt_to_phys(fmpfw_info); + + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, (uint32_t)addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW SHA256 init. ret = 0x%x\n", ret); + ret = -EFAULT; + goto error_sha_smc; + } + } + + hdata->digestsize = SHA256_DIGEST_SIZE; + hdata->alignmask = 0x0; + hdata->fmpfw_info = fmpfw_info; + + hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL); + if (unlikely(!hdata->async.result)) { + ret = -ENOMEM; + goto error; + } + + init_completion(&hdata->async.result->completion); + + hdata->init = 1; + + return 0; + +error_hmac_smc: +error_sha_smc: + kfree(fmpfw_info); +error_alloc_info: + hdata->fmpfw_info = NULL; +error: + kfree(hdata->async.result); + return ret; +} + +void fmpfw_hash_deinit(struct hash_data *hdata) +{ + if (hdata->init) { + kfree(hdata->async.result); + hdata->init = 0; + } +} + +ssize_t fmpfw_hash_update(struct fmp_info *info, struct hash_data *hdata, + struct scatterlist *sg, size_t len) +{ + int ret = 0; + unsigned long addr; + struct device *dev = info->dev; + struct hmac_sha256_fmpfw_info *fmpfw_info = hdata->fmpfw_info; + + fmpfw_info->s.step = UPDATE; + fmpfw_info->s.input = (uint32_t)sg_phys(sg); + __flush_dcache_area(sg_virt(sg), len); + fmpfw_info->s.input_len = len; + __flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); + addr = virt_to_phys(fmpfw_info); + + reinit_completion(&hdata->async.result->completion); + if (fmpfw_info->hmac_mode) { + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 update. ret = 0x%x\n", ret); + ret = -EFAULT; + } + } else { + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW SHA256 update. ret = 0x%x\n", ret); + ret = -EFAULT; + } + } + + return waitfor(info, hdata->async.result, ret); +} + +int fmpfw_hash_final(struct fmp_info *info, struct hash_data *hdata, void *output) +{ + int ret = 0; + unsigned long addr; + struct device *dev = info->dev; + struct hmac_sha256_fmpfw_info *fmpfw_info = hdata->fmpfw_info; + + memset(output, 0, hdata->digestsize); + fmpfw_info->s.step = FINAL; + fmpfw_info->s.output = (uint32_t)virt_to_phys(output); + __flush_dcache_area(fmpfw_info, sizeof(*fmpfw_info)); + addr = virt_to_phys(fmpfw_info); + + reinit_completion(&hdata->async.result->completion); + __dma_unmap_area((void *)output, hdata->digestsize, DMA_FROM_DEVICE); + if (fmpfw_info->hmac_mode) { + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_HMAC_SHA2_TEST, addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW HMAC SHA256 final. ret = 0x%x\n", ret); + ret = -EFAULT; + } + } else { + ret = exynos_smc(SMC_CMD_FMP, FMP_FW_SHA2_TEST, addr, 0); + if (unlikely(ret)) { + dev_err(dev, "Fail to smc call for FMPFW SHA256 final. ret = 0x%x\n", ret); + ret = -EFAULT; + } + } + __dma_unmap_area((void *)output, hdata->digestsize, DMA_FROM_DEVICE); + + if (fmpfw_info->hmac_mode) + dev_info(dev, "fmp fw hmac sha256 F/W final is done\n"); + else + dev_info(dev, "fmp fw sha256 F/W final is done\n"); + + kfree(fmpfw_info); + return waitfor(info, hdata->async.result, ret); +} + +int fmpdev_hash_init(struct fmp_info *info, struct hash_data *hdata, + const char *alg_name, + int hmac_mode, void *mackey, size_t mackeylen) +{ + int ret; + struct device *dev = info->dev; + + hdata->fmpfw_info = NULL; + hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0); + if (unlikely(IS_ERR(hdata->async.s))) { + dev_err(dev, "Failed to load transform for %s\n", alg_name); + return -EINVAL; + } + + /* Copy the key from user and set to TFM. */ + if (hmac_mode != 0) { + ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen); + if (unlikely(ret)) { + dev_err(dev, "Setting hmac key failed for %s-%zu.\n", + alg_name, mackeylen*8); + ret = -EINVAL; + goto error; + } + } + + hdata->digestsize = crypto_ahash_digestsize(hdata->async.s); + hdata->alignmask = crypto_ahash_alignmask(hdata->async.s); + + hdata->async.result = kzalloc(sizeof(*hdata->async.result), GFP_KERNEL); + if (unlikely(!hdata->async.result)) { + ret = -ENOMEM; + goto error; + } + + init_completion(&hdata->async.result->completion); + + hdata->async.request = ahash_request_alloc(hdata->async.s, GFP_KERNEL); + if (unlikely(!hdata->async.request)) { + dev_err(dev, "error allocating async crypto request\n"); + ret = -ENOMEM; + goto error; + } + + ahash_request_set_callback(hdata->async.request, + CRYPTO_TFM_REQ_MAY_BACKLOG, + fmpdev_complete, hdata->async.result); + + ret = crypto_ahash_init(hdata->async.request); + if (unlikely(ret)) { + dev_err(dev, "error in fmpdev_hash_init()\n"); + goto error_request; + } + + hdata->init = 1; + return 0; + +error_request: + ahash_request_free(hdata->async.request); +error: + kfree(hdata->async.result); + crypto_free_ahash(hdata->async.s); + return ret; +} + + +void fmpdev_hash_deinit(struct hash_data *hdata) +{ + if (hdata->init) { + if (hdata->async.request) + ahash_request_free(hdata->async.request); + kfree(hdata->async.result); + if (hdata->async.s) + crypto_free_ahash(hdata->async.s); + hdata->init = 0; + } +} + +int fmpdev_hash_reset(struct fmp_info *info, struct hash_data *hdata) +{ + int ret; + struct device *dev = info->dev; + + ret = crypto_ahash_init(hdata->async.request); + if (unlikely(ret)) { + dev_err(dev, "error in crypto_hash_init()\n"); + return ret; + } + + return 0; + +} + +ssize_t fmpdev_hash_update(struct fmp_info *info, struct hash_data *hdata, + struct scatterlist *sg, size_t len) +{ + int ret; + + reinit_completion(&hdata->async.result->completion); + ahash_request_set_crypt(hdata->async.request, sg, NULL, len); + + ret = crypto_ahash_update(hdata->async.request); + + return waitfor(info, hdata->async.result, ret); +} + +int fmpdev_hash_final(struct fmp_info *info, struct hash_data *hdata, void *output) +{ + int ret; + + reinit_completion(&hdata->async.result->completion); + ahash_request_set_crypt(hdata->async.request, NULL, output, 0); + + ret = crypto_ahash_final(hdata->async.request); + + return waitfor(info, hdata->async.result, ret); +} + +static int fmp_n_crypt(struct fmp_info *info, struct csession *ses_ptr, + struct crypt_op *cop, + struct scatterlist *src_sg, struct scatterlist *dst_sg, + uint32_t len) +{ + int ret; + struct device *dev = info->dev; + + if (cop->op == COP_ENCRYPT) { + if (ses_ptr->hdata.init != 0) { + if (!ses_ptr->hdata.fmpfw_info) + ret = fmpdev_hash_update(info, &ses_ptr->hdata, + src_sg, len); + else + ret = fmpfw_hash_update(info, &ses_ptr->hdata, + src_sg, len); + if (unlikely(ret)) + goto out_err; + } + + if (ses_ptr->cdata.init != 0) { + ret = fmpdev_cipher_encrypt(info, &ses_ptr->cdata, + src_sg, dst_sg, len); + if (unlikely(ret)) + goto out_err; + } + } else { + if (ses_ptr->cdata.init != 0) { + ret = fmpdev_cipher_decrypt(info, &ses_ptr->cdata, + src_sg, dst_sg, len); + if (unlikely(ret)) + goto out_err; + } + + if (ses_ptr->hdata.init != 0) { + if (!ses_ptr->hdata.fmpfw_info) + ret = fmpdev_hash_update(info, &ses_ptr->hdata, + dst_sg, len); + else + ret = fmpfw_hash_update(info, &ses_ptr->hdata, + dst_sg, len); + if (unlikely(ret)) + goto out_err; + } + } + + return 0; +out_err: + dev_err(dev, "FMP crypt failure: %d\n", ret); + + return ret; +} + +static int __fmp_run_std(struct fmp_info *info, + struct csession *ses_ptr, struct crypt_op *cop) +{ + char *data; + struct device *dev = info->dev; + char __user *src, *dst; + size_t nbytes, bufsize; + struct scatterlist sg; + int ret = 0; + + nbytes = cop->len; + data = (char *)__get_free_page(GFP_KERNEL); + if (unlikely(!data)) { + dev_err(dev, "Error getting free page.\n"); + return -ENOMEM; + } + + bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; + + src = cop->src; + dst = cop->dst; + + while (nbytes > 0) { + size_t current_len = nbytes > bufsize ? bufsize : nbytes; + + if (unlikely(copy_from_user(data, src, current_len))) { + dev_err(dev, "Error copying %d bytes from user address %p\n", + (int)current_len, src); + ret = -EFAULT; + break; + } + + sg_init_one(&sg, data, current_len); + ret = fmp_n_crypt(info, ses_ptr, cop, &sg, &sg, current_len); + if (unlikely(ret)) { + dev_err(dev, "fmp_n_crypt failed\n"); + break; + } + + if (ses_ptr->cdata.init != 0) { + if (unlikely(copy_to_user(dst, data, current_len))) { + dev_err(dev, "could not copy to user\n"); + ret = -EFAULT; + break; + } + } + + dst += current_len; + nbytes -= current_len; + src += current_len; + } + free_page((unsigned long)data); + + return ret; +} + + +int fmp_run(struct fmp_info *info, struct fcrypt *fcr, struct kernel_crypt_op *kcop) +{ + struct device *dev = info->dev; + struct csession *ses_ptr; + struct crypt_op *cop = &kcop->cop; + int ret; + + if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { + dev_err(dev, "invalid operation op=%u\n", cop->op); + return -EINVAL; + } + + /* this also enters ses_ptr->sem */ + ses_ptr = fmp_get_session_by_sid(fcr, cop->ses); + if (unlikely(!ses_ptr)) { + dev_err(dev, "invalid session ID=0x%08X\n", cop->ses); + return -EINVAL; + } + + if ((ses_ptr->cdata.init != 0) && (cop->len > PAGE_SIZE)) { + dev_err(dev, "Invalid input length. len = %d\n", cop->len); + return -EINVAL; + } + + if (ses_ptr->hdata.init != 0 && (cop->flags == 0 || cop->flags & COP_FLAG_RESET) && \ + !ses_ptr->hdata.fmpfw_info) { + ret = fmpdev_hash_reset(info, &ses_ptr->hdata); + if (unlikely(ret)) { + dev_err(dev, "error in fmpdev_hash_reset()"); + goto out_unlock; + } + } + + if (ses_ptr->cdata.init != 0) { + int blocksize = ses_ptr->cdata.blocksize; + + if (unlikely(cop->len % blocksize)) { + dev_err(dev, + "data size (%u) isn't a multiple " + "of block size (%u)\n", + cop->len, blocksize); + ret = -EINVAL; + goto out_unlock; + } + + if (cop->flags == COP_FLAG_AES_CBC) + fmpdev_cipher_set_iv(info, &ses_ptr->cdata, kcop->iv, 16); + else if (cop->flags == COP_FLAG_AES_XTS) + fmpdev_cipher_set_iv(info, &ses_ptr->cdata, (uint8_t *)&cop->data_unit_seqnumber, 16); + else { + ret = -EINVAL; + goto out_unlock; + } + } + + if (likely(cop->len)) { + ret = __fmp_run_std(info, ses_ptr, &kcop->cop); + if (unlikely(ret)) + goto out_unlock; + } + + if (ses_ptr->hdata.init != 0 && + ((cop->flags & COP_FLAG_FINAL) || + (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) { + if (!ses_ptr->hdata.fmpfw_info) + ret = fmpdev_hash_final(info, &ses_ptr->hdata, kcop->hash_output); + else + ret = fmpfw_hash_final(info, &ses_ptr->hdata, kcop->hash_output); + if (unlikely(ret)) { + dev_err(dev, "CryptoAPI failure: %d\n", ret); + goto out_unlock; + } + kcop->digestsize = ses_ptr->hdata.digestsize; + } + +out_unlock: + fmp_put_session(ses_ptr); + return ret; +} + +int fmp_run_AES_CBC_MCT(struct fmp_info *info, struct fcrypt *fcr, + struct kernel_crypt_op *kcop) +{ + struct device *dev = info->dev; + struct csession *ses_ptr; + struct crypt_op *cop = &kcop->cop; + char **Ct = 0; + char **Pt = 0; + int ret = 0, k = 0; + + if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { + dev_err(dev, "invalid operation op=%u\n", cop->op); + return -EINVAL; + } + + /* this also enters ses_ptr->sem */ + ses_ptr = fmp_get_session_by_sid(fcr, cop->ses); + if (unlikely(!ses_ptr)) { + dev_err(dev, "invalid session ID=0x%08X\n", cop->ses); + return -EINVAL; + } + + if (cop->len > PAGE_SIZE) { + dev_err(dev, "Invalid input length. len = %d\n", cop->len); + return -EINVAL; + } + + if (ses_ptr->cdata.init != 0) { + int blocksize = ses_ptr->cdata.blocksize; + + if (unlikely(cop->len % blocksize)) { + dev_err(dev, + "data size (%u) isn't a multiple " + "of block size (%u)\n", + cop->len, blocksize); + ret = -EINVAL; + goto out_unlock; + } + + fmpdev_cipher_set_iv(info, &ses_ptr->cdata, kcop->iv, 16); + } + + if (likely(cop->len)) { + if (cop->flags & COP_FLAG_AES_CBC_MCT) { + // do MCT here + char *data; + char __user *src, *dst, *secondLast; + struct scatterlist sg; + size_t nbytes, bufsize; + int ret = 0; + int y = 0; + + nbytes = cop->len; + data = (char *)__get_free_page(GFP_KERNEL); + if (unlikely(!data)) { + dev_err(dev, "Error getting free page.\n"); + return -ENOMEM; + } + + Pt = (char**)kmalloc(1000 * sizeof(char*), GFP_KERNEL); + for (k=0; k<1000; k++) + Pt[k]= (char*)kmalloc(nbytes, GFP_KERNEL); + + Ct = (char**)kmalloc(1000 * sizeof(char*), GFP_KERNEL); + for (k=0; k<1000; k++) + Ct[k]= (char*)kmalloc(nbytes, GFP_KERNEL); + + bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; + + src = cop->src; + dst = cop->dst; + secondLast = cop->secondLastEncodedData; + + if (unlikely(copy_from_user(data, src, nbytes))) { + printk(KERN_ERR "Error copying %d bytes from user address %p.\n", (int)nbytes, src); + ret = -EFAULT; + goto out_err; + } + + sg_init_one(&sg, data, nbytes); + for (y = 0; y < 1000; y++) { + memcpy(Pt[y], data, nbytes); + ret = fmp_n_crypt(info, ses_ptr, cop, &sg, &sg, nbytes); + memcpy(Ct[y], data, nbytes); + + if (y == 998) { + if (unlikely(copy_to_user(secondLast, data, nbytes))) { + int i = 0; + printk(KERN_ERR "unable to copy second last data for AES_CBC_MCT\n"); + for(i = 0; i < nbytes; i++) + printk("%2x", (char)data[i]); + printk("\n"); + } else { + printk(KERN_ERR "KAMAL copied secondlast data\n"); + } + } + + if( y == 0) { + memcpy(data, kcop->iv, kcop->ivlen); + } else { + if(y != 999) + memcpy(data, Ct[y-1], nbytes); + } + + if (cop->op == COP_ENCRYPT) + fmpdev_cipher_set_iv(info, &ses_ptr->cdata, Ct[y], 16); + else if (cop->op == COP_DECRYPT) + fmpdev_cipher_set_iv(info, &ses_ptr->cdata, Pt[y], 16); + } // for loop + + if (ses_ptr->cdata.init != 0) { + if (unlikely(copy_to_user(dst, data, nbytes))) { + printk(KERN_ERR "could not copy to user.\n"); + ret = -EFAULT; + goto out_err; + } + } + + for (k=0; k<1000; k++) { + kfree(Ct[k]); + kfree(Pt[k]); + } + + kfree(Ct); + kfree(Pt); + free_page((unsigned long)data); + } else + goto out_unlock; + + if (unlikely(ret)) + goto out_unlock; + } + +out_unlock: + fmp_put_session(ses_ptr); + return ret; + +out_err: + fmp_put_session(ses_ptr); + dev_info(dev, "CryptoAPI failure: %d\n", ret); + + return ret; +} diff --git a/drivers/crypto/fmp/fmplib.h b/drivers/crypto/fmp/fmplib.h new file mode 100644 index 000000000000..4c8b3c41f81a --- /dev/null +++ b/drivers/crypto/fmp/fmplib.h @@ -0,0 +1,36 @@ +/* + * Exynos FMP library header + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __FMPLIB_H__ +#define __FMPLIB_H__ + +int fmpdev_cipher_init(struct fmp_info *info, struct cipher_data *out, + const char *alg_name, + uint8_t *enckey, uint8_t *twkey, size_t keylen); +void fmpdev_cipher_deinit(struct cipher_data *cdata); +int fmpfw_hash_init(struct fmp_info *info, struct hash_data *hdata, + const char *alg_name, int hmac_mode, + void *mackey, size_t mackeylen); +void fmpfw_hash_deinit(struct hash_data *hdata); +int fmpdev_hash_init(struct fmp_info *info, struct hash_data *hdata, + const char *alg_name, + int hmac_mode, void *mackey, size_t mackeylen); +void fmpdev_hash_deinit(struct hash_data *hdata); +int fmpdev_hash_reset(struct fmp_info *info, struct hash_data *hdata); +ssize_t fmpdev_hash_update(struct hash_data *hdata, + struct scatterlist *sg, size_t len); +int fmpdev_hash_final(struct hash_data *hdata, void *output); +int fmp_run(struct fmp_info *info, struct fcrypt *fcr, struct kernel_crypt_op *kcop); +int fmpdev_cipher_exit(struct fmp_info *info); +int fmp_run_AES_CBC_MCT(struct fmp_info *info, struct fcrypt *fcr, + struct kernel_crypt_op *kcop); + +#endif diff --git a/drivers/crypto/fmp/hmac_fmp.c b/drivers/crypto/fmp/hmac_fmp.c new file mode 100644 index 000000000000..c334c2176af0 --- /dev/null +++ b/drivers/crypto/fmp/hmac_fmp.c @@ -0,0 +1,275 @@ +/* + * Cryptographic API. + * + * HMAC: Keyed-Hashing for Message Authentication (RFC2104). + * + * Copyright (c) 2002 James Morris + * Copyright (c) 2006 Herbert Xu + * + * The HMAC implementation is derived from USAGI. + * Copyright (c) 2002 Kazunori Miyazawa / USAGI + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct hmac_ctx { + struct crypto_shash *hash; +}; + +static inline void *align_ptr(void *p, unsigned int align) +{ + return (void *)ALIGN((unsigned long)p, align); +} + +static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm) +{ + return align_ptr(crypto_shash_ctx_aligned(tfm) + + crypto_shash_statesize(tfm) * 2, + crypto_tfm_ctx_alignment()); +} + +static int hmac_setkey(struct crypto_shash *parent, + const u8 *inkey, unsigned int keylen) +{ + int bs = crypto_shash_blocksize(parent); + int ds = crypto_shash_digestsize(parent); + int ss = crypto_shash_statesize(parent); + char *ipad = crypto_shash_ctx_aligned(parent); + char *opad = ipad + ss; + struct hmac_ctx *ctx = align_ptr(opad + ss, + crypto_tfm_ctx_alignment()); + struct crypto_shash *hash = ctx->hash; + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(hash)]; + } desc; + unsigned int i; + + desc.shash.tfm = hash; + desc.shash.flags = crypto_shash_get_flags(parent) & + CRYPTO_TFM_REQ_MAY_SLEEP; + + if (keylen > bs) { + int err; + + err = crypto_shash_digest(&desc.shash, inkey, keylen, ipad); + if (err) + return err; + + keylen = ds; + } else + memcpy(ipad, inkey, keylen); + + memset(ipad + keylen, 0, bs - keylen); + memcpy(opad, ipad, bs); + + for (i = 0; i < bs; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + return crypto_shash_init(&desc.shash) ?: + crypto_shash_update(&desc.shash, ipad, bs) ?: + crypto_shash_export(&desc.shash, ipad) ?: + crypto_shash_init(&desc.shash) ?: + crypto_shash_update(&desc.shash, opad, bs) ?: + crypto_shash_export(&desc.shash, opad); +} + +static int hmac_export(struct shash_desc *pdesc, void *out) +{ + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_export(desc, out); +} + +static int hmac_import(struct shash_desc *pdesc, const void *in) +{ + struct shash_desc *desc = shash_desc_ctx(pdesc); + struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm); + + desc->tfm = ctx->hash; + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_import(desc, in); +} + +static int hmac_init(struct shash_desc *pdesc) +{ + return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm)); +} + +static int hmac_update(struct shash_desc *pdesc, + const u8 *data, unsigned int nbytes) +{ + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_update(desc, data, nbytes); +} + +static int hmac_final(struct shash_desc *pdesc, u8 *out) +{ + struct crypto_shash *parent = pdesc->tfm; + int ds = crypto_shash_digestsize(parent); + int ss = crypto_shash_statesize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + ss; + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + printk(KERN_INFO "%s: fmp hmac sha256 S/W final is done.\n", __func__); + + return crypto_shash_final(desc, out) ?: + crypto_shash_import(desc, opad) ?: + crypto_shash_finup(desc, out, ds, out); +} + +static int hmac_finup(struct shash_desc *pdesc, const u8 *data, + unsigned int nbytes, u8 *out) +{ + + struct crypto_shash *parent = pdesc->tfm; + int ds = crypto_shash_digestsize(parent); + int ss = crypto_shash_statesize(parent); + char *opad = crypto_shash_ctx_aligned(parent) + ss; + struct shash_desc *desc = shash_desc_ctx(pdesc); + + desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + return crypto_shash_finup(desc, data, nbytes, out) ?: + crypto_shash_import(desc, opad) ?: + crypto_shash_finup(desc, out, ds, out); +} + +static int hmac_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_shash *parent = __crypto_shash_cast(tfm); + struct crypto_shash *hash; + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst); + struct hmac_ctx *ctx = hmac_ctx(parent); + + hash = crypto_spawn_shash(spawn); + if (IS_ERR(hash)) + return PTR_ERR(hash); + + parent->descsize = sizeof(struct shash_desc) + + crypto_shash_descsize(hash); + + ctx->hash = hash; + return 0; +} + +static void hmac_exit_tfm(struct crypto_tfm *tfm) +{ + struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm)); + crypto_free_shash(ctx->hash); +} + +static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct shash_instance *inst; + struct crypto_alg *alg; + struct shash_alg *salg; + int err; + int ds; + int ss; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); + if (err) + return err; + + salg = shash_attr_alg(tb[1], 0, 0); + if (IS_ERR(salg)) + return PTR_ERR(salg); + + err = -EINVAL; + ds = salg->digestsize; + ss = salg->statesize; + alg = &salg->base; + if (ds > alg->cra_blocksize || + ss < alg->cra_blocksize) + goto out_put_alg; + + inst = shash_alloc_instance("hmac-fmp", alg); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto out_put_alg; + + err = crypto_init_shash_spawn(shash_instance_ctx(inst), salg, + shash_crypto_instance(inst)); + if (err) + goto out_free_inst; + + inst->alg.base.cra_priority = alg->cra_priority; + inst->alg.base.cra_blocksize = alg->cra_blocksize; + inst->alg.base.cra_alignmask = alg->cra_alignmask; + + ss = ALIGN(ss, alg->cra_alignmask + 1); + inst->alg.digestsize = ds; + inst->alg.statesize = ss; + + inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) + + ALIGN(ss * 2, crypto_tfm_ctx_alignment()); + + inst->alg.base.cra_init = hmac_init_tfm; + inst->alg.base.cra_exit = hmac_exit_tfm; + + inst->alg.init = hmac_init; + inst->alg.update = hmac_update; + inst->alg.final = hmac_final; + inst->alg.finup = hmac_finup; + inst->alg.export = hmac_export; + inst->alg.import = hmac_import; + inst->alg.setkey = hmac_setkey; + + err = shash_register_instance(tmpl, inst); + if (err) { +out_free_inst: + shash_free_instance(shash_crypto_instance(inst)); + } + +out_put_alg: + crypto_mod_put(alg); + return err; +} + +static struct crypto_template hmac_tmpl = { + .name = "hmac-fmp", + .create = hmac_create, + .free = shash_free_instance, + .module = THIS_MODULE, +}; + +static int __init hmac_module_init(void) +{ + return crypto_register_template(&hmac_tmpl); +} + +static void __exit hmac_module_exit(void) +{ + crypto_unregister_template(&hmac_tmpl); +} + +module_init(hmac_module_init); +module_exit(hmac_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("HMAC hash algorithm"); diff --git a/drivers/crypto/fmp/last_file.c b/drivers/crypto/fmp/last_file.c new file mode 100644 index 000000000000..92f41ebd653f --- /dev/null +++ b/drivers/crypto/fmp/last_file.c @@ -0,0 +1,30 @@ +/* + * Last file for Exynos FMP FIPS integrity check + * + * Copyright (C) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +const int last_fmp_rodata = 1000; +int last_fmp_data = 2000; + +void last_fmp_text(void) __attribute__((unused)); +void last_fmp_text (void) +{ +} + +void __init last_fmp_init(void) __attribute__((unused)); +void __init last_fmp_init(void) +{ +} + +void __exit last_fmp_exit(void) __attribute__((unused)); +void __exit last_fmp_exit(void) +{ +} diff --git a/drivers/crypto/fmp/sha256_fmp.c b/drivers/crypto/fmp/sha256_fmp.c new file mode 100644 index 000000000000..0ae316e6031d --- /dev/null +++ b/drivers/crypto/fmp/sha256_fmp.c @@ -0,0 +1,346 @@ +/* + * Cryptographic API. + * + * SHA-256, as specified in + * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke . + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include + +static inline u32 Ch(u32 x, u32 y, u32 z) +{ + return z ^ (x & (y ^ z)); +} + +static inline u32 Maj(u32 x, u32 y, u32 z) +{ + return (x & y) | (z & (x | y)); +} + +#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22)) +#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25)) +#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) +#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) + +static inline void LOAD_OP(int I, u32 *W, const u8 *input) +{ + W[I] = __be32_to_cpu( ((__be32*)(input))[I] ); +} + +static inline void BLEND_OP(int I, u32 *W) +{ + W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; +} + +static void sha256_transform(u32 *state, const u8 *input) +{ + u32 a, b, c, d, e, f, g, h, t1, t2; + u32 W[64]; + int i; + + /* load the input */ + for (i = 0; i < 16; i++) + LOAD_OP(i, W, input); + + /* now blend */ + for (i = 16; i < 64; i++) + BLEND_OP(i, W); + + /* load the state into our registers */ + a=state[0]; b=state[1]; c=state[2]; d=state[3]; + e=state[4]; f=state[5]; g=state[6]; h=state[7]; + + /* now iterate */ + t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; + + /* clear any sensitive info... */ + a = b = c = d = e = f = g = h = t1 = t2 = 0; + memset(W, 0, 64 * sizeof(u32)); +} + + +static int sha256_init(struct shash_desc *desc) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + sctx->state[0] = SHA256_H0; + sctx->state[1] = SHA256_H1; + sctx->state[2] = SHA256_H2; + sctx->state[3] = SHA256_H3; + sctx->state[4] = SHA256_H4; + sctx->state[5] = SHA256_H5; + sctx->state[6] = SHA256_H6; + sctx->state[7] = SHA256_H7; + sctx->count = 0; + + return 0; +} + +static int sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + unsigned int partial, done; + const u8 *src; + + partial = sctx->count & 0x3f; + sctx->count += len; + done = 0; + src = data; + + if ((partial + len) > 63) { + if (partial) { + done = -partial; + memcpy(sctx->buf + partial, data, done + 64); + src = sctx->buf; + } + + do { + sha256_transform(sctx->state, src); + done += 64; + src = data + done; + } while (done + 63 < len); + + partial = 0; + } + memcpy(sctx->buf + partial, src, len - done); + + return 0; +} + +static int sha256_final(struct shash_desc *desc, u8 *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + __be32 *dst = (__be32 *)out; + __be64 bits; + unsigned int index, pad_len; + int i; + static const u8 padding[64] = { 0x80, }; + + /* Save number of bits */ + bits = cpu_to_be64(sctx->count << 3); + + /* Pad out to 56 mod 64. */ + index = sctx->count & 0x3f; + pad_len = (index < 56) ? (56 - index) : ((64+56) - index); + sha256_update(desc, padding, pad_len); + + /* Append length (before padding) */ + sha256_update(desc, (const u8 *)&bits, sizeof(bits)); + + /* Store state in digest */ + for (i = 0; i < 8; i++) + dst[i] = cpu_to_be32(sctx->state[i]); + + /* Zeroize sensitive information. */ + memset(sctx, 0, sizeof(*sctx)); + + printk(KERN_INFO "%s: fmp sha256 S/W final is done.\n", __func__); + return 0; +} + +static int sha256_export(struct shash_desc *desc, void *out) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(out, sctx, sizeof(*sctx)); + return 0; +} + +static int sha256_import(struct shash_desc *desc, const void *in) +{ + struct sha256_state *sctx = shash_desc_ctx(desc); + + memcpy(sctx, in, sizeof(*sctx)); + return 0; +} + +static struct shash_alg sha256_algs[1] = { { + .digestsize = SHA256_DIGEST_SIZE, + .init = sha256_init, + .update = sha256_update, + .final = sha256_final, + .export = sha256_export, + .import = sha256_import, + .descsize = sizeof(struct sha256_state), + .statesize = sizeof(struct sha256_state), + .base = { + .cra_name = "sha256-fmp", + .cra_driver_name= "sha256-fmp", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +} +}; + +static int __init sha256_generic_mod_init(void) +{ + return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); +} + +static void __exit sha256_generic_mod_fini(void) +{ + crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); +} + +module_init(sha256_generic_mod_init); +module_exit(sha256_generic_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA-256 Secure Hash Algorithm"); + +MODULE_ALIAS("sha256-fmp"); diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 397baf5c7c25..d76ed584fb94 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -128,6 +128,21 @@ config ARM_EXYNOS7420_BUS_DEVFREQ help This adds the DEVFREQ driver for Exynos5 series memory and int. +config ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET + bool "Apply Dynamically DRAM Thermal offset -10" + default y + depends on ARM_EXYNOS7420_BUS_DEVFREQ + +config ARM_EXYNOS7420_BUS_DEVFREQ_ODT_OFF + bool "Apply DRAM DQ ODT OFF(below 632MHz)" + default n + depends on ARM_EXYNOS7420_BUS_DEVFREQ + +config ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING + bool "Apply advanced mif thermal polling period" + default n + depends on ARM_EXYNOS7420_BUS_DEVFREQ + config ARM_EXYNOS7580_BUS_DEVFREQ bool "ARM Exynos7580 Memory Bus DEVFREQ Driver" default y diff --git a/drivers/devfreq/devfreq_exynos.h b/drivers/devfreq/devfreq_exynos.h index da7a70901f20..f3159f8bd430 100644 --- a/drivers/devfreq/devfreq_exynos.h +++ b/drivers/devfreq/devfreq_exynos.h @@ -234,6 +234,8 @@ struct devfreq_data_mif { void __iomem *base_vt_mon_mif[MIF_BLK_NUM]; void __iomem *base_nsp; + uint32_t mid; /* Manufacturer ID */ + int default_qos; int initial_freq; int cal_qos_max; @@ -243,6 +245,9 @@ struct devfreq_data_mif { uint32_t tmu_temp; + uint32_t mem_density; + uint32_t tREFI; + uint32_t per_mrs_en; uint32_t pll_safe_idx; ulong switching_pll_rate; /* dout_sclk_bus0_pll_mif(800M) */ @@ -336,6 +341,22 @@ struct devfreq_thermal_work { unsigned long max_freq; }; +typedef enum { + LP4_Non_SEC=0, + LP4_SEC=1, +} lp4_mid_t; + +typedef enum { + LP4_4Gb_Die=0, + LP4_6Gb_Die=1, + LP4_8Gb_Die=2, + LP4_12Gb_Die=3, + LP4_16Gb_Die=4, + LP4_24Gb_Die=5, + LP4_32Gb_Die=6, + LP4_Invalid_Die=7, +} lp4_density_t; + #define CTRL_LOCK_VALUE_SHIFT (0x8) #define CTRL_LOCK_VALUE_MASK (0x1FF) #define CTRL_FORCE_SHIFT (0x7) diff --git a/drivers/devfreq/exynos7420_bus.c b/drivers/devfreq/exynos7420_bus.c index 26eb9d0eabcd..4ae305083831 100644 --- a/drivers/devfreq/exynos7420_bus.c +++ b/drivers/devfreq/exynos7420_bus.c @@ -2081,10 +2081,12 @@ static int exynos7_devfreq_int_init_clock(void) } for (i = 0; i < ARRAY_SIZE(devfreq_clk_int_info_list); ++i) { - if (strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_mfc_532") && - strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_mscl_532") && - strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_vpp0_400") && - strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_vpp1_400")) + if (!strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_bus0_532") || + !strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_bus1_532") || + !strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_bus1_200") || + !strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_pclk_bus01_133") || + !strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_imem_266") || + !strcmp(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk_name, "dout_aclk_imem_200")) clk_prepare_enable(devfreq_int_clk[devfreq_clk_int_info_idx[i]].clk); } @@ -3655,7 +3657,55 @@ struct dmc_vtmon_dfs_mif_table #define PHY_DVFS_CON5_SET1_MASK (0x0)|(1<<31)|(0xF<<20)|(0xF<<12)|(0xF<<4) #define PHY_DVFS_CON5_SET0_MASK (0x0)|(1<<30)|(0xF<<16)|(0xF<<8)|(0xF<<0) +#ifdef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ODT_OFF +#define MR11_DRAM_DQ_ODT 0x00 /* DQ_ODT Disable */ +#else +#define MR11_DRAM_DQ_ODT 0x04 /* DQ_ODT RZQ/4 */ +#endif + #if defined(DMC_DQS_MODE2) +/* for SEC 12Gb die DRAM */ +static struct dmc_drex_dfs_mif_table dfs_drex_mif_table_12Gb[] = +{ + DREX_TIMING_PARA(0x00003737, 0x6D588652, 0x4732BBE0, 0x40710336, 0x00004E02, 0x00000000, 0x319BA14A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00003333, 0x66588611, 0x4732BBE0, 0x3C6A0336, 0x00004902, 0x00000000, 0x319BA14A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00002D2D, 0x5947754F, 0x4632B3DC, 0x345C0335, 0x00004002, 0x00000000, 0x319BA13A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00002626, 0x4B46648C, 0x3532B39C, 0x2C4E0335, 0x00003602, 0x00000000, 0x319BA13A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001D1D, 0x3A35538A, 0x3422AAD6, 0x243D0234, 0x00002A02, 0x00000000, 0x219BA12A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x1B<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001717, 0x2D2442C8, 0x2322A310, 0x1C2F0233, 0x00002003, 0x00000000, 0x019BA10B, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), +#ifdef L6_RL_WL_DECREASE + DREX_TIMING_PARA(0x00001414, 0x27233247, 0x23229ACC, 0x18290233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), +#else + DREX_TIMING_PARA(0x00001414, 0x27233247, 0x2322A2D0, 0x18290233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), +#endif + DREX_TIMING_PARA(0x00000F0F, 0x1e2331C5, 0x22229ACC, 0x141F0233, 0x00001502, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000D0D, 0x19232185, 0x22229ACC, 0x101F0233, 0x00001202, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +#ifdef L9_RL_WL_DECREASE + DREX_TIMING_PARA(0x00000A0A, 0x19232144, 0x22229286, 0x0C1F0233, 0x00000E02, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +#else + DREX_TIMING_PARA(0x00000A0A, 0x19232144, 0x22229A8C, 0x0C1F0233, 0x00000E02, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +#endif + DREX_TIMING_PARA(0x00000606, 0x192320C3, 0x22229286, 0x081F0233, 0x00000902, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000505, 0x192320C2, 0x22229286, 0x081F0233, 0x00000702, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000404, 0x192320C2, 0x22229286, 0x081F0233, 0x00000502, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +}; + +/* for SEC 6Gb die DRAM */ static struct dmc_drex_dfs_mif_table dfs_drex_mif_table[] = { DREX_TIMING_PARA(0x00002323, 0x46588652, 0x4732BBE0, 0x404A0336, 0x00004E02, 0x00000000, 0x319BA14A, 0x00005DC0, 0x01010101, 0x00000003, @@ -3669,13 +3719,13 @@ static struct dmc_drex_dfs_mif_table dfs_drex_mif_table[] = DREX_TIMING_PARA(0x00001313, 0x2635538A, 0x3422AAD6, 0x24280234, 0x00002A02, 0x00000000, 0x219BA12A, 0x00FFFFFF, 0x00000000, 0x00000000, 0x00211400, 0x00200800|(0x1B<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), DREX_TIMING_PARA(0x00000F0F, 0x1D2442C8, 0x2322A310, 0x1C1F0233, 0x00002003, 0x00000000, 0x019BA10B, 0x00FFFFFF, 0x00000000, 0x00000000, - 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), #ifdef L6_RL_WL_DECREASE DREX_TIMING_PARA(0x00000D0D, 0x19233247, 0x23229ACC, 0x181F0233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, - 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), #else DREX_TIMING_PARA(0x00000D0D, 0x19233247, 0x2322A2D0, 0x181F0233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, - 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), #endif DREX_TIMING_PARA(0x00000A0A, 0x192331C5, 0x22229ACC, 0x141F0233, 0x00001502, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), @@ -3696,6 +3746,69 @@ static struct dmc_drex_dfs_mif_table dfs_drex_mif_table[] = 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), }; +/* for Non-SEC 12Gb die DRAM */ +static struct dmc_drex_dfs_mif_table dfs_drex_mif_table_nonsec_12Gb[] = +{ + DREX_TIMING_PARA(0x00003737, 0x6D588652, 0x4732BBE0, 0x40710336, 0x00004E02, 0x00000000, 0x319BA14A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00003333, 0x66588611, 0x4732BBE0, 0x3C6A0336, 0x00004902, 0x00000000, 0x319BA14A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00002D2D, 0x5947754F, 0x4632B3DC, 0x345C0335, 0x00004002, 0x00000000, 0x319BA13A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00002626, 0x4B46648C, 0x3532B39C, 0x2C4E0335, 0x00003602, 0x00000000, 0x319BA13A, 0x00005DC0, 0x00000101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001D1D, 0x3A35538A, 0x3422AAD6, 0x243D0234, 0x00002A02, 0x00000000, 0x219BA12A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x1B<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001717, 0x2D2442C8, 0x2322A310, 0x1C2F0233, 0x00002003, 0x00000000, 0x019BA10B, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001414, 0x27233247, 0x2322A2D0, 0x18290233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000F0F, 0x1e2331C5, 0x22229ACC, 0x141F0233, 0x00001502, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000D0D, 0x19232185, 0x22229ACC, 0x101F0233, 0x00001202, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000A0A, 0x19232144, 0x22229A8C, 0x0C1F0233, 0x00000E02, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000606, 0x192320C3, 0x22229286, 0x081F0233, 0x00000902, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000505, 0x192320C2, 0x22229286, 0x081F0233, 0x00000702, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000404, 0x192320C2, 0x22229286, 0x081F0233, 0x00000502, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +}; + +/* for Non-SEC 6Gb die DRAM */ +static struct dmc_drex_dfs_mif_table dfs_drex_mif_table_nonsec[] = +{ + DREX_TIMING_PARA(0x00002323, 0x46588652, 0x4732BBE0, 0x404A0336, 0x00004E02, 0x00000000, 0x319BA14A, 0x00005DC0, 0x01010101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00002121, 0x42588611, 0x4732BBE0, 0x3C460336, 0x00004902, 0x00000000, 0x319BA14A, 0x00005DC0, 0x01010101, 0x00000003, + 0x00211400, 0x00200800|(0x2D<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001D1D, 0x3947754F, 0x4632B3DC, 0x343D0335, 0x00004002, 0x00000000, 0x319BA13A, 0x00005DC0, 0x01010101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001919, 0x3146648C, 0x3532B39C, 0x2C340335, 0x00003602, 0x00000000, 0x319BA13A, 0x00005DC0, 0x01010101, 0x00000003, + 0x00211400, 0x00200800|(0x24<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00001313, 0x2635538A, 0x3422AAD6, 0x24280234, 0x00002A02, 0x00000000, 0x219BA12A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x1B<<2), 0x00221800 | (0x26<<2), 0x00210c00|(0x04<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000F0F, 0x1D2442C8, 0x2322A310, 0x1C1F0233, 0x00002003, 0x00000000, 0x019BA10B, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000D0D, 0x19233247, 0x2322A2D0, 0x181F0233, 0x00001C02, 0x00000000, 0x019BA10A, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x12<<2), 0x00221800 | (0x26<<2), 0x00210c00|(MR11_DRAM_DQ_ODT<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000A0A, 0x192331C5, 0x22229ACC, 0x141F0233, 0x00001502, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000808, 0x19232185, 0x22229ACC, 0x101F0233, 0x00001202, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000707, 0x19232144, 0x22229A8C, 0x0C1F0233, 0x00000E02, 0x00000000, 0x019BA0FA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x09<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000404, 0x192320C3, 0x22229286, 0x081F0233, 0x00000902, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000303, 0x192320C2, 0x22229286, 0x081F0233, 0x00000702, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), + DREX_TIMING_PARA(0x00000303, 0x192320C2, 0x22229286, 0x081F0233, 0x00000502, 0x00000000, 0x019BA0EA, 0x00FFFFFF, 0x00000000, 0x00000000, + 0x00211400, 0x00200800|(0x00<<2), 0x00221800 | (0x24<<2), 0x00210c00|(0x00<<2), 0x00211800|(0x0F<<2), 0x00000000), +}; + +/* for SEC memory */ static struct dmc_phy_dfs_mif_table dfs_phy_mif_table[] = { PHY_DVFS_CON(0x80200000|(dvfs_dqs_osc_en<<17), 0x40100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, @@ -3795,6 +3908,89 @@ static struct dmc_phy_dfs_mif_table dfs_phy_mif_table[] = 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), }; + +/* for Non-SEC memory */ +static struct dmc_phy_dfs_mif_table dfs_phy_mif_table_nonsec[] = +{ + PHY_DVFS_CON(0x80200000|(dvfs_dqs_osc_en<<17), 0x40100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x2000B000, 0x002000B0, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x0860E000, 0x0400060E, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x80700000, 0x40070000, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x2000B000, 0x002000B0, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x085B0000, 0x040005B0, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x80700000, 0x40070000, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x1C00B000, 0x001C00B0, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x084F0000, 0x040004F0, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x80700000, 0x40070000, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x1C00B000, 0x001C00B0, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x0842C000, 0x0400042C, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x80700000, 0x40070000, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x16004000, 0x00160040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x0033C000, 0x0000033C, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x00501000, 0x00050100, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_offset<<8)|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_offset<<0)|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x10004000, 0x00100040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x00278000, 0x00000278, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x00501000, 0x00050100, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_offset<<8)|(dvfs_dqs_osc_en<<17), 0x41100000|(dvfs_offset<<0)|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x10004000, 0x00100040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x0021F000, 0x0000021F, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x00501000, 0x00050100, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82200000|(dvfs_offset<<8)|(dvfs_dqs_osc_en<<17), 0x41500000|(dvfs_offset<<0)|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x0C004000, 0x400C0040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x001A0000, 0x000001A0, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x00501000, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82A80000|(dvfs_dqs_osc_en<<17), 0x41540000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x8C004000, 0x400C0040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x0015C000, 0x0000015C, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82A80000|(dvfs_dqs_osc_en<<17), 0x41540000|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x8C004000, 0x400C0040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x00114000, 0x00000114, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82803000|(dvfs_dqs_osc_en<<17), 0x41400030|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x86004000, 0x40060040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x000A7000, 0x000000A7, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82803000|(dvfs_dqs_osc_en<<17), 0x41400030|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x86004000, 0x40060040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x00085000, 0x00000085, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), + PHY_DVFS_CON(0x82803000|(dvfs_dqs_osc_en<<17), 0x41400030|(dvfs_dqs_osc_en<<16), PHY_DVFS_CON0_SET1_MASK, PHY_DVFS_CON0_SET0_MASK, + 0x86004000, 0x40060040, PHY_DVFS_CON1_SET1_MASK, PHY_DVFS_CON1_SET0_MASK, + 0x20000000, 0x00400000, PHY_DVFS_CON2_SET1_MASK, PHY_DVFS_CON2_SET0_MASK, + 0x00064000, 0x00000064, PHY_DVFS_CON3_SET1_MASK, PHY_DVFS_CON3_SET0_MASK, + 0x00000000, 0x00000000, PHY_DVFS_CON4_SET1_MASK, PHY_DVFS_CON4_SET0_MASK, + 0x005010F0, 0x0005010F, PHY_DVFS_CON5_SET1_MASK, PHY_DVFS_CON5_SET0_MASK), +}; #elif defined(DMC_DQS_MODE1) static struct dmc_drex_dfs_mif_table dfs_drex_mif_table[] = { @@ -4216,16 +4412,28 @@ static int exynos7_devfreq_mif_preset(struct devfreq_data_mif *data, struct dmc_vtmon_dfs_mif_table *cur_vtmon_param; uint32_t tmp; int i; - uint32_t soc_vref[MIF_BLK_NUM][NUM_OF_SLICE]; + uint32_t soc_vref[MIF_BLK_NUM][NUM_OF_SLICE]; + + if (data_mif->mid == LP4_SEC) { + if (data_mif->mem_density == LP4_12Gb_Die) + cur_drex_param = &dfs_drex_mif_table_12Gb[target_idx]; + else + cur_drex_param = &dfs_drex_mif_table[target_idx]; + cur_phy_param = &dfs_phy_mif_table[target_idx]; + } else { + if (data_mif->mem_density == LP4_12Gb_Die) + cur_drex_param = &dfs_drex_mif_table_nonsec_12Gb[target_idx]; + else + cur_drex_param = &dfs_drex_mif_table_nonsec[target_idx]; + cur_phy_param = &dfs_phy_mif_table_nonsec[target_idx]; + } - cur_drex_param = &dfs_drex_mif_table[target_idx]; - cur_phy_param = &dfs_phy_mif_table[target_idx]; cur_vtmon_param = &dfs_vtmon_mif_table[target_idx]; - for (i = 0; i< MIF_BLK_NUM; i++) { - soc_vref[i][1] = (__raw_readl(data->base_lp4_phy[i] + PHY_ZQ_CON9) & 0x3f00) >> 8; - soc_vref[i][0] = (__raw_readl(data->base_lp4_phy[i] + PHY_ZQ_CON9) & 0x003f) >> 0; - } + for (i = 0; i< MIF_BLK_NUM; i++) { + soc_vref[i][1] = (__raw_readl(data->base_lp4_phy[i] + PHY_ZQ_CON9) & 0x3f00) >> 8; + soc_vref[i][0] = (__raw_readl(data->base_lp4_phy[i] + PHY_ZQ_CON9) & 0x003f) >> 0; + } pr_debug(" ===> pre-setting mif_timing_set_#%d\n", timing_set_num); @@ -4276,7 +4484,7 @@ static int exynos7_devfreq_mif_preset(struct devfreq_data_mif *data, __raw_writel(cur_vtmon_param->vtmon_Cnt_Limit_set1, data->base_vt_mon_mif[i] + VTMON_CNT_LIMIT_SET1_SW1); /* DIRECTCMD */ - __raw_writel((0x40<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_drex[i] + DREX_DIRECTCMD); + __raw_writel((0x50<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr2, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr22, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr11, data->base_drex[i] + DREX_DIRECTCMD); @@ -4284,7 +4492,7 @@ static int exynos7_devfreq_mif_preset(struct devfreq_data_mif *data, /* VTMON */ __raw_writel((0x1<<0)| cur_drex_param->vtmon_Drex_Timing_Set_Sw, data->base_vt_mon_mif[i] + VTMON_DREX_TIMING_SW_SET); - __raw_writel((0xC0<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_vt_mon_mif[i] + VTMON_MIF_DREX_WDATA0); + __raw_writel((0xD0<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_vt_mon_mif[i] + VTMON_MIF_DREX_WDATA0); } } else { for (i = 0; i< MIF_BLK_NUM; i++) { @@ -4333,7 +4541,7 @@ static int exynos7_devfreq_mif_preset(struct devfreq_data_mif *data, __raw_writel(cur_vtmon_param->vtmon_Cnt_Limit_set1, data->base_vt_mon_mif[i] + VTMON_CNT_LIMIT_SET1_SW0); /* DIRECTCMD */ - __raw_writel((0x80<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_drex[i] + DREX_DIRECTCMD); + __raw_writel((0x90<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr2, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr22, data->base_drex[i] + DREX_DIRECTCMD); __raw_writel(cur_drex_param->drex_DirectCmd_mr11, data->base_drex[i] + DREX_DIRECTCMD); @@ -4341,7 +4549,7 @@ static int exynos7_devfreq_mif_preset(struct devfreq_data_mif *data, /* VTMON */ __raw_writel((0x0<<0)|cur_drex_param->vtmon_Drex_Timing_Set_Sw, data->base_vt_mon_mif[i] + VTMON_DREX_TIMING_SW_SET); - __raw_writel((0x0<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_vt_mon_mif[i] + VTMON_MIF_DREX_WDATA0); + __raw_writel((0x10<<2)|cur_drex_param->drex_DirectCmd_mr13, data->base_vt_mon_mif[i] + VTMON_MIF_DREX_WDATA0); } } return 0; @@ -4658,7 +4866,8 @@ static int exynos7_devfreq_mif_set_freq(struct devfreq_data_mif *data, exynos7_devfreq_check_mif_mux_ctrl_by_cmuc(data); #ifdef DRAM_POWER_DYNAMIC_SAVE - exynos7_devfreq_mif_set_refresh_method_pre_dvfs(data, target_idx, old_idx); + if (!((data->mem_density == LP4_12Gb_Die) && (data->tREFI == RATE_QUARTER))) + exynos7_devfreq_mif_set_refresh_method_pre_dvfs(data, target_idx, old_idx); #endif if ((old_idx <= MIF_LV4) && (target_idx <= MIF_LV4)) { clk_set_rate(devfreq_mif_clk[DOUT_SCLK_BUS0_PLL_MIF].clk, 1600000000); @@ -4820,7 +5029,8 @@ static int exynos7_devfreq_mif_set_freq(struct devfreq_data_mif *data, } #ifdef DRAM_POWER_DYNAMIC_SAVE - exynos7_devfreq_mif_set_refresh_method_post_dvfs(data, target_idx, old_idx); + if (!((data->mem_density == LP4_12Gb_Die) && (data->tREFI == RATE_QUARTER))) + exynos7_devfreq_mif_set_refresh_method_post_dvfs(data, target_idx, old_idx); exynos7_devfreq_mif_set_dynamic_sref_cycle(data, target_idx); #endif @@ -4839,11 +5049,14 @@ int exynos7_devfreq_mif_tmu_notifier(struct notifier_block *nb, unsigned long ev tmu_notifier); unsigned int prev_volt, set_volt; unsigned int *on = v, cl_idx; - int i; struct opp *target_opp; unsigned long freq = 0; +#ifdef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET + int i; +#endif if (event == MIF_TH_LV2) { +#ifdef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET /* it means that tmu_temp is Greater than or equal to 65 degrees */ mutex_lock(&data->lock); @@ -4858,8 +5071,10 @@ int exynos7_devfreq_mif_tmu_notifier(struct notifier_block *nb, unsigned long ev mutex_unlock(&data->lock); pr_info("MIF_TH_LV2 from TMU, %d\n", data->tmu_temp); +#endif return NOTIFY_OK; } else if (event == MIF_TH_LV1) { +#ifdef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET /* it means that tmu_temp is under 65 degrees */ mutex_lock(&data->lock); @@ -4867,6 +5082,7 @@ int exynos7_devfreq_mif_tmu_notifier(struct notifier_block *nb, unsigned long ev mutex_unlock(&data->lock); pr_info("MIF_TH_LV1 from TMU, %d\n", data->tmu_temp); +#endif return NOTIFY_OK; } else if (event == TMU_COLD) { if (*on) { @@ -4956,6 +5172,104 @@ static void exynos7_devfreq_thermal_event(struct devfreq_thermal_work *work) #endif } +#if defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) +#define MIF_THERMAL_MR4_OFFSET 2 +#define MIF_THERMAL_MR4_MAX_IDX 2 +#define MIF_THERMAL_MR4_MAX_PERIOD 5000 + +static int mif_thermal_polling_period[][4] = { + /* Freq 2 3 4 */ + {400000, 5000, 1000, 100}, + {1000000, 500, 100, 100}, + {2100000, 100, 100, 100}, +}; + +struct mif_thermal_data { + uint32_t max_thermal_level; + uint32_t prev_period; + uint32_t target_freq; + uint32_t cl; + bool big_alive; +}; + +static struct mif_thermal_data thermal_data = { + .max_thermal_level = 0, + .prev_period = 0, + .target_freq = 1000000, + .cl = 0, + .big_alive = 1, +}; + +static int mif_thermal_set_polling_period(void) +{ + unsigned int i; + int clk_idx = 0; + int mr4_idx = 0; + unsigned int polling_period = 0; + + if (!data_mif || !data_mif->use_dvfs) + return -1; + + mutex_lock(&data_mif->lock); + + mr4_idx = thermal_data.max_thermal_level - MIF_THERMAL_MR4_OFFSET; + if (mr4_idx >= MIF_THERMAL_MR4_MAX_IDX) + mr4_idx = MIF_THERMAL_MR4_MAX_IDX; + else if (mr4_idx < 0) + mr4_idx = 0; + + for (i = 0; i < ARRAY_SIZE(mif_thermal_polling_period); i++) { + if (thermal_data.target_freq <= mif_thermal_polling_period[i][0]) { + clk_idx = i; + break; + } + } + + if (thermal_data.big_alive && clk_idx == 0) + clk_idx++; + + polling_period = mif_thermal_polling_period[clk_idx][mr4_idx + 1]; + + if (thermal_data.prev_period == polling_period) { + mutex_unlock(&data_mif->lock); + return -1; + } + + thermal_data.prev_period = devfreq_mif_thermal_work.polling_period = polling_period; + + pr_debug("%s: %d, %d, %d, %d, %d, %d, %d\n", + __func__, devfreq_mif_thermal_work.polling_period, clk_idx, mr4_idx, + thermal_data.target_freq, thermal_data.max_thermal_level, + thermal_data.cl, thermal_data.big_alive); + + mutex_unlock(&data_mif->lock); + + return 0; +} + +void exynos7_devfreq_mif_thermal_set_polling_period(uint32_t target_freq, uint32_t cl, bool big_alive) +{ + if (!data_mif || !data_mif->use_dvfs) + return; + + mutex_lock(&data_mif->lock); + thermal_data.target_freq = target_freq; + thermal_data.cl = cl; + thermal_data.big_alive = big_alive; + mutex_unlock(&data_mif->lock); + + if (mif_thermal_set_polling_period()) + return; + + if (devfreq_mif_thermal_work.polling_period >= MIF_THERMAL_MR4_MAX_PERIOD) { + flush_delayed_work(&devfreq_mif_thermal_work.devfreq_mif_thermal_work); + } + + exynos7_devfreq_thermal_event(&devfreq_mif_thermal_work); +} +EXPORT_SYMBOL(exynos7_devfreq_mif_thermal_set_polling_period); +#endif /*CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING */ + static ssize_t mif_show_templvl_ch0_0(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%u\n", devfreq_mif_thermal_work.thermal_level_ch0_cs0); @@ -5063,6 +5377,7 @@ enum devfreq_mif_thermal_autorate exynos7_devfreq_get_autorate(unsigned int ther return timingaref_value; } +#ifdef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET static void exynos7_devfreq_mr4_set(void __iomem *base_drex, uint32_t cs_num, uint32_t prev_mr4, uint32_t next_mr4, uint32_t tmu_temp) { uint32_t cmd_chip; @@ -5078,6 +5393,12 @@ static void exynos7_devfreq_mr4_set(void __iomem *base_drex, uint32_t cs_num, ui } } } +#else +static void exynos7_devfreq_mr4_set(void __iomem *base_drex, uint32_t cs_num, uint32_t prev_mr4, uint32_t next_mr4, uint32_t tmu_temp) +{ + return; +} +#endif static void exynos7_devfreq_thermal_monitor(struct work_struct *work) { @@ -5127,12 +5448,14 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) max_thermal_level = ch0_cs0_thermal_level; thermal_work->thermal_level_ch0_cs0 = ch0_cs0_thermal_level; - __raw_writel(0x09101000, base_drex0 + DREX_DIRECTCMD); - mrstatus0 = __raw_readl(base_drex0 + MRSTATUS); - ch0_cs1_thermal_level = (mrstatus0 & MRSTATUS_THERMAL_LV_MASK); - exynos7_devfreq_mr4_set(base_drex0, 1, thermal_work->thermal_level_ch0_cs1, ch0_cs1_thermal_level, data_mif->tmu_temp); - if (ch0_cs1_thermal_level > max_thermal_level) - max_thermal_level = ch0_cs1_thermal_level; + if (data_mif->mem_density != LP4_12Gb_Die) { + __raw_writel(0x09101000, base_drex0 + DREX_DIRECTCMD); + mrstatus0 = __raw_readl(base_drex0 + MRSTATUS); + ch0_cs1_thermal_level = (mrstatus0 & MRSTATUS_THERMAL_LV_MASK); + exynos7_devfreq_mr4_set(base_drex0, 1, thermal_work->thermal_level_ch0_cs1, ch0_cs1_thermal_level, data_mif->tmu_temp); + if (ch0_cs1_thermal_level > max_thermal_level) + max_thermal_level = ch0_cs1_thermal_level; + } thermal_work->thermal_level_ch0_cs1 = ch0_cs1_thermal_level; ch0_max_thermal_level = max(ch0_cs0_thermal_level, ch0_cs1_thermal_level); @@ -5145,12 +5468,14 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) max_thermal_level = ch1_cs0_thermal_level; thermal_work->thermal_level_ch1_cs0 = ch1_cs0_thermal_level; - __raw_writel(0x09101000, base_drex1 + DREX_DIRECTCMD); - mrstatus1 = __raw_readl(base_drex1 + MRSTATUS); - ch1_cs1_thermal_level = (mrstatus1 & MRSTATUS_THERMAL_LV_MASK); - exynos7_devfreq_mr4_set(base_drex1, 1, thermal_work->thermal_level_ch1_cs1, ch1_cs1_thermal_level, data_mif->tmu_temp); - if (ch1_cs1_thermal_level > max_thermal_level) - max_thermal_level = ch1_cs1_thermal_level; + if (data_mif->mem_density != LP4_12Gb_Die) { + __raw_writel(0x09101000, base_drex1 + DREX_DIRECTCMD); + mrstatus1 = __raw_readl(base_drex1 + MRSTATUS); + ch1_cs1_thermal_level = (mrstatus1 & MRSTATUS_THERMAL_LV_MASK); + exynos7_devfreq_mr4_set(base_drex1, 1, thermal_work->thermal_level_ch1_cs1, ch1_cs1_thermal_level, data_mif->tmu_temp); + if (ch1_cs1_thermal_level > max_thermal_level) + max_thermal_level = ch1_cs1_thermal_level; + } thermal_work->thermal_level_ch1_cs1 = ch1_cs1_thermal_level; ch1_max_thermal_level = max(ch1_cs0_thermal_level, ch1_cs1_thermal_level); @@ -5163,12 +5488,14 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) max_thermal_level = ch2_cs0_thermal_level; thermal_work->thermal_level_ch2_cs0 = ch2_cs0_thermal_level; - __raw_writel(0x09101000, base_drex2 + DREX_DIRECTCMD); - mrstatus2 = __raw_readl(base_drex2 + MRSTATUS); - ch2_cs1_thermal_level = (mrstatus2 & MRSTATUS_THERMAL_LV_MASK); - exynos7_devfreq_mr4_set(base_drex2, 1, thermal_work->thermal_level_ch2_cs1, ch2_cs1_thermal_level, data_mif->tmu_temp); - if (ch2_cs1_thermal_level > max_thermal_level) - max_thermal_level = ch2_cs1_thermal_level; + if (data_mif->mem_density != LP4_12Gb_Die) { + __raw_writel(0x09101000, base_drex2 + DREX_DIRECTCMD); + mrstatus2 = __raw_readl(base_drex2 + MRSTATUS); + ch2_cs1_thermal_level = (mrstatus2 & MRSTATUS_THERMAL_LV_MASK); + exynos7_devfreq_mr4_set(base_drex2, 1, thermal_work->thermal_level_ch2_cs1, ch2_cs1_thermal_level, data_mif->tmu_temp); + if (ch2_cs1_thermal_level > max_thermal_level) + max_thermal_level = ch2_cs1_thermal_level; + } thermal_work->thermal_level_ch2_cs1 = ch2_cs1_thermal_level; ch2_max_thermal_level = max(ch2_cs0_thermal_level, ch2_cs1_thermal_level); @@ -5181,16 +5508,22 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) max_thermal_level = ch3_cs0_thermal_level; thermal_work->thermal_level_ch3_cs0 = ch3_cs0_thermal_level; - __raw_writel(0x09101000, base_drex3 + DREX_DIRECTCMD); - mrstatus3 = __raw_readl(base_drex3 + MRSTATUS); - ch3_cs1_thermal_level = (mrstatus3 & MRSTATUS_THERMAL_LV_MASK); - exynos7_devfreq_mr4_set(base_drex3, 1, thermal_work->thermal_level_ch3_cs1, ch3_cs1_thermal_level, data_mif->tmu_temp); - if (ch3_cs1_thermal_level > max_thermal_level) - max_thermal_level = ch3_cs1_thermal_level; + if (data_mif->mem_density != LP4_12Gb_Die) { + __raw_writel(0x09101000, base_drex3 + DREX_DIRECTCMD); + mrstatus3 = __raw_readl(base_drex3 + MRSTATUS); + ch3_cs1_thermal_level = (mrstatus3 & MRSTATUS_THERMAL_LV_MASK); + exynos7_devfreq_mr4_set(base_drex3, 1, thermal_work->thermal_level_ch3_cs1, ch3_cs1_thermal_level, data_mif->tmu_temp); + if (ch3_cs1_thermal_level > max_thermal_level) + max_thermal_level = ch3_cs1_thermal_level; + } thermal_work->thermal_level_ch3_cs1 = ch3_cs1_thermal_level; ch3_max_thermal_level = max(ch3_cs0_thermal_level, ch3_cs1_thermal_level); +#if defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) + thermal_data.max_thermal_level = max_thermal_level; +#endif + mutex_unlock(&data_mif->lock); switch (max_thermal_level) { @@ -5198,20 +5531,28 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) case 1: case 2: case 3: +#if !defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) thermal_work->polling_period = 500; +#endif break; case 4: throttling = true; +#if !defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) thermal_work->polling_period = 300; +#endif break; case 5: case 6: throttling = true; +#if !defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) thermal_work->polling_period = 100; +#endif break; case 7: throttling = true; +#if !defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) thermal_work->polling_period = 100; +#endif exynos7_devfreq_swtrip(); break; default: @@ -5236,17 +5577,35 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) /* set timming auto refresh rate */ mutex_lock(&data_mif->lock); ch0_timingaref_value = exynos7_devfreq_get_autorate(ch0_max_thermal_level); - if (ch0_timingaref_value > 0) + if (ch0_timingaref_value > 0) { + /* If memory is 12Gb die and it is under hot-temp, it use ABR */ + if ((ch0_timingaref_value == RATE_QUARTER) && (data_mif->mem_density == LP4_12Gb_Die)) + exynos7_devfreq_mif_set_PBR_en(data_mif, 0); __raw_writel(ch0_timingaref_value, base_drex0 + TIMINGAREF); + /* data_mif->tREFI is the worst tREFI of 4 channels */ + data_mif->tREFI = ch0_timingaref_value; + } ch1_timingaref_value = exynos7_devfreq_get_autorate(ch1_max_thermal_level); - if (ch1_timingaref_value > 0) + if (ch1_timingaref_value > 0) { + if ((ch1_timingaref_value == RATE_QUARTER) && (data_mif->tREFI != RATE_QUARTER) && (data_mif->mem_density == LP4_12Gb_Die)) + exynos7_devfreq_mif_set_PBR_en(data_mif, 0); __raw_writel(ch1_timingaref_value, base_drex1 + TIMINGAREF); + data_mif->tREFI = min(data_mif->tREFI, ch1_timingaref_value); + } ch2_timingaref_value = exynos7_devfreq_get_autorate(ch2_max_thermal_level); - if (ch2_timingaref_value > 0) + if (ch2_timingaref_value > 0) { + if ((ch2_timingaref_value == RATE_QUARTER) && (data_mif->tREFI != RATE_QUARTER) && (data_mif->mem_density == LP4_12Gb_Die)) + exynos7_devfreq_mif_set_PBR_en(data_mif, 0); __raw_writel(ch2_timingaref_value, base_drex2 + TIMINGAREF); + data_mif->tREFI = min(data_mif->tREFI, ch2_timingaref_value); + } ch3_timingaref_value = exynos7_devfreq_get_autorate(ch3_max_thermal_level); - if (ch3_timingaref_value > 0) + if (ch3_timingaref_value > 0) { + if ((ch3_timingaref_value == RATE_QUARTER) && (data_mif->tREFI != RATE_QUARTER) && (data_mif->mem_density == LP4_12Gb_Die)) + exynos7_devfreq_mif_set_PBR_en(data_mif, 0); __raw_writel(ch3_timingaref_value, base_drex3 + TIMINGAREF); + data_mif->tREFI = min(data_mif->tREFI, ch3_timingaref_value); + } mutex_unlock(&data_mif->lock); exynos_ss_printk("[MIF]%d,%d(tREFI:0x%08x);%d,%d(0x%08x);%d,%d(0x%08x);%d,%d(0x%08x)", @@ -5254,6 +5613,11 @@ static void exynos7_devfreq_thermal_monitor(struct work_struct *work) ch1_cs0_thermal_level, ch1_cs1_thermal_level, ch1_timingaref_value, ch2_cs0_thermal_level, ch2_cs1_thermal_level, ch2_timingaref_value, ch3_cs0_thermal_level, ch3_cs1_thermal_level, ch3_timingaref_value); + +#if defined(CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_ADV_MIF_THERMAL_POLLING) + mif_thermal_set_polling_period(); + pr_debug("%s: polling_period = %d\n", __func__, thermal_work->polling_period); +#endif exynos7_devfreq_thermal_event(thermal_work); } @@ -5300,6 +5664,59 @@ int exynos7_devfreq_mif_init_clock(void) return 0; } +static lp4_density_t exynos7_devfreq_lp4_size(struct devfreq_data_mif *data, char *name) +{ + unsigned int mem_type, mem_density, mem_width; + unsigned int mrstatus; + int loop=20, delay; + int ch = 0; + + do { + __raw_writel(0x09010000, data->base_drex[ch] + DREX_DIRECTCMD); + mrstatus = __raw_readl(data->base_drex[ch] + MRSTATUS); + + mem_type = mrstatus & 0x3; + mem_density = (mrstatus >> 2) & 0xF; + mem_width = (mrstatus >> 6) & 0x3; + + loop--; + + if (loop < 1) { + ch++; + + if(ch > 3) { + for (delay = 0 ; delay < 0xFF000000 ; delay++) ; /* delay */ + mem_density = 7; + break; + } + loop=20; + } + } while ((mem_type != 0x0) || (mem_width != 0x0) || (mem_density < 1) || (mem_density > 3)); + + pr_info("DEVFREQ(MIF): mem_density : %d\n", mem_density); + + switch(mem_density) + { + case 1: + mem_density = LP4_6Gb_Die; + strncpy(name, "LP4_6Gb_Die", strlen("LP4_6Gb_Die") + 1); + break; + case 2: + mem_density = LP4_8Gb_Die; + strncpy(name, "LP4_8Gb_Die", strlen("LP4_8Gb_Die") + 1); + break; + case 3: + mem_density = LP4_12Gb_Die; + strncpy(name, "LP4_12Gb_Die", strlen("LP4_12Gb_Die") + 1); + break; + default: + mem_density = LP4_Invalid_Die; + strncpy(name, "LP4_Invalid_Die", strlen("LP4_Invalid_Die") + 1); + break; + } + return mem_density; +} + #define DREX0_BASE 0x10800000 #define DREX1_BASE 0x10900000 #define DREX2_BASE 0x10a00000 @@ -5320,8 +5737,11 @@ int exynos7_devfreq_mif_init_clock(void) int exynos7_devfreq_mif_init_parameter(struct devfreq_data_mif *data) { + char mem_density_name[32]; +#ifndef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET int i; - uint32_t temp; +#endif + data->base_drex[0] = devm_ioremap(data->dev, DREX0_BASE, SZ_64K); data->base_drex[1] = devm_ioremap(data->dev, DREX1_BASE, SZ_64K); data->base_drex[2] = devm_ioremap(data->dev, DREX2_BASE, SZ_64K); @@ -5344,20 +5764,26 @@ int exynos7_devfreq_mif_init_parameter(struct devfreq_data_mif *data) data->base_vt_mon_mif[2] = devm_ioremap(data->dev, EXYNOS7420_VT_MON_2, SZ_64K); data->base_vt_mon_mif[3] = devm_ioremap(data->dev, EXYNOS7420_VT_MON_3, SZ_64K); - /* it shoul be clear ctrl_dqs_osc_en, per_mrs_en in bl 2*/ - for (i = 0; i< MIF_BLK_NUM; i++) { - temp = __raw_readl(data->base_vt_mon_mif[i] + VT_MON_CON_OFFSET); - pr_info("VT_MON%d: PER_MRS_EN: 0x%08x\n", i, (uint32_t)(temp & PER_MRS_EN)); - //temp &= ~(PER_MRS_EN); - //__raw_writel(temp, data->base_vt_mon_mif[i] + VT_MON_CON_OFFSET); - } + /* MR5 (Manufacturer ID) read */ + __raw_writel(0x09001400, data->base_drex[0] + DREX_DIRECTCMD); + data->mid = (__raw_readl(data->base_drex[0] + MRSTATUS) & 0xf); + + if (data-> mid == LP4_SEC) + pr_info("DEVFREQ(MIF): LP4_SEC momory\n"); + else + pr_info("DEVFREQ(MIF): LP4_Non_SEC moemry\n"); + + data->mem_density = exynos7_devfreq_lp4_size(data, mem_density_name); + pr_info("DEVFREQ(MIF): mem_density: %s\n", mem_density_name); +#ifndef CONFIG_ARM_EXYNOS7420_BUS_DEVFREQ_THERMAL_OFFSET + /* DRAM Thermal offset 0 */ for (i = 0; i< MIF_BLK_NUM; i++) { - temp = __raw_readl(data->base_lp4_phy[i] + CAL_CON0); - pr_info("LP4_PHY%d: CTRL_DQS_OSC_EN: 0x%08x\n", i, (uint32_t)(temp & CTRL_DQS_OSC_EN)); - //temp &= ~(CTRL_DQS_OSC_EN); - //__raw_writel(temp, data->base_lp4_phy[i] + CAL_CON0); + __raw_writel((0x00001000 | (0 << 20) | 0x0 << 2), data->base_drex[i] + DREX_DIRECTCMD); + __raw_writel((0x00001000 | (1 << 20) | 0x0 << 2), data->base_drex[i] + DREX_DIRECTCMD); } +#endif + return 0; } diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index a4af788ca6cb..c0d39145d3e4 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2312,7 +2312,7 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) */ pl330->mcode_cpu = dma_alloc_coherent(pi->dev, chans * pi->mcbufsz, - &pl330->mcode_bus, GFP_KERNEL); + &pl330->mcode_bus, GFP_KERNEL | GFP_DMA); if (!pl330->mcode_cpu) { dev_err(pi->dev, "%s:%d Can't allocate memory!\n", @@ -2623,7 +2623,10 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err) spin_unlock_irqrestore(&pdmac->pool_lock, flags); - tasklet_schedule(&pch->task); + if (desc->req.infiniteloop) + pl330_tasklet((unsigned long)pch); + else + tasklet_schedule(&pch->task); } static bool pl330_dt_filter(struct dma_chan *chan, void *param) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 2fe73d2bb81e..ba75dbde8c43 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -252,17 +252,33 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) { - switch (info->micd_modes[0].bias) { - case 1: - return "MICBIAS1"; - case 2: - return "MICBIAS2"; - case 3: - return "MICBIAS3"; - case 4: - return "MICBIAS4"; + struct arizona *arizona = info->arizona; + + switch (arizona->type) { + case CS47L35: + switch (info->micd_modes[0].bias) { + case 1: + return "MICBIAS1A"; + case 2: + return "MICBIAS1B"; + case 3: + return "MICBIAS2A"; + default: + return "MICVDD"; + } default: - return "MICVDD"; + switch (info->micd_modes[0].bias) { + case 1: + return "MICBIAS1"; + case 2: + return "MICBIAS2"; + case 3: + return "MICBIAS3"; + case 4: + return "MICBIAS4"; + default: + return "MICVDD"; + } } } @@ -1267,23 +1283,23 @@ static int arizona_extcon_of_get_pdata(struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; - arizona_of_read_u32(arizona, "wlf,micd-detect-debounce", false, + arizona_of_read_s32(arizona, "wlf,micd-detect-debounce", false, &pdata->micd_detect_debounce); pdata->micd_pol_gpio = arizona_of_get_named_gpio(arizona, "wlf,micd-pol-gpio", false); - arizona_of_read_u32(arizona, "wlf,micd-bias-start-time", false, + arizona_of_read_s32(arizona, "wlf,micd-bias-start-time", false, &pdata->micd_bias_start_time); - arizona_of_read_u32(arizona, "wlf,micd-rate", false, + arizona_of_read_s32(arizona, "wlf,micd-rate", false, &pdata->micd_rate); - arizona_of_read_u32(arizona, "wlf,micd-dbtime", false, + arizona_of_read_s32(arizona, "wlf,micd-dbtime", false, &pdata->micd_dbtime); - arizona_of_read_u32(arizona, "wlf,micd-timeout", false, + arizona_of_read_s32(arizona, "wlf,micd-timeout", false, &pdata->micd_timeout); pdata->micd_force_micbias = @@ -1309,7 +1325,7 @@ static int arizona_extcon_of_get_pdata(struct arizona *arizona) arizona_of_read_u32(arizona, "wlf,gpsw", false, &pdata->gpsw); - arizona_of_read_u32(arizona, "wlf,init-mic-delay", false, + arizona_of_read_s32(arizona, "wlf,init-mic-delay", false, &pdata->init_mic_delay); arizona_of_read_u32(arizona, "wlf,micd-clamp-mode", false, @@ -1502,6 +1518,9 @@ static int arizona_extcon_probe(struct platform_device *pdev) break; } break; + case CS47L35: + arizona->pdata.micd_force_micbias = true; + /* fall through to default case to set common properties */ default: info->micd_clamp = true; info->hpdet_ip = 2; diff --git a/drivers/fingerprint/Makefile b/drivers/fingerprint/Makefile index 0149055749bf..a48d4ba399bb 100644 --- a/drivers/fingerprint/Makefile +++ b/drivers/fingerprint/Makefile @@ -4,6 +4,8 @@ # Each configuration option enables a list of files. +ccflags-y := $(KBUILD_FP_SENSOR_CFLAGS) + obj-$(CONFIG_SENSORS_FINGERPRINT_SYSFS) += fingerprint_sysfs.o obj-$(CONFIG_SENSORS_VFS7XXX) += vfs7xxx.o obj-$(CONFIG_SENSORS_ET310) += et310-spi.o et310-spi_data_transfer.o diff --git a/drivers/fingerprint/et310-spi.c b/drivers/fingerprint/et310-spi.c index 421557d3b0c9..8c376f2da195 100644 --- a/drivers/fingerprint/et310-spi.c +++ b/drivers/fingerprint/et310-spi.c @@ -157,10 +157,10 @@ static void etspi_reset(struct etspi_data *etspi) pr_info("%s\n", __func__); pr_info("%s set gpio %d value %d\n", __func__, etspi->sleepPin, 0); gpio_set_value(etspi->sleepPin, 0); - msleep(30); + usleep_range(50, 100); pr_info("%s set gpio %d value %d\n", __func__, etspi->sleepPin, 1); gpio_set_value(etspi->sleepPin, 1); - msleep(20); + usleep_range(50, 100); pr_info("%s end\n", __func__); } @@ -168,29 +168,30 @@ static void etspi_reset_set(struct etspi_data *etspi, int enable) { pr_info("%s\n", __func__); pr_info("%s enable %d\n", __func__, enable); - if (enable == 0) { + if (enable == 0) gpio_set_value(etspi->sleepPin, 0); - msleep(30); - } else { + else gpio_set_value(etspi->sleepPin, 1); - msleep(20); - } + + usleep_range(50, 100); } static void etspi_power_control(struct etspi_data *etspi, int status) { pr_info("%s status = %d\n", __func__, status); if (status == 1) { - gpio_set_value(etspi->ocp_en, status); + gpio_set_value(etspi->ocp_en, 1); usleep_range(2950, 3000); - gpio_set_value(etspi->ldo_pin, status); - gpio_set_value(etspi->ldo_pin2, status); + gpio_set_value(etspi->ldo_pin, 1); + if (etspi->ldo_pin2) + gpio_set_value(etspi->ldo_pin2, 1); msleep(20); } else if (status == 0) { - gpio_set_value(etspi->ldo_pin, status); - gpio_set_value(etspi->ldo_pin2, status); + gpio_set_value(etspi->ldo_pin, 0); + if (etspi->ldo_pin2) + gpio_set_value(etspi->ldo_pin2, 0); usleep_range(2950, 3000); - gpio_set_value(etspi->ocp_en, status); + gpio_set_value(etspi->ocp_en, 0); } pr_info("%s end\n", __func__); } @@ -213,6 +214,51 @@ static ssize_t etspi_write(struct file *filp, return 0; } +#ifdef ENABLE_SENSORS_FPRINT_SECURE +static int sec_spi_prepare(struct sec_spi_info *spi_info, struct spi_device *spi) +{ + struct s3c64xx_spi_csinfo *cs; + struct s3c64xx_spi_driver_data *sdd = NULL; + + sdd = spi_master_get_devdata(spi->master); + if (!sdd) + return -EFAULT; + + pm_runtime_get_sync(&sdd->pdev->dev); + + /* set spi clock rate */ + clk_set_rate(sdd->src_clk, spi_info->speed * 2); + + /* enable chip select */ + cs = spi->controller_data; + + if(cs->line != 0) + gpio_set_value(cs->line, 0); + + return 0; +} + +static int sec_spi_unprepare(struct sec_spi_info *spi_info, struct spi_device *spi) +{ + struct s3c64xx_spi_csinfo *cs; + struct s3c64xx_spi_driver_data *sdd = NULL; + + sdd = spi_master_get_devdata(spi->master); + if (!sdd) + return -EFAULT; + + /* disable chip select */ + cs = spi->controller_data; + if(cs->line != 0) + gpio_set_value(cs->line, 1); + + pm_runtime_put(&sdd->pdev->dev); + + return 0; +} + +#endif + static long etspi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0, retval = 0; @@ -221,6 +267,10 @@ static long etspi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) u32 tmp; struct egis_ioc_transfer *ioc = NULL; +#ifdef ENABLE_SENSORS_FPRINT_SECURE + struct sec_spi_info *spi_info = NULL; +#endif + /* Check type and command number */ if (_IOC_TYPE(cmd) != EGIS_IOC_MAGIC) { pr_err("%s _IOC_TYPE(cmd) != EGIS_IOC_MAGIC", __func__); @@ -349,15 +399,35 @@ static long etspi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (ioc->opcode == FP_SET_SPI_CLOCK) { - __u32 current_speed = spi->max_speed_hz; pr_info("%s FP_SET_SPI_CLOCK\n", __func__); pr_info("%s clock = %d\n", __func__, ioc->speed_hz); spi->max_speed_hz = ioc->speed_hz; - retval = spi_setup(spi); - if (retval < 0) { - pr_err("%s spi_setup error %d\n", __func__, retval); - spi->max_speed_hz = current_speed; + +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!etspi->enabled_clk) { + spi_info = kmalloc(sizeof(struct sec_spi_info), + GFP_KERNEL); + if (spi_info != NULL) { + pr_info("%s ENABLE_SPI_CLOCK\n", __func__); + + /* System LSI W/A Code */ + exynos7_update_media_scenario(TYPE_SPDMA, 1, 0); + + spi_info->speed = spi->max_speed_hz; + retval = sec_spi_prepare(spi_info, spi); + if (retval < 0) + pr_err("%s: Unable to enable spi clk\n", + __func__); + + kfree(spi_info); +#ifdef FEATURE_SPI_WAKELOCK + wake_lock(&etspi->fp_spi_lock); +#endif + etspi->enabled_clk = true; + } else + retval = -ENOMEM; } +#endif } if (ioc->opcode == FP_EEPROM_WREN) { @@ -430,6 +500,55 @@ static long etspi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) pr_info("%s Trigger function close\n", __func__); etspi_Interrupt_Abort(etspi); } +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (ioc->opcode == FP_DIABLE_SPI_CLOCK) { + pr_info("%s FP_DISABLE_SPI_CLOCK\n", __func__); + + if (etspi->enabled_clk) { + pr_info("%s DISABLE_SPI_CLOCK\n", __func__); + + retval = sec_spi_unprepare(spi_info, spi); + if (retval < 0) + pr_err("%s: couldn't disable spi clks\n", __func__); + +#ifdef FEATURE_SPI_WAKELOCK + wake_unlock(&etspi->fp_spi_lock); +#endif + etspi->enabled_clk = false; + + /* System LSI W/A Code */ + exynos7_update_media_scenario(TYPE_SPDMA, 0, 0); + } + } + if (ioc->opcode == FP_CPU_SPEEDUP) { + pr_info("%s FP_CPU_SPEEDUP\n", __func__); + if (ioc->len) { + u8 retry_cnt = 0; + pr_info("%s FP_CPU_SPEEDUP ON:%d, retry: %d\n", + __func__, ioc->len, retry_cnt); +#if defined(CONFIG_SECURE_OS_BOOSTER_API) + do { + retval = secos_booster_start(ioc->len - 1); + retry_cnt++; + if (retval) { + pr_err("%s: booster start failed. (%d) retry: %d\n" + , __func__, retval, retry_cnt); + if (retry_cnt < 7) + usleep_range(500, 510); + } + } while (retval && retry_cnt < 7); +#endif + } else { + pr_info("%s FP_CPU_SPEEDUP OFF\n", __func__); +#if defined(CONFIG_SECURE_OS_BOOSTER_API) + retval = secos_booster_stop(); + if (retval) + pr_err("%s: booster stop failed. (%d)\n" + , __func__, retval); +#endif + } + } +#endif out: if (ioc != NULL) kfree(ioc); @@ -535,13 +654,16 @@ int etspi_platformInit(struct etspi_data *etspi) pr_err("%s gpio_request etspi_ocp_en failed\n", __func__); } - gpio_direction_output(etspi->ocp_en, 1); + gpio_direction_output(etspi->ocp_en, 0); } - status = gpio_request(etspi->ldo_pin, "etspi_ldo_en"); - if (status < 0) { - pr_err("%s gpio_request etspi_ldo_en failed\n", - __func__); - goto etspi_platformInit_ldo_failed; + if (etspi->ldo_pin) { + status = gpio_request(etspi->ldo_pin, "etspi_ldo_en"); + if (status < 0) { + pr_err("%s gpio_request etspi_ldo_en failed\n", + __func__); + goto etspi_platformInit_ldo_failed; + } + gpio_direction_output(etspi->ldo_pin, 0); } if (etspi->ldo_pin2) { status = gpio_request(etspi->ldo_pin2, "etspi_ldo_en2"); @@ -550,6 +672,7 @@ int etspi_platformInit(struct etspi_data *etspi) __func__); goto etspi_platformInit_ldo2_failed; } + gpio_direction_output(etspi->ldo_pin2, 0); } status = gpio_request(etspi->sleepPin, "etspi_sleep"); if (status < 0) { @@ -557,20 +680,20 @@ int etspi_platformInit(struct etspi_data *etspi) __func__); goto etspi_platformInit_sleep_failed; } + + gpio_direction_output(etspi->sleepPin, 1); + if (status < 0) { + pr_err("%s gpio_direction_output SLEEP failed\n", __func__); + status = -EBUSY; + goto etspi_platformInit_sleep_failed; + } + status = gpio_request(etspi->drdyPin, "etspi_drdy"); if (status < 0) { pr_err("%s gpio_request etspi_drdy failed\n", __func__); goto etspi_platformInit_drdy_failed; } - if (etspi->ldo_pin) { - gpio_direction_output(etspi->ldo_pin, 1); - mdelay(1); - if (etspi->ldo_pin2) { - gpio_direction_output(etspi->ldo_pin2, 1); - mdelay(1); - } - } status = gpio_direction_input(etspi->drdyPin); if (status < 0) { @@ -578,10 +701,7 @@ int etspi_platformInit(struct etspi_data *etspi) __func__); goto etspi_platformInit_gpio_init_failed; } - if (etspi->sleepPin) { - gpio_direction_output(etspi->sleepPin, 1); - mdelay(1); - } + pr_info("%s sleep value =%d\n" "%s ldo en value =%d\n", __func__, gpio_get_value(etspi->sleepPin), @@ -594,8 +714,12 @@ int etspi_platformInit(struct etspi_data *etspi) status = -EFAULT; } - pr_info("%s reset sensor in platforminit\n", __func__); - etspi_reset(etspi); +#ifdef ENABLE_SENSORS_FPRINT_SECURE +#ifdef FEATURE_SPI_WAKELOCK + wake_lock_init(&etspi->fp_spi_lock, + WAKE_LOCK_SUSPEND, "etspi_wake_lock"); +#endif +#endif pr_info("%s successful status=%d\n", __func__, status); return status; @@ -604,7 +728,8 @@ int etspi_platformInit(struct etspi_data *etspi) etspi_platformInit_drdy_failed: gpio_free(etspi->sleepPin); etspi_platformInit_sleep_failed: - gpio_free(etspi->ldo_pin2); + if (etspi->ldo_pin2) + gpio_free(etspi->ldo_pin2); etspi_platformInit_ldo2_failed: gpio_free(etspi->ldo_pin); etspi_platformInit_ldo_failed: @@ -627,6 +752,11 @@ void etspi_platformUninit(struct etspi_data *etspi) gpio_free(etspi->ldo_pin2); gpio_free(etspi->sleepPin); gpio_free(etspi->drdyPin); +#ifdef ENABLE_SENSORS_FPRINT_SECURE +#ifdef FEATURE_SPI_WAKELOCK + wake_lock_destroy(&etspi->fp_spi_lock); +#endif +#endif } } @@ -716,10 +846,15 @@ static int etspi_type_check(struct etspi_data *etspi) { u8 buf1, buf2, buf3, buf4; + etspi_power_control(g_data, 1); + etspi_read_register(etspi, 0x10, &buf1); etspi_read_register(etspi, 0x11, &buf2); etspi_read_register(etspi, 0x12, &buf3); etspi_read_register(etspi, 0x13, &buf4); + + etspi_power_control(g_data, 0); + pr_info("%s buf1: %x, buf2: %x, buf3: %x, buf4: %x\n", __func__, buf1, buf2, buf3, buf4); @@ -888,6 +1023,10 @@ static int etspi_probe(struct spi_device *spi) , __func__, etspi->sensortype, retry); } while (!etspi->sensortype && ++retry < 3); +#ifdef ENABLE_SENSORS_FPRINT_SECURE + etspi->tz_mode = true; +#endif + /* If we can allocate a minor number, hook up this device. * Reusing minors is fine so long as udev or mdev is working. */ @@ -977,6 +1116,33 @@ static int etspi_remove(struct spi_device *spi) return 0; } +#undef ETSPI_PM_SUSPEND +#ifdef ETSPI_PM_SUSPEND +static int etspi_pm_suspend(struct device *dev) +{ + if (g_data != NULL) { + etspi_disable_debug_timer(); + etspi_power_control(g_data, 0); + } + pr_info("%s\n", __func__); + return 0; +} + +static int etspi_pm_resume(struct device *dev) +{ + if (g_data != NULL) { + etspi_power_control(g_data, 1); + etspi_enable_debug_timer(); + } + pr_info("%s\n", __func__); + return 0; +} + +static const struct dev_pm_ops etspi_pm_ops = { + .suspend = etspi_pm_suspend, + .resume = etspi_pm_resume +}; +#endif static struct of_device_id etspi_match_table[] = { { .compatible = "etspi,et310",}, {}, @@ -986,6 +1152,9 @@ static struct spi_driver etspi_spi_driver = { .driver = { .name = "egis_fingerprint", .owner = THIS_MODULE, +#ifdef ETSPI_PM_SUSPEND + .pm = &etspi_pm_ops, +#endif .of_match_table = etspi_match_table }, .probe = etspi_probe, diff --git a/drivers/fingerprint/et310-spi_data_transfer.c b/drivers/fingerprint/et310-spi_data_transfer.c index 27744301ee6e..3f5becc43394 100644 --- a/drivers/fingerprint/et310-spi_data_transfer.c +++ b/drivers/fingerprint/et310-spi_data_transfer.c @@ -25,6 +25,9 @@ int etspi_mass_read(struct etspi_data *etspi, u8 addr, u8 *buf, int read_len) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status; struct spi_device *spi; struct spi_message m; @@ -65,6 +68,7 @@ int etspi_mass_read(struct etspi_data *etspi, u8 addr, u8 *buf, int read_len) spi_message_init(&m); spi_message_add_tail(&t_read_data, &m); status = spi_sync(spi, &m); + kfree(write_addr); if (status == 0) @@ -75,11 +79,15 @@ int etspi_mass_read(struct etspi_data *etspi, u8 addr, u8 *buf, int read_len) kfree(read_data); return status; +#endif } /* Read io register */ int etspi_io_read_register(struct etspi_data *etspi, u8 *addr, u8 *buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; struct spi_message m; @@ -138,11 +146,15 @@ int etspi_io_read_register(struct etspi_data *etspi, u8 *addr, u8 *buf) } return status; +#endif } /* Write data to register */ int etspi_io_write_register(struct etspi_data *etspi, u8 *buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; int write_len = 2; @@ -192,10 +204,14 @@ int etspi_io_write_register(struct etspi_data *etspi, u8 *buf) } return status; +#endif } int etspi_read_register(struct etspi_data *etspi, u8 addr, u8 *buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status; struct spi_device *spi; struct spi_message m; @@ -231,10 +247,14 @@ int etspi_read_register(struct etspi_data *etspi, u8 addr, u8 *buf) , __func__, status); return status; +#endif } int etspi_io_get_one_image(struct etspi_data *etspi, u8 *buf, u8 *image_buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else uint8_t read_val, *tx_buf = (uint8_t *)buf, *work_buf = NULL, @@ -293,11 +313,15 @@ int etspi_io_get_one_image(struct etspi_data *etspi, u8 *buf, u8 *image_buf) kfree(val); kfree(work_buf); return status; +#endif } /*----------------------- EEPROM ------------------------*/ int etspi_eeprom_wren(struct etspi_data *etspi) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; struct spi_message m; @@ -322,10 +346,14 @@ int etspi_eeprom_wren(struct etspi_data *etspi) } return status; +#endif } int etspi_eeprom_wrdi(struct etspi_data *etspi) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; struct spi_message m; @@ -350,10 +378,14 @@ int etspi_eeprom_wrdi(struct etspi_data *etspi) } return status; +#endif } int etspi_eeprom_rdsr(struct etspi_data *etspi, u8 *buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status; struct spi_device *spi; struct spi_message m; @@ -389,10 +421,14 @@ int etspi_eeprom_rdsr(struct etspi_data *etspi, u8 *buf) } return status; +#endif } int etspi_eeprom_wrsr(struct etspi_data *etspi, u8 *buf) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status; struct spi_device *spi; struct spi_message m; @@ -428,10 +464,14 @@ int etspi_eeprom_wrsr(struct etspi_data *etspi, u8 *buf) } return status; +#endif } int etspi_eeprom_read(struct etspi_data *etspi, u8 *addr, u8 *buf, int read_len) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; struct spi_message m; @@ -483,6 +523,7 @@ int etspi_eeprom_read(struct etspi_data *etspi, u8 *addr, u8 *buf, int read_len) kfree(read_value); return status; +#endif } /* @@ -491,6 +532,9 @@ int etspi_eeprom_read(struct etspi_data *etspi, u8 *addr, u8 *buf, int read_len) */ int etspi_eeprom_write(struct etspi_data *etspi, u8 *buf, int write_len) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + return 0; +#else int status = 0; struct spi_device *spi; struct spi_message m; @@ -534,4 +578,5 @@ int etspi_eeprom_write(struct etspi_data *etspi, u8 *buf, int write_len) kfree(write_value); return status; +#endif } diff --git a/drivers/fingerprint/et310.h b/drivers/fingerprint/et310.h index ea30775d189e..c74fa5afb896 100644 --- a/drivers/fingerprint/et310.h +++ b/drivers/fingerprint/et310.h @@ -19,8 +19,36 @@ #ifndef _ET310_LINUX_DIRVER_H_ #define _ET310_LINUX_DIRVER_H_ +#ifdef CONFIG_SEC_FACTORY +#undef ENABLE_SENSORS_FPRINT_SECURE +#else +#undef ENABLE_SENSORS_FPRINT_SECURE +#undef FEATURE_SPI_WAKELOCK +#endif /* CONFIG_SEC_FACTORY */ + #include #include +#ifdef ENABLE_SENSORS_FPRINT_SECURE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_SECURE_OS_BOOSTER_API) +#include +#endif + +struct sec_spi_info { + int port; + unsigned long speed; +}; +#endif /*#define ET310_SPI_DEBUG*/ @@ -66,6 +94,11 @@ #define FP_SET_SPI_CLOCK 0x06 #define FP_RESET_SET 0x07 +#ifdef ENABLE_SENSORS_FPRINT_SECURE +#define FP_DIABLE_SPI_CLOCK 0x10 +#define FP_CPU_SPEEDUP 0x11 +#endif + #define FP_EEPROM_WREN 0x90 #define FP_EEPROM_WRDI 0x91 #define FP_EEPROM_RDSR 0x92 @@ -141,6 +174,12 @@ struct etspi_data { unsigned int sensortype; #ifdef CONFIG_SENSORS_FINGERPRINT_SYSFS struct device *fp_device; +#endif +#ifdef ENABLE_SENSORS_FPRINT_SECURE + bool enabled_clk; +#ifdef FEATURE_SPI_WAKELOCK + struct wake_lock fp_spi_lock; +#endif #endif bool tz_mode; int detect_period; diff --git a/drivers/fingerprint/fingerprint.h b/drivers/fingerprint/fingerprint.h index 7357a11ed12f..7b791913060e 100644 --- a/drivers/fingerprint/fingerprint.h +++ b/drivers/fingerprint/fingerprint.h @@ -26,13 +26,16 @@ /* For Sensor Type Check */ enum { - SENSOR_FAILED = 0, + SENSOR_UNKNOWN = -1, + SENSOR_FAILED, SENSOR_VIPER, SENSOR_RAPTOR, SENSOR_EGIS, }; -static char sensor_status[4][7] ={"failed", "viper", "raptor", "egis"}; +#define SENSOR_STATUS_SIZE 5 +static char sensor_status[SENSOR_STATUS_SIZE][8] ={"unknown", "failed", + "viper", "raptor", "egis"}; /* Fingerprint vendor check */ #undef ENABLE_VENDOR_CHECK @@ -41,4 +44,8 @@ static char sensor_status[4][7] ={"failed", "viper", "raptor", "egis"}; extern int FP_CHECK; /* extern variable */ #endif +#define MC_FC_FP_PM_SUSPEND ((uint32_t)(0x83000021)) +#define MC_FC_FP_PM_RESUME ((uint32_t)(0x83000022)) +#define MC_FC_FP_BTP_OCP_HIGH ((uint32_t)(0x83000023)) +#define MC_FC_FP_BTP_OCP_LOW ((uint32_t)(0x83000024)) #endif diff --git a/drivers/fingerprint/vfs7xxx.c b/drivers/fingerprint/vfs7xxx.c index b3db4f435948..b6a887934dcf 100644 --- a/drivers/fingerprint/vfs7xxx.c +++ b/drivers/fingerprint/vfs7xxx.c @@ -74,6 +74,9 @@ #include #endif #include +#ifdef ENABLE_SENSORS_FPRINT_SECURE +#include +#endif struct sec_spi_info { int port; @@ -140,7 +143,9 @@ struct vfsspi_device_data { spinlock_t irq_lock; unsigned short drdy_irq_flag; unsigned int ldocontrol; +#ifndef ENABLE_SENSORS_FPRINT_SECURE unsigned int ocp_en; +#endif unsigned int ldo_pin; /* Ldo 3.3V GPIO pin number */ unsigned int ldo_pin2; /* Ldo 1.8V GPIO pin number */ #ifdef ENABLE_VENDOR_CHECK @@ -162,7 +167,7 @@ struct vfsspi_device_data { struct wake_lock fp_spi_lock; #endif #endif - unsigned int sensortype; + int sensortype; unsigned int orient; }; @@ -170,10 +175,13 @@ struct vfsspi_device_data { int FP_CHECK = 0; /* extern variable init */ #endif -#define VENDOR "SYNATPICS" +#define VENDOR "SYNAPTICS" #define CHIP_ID "VIPER" static struct vfsspi_device_data *g_data; +#ifndef ENABLE_SENSORS_FPRINT_SECURE +static int vfsspi_type_check(struct vfsspi_device_data *vfsspi_device); +#endif #ifdef CONFIG_SENSORS_FINGERPRINT_SYSFS extern int fingerprint_register(struct device *dev, void *drvdata, @@ -440,42 +448,46 @@ static int vfsspi_rw_spi_message(struct vfsspi_device_data *vfsspi_device, #ifdef ENABLE_SENSORS_FPRINT_SECURE static int sec_spi_prepare(struct sec_spi_info *spi_info, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs; - struct s3c64xx_spi_driver_data *sdd = NULL; + struct clk *fp_spi_pclk, *fp_spi_sclk; - sdd = spi_master_get_devdata(spi->master); - if (!sdd) - return -EFAULT; + fp_spi_pclk = clk_get(NULL, "fp-spi-pclk"); - pm_runtime_get_sync(&sdd->pdev->dev); + if (IS_ERR(fp_spi_pclk)) + pr_err("Can't get fp_spi_pclk\n"); - /* set spi clock rate */ - clk_set_rate(sdd->src_clk, spi_info->speed * 2); + fp_spi_sclk = clk_get(NULL, "fp-spi-sclk"); - /* enable chip select */ - cs = spi->controller_data; + if (IS_ERR(fp_spi_sclk)) + pr_err("Can't get fp_spi_sclk\n"); - if(cs->line != 0) - gpio_set_value(cs->line, 0); + clk_prepare_enable(fp_spi_pclk); + clk_prepare_enable(fp_spi_sclk); + clk_set_rate(fp_spi_sclk, spi_info->speed * 2); + + clk_put(fp_spi_pclk); + clk_put(fp_spi_sclk); return 0; } static int sec_spi_unprepare(struct sec_spi_info *spi_info, struct spi_device *spi) { - struct s3c64xx_spi_csinfo *cs; - struct s3c64xx_spi_driver_data *sdd = NULL; + struct clk *fp_spi_pclk, *fp_spi_sclk; - sdd = spi_master_get_devdata(spi->master); - if (!sdd) - return -EFAULT; + fp_spi_pclk = clk_get(NULL, "fp-spi-pclk"); + if (IS_ERR(fp_spi_pclk)) + pr_err("Can't get fp_spi_pclk\n"); + + fp_spi_sclk = clk_get(NULL, "fp-spi-sclk"); - /* disable chip select */ - cs = spi->controller_data; - if(cs->line != 0) - gpio_set_value(cs->line, 1); + if (IS_ERR(fp_spi_sclk)) + pr_err("Can't get fp_spi_sclk\n"); - pm_runtime_put(&sdd->pdev->dev); + clk_disable_unprepare(fp_spi_pclk); + clk_disable_unprepare(fp_spi_sclk); + + clk_put(fp_spi_pclk); + clk_put(fp_spi_sclk); return 0; } @@ -713,13 +725,23 @@ static int vfsspi_set_drdy_int(struct vfsspi_device_data *vfsspi_device, void vfsspi_regulator_onoff(struct vfsspi_device_data *vfsspi_device, bool onoff) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + int ret; +#endif if (vfsspi_device->ldo_pin) { if (vfsspi_device->ldocontrol) { if (onoff) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + /* ocp_en on example*/ + ret = exynos_smc(MC_FC_FP_BTP_OCP_HIGH, 0, 0, 0); + pr_info("%s: ocp on, smc ret = %d\n", __func__, ret); + usleep_range(2950, 3000); +#else if (vfsspi_device->ocp_en) { gpio_set_value(vfsspi_device->ocp_en, 1); usleep_range(2950, 3000); } +#endif if (vfsspi_device->ldo_pin2) gpio_set_value(vfsspi_device->ldo_pin2, 1); @@ -730,13 +752,19 @@ void vfsspi_regulator_onoff(struct vfsspi_device_data *vfsspi_device, if (vfsspi_device->ldo_pin2) gpio_set_value(vfsspi_device->ldo_pin2, 0); +#ifdef ENABLE_SENSORS_FPRINT_SECURE + /* ocp_en off example*/ + ret = exynos_smc(MC_FC_FP_BTP_OCP_LOW, 0, 0, 0); + pr_info("%s: ocp off, smc ret = %d\n", __func__, ret); +#else if (vfsspi_device->ocp_en) gpio_set_value(vfsspi_device->ocp_en, 0); +#endif } vfsspi_device->ldo_onoff = onoff; - pr_info("%s: %s ocp_en: %s\n", - __func__, onoff ? "on" : "off", - vfsspi_device->ocp_en ? "enable" : "disable"); + + pr_info("%s: %s \n", + __func__, onoff ? "on" : "off"); } else pr_info("%s: can't control in this revion\n", __func__); } @@ -799,6 +827,7 @@ static long vfsspi_ioctl(struct file *filp, unsigned int cmd, struct vfsspi_device_data *vfsspi_device = NULL; #ifdef ENABLE_SENSORS_FPRINT_SECURE unsigned int onoff = 0; + unsigned int type_check = -1; #endif pr_debug("%s\n", __func__); @@ -885,6 +914,14 @@ static long vfsspi_ioctl(struct file *filp, unsigned int cmd, #endif } break; + case VFSSPI_IOCTL_SET_SENSOR_TYPE: + if (copy_from_user(&type_check, (void *)arg, + sizeof(unsigned int)) != 0) + return -EFAULT; + vfsspi_device->sensortype = (int)type_check; + pr_info("%s VFSSPI_IOCTL_SET_SENSOR_TYPE :%d \n", + __func__, vfsspi_device->sensortype); + break; #endif case VFSSPI_IOCTL_GET_SENSOR_ORIENT: pr_info("%s: orient is %d(0: normal, 1: upsidedown)\n", @@ -1012,6 +1049,7 @@ static int vfsspi_platformInit(struct vfsspi_device_data *vfsspi_device) int status = 0; pr_info("%s\n", __func__); +#ifndef ENABLE_SENSORS_FPRINT_SECURE if (vfsspi_device->ocp_en) { status = gpio_request(vfsspi_device->ocp_en, "vfsspi_ocp_en"); if (status < 0) { @@ -1022,7 +1060,7 @@ static int vfsspi_platformInit(struct vfsspi_device_data *vfsspi_device) gpio_direction_output(vfsspi_device->ocp_en, 0); pr_info("%s ocp off\n", __func__); } - +#endif if (vfsspi_device->ldo_pin) { status = gpio_request(vfsspi_device->ldo_pin, "vfsspi_ldo_en"); if (status < 0) { @@ -1100,12 +1138,15 @@ static int vfsspi_platformInit(struct vfsspi_device_data *vfsspi_device) vfsspi_platformInit_sleep_failed: gpio_free(vfsspi_device->drdy_pin); vfsspi_platformInit_drdy_failed: - gpio_free(vfsspi_device->ldo_pin2); + if (vfsspi_device->ldo_pin2) + gpio_free(vfsspi_device->ldo_pin2); vfsspi_platformInit_ldo2_failed: gpio_free(vfsspi_device->ldo_pin); vfsspi_platformInit_ldo_failed: +#ifndef ENABLE_SENSORS_FPRINT_SECURE gpio_free(vfsspi_device->ocp_en); vfsspi_platformInit_ocpen_failed: +#endif pr_info("%s : platformInit failed!\n", __func__); return status; } @@ -1127,8 +1168,10 @@ static void vfsspi_platformUninit(struct vfsspi_device_data *vfsspi_device) if (vfsspi_device->vendor_pin) gpio_free(vfsspi_device->vendor_pin); #endif +#ifndef ENABLE_SENSORS_FPRINT_SECURE if (vfsspi_device->ocp_en) gpio_free(vfsspi_device->ocp_en); +#endif #ifdef ENABLE_SENSORS_FPRINT_SECURE #ifdef FEATURE_SPI_WAKELOCK wake_lock_destroy(&vfsspi_device->fp_spi_lock); @@ -1162,7 +1205,7 @@ static int vfsspi_parse_dt(struct device *dev, pr_info("%s: drdyPin=%d\n", __func__, data->drdy_pin); } - +#ifndef ENABLE_SENSORS_FPRINT_SECURE if (!of_find_property(np, "vfsspi-ocpen", NULL)) { pr_err("%s: not set ocp_en in dts\n", __func__); } else { @@ -1174,7 +1217,7 @@ static int vfsspi_parse_dt(struct device *dev, } pr_info("%s: ocp_en=%d\n", __func__, data->ocp_en); - +#endif gpio = of_get_named_gpio(np, "vfsspi-ldoPin", 0); if (gpio < 0) { data->ldo_pin = 0; @@ -1268,7 +1311,7 @@ static ssize_t vfsspi_type_check_show(struct device *dev, { struct vfsspi_device_data *data = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", data->sensortype); + return snprintf(buf, PAGE_SIZE, "%d\n", data->sensortype); } static ssize_t vfsspi_vendor_show(struct device *dev, @@ -1310,13 +1353,13 @@ static void vfsspi_work_func_debug(struct work_struct *work) | gpio_get_value(g_data->ldo_pin); } - pr_info("%s ocpen: %d, ldo: %d," + pr_info("%s ldo: %d," " sleep: %d, irq: %d, tz: %d, type: %s\n", - __func__, gpio_get_value(g_data->ocp_en), + __func__, ldo_value, gpio_get_value(g_data->sleep_pin), gpio_get_value(g_data->drdy_pin), g_data->tz_mode, - sensor_status[g_data->sensortype]); + sensor_status[g_data->sensortype + 1]); } static void vfsspi_enable_debug_timer(void) @@ -1341,8 +1384,7 @@ static void vfsspi_timer_func(unsigned long ptr) static int vfsspi_vendor_check(struct vfsspi_device_data *vfsspi_device) { int status = 0; - - pr_info("%s\n", __func__); + pr_info("%s\n", __func__); vfsspi_regulator_onoff(vfsspi_device, true); /* power on */ @@ -1370,6 +1412,7 @@ static int vfsspi_vendor_check(struct vfsspi_device_data *vfsspi_device) return status; } #endif +#ifndef ENABLE_SENSORS_FPRINT_SECURE static int vfsspi_type_check(struct vfsspi_device_data *vfsspi_device) { struct spi_device * spi = NULL; @@ -1487,10 +1530,14 @@ static int vfsspi_type_check(struct vfsspi_device_data *vfsspi_device) return 0; } +#endif static int vfsspi_probe(struct spi_device *spi) { - int status = 0, retry = 0; + int status = 0; +#ifndef ENABLE_SENSORS_FPRINT_SECURE + int retry = 0; +#endif struct vfsspi_device_data *vfsspi_device; struct device *dev; @@ -1546,11 +1593,13 @@ static int vfsspi_probe(struct spi_device *spi) spi->max_speed_hz = SLOW_BAUD_RATE; spi->mode = SPI_MODE_0; +#ifndef ENABLE_SENSORS_FPRINT_SECURE status = spi_setup(spi); if (status) { pr_err("%s : spi_setup failed\n", __func__); goto vfsspi_probe_spi_setup_failed; } +#endif mutex_lock(&device_list_mutex); /* Create device node */ @@ -1613,12 +1662,16 @@ static int vfsspi_probe(struct spi_device *spi) } INIT_WORK(&vfsspi_device->work_debug, vfsspi_work_func_debug); +#ifdef ENABLE_SENSORS_FPRINT_SECURE + vfsspi_device->sensortype = SENSOR_UNKNOWN; +#else /* sensor hw type check */ - do { - vfsspi_type_check(vfsspi_device); - pr_info("%s, type (%u), retry (%d)\n" - , __func__, vfsspi_device->sensortype, retry); + do { + vfsspi_type_check(vfsspi_device); + pr_info("%s, type (%u), retry (%d)\n", + __func__, vfsspi_device->sensortype, retry); } while (!vfsspi_device->sensortype && ++retry < 3); +#endif disable_irq(gpio_irq); vfsspi_pin_control(vfsspi_device, false); @@ -1639,9 +1692,12 @@ static int vfsspi_probe(struct spi_device *spi) vfsspi_probe_cdev_add_failed: unregister_chrdev_region(vfsspi_device->devt, 1); vfsspi_probe_alloc_chardev_failed: +#ifndef ENABLE_SENSORS_FPRINT_SECURE vfsspi_probe_spi_setup_failed: +#endif #ifdef ENABLE_VENDOR_CHECK vfsspi_vendor_check_failed: + pinctrl_put(vfsspi_device->p); #endif vfsspi_platformUninit(vfsspi_device); #ifdef ENABLE_VENDOR_CHECK @@ -1707,10 +1763,16 @@ static void vfsspi_shutdown(struct spi_device *spi) static int vfsspi_pm_suspend(struct device *dev) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + int ret; +#endif + if (g_data != NULL) { vfsspi_disable_debug_timer(); #ifdef ENABLE_SENSORS_FPRINT_SECURE vfsspi_ioctl_power_off(g_data); + ret = exynos_smc(MC_FC_FP_PM_SUSPEND, 0, 0, 0); + pr_info("%s: suspend smc ret = %d\n", __func__, ret); #endif } pr_info("%s\n", __func__); @@ -1719,8 +1781,14 @@ static int vfsspi_pm_suspend(struct device *dev) static int vfsspi_pm_resume(struct device *dev) { +#ifdef ENABLE_SENSORS_FPRINT_SECURE + int ret; +#endif + if (g_data != NULL) { #ifdef ENABLE_SENSORS_FPRINT_SECURE + ret = exynos_smc(MC_FC_FP_PM_RESUME, 0, 0, 0); + pr_info("%s: resume smc ret = %d\n", __func__, ret); vfsspi_ioctl_power_on(g_data); #endif vfsspi_enable_debug_timer(); diff --git a/drivers/fingerprint/vfs7xxx.h b/drivers/fingerprint/vfs7xxx.h index 54e052702c4c..f19df39de944 100644 --- a/drivers/fingerprint/vfs7xxx.h +++ b/drivers/fingerprint/vfs7xxx.h @@ -35,10 +35,7 @@ #define DRDY_IRQ_ENABLE 1 #define DRDY_IRQ_DISABLE 0 -#ifdef CONFIG_SEC_FACTORY -#undef ENABLE_SENSORS_FPRINT_SECURE -#else -#define ENABLE_SENSORS_FPRINT_SECURE +#ifdef ENABLE_SENSORS_FPRINT_SECURE #define FEATURE_SPI_WAKELOCK #endif /* CONFIG_SEC_FACTORY */ @@ -129,6 +126,8 @@ /* To switch core */ #define VFSSPI_IOCTL_CPU_SPEEDUP _IOW(VFSSPI_IOCTL_MAGIC, \ 19, unsigned int) +#define VFSSPI_IOCTL_SET_SENSOR_TYPE _IOW(VFSSPI_IOCTL_MAGIC, \ + 20, unsigned int) #endif /* get sensor orienation from the SPI driver*/ #define VFSSPI_IOCTL_GET_SENSOR_ORIENT \ diff --git a/drivers/gator/Kconfig b/drivers/gator/Kconfig index e46ccb9b8064..b2358bbc1293 100644 --- a/drivers/gator/Kconfig +++ b/drivers/gator/Kconfig @@ -24,8 +24,8 @@ config GATOR_MALI_4XXMP bool "Mali-400MP or Mali-450MP" select GATOR_WITH_MALI_SUPPORT -config GATOR_MALI_T6XX - bool "Mali-T604 or Mali-T658" +config GATOR_MALI_MIDGARD + bool "Mali-T60x, Mali-T62x, Mali-T72x or Mali-T76x" select GATOR_WITH_MALI_SUPPORT endchoice diff --git a/drivers/gator/Makefile b/drivers/gator/Makefile index 3dc9d059a4b4..ab7bdcc78fae 100644 --- a/drivers/gator/Makefile +++ b/drivers/gator/Makefile @@ -1,29 +1,30 @@ ifneq ($(KERNELRELEASE),) # Uncomment the following line to enable kernel stack unwinding within gator, or update gator_backtrace.c -# EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING - +EXTRA_CFLAGS += -DGATOR_KERNEL_STACK_UNWINDING CONFIG_GATOR ?= m obj-$(CONFIG_GATOR) := gator.o +#obj-y := gator.o + gator-y := gator_main.o \ - gator_events_irq.o \ - gator_events_sched.o \ - gator_events_net.o \ gator_events_block.o \ + gator_events_irq.o \ gator_events_meminfo.o \ - gator_events_perf_pmu.o \ gator_events_mmapped.o \ + gator_events_net.o \ + gator_events_perf_pmu.o \ + gator_events_sched.o \ # Convert the old GATOR_WITH_MALI_SUPPORT to the new kernel flags ifneq ($(GATOR_WITH_MALI_SUPPORT),) CONFIG_GATOR_WITH_MALI_SUPPORT := y - ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_T6xx) + ifeq ($(GATOR_WITH_MALI_SUPPORT),MALI_MIDGARD) CONFIG_GATOR_MALI_4XXMP := n - CONFIG_GATOR_MALI_T6XX := y + CONFIG_GATOR_MALI_MIDGARD := y else CONFIG_GATOR_MALI_4XXMP := y - CONFIG_GATOR_MALI_T6XX := n + CONFIG_GATOR_MALI_MIDGARD := n endif EXTRA_CFLAGS += -DMALI_SUPPORT=$(GATOR_WITH_MALI_SUPPORT) ifneq ($(GATOR_MALI_INTERFACE_STYLE),) @@ -32,10 +33,10 @@ ifneq ($(GATOR_WITH_MALI_SUPPORT),) endif ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y) - ifeq ($(CONFIG_GATOR_MALI_T6XX),y) - gator-y += gator_events_mali_t6xx.o \ - gator_events_mali_t6xx_hw.o - include $(src)/mali_t6xx.mk + ifeq ($(CONFIG_GATOR_MALI_MIDGARD),y) + gator-y += gator_events_mali_midgard.o \ + gator_events_mali_midgard_hw.o + include $(src)/mali_midgard.mk else gator-y += gator_events_mali_4xx.o endif @@ -45,20 +46,23 @@ ifeq ($(CONFIG_GATOR_WITH_MALI_SUPPORT),y) ccflags-y += -I$(CONFIG_GATOR_MALI_PATH) endif ccflags-$(CONFIG_GATOR_MALI_4XXMP) += -DMALI_SUPPORT=MALI_4xx - ccflags-$(CONFIG_GATOR_MALI_T6XX) += -DMALI_SUPPORT=MALI_T6xx + ccflags-$(CONFIG_GATOR_MALI_MIDGARD) += -DMALI_SUPPORT=MALI_MIDGARD endif -# GATOR_TEST controls whether to include (=1) or exclude (=0) test code. +# GATOR_TEST controls whether to include (=1) or exclude (=0) test code. GATOR_TEST ?= 0 EXTRA_CFLAGS += -DGATOR_TEST=$(GATOR_TEST) +# Should the original or new block_rq_complete API be used? +OLD_BLOCK_RQ_COMPLETE := $(shell grep -A3 block_rq_complete $(srctree)/include/trace/events/block.h | grep nr_bytes -q; echo $$?) +EXTRA_CFLAGS += -DOLD_BLOCK_RQ_COMPLETE=$(OLD_BLOCK_RQ_COMPLETE) + gator-$(CONFIG_ARM) += gator_events_armv6.o \ gator_events_armv7.o \ - gator_events_ccn-504.o \ gator_events_l2c-310.o \ gator_events_scorpion.o -gator-$(CONFIG_ARM64) += gator_events_ccn-504.o +gator-$(CONFIG_ARM64) += else diff --git a/drivers/gator/gator.h b/drivers/gator/gator.h index 586cd9e742fb..5cc73a388c4f 100644 --- a/drivers/gator/gator.h +++ b/drivers/gator/gator.h @@ -14,13 +14,13 @@ #include #include -#define GATOR_PERF_SUPPORT LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) -#define GATOR_PERF_PMU_SUPPORT GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS)) +#define GATOR_PERF_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) +#define GATOR_PERF_PMU_SUPPORT (GATOR_PERF_SUPPORT && defined(CONFIG_PERF_EVENTS) && (!(defined(__arm__) || defined(__aarch64__)) || defined(CONFIG_HW_PERF_EVENTS))) #define GATOR_NO_PERF_SUPPORT (!(GATOR_PERF_SUPPORT)) -#define GATOR_CPU_FREQ_SUPPORT (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ) +#define GATOR_CPU_FREQ_SUPPORT ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)) && defined(CONFIG_CPU_FREQ)) #define GATOR_IKS_SUPPORT defined(CONFIG_BL_SWITCHER) -// cpu ids +/* cpu ids */ #define ARM1136 0xb36 #define ARM1156 0xb56 #define ARM1176 0xb76 @@ -29,7 +29,6 @@ #define CORTEX_A7 0xc07 #define CORTEX_A8 0xc08 #define CORTEX_A9 0xc09 -#define CORTEX_A12 0xc0d #define CORTEX_A15 0xc0f #define CORTEX_A17 0xc0e #define SCORPION 0x00f @@ -42,16 +41,20 @@ #define AARCH64 0xd0f #define OTHER 0xfff +/* gpu enums */ +#define MALI_4xx 1 +#define MALI_MIDGARD 2 + #define MAXSIZE_CORE_NAME 32 struct gator_cpu { const int cpuid; - // Human readable name + /* Human readable name */ const char core_name[MAXSIZE_CORE_NAME]; - // gatorfs event and Perf PMU name - const char * const pmnc_name; - // compatible from Documentation/devicetree/bindings/arm/cpus.txt - const char * const dt_name; + /* gatorfs event and Perf PMU name */ + const char *const pmnc_name; + /* compatible from Documentation/devicetree/bindings/arm/cpus.txt */ + const char *const dt_name; const int pmnc_counters; }; @@ -82,28 +85,40 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, register_trace_##probe_name(probe_##probe_name) # define GATOR_UNREGISTER_TRACE(probe_name) \ unregister_trace_##probe_name(probe_##probe_name) -#else +#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) # define GATOR_DEFINE_PROBE(probe_name, proto) \ static void probe_##probe_name(void *data, PARAMS(proto)) # define GATOR_REGISTER_TRACE(probe_name) \ register_trace_##probe_name(probe_##probe_name, NULL) # define GATOR_UNREGISTER_TRACE(probe_name) \ unregister_trace_##probe_name(probe_##probe_name, NULL) +#else +# define GATOR_DEFINE_PROBE(probe_name, proto) \ + extern struct tracepoint *gator_tracepoint_##probe_name; \ + static void probe_##probe_name(void *data, PARAMS(proto)) +# define GATOR_REGISTER_TRACE(probe_name) \ + ((gator_tracepoint_##probe_name == NULL) || tracepoint_probe_register(gator_tracepoint_##probe_name, probe_##probe_name, NULL)) +# define GATOR_UNREGISTER_TRACE(probe_name) \ + tracepoint_probe_unregister(gator_tracepoint_##probe_name, probe_##probe_name, NULL) #endif /****************************************************************************** * Events ******************************************************************************/ struct gator_interface { - void (*shutdown)(void); // Complementary function to init + /* Complementary function to init */ + void (*shutdown)(void); int (*create_files)(struct super_block *sb, struct dentry *root); int (*start)(void); - void (*stop)(void); // Complementary function to start + /* Complementary function to start */ + void (*stop)(void); int (*online)(int **buffer, bool migrate); int (*offline)(int **buffer, bool migrate); - void (*online_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' - void (*offline_dispatch)(int cpu, bool migrate); // called in process context but may not be running on core 'cpu' - int (*read)(int **buffer); + /* called in process context but may not be running on core 'cpu' */ + void (*online_dispatch)(int cpu, bool migrate); + /* called in process context but may not be running on core 'cpu' */ + void (*offline_dispatch)(int cpu, bool migrate); + int (*read)(int **buffer, bool sched_switch); int (*read64)(long long **buffer); int (*read_proc)(long long **buffer, struct task_struct *); struct list_head list; @@ -115,6 +130,8 @@ u32 gator_cpuid(void); void gator_backtrace_handler(struct pt_regs *const regs); +void gator_marshal_activity_switch(int core, int key, int activity, int pid); + #if !GATOR_IKS_SUPPORT #define get_physical_cpu() smp_processor_id() @@ -132,4 +149,4 @@ int pcpu_to_lcpu(const int pcpu); #define get_logical_cpu() smp_processor_id() #define on_primary_core() (get_logical_cpu() == 0) -#endif // GATOR_H_ +#endif /* GATOR_H_ */ diff --git a/drivers/gator/gator_annotate.c b/drivers/gator/gator_annotate.c index 7e2c6e5d8715..ff9a3cef7b2e 100644 --- a/drivers/gator/gator_annotate.c +++ b/drivers/gator/gator_annotate.c @@ -11,12 +11,12 @@ #include #include #include -#include +#include #include #include static DEFINE_SPINLOCK(annotate_lock); -static bool collect_annotations = false; +static bool collect_annotations; static int annotate_copy(struct file *file, char const __user *buf, size_t count) { @@ -24,10 +24,10 @@ static int annotate_copy(struct file *file, char const __user *buf, size_t count int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF]; if (file == NULL) { - // copy from kernel + /* copy from kernel */ memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count); } else { - // copy from user space + /* copy from user space */ if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0) return -1; } @@ -41,70 +41,70 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t int pid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff; bool interrupt_context; - if (*offset) { + if (*offset) return -EINVAL; - } interrupt_context = in_interrupt(); - // Annotations are not supported in interrupt context, but may work if you comment out the the next four lines of code. - // By doing so, annotations in interrupt context can result in deadlocks and lost data. + /* Annotations are not supported in interrupt context, but may work + * if you comment out the the next four lines of code. By doing so, + * annotations in interrupt context can result in deadlocks and lost + * data. + */ if (interrupt_context) { - printk(KERN_WARNING "gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n"); + pr_warning("gator: Annotations are not supported in interrupt context. Edit gator_annotate.c in the gator driver to enable annotations in interrupt context.\n"); return -EINVAL; } retry: - // synchronize between cores and with collect_annotations + /* synchronize between cores and with collect_annotations */ spin_lock(&annotate_lock); if (!collect_annotations) { - // Not collecting annotations, tell the caller everything was written + /* Not collecting annotations, tell the caller everything was written */ size = count_orig; goto annotate_write_out; } - // Annotation only uses a single per-cpu buffer as the data must be in order to the engine + /* Annotation only uses a single per-cpu buffer as the data must be in order to the engine */ cpu = 0; - if (current == NULL) { + if (current == NULL) pid = 0; - } else { + else pid = current->pid; - } - // determine total size of the payload + /* determine total size of the payload */ header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64; available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size; size = count < available ? count : available; if (size <= 0) { - // Buffer is full, wait until space is available + /* Buffer is full, wait until space is available */ spin_unlock(&annotate_lock); - // Drop the annotation as blocking is not allowed in interrupt context - if (interrupt_context) { + /* Drop the annotation as blocking is not allowed in interrupt context */ + if (interrupt_context) return -EINVAL; - } wait_event_interruptible(gator_annotate_wait, buffer_bytes_available(cpu, ANNOTATE_BUF) > header_size || !collect_annotations); - // Check to see if a signal is pending - if (signal_pending(current)) { + /* Check to see if a signal is pending */ + if (signal_pending(current)) return -EINTR; - } goto retry; } - // synchronize shared variables annotateBuf and annotatePos + /* synchronize shared variables annotateBuf and annotatePos */ if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) { u64 time = gator_get_time(); + gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu()); gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, time); gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size); - // determine the sizes to capture, length1 + length2 will equal size + /* determine the sizes to capture, length1 + length2 will equal size */ contiguous = contiguous_space_available(cpu, ANNOTATE_BUF); if (size < contiguous) { length1 = size; @@ -124,14 +124,14 @@ static ssize_t annotate_write(struct file *file, char const __user *buf, size_t goto annotate_write_out; } - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, ANNOTATE_BUF, time); } annotate_write_out: spin_unlock(&annotate_lock); - // return the number of bytes written + /* return the number of bytes written */ return size; } @@ -141,18 +141,21 @@ static int annotate_release(struct inode *inode, struct file *file) { int cpu = 0; - // synchronize between cores + /* synchronize between cores */ spin_lock(&annotate_lock); if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { uint32_t pid = current->pid; + gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, get_physical_cpu()); gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, pid); - gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time - gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size + /* time */ + gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); + /* size */ + gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); } - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, ANNOTATE_BUF, gator_get_time()); spin_unlock(&annotate_lock); @@ -178,7 +181,7 @@ static int gator_annotate_start(void) static void gator_annotate_stop(void) { - // the spinlock here will ensure that when this function exits, we are not in the middle of an annotation + /* the spinlock here will ensure that when this function exits, we are not in the middle of an annotation */ spin_lock(&annotate_lock); collect_annotations = false; wake_up(&gator_annotate_wait); diff --git a/drivers/gator/gator_annotate_kernel.c b/drivers/gator/gator_annotate_kernel.c index 010806825529..69471f99e5fb 100644 --- a/drivers/gator/gator_annotate_kernel.c +++ b/drivers/gator/gator_annotate_kernel.c @@ -19,10 +19,11 @@ static void kannotate_write(const char *ptr, unsigned int size) int retval; int pos = 0; loff_t offset = 0; + while (pos < size) { retval = annotate_write(NULL, &ptr[pos], size - pos, &offset); if (retval < 0) { - printk(KERN_WARNING "gator: kannotate_write failed with return value %d\n", retval); + pr_warning("gator: kannotate_write failed with return value %d\n", retval); return; } pos += retval; @@ -47,6 +48,7 @@ void gator_annotate_channel(int channel, const char *str) { const u16 str_size = strlen(str) & 0xffff; char header[8]; + header[0] = ESCAPE_CODE; header[1] = STRING_ANNOTATION; marshal_u32(header + 2, channel); @@ -54,20 +56,19 @@ void gator_annotate_channel(int channel, const char *str) kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } - EXPORT_SYMBOL(gator_annotate_channel); void gator_annotate(const char *str) { gator_annotate_channel(0, str); } - EXPORT_SYMBOL(gator_annotate); void gator_annotate_channel_color(int channel, int color, const char *str) { const u16 str_size = (strlen(str) + 4) & 0xffff; char header[12]; + header[0] = ESCAPE_CODE; header[1] = STRING_ANNOTATION; marshal_u32(header + 2, channel); @@ -76,39 +77,37 @@ void gator_annotate_channel_color(int channel, int color, const char *str) kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } - EXPORT_SYMBOL(gator_annotate_channel_color); void gator_annotate_color(int color, const char *str) { gator_annotate_channel_color(0, color, str); } - EXPORT_SYMBOL(gator_annotate_color); void gator_annotate_channel_end(int channel) { char header[8]; + header[0] = ESCAPE_CODE; header[1] = STRING_ANNOTATION; marshal_u32(header + 2, channel); marshal_u16(header + 6, 0); kannotate_write(header, sizeof(header)); } - EXPORT_SYMBOL(gator_annotate_channel_end); void gator_annotate_end(void) { gator_annotate_channel_end(0); } - EXPORT_SYMBOL(gator_annotate_end); -void gator_annotate_name_channel(int channel, int group, const char* str) +void gator_annotate_name_channel(int channel, int group, const char *str) { const u16 str_size = strlen(str) & 0xffff; char header[12]; + header[0] = ESCAPE_CODE; header[1] = NAME_CHANNEL_ANNOTATION; marshal_u32(header + 2, channel); @@ -117,13 +116,13 @@ void gator_annotate_name_channel(int channel, int group, const char* str) kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } - EXPORT_SYMBOL(gator_annotate_name_channel); -void gator_annotate_name_group(int group, const char* str) +void gator_annotate_name_group(int group, const char *str) { const u16 str_size = strlen(str) & 0xffff; char header[8]; + header[0] = ESCAPE_CODE; header[1] = NAME_GROUP_ANNOTATION; marshal_u32(header + 2, group); @@ -131,7 +130,6 @@ void gator_annotate_name_group(int group, const char* str) kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } - EXPORT_SYMBOL(gator_annotate_name_group); void gator_annotate_visual(const char *data, unsigned int length, const char *str) @@ -139,6 +137,7 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st const u16 str_size = strlen(str) & 0xffff; char header[4]; char header_length[4]; + header[0] = ESCAPE_CODE; header[1] = VISUAL_ANNOTATION; marshal_u16(header + 2, str_size); @@ -148,49 +147,49 @@ void gator_annotate_visual(const char *data, unsigned int length, const char *st kannotate_write(header_length, sizeof(header_length)); kannotate_write(data, length); } - EXPORT_SYMBOL(gator_annotate_visual); void gator_annotate_marker(void) { char header[4]; + header[0] = ESCAPE_CODE; header[1] = MARKER_ANNOTATION; marshal_u16(header + 2, 0); kannotate_write(header, sizeof(header)); } - EXPORT_SYMBOL(gator_annotate_marker); void gator_annotate_marker_str(const char *str) { const u16 str_size = strlen(str) & 0xffff; char header[4]; + header[0] = ESCAPE_CODE; header[1] = MARKER_ANNOTATION; marshal_u16(header + 2, str_size); kannotate_write(header, sizeof(header)); kannotate_write(str, str_size); } - EXPORT_SYMBOL(gator_annotate_marker_str); void gator_annotate_marker_color(int color) { char header[8]; + header[0] = ESCAPE_CODE; header[1] = MARKER_ANNOTATION; marshal_u16(header + 2, 4); marshal_u32(header + 4, color); kannotate_write(header, sizeof(header)); } - EXPORT_SYMBOL(gator_annotate_marker_color); void gator_annotate_marker_color_str(int color, const char *str) { const u16 str_size = (strlen(str) + 4) & 0xffff; char header[8]; + header[0] = ESCAPE_CODE; header[1] = MARKER_ANNOTATION; marshal_u16(header + 2, str_size); @@ -198,5 +197,4 @@ void gator_annotate_marker_color_str(int color, const char *str) kannotate_write(header, sizeof(header)); kannotate_write(str, str_size - 4); } - EXPORT_SYMBOL(gator_annotate_marker_color_str); diff --git a/drivers/gator/gator_backtrace.c b/drivers/gator/gator_backtrace.c index 9f305cf7242c..76c941d009a9 100644 --- a/drivers/gator/gator_backtrace.c +++ b/drivers/gator/gator_backtrace.c @@ -14,17 +14,17 @@ struct stack_frame_eabi { union { struct { unsigned long fp; - // May be the fp in the case of a leaf function or clang + /* May be the fp in the case of a leaf function or clang */ unsigned long lr; - // If lr is really the fp, lr2 is the corresponding lr + /* If lr is really the fp, lr2 is the corresponding lr */ unsigned long lr2; }; - // Used to read 32 bit fp/lr from a 64 bit kernel + /* Used to read 32 bit fp/lr from a 64 bit kernel */ struct { u32 fp_32; - // same as lr above + /* same as lr above */ u32 lr_32; - // same as lr2 above + /* same as lr2 above */ u32 lr2_32; }; }; @@ -35,9 +35,8 @@ static void gator_add_trace(int cpu, unsigned long address) off_t offset = 0; unsigned long cookie = get_address_cookie(cpu, current, address & ~1, &offset); - if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) { + if (cookie == NO_COOKIE || cookie == UNRESOLVED_COOKIE) offset = address; - } marshal_backtrace(offset & ~1, cookie, 0); } @@ -54,36 +53,34 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int unsigned long lr = regs->ARM_lr; const int gcc_frame_offset = sizeof(unsigned long); #else - // Is userspace aarch32 (32 bit) + /* Is userspace aarch32 (32 bit) */ const bool is_compat = compat_user_mode(regs); unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]); unsigned long sp = (is_compat ? regs->compat_sp : regs->sp); unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]); const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0); #endif - // clang frame offset is always zero + /* clang frame offset is always zero */ int is_user_mode = user_mode(regs); - // pc (current function) has already been added + /* pc (current function) has already been added */ - if (!is_user_mode) { + if (!is_user_mode) return; - } - // Add the lr (parent function) - // entry preamble may not have executed + /* Add the lr (parent function), entry preamble may not have + * executed + */ gator_add_trace(cpu, lr); - // check fp is valid - if (fp == 0 || fp < sp) { + /* check fp is valid */ + if (fp == 0 || fp < sp) return; - } - // Get the current stack frame + /* Get the current stack frame */ curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset); - if ((unsigned long)curr & 3) { + if ((unsigned long)curr & 3) return; - } while (depth-- && curr) { if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) || @@ -95,13 +92,15 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr); #define calc_next(reg) ((reg) - gcc_frame_offset) - // Returns true if reg is a valid fp + /* Returns true if reg is a valid fp */ #define validate_next(reg, curr) \ ((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg)) - // Try lr from the stack as the fp because gcc leaf functions do not push lr - // If gcc_frame_offset is non-zero, the lr will also be the clang fp - // This assumes code is at a lower address than the stack + /* Try lr from the stack as the fp because gcc leaf functions do + * not push lr. If gcc_frame_offset is non-zero, the lr will also + * be the clang fp. This assumes code is at a lower address than + * the stack + */ if (validate_next(lr, curr)) { fp = lr; lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2); @@ -109,11 +108,10 @@ static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int gator_add_trace(cpu, lr); - if (!validate_next(fp, curr)) { + if (!validate_next(fp, curr)) return; - } - // Move to the next stack frame + /* Move to the next stack frame */ curr = (struct stack_frame_eabi *)calc_next(fp); } #endif @@ -129,6 +127,7 @@ static int report_trace(struct stackframe *frame, void *d) #if defined(MODULE) unsigned int cpu = get_physical_cpu(); struct module *mod = __module_address(addr); + if (mod) { cookie = get_cookie(cpu, current, mod->name, false); addr = addr - (unsigned long)mod->module_core; @@ -142,13 +141,13 @@ static int report_trace(struct stackframe *frame, void *d) } #endif -// Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile -// #define GATOR_KERNEL_STACK_UNWINDING +/* Uncomment the following line to enable kernel stack unwinding within gator, note it can also be defined from the Makefile */ +/* #define GATOR_KERNEL_STACK_UNWINDING */ #if (defined(__arm__) || defined(__aarch64__)) && !defined(GATOR_KERNEL_STACK_UNWINDING) -// Disabled by default +/* Disabled by default */ MODULE_PARM_DESC(kernel_stack_unwinding, "Allow kernel stack unwinding."); -static bool kernel_stack_unwinding = 0; +static bool kernel_stack_unwinding; module_param(kernel_stack_unwinding, bool, 0644); #endif @@ -161,6 +160,7 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs) int depth = (kernel_stack_unwinding ? gator_backtrace_depth : 1); #endif struct stackframe frame; + if (depth == 0) depth = 1; #if defined(__arm__) @@ -178,7 +178,7 @@ static void kernel_backtrace(int cpu, struct pt_regs *const regs) marshal_backtrace(PC_REG & ~1, NO_COOKIE, 1); #endif } - + static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time) { bool in_kernel; @@ -196,10 +196,10 @@ static void gator_add_sample(int cpu, struct pt_regs *const regs, u64 time) if (in_kernel) { kernel_backtrace(cpu, regs); } else { - // Cookie+PC + /* Cookie+PC */ gator_add_trace(cpu, PC_REG); - // Backtrace + /* Backtrace */ if (gator_backtrace_depth) arm_backtrace_eabi(cpu, regs, gator_backtrace_depth); } diff --git a/drivers/gator/gator_buffer.c b/drivers/gator/gator_buffer.c index eba22dfe3bf2..910d5aa15066 100644 --- a/drivers/gator/gator_buffer.c +++ b/drivers/gator/gator_buffer.c @@ -10,55 +10,65 @@ static void marshal_frame(int cpu, int buftype) { int frame; + bool write_cpu; - if (!per_cpu(gator_buffer, cpu)[buftype]) { + if (!per_cpu(gator_buffer, cpu)[buftype]) return; - } switch (buftype) { case SUMMARY_BUF: + write_cpu = false; frame = FRAME_SUMMARY; break; case BACKTRACE_BUF: + write_cpu = true; frame = FRAME_BACKTRACE; break; case NAME_BUF: + write_cpu = true; frame = FRAME_NAME; break; case COUNTER_BUF: + write_cpu = false; frame = FRAME_COUNTER; break; case BLOCK_COUNTER_BUF: + write_cpu = true; frame = FRAME_BLOCK_COUNTER; break; case ANNOTATE_BUF: + write_cpu = false; frame = FRAME_ANNOTATE; break; case SCHED_TRACE_BUF: + write_cpu = true; frame = FRAME_SCHED_TRACE; break; - case GPU_TRACE_BUF: - frame = FRAME_GPU_TRACE; - break; case IDLE_BUF: + write_cpu = false; frame = FRAME_IDLE; break; + case ACTIVITY_BUF: + write_cpu = false; + frame = FRAME_ACTIVITY; + break; default: + write_cpu = false; frame = -1; break; } - // add response type - if (gator_response_type > 0) { + /* add response type */ + if (gator_response_type > 0) gator_buffer_write_packed_int(cpu, buftype, gator_response_type); - } - // leave space for 4-byte unpacked length + /* leave space for 4-byte unpacked length */ per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype]; - // add frame type and core number + /* add frame type and core number */ gator_buffer_write_packed_int(cpu, buftype, frame); - gator_buffer_write_packed_int(cpu, buftype, cpu); + if (write_cpu) + gator_buffer_write_packed_int(cpu, buftype, cpu); } static int buffer_bytes_available(int cpu, int buftype) @@ -66,19 +76,17 @@ static int buffer_bytes_available(int cpu, int buftype) int remaining, filled; filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype]; - if (filled < 0) { + if (filled < 0) filled += gator_buffer_size[buftype]; - } remaining = gator_buffer_size[buftype] - filled; - if (per_cpu(buffer_space_available, cpu)[buftype]) { - // Give some extra room; also allows space to insert the overflow error packet + if (per_cpu(buffer_space_available, cpu)[buftype]) + /* Give some extra room; also allows space to insert the overflow error packet */ remaining -= 200; - } else { - // Hysteresis, prevents multiple overflow messages + else + /* Hysteresis, prevents multiple overflow messages */ remaining -= 2000; - } return remaining; } @@ -87,11 +95,10 @@ static bool buffer_check_space(int cpu, int buftype, int bytes) { int remaining = buffer_bytes_available(cpu, buftype); - if (remaining < bytes) { + if (remaining < bytes) per_cpu(buffer_space_available, cpu)[buftype] = false; - } else { + else per_cpu(buffer_space_available, cpu)[buftype] = true; - } return per_cpu(buffer_space_available, cpu)[buftype]; } @@ -100,10 +107,10 @@ static int contiguous_space_available(int cpu, int buftype) { int remaining = buffer_bytes_available(cpu, buftype); int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype]; + if (remaining < contiguous) return remaining; - else - return contiguous; + return contiguous; } static void gator_commit_buffer(int cpu, int buftype, u64 time) @@ -114,41 +121,38 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time) if (!per_cpu(gator_buffer, cpu)[buftype]) return; - // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload + /* post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload */ local_irq_save(flags); type_length = gator_response_type ? 1 : 0; commit = per_cpu(gator_buffer_commit, cpu)[buftype]; length = per_cpu(gator_buffer_write, cpu)[buftype] - commit; - if (length < 0) { + if (length < 0) length += gator_buffer_size[buftype]; - } length = length - type_length - sizeof(s32); if (length <= FRAME_HEADER_SIZE) { - // Nothing to write, only the frame header is present + /* Nothing to write, only the frame header is present */ local_irq_restore(flags); return; } - for (byte = 0; byte < sizeof(s32); byte++) { + for (byte = 0; byte < sizeof(s32); byte++) per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF; - } per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype]; if (gator_live_rate > 0) { - while (time > per_cpu(gator_buffer_commit_time, cpu)) { + while (time > per_cpu(gator_buffer_commit_time, cpu)) per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate; - } } marshal_frame(cpu, buftype); local_irq_restore(flags); - // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater + /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */ if (per_cpu(in_scheduler_context, cpu)) { #ifndef CONFIG_PREEMPT_RT_FULL - // mod_timer can not be used in interrupt context in RT-Preempt full + /* mod_timer can not be used in interrupt context in RT-Preempt full */ mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); #endif } else { @@ -159,10 +163,9 @@ static void gator_commit_buffer(int cpu, int buftype, u64 time) static void buffer_check(int cpu, int buftype, u64 time) { int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype]; - if (filled < 0) { + + if (filled < 0) filled += gator_buffer_size[buftype]; - } - if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) { + if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) gator_commit_buffer(cpu, buftype, time); - } } diff --git a/drivers/gator/gator_buffer_write.c b/drivers/gator/gator_buffer_write.c index b621ba93ee5e..654ec606cfad 100644 --- a/drivers/gator/gator_buffer_write.c +++ b/drivers/gator/gator_buffer_write.c @@ -14,16 +14,17 @@ static void gator_buffer_write_packed_int(int cpu, int buftype, int x) char *buffer = per_cpu(gator_buffer, cpu)[buftype]; int packedBytes = 0; int more = true; + while (more) { - // low order 7 bits of x + /* low order 7 bits of x */ char b = x & 0x7f; + x >>= 7; - if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) { + if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) more = false; - } else { + else b |= 0x80; - } buffer[(write + packedBytes) & mask] = b; packedBytes++; @@ -39,16 +40,17 @@ static void gator_buffer_write_packed_int64(int cpu, int buftype, long long x) char *buffer = per_cpu(gator_buffer, cpu)[buftype]; int packedBytes = 0; int more = true; + while (more) { - // low order 7 bits of x + /* low order 7 bits of x */ char b = x & 0x7f; + x >>= 7; - if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) { + if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) more = false; - } else { + else b |= 0x80; - } buffer[(write + packedBytes) & mask] = b; packedBytes++; @@ -75,6 +77,7 @@ static void gator_buffer_write_bytes(int cpu, int buftype, const char *x, int le static void gator_buffer_write_string(int cpu, int buftype, const char *x) { int len = strlen(x); + gator_buffer_write_packed_int(cpu, buftype, len); gator_buffer_write_bytes(cpu, buftype, x, len); } diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c index 5c7d842070e0..c43cce815226 100644 --- a/drivers/gator/gator_cookies.c +++ b/drivers/gator/gator_cookies.c @@ -7,8 +7,10 @@ * */ -#define COOKIEMAP_ENTRIES 1024 /* must be power of 2 */ -#define TRANSLATE_BUFFER_SIZE 512 // must be a power of 2 - 512/4 = 128 entries +/* must be power of 2 */ +#define COOKIEMAP_ENTRIES 1024 +/* must be a power of 2 - 512/4 = 128 entries */ +#define TRANSLATE_BUFFER_SIZE 512 #define TRANSLATE_TEXT_SIZE 256 #define MAX_COLLISIONS 2 @@ -38,6 +40,7 @@ static uint32_t cookiemap_code(uint64_t value64) { uint32_t value = (uint32_t)((value64 >> 32) + value64); uint32_t cookiecode = (value >> 24) & 0xff; + cookiecode = cookiecode * 31 + ((value >> 16) & 0xff); cookiecode = cookiecode * 31 + ((value >> 8) & 0xff); cookiecode = cookiecode * 31 + ((value >> 0) & 0xff); @@ -52,9 +55,8 @@ static uint32_t gator_chksum_crc32(const char *data) int i, length = strlen(data); crc = 0xFFFFFFFF; - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++) crc = ((crc >> 8) & 0x00FFFFFF) ^ gator_crc32_table[(crc ^ *block++) & 0xFF]; - } return (crc ^ 0xFFFFFFFF); } @@ -72,11 +74,12 @@ static uint32_t cookiemap_exists(uint64_t key) uint64_t *keys = &(per_cpu(cookie_keys, cpu)[cookiecode]); uint32_t *values = &(per_cpu(cookie_values, cpu)[cookiecode]); - // Can be called from interrupt handler or from work queue + /* Can be called from interrupt handler or from work queue */ local_irq_save(flags); for (x = 0; x < MAX_COLLISIONS; x++) { if (keys[x] == key) { uint32_t value = values[x]; + for (; x > 0; x--) { keys[x] = keys[x - 1]; values[x] = values[x - 1]; @@ -126,7 +129,7 @@ static void translate_buffer_write_args(int cpu, struct task_struct *task, const write = per_cpu(translate_buffer_write, cpu); next_write = (write + 1) & translate_buffer_mask; - // At least one entry must always remain available as when read == write, the queue is empty not full + /* At least one entry must always remain available as when read == write, the queue is empty not full */ if (next_write != per_cpu(translate_buffer_read, cpu)) { args = &per_cpu(translate_buffer, cpu)[write]; args->task = task; @@ -178,11 +181,11 @@ static void wq_cookie_handler(struct work_struct *unused) static void app_process_wake_up_handler(unsigned long unused_data) { - // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater + /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */ schedule_work(&cookie_work); } -// Retrieve full name from proc/pid/cmdline for java processes on Android +/* Retrieve full name from proc/pid/cmdline for java processes on Android */ static int translate_app_process(const char **text, int cpu, struct task_struct *task, bool from_wq) { void *maddr; @@ -195,12 +198,16 @@ static int translate_app_process(const char **text, int cpu, struct task_struct char *buf = per_cpu(translate_text, cpu); #ifndef CONFIG_PREEMPT_RT_FULL - // Push work into a work queue if in atomic context as the kernel functions below might sleep - // Rely on the in_interrupt variable rather than in_irq() or in_interrupt() kernel functions, as the value of these functions seems - // inconsistent during a context switch between android/linux versions + /* Push work into a work queue if in atomic context as the kernel + * functions below might sleep. Rely on the in_interrupt variable + * rather than in_irq() or in_interrupt() kernel functions, as the + * value of these functions seems inconsistent during a context + * switch between android/linux versions + */ if (!from_wq) { - // Check if already in buffer + /* Check if already in buffer */ int pos = per_cpu(translate_buffer_read, cpu); + while (pos != per_cpu(translate_buffer_write, cpu)) { if (per_cpu(translate_buffer, cpu)[pos].task == task) goto out; @@ -209,7 +216,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct translate_buffer_write_args(cpu, task, *text); - // Not safe to call in RT-Preempt full in schedule switch context + /* Not safe to call in RT-Preempt full in schedule switch context */ mod_timer(&app_process_wake_up_timer, jiffies + 1); goto out; } @@ -239,7 +246,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct copy_from_user_page(page_vma, page, addr, buf, maddr + offset, bytes); - kunmap(page); // release page allocated by get_user_pages() + /* release page allocated by get_user_pages() */ + kunmap(page); page_cache_release(page); len -= bytes; @@ -250,7 +258,7 @@ static int translate_app_process(const char **text, int cpu, struct task_struct retval = 1; } - // On app_process startup, /proc/pid/cmdline is initially "zygote" then "" but changes after an initial startup period + /* On app_process startup, /proc/pid/cmdline is initially "zygote" then "" but changes after an initial startup period */ if (strcmp(*text, "zygote") == 0 || strcmp(*text, "") == 0) retval = 0; @@ -262,6 +270,8 @@ static int translate_app_process(const char **text, int cpu, struct task_struct return retval; } +static const char APP_PROCESS[] = "app_process"; + static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq) { unsigned long flags, cookie; @@ -271,16 +281,16 @@ static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, key = (key << 32) | (uint32_t)task->tgid; cookie = cookiemap_exists(key); - if (cookie) { + if (cookie) return cookie; - } - if (strcmp(text, "app_process") == 0) { + /* On 64-bit android app_process can be app_process32 or app_process64 */ + if (strncmp(text, APP_PROCESS, sizeof(APP_PROCESS) - 1) == 0) { if (!translate_app_process(&text, cpu, task, from_wq)) return UNRESOLVED_COOKIE; } - // Can be called from interrupt handler or from work queue or from scheduler trace + /* Can be called from interrupt handler or from work queue or from scheduler trace */ local_irq_save(flags); cookie = UNRESOLVED_COOKIE; @@ -300,7 +310,7 @@ static int get_exec_cookie(int cpu, struct task_struct *task) struct mm_struct *mm = task->mm; const char *text; - // kernel threads have no address space + /* kernel threads have no address space */ if (!mm) return NO_COOKIE; @@ -355,7 +365,7 @@ static int cookies_initialize(void) per_cpu(cookie_next_key, cpu) = nr_cpu_ids + cpu; size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint64_t); - per_cpu(cookie_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL); + per_cpu(cookie_keys, cpu) = kmalloc(size, GFP_KERNEL); if (!per_cpu(cookie_keys, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -363,14 +373,14 @@ static int cookies_initialize(void) memset(per_cpu(cookie_keys, cpu), 0, size); size = COOKIEMAP_ENTRIES * MAX_COLLISIONS * sizeof(uint32_t); - per_cpu(cookie_values, cpu) = (uint32_t *)kmalloc(size, GFP_KERNEL); + per_cpu(cookie_values, cpu) = kmalloc(size, GFP_KERNEL); if (!per_cpu(cookie_values, cpu)) { err = -ENOMEM; goto cookie_setup_error; } memset(per_cpu(cookie_values, cpu), 0, size); - per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL); + per_cpu(translate_buffer, cpu) = kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL); if (!per_cpu(translate_buffer, cpu)) { err = -ENOMEM; goto cookie_setup_error; @@ -379,16 +389,16 @@ static int cookies_initialize(void) per_cpu(translate_buffer_write, cpu) = 0; per_cpu(translate_buffer_read, cpu) = 0; - per_cpu(translate_text, cpu) = (char *)kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL); + per_cpu(translate_text, cpu) = kmalloc(TRANSLATE_TEXT_SIZE, GFP_KERNEL); if (!per_cpu(translate_text, cpu)) { err = -ENOMEM; goto cookie_setup_error; } } - // build CRC32 table + /* build CRC32 table */ poly = 0x04c11db7; - gator_crc32_table = (uint32_t *)kmalloc(256 * sizeof(uint32_t), GFP_KERNEL); + gator_crc32_table = kmalloc(256 * sizeof(*gator_crc32_table), GFP_KERNEL); if (!gator_crc32_table) { err = -ENOMEM; goto cookie_setup_error; @@ -396,11 +406,10 @@ static int cookies_initialize(void) for (i = 0; i < 256; i++) { crc = i; for (j = 8; j > 0; j--) { - if (crc & 1) { + if (crc & 1) crc = (crc >> 1) ^ poly; - } else { + else crc >>= 1; - } } gator_crc32_table[i] = crc; } diff --git a/drivers/gator/gator_events_armv6.c b/drivers/gator/gator_events_armv6.c index 353645622306..a157a0013302 100644 --- a/drivers/gator/gator_events_armv6.c +++ b/drivers/gator/gator_events_armv6.c @@ -8,7 +8,7 @@ #include "gator.h" -// gator_events_perf_pmu.c is used if perf is supported +/* gator_events_perf_pmu.c is used if perf is supported */ #if GATOR_NO_PERF_SUPPORT static const char *pmnc_name; @@ -28,7 +28,7 @@ static const char *pmnc_name; #define CCNT 2 #define CNTMAX (CCNT+1) -static int pmnc_counters = 0; +static int pmnc_counters; static unsigned long pmnc_enabled[CNTMAX]; static unsigned long pmnc_event[CNTMAX]; static unsigned long pmnc_key[CNTMAX]; @@ -45,6 +45,7 @@ static inline void armv6_pmnc_write(u32 val) static inline u32 armv6_pmnc_read(void) { u32 val; + asm volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (val)); return val; } @@ -52,6 +53,7 @@ static inline u32 armv6_pmnc_read(void) static void armv6_pmnc_reset_counter(unsigned int cnt) { u32 val = 0; + switch (cnt) { case CCNT: asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val)); @@ -74,20 +76,18 @@ int gator_events_armv6_create_files(struct super_block *sb, struct dentry *root) for (i = PMN0; i <= CCNT; i++) { char buf[40]; - if (i == CCNT) { - snprintf(buf, sizeof buf, "ARM_%s_ccnt", pmnc_name); - } else { - snprintf(buf, sizeof buf, "ARM_%s_cnt%d", pmnc_name, i); - } + + if (i == CCNT) + snprintf(buf, sizeof(buf), "ARM_%s_ccnt", pmnc_name); + else + snprintf(buf, sizeof(buf), "ARM_%s_cnt%d", pmnc_name, i); dir = gatorfs_mkdir(sb, root, buf); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); - if (i != CCNT) { + if (i != CCNT) gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); - } } return 0; @@ -98,9 +98,8 @@ static int gator_events_armv6_online(int **buffer, bool migrate) unsigned int cnt, len = 0, cpu = smp_processor_id(); u32 pmnc; - if (armv6_pmnc_read() & PMCR_E) { + if (armv6_pmnc_read() & PMCR_E) armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); - } /* initialize PMNC, reset overflow, D bit, C bit and P bit. */ armv6_pmnc_write(PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT | @@ -115,19 +114,18 @@ static int gator_events_armv6_online(int **buffer, bool migrate) event = pmnc_event[cnt] & 255; - // Set event (if destined for PMNx counters) - if (cnt == PMN0) { + /* Set event (if destined for PMNx counters) */ + if (cnt == PMN0) pmnc |= event << 20; - } else if (cnt == PMN1) { + else if (cnt == PMN1) pmnc |= event << 12; - } - // Reset counter + /* Reset counter */ armv6_pmnc_reset_counter(cnt); } armv6_pmnc_write(pmnc | PMCR_E); - // return zero values, no need to read as the counters were just reset + /* return zero values, no need to read as the counters were just reset */ for (cnt = PMN0; cnt <= CCNT; cnt++) { if (pmnc_enabled[cnt]) { per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; @@ -146,9 +144,8 @@ static int gator_events_armv6_offline(int **buffer, bool migrate) unsigned int cnt; armv6_pmnc_write(armv6_pmnc_read() & ~PMCR_E); - for (cnt = PMN0; cnt <= CCNT; cnt++) { + for (cnt = PMN0; cnt <= CCNT; cnt++) armv6_pmnc_reset_counter(cnt); - } return 0; } @@ -163,19 +160,19 @@ static void gator_events_armv6_stop(void) } } -static int gator_events_armv6_read(int **buffer) +static int gator_events_armv6_read(int **buffer, bool sched_switch) { int cnt, len = 0; int cpu = smp_processor_id(); - // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled - if (!(armv6_pmnc_read() & PMCR_E)) { + /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */ + if (!(armv6_pmnc_read() & PMCR_E)) return 0; - } for (cnt = PMN0; cnt <= CCNT; cnt++) { if (pmnc_enabled[cnt]) { u32 value = 0; + switch (cnt) { case CCNT: asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (value)); diff --git a/drivers/gator/gator_events_armv7.c b/drivers/gator/gator_events_armv7.c index 153119b463e6..09c94220114c 100644 --- a/drivers/gator/gator_events_armv7.c +++ b/drivers/gator/gator_events_armv7.c @@ -15,21 +15,21 @@ #include "gator.h" -// gator_events_perf_pmu.c is used if perf is supported +/* gator_events_perf_pmu.c is used if perf is supported */ #if GATOR_NO_PERF_SUPPORT -// Per-CPU PMNC: config reg +/* Per-CPU PMNC: config reg */ #define PMNC_E (1 << 0) /* Enable all counters */ #define PMNC_P (1 << 1) /* Reset all counters */ #define PMNC_C (1 << 2) /* Cycle counter reset */ #define PMNC_MASK 0x3f /* Mask for writable bits */ -// ccnt reg +/* ccnt reg */ #define CCNT_REG (1 << 31) -#define CCNT 0 +#define CCNT 0 #define CNT0 1 -#define CNTMAX (6+1) +#define CNTMAX (6+1) static const char *pmnc_name; static int pmnc_counters; @@ -49,6 +49,7 @@ inline void armv7_pmnc_write(u32 val) inline u32 armv7_pmnc_read(void) { u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); return val; } @@ -61,10 +62,10 @@ inline u32 armv7_ccnt_read(u32 reset_value) u32 val; local_irq_save(flags); - asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable - asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); // read - asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); // new value - asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */ + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); /* read */ + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (newval)); /* new value */ + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */ local_irq_restore(flags); return val; @@ -79,11 +80,11 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value) u32 oldval; local_irq_save(flags); - asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); // disable - asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); // select - asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); // read - asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); // new value - asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); // enable + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (den)); /* disable */ + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (sel)); /* select */ + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (oldval)); /* read */ + asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (newval)); /* new value */ + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (den)); /* enable */ local_irq_restore(flags); return oldval; @@ -92,13 +93,15 @@ inline u32 armv7_cntn_read(unsigned int cnt, u32 reset_value) static inline void armv7_pmnc_disable_interrupt(unsigned int cnt) { u32 val = cnt ? (1 << (cnt - CNT0)) : (1 << 31); + asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val)); } inline u32 armv7_pmnc_reset_interrupt(void) { - // Get and reset overflow status flags + /* Get and reset overflow status flags */ u32 flags; + asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (flags)); flags &= 0x8000003f; asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (flags)); @@ -108,6 +111,7 @@ inline u32 armv7_pmnc_reset_interrupt(void) static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) { u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; + asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val)); return cnt; } @@ -115,6 +119,7 @@ static inline u32 armv7_pmnc_enable_counter(unsigned int cnt) static inline u32 armv7_pmnc_disable_counter(unsigned int cnt) { u32 val = cnt ? (1 << (cnt - CNT0)) : CCNT_REG; + asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val)); return cnt; } @@ -122,15 +127,15 @@ static inline u32 armv7_pmnc_disable_counter(unsigned int cnt) static inline int armv7_pmnc_select_counter(unsigned int cnt) { u32 val = (cnt - CNT0); + asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val)); return cnt; } static inline void armv7_pmnc_write_evtsel(unsigned int cnt, u32 val) { - if (armv7_pmnc_select_counter(cnt) == cnt) { + if (armv7_pmnc_select_counter(cnt) == cnt) asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val)); - } } static int gator_events_armv7_create_files(struct super_block *sb, struct dentry *root) @@ -140,20 +145,18 @@ static int gator_events_armv7_create_files(struct super_block *sb, struct dentry for (i = 0; i < pmnc_counters; i++) { char buf[40]; - if (i == 0) { - snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name); - } else { - snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1); - } + + if (i == 0) + snprintf(buf, sizeof(buf), "%s_ccnt", pmnc_name); + else + snprintf(buf, sizeof(buf), "%s_cnt%d", pmnc_name, i - 1); dir = gatorfs_mkdir(sb, root, buf); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); - if (i > 0) { + if (i > 0) gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); - } } return 0; @@ -163,14 +166,13 @@ static int gator_events_armv7_online(int **buffer, bool migrate) { unsigned int cnt, len = 0, cpu = smp_processor_id(); - if (armv7_pmnc_read() & PMNC_E) { + if (armv7_pmnc_read() & PMNC_E) armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); - } - // Initialize & Reset PMNC: C bit and P bit + /* Initialize & Reset PMNC: C bit and P bit */ armv7_pmnc_write(PMNC_P | PMNC_C); - // Reset overflow flags + /* Reset overflow flags */ armv7_pmnc_reset_interrupt(); for (cnt = CCNT; cnt < CNTMAX; cnt++) { @@ -179,28 +181,28 @@ static int gator_events_armv7_online(int **buffer, bool migrate) if (!pmnc_enabled[cnt]) continue; - // Disable counter + /* Disable counter */ armv7_pmnc_disable_counter(cnt); event = pmnc_event[cnt] & 255; - // Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count + /* Set event (if destined for PMNx counters), we don't need to set the event if it's a cycle count */ if (cnt != CCNT) armv7_pmnc_write_evtsel(cnt, event); armv7_pmnc_disable_interrupt(cnt); - // Reset counter + /* Reset counter */ cnt ? armv7_cntn_read(cnt, 0) : armv7_ccnt_read(0); - // Enable counter + /* Enable counter */ armv7_pmnc_enable_counter(cnt); } - // enable + /* enable */ armv7_pmnc_write(armv7_pmnc_read() | PMNC_E); - // return zero values, no need to read as the counters were just reset + /* return zero values, no need to read as the counters were just reset */ for (cnt = 0; cnt < pmnc_counters; cnt++) { if (pmnc_enabled[cnt]) { per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; @@ -216,7 +218,7 @@ static int gator_events_armv7_online(int **buffer, bool migrate) static int gator_events_armv7_offline(int **buffer, bool migrate) { - // disable all counters, including PMCCNTR; overflow IRQs will not be signaled + /* disable all counters, including PMCCNTR; overflow IRQs will not be signaled */ armv7_pmnc_write(armv7_pmnc_read() & ~PMNC_E); return 0; @@ -232,24 +234,23 @@ static void gator_events_armv7_stop(void) } } -static int gator_events_armv7_read(int **buffer) +static int gator_events_armv7_read(int **buffer, bool sched_switch) { int cnt, len = 0; int cpu = smp_processor_id(); - // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled - if (!(armv7_pmnc_read() & PMNC_E)) { + /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */ + if (!(armv7_pmnc_read() & PMNC_E)) return 0; - } for (cnt = 0; cnt < pmnc_counters; cnt++) { if (pmnc_enabled[cnt]) { int value; - if (cnt == CCNT) { + + if (cnt == CCNT) value = armv7_ccnt_read(0); - } else { + else value = armv7_cntn_read(cnt, 0); - } per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; per_cpu(perfCnt, cpu)[len++] = value; } @@ -290,17 +291,16 @@ int gator_events_armv7_init(void) pmnc_name = "ARMv7_Cortex_A9"; pmnc_counters = 6; break; - // ARM Cortex A12 is not supported by version of Linux before 3.0 case CORTEX_A15: pmnc_name = "ARMv7_Cortex_A15"; pmnc_counters = 6; break; - // ARM Cortex A17 is not supported by version of Linux before 3.0 + /* ARM Cortex A17 is not supported by version of Linux before 3.0 */ default: return -1; } - pmnc_counters++; // CNT[n] + CCNT + pmnc_counters++; /* CNT[n] + CCNT */ for (cnt = CCNT; cnt < CNTMAX; cnt++) { pmnc_enabled[cnt] = 0; diff --git a/drivers/gator/gator_events_block.c b/drivers/gator/gator_events_block.c index 0a1dc1aef523..a352a54afa02 100644 --- a/drivers/gator/gator_events_block.c +++ b/drivers/gator/gator_events_block.c @@ -28,26 +28,35 @@ static ulong block_rq_rd_key; static atomic_t blockCnt[BLOCK_TOTAL]; static int blockGet[BLOCK_TOTAL * 4]; +/* Tracepoint changed in 3.15 backported to older kernels. The Makefile tries to autodetect the correct value, but if it fails change the #if below */ +#if OLD_BLOCK_RQ_COMPLETE +GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq)) +#else GATOR_DEFINE_PROBE(block_rq_complete, TP_PROTO(struct request_queue *q, struct request *rq, unsigned int nr_bytes)) +#endif { int write; + unsigned int size; if (!rq) return; write = rq->cmd_flags & EVENTWRITE; +#if OLD_BLOCK_RQ_COMPLETE + size = rq->resid_len; +#else + size = nr_bytes; +#endif - if (!nr_bytes) + if (!size) return; if (write) { - if (block_rq_wr_enabled) { - atomic_add(nr_bytes, &blockCnt[BLOCK_RQ_WR]); - } + if (block_rq_wr_enabled) + atomic_add(size, &blockCnt[BLOCK_RQ_WR]); } else { - if (block_rq_rd_enabled) { - atomic_add(nr_bytes, &blockCnt[BLOCK_RQ_RD]); - } + if (block_rq_rd_enabled) + atomic_add(size, &blockCnt[BLOCK_RQ_RD]); } } @@ -57,17 +66,15 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry /* block_complete_wr */ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_wr"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &block_rq_wr_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_wr_key); /* block_complete_rd */ dir = gatorfs_mkdir(sb, root, "Linux_block_rq_rd"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &block_rq_rd_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &block_rq_rd_key); @@ -76,7 +83,7 @@ static int gator_events_block_create_files(struct super_block *sb, struct dentry static int gator_events_block_start(void) { - // register tracepoints + /* register tracepoints */ if (block_rq_wr_enabled || block_rq_rd_enabled) if (GATOR_REGISTER_TRACE(block_rq_complete)) goto fail_block_rq_exit; @@ -84,7 +91,7 @@ static int gator_events_block_start(void) return 0; - // unregister tracepoints on error + /* unregister tracepoints on error */ fail_block_rq_exit: pr_err("gator: block event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); @@ -101,19 +108,19 @@ static void gator_events_block_stop(void) block_rq_rd_enabled = 0; } -static int gator_events_block_read(int **buffer) +static int gator_events_block_read(int **buffer, bool sched_switch) { int len, value, data = 0; - if (!on_primary_core()) { + if (!on_primary_core()) return 0; - } len = 0; if (block_rq_wr_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_WR])) > 0) { atomic_sub(value, &blockCnt[BLOCK_RQ_WR]); blockGet[len++] = block_rq_wr_key; - blockGet[len++] = 0; // indicates to Streamline that value bytes were written now, not since the last message + /* Indicates to Streamline that value bytes were written now, not since the last message */ + blockGet[len++] = 0; blockGet[len++] = block_rq_wr_key; blockGet[len++] = value; data += value; @@ -121,7 +128,8 @@ static int gator_events_block_read(int **buffer) if (block_rq_rd_enabled && (value = atomic_read(&blockCnt[BLOCK_RQ_RD])) > 0) { atomic_sub(value, &blockCnt[BLOCK_RQ_RD]); blockGet[len++] = block_rq_rd_key; - blockGet[len++] = 0; // indicates to Streamline that value bytes were read now, not since the last message + /* Indicates to Streamline that value bytes were read now, not since the last message */ + blockGet[len++] = 0; blockGet[len++] = block_rq_rd_key; blockGet[len++] = value; data += value; diff --git a/drivers/gator/gator_events_irq.c b/drivers/gator/gator_events_irq.c index facbdd62325e..5221aac581b3 100644 --- a/drivers/gator/gator_events_irq.c +++ b/drivers/gator/gator_events_irq.c @@ -42,17 +42,15 @@ static int gator_events_irq_create_files(struct super_block *sb, struct dentry * /* irq */ dir = gatorfs_mkdir(sb, root, "Linux_irq_irq"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &hardirq_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &hardirq_key); /* soft irq */ dir = gatorfs_mkdir(sb, root, "Linux_irq_softirq"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &softirq_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &softirq_key); @@ -63,7 +61,7 @@ static int gator_events_irq_online(int **buffer, bool migrate) { int len = 0, cpu = get_physical_cpu(); - // synchronization with the irq_exit functions is not necessary as the values are being reset + /* synchronization with the irq_exit functions is not necessary as the values are being reset */ if (hardirq_enabled) { atomic_set(&per_cpu(irqCnt, cpu)[HARDIRQ], 0); per_cpu(irqGet, cpu)[len++] = hardirq_key; @@ -84,7 +82,7 @@ static int gator_events_irq_online(int **buffer, bool migrate) static int gator_events_irq_start(void) { - // register tracepoints + /* register tracepoints */ if (hardirq_enabled) if (GATOR_REGISTER_TRACE(irq_handler_exit)) goto fail_hardirq_exit; @@ -95,7 +93,7 @@ static int gator_events_irq_start(void) return 0; - // unregister tracepoints on error + /* unregister tracepoints on error */ fail_softirq_exit: if (hardirq_enabled) GATOR_UNREGISTER_TRACE(irq_handler_exit); @@ -117,7 +115,7 @@ static void gator_events_irq_stop(void) softirq_enabled = 0; } -static int gator_events_irq_read(int **buffer) +static int gator_events_irq_read(int **buffer, bool sched_switch) { int len, value; int cpu = get_physical_cpu(); diff --git a/drivers/gator/gator_events_l2c-310.c b/drivers/gator/gator_events_l2c-310.c index 553f9707bdbf..73aaac32327e 100644 --- a/drivers/gator/gator_events_l2c-310.c +++ b/drivers/gator/gator_events_l2c-310.c @@ -91,7 +91,7 @@ static void gator_events_l2c310_stop(void) writel(0, l2c310_base + L2X0_EVENT_CNT_CTRL); } -static int gator_events_l2c310_read(int **buffer) +static int gator_events_l2c310_read(int **buffer, bool sched_switch) { static const unsigned long l2x0_event_cntx_val[L2C310_COUNTERS_NUM] = { L2X0_EVENT_CNT0_VAL, @@ -149,8 +149,8 @@ static void __iomem *gator_events_l2c310_probe(void) 0xa0412000, #endif #if defined(CONFIG_ARCH_VEXPRESS) - 0x1e00a000, // A9x4 core tile (HBI-0191) - 0x2c0f0000, // New memory map tiles + 0x1e00a000, /* A9x4 core tile (HBI-0191) */ + 0x2c0f0000, /* New memory map tiles */ #endif }; int i; diff --git a/drivers/gator/gator_events_mali_4xx.c b/drivers/gator/gator_events_mali_4xx.c index 85d47645a9d9..9cf43fe2c29b 100644 --- a/drivers/gator/gator_events_mali_4xx.c +++ b/drivers/gator/gator_events_mali_4xx.c @@ -18,17 +18,27 @@ #include "gator_events_mali_4xx.h" /* - * There are (currently) four different variants of the comms between gator and Mali: - * 1 (deprecated): No software counter support - * 2 (deprecated): Tracepoint called for each separate s/w counter value as it appears - * 3 (default): Single tracepoint for all s/w counters in a bundle. - * Interface style 3 is the default if no other is specified. 1 and 2 will be eliminated when - * existing Mali DDKs are upgraded. - * 4. As above, but for the Utgard (Mali-450) driver. - */ +* There have been four different variants of the comms between gator and Mali depending on driver version: +* # | DDK vsn range | Support | Notes +* +* 1 | (obsolete) | No software counter support | Obsolete patches +* 2 | (obsolete) | Tracepoint called for each separate s/w counter value as it appears | Obsolete patches +* 3 | r3p0-04rel0 - r3p2-01rel2 | Single tracepoint for all s/w counters in a bundle. | +* 4 | r3p2-01rel3 - date | As above but with extensions for MP devices (Mali-450) | At least r4p0-00rel1 +*/ #if !defined(GATOR_MALI_INTERFACE_STYLE) -#define GATOR_MALI_INTERFACE_STYLE (3) +#define GATOR_MALI_INTERFACE_STYLE (4) +#endif + +#if GATOR_MALI_INTERFACE_STYLE == 1 +#error GATOR_MALI_INTERFACE_STYLE 1 is obsolete +#elif GATOR_MALI_INTERFACE_STYLE == 2 +#error GATOR_MALI_INTERFACE_STYLE 2 is obsolete +#elif GATOR_MALI_INTERFACE_STYLE >= 3 +/* Valid GATOR_MALI_INTERFACE_STYLE */ +#else +#error Unknown GATOR_MALI_INTERFACE_STYLE option. #endif #if GATOR_MALI_INTERFACE_STYLE < 4 @@ -44,6 +54,8 @@ #error MALI_SUPPORT set to an invalid device code: expecting MALI_4xx #endif +static const char mali_name[] = "4xx"; + /* gatorfs variables for counter enable state, * the event the counter should count and the * 'key' (a unique id set by gatord and returned @@ -61,8 +73,9 @@ static u32 *counter_address[NUMBER_OF_EVENTS]; /* An array used to return the data we recorded * as key,value pairs hence the *2 */ -static unsigned long counter_dump[NUMBER_OF_EVENTS * 2]; -static unsigned long counter_prev[NUMBER_OF_EVENTS]; +static int counter_dump[NUMBER_OF_EVENTS * 2]; +static int counter_prev[NUMBER_OF_EVENTS]; +static bool prev_set[NUMBER_OF_EVENTS]; /* Note whether tracepoints have been registered */ static int trace_registered; @@ -76,18 +89,11 @@ static unsigned int n_vp_cores = MAX_NUM_VP_CORES; static unsigned int n_l2_cores = MAX_NUM_L2_CACHE_CORES; static unsigned int n_fp_cores = MAX_NUM_FP_CORES; -/** - * Calculate the difference and handle the overflow. - */ -static u32 get_difference(u32 start, u32 end) -{ - if (start - end >= 0) { - return start - end; - } - - // Mali counters are unsigned 32 bit values that wrap. - return (4294967295u - end) + start; -} +extern struct mali_counter mali_activity[2]; +static const char *const mali_activity_names[] = { + "fragment", + "vertex", +}; /** * Returns non-zero if the given counter ID is an activity counter. @@ -106,94 +112,23 @@ static inline int is_hw_counter(unsigned int event_id) return (event_id >= FIRST_HW_COUNTER && event_id <= LAST_HW_COUNTER); } -/* - * These are provided for utgard compatibility. - */ -typedef void _mali_profiling_get_mali_version_type(struct _mali_profiling_mali_version *values); -typedef u32 _mali_profiling_get_l2_counters_type(_mali_profiling_l2_counter_values *values); - -#if GATOR_MALI_INTERFACE_STYLE == 2 -/** - * Returns non-zero if the given counter ID is a software counter. - */ -static inline int is_sw_counter(unsigned int event_id) -{ - return (event_id >= FIRST_SW_COUNTER && event_id <= LAST_SW_COUNTER); -} -#endif - -#if GATOR_MALI_INTERFACE_STYLE == 2 -/* - * The Mali DDK uses s64 types to contain software counter values, but gator - * can only use a maximum of 32 bits. This function scales a software counter - * to an appropriate range. - */ -static u32 scale_sw_counter_value(unsigned int event_id, signed long long value) -{ - u32 scaled_value; - - switch (event_id) { - case COUNTER_GLES_UPLOAD_TEXTURE_TIME: - case COUNTER_GLES_UPLOAD_VBO_TIME: - scaled_value = (u32)div_s64(value, 1000000); - break; - default: - scaled_value = (u32)value; - break; - } - - return scaled_value; -} -#endif - -/* Probe for continuously sampled counter */ -#if 0 //WE_DONT_CURRENTLY_USE_THIS_SO_SUPPRESS_WARNING -GATOR_DEFINE_PROBE(mali_sample_address, TP_PROTO(unsigned int event_id, u32 *addr)) -{ - /* Turning on too many pr_debug statements in frequently called functions - * can cause stability and/or performance problems - */ - //pr_debug("gator: mali_sample_address %d %d\n", event_id, addr); - if (event_id >= ACTIVITY_VP && event_id <= COUNTER_FP3_C1) { - counter_address[event_id] = addr; - } -} -#endif - /* Probe for hardware counter events */ GATOR_DEFINE_PROBE(mali_hw_counter, TP_PROTO(unsigned int event_id, unsigned int value)) { - /* Turning on too many pr_debug statements in frequently called functions - * can cause stability and/or performance problems - */ - //pr_debug("gator: mali_hw_counter %d %d\n", event_id, value); - if (is_hw_counter(event_id)) { + if (is_hw_counter(event_id)) counter_data[event_id] = value; - } } -#if GATOR_MALI_INTERFACE_STYLE == 2 -GATOR_DEFINE_PROBE(mali_sw_counter, TP_PROTO(unsigned int event_id, signed long long value)) -{ - if (is_sw_counter(event_id)) { - counter_data[event_id] = scale_sw_counter_value(event_id, value); - } -} -#endif /* GATOR_MALI_INTERFACE_STYLE == 2 */ - -#if GATOR_MALI_INTERFACE_STYLE >= 3 GATOR_DEFINE_PROBE(mali_sw_counters, TP_PROTO(pid_t pid, pid_t tid, void *surface_id, unsigned int *counters)) { u32 i; /* Copy over the values for those counters which are enabled. */ for (i = FIRST_SW_COUNTER; i <= LAST_SW_COUNTER; i++) { - if (counter_enabled[i]) { + if (counter_enabled[i]) counter_data[i] = (u32)(counters[i - FIRST_SW_COUNTER]); - } } } -#endif /* GATOR_MALI_INTERFACE_STYLE >= 3 */ /** * Create a single filesystem entry for a specified event. @@ -211,13 +146,11 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch dir = gatorfs_mkdir(sb, root, name); - if (!dir) { + if (!dir) return -1; - } - if (create_event_item) { + if (create_event_item) gatorfs_create_ulong(sb, dir, "event", &counter_event[event]); - } gatorfs_create_ulong(sb, dir, "enabled", &counter_enabled[event]); gatorfs_create_ro_ulong(sb, dir, "key", &counter_key[event]); @@ -231,7 +164,7 @@ static int create_fs_entry(struct super_block *sb, struct dentry *root, const ch */ static void initialise_version_info(void) { - _mali_profiling_get_mali_version_type *mali_profiling_get_mali_version_symbol; + void (*mali_profiling_get_mali_version_symbol)(struct _mali_profiling_mali_version *values); mali_profiling_get_mali_version_symbol = symbol_get(_mali_profiling_get_mali_version); @@ -253,7 +186,8 @@ static void initialise_version_info(void) /* Release the function - we're done with it. */ symbol_put(_mali_profiling_get_mali_version); } else { - printk("gator: mali online _mali_profiling_get_mali_version symbol not found\n"); + pr_err("gator: mali online _mali_profiling_get_mali_version symbol not found\n"); + pr_err("gator: check your Mali DDK version versus the GATOR_MALI_INTERFACE_STYLE setting\n"); } } #endif @@ -261,7 +195,6 @@ static void initialise_version_info(void) static int create_files(struct super_block *sb, struct dentry *root) { int event; - const char *mali_name = gator_mali_get_mali_name(); char buf[40]; int core_id; @@ -278,21 +211,27 @@ static int create_files(struct super_block *sb, struct dentry *root) initialise_version_info(); #endif + mali_activity[0].cores = n_fp_cores; + mali_activity[1].cores = n_vp_cores; + for (event = 0; event < ARRAY_SIZE(mali_activity); event++) { + if (gator_mali_create_file_system(mali_name, mali_activity_names[event], sb, root, &mali_activity[event], NULL) != 0) + return -1; + } + /* Vertex processor counters */ for (core_id = 0; core_id < n_vp_cores; core_id++) { int activity_counter_id = ACTIVITY_VP_0; - snprintf(buf, sizeof buf, "ARM_%s_VP_%d_active", mali_name, core_id); - if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) { + + snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_active", mali_name, core_id); + if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) return -1; - } for (counter_number = 0; counter_number < 2; counter_number++) { int counter_id = COUNTER_VP_0_C0 + (2 * core_id) + counter_number; - snprintf(buf, sizeof buf, "ARM_%s_VP_%d_cnt%d", mali_name, core_id, counter_number); - if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_VP_%d_cnt%d", mali_name, core_id, counter_number); + if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) return -1; - } } } @@ -300,18 +239,16 @@ static int create_files(struct super_block *sb, struct dentry *root) for (core_id = 0; core_id < n_fp_cores; core_id++) { int activity_counter_id = ACTIVITY_FP_0 + core_id; - snprintf(buf, sizeof buf, "ARM_%s_FP_%d_active", mali_name, core_id); - if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_active", mali_name, core_id); + if (create_fs_entry(sb, root, buf, activity_counter_id, 0) != 0) return -1; - } for (counter_number = 0; counter_number < 2; counter_number++) { int counter_id = COUNTER_FP_0_C0 + (2 * core_id) + counter_number; - snprintf(buf, sizeof buf, "ARM_%s_FP_%d_cnt%d", mali_name, core_id, counter_number); - if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_FP_%d_cnt%d", mali_name, core_id, counter_number); + if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) return -1; - } } } @@ -320,38 +257,33 @@ static int create_files(struct super_block *sb, struct dentry *root) for (counter_number = 0; counter_number < 2; counter_number++) { int counter_id = COUNTER_L2_0_C0 + (2 * core_id) + counter_number; - snprintf(buf, sizeof buf, "ARM_%s_L2_%d_cnt%d", mali_name, core_id, counter_number); - if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_L2_%d_cnt%d", mali_name, core_id, counter_number); + if (create_fs_entry(sb, root, buf, counter_id, 1) != 0) return -1; - } } } /* Now set up the software counter entries */ for (event = FIRST_SW_COUNTER; event <= LAST_SW_COUNTER; event++) { - snprintf(buf, sizeof(buf), "ARM_%s_SW_%d", mali_name, event - FIRST_SW_COUNTER); + snprintf(buf, sizeof(buf), "ARM_Mali-%s_SW_%d", mali_name, event - FIRST_SW_COUNTER); - if (create_fs_entry(sb, root, buf, event, 0) != 0) { + if (create_fs_entry(sb, root, buf, event, 0) != 0) return -1; - } } /* Now set up the special counter entries */ - snprintf(buf, sizeof(buf), "ARM_%s_Filmstrip_cnt0", mali_name); - if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_Filmstrip_cnt0", mali_name); + if (create_fs_entry(sb, root, buf, COUNTER_FILMSTRIP, 1) != 0) return -1; - } #ifdef DVFS_REPORTED_BY_DDK - snprintf(buf, sizeof(buf), "ARM_%s_Frequency", mali_name); - if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_Frequency", mali_name); + if (create_fs_entry(sb, root, buf, COUNTER_FREQUENCY, 1) != 0) return -1; - } - snprintf(buf, sizeof(buf), "ARM_%s_Voltage", mali_name); - if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) { + snprintf(buf, sizeof(buf), "ARM_Mali-%s_Voltage", mali_name); + if (create_fs_entry(sb, root, buf, COUNTER_VOLTAGE, 1) != 0) return -1; - } #endif return 0; @@ -361,8 +293,8 @@ static int create_files(struct super_block *sb, struct dentry *root) * Local store for the get_counters entry point into the DDK. * This is stored here since it is used very regularly. */ -static mali_profiling_get_counters_type *mali_get_counters = NULL; -static _mali_profiling_get_l2_counters_type *mali_get_l2_counters = NULL; +static void (*mali_get_counters)(unsigned int *, unsigned int *, unsigned int *, unsigned int *); +static u32 (*mali_get_l2_counters)(struct _mali_profiling_l2_counter_values *values); /* * Examine list of counters between two index limits and determine if any one is enabled. @@ -373,9 +305,8 @@ static int is_any_counter_enabled(unsigned int first_counter, unsigned int last_ unsigned int i; for (i = first_counter; i <= last_counter; i++) { - if (counter_enabled[i]) { + if (counter_enabled[i]) return 1; /* At least one counter is enabled */ - } } return 0; /* No s/w counters enabled */ @@ -397,23 +328,21 @@ static void init_counters(unsigned int from_counter, unsigned int to_counter) pr_debug("gator: mali online _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event); for (counter_id = from_counter; counter_id <= to_counter; counter_id++) { - if (counter_enabled[counter_id]) { + if (counter_enabled[counter_id]) mali_set_hw_event(counter_id, counter_event[counter_id]); - } else { + else mali_set_hw_event(counter_id, 0xFFFFFFFF); - } } symbol_put(_mali_profiling_set_event); } else { - printk("gator: mali online _mali_profiling_set_event symbol not found\n"); + pr_err("gator: mali online _mali_profiling_set_event symbol not found\n"); } } static void mali_counter_initialize(void) { int i; - int core_id; mali_profiling_control_type *mali_control; @@ -439,39 +368,30 @@ static void mali_counter_initialize(void) symbol_put(_mali_profiling_control); } else { - printk("gator: mali online _mali_profiling_control symbol not found\n"); + pr_err("gator: mali online _mali_profiling_control symbol not found\n"); } mali_get_counters = symbol_get(_mali_profiling_get_counters); - if (mali_get_counters) { + if (mali_get_counters) pr_debug("gator: mali online _mali_profiling_get_counters symbol @ %p\n", mali_get_counters); - - } else { - pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined"); - } + else + pr_debug("gator WARNING: mali _mali_profiling_get_counters symbol not defined\n"); mali_get_l2_counters = symbol_get(_mali_profiling_get_l2_counters); - if (mali_get_l2_counters) { + if (mali_get_l2_counters) pr_debug("gator: mali online _mali_profiling_get_l2_counters symbol @ %p\n", mali_get_l2_counters); - - } else { - pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined"); - } + else + pr_debug("gator WARNING: mali _mali_profiling_get_l2_counters symbol not defined\n"); if (!mali_get_counters && !mali_get_l2_counters) { - pr_debug("gator: WARNING: no L2 counters available"); + pr_debug("gator: WARNING: no L2 counters available\n"); n_l2_cores = 0; } - for (core_id = 0; core_id < n_l2_cores; core_id++) { - int counter_id = COUNTER_L2_0_C0 + (2 * core_id); - counter_prev[counter_id] = 0; - counter_prev[counter_id + 1] = 0; - } - /* Clear counters in the start */ for (i = 0; i < NUMBER_OF_EVENTS; i++) { counter_data[i] = 0; + prev_set[i] = false; } } @@ -486,13 +406,12 @@ static void mali_counter_deinitialize(void) int i; pr_debug("gator: mali offline _mali_profiling_set_event symbol @ %p\n", mali_set_hw_event); - for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) { + for (i = FIRST_HW_COUNTER; i <= LAST_HW_COUNTER; i++) mali_set_hw_event(i, 0xFFFFFFFF); - } symbol_put(_mali_profiling_set_event); } else { - printk("gator: mali offline _mali_profiling_set_event symbol not found\n"); + pr_err("gator: mali offline _mali_profiling_set_event symbol not found\n"); } /* Generic control interface for Mali DDK. */ @@ -508,43 +427,29 @@ static void mali_counter_deinitialize(void) symbol_put(_mali_profiling_control); } else { - printk("gator: mali offline _mali_profiling_control symbol not found\n"); + pr_err("gator: mali offline _mali_profiling_control symbol not found\n"); } - if (mali_get_counters) { + if (mali_get_counters) symbol_put(_mali_profiling_get_counters); - } - if (mali_get_l2_counters) { + if (mali_get_l2_counters) symbol_put(_mali_profiling_get_l2_counters); - } } static int start(void) { - // register tracepoints + /* register tracepoints */ if (GATOR_REGISTER_TRACE(mali_hw_counter)) { - printk("gator: mali_hw_counter tracepoint failed to activate\n"); + pr_err("gator: mali_hw_counter tracepoint failed to activate\n"); return -1; } -#if GATOR_MALI_INTERFACE_STYLE == 1 - /* None. */ -#elif GATOR_MALI_INTERFACE_STYLE == 2 - /* For patched Mali driver. */ - if (GATOR_REGISTER_TRACE(mali_sw_counter)) { - printk("gator: mali_sw_counter tracepoint failed to activate\n"); - return -1; - } -#elif GATOR_MALI_INTERFACE_STYLE >= 3 /* For Mali drivers with built-in support. */ if (GATOR_REGISTER_TRACE(mali_sw_counters)) { - printk("gator: mali_sw_counters tracepoint failed to activate\n"); + pr_err("gator: mali_sw_counters tracepoint failed to activate\n"); return -1; } -#else -#error Unknown GATOR_MALI_INTERFACE_STYLE option. -#endif trace_registered = 1; @@ -561,17 +466,8 @@ static void stop(void) if (trace_registered) { GATOR_UNREGISTER_TRACE(mali_hw_counter); -#if GATOR_MALI_INTERFACE_STYLE == 1 - /* None. */ -#elif GATOR_MALI_INTERFACE_STYLE == 2 - /* For patched Mali driver. */ - GATOR_UNREGISTER_TRACE(mali_sw_counter); -#elif GATOR_MALI_INTERFACE_STYLE >= 3 /* For Mali drivers with built-in support. */ GATOR_UNREGISTER_TRACE(mali_sw_counters); -#else -#error Unknown GATOR_MALI_INTERFACE_STYLE option. -#endif pr_debug("gator: mali timeline tracepoint deactivated\n"); @@ -601,17 +497,17 @@ static void dump_counters(unsigned int from_counter, unsigned int to_counter, un } } -static int read(int **buffer) +static int read(int **buffer, bool sched_switch) { int len = 0; if (!on_primary_core()) return 0; - // Read the L2 C0 and C1 here. + /* Read the L2 C0 and C1 here. */ if (n_l2_cores > 0 && is_any_counter_enabled(COUNTER_L2_0_C0, COUNTER_L2_0_C0 + (2 * n_l2_cores))) { unsigned int unavailable_l2_caches = 0; - _mali_profiling_l2_counter_values cache_values; + struct _mali_profiling_l2_counter_values cache_values; unsigned int cache_id; struct _mali_profiling_core_counters *per_core; @@ -630,27 +526,28 @@ static int read(int **buffer) unsigned int counter_id_0 = COUNTER_L2_0_C0 + (2 * cache_id); unsigned int counter_id_1 = counter_id_0 + 1; - if ((1 << cache_id) & unavailable_l2_caches) { + if ((1 << cache_id) & unavailable_l2_caches) continue; /* This cache is unavailable (powered-off, possibly). */ - } per_core = &cache_values.cores[cache_id]; - if (counter_enabled[counter_id_0]) { - // Calculate and save src0's counter val0 + if (counter_enabled[counter_id_0] && prev_set[counter_id_0]) { + /* Calculate and save src0's counter val0 */ counter_dump[len++] = counter_key[counter_id_0]; - counter_dump[len++] = get_difference(per_core->value0, counter_prev[counter_id_0]); + counter_dump[len++] = per_core->value0 - counter_prev[counter_id_0]; } - if (counter_enabled[counter_id_1]) { - // Calculate and save src1's counter val1 + if (counter_enabled[counter_id_1] && prev_set[counter_id_1]) { + /* Calculate and save src1's counter val1 */ counter_dump[len++] = counter_key[counter_id_1]; - counter_dump[len++] = get_difference(per_core->value1, counter_prev[counter_id_1]); + counter_dump[len++] = per_core->value1 - counter_prev[counter_id_1]; } - // Save the previous values for the counters. + /* Save the previous values for the counters. */ counter_prev[counter_id_0] = per_core->value0; + prev_set[counter_id_0] = true; counter_prev[counter_id_1] = per_core->value1; + prev_set[counter_id_1] = true; } } @@ -664,8 +561,9 @@ static int read(int **buffer) { int cnt; /* - * Add in the voltage and frequency counters if enabled. Note that, since these are - * actually passed as events, the counter value should not be cleared. + * Add in the voltage and frequency counters if enabled. Note + * that, since these are actually passed as events, the counter + * value should not be cleared. */ cnt = COUNTER_FREQUENCY; if (counter_enabled[cnt]) { @@ -681,9 +579,8 @@ static int read(int **buffer) } #endif - if (buffer) { - *buffer = (int *)counter_dump; - } + if (buffer) + *buffer = counter_dump; return len; } @@ -709,6 +606,8 @@ int gator_events_mali_init(void) pr_debug("gator: mali init\n"); + gator_mali_initialise_counters(mali_activity, ARRAY_SIZE(mali_activity)); + for (cnt = 0; cnt < NUMBER_OF_EVENTS; cnt++) { counter_enabled[cnt] = 0; counter_event[cnt] = 0; diff --git a/drivers/gator/gator_events_mali_common.c b/drivers/gator/gator_events_mali_common.c index dc58dcf0c662..1af87d649afe 100644 --- a/drivers/gator/gator_events_mali_common.c +++ b/drivers/gator/gator_events_mali_common.c @@ -8,27 +8,7 @@ */ #include "gator_events_mali_common.h" -static u32 gator_mali_get_id(void) -{ - return MALI_SUPPORT; -} - -extern const char *gator_mali_get_mali_name(void) -{ - u32 id = gator_mali_get_id(); - - switch (id) { - case MALI_T6xx: - return "Mali-T6xx"; - case MALI_4xx: - return "Mali-4xx"; - default: - pr_debug("gator: Mali-T6xx: unknown Mali ID (%d)\n", id); - return "Mali-Unknown"; - } -} - -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event) +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event) { int err; char buf[255]; @@ -37,29 +17,39 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even /* If the counter name is empty ignore it */ if (strlen(event_name) != 0) { /* Set up the filesystem entry for this event. */ - snprintf(buf, sizeof(buf), "ARM_%s_%s", mali_name, event_name); + if (mali_name == NULL) + snprintf(buf, sizeof(buf), "ARM_Mali-%s", event_name); + else + snprintf(buf, sizeof(buf), "ARM_Mali-%s_%s", mali_name, event_name); dir = gatorfs_mkdir(sb, root, buf); if (dir == NULL) { - pr_debug("gator: Mali-T6xx: error creating file system for: %s (%s)", event_name, buf); + pr_debug("gator: %s: error creating file system for: %s (%s)\n", mali_name, event_name, buf); return -1; } err = gatorfs_create_ulong(sb, dir, "enabled", &counter->enabled); if (err != 0) { - pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ulong for: %s (%s)", event_name, buf); + pr_debug("gator: %s: error calling gatorfs_create_ulong for: %s (%s)\n", mali_name, event_name, buf); return -1; } err = gatorfs_create_ro_ulong(sb, dir, "key", &counter->key); if (err != 0) { - pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); + pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf); return -1; } + if (counter->cores != -1) { + err = gatorfs_create_ro_ulong(sb, dir, "cores", &counter->cores); + if (err != 0) { + pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf); + return -1; + } + } if (event != NULL) { err = gatorfs_create_ulong(sb, dir, "event", event); if (err != 0) { - pr_debug("gator: Mali-T6xx: error calling gatorfs_create_ro_ulong for: %s (%s)", event_name, buf); + pr_debug("gator: %s: error calling gatorfs_create_ro_ulong for: %s (%s)\n", mali_name, event_name, buf); return -1; } } @@ -68,14 +58,15 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even return 0; } -extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters) +extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters) { unsigned int cnt; for (cnt = 0; cnt < n_counters; cnt++) { - mali_counter *counter = &counters[cnt]; + struct mali_counter *counter = &counters[cnt]; counter->key = gator_events_get_key(); counter->enabled = 0; + counter->cores = -1; } } diff --git a/drivers/gator/gator_events_mali_common.h b/drivers/gator/gator_events_mali_common.h index 41c2a3c13fae..e7082e62fe88 100644 --- a/drivers/gator/gator_events_mali_common.h +++ b/drivers/gator/gator_events_mali_common.h @@ -16,11 +16,7 @@ #include #include #include -#include - -/* Device codes for each known GPU */ -#define MALI_4xx (0x0b07) -#define MALI_T6xx (0x0056) +#include /* Ensure that MALI_SUPPORT has been defined to something. */ #ifndef MALI_SUPPORT @@ -34,17 +30,20 @@ /* * Runtime state information for a counter. */ -typedef struct { - unsigned long key; /* 'key' (a unique id set by gatord and returned by gator.ko) */ - unsigned long enabled; /* counter enable state */ -} mali_counter; +struct mali_counter { + /* 'key' (a unique id set by gatord and returned by gator.ko) */ + unsigned long key; + /* counter enable state */ + unsigned long enabled; + /* for activity counters, the number of cores, otherwise -1 */ + unsigned long cores; +}; /* * Mali-4xx */ typedef int mali_profiling_set_event_type(unsigned int, int); typedef void mali_profiling_control_type(unsigned int, unsigned int); -typedef void mali_profiling_get_counters_type(unsigned int *, unsigned int *, unsigned int *, unsigned int *); /* * Driver entry points for functions called directly by gator. @@ -53,18 +52,10 @@ extern int _mali_profiling_set_event(unsigned int, int); extern void _mali_profiling_control(unsigned int, unsigned int); extern void _mali_profiling_get_counters(unsigned int *, unsigned int *, unsigned int *, unsigned int *); -/** - * Returns a name which identifies the GPU type (eg Mali-4xx, Mali-T6xx). - * - * @return The name as a constant string. - */ -extern const char *gator_mali_get_mali_name(void); - /** * Creates a filesystem entry under /dev/gator relating to the specified event name and key, and * associate the key/enable values with this entry point. * - * @param mali_name A name related to the type of GPU, obtained from a call to gator_mali_get_mali_name() * @param event_name The name of the event. * @param sb Linux super block * @param root Directory under which the entry will be created. @@ -73,7 +64,7 @@ extern const char *gator_mali_get_mali_name(void); * * @return 0 if entry point was created, non-zero if not. */ -extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, mali_counter *counter, unsigned long *event); +extern int gator_mali_create_file_system(const char *mali_name, const char *event_name, struct super_block *sb, struct dentry *root, struct mali_counter *counter, unsigned long *event); /** * Initializes the counter array. @@ -81,6 +72,6 @@ extern int gator_mali_create_file_system(const char *mali_name, const char *even * @param keys The array of counters * @param n_counters The number of entries in each of the arrays. */ -extern void gator_mali_initialise_counters(mali_counter counters[], unsigned int n_counters); +extern void gator_mali_initialise_counters(struct mali_counter counters[], unsigned int n_counters); #endif /* GATOR_EVENTS_MALI_COMMON_H */ diff --git a/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c index c633dfdce306..c625ac5af9cd 100644 --- a/drivers/gator/gator_events_meminfo.c +++ b/drivers/gator/gator_events_meminfo.c @@ -16,6 +16,8 @@ #include #include +#define USE_THREAD defined(CONFIG_PREEMPT_RT_FULL) + enum { MEMINFO_MEMFREE, MEMINFO_MEMUSED, @@ -48,7 +50,7 @@ static bool meminfo_global_enabled; static ulong meminfo_enabled[MEMINFO_TOTAL]; static ulong meminfo_keys[MEMINFO_TOTAL]; static long long meminfo_buffer[2 * (MEMINFO_TOTAL + 2)]; -static int meminfo_length = 0; +static int meminfo_length; static bool new_data_avail; static bool proc_global_enabled; @@ -56,22 +58,44 @@ static ulong proc_enabled[PROC_COUNT]; static ulong proc_keys[PROC_COUNT]; static DEFINE_PER_CPU(long long, proc_buffer[2 * (PROC_COUNT + 3)]); +#if USE_THREAD + static int gator_meminfo_func(void *data); static bool gator_meminfo_run; -// Initialize semaphore unlocked to initialize memory values +/* Initialize semaphore unlocked to initialize memory values */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) static DECLARE_MUTEX(gator_meminfo_sem); #else static DEFINE_SEMAPHORE(gator_meminfo_sem); #endif +static void notify(void) +{ + up(&gator_meminfo_sem); +} + +#else + +static unsigned int mem_event; +static void wq_sched_handler(struct work_struct *wsptr); +DECLARE_WORK(work, wq_sched_handler); +static struct timer_list meminfo_wake_up_timer; +static void meminfo_wake_up_handler(unsigned long unused_data); + +static void notify(void) +{ + mem_event++; +} + +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) #else GATOR_DEFINE_PROBE(mm_page_free, TP_PROTO(struct page *page, unsigned int order)) #endif { - up(&gator_meminfo_sem); + notify(); } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) @@ -80,12 +104,12 @@ GATOR_DEFINE_PROBE(mm_pagevec_free, TP_PROTO(struct page *page, int cold)) GATOR_DEFINE_PROBE(mm_page_free_batched, TP_PROTO(struct page *page, int cold)) #endif { - up(&gator_meminfo_sem); + notify(); } GATOR_DEFINE_PROBE(mm_page_alloc, TP_PROTO(struct page *page, unsigned int order, gfp_t gfp_flags, int migratetype)) { - up(&gator_meminfo_sem); + notify(); } static int gator_events_meminfo_create_files(struct super_block *sb, struct dentry *root) @@ -95,18 +119,16 @@ static int gator_events_meminfo_create_files(struct super_block *sb, struct dent for (i = 0; i < MEMINFO_TOTAL; i++) { dir = gatorfs_mkdir(sb, root, meminfo_names[i]); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &meminfo_enabled[i]); gatorfs_create_ro_ulong(sb, dir, "key", &meminfo_keys[i]); } for (i = 0; i < PROC_COUNT; ++i) { dir = gatorfs_mkdir(sb, root, proc_names[i]); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &proc_enabled[i]); gatorfs_create_ro_ulong(sb, dir, "key", &proc_keys[i]); } @@ -134,9 +156,8 @@ static int gator_events_meminfo_start(void) break; } } - if (meminfo_enabled[MEMINFO_MEMUSED]) { + if (meminfo_enabled[MEMINFO_MEMUSED]) proc_global_enabled = 1; - } if (meminfo_global_enabled == 0) return 0; @@ -156,16 +177,22 @@ static int gator_events_meminfo_start(void) if (GATOR_REGISTER_TRACE(mm_page_alloc)) goto mm_page_alloc_exit; - // Start worker thread +#if USE_THREAD + /* Start worker thread */ gator_meminfo_run = true; - // Since the mutex starts unlocked, memory values will be initialized + /* Since the mutex starts unlocked, memory values will be initialized */ if (IS_ERR(kthread_run(gator_meminfo_func, NULL, "gator_meminfo"))) goto kthread_run_exit; +#else + setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0); +#endif return 0; +#if USE_THREAD kthread_run_exit: GATOR_UNREGISTER_TRACE(mm_page_alloc); +#endif mm_page_alloc_exit: #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) GATOR_UNREGISTER_TRACE(mm_pagevec_free); @@ -194,75 +221,111 @@ static void gator_events_meminfo_stop(void) #endif GATOR_UNREGISTER_TRACE(mm_page_alloc); - // Stop worker thread +#if USE_THREAD + /* Stop worker thread */ gator_meminfo_run = false; up(&gator_meminfo_sem); +#else + del_timer_sync(&meminfo_wake_up_timer); +#endif } } -// Must be run in process context as the kernel function si_meminfo() can sleep -static int gator_meminfo_func(void *data) +static void do_read(void) { struct sysinfo info; int i, len; unsigned long long value; - for (;;) { - if (down_killable(&gator_meminfo_sem)) { - break; + meminfo_length = len = 0; + + si_meminfo(&info); + for (i = 0; i < MEMINFO_TOTAL; i++) { + if (meminfo_enabled[i]) { + switch (i) { + case MEMINFO_MEMFREE: + value = info.freeram * PAGE_SIZE; + break; + case MEMINFO_MEMUSED: + /* pid -1 means system wide */ + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = -1; + /* Emit value */ + meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED]; + meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE; + /* Clear pid */ + meminfo_buffer[len++] = 1; + meminfo_buffer[len++] = 0; + continue; + case MEMINFO_BUFFERRAM: + value = info.bufferram * PAGE_SIZE; + break; + default: + value = 0; + break; + } + meminfo_buffer[len++] = meminfo_keys[i]; + meminfo_buffer[len++] = value; } + } - // Eat up any pending events - while (!down_trylock(&gator_meminfo_sem)); + meminfo_length = len; + new_data_avail = true; +} - if (!gator_meminfo_run) { +#if USE_THREAD + +static int gator_meminfo_func(void *data) +{ + for (;;) { + if (down_killable(&gator_meminfo_sem)) break; - } - meminfo_length = len = 0; - - si_meminfo(&info); - for (i = 0; i < MEMINFO_TOTAL; i++) { - if (meminfo_enabled[i]) { - switch (i) { - case MEMINFO_MEMFREE: - value = info.freeram * PAGE_SIZE; - break; - case MEMINFO_MEMUSED: - // pid -1 means system wide - meminfo_buffer[len++] = 1; - meminfo_buffer[len++] = -1; - // Emit value - meminfo_buffer[len++] = meminfo_keys[MEMINFO_MEMUSED]; - meminfo_buffer[len++] = (info.totalram - info.freeram) * PAGE_SIZE; - // Clear pid - meminfo_buffer[len++] = 1; - meminfo_buffer[len++] = 0; - continue; - case MEMINFO_BUFFERRAM: - value = info.bufferram * PAGE_SIZE; - break; - default: - value = 0; - break; - } - meminfo_buffer[len++] = meminfo_keys[i]; - meminfo_buffer[len++] = value; - } - } + /* Eat up any pending events */ + while (!down_trylock(&gator_meminfo_sem)) + ; + + if (!gator_meminfo_run) + break; - meminfo_length = len; - new_data_avail = true; + do_read(); } return 0; } +#else + +/* Must be run in process context as the kernel function si_meminfo() can sleep */ +static void wq_sched_handler(struct work_struct *wsptr) +{ + do_read(); +} + +static void meminfo_wake_up_handler(unsigned long unused_data) +{ + /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */ + schedule_work(&work); +} + +#endif + static int gator_events_meminfo_read(long long **buffer) { +#if !USE_THREAD + static unsigned int last_mem_event; +#endif + if (!on_primary_core() || !meminfo_global_enabled) return 0; +#if !USE_THREAD + if (last_mem_event != mem_event) { + last_mem_event = mem_event; + mod_timer(&meminfo_wake_up_timer, jiffies + 1); + } +#endif + if (!new_data_avail) return 0; @@ -280,6 +343,7 @@ static inline unsigned long gator_get_mm_counter(struct mm_struct *mm, int membe { #ifdef SPLIT_RSS_COUNTING long val = atomic_long_read(&mm->rss_stat.count[member]); + if (val < 0) val = 0; return (unsigned long)val; @@ -306,22 +370,19 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct int cpu = get_physical_cpu(); long long *buf = per_cpu(proc_buffer, cpu); - if (!proc_global_enabled) { + if (!proc_global_enabled) return 0; - } - // Collect the memory stats of the process instead of the thread - if (task->group_leader != NULL) { + /* Collect the memory stats of the process instead of the thread */ + if (task->group_leader != NULL) task = task->group_leader; - } - // get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch + /* get_task_mm/mmput is not needed in this context because the task and it's mm are required as part of the sched_switch */ mm = task->mm; - if (mm == NULL) { + if (mm == NULL) return 0; - } - // Derived from task_statm in fs/proc/task_mmu.c + /* Derived from task_statm in fs/proc/task_mmu.c */ if (meminfo_enabled[MEMINFO_MEMUSED] || proc_enabled[PROC_SHARE]) { share = get_mm_counter(mm, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) @@ -332,7 +393,7 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct ); } - // key of 1 indicates a pid + /* key of 1 indicates a pid */ buf[len++] = 1; buf[len++] = task->pid; @@ -366,12 +427,12 @@ static int gator_events_meminfo_read_proc(long long **buffer, struct task_struct MM_ANONPAGES #endif ); - // Send resident for this pid + /* Send resident for this pid */ buf[len++] = meminfo_keys[MEMINFO_MEMUSED]; buf[len++] = value * PAGE_SIZE; } - // Clear pid + /* Clear pid */ buf[len++] = 1; buf[len++] = 0; diff --git a/drivers/gator/gator_events_mmapped.c b/drivers/gator/gator_events_mmapped.c index 3b248ec24e6e..6b2af995ed41 100644 --- a/drivers/gator/gator_events_mmapped.c +++ b/drivers/gator/gator_events_mmapped.c @@ -8,21 +8,25 @@ * published by the Free Software Foundation. * * Similar entries to those below must be present in the events.xml file. - * To add them to the events.xml, create an events-mmap.xml with the + * To add them to the events.xml, create an events-mmap.xml with the * following contents and rebuild gatord: * - * - * - * - * - * + * + * + * + * * * - * When adding custom events, be sure do the following + * When adding custom events, be sure to do the following: * - add any needed .c files to the gator driver Makefile * - call gator_events_install in the events init function * - add the init function to GATOR_EVENTS_LIST in gator_main.c * - add a new events-*.xml file to the gator daemon and rebuild + * + * Troubleshooting: + * - verify the new events are part of events.xml, which is created when building the daemon + * - verify the new events exist at /dev/gator/events/ once gatord is launched + * - verify the counter name in the XML matches the name at /dev/gator/events */ #include @@ -37,7 +41,6 @@ static int mmapped_global_enabled; static struct { unsigned long enabled; - unsigned long event; unsigned long key; } mmapped_counters[MMAPPED_COUNTERS_NUM]; @@ -47,7 +50,7 @@ static s64 prev_time; /* Adds mmapped_cntX directories and enabled, event, and key files to /dev/gator/events */ static int gator_events_mmapped_create_files(struct super_block *sb, - struct dentry *root) + struct dentry *root) { int i; @@ -61,8 +64,6 @@ static int gator_events_mmapped_create_files(struct super_block *sb, return -1; gatorfs_create_ulong(sb, dir, "enabled", &mmapped_counters[i].enabled); - gatorfs_create_ulong(sb, dir, "event", - &mmapped_counters[i].event); gatorfs_create_ro_ulong(sb, dir, "key", &mmapped_counters[i].key); } @@ -102,7 +103,7 @@ static int mmapped_simulate(int counter, int delta_in_us) switch (counter) { case 0: /* sort-of-sine */ { - static int t = 0; + static int t; int x; t += delta_in_us; @@ -139,7 +140,7 @@ static int mmapped_simulate(int counter, int delta_in_us) break; case 2: /* PWM signal */ { - static int dc, x, t = 0; + static int dc, x, t; t += delta_in_us; if (t > 1000000) @@ -156,7 +157,7 @@ static int mmapped_simulate(int counter, int delta_in_us) return result; } -static int gator_events_mmapped_read(int **buffer) +static int gator_events_mmapped_read(int **buffer, bool sched_switch) { int i; int len = 0; @@ -177,8 +178,7 @@ static int gator_events_mmapped_read(int **buffer) if (mmapped_counters[i].enabled) { mmapped_buffer[len++] = mmapped_counters[i].key; mmapped_buffer[len++] = - mmapped_simulate(mmapped_counters[i].event, - delta_in_us); + mmapped_simulate(i, delta_in_us); } } diff --git a/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c index 11c10e375511..d21b4db7b77c 100644 --- a/drivers/gator/gator_events_net.c +++ b/drivers/gator/gator_events_net.c @@ -25,7 +25,7 @@ static int netGet[TOTALNET * 4]; static struct timer_list net_wake_up_timer; -// Must be run in process context as the kernel function dev_get_stats() can sleep +/* Must be run in process context as the kernel function dev_get_stats() can sleep */ static void get_network_stats(struct work_struct *wsptr) { int rx = 0, tx = 0; @@ -49,7 +49,7 @@ DECLARE_WORK(wq_get_stats, get_network_stats); static void net_wake_up_handler(unsigned long unused_data) { - // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater + /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */ schedule_work(&wq_get_stats); } @@ -73,21 +73,19 @@ static void calculate_delta(int *rx, int *tx) static int gator_events_net_create_files(struct super_block *sb, struct dentry *root) { - // Network counters are not currently supported in RT-Preempt full because mod_timer is used + /* Network counters are not currently supported in RT-Preempt full because mod_timer is used */ #ifndef CONFIG_PREEMPT_RT_FULL struct dentry *dir; dir = gatorfs_mkdir(sb, root, "Linux_net_rx"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &netrx_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &netrx_key); dir = gatorfs_mkdir(sb, root, "Linux_net_tx"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &nettx_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &nettx_key); #endif @@ -115,10 +113,10 @@ static void gator_events_net_stop(void) nettx_enabled = 0; } -static int gator_events_net_read(int **buffer) +static int gator_events_net_read(int **buffer, bool sched_switch) { int len, rx_delta, tx_delta; - static int last_rx_delta = 0, last_tx_delta = 0; + static int last_rx_delta, last_tx_delta; if (!on_primary_core()) return 0; @@ -134,7 +132,8 @@ static int gator_events_net_read(int **buffer) if (netrx_enabled && last_rx_delta != rx_delta) { last_rx_delta = rx_delta; netGet[len++] = netrx_key; - netGet[len++] = 0; // indicates to Streamline that rx_delta bytes were transmitted now, not since the last message + /* indicates to Streamline that rx_delta bytes were transmitted now, not since the last message */ + netGet[len++] = 0; netGet[len++] = netrx_key; netGet[len++] = rx_delta; } @@ -142,7 +141,8 @@ static int gator_events_net_read(int **buffer) if (nettx_enabled && last_tx_delta != tx_delta) { last_tx_delta = tx_delta; netGet[len++] = nettx_key; - netGet[len++] = 0; // indicates to Streamline that tx_delta bytes were transmitted now, not since the last message + /* indicates to Streamline that tx_delta bytes were transmitted now, not since the last message */ + netGet[len++] = 0; netGet[len++] = nettx_key; netGet[len++] = tx_delta; } diff --git a/drivers/gator/gator_events_perf_pmu.c b/drivers/gator/gator_events_perf_pmu.c index 8b2d67a058b3..47cf278e508b 100644 --- a/drivers/gator/gator_events_perf_pmu.c +++ b/drivers/gator/gator_events_perf_pmu.c @@ -8,7 +8,7 @@ #include "gator.h" -// gator_events_armvX.c is used for Linux 2.6.x +/* gator_events_armvX.c is used for Linux 2.6.x */ #if GATOR_PERF_PMU_SUPPORT #include @@ -20,39 +20,41 @@ extern bool event_based_sampling; -// Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE +/* Maximum number of per-core counters - currently reserves enough space for two full hardware PMUs for big.LITTLE */ #define CNTMAX 16 #define CCI_400 4 -// Maximum number of uncore counters -// + 1 for the cci-400 cycles counter -#define UCCNT (CCI_400 + 1) +#define CCN_5XX 8 +/* Maximum number of uncore counters */ +/* + 1 for the cci-400 cycles counter */ +/* + 1 for the CCN-5xx cycles counter */ +#define UCCNT (CCI_400 + 1 + CCN_5XX + 1) -// Default to 0 if unable to probe the revision which was the previous behavior +/* Default to 0 if unable to probe the revision which was the previous behavior */ #define DEFAULT_CCI_REVISION 0 -// A gator_attr is needed for every counter +/* A gator_attr is needed for every counter */ struct gator_attr { - // Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs + /* Set once in gator_events_perf_pmu_*_init - the name of the event in the gatorfs */ char name[40]; - // Exposed in gatorfs - set by gatord to enable this counter + /* Exposed in gatorfs - set by gatord to enable this counter */ unsigned long enabled; - // Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file. + /* Set once in gator_events_perf_pmu_*_init - the perf type to use, see perf_type_id in the perf_event.h header file. */ unsigned long type; - // Exposed in gatorfs - set by gatord to select the event to collect + /* Exposed in gatorfs - set by gatord to select the event to collect */ unsigned long event; - // Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter + /* Exposed in gatorfs - set by gatord with the sample period to use and enable EBS for this counter */ unsigned long count; - // Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data + /* Exposed as read only in gatorfs - set once in __attr_init as the key to use in the APC data */ unsigned long key; }; -// Per-core counter attributes +/* Per-core counter attributes */ static struct gator_attr attrs[CNTMAX]; -// Number of initialized per-core counters +/* Number of initialized per-core counters */ static int attr_count; -// Uncore counter attributes +/* Uncore counter attributes */ static struct gator_attr uc_attrs[UCCNT]; -// Number of initialized uncore counters +/* Number of initialized uncore counters */ static int uc_attr_count; struct gator_event { @@ -74,13 +76,11 @@ static int __create_files(struct super_block *sb, struct dentry *root, struct ga { struct dentry *dir; - if (attr->name[0] == '\0') { + if (attr->name[0] == '\0') return 0; - } dir = gatorfs_mkdir(sb, root, attr->name); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &attr->enabled); gatorfs_create_ulong(sb, dir, "count", &attr->count); gatorfs_create_ro_ulong(sb, dir, "key", &attr->key); @@ -94,15 +94,13 @@ static int gator_events_perf_pmu_create_files(struct super_block *sb, struct den int cnt; for (cnt = 0; cnt < attr_count; cnt++) { - if (__create_files(sb, root, &attrs[cnt]) != 0) { + if (__create_files(sb, root, &attrs[cnt]) != 0) return -1; - } } for (cnt = 0; cnt < uc_attr_count; cnt++) { - if (__create_files(sb, root, &uc_attrs[cnt]) != 0) { + if (__create_files(sb, root, &uc_attrs[cnt]) != 0) return -1; - } } return 0; @@ -123,14 +121,14 @@ static void dummy_handler(struct perf_event *event, int unused, struct perf_samp static void dummy_handler(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs) #endif { -// Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll + /* Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll */ } -static int gator_events_perf_pmu_read(int **buffer); +static int gator_events_perf_pmu_read(int **buffer, bool sched_switch); static int gator_events_perf_pmu_online(int **buffer, bool migrate) { - return gator_events_perf_pmu_read(buffer); + return gator_events_perf_pmu_read(buffer, false); } static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const attr, struct gator_event *const event) @@ -139,15 +137,13 @@ static void __online_dispatch(int cpu, bool migrate, struct gator_attr *const at event->zero = true; - if (event->pevent != NULL || event->pevent_attr == 0 || migrate) { + if (event->pevent != NULL || event->pevent_attr == 0 || migrate) return; - } - if (attr->count > 0) { + if (attr->count > 0) handler = ebs_overflow_handler; - } else { + else handler = dummy_handler; - } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) event->pevent = perf_event_create_kernel_counter(event->pevent_attr, cpu, 0, handler); @@ -174,14 +170,12 @@ static void gator_events_perf_pmu_online_dispatch(int cpu, bool migrate) cpu = pcpu_to_lcpu(cpu); - for (cnt = 0; cnt < attr_count; cnt++) { + for (cnt = 0; cnt < attr_count; cnt++) __online_dispatch(cpu, migrate, &attrs[cnt], &per_cpu(events, cpu)[cnt]); - } if (cpu == 0) { - for (cnt = 0; cnt < uc_attr_count; cnt++) { + for (cnt = 0; cnt < uc_attr_count; cnt++) __online_dispatch(cpu, migrate, &uc_attrs[cnt], &uc_events[cnt]); - } } } @@ -194,28 +188,24 @@ static void __offline_dispatch(int cpu, struct gator_event *const event) event->pevent = NULL; } - if (pe) { + if (pe) perf_event_release_kernel(pe); - } } static void gator_events_perf_pmu_offline_dispatch(int cpu, bool migrate) { int cnt; - if (migrate) { + if (migrate) return; - } cpu = pcpu_to_lcpu(cpu); - for (cnt = 0; cnt < attr_count; cnt++) { + for (cnt = 0; cnt < attr_count; cnt++) __offline_dispatch(cpu, &per_cpu(events, cpu)[cnt]); - } if (cpu == 0) { - for (cnt = 0; cnt < uc_attr_count; cnt++) { + for (cnt = 0; cnt < uc_attr_count; cnt++) __offline_dispatch(cpu, &uc_events[cnt]); - } } } @@ -225,7 +215,7 @@ static int __check_ebs(struct gator_attr *const attr) if (!event_based_sampling) { event_based_sampling = true; } else { - printk(KERN_WARNING "gator: Only one ebs counter is allowed\n"); + pr_warning("gator: Only one ebs counter is allowed\n"); return -1; } } @@ -238,9 +228,9 @@ static int __start(struct gator_attr *const attr, struct gator_event *const even u32 size = sizeof(struct perf_event_attr); event->pevent = NULL; - if (!attr->enabled) { // Skip disabled counters + /* Skip disabled counters */ + if (!attr->enabled) return 0; - } event->prev = 0; event->curr = 0; @@ -267,29 +257,25 @@ static int gator_events_perf_pmu_start(void) event_based_sampling = false; for (cnt = 0; cnt < attr_count; cnt++) { - if (__check_ebs(&attrs[cnt]) != 0) { + if (__check_ebs(&attrs[cnt]) != 0) return -1; - } } for (cnt = 0; cnt < uc_attr_count; cnt++) { - if (__check_ebs(&uc_attrs[cnt]) != 0) { + if (__check_ebs(&uc_attrs[cnt]) != 0) return -1; - } } for_each_present_cpu(cpu) { for (cnt = 0; cnt < attr_count; cnt++) { - if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) { + if (__start(&attrs[cnt], &per_cpu(events, cpu)[cnt]) != 0) return -1; - } } } for (cnt = 0; cnt < uc_attr_count; cnt++) { - if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) { + if (__start(&uc_attrs[cnt], &uc_events[cnt]) != 0) return -1; - } } return 0; @@ -297,10 +283,8 @@ static int gator_events_perf_pmu_start(void) static void __event_stop(struct gator_event *const event) { - if (event->pevent_attr) { - kfree(event->pevent_attr); - event->pevent_attr = NULL; - } + kfree(event->pevent_attr); + event->pevent_attr = NULL; } static void __attr_stop(struct gator_attr *const attr) @@ -315,29 +299,25 @@ static void gator_events_perf_pmu_stop(void) unsigned int cnt, cpu; for_each_present_cpu(cpu) { - for (cnt = 0; cnt < attr_count; cnt++) { + for (cnt = 0; cnt < attr_count; cnt++) __event_stop(&per_cpu(events, cpu)[cnt]); - } } - for (cnt = 0; cnt < uc_attr_count; cnt++) { + for (cnt = 0; cnt < uc_attr_count; cnt++) __event_stop(&uc_events[cnt]); - } - for (cnt = 0; cnt < attr_count; cnt++) { + for (cnt = 0; cnt < attr_count; cnt++) __attr_stop(&attrs[cnt]); - } - for (cnt = 0; cnt < uc_attr_count; cnt++) { + for (cnt = 0; cnt < uc_attr_count; cnt++) __attr_stop(&uc_attrs[cnt]); - } } static void __read(int *const len, int cpu, struct gator_attr *const attr, struct gator_event *const event) { int delta; - struct perf_event *const ev = event->pevent; + if (ev != NULL && ev->state == PERF_EVENT_STATE_ACTIVE) { /* After creating the perf counter in __online_dispatch, there * is a race condition between gator_events_perf_pmu_online and @@ -361,33 +341,29 @@ static void __read(int *const len, int cpu, struct gator_attr *const attr, struc event->prev_delta = delta; event->prev = event->curr; per_cpu(perf_cnt, cpu)[(*len)++] = attr->key; - if (delta < 0) { + if (delta < 0) delta *= -1; - } per_cpu(perf_cnt, cpu)[(*len)++] = delta; } } } } -static int gator_events_perf_pmu_read(int **buffer) +static int gator_events_perf_pmu_read(int **buffer, bool sched_switch) { int cnt, len = 0; const int cpu = get_logical_cpu(); - for (cnt = 0; cnt < attr_count; cnt++) { + for (cnt = 0; cnt < attr_count; cnt++) __read(&len, cpu, &attrs[cnt], &per_cpu(events, cpu)[cnt]); - } if (cpu == 0) { - for (cnt = 0; cnt < uc_attr_count; cnt++) { + for (cnt = 0; cnt < uc_attr_count; cnt++) __read(&len, cpu, &uc_attrs[cnt], &uc_events[cnt]); - } } - if (buffer) { + if (buffer) *buffer = per_cpu(perf_cnt, cpu); - } return len; } @@ -428,23 +404,20 @@ static int probe_cci_revision(void) int ret = DEFAULT_CCI_REVISION; np = of_find_matching_node(NULL, arm_cci_matches); - if (!np) { + if (!np) return ret; - } - if (of_address_to_resource(np, 0, &res)) { + if (of_address_to_resource(np, 0, &res)) goto node_put; - } cci_ctrl_base = ioremap(res.start, resource_size(&res)); rev = (readl_relaxed(cci_ctrl_base + 0xfe8) >> 4) & 0xf; - if (rev <= 4) { + if (rev <= 4) ret = 0; - } else if (rev <= 6) { + else if (rev <= 6) ret = 1; - } iounmap(cci_ctrl_base); @@ -463,32 +436,39 @@ static int probe_cci_revision(void) #endif -static void gator_events_perf_pmu_cci_init(const int type) +static void gator_events_perf_pmu_uncore_init(const char *const name, const int type, const int count) { int cnt; + + snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", name); + uc_attrs[uc_attr_count].type = type; + ++uc_attr_count; + + for (cnt = 0; cnt < count; ++cnt, ++uc_attr_count) { + struct gator_attr *const attr = &uc_attrs[uc_attr_count]; + + snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", name, cnt); + attr->type = type; + } +} + +static void gator_events_perf_pmu_cci_init(const int type) +{ const char *cci_name; switch (probe_cci_revision()) { case 0: - cci_name = "cci-400"; + cci_name = "CCI_400"; break; case 1: - cci_name = "cci-400-r1"; + cci_name = "CCI_400-r1"; break; default: pr_debug("gator: unrecognized cci-400 revision\n"); return; } - snprintf(uc_attrs[uc_attr_count].name, sizeof(uc_attrs[uc_attr_count].name), "%s_ccnt", cci_name); - uc_attrs[uc_attr_count].type = type; - ++uc_attr_count; - - for (cnt = 0; cnt < CCI_400; ++cnt, ++uc_attr_count) { - struct gator_attr *const attr = &uc_attrs[uc_attr_count]; - snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", cci_name, cnt); - attr->type = type; - } + gator_events_perf_pmu_uncore_init(cci_name, type, CCI_400); } static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_cpu, const int type) @@ -501,6 +481,7 @@ static void gator_events_perf_pmu_cpu_init(const struct gator_cpu *const gator_c for (cnt = 0; cnt < gator_cpu->pmnc_counters; ++cnt, ++attr_count) { struct gator_attr *const attr = &attrs[attr_count]; + snprintf(attr->name, sizeof(attr->name), "%s_cnt%d", gator_cpu->pmnc_name, cnt); attr->type = type; } @@ -516,12 +497,10 @@ int gator_events_perf_pmu_init(void) int cnt; bool found_cpu = false; - for (cnt = 0; cnt < CNTMAX; cnt++) { + for (cnt = 0; cnt < CNTMAX; cnt++) __attr_init(&attrs[cnt]); - } - for (cnt = 0; cnt < UCCNT; cnt++) { + for (cnt = 0; cnt < UCCNT; cnt++) __attr_init(&uc_attrs[cnt]); - } memset(&pea, 0, sizeof(pea)); pea.size = sizeof(pea); @@ -531,7 +510,7 @@ int gator_events_perf_pmu_init(void) for (type = PERF_TYPE_MAX; type < 0x20; ++type) { pea.type = type; - // A particular PMU may work on some but not all cores, so try on each core + /* A particular PMU may work on some but not all cores, so try on each core */ pe = NULL; for_each_present_cpu(cpu) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) @@ -539,23 +518,31 @@ int gator_events_perf_pmu_init(void) #else pe = perf_event_create_kernel_counter(&pea, cpu, 0, dummy_handler, 0); #endif - if (!IS_ERR(pe)) { + if (!IS_ERR(pe)) break; - } } - // Assume that valid PMUs are contiguous + /* Assume that valid PMUs are contiguous */ if (IS_ERR(pe)) { - break; + pea.config = 0xff00; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) + pe = perf_event_create_kernel_counter(&pea, 0, 0, dummy_handler); +#else + pe = perf_event_create_kernel_counter(&pea, 0, 0, dummy_handler, 0); +#endif + if (IS_ERR(pe)) + break; } if (pe->pmu != NULL && type == pe->pmu->type) { - if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0) { + if (strcmp("CCI", pe->pmu->name) == 0 || strcmp("CCI_400", pe->pmu->name) == 0 || strcmp("CCI_400-r1", pe->pmu->name) == 0) { gator_events_perf_pmu_cci_init(type); + } else if (strcmp("ccn", pe->pmu->name) == 0) { + gator_events_perf_pmu_uncore_init("ARM_CCN_5XX", type, CCN_5XX); } else if ((gator_cpu = gator_find_cpu_by_pmu_name(pe->pmu->name)) != NULL) { found_cpu = true; gator_events_perf_pmu_cpu_init(gator_cpu, type); } - // Initialize gator_attrs for dynamic PMUs here + /* Initialize gator_attrs for dynamic PMUs here */ } perf_event_release_kernel(pe); @@ -563,21 +550,21 @@ int gator_events_perf_pmu_init(void) if (!found_cpu) { const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(gator_cpuid()); - if (gator_cpu == NULL) { + + if (gator_cpu == NULL) return -1; - } gator_events_perf_pmu_cpu_init(gator_cpu, PERF_TYPE_RAW); } - // Initialize gator_attrs for non-dynamic PMUs here + /* Initialize gator_attrs for non-dynamic PMUs here */ if (attr_count > CNTMAX) { - printk(KERN_ERR "gator: Too many perf counters\n"); + pr_err("gator: Too many perf counters\n"); return -1; } if (uc_attr_count > UCCNT) { - printk(KERN_ERR "gator: Too many perf uncore counters\n"); + pr_err("gator: Too many perf uncore counters\n"); return -1; } diff --git a/drivers/gator/gator_events_sched.c b/drivers/gator/gator_events_sched.c index 9e3915830182..637107d6af1d 100644 --- a/drivers/gator/gator_events_sched.c +++ b/drivers/gator/gator_events_sched.c @@ -26,8 +26,9 @@ GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_ { unsigned long flags; - // disable interrupts to synchronize with gator_events_sched_read() - // spinlocks not needed since percpu buffers are used + /* disable interrupts to synchronize with gator_events_sched_read() + * spinlocks not needed since percpu buffers are used + */ local_irq_save(flags); per_cpu(schedCnt, get_physical_cpu())[SCHED_SWITCH]++; local_irq_restore(flags); @@ -39,9 +40,8 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry /* switch */ dir = gatorfs_mkdir(sb, root, "Linux_sched_switch"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &sched_switch_enabled); gatorfs_create_ro_ulong(sb, dir, "key", &sched_switch_key); @@ -50,7 +50,7 @@ static int gator_events_sched_create_files(struct super_block *sb, struct dentry static int gator_events_sched_start(void) { - // register tracepoints + /* register tracepoints */ if (sched_switch_enabled) if (GATOR_REGISTER_TRACE(sched_switch)) goto sched_switch_exit; @@ -58,7 +58,7 @@ static int gator_events_sched_start(void) return 0; - // unregister tracepoints on error + /* unregister tracepoints on error */ sched_switch_exit: pr_err("gator: scheduler event tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); @@ -74,7 +74,7 @@ static void gator_events_sched_stop(void) sched_switch_enabled = 0; } -static int gator_events_sched_read(int **buffer) +static int gator_events_sched_read(int **buffer, bool sched_switch) { unsigned long flags; int len, value; diff --git a/drivers/gator/gator_events_scorpion.c b/drivers/gator/gator_events_scorpion.c index 8ca251af0e26..49219362db09 100644 --- a/drivers/gator/gator_events_scorpion.c +++ b/drivers/gator/gator_events_scorpion.c @@ -8,13 +8,13 @@ #include "gator.h" -// gator_events_perf_pmu.c is used if perf is supported +/* gator_events_perf_pmu.c is used if perf is supported */ #if GATOR_NO_PERF_SUPPORT static const char *pmnc_name; static int pmnc_counters; -// Per-CPU PMNC: config reg +/* Per-CPU PMNC: config reg */ #define PMNC_E (1 << 0) /* Enable all counters */ #define PMNC_P (1 << 1) /* Reset all counters */ #define PMNC_C (1 << 2) /* Cycle counter reset */ @@ -23,12 +23,12 @@ static int pmnc_counters; #define PMNC_DP (1 << 5) /* Disable CCNT if non-invasive debug */ #define PMNC_MASK 0x3f /* Mask for writable bits */ -// ccnt reg +/* ccnt reg */ #define CCNT_REG (1 << 31) -#define CCNT 0 +#define CCNT 0 #define CNT0 1 -#define CNTMAX (4+1) +#define CNTMAX (4+1) static unsigned long pmnc_enabled[CNTMAX]; static unsigned long pmnc_event[CNTMAX]; @@ -243,6 +243,7 @@ static inline void scorpion_pmnc_write(u32 val) static inline u32 scorpion_pmnc_read(void) { u32 val; + asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val)); return val; } @@ -250,6 +251,7 @@ static inline u32 scorpion_pmnc_read(void) static inline u32 scorpion_ccnt_read(void) { u32 val; + asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val)); return val; } @@ -257,6 +259,7 @@ static inline u32 scorpion_ccnt_read(void) static inline u32 scorpion_cntn_read(void) { u32 val; + asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val)); return val; } @@ -317,6 +320,7 @@ static inline int scorpion_pmnc_select_counter(unsigned int cnt) static u32 scorpion_read_lpm0(void) { u32 val; + asm volatile("mrc p15, 0, %0, c15, c0, 0" : "=r" (val)); return val; } @@ -329,6 +333,7 @@ static void scorpion_write_lpm0(u32 val) static u32 scorpion_read_lpm1(void) { u32 val; + asm volatile("mrc p15, 1, %0, c15, c0, 0" : "=r" (val)); return val; } @@ -341,6 +346,7 @@ static void scorpion_write_lpm1(u32 val) static u32 scorpion_read_lpm2(void) { u32 val; + asm volatile("mrc p15, 2, %0, c15, c0, 0" : "=r" (val)); return val; } @@ -353,6 +359,7 @@ static void scorpion_write_lpm2(u32 val) static u32 scorpion_read_l2lpm(void) { u32 val; + asm volatile("mrc p15, 3, %0, c15, c2, 0" : "=r" (val)); return val; } @@ -365,6 +372,7 @@ static void scorpion_write_l2lpm(u32 val) static u32 scorpion_read_vlpm(void) { u32 val; + asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val)); return val; } @@ -375,7 +383,7 @@ static void scorpion_write_vlpm(u32 val) } struct scorpion_access_funcs { - u32(*read)(void); + u32 (*read)(void); void (*write)(u32); }; @@ -420,17 +428,17 @@ static u32 scorpion_get_columnmask(u32 setval) { if (setval & COLMN0MASK) return 0xffffff00; - else if (setval & COLMN1MASK) + if (setval & COLMN1MASK) return 0xffff00ff; - else if (setval & COLMN2MASK) + if (setval & COLMN2MASK) return 0xff00ffff; - else - return 0x80ffffff; + return 0x80ffffff; } static void scorpion_evt_setup(u32 gr, u32 setval) { u32 val; + if (gr == 4) scorpion_pre_vlpm(); val = scorpion_get_columnmask(setval) & scor_func[gr].read(); @@ -443,6 +451,7 @@ static void scorpion_evt_setup(u32 gr, u32 setval) static int get_scorpion_evtinfo(unsigned int evt_type, struct scorp_evt *evtinfo) { u32 idx; + if ((evt_type < 0x4c) || (evt_type >= MSM_MAX_EVT)) return 0; idx = evt_type - 0x4c; @@ -463,7 +472,7 @@ static inline void scorpion_pmnc_write_evtsel(unsigned int cnt, u32 val) } else { u32 zero = 0; struct scorp_evt evtinfo; - // extract evtinfo.grp and evtinfo.tevt_type_act from val + /* extract evtinfo.grp and evtinfo.tevt_type_act from val */ if (get_scorpion_evtinfo(val, &evtinfo) == 0) return; asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtinfo.evt_type_act)); @@ -505,20 +514,18 @@ static int gator_events_scorpion_create_files(struct super_block *sb, struct den for (i = 0; i < pmnc_counters; i++) { char buf[40]; - if (i == 0) { - snprintf(buf, sizeof buf, "%s_ccnt", pmnc_name); - } else { - snprintf(buf, sizeof buf, "%s_cnt%d", pmnc_name, i - 1); - } + + if (i == 0) + snprintf(buf, sizeof(buf), "%s_ccnt", pmnc_name); + else + snprintf(buf, sizeof(buf), "%s_cnt%d", pmnc_name, i - 1); dir = gatorfs_mkdir(sb, root, buf); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &pmnc_enabled[i]); gatorfs_create_ro_ulong(sb, dir, "key", &pmnc_key[i]); - if (i > 0) { + if (i > 0) gatorfs_create_ulong(sb, dir, "event", &pmnc_event[i]); - } } return 0; @@ -528,9 +535,8 @@ static int gator_events_scorpion_online(int **buffer, bool migrate) { unsigned int cnt, len = 0, cpu = smp_processor_id(); - if (scorpion_pmnc_read() & PMNC_E) { + if (scorpion_pmnc_read() & PMNC_E) scorpion_pmnc_write(scorpion_pmnc_read() & ~PMNC_E); - } /* Initialize & Reset PMNC: C bit and P bit */ scorpion_pmnc_write(PMNC_P | PMNC_C); @@ -541,33 +547,32 @@ static int gator_events_scorpion_online(int **buffer, bool migrate) if (!pmnc_enabled[cnt]) continue; - // disable counter + /* disable counter */ scorpion_pmnc_disable_counter(cnt); event = pmnc_event[cnt] & 255; - // Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count + /* Set event (if destined for PMNx counters), We don't need to set the event if it's a cycle count */ if (cnt != CCNT) scorpion_pmnc_write_evtsel(cnt, event); - // reset counter + /* reset counter */ scorpion_pmnc_reset_counter(cnt); - // Enable counter, do not enable interrupt for this counter + /* Enable counter, do not enable interrupt for this counter */ scorpion_pmnc_enable_counter(cnt); } - // enable + /* enable */ scorpion_pmnc_write(scorpion_pmnc_read() | PMNC_E); - // read the counters and toss the invalid data, return zero instead + /* read the counters and toss the invalid data, return zero instead */ for (cnt = 0; cnt < pmnc_counters; cnt++) { if (pmnc_enabled[cnt]) { - if (cnt == CCNT) { + if (cnt == CCNT) scorpion_ccnt_read(); - } else if (scorpion_pmnc_select_counter(cnt) == cnt) { + else if (scorpion_pmnc_select_counter(cnt) == cnt) scorpion_cntn_read(); - } scorpion_pmnc_reset_counter(cnt); per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; @@ -597,26 +602,25 @@ static void gator_events_scorpion_stop(void) } } -static int gator_events_scorpion_read(int **buffer) +static int gator_events_scorpion_read(int **buffer, bool sched_switch) { int cnt, len = 0; int cpu = smp_processor_id(); - // a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled - if (!(scorpion_pmnc_read() & PMNC_E)) { + /* a context switch may occur before the online hotplug event, thus need to check that the pmu is enabled */ + if (!(scorpion_pmnc_read() & PMNC_E)) return 0; - } for (cnt = 0; cnt < pmnc_counters; cnt++) { if (pmnc_enabled[cnt]) { int value; - if (cnt == CCNT) { + + if (cnt == CCNT) value = scorpion_ccnt_read(); - } else if (scorpion_pmnc_select_counter(cnt) == cnt) { + else if (scorpion_pmnc_select_counter(cnt) == cnt) value = scorpion_cntn_read(); - } else { + else value = 0; - } scorpion_pmnc_reset_counter(cnt); per_cpu(perfCnt, cpu)[len++] = pmnc_key[cnt]; @@ -655,7 +659,8 @@ int gator_events_scorpion_init(void) return -1; } - pmnc_counters++; // CNT[n] + CCNT + /* CNT[n] + CCNT */ + pmnc_counters++; for (cnt = CCNT; cnt < CNTMAX; cnt++) { pmnc_enabled[cnt] = 0; diff --git a/drivers/gator/gator_fs.c b/drivers/gator/gator_fs.c index 166cfe7d681d..d8fb357b9eda 100644 --- a/drivers/gator/gator_fs.c +++ b/drivers/gator/gator_fs.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #define gatorfs_MAGIC 0x24051020 #define TMPBUFSIZE 50 @@ -43,6 +43,7 @@ static ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t { char tmpbuf[TMPBUFSIZE]; size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val); + if (maxlen > TMPBUFSIZE) maxlen = TMPBUFSIZE; return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); @@ -52,6 +53,7 @@ static ssize_t gatorfs_u64_to_user(u64 val, char __user *buf, size_t count, loff { char tmpbuf[TMPBUFSIZE]; size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%llu\n", val); + if (maxlen > TMPBUFSIZE) maxlen = TMPBUFSIZE; return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen); @@ -104,12 +106,14 @@ static int gatorfs_u64_from_user(u64 *val, char const __user *buf, size_t count) static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { unsigned long *val = file->private_data; + return gatorfs_ulong_to_user(*val, buf, count, offset); } static ssize_t u64_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { u64 *val = file->private_data; + return gatorfs_u64_to_user(*val, buf, count, offset); } @@ -231,7 +235,7 @@ int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root, } static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root, - char const *name, u64 * val) + char const *name, u64 *val) { struct dentry *d = __gatorfs_create_file(sb, root, name, &u64_ro_fops, 0444); @@ -245,6 +249,7 @@ static int gatorfs_create_ro_u64(struct super_block *sb, struct dentry *root, static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset) { atomic_t *val = file->private_data; + return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset); } diff --git a/drivers/gator/gator_hrtimer_gator.c b/drivers/gator/gator_hrtimer_gator.c index 76584554b00f..c1525e10a8da 100644 --- a/drivers/gator/gator_hrtimer_gator.c +++ b/drivers/gator/gator_hrtimer_gator.c @@ -18,6 +18,7 @@ static void gator_hrtimer_offline(void); static enum hrtimer_restart gator_hrtimer_notify(struct hrtimer *hrtimer) { int cpu = get_logical_cpu(); + hrtimer_forward(hrtimer, per_cpu(hrtimer_expire, cpu), profiling_interval); per_cpu(hrtimer_expire, cpu) = ktime_add(per_cpu(hrtimer_expire, cpu), profiling_interval); (*callback)(); @@ -64,12 +65,11 @@ static int gator_hrtimer_init(int interval, void (*func)(void)) per_cpu(hrtimer_is_active, cpu) = 0; } - // calculate profiling interval - if (interval > 0) { + /* calculate profiling interval */ + if (interval > 0) profiling_interval = ns_to_ktime(1000000000UL / interval); - } else { + else profiling_interval.tv64 = 0; - } return 0; } diff --git a/drivers/gator/gator_iks.c b/drivers/gator/gator_iks.c index e90dfcce9381..fb78c10fd987 100644 --- a/drivers/gator/gator_iks.c +++ b/drivers/gator/gator_iks.c @@ -16,7 +16,7 @@ static bool map_cpuids; static int mpidr_cpuids[NR_CPUS]; -static const struct gator_cpu * mpidr_cpus[NR_CPUS]; +static const struct gator_cpu *mpidr_cpus[NR_CPUS]; static int __lcpu_to_pcpu[NR_CPUS]; static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name) @@ -25,9 +25,9 @@ static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name) for (i = 0; gator_cpus[i].cpuid != 0; ++i) { const struct gator_cpu *const gator_cpu = &gator_cpus[i]; - if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) { + + if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) return gator_cpu; - } } return NULL; @@ -41,7 +41,7 @@ static void calc_first_cluster_size(void) struct device_node *cn = NULL; int mpidr_cpuids_count = 0; - // Zero is a valid cpuid, so initialize the array to 0xff's + /* Zero is a valid cpuid, so initialize the array to 0xff's */ memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids)); memset(&mpidr_cpus, 0, sizeof(mpidr_cpus)); @@ -70,10 +70,10 @@ static void calc_first_cluster_size(void) static int linearize_mpidr(int mpidr) { int i; + for (i = 0; i < nr_cpu_ids; ++i) { - if (mpidr_cpuids[i] == mpidr) { + if (mpidr_cpuids[i] == mpidr) return i; - } } BUG(); @@ -113,6 +113,7 @@ static void gator_update_cpu_mapping(u32 cpu_hwid) { int lcpu = smp_processor_id(); int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK); + BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); __lcpu_to_pcpu[lcpu] = pcpu; @@ -132,7 +133,7 @@ GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid)) gator_update_cpu_mapping(cpu_hwid); - // get_physical_cpu must be called after gator_update_cpu_mapping + /* get_physical_cpu must be called after gator_update_cpu_mapping */ cpu = get_physical_cpu(); gator_timer_online_dispatch(cpu, true); gator_timer_online((void *)1); @@ -146,12 +147,11 @@ GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid)) static void gator_send_iks_core_names(void) { int cpu; - // Send the cpu names + /* Send the cpu names */ preempt_disable(); for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { - if (mpidr_cpus[cpu] != NULL) { - gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid, mpidr_cpus[cpu]); - } + if (mpidr_cpus[cpu] != NULL) + gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid); } preempt_enable(); } @@ -170,7 +170,7 @@ static int gator_migrate_start(void) if (retval == 0) retval = GATOR_REGISTER_TRACE(cpu_migrate_current); if (retval == 0) { - // Initialize the logical to physical cpu mapping + /* Initialize the logical to physical cpu mapping */ memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu)); bL_switcher_trace_trigger(); } diff --git a/drivers/gator/gator_main.c b/drivers/gator/gator_main.c index e67f7c5cc61d..30bf60d95286 100644 --- a/drivers/gator/gator_main.c +++ b/drivers/gator/gator_main.c @@ -7,8 +7,8 @@ * */ -// This version must match the gator daemon version -#define PROTOCOL_VERSION 18 +/* This version must match the gator daemon version */ +#define PROTOCOL_VERSION 20 static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include @@ -25,7 +25,7 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION; #include #include #include -#include +#include #include "gator.h" @@ -67,12 +67,12 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION; #define SUMMARY_BUFFER_SIZE (1*1024) #define BACKTRACE_BUFFER_SIZE (128*1024) #define NAME_BUFFER_SIZE (64*1024) -#define COUNTER_BUFFER_SIZE (64*1024) // counters have the core as part of the data and the core value in the frame header may be discarded +#define COUNTER_BUFFER_SIZE (64*1024) /* counters have the core as part of the data and the core value in the frame header may be discarded */ #define BLOCK_COUNTER_BUFFER_SIZE (128*1024) -#define ANNOTATE_BUFFER_SIZE (128*1024) // annotate counters have the core as part of the data and the core value in the frame header may be discarded +#define ANNOTATE_BUFFER_SIZE (128*1024) /* annotate counters have the core as part of the data and the core value in the frame header may be discarded */ #define SCHED_TRACE_BUFFER_SIZE (128*1024) -#define GPU_TRACE_BUFFER_SIZE (64*1024) // gpu trace counters have the core as part of the data and the core value in the frame header may be discarded -#define IDLE_BUFFER_SIZE (32*1024) // idle counters have the core as part of the data and the core value in the frame header may be discarded +#define IDLE_BUFFER_SIZE (32*1024) /* idle counters have the core as part of the data and the core value in the frame header may be discarded */ +#define ACTIVITY_BUFFER_SIZE (128*1024) #define NO_COOKIE 0U #define UNRESOLVED_COOKIE ~0U @@ -84,33 +84,32 @@ static unsigned long gator_protocol_version = PROTOCOL_VERSION; #define FRAME_BLOCK_COUNTER 5 #define FRAME_ANNOTATE 6 #define FRAME_SCHED_TRACE 7 -#define FRAME_GPU_TRACE 8 #define FRAME_IDLE 9 +#define FRAME_ACTIVITY 13 #define MESSAGE_END_BACKTRACE 1 -// Name Frame Messages +/* Name Frame Messages */ #define MESSAGE_COOKIE 1 #define MESSAGE_THREAD_NAME 2 #define MESSAGE_LINK 4 -// GPU Trace Frame Messages -#define MESSAGE_GPU_START 1 -#define MESSAGE_GPU_STOP 2 - -// Scheduler Trace Frame Messages +/* Scheduler Trace Frame Messages */ #define MESSAGE_SCHED_SWITCH 1 #define MESSAGE_SCHED_EXIT 2 -#define MESSAGE_SCHED_START 3 -// Idle Frame Messages +/* Idle Frame Messages */ #define MESSAGE_IDLE_ENTER 1 #define MESSAGE_IDLE_EXIT 2 -// Summary Frame Messages +/* Summary Frame Messages */ #define MESSAGE_SUMMARY 1 #define MESSAGE_CORE_NAME 3 +/* Activity Frame Messages */ +#define MESSAGE_SWITCH 2 +#define MESSAGE_EXIT 3 + #define MAXSIZE_PACK32 5 #define MAXSIZE_PACK64 10 @@ -132,8 +131,8 @@ enum { BLOCK_COUNTER_BUF, ANNOTATE_BUF, SCHED_TRACE_BUF, - GPU_TRACE_BUF, IDLE_BUF, + ACTIVITY_BUF, NUM_GATOR_BUFS }; @@ -141,14 +140,15 @@ enum { * Globals ******************************************************************************/ static unsigned long gator_cpu_cores; -// Size of the largest buffer. Effectively constant, set in gator_op_create_files +/* Size of the largest buffer. Effectively constant, set in gator_op_create_files */ static unsigned long userspace_buffer_size; static unsigned long gator_backtrace_depth; -// How often to commit the buffers for live in nanoseconds +/* How often to commit the buffers for live in nanoseconds */ static u64 gator_live_rate; static unsigned long gator_started; static u64 gator_monotonic_started; +static u64 gator_sync_time; static u64 gator_hibernate_time; static unsigned long gator_buffer_opened; static unsigned long gator_timer_count; @@ -162,7 +162,7 @@ static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait); static DECLARE_WAIT_QUEUE_HEAD(gator_annotate_wait); static struct timer_list gator_buffer_wake_up_timer; static bool gator_buffer_wake_run; -// Initialize semaphore unlocked to initialize memory values +/* Initialize semaphore unlocked to initialize memory values */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) static DECLARE_MUTEX(gator_buffer_wake_sem); #else @@ -175,6 +175,7 @@ static DEFINE_PER_CPU(u64, last_timestamp); static bool printed_monotonic_warning; +static u32 gator_cpuids[NR_CPUS]; static bool sent_core_name[NR_CPUS]; static DEFINE_PER_CPU(bool, in_scheduler_context); @@ -183,33 +184,43 @@ static DEFINE_PER_CPU(bool, in_scheduler_context); * Prototypes ******************************************************************************/ static u64 gator_get_time(void); +static void gator_emit_perf_time(u64 time); static void gator_op_create_files(struct super_block *sb, struct dentry *root); -// gator_buffer is protected by being per_cpu and by having IRQs disabled when writing to it. -// Most marshal_* calls take care of this except for marshal_cookie*, marshal_backtrace* and marshal_frame where the caller is responsible for doing so. -// No synchronization is needed with the backtrace buffer as it is per cpu and is only used from the hrtimer. -// The annotate_lock must be held when using the annotation buffer as it is not per cpu. -// collect_counters which is the sole writer to the block counter frame is additionally protected by the per cpu collecting flag +/* gator_buffer is protected by being per_cpu and by having IRQs + * disabled when writing to it. Most marshal_* calls take care of this + * except for marshal_cookie*, marshal_backtrace* and marshal_frame + * where the caller is responsible for doing so. No synchronization is + * needed with the backtrace buffer as it is per cpu and is only used + * from the hrtimer. The annotate_lock must be held when using the + * annotation buffer as it is not per cpu. collect_counters which is + * the sole writer to the block counter frame is additionally + * protected by the per cpu collecting flag. + */ -// Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. +/* Size of the buffer, must be a power of 2. Effectively constant, set in gator_op_setup. */ static uint32_t gator_buffer_size[NUM_GATOR_BUFS]; -// gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup. +/* gator_buffer_size - 1, bitwise and with pos to get offset into the array. Effectively constant, set in gator_op_setup. */ static uint32_t gator_buffer_mask[NUM_GATOR_BUFS]; -// Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read +/* Read position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are read by userspace in userspace_buffer_read */ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_read); -// Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer +/* Write position in the buffer. Initialized to zero in gator_op_setup and incremented after bytes are written to the buffer */ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_write); -// Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace +/* Commit position in the buffer. Initialized to zero in gator_op_setup and incremented after a frame is ready to be read by userspace */ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], gator_buffer_commit); -// If set to false, decreases the number of bytes returned by buffer_bytes_available. Set in buffer_check_space if no space is remaining. Initialized to true in gator_op_setup -// This means that if we run out of space, continue to report that no space is available until bytes are read by userspace +/* If set to false, decreases the number of bytes returned by + * buffer_bytes_available. Set in buffer_check_space if no space is + * remaining. Initialized to true in gator_op_setup. This means that + * if we run out of space, continue to report that no space is + * available until bytes are read by userspace + */ static DEFINE_PER_CPU(int[NUM_GATOR_BUFS], buffer_space_available); -// The buffer. Allocated in gator_op_setup +/* The buffer. Allocated in gator_op_setup */ static DEFINE_PER_CPU(char *[NUM_GATOR_BUFS], gator_buffer); -// The time after which the buffer should be committed for live display +/* The time after which the buffer should be committed for live display */ static DEFINE_PER_CPU(u64, gator_buffer_commit_time); -// List of all gator events - new events must be added to this list +/* List of all gator events - new events must be added to this list */ #define GATOR_EVENTS_LIST \ GATOR_EVENT(gator_events_armv6_init) \ GATOR_EVENT(gator_events_armv7_init) \ @@ -218,8 +229,8 @@ static DEFINE_PER_CPU(u64, gator_buffer_commit_time); GATOR_EVENT(gator_events_irq_init) \ GATOR_EVENT(gator_events_l2c310_init) \ GATOR_EVENT(gator_events_mali_init) \ - GATOR_EVENT(gator_events_mali_t6xx_hw_init) \ - GATOR_EVENT(gator_events_mali_t6xx_init) \ + GATOR_EVENT(gator_events_mali_midgard_hw_init) \ + GATOR_EVENT(gator_events_mali_midgard_init) \ GATOR_EVENT(gator_events_meminfo_init) \ GATOR_EVENT(gator_events_mmapped_init) \ GATOR_EVENT(gator_events_net_init) \ @@ -313,13 +324,6 @@ static const struct gator_cpu gator_cpus[] = { .dt_name = "arm,cortex-a9", .pmnc_counters = 6, }, - { - .cpuid = CORTEX_A12, - .core_name = "Cortex-A12", - .pmnc_name = "ARMv7_Cortex_A12", - .dt_name = "arm,cortex-a12", - .pmnc_counters = 6, - }, { .cpuid = CORTEX_A15, .core_name = "Cortex-A15", @@ -399,23 +403,32 @@ const struct gator_cpu *gator_find_cpu_by_cpuid(const u32 cpuid) for (i = 0; gator_cpus[i].cpuid != 0; ++i) { const struct gator_cpu *const gator_cpu = &gator_cpus[i]; - if (gator_cpu->cpuid == cpuid) { + + if (gator_cpu->cpuid == cpuid) return gator_cpu; - } } return NULL; } +static const char OLD_PMU_PREFIX[] = "ARMv7 Cortex-"; +static const char NEW_PMU_PREFIX[] = "ARMv7_Cortex_"; + const struct gator_cpu *gator_find_cpu_by_pmu_name(const char *const name) { int i; for (i = 0; gator_cpus[i].cpuid != 0; ++i) { const struct gator_cpu *const gator_cpu = &gator_cpus[i]; - if (gator_cpu->pmnc_name != NULL && strcmp(gator_cpu->pmnc_name, name) == 0) { + + if (gator_cpu->pmnc_name != NULL && + /* Do the names match exactly? */ + (strcasecmp(gator_cpu->pmnc_name, name) == 0 || + /* Do these names match but have the old vs new prefix? */ + ((strncasecmp(name, OLD_PMU_PREFIX, sizeof(OLD_PMU_PREFIX) - 1) == 0 && + strncasecmp(gator_cpu->pmnc_name, NEW_PMU_PREFIX, sizeof(NEW_PMU_PREFIX) - 1) == 0 && + strcasecmp(name + sizeof(OLD_PMU_PREFIX) - 1, gator_cpu->pmnc_name + sizeof(NEW_PMU_PREFIX) - 1) == 0)))) return gator_cpu; - } } return NULL; @@ -444,16 +457,15 @@ static void gator_buffer_wake_up(unsigned long data) static int gator_buffer_wake_func(void *data) { for (;;) { - if (down_killable(&gator_buffer_wake_sem)) { + if (down_killable(&gator_buffer_wake_sem)) break; - } - // Eat up any pending events - while (!down_trylock(&gator_buffer_wake_sem)); + /* Eat up any pending events */ + while (!down_trylock(&gator_buffer_wake_sem)) + ; - if (!gator_buffer_wake_run) { + if (!gator_buffer_wake_run) break; - } gator_buffer_wake_up(0); } @@ -467,6 +479,7 @@ static int gator_buffer_wake_func(void *data) static bool buffer_commit_ready(int *cpu, int *buftype) { int cpu_x, x; + for_each_present_cpu(cpu_x) { for (x = 0; x < NUM_GATOR_BUFS; x++) if (per_cpu(gator_buffer_commit, cpu_x)[x] != per_cpu(gator_buffer_read, cpu_x)[x]) { @@ -486,6 +499,7 @@ static bool buffer_commit_ready(int *cpu, int *buftype) static void gator_timer_interrupt(void) { struct pt_regs *const regs = get_irq_regs(); + gator_backtrace_handler(regs); } @@ -494,15 +508,14 @@ void gator_backtrace_handler(struct pt_regs *const regs) u64 time = gator_get_time(); int cpu = get_physical_cpu(); - // Output backtrace + /* Output backtrace */ gator_add_sample(cpu, regs, time); - // Collect counters - if (!per_cpu(collecting, cpu)) { - collect_counters(time, NULL); - } + /* Collect counters */ + if (!per_cpu(collecting, cpu)) + collect_counters(time, current, false); - // No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed + /* No buffer flushing occurs during sched switch for RT-Preempt full. The block counter frame will be flushed by collect_counters, but the sched buffer needs to be explicitly flushed */ #ifdef CONFIG_PREEMPT_RT_FULL buffer_check(cpu, SCHED_TRACE_BUF, time); #endif @@ -510,7 +523,7 @@ void gator_backtrace_handler(struct pt_regs *const regs) static int gator_running; -// This function runs in interrupt context and on the appropriate core +/* This function runs in interrupt context and on the appropriate core */ static void gator_timer_offline(void *migrate) { struct gator_interface *gi; @@ -521,11 +534,10 @@ static void gator_timer_offline(void *migrate) gator_trace_sched_offline(); gator_trace_power_offline(); - if (!migrate) { + if (!migrate) gator_hrtimer_offline(); - } - // Offline any events and output counters + /* Offline any events and output counters */ time = gator_get_time(); if (marshal_event_header(time)) { list_for_each_entry(gi, &gator_events, list) { @@ -534,24 +546,23 @@ static void gator_timer_offline(void *migrate) marshal_event(len, buffer); } } - // Only check after writing all counters so that time and corresponding counters appear in the same frame + /* Only check after writing all counters so that time and corresponding counters appear in the same frame */ buffer_check(cpu, BLOCK_COUNTER_BUF, time); } - // Flush all buffers on this core + /* Flush all buffers on this core */ for (i = 0; i < NUM_GATOR_BUFS; i++) gator_commit_buffer(cpu, i, time); } -// This function runs in interrupt context and may be running on a core other than core 'cpu' +/* This function runs in interrupt context and may be running on a core other than core 'cpu' */ static void gator_timer_offline_dispatch(int cpu, bool migrate) { struct gator_interface *gi; list_for_each_entry(gi, &gator_events, list) { - if (gi->offline_dispatch) { + if (gi->offline_dispatch) gi->offline_dispatch(cpu, migrate); - } } } @@ -570,27 +581,38 @@ static void gator_timer_stop(void) } } -#if defined(__arm__) || defined(__aarch64__) -static void gator_send_core_name(int cpu, const u32 cpuid, const struct gator_cpu *const gator_cpu) +static void gator_send_core_name(const int cpu, const u32 cpuid) { - const char *core_name = NULL; - char core_name_buf[32]; +#if defined(__arm__) || defined(__aarch64__) + if (!sent_core_name[cpu] || (cpuid != gator_cpuids[cpu])) { + const struct gator_cpu *const gator_cpu = gator_find_cpu_by_cpuid(cpuid); + const char *core_name = NULL; + char core_name_buf[32]; - if (!sent_core_name[cpu]) { + /* Save off this cpuid */ + gator_cpuids[cpu] = cpuid; if (gator_cpu != NULL) { core_name = gator_cpu->core_name; } else { - snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid); + if (cpuid == -1) + snprintf(core_name_buf, sizeof(core_name_buf), "Unknown"); + else + snprintf(core_name_buf, sizeof(core_name_buf), "Unknown (0x%.3x)", cpuid); core_name = core_name_buf; } marshal_core_name(cpu, cpuid, core_name); sent_core_name[cpu] = true; } -} #endif +} + +static void gator_read_cpuid(void *arg) +{ + gator_cpuids[get_physical_cpu()] = gator_cpuid(); +} -// This function runs in interrupt context and on the appropriate core +/* This function runs in interrupt context and on the appropriate core */ static void gator_timer_online(void *migrate) { struct gator_interface *gi; @@ -598,9 +620,12 @@ static void gator_timer_online(void *migrate) int *buffer; u64 time; + /* Send what is currently running on this core */ + marshal_sched_trace_switch(current->pid, 0); + gator_trace_power_online(); - // online any events and output counters + /* online any events and output counters */ time = gator_get_time(); if (marshal_event_header(time)) { list_for_each_entry(gi, &gator_events, list) { @@ -609,31 +634,24 @@ static void gator_timer_online(void *migrate) marshal_event(len, buffer); } } - // Only check after writing all counters so that time and corresponding counters appear in the same frame + /* Only check after writing all counters so that time and corresponding counters appear in the same frame */ buffer_check(cpu, BLOCK_COUNTER_BUF, time); } - if (!migrate) { + if (!migrate) gator_hrtimer_online(); - } -#if defined(__arm__) || defined(__aarch64__) - if (!sent_core_name[cpu]) { - const u32 cpuid = gator_cpuid(); - gator_send_core_name(cpu, cpuid, gator_find_cpu_by_cpuid(cpuid)); - } -#endif + gator_send_core_name(cpu, gator_cpuid()); } -// This function runs in interrupt context and may be running on a core other than core 'cpu' +/* This function runs in interrupt context and may be running on a core other than core 'cpu' */ static void gator_timer_online_dispatch(int cpu, bool migrate) { struct gator_interface *gi; list_for_each_entry(gi, &gator_events, list) { - if (gi->online_dispatch) { + if (gi->online_dispatch) gi->online_dispatch(cpu, migrate); - } } } @@ -650,14 +668,20 @@ static int gator_timer_start(unsigned long sample_rate) gator_running = 1; - // event based sampling trumps hr timer based sampling - if (event_based_sampling) { + /* event based sampling trumps hr timer based sampling */ + if (event_based_sampling) sample_rate = 0; - } if (gator_hrtimer_init(sample_rate, gator_timer_interrupt) == -1) return -1; + /* Send off the previously saved cpuids */ + for_each_present_cpu(cpu) { + preempt_disable(); + gator_send_core_name(cpu, gator_cpuids[cpu]); + preempt_enable(); + } + gator_send_iks_core_names(); for_each_online_cpu(cpu) { gator_timer_online_dispatch(lcpu_to_pcpu(cpu), false); @@ -675,21 +699,24 @@ static u64 gator_get_time(void) u64 delta; int cpu = smp_processor_id(); - // Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace + /* Match clock_gettime(CLOCK_MONOTONIC_RAW, &ts) from userspace */ getrawmonotonic(&ts); timestamp = timespec_to_ns(&ts); - // getrawmonotonic is not monotonic on all systems. Detect and attempt to correct these cases. - // up to 0.5ms delta has been seen on some systems, which can skew Streamline data when viewing at high resolution. - // This doesn't work well with interrupts, but that it's OK - the real concern is to catch big jumps in time + /* getrawmonotonic is not monotonic on all systems. Detect and + * attempt to correct these cases. up to 0.5ms delta has been seen + * on some systems, which can skew Streamline data when viewing at + * high resolution. This doesn't work well with interrupts, but that + * it's OK - the real concern is to catch big jumps in time + */ prev_timestamp = per_cpu(last_timestamp, cpu); if (prev_timestamp <= timestamp) { per_cpu(last_timestamp, cpu) = timestamp; } else { delta = prev_timestamp - timestamp; - // Log the error once + /* Log the error once */ if (!printed_monotonic_warning && delta > 500000) { - printk(KERN_ERR "%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __FUNCTION__, cpu, delta); + pr_err("%s: getrawmonotonic is not monotonic cpu: %i delta: %lli\nSkew in Streamline data may be present at the fine zoom levels\n", __func__, cpu, delta); printed_monotonic_warning = true; } timestamp = prev_timestamp; @@ -698,6 +725,19 @@ static u64 gator_get_time(void) return timestamp - gator_monotonic_started; } +static void gator_emit_perf_time(u64 time) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) + if (time >= gator_sync_time) { + int cpu = get_physical_cpu(); + + marshal_event_single64(0, -1, local_clock()); + gator_sync_time += NSEC_PER_SEC; + gator_commit_buffer(cpu, COUNTER_BUF, time); + } +#endif +} + /****************************************************************************** * cpu hotplug and pm notifiers ******************************************************************************/ @@ -725,8 +765,10 @@ static struct notifier_block __refdata gator_hotcpu_notifier = { .notifier_call = gator_hotcpu_notify, }; -// n.b. calling "on_each_cpu" only runs on those that are online -// Registered linux events are not disabled, so their counters will continue to collect +/* n.b. calling "on_each_cpu" only runs on those that are online. + * Registered linux events are not disabled, so their counters will + * continue to collect + */ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) { int cpu; @@ -742,13 +784,13 @@ static int gator_pm_notify(struct notifier_block *nb, unsigned long event, void gator_timer_offline_dispatch(lcpu_to_pcpu(cpu), false); } - // Record the wallclock hibernate time + /* Record the wallclock hibernate time */ getnstimeofday(&ts); gator_hibernate_time = timespec_to_ns(&ts) - gator_get_time(); break; case PM_POST_HIBERNATION: case PM_POST_SUSPEND: - // Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it + /* Adjust gator_monotonic_started for the time spent sleeping, as gator_get_time does not account for it */ if (gator_hibernate_time > 0) { getnstimeofday(&ts); gator_monotonic_started += gator_hibernate_time + gator_get_time() - timespec_to_ns(&ts); @@ -774,6 +816,7 @@ static struct notifier_block gator_pm_notifier = { static int gator_notifier_start(void) { int retval; + retval = register_hotcpu_notifier(&gator_hotcpu_notifier); if (retval == 0) retval = register_pm_notifier(&gator_pm_notifier); @@ -794,28 +837,37 @@ static void gator_summary(void) u64 timestamp, uptime; struct timespec ts; char uname_buf[512]; - void (*m2b)(struct timespec *ts); snprintf(uname_buf, sizeof(uname_buf), "%s %s %s %s %s GNU/Linux", utsname()->sysname, utsname()->nodename, utsname()->release, utsname()->version, utsname()->machine); getnstimeofday(&ts); timestamp = timespec_to_ns(&ts); - do_posix_clock_monotonic_gettime(&ts); - // monotonic_to_bootbased is not defined for some versions of Android - m2b = symbol_get(monotonic_to_bootbased); - if (m2b) { - m2b(&ts); + /* Similar to reading /proc/uptime from fs/proc/uptime.c, calculate uptime */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0) + { + void (*m2b)(struct timespec *ts); + + do_posix_clock_monotonic_gettime(&ts); + /* monotonic_to_bootbased is not defined for some versions of Android */ + m2b = symbol_get(monotonic_to_bootbased); + if (m2b) + m2b(&ts); } +#else + get_monotonic_boottime(&ts); +#endif uptime = timespec_to_ns(&ts); - // Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic + /* Disable preemption as gator_get_time calls smp_processor_id to verify time is monotonic */ preempt_disable(); - // Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started + /* Set monotonic_started to zero as gator_get_time is uptime minus monotonic_started */ gator_monotonic_started = 0; gator_monotonic_started = gator_get_time(); marshal_summary(timestamp, uptime, gator_monotonic_started, uname_buf); + gator_sync_time = 0; + gator_emit_perf_time(gator_monotonic_started); preempt_enable(); } @@ -828,12 +880,14 @@ int gator_events_install(struct gator_interface *interface) int gator_events_get_key(void) { - // key 0 is reserved as a timestamp - // key 1 is reserved as the marker for thread specific counters - // Odd keys are assigned by the driver, even keys by the daemon + /* key 0 is reserved as a timestamp. key 1 is reserved as the marker + * for thread specific counters. key 2 is reserved as the marker for + * core. Odd keys are assigned by the driver, even keys by the + * daemon. + */ static int key = 3; - const int ret = key; + key += 2; return ret; } @@ -844,7 +898,7 @@ static int gator_init(void) calc_first_cluster_size(); - // events sources + /* events sources */ for (i = 0; i < ARRAY_SIZE(gator_events_list); i++) if (gator_events_list[i]) gator_events_list[i](); @@ -870,26 +924,25 @@ static int gator_start(void) struct gator_interface *gi; gator_buffer_wake_run = true; - if (IS_ERR(gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"))) { + gator_buffer_wake_thread = kthread_run(gator_buffer_wake_func, NULL, "gator_bwake"); + if (IS_ERR(gator_buffer_wake_thread)) goto bwake_failure; - } if (gator_migrate_start()) goto migrate_failure; - // Initialize the buffer with the frame type and core + /* Initialize the buffer with the frame type and core */ for_each_present_cpu(cpu) { - for (i = 0; i < NUM_GATOR_BUFS; i++) { + for (i = 0; i < NUM_GATOR_BUFS; i++) marshal_frame(cpu, i); - } per_cpu(last_timestamp, cpu) = 0; } printed_monotonic_warning = false; - // Capture the start time + /* Capture the start time */ gator_summary(); - // start all events + /* start all events */ list_for_each_entry(gi, &gator_events, list) { if (gi->start && gi->start() != 0) { struct list_head *ptr = gi->list.prev; @@ -906,7 +959,7 @@ static int gator_start(void) } } - // cookies shall be initialized before trace_sched_start() and gator_timer_start() + /* cookies shall be initialized before trace_sched_start() and gator_timer_start() */ if (cookies_initialize()) goto cookies_failure; if (gator_annotate_start()) @@ -937,7 +990,7 @@ static int gator_start(void) annotate_failure: cookies_release(); cookies_failure: - // stop all events + /* stop all events */ list_for_each_entry(gi, &gator_events, list) if (gi->stop) gi->stop(); @@ -961,11 +1014,11 @@ static void gator_stop(void) gator_trace_power_stop(); gator_trace_gpu_stop(); - // stop all interrupt callback reads before tearing down other interfaces - gator_notifier_stop(); // should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined + /* stop all interrupt callback reads before tearing down other interfaces */ + gator_notifier_stop(); /* should be called before gator_timer_stop to avoid re-enabling the hrtimer after it has been offlined */ gator_timer_stop(); - // stop all events + /* stop all events */ list_for_each_entry(gi, &gator_events, list) if (gi->stop) gi->stop(); @@ -1009,15 +1062,15 @@ static int gator_op_setup(void) gator_buffer_size[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE; gator_buffer_mask[SCHED_TRACE_BUF] = SCHED_TRACE_BUFFER_SIZE - 1; - gator_buffer_size[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE; - gator_buffer_mask[GPU_TRACE_BUF] = GPU_TRACE_BUFFER_SIZE - 1; - gator_buffer_size[IDLE_BUF] = IDLE_BUFFER_SIZE; gator_buffer_mask[IDLE_BUF] = IDLE_BUFFER_SIZE - 1; - // Initialize percpu per buffer variables + gator_buffer_size[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE; + gator_buffer_mask[ACTIVITY_BUF] = ACTIVITY_BUFFER_SIZE - 1; + + /* Initialize percpu per buffer variables */ for (i = 0; i < NUM_GATOR_BUFS; i++) { - // Verify buffers are a power of 2 + /* Verify buffers are a power of 2 */ if (gator_buffer_size[i] & (gator_buffer_size[i] - 1)) { err = -ENOEXEC; goto setup_error; @@ -1030,7 +1083,7 @@ static int gator_op_setup(void) per_cpu(buffer_space_available, cpu)[i] = true; per_cpu(gator_buffer_commit_time, cpu) = gator_live_rate; - // Annotation is a special case that only uses a single buffer + /* Annotation is a special case that only uses a single buffer */ if (cpu > 0 && i == ANNOTATE_BUF) { per_cpu(gator_buffer, cpu)[i] = NULL; continue; @@ -1170,7 +1223,8 @@ static int userspace_buffer_open(struct inode *inode, struct file *file) if (test_and_set_bit_lock(0, &gator_buffer_opened)) return -EBUSY; - if ((err = gator_op_setup())) + err = gator_op_setup(); + if (err) goto fail; /* NB: the actual start happens from userspace @@ -1200,22 +1254,20 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t int cpu, buftype; int written = 0; - // ensure there is enough space for a whole frame - if (count < userspace_buffer_size || *offset) { + /* ensure there is enough space for a whole frame */ + if (count < userspace_buffer_size || *offset) return -EINVAL; - } - // sleep until the condition is true or a signal is received - // the condition is checked each time gator_buffer_wait is woken up + /* sleep until the condition is true or a signal is received the + * condition is checked each time gator_buffer_wait is woken up + */ wait_event_interruptible(gator_buffer_wait, buffer_commit_ready(&cpu, &buftype) || !gator_started); - if (signal_pending(current)) { + if (signal_pending(current)) return -EINTR; - } - if (buftype == -1 || cpu == -1) { + if (buftype == -1 || cpu == -1) return 0; - } mutex_lock(&gator_buffer_mutex); @@ -1223,12 +1275,11 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t read = per_cpu(gator_buffer_read, cpu)[buftype]; commit = per_cpu(gator_buffer_commit, cpu)[buftype]; - // May happen if the buffer is freed during pending reads. - if (!per_cpu(gator_buffer, cpu)[buftype]) { + /* May happen if the buffer is freed during pending reads. */ + if (!per_cpu(gator_buffer, cpu)[buftype]) break; - } - // determine the size of two halves + /* determine the size of two halves */ length1 = commit - read; length2 = 0; buffer1 = &(per_cpu(gator_buffer, cpu)[buftype][read]); @@ -1238,32 +1289,28 @@ static ssize_t userspace_buffer_read(struct file *file, char __user *buf, size_t length2 = commit; } - if (length1 + length2 > count - written) { + if (length1 + length2 > count - written) break; - } - // start, middle or end - if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1)) { + /* start, middle or end */ + if (length1 > 0 && copy_to_user(&buf[written], buffer1, length1)) break; - } - // possible wrap around - if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2)) { + /* possible wrap around */ + if (length2 > 0 && copy_to_user(&buf[written + length1], buffer2, length2)) break; - } per_cpu(gator_buffer_read, cpu)[buftype] = commit; written += length1 + length2; - // Wake up annotate_write if more space is available - if (buftype == ANNOTATE_BUF) { + /* Wake up annotate_write if more space is available */ + if (buftype == ANNOTATE_BUF) wake_up(&gator_annotate_wait); - } } while (buffer_commit_ready(&cpu, &buftype)); mutex_unlock(&gator_buffer_mutex); - // kick just in case we've lost an SMP event + /* kick just in case we've lost an SMP event */ wake_up(&gator_buffer_wait); return written > 0 ? written : -EFAULT; @@ -1330,30 +1377,86 @@ static void gator_op_create_files(struct super_block *sb, struct dentry *root) gatorfs_create_ro_u64(sb, root, "started", &gator_monotonic_started); gatorfs_create_u64(sb, root, "live_rate", &gator_live_rate); - // Annotate interface + /* Annotate interface */ gator_annotate_create_files(sb, root); - // Linux Events + /* Linux Events */ dir = gatorfs_mkdir(sb, root, "events"); list_for_each_entry(gi, &gator_events, list) if (gi->create_files) gi->create_files(sb, dir); - // Sched Events + /* Sched Events */ sched_trace_create_files(sb, dir); - // Power interface + /* Power interface */ gator_trace_power_create_files(sb, dir); } /****************************************************************************** * Module ******************************************************************************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0) + +#define GATOR_TRACEPOINTS \ + GATOR_HANDLE_TRACEPOINT(block_rq_complete); \ + GATOR_HANDLE_TRACEPOINT(cpu_frequency); \ + GATOR_HANDLE_TRACEPOINT(cpu_idle); \ + GATOR_HANDLE_TRACEPOINT(cpu_migrate_begin); \ + GATOR_HANDLE_TRACEPOINT(cpu_migrate_current); \ + GATOR_HANDLE_TRACEPOINT(cpu_migrate_finish); \ + GATOR_HANDLE_TRACEPOINT(irq_handler_exit); \ + GATOR_HANDLE_TRACEPOINT(mali_hw_counter); \ + GATOR_HANDLE_TRACEPOINT(mali_job_slots_event); \ + GATOR_HANDLE_TRACEPOINT(mali_mmu_as_in_use); \ + GATOR_HANDLE_TRACEPOINT(mali_mmu_as_released); \ + GATOR_HANDLE_TRACEPOINT(mali_page_fault_insert_pages); \ + GATOR_HANDLE_TRACEPOINT(mali_pm_status); \ + GATOR_HANDLE_TRACEPOINT(mali_sw_counter); \ + GATOR_HANDLE_TRACEPOINT(mali_sw_counters); \ + GATOR_HANDLE_TRACEPOINT(mali_timeline_event); \ + GATOR_HANDLE_TRACEPOINT(mali_total_alloc_pages_change); \ + GATOR_HANDLE_TRACEPOINT(mm_page_alloc); \ + GATOR_HANDLE_TRACEPOINT(mm_page_free); \ + GATOR_HANDLE_TRACEPOINT(mm_page_free_batched); \ + GATOR_HANDLE_TRACEPOINT(sched_process_exec); \ + GATOR_HANDLE_TRACEPOINT(sched_process_fork); \ + GATOR_HANDLE_TRACEPOINT(sched_process_free); \ + GATOR_HANDLE_TRACEPOINT(sched_switch); \ + GATOR_HANDLE_TRACEPOINT(softirq_exit); \ + GATOR_HANDLE_TRACEPOINT(task_rename); \ + +#define GATOR_HANDLE_TRACEPOINT(probe_name) \ + struct tracepoint *gator_tracepoint_##probe_name +GATOR_TRACEPOINTS; +#undef GATOR_HANDLE_TRACEPOINT + +static void gator_save_tracepoint(struct tracepoint *tp, void *priv) +{ +#define GATOR_HANDLE_TRACEPOINT(probe_name) \ + do { \ + if (strcmp(tp->name, #probe_name) == 0) { \ + gator_tracepoint_##probe_name = tp; \ + return; \ + } \ + } while (0) +GATOR_TRACEPOINTS; +#undef GATOR_HANDLE_TRACEPOINT +} + +#else + +#define for_each_kernel_tracepoint(fct, priv) + +#endif + static int __init gator_module_init(void) { - if (gatorfs_register()) { + for_each_kernel_tracepoint(gator_save_tracepoint, NULL); + + if (gatorfs_register()) return -1; - } if (gator_init()) { gatorfs_unregister(); @@ -1362,6 +1465,10 @@ static int __init gator_module_init(void) setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0); + /* Initialize the list of cpuids */ + memset(gator_cpuids, -1, sizeof(gator_cpuids)); + on_each_cpu(gator_read_cpuid, NULL, 1); + return 0; } diff --git a/drivers/gator/gator_marshaling.c b/drivers/gator/gator_marshaling.c index fd413ad1331c..0d1167643642 100644 --- a/drivers/gator/gator_marshaling.c +++ b/drivers/gator/gator_marshaling.c @@ -23,7 +23,7 @@ #include "gator_events_mali_common.h" #endif -static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char * uname) +static void marshal_summary(long long timestamp, long long uptime, long long monotonic_delta, const char *uname) { unsigned long flags; int cpu = 0; @@ -40,19 +40,27 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon gator_buffer_write_string(cpu, SUMMARY_BUF, "iks"); gator_buffer_write_string(cpu, SUMMARY_BUF, ""); #endif - // Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release. +#ifdef CONFIG_PREEMPT_RTB + gator_buffer_write_string(cpu, SUMMARY_BUF, "preempt_rtb"); + gator_buffer_write_string(cpu, SUMMARY_BUF, ""); +#endif +#ifdef CONFIG_PREEMPT_RT_FULL + gator_buffer_write_string(cpu, SUMMARY_BUF, "preempt_rt_full"); + gator_buffer_write_string(cpu, SUMMARY_BUF, ""); +#endif + /* Let Streamline know which GPU is used so that it can label the GPU Activity appropriately. This is a temporary fix, to be improved in a future release. */ #ifdef MALI_SUPPORT gator_buffer_write_string(cpu, SUMMARY_BUF, "mali_type"); #if (MALI_SUPPORT == MALI_4xx) gator_buffer_write_string(cpu, SUMMARY_BUF, "4xx"); -#elif (MALI_SUPPORT == MALI_T6xx) +#elif (MALI_SUPPORT == MALI_MIDGARD) gator_buffer_write_string(cpu, SUMMARY_BUF, "6xx"); #else gator_buffer_write_string(cpu, SUMMARY_BUF, "unknown"); #endif #endif gator_buffer_write_string(cpu, SUMMARY_BUF, ""); - // Commit the buffer now so it can be one of the first frames read by Streamline + /* Commit the buffer now so it can be one of the first frames read by Streamline */ local_irq_restore(flags); gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time()); } @@ -60,13 +68,14 @@ static void marshal_summary(long long timestamp, long long uptime, long long mon static bool marshal_cookie_header(const char *text) { int cpu = get_physical_cpu(); + return buffer_check_space(cpu, NAME_BUF, strlen(text) + 3 * MAXSIZE_PACK32); } static void marshal_cookie(int cookie, const char *text) { int cpu = get_physical_cpu(); - // buffer_check_space already called by marshal_cookie_header + /* buffer_check_space already called by marshal_cookie_header */ gator_buffer_write_packed_int(cpu, NAME_BUF, MESSAGE_COOKIE); gator_buffer_write_packed_int(cpu, NAME_BUF, cookie); gator_buffer_write_string(cpu, NAME_BUF, text); @@ -77,6 +86,7 @@ static void marshal_thread_name(int pid, char *name) { unsigned long flags, cpu; u64 time; + local_irq_save(flags); cpu = get_physical_cpu(); time = gator_get_time(); @@ -105,15 +115,16 @@ static void marshal_link(int cookie, int tgid, int pid) gator_buffer_write_packed_int(cpu, NAME_BUF, pid); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, NAME_BUF, time); } static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 time) { int cpu = get_physical_cpu(); + if (!buffer_check_space(cpu, BACKTRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32 + gator_backtrace_depth * 2 * MAXSIZE_PACK32)) { - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, BACKTRACE_BUF, time); return false; @@ -130,9 +141,9 @@ static bool marshal_backtrace_header(int exec_cookie, int tgid, int pid, u64 tim static void marshal_backtrace(unsigned long address, int cookie, int in_kernel) { int cpu = get_physical_cpu(); - if (cookie == 0 && !in_kernel) { + + if (cookie == 0 && !in_kernel) cookie = UNRESOLVED_COOKIE; - } gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, cookie); gator_buffer_write_packed_int64(cpu, BACKTRACE_BUF, address); } @@ -140,9 +151,10 @@ static void marshal_backtrace(unsigned long address, int cookie, int in_kernel) static void marshal_backtrace_footer(u64 time) { int cpu = get_physical_cpu(); + gator_buffer_write_packed_int(cpu, BACKTRACE_BUF, MESSAGE_END_BACKTRACE); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, BACKTRACE_BUF, time); } @@ -153,7 +165,7 @@ static bool marshal_event_header(u64 time) local_irq_save(flags); if (buffer_check_space(cpu, BLOCK_COUNTER_BUF, MAXSIZE_PACK32 + MAXSIZE_PACK64)) { - gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); // key of zero indicates a timestamp + gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, 0); /* key of zero indicates a timestamp */ gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, time); retval = true; } @@ -169,18 +181,17 @@ static void marshal_event(int len, int *buffer) if (len <= 0) return; - // length must be even since all data is a (key, value) pair + /* length must be even since all data is a (key, value) pair */ if (len & 0x1) { - pr_err("gator: invalid counter data detected and discarded"); + pr_err("gator: invalid counter data detected and discarded\n"); return; } - // events must be written in key,value pairs + /* events must be written in key,value pairs */ local_irq_save(flags); for (i = 0; i < len; i += 2) { - if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32)) { + if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK32)) break; - } gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i]); gator_buffer_write_packed_int(cpu, BLOCK_COUNTER_BUF, buffer[i + 1]); } @@ -194,26 +205,24 @@ static void marshal_event64(int len, long long *buffer64) if (len <= 0) return; - // length must be even since all data is a (key, value) pair + /* length must be even since all data is a (key, value) pair */ if (len & 0x1) { - pr_err("gator: invalid counter data detected and discarded"); + pr_err("gator: invalid counter data detected and discarded\n"); return; } - // events must be written in key,value pairs + /* events must be written in key,value pairs */ local_irq_save(flags); for (i = 0; i < len; i += 2) { - if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64)) { + if (!buffer_check_space(cpu, BLOCK_COUNTER_BUF, 2 * MAXSIZE_PACK64)) break; - } gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i]); gator_buffer_write_packed_int64(cpu, BLOCK_COUNTER_BUF, buffer64[i + 1]); } local_irq_restore(flags); } -#if GATOR_CPU_FREQ_SUPPORT -static void marshal_event_single(int core, int key, int value) +static void __maybe_unused marshal_event_single(int core, int key, int value) { unsigned long flags, cpu; u64 time; @@ -228,78 +237,30 @@ static void marshal_event_single(int core, int key, int value) gator_buffer_write_packed_int(cpu, COUNTER_BUF, value); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, COUNTER_BUF, time); } -#endif - -static void marshal_sched_gpu_start(int unit, int core, int tgid, int pid) -{ - unsigned long cpu = get_physical_cpu(), flags; - u64 time; - - if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) - return; - - local_irq_save(flags); - time = gator_get_time(); - if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_START); - gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, tgid); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, pid); - } - local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full - buffer_check(cpu, GPU_TRACE_BUF, time); -} - -static void marshal_sched_gpu_stop(int unit, int core) -{ - unsigned long cpu = get_physical_cpu(), flags; - u64 time; - - if (!per_cpu(gator_buffer, cpu)[GPU_TRACE_BUF]) - return; - - local_irq_save(flags); - time = gator_get_time(); - if (buffer_check_space(cpu, GPU_TRACE_BUF, MAXSIZE_PACK64 + 3 * MAXSIZE_PACK32)) { - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, MESSAGE_GPU_STOP); - gator_buffer_write_packed_int64(cpu, GPU_TRACE_BUF, time); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, unit); - gator_buffer_write_packed_int(cpu, GPU_TRACE_BUF, core); - } - local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full - buffer_check(cpu, GPU_TRACE_BUF, time); -} -static void marshal_sched_trace_start(int tgid, int pid, int cookie) +static void __maybe_unused marshal_event_single64(int core, int key, long long value) { - unsigned long cpu = get_physical_cpu(), flags; + unsigned long flags, cpu; u64 time; - if (!per_cpu(gator_buffer, cpu)[SCHED_TRACE_BUF]) - return; - local_irq_save(flags); + cpu = get_physical_cpu(); time = gator_get_time(); - if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_START); - gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid); - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); + if (buffer_check_space(cpu, COUNTER_BUF, 2 * MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) { + gator_buffer_write_packed_int64(cpu, COUNTER_BUF, time); + gator_buffer_write_packed_int(cpu, COUNTER_BUF, core); + gator_buffer_write_packed_int(cpu, COUNTER_BUF, key); + gator_buffer_write_packed_int64(cpu, COUNTER_BUF, value); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full - buffer_check(cpu, SCHED_TRACE_BUF, time); + /* Check and commit; commit is set to occur once buffer is 3/4 full */ + buffer_check(cpu, COUNTER_BUF, time); } -static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state) +static void marshal_sched_trace_switch(int pid, int state) { unsigned long cpu = get_physical_cpu(), flags; u64 time; @@ -312,13 +273,11 @@ static void marshal_sched_trace_switch(int tgid, int pid, int cookie, int state) if (buffer_check_space(cpu, SCHED_TRACE_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, MESSAGE_SCHED_SWITCH); gator_buffer_write_packed_int64(cpu, SCHED_TRACE_BUF, time); - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, tgid); gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); - gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, cookie); gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, state); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, SCHED_TRACE_BUF, time); } @@ -338,7 +297,7 @@ static void marshal_sched_trace_exit(int tgid, int pid) gator_buffer_write_packed_int(cpu, SCHED_TRACE_BUF, pid); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, SCHED_TRACE_BUF, time); } @@ -357,7 +316,7 @@ static void marshal_idle(int core, int state) gator_buffer_write_packed_int(cpu, IDLE_BUF, core); } local_irq_restore(flags); - // Check and commit; commit is set to occur once buffer is 3/4 full + /* Check and commit; commit is set to occur once buffer is 3/4 full */ buffer_check(cpu, IDLE_BUF, time); } #endif @@ -367,6 +326,7 @@ static void marshal_core_name(const int core, const int cpuid, const char *name) { int cpu = get_physical_cpu(); unsigned long flags; + local_irq_save(flags); if (buffer_check_space(cpu, SUMMARY_BUF, MAXSIZE_PACK32 + MAXSIZE_CORE_NAME)) { gator_buffer_write_packed_int(cpu, SUMMARY_BUF, MESSAGE_CORE_NAME); @@ -374,8 +334,38 @@ static void marshal_core_name(const int core, const int cpuid, const char *name) gator_buffer_write_packed_int(cpu, SUMMARY_BUF, cpuid); gator_buffer_write_string(cpu, SUMMARY_BUF, name); } - // Commit core names now so that they can show up in live + /* Commit core names now so that they can show up in live */ local_irq_restore(flags); gator_commit_buffer(cpu, SUMMARY_BUF, gator_get_time()); } #endif + +static void marshal_activity_switch(int core, int key, int activity, int pid, int state) +{ + unsigned long cpu = get_physical_cpu(), flags; + u64 time; + + if (!per_cpu(gator_buffer, cpu)[ACTIVITY_BUF]) + return; + + local_irq_save(flags); + time = gator_get_time(); + if (buffer_check_space(cpu, ACTIVITY_BUF, MAXSIZE_PACK64 + 5 * MAXSIZE_PACK32)) { + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, MESSAGE_SWITCH); + gator_buffer_write_packed_int64(cpu, ACTIVITY_BUF, time); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, core); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, key); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, activity); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, pid); + gator_buffer_write_packed_int(cpu, ACTIVITY_BUF, state); + } + local_irq_restore(flags); + /* Check and commit; commit is set to occur once buffer is 3/4 full */ + buffer_check(cpu, ACTIVITY_BUF, time); +} + +void gator_marshal_activity_switch(int core, int key, int activity, int pid) +{ + /* state is reserved for cpu use only */ + marshal_activity_switch(core, key, activity, pid, 0); +} diff --git a/drivers/gator/gator_trace_gpu.c b/drivers/gator/gator_trace_gpu.c index 6332098e5958..5de9152e365a 100644 --- a/drivers/gator/gator_trace_gpu.c +++ b/drivers/gator/gator_trace_gpu.c @@ -23,8 +23,6 @@ #endif #endif -#include "gator_trace_gpu.h" - /* * Taken from MALI_PROFILING_EVENT_TYPE_* items in Mali DDK. */ @@ -37,7 +35,6 @@ /* Note whether tracepoints have been registered */ static int mali_timeline_trace_registered; static int mali_job_slots_trace_registered; -static int gpu_trace_registered; enum { GPU_UNIT_NONE = 0, @@ -47,74 +44,117 @@ enum { NUMBER_OF_GPU_UNITS }; -#define MALI_4xx (0x0b07) -#define MALI_T6xx (0x0056) +#if defined(MALI_SUPPORT) -struct mali_gpu_job { +struct mali_activity { + int core; + int key; int count; - int last_tgid; + int last_activity; int last_pid; - int last_job_id; }; #define NUMBER_OF_GPU_CORES 16 -static struct mali_gpu_job mali_gpu_jobs[NUMBER_OF_GPU_UNITS][NUMBER_OF_GPU_CORES]; -static DEFINE_SPINLOCK(mali_gpu_jobs_lock); - -/* Only one event should be running on a unit and core at a time (ie, a start - * event can only be followed by a stop and vice versa), but because the kernel - * only knows when a job is enqueued and not started, it is possible for a - * start1, start2, stop1, stop2. Change it back into start1, stop1, start2, - * stop2 by queueing up start2 and releasing it when stop1 is received. +static struct mali_activity mali_activities[NUMBER_OF_GPU_UNITS*NUMBER_OF_GPU_CORES]; +static DEFINE_SPINLOCK(mali_activities_lock); + +/* Only one event should be running on a unit and core at a time (ie, + * a start event can only be followed by a stop and vice versa), but + * because the kernel only knows when a job is enqueued and not + * started, it is possible for a start1, start2, stop1, stop2. Change + * it back into start1, stop1, start2, stop2 by queueing up start2 and + * releasing it when stop1 is received. */ -static void mali_gpu_enqueue(int unit, int core, int tgid, int pid, int job_id) + +static int mali_activity_index(int core, int key) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mali_activities); ++i) { + if ((mali_activities[i].core == core) && (mali_activities[i].key == key)) + break; + if ((mali_activities[i].core == 0) && (mali_activities[i].key == 0)) { + mali_activities[i].core = core; + mali_activities[i].key = key; + break; + } + } + BUG_ON(i >= ARRAY_SIZE(mali_activities)); + + return i; +} + +static void mali_activity_enqueue(int core, int key, int activity, int pid) { + int i; int count; - spin_lock(&mali_gpu_jobs_lock); - count = mali_gpu_jobs[unit][core].count; + spin_lock(&mali_activities_lock); + i = mali_activity_index(core, key); + + count = mali_activities[i].count; BUG_ON(count < 0); - ++mali_gpu_jobs[unit][core].count; + ++mali_activities[i].count; if (count) { - mali_gpu_jobs[unit][core].last_tgid = tgid; - mali_gpu_jobs[unit][core].last_pid = pid; - mali_gpu_jobs[unit][core].last_job_id = job_id; + mali_activities[i].last_activity = activity; + mali_activities[i].last_pid = pid; } - spin_unlock(&mali_gpu_jobs_lock); + spin_unlock(&mali_activities_lock); - if (!count) { - marshal_sched_gpu_start(unit, core, tgid, pid/*, job_id*/); - } + if (!count) + gator_marshal_activity_switch(core, key, activity, pid); } -static void mali_gpu_stop(int unit, int core) +static void mali_activity_stop(int core, int key) { + int i; int count; - int last_tgid = 0; + int last_activity = 0; int last_pid = 0; - //int last_job_id = 0; - spin_lock(&mali_gpu_jobs_lock); - if (mali_gpu_jobs[unit][core].count == 0) { - spin_unlock(&mali_gpu_jobs_lock); + spin_lock(&mali_activities_lock); + i = mali_activity_index(core, key); + + if (mali_activities[i].count == 0) { + spin_unlock(&mali_activities_lock); return; } - --mali_gpu_jobs[unit][core].count; - count = mali_gpu_jobs[unit][core].count; + --mali_activities[i].count; + count = mali_activities[i].count; if (count) { - last_tgid = mali_gpu_jobs[unit][core].last_tgid; - last_pid = mali_gpu_jobs[unit][core].last_pid; - //last_job_id = mali_gpu_jobs[unit][core].last_job_id; + last_activity = mali_activities[i].last_activity; + last_pid = mali_activities[i].last_pid; } - spin_unlock(&mali_gpu_jobs_lock); + spin_unlock(&mali_activities_lock); - marshal_sched_gpu_stop(unit, core); - if (count) { - marshal_sched_gpu_start(unit, core, last_tgid, last_pid/*, last_job_id*/); + gator_marshal_activity_switch(core, key, 0, 0); + if (count) + gator_marshal_activity_switch(core, key, last_activity, last_pid); +} + +void mali_activity_clear(struct mali_counter mali_activity[], size_t mali_activity_size) +{ + int activity; + int cores; + int core; + + for (activity = 0; activity < mali_activity_size; ++activity) { + cores = mali_activity[activity].cores; + if (cores < 0) + cores = 1; + for (core = 0; core < cores; ++core) { + if (mali_activity[activity].enabled) { + preempt_disable(); + gator_marshal_activity_switch(core, mali_activity[activity].key, 0, 0); + preempt_enable(); + } + } } } -#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) +#endif + +#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_MIDGARD) #include "gator_events_mali_4xx.h" /* @@ -142,30 +182,36 @@ enum { EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1, }; +struct mali_counter mali_activity[2]; + GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned int d2, unsigned int d3, unsigned int d4)) { unsigned int component, state; - // do as much work as possible before disabling interrupts - component = (event_id >> 16) & 0xFF; // component is an 8-bit field - state = (event_id >> 24) & 0xF; // state is a 4-bit field + /* do as much work as possible before disabling interrupts */ + component = (event_id >> 16) & 0xFF; /* component is an 8-bit field */ + state = (event_id >> 24) & 0xF; /* state is a 4-bit field */ switch (state) { case EVENT_TYPE_START: if (component == EVENT_CHANNEL_VP0) { /* tgid = d0; pid = d1; */ - mali_gpu_enqueue(GPU_UNIT_VP, 0, d0, d1, 0); + if (mali_activity[1].enabled) + mali_activity_enqueue(0, mali_activity[1].key, 1, d1); } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { /* tgid = d0; pid = d1; */ - mali_gpu_enqueue(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0, d0, d1, 0); + if (mali_activity[0].enabled) + mali_activity_enqueue(component - EVENT_CHANNEL_FP0, mali_activity[0].key, 1, d1); } break; case EVENT_TYPE_STOP: if (component == EVENT_CHANNEL_VP0) { - mali_gpu_stop(GPU_UNIT_VP, 0); + if (mali_activity[1].enabled) + mali_activity_stop(0, mali_activity[1].key); } else if (component >= EVENT_CHANNEL_FP0 && component <= EVENT_CHANNEL_FP7) { - mali_gpu_stop(GPU_UNIT_FP, component - EVENT_CHANNEL_FP0); + if (mali_activity[0].enabled) + mali_activity_stop(component - EVENT_CHANNEL_FP0, mali_activity[0].key); } break; @@ -173,9 +219,8 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned if (component == EVENT_CHANNEL_GPU) { unsigned int reason = (event_id & 0xffff); - if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) { + if (reason == EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE) gator_events_mali_log_dvfs_event(d0, d1); - } } break; @@ -185,7 +230,10 @@ GATOR_DEFINE_PROBE(mali_timeline_event, TP_PROTO(unsigned int event_id, unsigned } #endif -#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) +#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD) + +struct mali_counter mali_activity[3]; + #if defined(MALI_JOB_SLOTS_EVENT_CHANGED) GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigned int tgid, unsigned int pid, unsigned char job_id)) #else @@ -197,8 +245,8 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne unsigned char job_id = 0; #endif - component = (event_id >> 16) & 0xFF; // component is an 8-bit field - state = (event_id >> 24) & 0xF; // state is a 4-bit field + component = (event_id >> 16) & 0xFF; /* component is an 8-bit field */ + state = (event_id >> 24) & 0xF; /* state is a 4-bit field */ switch (component) { case 0: @@ -217,31 +265,19 @@ GATOR_DEFINE_PROBE(mali_job_slots_event, TP_PROTO(unsigned int event_id, unsigne if (unit != GPU_UNIT_NONE) { switch (state) { case EVENT_TYPE_START: - mali_gpu_enqueue(unit, 0, tgid, (pid != 0 ? pid : tgid), job_id); + if (mali_activity[component].enabled) + mali_activity_enqueue(0, mali_activity[component].key, 1, (pid != 0 ? pid : tgid)); break; case EVENT_TYPE_STOP: - mali_gpu_stop(unit, 0); + default: /* Some jobs can be soft-stopped, so ensure that this terminates the activity trace. */ + if (mali_activity[component].enabled) + mali_activity_stop(0, mali_activity[component].key); break; - default: - /* - * Some jobs can be soft-stopped, so ensure that this terminates the activity trace. - */ - mali_gpu_stop(unit, 0); } } } #endif -GATOR_DEFINE_PROBE(gpu_activity_start, TP_PROTO(int gpu_unit, int gpu_core, struct task_struct *p)) -{ - mali_gpu_enqueue(gpu_unit, gpu_core, (int)p->tgid, (int)p->pid, 0); -} - -GATOR_DEFINE_PROBE(gpu_activity_stop, TP_PROTO(int gpu_unit, int gpu_core)) -{ - mali_gpu_stop(gpu_unit, gpu_core); -} - static int gator_trace_gpu_start(void) { /* @@ -249,53 +285,37 @@ static int gator_trace_gpu_start(void) * Absence of gpu trace points is not an error */ - memset(&mali_gpu_jobs, 0, sizeof(mali_gpu_jobs)); - gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; +#if defined(MALI_SUPPORT) + memset(&mali_activities, 0, sizeof(mali_activities)); +#endif + mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; -#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) - if (!GATOR_REGISTER_TRACE(mali_timeline_event)) { +#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_MIDGARD) + mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity)); + if (!GATOR_REGISTER_TRACE(mali_timeline_event)) mali_timeline_trace_registered = 1; - } #endif -#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) - if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) { +#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD) + mali_activity_clear(mali_activity, ARRAY_SIZE(mali_activity)); + if (!GATOR_REGISTER_TRACE(mali_job_slots_event)) mali_job_slots_trace_registered = 1; - } #endif - if (!mali_timeline_trace_registered) { - if (GATOR_REGISTER_TRACE(gpu_activity_start)) { - return 0; - } - if (GATOR_REGISTER_TRACE(gpu_activity_stop)) { - GATOR_UNREGISTER_TRACE(gpu_activity_start); - return 0; - } - gpu_trace_registered = 1; - } - return 0; } static void gator_trace_gpu_stop(void) { -#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_T6xx) - if (mali_timeline_trace_registered) { +#if defined(MALI_SUPPORT) && (MALI_SUPPORT != MALI_MIDGARD) + if (mali_timeline_trace_registered) GATOR_UNREGISTER_TRACE(mali_timeline_event); - } #endif -#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_T6xx) - if (mali_job_slots_trace_registered) { +#if defined(MALI_SUPPORT) && (MALI_SUPPORT == MALI_MIDGARD) + if (mali_job_slots_trace_registered) GATOR_UNREGISTER_TRACE(mali_job_slots_event); - } #endif - if (gpu_trace_registered) { - GATOR_UNREGISTER_TRACE(gpu_activity_stop); - GATOR_UNREGISTER_TRACE(gpu_activity_start); - } - - gpu_trace_registered = mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; + mali_timeline_trace_registered = mali_job_slots_trace_registered = 0; } diff --git a/drivers/gator/gator_trace_power.c b/drivers/gator/gator_trace_power.c index 1895bb988c9f..46e04b29a187 100644 --- a/drivers/gator/gator_trace_power.c +++ b/drivers/gator/gator_trace_power.c @@ -22,18 +22,20 @@ #endif -// cpu_frequency and cpu_idle trace points were introduced in Linux kernel v2.6.38 -// the now deprecated power_frequency trace point was available prior to 2.6.38, but only for x86 +/* cpu_frequency and cpu_idle trace points were introduced in Linux + * kernel v2.6.38 the now deprecated power_frequency trace point was + * available prior to 2.6.38, but only for x86 + */ #if GATOR_CPU_FREQ_SUPPORT enum { POWER_CPU_FREQ, - POWER_CPU_IDLE, POWER_TOTAL }; static DEFINE_PER_CPU(ulong, idle_prev_state); static ulong power_cpu_enabled[POWER_TOTAL]; static ulong power_cpu_key[POWER_TOTAL]; +static ulong power_cpu_cores; static int gator_trace_power_create_files(struct super_block *sb, struct dentry *root) { @@ -41,8 +43,9 @@ static int gator_trace_power_create_files(struct super_block *sb, struct dentry int cpu; bool found_nonzero_freq = false; - // Even if CONFIG_CPU_FREQ is defined, it still may not be used. Check - // for non-zero values from cpufreq_quick_get + /* Even if CONFIG_CPU_FREQ is defined, it still may not be + * used. Check for non-zero values from cpufreq_quick_get + */ for_each_online_cpu(cpu) { if (cpufreq_quick_get(cpu) > 0) { found_nonzero_freq = true; @@ -51,87 +54,72 @@ static int gator_trace_power_create_files(struct super_block *sb, struct dentry } if (found_nonzero_freq) { - // cpu_frequency + /* cpu_frequency */ dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_freq"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_FREQ]); gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_FREQ]); } - // cpu_idle - dir = gatorfs_mkdir(sb, root, "Linux_power_cpu_idle"); - if (!dir) { - return -1; - } - gatorfs_create_ulong(sb, dir, "enabled", &power_cpu_enabled[POWER_CPU_IDLE]); - gatorfs_create_ro_ulong(sb, dir, "key", &power_cpu_key[POWER_CPU_IDLE]); - return 0; } -// 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change +/* 'cpu' may not equal smp_processor_id(), i.e. may not be running on the core that is having the freq/idle state change */ GATOR_DEFINE_PROBE(cpu_frequency, TP_PROTO(unsigned int frequency, unsigned int cpu)) { cpu = lcpu_to_pcpu(cpu); - marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000); + marshal_event_single64(cpu, power_cpu_key[POWER_CPU_FREQ], frequency * 1000L); } GATOR_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu)) { cpu = lcpu_to_pcpu(cpu); - if (state == per_cpu(idle_prev_state, cpu)) { + if (state == per_cpu(idle_prev_state, cpu)) return; - } if (implements_wfi()) { if (state == PWR_EVENT_EXIT) { - // transition from wfi to non-wfi + /* transition from wfi to non-wfi */ marshal_idle(cpu, MESSAGE_IDLE_EXIT); } else { - // transition from non-wfi to wfi + /* transition from non-wfi to wfi */ marshal_idle(cpu, MESSAGE_IDLE_ENTER); } } per_cpu(idle_prev_state, cpu) = state; - - if (power_cpu_enabled[POWER_CPU_IDLE]) { - // Increment state so that no negative numbers are sent - marshal_event_single(cpu, power_cpu_key[POWER_CPU_IDLE], state + 1); - } } static void gator_trace_power_online(void) { int pcpu = get_physical_cpu(); int lcpu = get_logical_cpu(); - if (power_cpu_enabled[POWER_CPU_FREQ]) { - marshal_event_single(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000); - } + + if (power_cpu_enabled[POWER_CPU_FREQ]) + marshal_event_single64(pcpu, power_cpu_key[POWER_CPU_FREQ], cpufreq_quick_get(lcpu) * 1000L); } static void gator_trace_power_offline(void) { - // Set frequency to zero on an offline + /* Set frequency to zero on an offline */ int cpu = get_physical_cpu(); - if (power_cpu_enabled[POWER_CPU_FREQ]) { + + if (power_cpu_enabled[POWER_CPU_FREQ]) marshal_event_single(cpu, power_cpu_key[POWER_CPU_FREQ], 0); - } } static int gator_trace_power_start(void) { int cpu; - // register tracepoints + /* register tracepoints */ if (power_cpu_enabled[POWER_CPU_FREQ]) if (GATOR_REGISTER_TRACE(cpu_frequency)) goto fail_cpu_frequency_exit; - // Always register for cpu:idle for detecting WFI, independent of power_cpu_enabled[POWER_CPU_IDLE] + /* Always register for cpu_idle for detecting WFI */ if (GATOR_REGISTER_TRACE(cpu_idle)) goto fail_cpu_idle_exit; pr_debug("gator: registered power event tracepoints\n"); @@ -142,7 +130,7 @@ static int gator_trace_power_start(void) return 0; - // unregister tracepoints on error + /* unregister tracepoints on error */ fail_cpu_idle_exit: if (power_cpu_enabled[POWER_CPU_FREQ]) GATOR_UNREGISTER_TRACE(cpu_frequency); @@ -161,14 +149,15 @@ static void gator_trace_power_stop(void) GATOR_UNREGISTER_TRACE(cpu_idle); pr_debug("gator: unregistered power event tracepoints\n"); - for (i = 0; i < POWER_TOTAL; i++) { + for (i = 0; i < POWER_TOTAL; i++) power_cpu_enabled[i] = 0; - } } static void gator_trace_power_init(void) { int i; + + power_cpu_cores = nr_cpu_ids; for (i = 0; i < POWER_TOTAL; i++) { power_cpu_enabled[i] = 0; power_cpu_key[i] = gator_events_get_key(); diff --git a/drivers/gator/gator_trace_sched.c b/drivers/gator/gator_trace_sched.c index 52990e9d4811..6d7cbd7348e1 100644 --- a/drivers/gator/gator_trace_sched.c +++ b/drivers/gator/gator_trace_sched.c @@ -8,6 +8,10 @@ */ #include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +#include +#endif + #include "gator.h" #define TASK_MAP_ENTRIES 1024 /* must be power of 2 */ @@ -23,8 +27,10 @@ enum { static DEFINE_PER_CPU(uint64_t *, taskname_keys); static DEFINE_PER_CPU(int, collecting); -// this array is never read as the cpu wait charts are derived counters -// the files are needed, nonetheless, to show that these counters are available +/* this array is never read as the cpu wait charts are derived + * counters the files are needed, nonetheless, to show that these + * counters are available + */ static ulong cpu_wait_enabled[CPU_WAIT_TOTAL]; static ulong sched_cpu_key[CPU_WAIT_TOTAL]; @@ -32,26 +38,24 @@ static int sched_trace_create_files(struct super_block *sb, struct dentry *root) { struct dentry *dir; - // CPU Wait - Contention + /* CPU Wait - Contention */ dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_contention"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_CONTENTION]); gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_CONTENTION]); - // CPU Wait - I/O + /* CPU Wait - I/O */ dir = gatorfs_mkdir(sb, root, "Linux_cpu_wait_io"); - if (!dir) { + if (!dir) return -1; - } gatorfs_create_ulong(sb, dir, "enabled", &cpu_wait_enabled[STATE_WAIT_ON_IO]); gatorfs_create_ro_ulong(sb, dir, "key", &sched_cpu_key[STATE_WAIT_ON_IO]); return 0; } -static void emit_pid_name(struct task_struct *task) +static void emit_pid_name(const char *comm, struct task_struct *task) { bool found = false; char taskcomm[TASK_COMM_LEN + 3]; @@ -59,10 +63,10 @@ static void emit_pid_name(struct task_struct *task) uint64_t *keys = &(per_cpu(taskname_keys, cpu)[(task->pid & 0xFF) * TASK_MAX_COLLISIONS]); uint64_t value; - value = gator_chksum_crc32(task->comm); + value = gator_chksum_crc32(comm); value = (value << 32) | (uint32_t)task->pid; - // determine if the thread name was emitted already + /* determine if the thread name was emitted already */ for (x = 0; x < TASK_MAX_COLLISIONS; x++) { if (keys[x] == value) { found = true; @@ -71,17 +75,18 @@ static void emit_pid_name(struct task_struct *task) } if (!found) { - // shift values, new value always in front + /* shift values, new value always in front */ uint64_t oldv, newv = value; + for (x = 0; x < TASK_MAX_COLLISIONS; x++) { oldv = keys[x]; keys[x] = newv; newv = oldv; } - // emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions - if (strlcpy(taskcomm, task->comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) { - // append ellipses if task->comm has length of TASK_COMM_LEN - 1 + /* emit pid names, cannot use get_task_comm, as it's not exported on all kernel versions */ + if (strlcpy(taskcomm, comm, TASK_COMM_LEN) == TASK_COMM_LEN - 1) { + /* append ellipses if comm has length of TASK_COMM_LEN - 1 */ strcat(taskcomm, "..."); } @@ -89,7 +94,7 @@ static void emit_pid_name(struct task_struct *task) } } -static void collect_counters(u64 time, struct task_struct *task) +static void collect_counters(u64 time, struct task_struct *task, bool sched_switch) { int *buffer, len, cpu = get_physical_cpu(); long long *buffer64; @@ -98,7 +103,7 @@ static void collect_counters(u64 time, struct task_struct *task) if (marshal_event_header(time)) { list_for_each_entry(gi, &gator_events, list) { if (gi->read) { - len = gi->read(&buffer); + len = gi->read(&buffer, sched_switch); marshal_event(len, buffer); } else if (gi->read64) { len = gi->read64(&buffer64); @@ -109,22 +114,26 @@ static void collect_counters(u64 time, struct task_struct *task) marshal_event64(len, buffer64); } } - // Only check after writing all counters so that time and corresponding counters appear in the same frame + if (cpu == 0) + gator_emit_perf_time(time); + /* Only check after writing all counters so that time and corresponding counters appear in the same frame */ buffer_check(cpu, BLOCK_COUNTER_BUF, time); - // Commit buffers on timeout + /* Commit buffers on timeout */ if (gator_live_rate > 0 && time >= per_cpu(gator_buffer_commit_time, cpu)) { - static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF }; + static const int buftypes[] = { NAME_BUF, COUNTER_BUF, BLOCK_COUNTER_BUF, SCHED_TRACE_BUF, ACTIVITY_BUF }; int i; - for (i = 0; i < ARRAY_SIZE(buftypes); ++i) { + for (i = 0; i < ARRAY_SIZE(buftypes); ++i) gator_commit_buffer(cpu, buftypes[i], time); - } - // spinlocks are noops on uniprocessor machines and mutexes do not work in sched_switch context in - // RT-Preempt full, so disable proactive flushing of the annotate frame on uniprocessor machines. + /* spinlocks are noops on uniprocessor machines and mutexes do + * not work in sched_switch context in RT-Preempt full, so + * disable proactive flushing of the annotate frame on + * uniprocessor machines. + */ #ifdef CONFIG_SMP - // Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full + /* Try to preemptively flush the annotate buffer to reduce the chance of the buffer being full */ if (on_primary_core() && spin_trylock(&annotate_lock)) { gator_commit_buffer(0, ANNOTATE_BUF, time); spin_unlock(&annotate_lock); @@ -134,51 +143,71 @@ static void collect_counters(u64 time, struct task_struct *task) } } -// special case used during a suspend of the system +/* special case used during a suspend of the system */ static void trace_sched_insert_idle(void) { - marshal_sched_trace_switch(0, 0, 0, 0); + marshal_sched_trace_switch(0, 0); } -GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child)) +static void gator_trace_emit_link(struct task_struct *p) { int cookie; int cpu = get_physical_cpu(); - cookie = get_exec_cookie(cpu, child); - emit_pid_name(child); + cookie = get_exec_cookie(cpu, p); + emit_pid_name(p->comm, p); - marshal_sched_trace_start(child->tgid, child->pid, cookie); + marshal_link(cookie, p->tgid, p->pid); } +GATOR_DEFINE_PROBE(sched_process_fork, TP_PROTO(struct task_struct *parent, struct task_struct *child)) +{ + gator_trace_emit_link(child); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) +GATOR_DEFINE_PROBE(sched_process_exec, TP_PROTO(struct task_struct *p, pid_t old_pid, struct linux_binprm *bprm)) +{ + gator_trace_emit_link(p); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) +GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, char *comm)) +#else +GATOR_DEFINE_PROBE(task_rename, TP_PROTO(struct task_struct *task, const char *comm)) +#endif +{ + emit_pid_name(comm, task); +} +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct rq *rq, struct task_struct *prev, struct task_struct *next)) #else GATOR_DEFINE_PROBE(sched_switch, TP_PROTO(struct task_struct *prev, struct task_struct *next)) #endif { - int cookie; int state; int cpu = get_physical_cpu(); per_cpu(in_scheduler_context, cpu) = true; - // do as much work as possible before disabling interrupts - cookie = get_exec_cookie(cpu, next); - emit_pid_name(next); - if (prev->state == TASK_RUNNING) { + /* do as much work as possible before disabling interrupts */ + if (prev->state == TASK_RUNNING) state = STATE_CONTENTION; - } else if (prev->in_iowait) { + else if (prev->in_iowait) state = STATE_WAIT_ON_IO; - } else { + else state = STATE_WAIT_ON_OTHER; - } per_cpu(collecting, cpu) = 1; - collect_counters(gator_get_time(), prev); + collect_counters(gator_get_time(), prev, true); per_cpu(collecting, cpu) = 0; - marshal_sched_trace_switch(next->tgid, next->pid, cookie, state); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0) + gator_trace_emit_link(next); +#endif + marshal_sched_trace_switch(next->pid, state); per_cpu(in_scheduler_context, cpu) = false; } @@ -190,31 +219,44 @@ GATOR_DEFINE_PROBE(sched_process_free, TP_PROTO(struct task_struct *p)) static void do_nothing(void *info) { - // Intentionally do nothing + /* Intentionally do nothing */ (void)info; } static int register_scheduler_tracepoints(void) { - // register tracepoints + /* register tracepoints */ if (GATOR_REGISTER_TRACE(sched_process_fork)) goto fail_sched_process_fork; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) + if (GATOR_REGISTER_TRACE(sched_process_exec)) + goto fail_sched_process_exec; + if (GATOR_REGISTER_TRACE(task_rename)) + goto fail_task_rename; +#endif if (GATOR_REGISTER_TRACE(sched_switch)) goto fail_sched_switch; if (GATOR_REGISTER_TRACE(sched_process_free)) goto fail_sched_process_free; pr_debug("gator: registered tracepoints\n"); - // Now that the scheduler tracepoint is registered, force a context switch - // on all cpus to capture what is currently running. + /* Now that the scheduler tracepoint is registered, force a context + * switch on all cpus to capture what is currently running. + */ on_each_cpu(do_nothing, NULL, 0); return 0; - // unregister tracepoints on error + /* unregister tracepoints on error */ fail_sched_process_free: GATOR_UNREGISTER_TRACE(sched_switch); fail_sched_switch: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) + GATOR_UNREGISTER_TRACE(task_rename); +fail_task_rename: + GATOR_UNREGISTER_TRACE(sched_process_exec); +fail_sched_process_exec: +#endif GATOR_UNREGISTER_TRACE(sched_process_fork); fail_sched_process_fork: pr_err("gator: tracepoints failed to activate, please verify that tracepoints are enabled in the linux kernel\n"); @@ -222,29 +264,13 @@ static int register_scheduler_tracepoints(void) return -1; } -static int gator_trace_sched_start(void) -{ - int cpu, size; - - for_each_present_cpu(cpu) { - size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t); - per_cpu(taskname_keys, cpu) = (uint64_t *)kmalloc(size, GFP_KERNEL); - if (!per_cpu(taskname_keys, cpu)) - return -1; - memset(per_cpu(taskname_keys, cpu), 0, size); - } - - return register_scheduler_tracepoints(); -} - -static void gator_trace_sched_offline(void) -{ - trace_sched_insert_idle(); -} - static void unregister_scheduler_tracepoints(void) { GATOR_UNREGISTER_TRACE(sched_process_fork); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) + GATOR_UNREGISTER_TRACE(sched_process_exec); + GATOR_UNREGISTER_TRACE(task_rename); +#endif GATOR_UNREGISTER_TRACE(sched_switch); GATOR_UNREGISTER_TRACE(sched_process_free); pr_debug("gator: unregistered tracepoints\n"); @@ -253,6 +279,7 @@ static void unregister_scheduler_tracepoints(void) static void gator_trace_sched_stop(void) { int cpu; + unregister_scheduler_tracepoints(); for_each_present_cpu(cpu) { @@ -260,9 +287,33 @@ static void gator_trace_sched_stop(void) } } +static int gator_trace_sched_start(void) +{ + int cpu, size; + int ret; + + for_each_present_cpu(cpu) { + size = TASK_MAP_ENTRIES * TASK_MAX_COLLISIONS * sizeof(uint64_t); + per_cpu(taskname_keys, cpu) = kmalloc(size, GFP_KERNEL); + if (!per_cpu(taskname_keys, cpu)) + return -1; + memset(per_cpu(taskname_keys, cpu), 0, size); + } + + ret = register_scheduler_tracepoints(); + + return ret; +} + +static void gator_trace_sched_offline(void) +{ + trace_sched_insert_idle(); +} + static void gator_trace_sched_init(void) { int i; + for (i = 0; i < CPU_WAIT_TOTAL; i++) { cpu_wait_enabled[i] = 0; sched_cpu_key[i] = gator_events_get_key(); diff --git a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h index ff00d90cee78..2bc0b037eee6 100644 --- a/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h +++ b/drivers/gator/mali/mali_mjollnir_profiling_gator_api.h @@ -23,83 +23,82 @@ extern "C" #define MAX_NUM_VP_CORES (1) #define MAX_NUM_L2_CACHE_CORES (1) -enum counters -{ - /* Timeline activity */ - ACTIVITY_VP_0 = 0, - ACTIVITY_FP_0, - ACTIVITY_FP_1, - ACTIVITY_FP_2, - ACTIVITY_FP_3, - - /* L2 cache counters */ - COUNTER_L2_0_C0, - COUNTER_L2_0_C1, - - /* Vertex processor counters */ - COUNTER_VP_0_C0, - COUNTER_VP_0_C1, - - /* Fragment processor counters */ - COUNTER_FP_0_C0, - COUNTER_FP_0_C1, - COUNTER_FP_1_C0, - COUNTER_FP_1_C1, - COUNTER_FP_2_C0, - COUNTER_FP_2_C1, - COUNTER_FP_3_C0, - COUNTER_FP_3_C1, - - /* EGL Software Counters */ - COUNTER_EGL_BLIT_TIME, - - /* GLES Software Counters */ - COUNTER_GLES_DRAW_ELEMENTS_CALLS, - COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, - COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, - COUNTER_GLES_DRAW_ARRAYS_CALLS, - COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, - COUNTER_GLES_DRAW_POINTS, - COUNTER_GLES_DRAW_LINES, - COUNTER_GLES_DRAW_LINE_LOOP, - COUNTER_GLES_DRAW_LINE_STRIP, - COUNTER_GLES_DRAW_TRIANGLES, - COUNTER_GLES_DRAW_TRIANGLE_STRIP, - COUNTER_GLES_DRAW_TRIANGLE_FAN, - COUNTER_GLES_NON_VBO_DATA_COPY_TIME, - COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, - COUNTER_GLES_UPLOAD_TEXTURE_TIME, - COUNTER_GLES_UPLOAD_VBO_TIME, - COUNTER_GLES_NUM_FLUSHES, - COUNTER_GLES_NUM_VSHADERS_GENERATED, - COUNTER_GLES_NUM_FSHADERS_GENERATED, - COUNTER_GLES_VSHADER_GEN_TIME, - COUNTER_GLES_FSHADER_GEN_TIME, - COUNTER_GLES_INPUT_TRIANGLES, - COUNTER_GLES_VXCACHE_HIT, - COUNTER_GLES_VXCACHE_MISS, - COUNTER_GLES_VXCACHE_COLLISION, - COUNTER_GLES_CULLED_TRIANGLES, - COUNTER_GLES_CULLED_LINES, - COUNTER_GLES_BACKFACE_TRIANGLES, - COUNTER_GLES_GBCLIP_TRIANGLES, - COUNTER_GLES_GBCLIP_LINES, - COUNTER_GLES_TRIANGLES_DRAWN, - COUNTER_GLES_DRAWCALL_TIME, - COUNTER_GLES_TRIANGLES_COUNT, - COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, - COUNTER_GLES_STRIP_TRIANGLES_COUNT, - COUNTER_GLES_FAN_TRIANGLES_COUNT, - COUNTER_GLES_LINES_COUNT, - COUNTER_GLES_INDEPENDENT_LINES_COUNT, - COUNTER_GLES_STRIP_LINES_COUNT, - COUNTER_GLES_LOOP_LINES_COUNT, - - COUNTER_FILMSTRIP, - COUNTER_FREQUENCY, - COUNTER_VOLTAGE, - - NUMBER_OF_EVENTS +enum counters { + /* Timeline activity */ + ACTIVITY_VP_0 = 0, + ACTIVITY_FP_0, + ACTIVITY_FP_1, + ACTIVITY_FP_2, + ACTIVITY_FP_3, + + /* L2 cache counters */ + COUNTER_L2_0_C0, + COUNTER_L2_0_C1, + + /* Vertex processor counters */ + COUNTER_VP_0_C0, + COUNTER_VP_0_C1, + + /* Fragment processor counters */ + COUNTER_FP_0_C0, + COUNTER_FP_0_C1, + COUNTER_FP_1_C0, + COUNTER_FP_1_C1, + COUNTER_FP_2_C0, + COUNTER_FP_2_C1, + COUNTER_FP_3_C0, + COUNTER_FP_3_C1, + + /* EGL Software Counters */ + COUNTER_EGL_BLIT_TIME, + + /* GLES Software Counters */ + COUNTER_GLES_DRAW_ELEMENTS_CALLS, + COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, + COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_ARRAYS_CALLS, + COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_POINTS, + COUNTER_GLES_DRAW_LINES, + COUNTER_GLES_DRAW_LINE_LOOP, + COUNTER_GLES_DRAW_LINE_STRIP, + COUNTER_GLES_DRAW_TRIANGLES, + COUNTER_GLES_DRAW_TRIANGLE_STRIP, + COUNTER_GLES_DRAW_TRIANGLE_FAN, + COUNTER_GLES_NON_VBO_DATA_COPY_TIME, + COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, + COUNTER_GLES_UPLOAD_TEXTURE_TIME, + COUNTER_GLES_UPLOAD_VBO_TIME, + COUNTER_GLES_NUM_FLUSHES, + COUNTER_GLES_NUM_VSHADERS_GENERATED, + COUNTER_GLES_NUM_FSHADERS_GENERATED, + COUNTER_GLES_VSHADER_GEN_TIME, + COUNTER_GLES_FSHADER_GEN_TIME, + COUNTER_GLES_INPUT_TRIANGLES, + COUNTER_GLES_VXCACHE_HIT, + COUNTER_GLES_VXCACHE_MISS, + COUNTER_GLES_VXCACHE_COLLISION, + COUNTER_GLES_CULLED_TRIANGLES, + COUNTER_GLES_CULLED_LINES, + COUNTER_GLES_BACKFACE_TRIANGLES, + COUNTER_GLES_GBCLIP_TRIANGLES, + COUNTER_GLES_GBCLIP_LINES, + COUNTER_GLES_TRIANGLES_DRAWN, + COUNTER_GLES_DRAWCALL_TIME, + COUNTER_GLES_TRIANGLES_COUNT, + COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, + COUNTER_GLES_STRIP_TRIANGLES_COUNT, + COUNTER_GLES_FAN_TRIANGLES_COUNT, + COUNTER_GLES_LINES_COUNT, + COUNTER_GLES_INDEPENDENT_LINES_COUNT, + COUNTER_GLES_STRIP_LINES_COUNT, + COUNTER_GLES_LOOP_LINES_COUNT, + + COUNTER_FILMSTRIP, + COUNTER_FREQUENCY, + COUNTER_VOLTAGE, + + NUMBER_OF_EVENTS }; #define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0 @@ -117,34 +116,31 @@ enum counters /** * Structure to pass performance counter data of a Mali core */ -typedef struct _mali_profiling_core_counters -{ - u32 source0; - u32 value0; - u32 source1; - u32 value1; -} _mali_profiling_core_counters; +struct _mali_profiling_core_counters { + u32 source0; + u32 value0; + u32 source1; + u32 value1; +}; /* * For compatibility with utgard. */ -typedef struct _mali_profiling_l2_counter_values -{ - struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; -} _mali_profiling_l2_counter_values; +struct _mali_profiling_l2_counter_values { + struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; +}; -typedef struct _mali_profiling_mali_version -{ - u32 mali_product_id; - u32 mali_version_major; - u32 mali_version_minor; - u32 num_of_l2_cores; - u32 num_of_fp_cores; - u32 num_of_vp_cores; -} _mali_profiling_mali_version; +struct _mali_profiling_mali_version { + u32 mali_product_id; + u32 mali_version_major; + u32 mali_version_minor; + u32 num_of_l2_cores; + u32 num_of_fp_cores; + u32 num_of_vp_cores; +}; extern void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values); -extern u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values); +extern u32 _mali_profiling_get_l2_counters(struct _mali_profiling_l2_counter_values *values); /* * List of possible actions allowing DDK to be controlled by Streamline. diff --git a/drivers/gator/mali/mali_utgard_profiling_gator_api.h b/drivers/gator/mali/mali_utgard_profiling_gator_api.h index 43c576042880..d6465312628e 100644 --- a/drivers/gator/mali/mali_utgard_profiling_gator_api.h +++ b/drivers/gator/mali/mali_utgard_profiling_gator_api.h @@ -22,105 +22,104 @@ extern "C" #define MAX_NUM_VP_CORES 1 /** The list of events supported by the Mali DDK. */ -typedef enum -{ - /* Vertex processor activity */ - ACTIVITY_VP_0 = 0, - - /* Fragment processor activity */ - ACTIVITY_FP_0, /* 1 */ - ACTIVITY_FP_1, - ACTIVITY_FP_2, - ACTIVITY_FP_3, - ACTIVITY_FP_4, - ACTIVITY_FP_5, - ACTIVITY_FP_6, - ACTIVITY_FP_7, - - /* L2 cache counters */ - COUNTER_L2_0_C0, - COUNTER_L2_0_C1, - COUNTER_L2_1_C0, - COUNTER_L2_1_C1, - COUNTER_L2_2_C0, - COUNTER_L2_2_C1, - - /* Vertex processor counters */ - COUNTER_VP_0_C0, /*15*/ - COUNTER_VP_0_C1, - - /* Fragment processor counters */ - COUNTER_FP_0_C0, - COUNTER_FP_0_C1, - COUNTER_FP_1_C0, - COUNTER_FP_1_C1, - COUNTER_FP_2_C0, - COUNTER_FP_2_C1, - COUNTER_FP_3_C0, - COUNTER_FP_3_C1, - COUNTER_FP_4_C0, - COUNTER_FP_4_C1, - COUNTER_FP_5_C0, - COUNTER_FP_5_C1, - COUNTER_FP_6_C0, - COUNTER_FP_6_C1, - COUNTER_FP_7_C0, - COUNTER_FP_7_C1, /* 32 */ - - /* - * If more hardware counters are added, the _mali_osk_hw_counter_table - * below should also be updated. - */ - - /* EGL software counters */ - COUNTER_EGL_BLIT_TIME, - - /* GLES software counters */ - COUNTER_GLES_DRAW_ELEMENTS_CALLS, - COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, - COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, - COUNTER_GLES_DRAW_ARRAYS_CALLS, - COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, - COUNTER_GLES_DRAW_POINTS, - COUNTER_GLES_DRAW_LINES, - COUNTER_GLES_DRAW_LINE_LOOP, - COUNTER_GLES_DRAW_LINE_STRIP, - COUNTER_GLES_DRAW_TRIANGLES, - COUNTER_GLES_DRAW_TRIANGLE_STRIP, - COUNTER_GLES_DRAW_TRIANGLE_FAN, - COUNTER_GLES_NON_VBO_DATA_COPY_TIME, - COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, - COUNTER_GLES_UPLOAD_TEXTURE_TIME, - COUNTER_GLES_UPLOAD_VBO_TIME, - COUNTER_GLES_NUM_FLUSHES, - COUNTER_GLES_NUM_VSHADERS_GENERATED, - COUNTER_GLES_NUM_FSHADERS_GENERATED, - COUNTER_GLES_VSHADER_GEN_TIME, - COUNTER_GLES_FSHADER_GEN_TIME, - COUNTER_GLES_INPUT_TRIANGLES, - COUNTER_GLES_VXCACHE_HIT, - COUNTER_GLES_VXCACHE_MISS, - COUNTER_GLES_VXCACHE_COLLISION, - COUNTER_GLES_CULLED_TRIANGLES, - COUNTER_GLES_CULLED_LINES, - COUNTER_GLES_BACKFACE_TRIANGLES, - COUNTER_GLES_GBCLIP_TRIANGLES, - COUNTER_GLES_GBCLIP_LINES, - COUNTER_GLES_TRIANGLES_DRAWN, - COUNTER_GLES_DRAWCALL_TIME, - COUNTER_GLES_TRIANGLES_COUNT, - COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, - COUNTER_GLES_STRIP_TRIANGLES_COUNT, - COUNTER_GLES_FAN_TRIANGLES_COUNT, - COUNTER_GLES_LINES_COUNT, - COUNTER_GLES_INDEPENDENT_LINES_COUNT, - COUNTER_GLES_STRIP_LINES_COUNT, - COUNTER_GLES_LOOP_LINES_COUNT, - - /* Framebuffer capture pseudo-counter */ - COUNTER_FILMSTRIP, - - NUMBER_OF_EVENTS +enum { + /* Vertex processor activity */ + ACTIVITY_VP_0 = 0, + + /* Fragment processor activity */ + ACTIVITY_FP_0, /* 1 */ + ACTIVITY_FP_1, + ACTIVITY_FP_2, + ACTIVITY_FP_3, + ACTIVITY_FP_4, + ACTIVITY_FP_5, + ACTIVITY_FP_6, + ACTIVITY_FP_7, + + /* L2 cache counters */ + COUNTER_L2_0_C0, + COUNTER_L2_0_C1, + COUNTER_L2_1_C0, + COUNTER_L2_1_C1, + COUNTER_L2_2_C0, + COUNTER_L2_2_C1, + + /* Vertex processor counters */ + COUNTER_VP_0_C0, /*15*/ + COUNTER_VP_0_C1, + + /* Fragment processor counters */ + COUNTER_FP_0_C0, + COUNTER_FP_0_C1, + COUNTER_FP_1_C0, + COUNTER_FP_1_C1, + COUNTER_FP_2_C0, + COUNTER_FP_2_C1, + COUNTER_FP_3_C0, + COUNTER_FP_3_C1, + COUNTER_FP_4_C0, + COUNTER_FP_4_C1, + COUNTER_FP_5_C0, + COUNTER_FP_5_C1, + COUNTER_FP_6_C0, + COUNTER_FP_6_C1, + COUNTER_FP_7_C0, + COUNTER_FP_7_C1, /* 32 */ + + /* + * If more hardware counters are added, the _mali_osk_hw_counter_table + * below should also be updated. + */ + + /* EGL software counters */ + COUNTER_EGL_BLIT_TIME, + + /* GLES software counters */ + COUNTER_GLES_DRAW_ELEMENTS_CALLS, + COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, + COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_ARRAYS_CALLS, + COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, + COUNTER_GLES_DRAW_POINTS, + COUNTER_GLES_DRAW_LINES, + COUNTER_GLES_DRAW_LINE_LOOP, + COUNTER_GLES_DRAW_LINE_STRIP, + COUNTER_GLES_DRAW_TRIANGLES, + COUNTER_GLES_DRAW_TRIANGLE_STRIP, + COUNTER_GLES_DRAW_TRIANGLE_FAN, + COUNTER_GLES_NON_VBO_DATA_COPY_TIME, + COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, + COUNTER_GLES_UPLOAD_TEXTURE_TIME, + COUNTER_GLES_UPLOAD_VBO_TIME, + COUNTER_GLES_NUM_FLUSHES, + COUNTER_GLES_NUM_VSHADERS_GENERATED, + COUNTER_GLES_NUM_FSHADERS_GENERATED, + COUNTER_GLES_VSHADER_GEN_TIME, + COUNTER_GLES_FSHADER_GEN_TIME, + COUNTER_GLES_INPUT_TRIANGLES, + COUNTER_GLES_VXCACHE_HIT, + COUNTER_GLES_VXCACHE_MISS, + COUNTER_GLES_VXCACHE_COLLISION, + COUNTER_GLES_CULLED_TRIANGLES, + COUNTER_GLES_CULLED_LINES, + COUNTER_GLES_BACKFACE_TRIANGLES, + COUNTER_GLES_GBCLIP_TRIANGLES, + COUNTER_GLES_GBCLIP_LINES, + COUNTER_GLES_TRIANGLES_DRAWN, + COUNTER_GLES_DRAWCALL_TIME, + COUNTER_GLES_TRIANGLES_COUNT, + COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, + COUNTER_GLES_STRIP_TRIANGLES_COUNT, + COUNTER_GLES_FAN_TRIANGLES_COUNT, + COUNTER_GLES_LINES_COUNT, + COUNTER_GLES_INDEPENDENT_LINES_COUNT, + COUNTER_GLES_STRIP_LINES_COUNT, + COUNTER_GLES_LOOP_LINES_COUNT, + + /* Framebuffer capture pseudo-counter */ + COUNTER_FILMSTRIP, + + NUMBER_OF_EVENTS } _mali_osk_counter_id; #define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0 @@ -138,21 +137,19 @@ typedef enum /** * Structure to pass performance counter data of a Mali core */ -typedef struct _mali_profiling_core_counters -{ +struct _mali_profiling_core_counters { u32 source0; u32 value0; u32 source1; u32 value1; -} _mali_profiling_core_counters; +}; /** * Structure to pass performance counter data of Mali L2 cache cores */ -typedef struct _mali_profiling_l2_counter_values -{ +struct _mali_profiling_l2_counter_values { struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; -} _mali_profiling_l2_counter_values; +}; /** * Structure to pass data defining Mali instance in use: @@ -164,15 +161,14 @@ typedef struct _mali_profiling_l2_counter_values * num_of_fp_cores - number of fragment processor cores * num_of_vp_cores - number of vertex processor cores */ -typedef struct _mali_profiling_mali_version -{ +struct _mali_profiling_mali_version { u32 mali_product_id; u32 mali_version_major; u32 mali_version_minor; u32 num_of_l2_cores; u32 num_of_fp_cores; u32 num_of_vp_cores; -} _mali_profiling_mali_version; +}; /* * List of possible actions to be controlled by Streamline. @@ -186,7 +182,7 @@ typedef struct _mali_profiling_mali_version void _mali_profiling_control(u32 action, u32 value); -u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values); +u32 _mali_profiling_get_l2_counters(struct _mali_profiling_l2_counter_values *values); int _mali_profiling_set_event(u32 counter_id, s32 event_id); diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 8c58cc082207..50cde7d46d9f 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -200,6 +200,16 @@ static int arizona_gpio_probe(struct platform_device *pdev) case CS47L24: arizona_gpio->gpio_chip.ngpio = 2; break; + case CS47L35: + arizona_gpio->gpio_chip.direction_input = + clearwater_gpio_direction_in; + arizona_gpio->gpio_chip.get = clearwater_gpio_get; + arizona_gpio->gpio_chip.direction_output = + clearwater_gpio_direction_out; + arizona_gpio->gpio_chip.set = clearwater_gpio_set; + + arizona_gpio->gpio_chip.ngpio = 16; + break; default: dev_err(&pdev->dev, "Unknown chip variant %d\n", arizona->type); diff --git a/drivers/gpu/arm/mali400/ump/arch b/drivers/gpu/arm/mali400/ump/arch index 09cfee961d1c..58ffbe7dd66b 120000 --- a/drivers/gpu/arm/mali400/ump/arch +++ b/drivers/gpu/arm/mali400/ump/arch @@ -1 +1 @@ -arch-release/ \ No newline at end of file +arch-release \ No newline at end of file diff --git a/drivers/gpu/arm/t7xx/r5p0/platform/gpu_exynos7420.c b/drivers/gpu/arm/t7xx/r5p0/platform/gpu_exynos7420.c index c1d7b0108c9d..e1adbc741825 100644 --- a/drivers/gpu/arm/t7xx/r5p0/platform/gpu_exynos7420.c +++ b/drivers/gpu/arm/t7xx/r5p0/platform/gpu_exynos7420.c @@ -115,6 +115,9 @@ static gpu_attribute gpu_config_attributes[] = { {GPU_PERF_GATHERING, 0}, #ifdef MALI_SEC_HWCNT {GPU_HWCNT_GATHERING, 1}, + {GPU_HWCNT_POLLING_TIME, 90}, + {GPU_HWCNT_UP_STEP, 3}, + {GPU_HWCNT_DOWN_STEP, 2}, {GPU_HWCNT_GPR, 1}, {GPU_HWCNT_DUMP_PERIOD, 50}, /* ms */ {GPU_HWCNT_CHOOSE_JM , 0}, @@ -128,7 +131,7 @@ static gpu_attribute gpu_config_attributes[] = { {GPU_PMQOS_INT_DISABLE, 1}, {GPU_PMQOS_MIF_MAX_CLOCK, 1456000}, {GPU_PMQOS_MIF_MAX_CLOCK_BASE, 700}, - {GPU_CL_DVFS_START_BASE, 700}, + {GPU_CL_DVFS_START_BASE, 266}, {GPU_DEBUG_LEVEL, DVFS_WARNING}, {GPU_TRACE_LEVEL, TRACE_ALL}, }; @@ -161,6 +164,8 @@ struct clk *fout_g3d_pll; struct clk *aclk_g3d; struct clk *mout_g3d; struct clk *sclk_hpm_g3d; +struct clk *aclk_lh_g3d0; +struct clk *aclk_lh_g3d1; #ifdef CONFIG_REGULATOR struct regulator *g3d_regulator; #endif /* CONFIG_REGULATOR */ @@ -344,6 +349,26 @@ static int gpu_set_clock(struct exynos_context *platform, int clk) return ret; } +static int gpu_enable_clock(struct exynos_context *platform) +{ + int ret = 0; + ret = clk_prepare_enable(aclk_lh_g3d0); + if (ret) + GPU_LOG(DVFS_ERROR, DUMMY, 0u, 0u, "%s: g3d aclk lh g3d0 enable fail.\n", __func__); + + ret = clk_prepare_enable(aclk_lh_g3d1); + if (ret) + GPU_LOG(DVFS_ERROR, DUMMY, 0u, 0u, "%s: g3d aclk lh g3d1 enable fail.\n", __func__); + + return 0; +} +static int gpu_disable_clock(struct exynos_context *platform) +{ + clk_disable_unprepare(aclk_lh_g3d0); + clk_disable_unprepare(aclk_lh_g3d1); + + return 0; +} static int gpu_get_clock(struct kbase_device *kbdev) { struct exynos_context *platform = (struct exynos_context *) kbdev->platform_context; @@ -382,8 +407,22 @@ static int gpu_get_clock(struct kbase_device *kbdev) return -1; } + aclk_lh_g3d0 = clk_get(kbdev->dev, "aclk_lh_g3d0"); + if (IS_ERR(aclk_lh_g3d0)) { + GPU_LOG(DVFS_ERROR, DUMMY, 0u, 0u, "%s: failed to clk_get [aclk_lh_g3d0]\n", __func__); + return -1; + } + + aclk_lh_g3d1 = clk_get(kbdev->dev, "aclk_lh_g3d1"); + if (IS_ERR(aclk_lh_g3d1)) { + GPU_LOG(DVFS_ERROR, DUMMY, 0u, 0u, "%s: failed to clk_get [aclk_lh_g3d1]\n", __func__); + return -1; + } + __raw_writel(0x1, EXYNOS7420_MUX_SEL_G3D); + gpu_enable_clock(platform); + return 0; } @@ -485,8 +524,8 @@ static struct gpu_control_ops ctr_ops = { .set_clock = gpu_set_clock, .set_clock_pre = NULL, .set_clock_post = NULL, - .enable_clock = NULL, - .disable_clock = NULL, + .enable_clock = gpu_enable_clock, + .disable_clock = gpu_disable_clock, }; struct gpu_control_ops *gpu_get_control_ops(void) diff --git a/drivers/gpu/arm/t7xx/r5p0/platform/gpu_hwcnt.c b/drivers/gpu/arm/t7xx/r5p0/platform/gpu_hwcnt.c index 71c8079bbb6c..92e84641e31f 100644 --- a/drivers/gpu/arm/t7xx/r5p0/platform/gpu_hwcnt.c +++ b/drivers/gpu/arm/t7xx/r5p0/platform/gpu_hwcnt.c @@ -24,6 +24,8 @@ mali_error exynos_gpu_hwcnt_update(struct kbase_device *kbdev) { mali_error err = MALI_ERROR_FUNCTION_FAILED; + struct exynos_context *platform = (struct exynos_context *) kbdev->platform_context; + static int polling_period = 0; KBASE_DEBUG_ASSERT(kbdev); @@ -37,8 +39,15 @@ mali_error exynos_gpu_hwcnt_update(struct kbase_device *kbdev) goto out; } + polling_period -= platform->polling_speed; + if (polling_period > 0) { + err = MALI_ERROR_NONE; + goto out; + } + #ifdef MALI_SEC_HWCNT_DUMP_DVFS_THREAD if (kbdev->hwcnt.is_powered && kbdev->hwcnt.kctx) { + polling_period = platform->hwcnt_polling_speed; err = hwcnt_dump(kbdev->hwcnt.kctx); if (err != MALI_ERROR_NONE) { GPU_LOG(DVFS_INFO, DUMMY, 0u, 0u, "hwcnt dump error in %s %d \n", __FUNCTION__, err); @@ -101,14 +110,14 @@ void hwcnt_utilization_equation(struct kbase_device *kbdev) platform->cur_clock >= platform->gpu_max_clock_limit) { kbdev->hwcnt.cnt_for_bt_start++; kbdev->hwcnt.cnt_for_bt_stop = 0; - if (kbdev->hwcnt.cnt_for_bt_start > 10) { + if (kbdev->hwcnt.cnt_for_bt_start > platform->hwcnt_up_step) { platform->hwcnt_bt_clk = TRUE; kbdev->hwcnt.cnt_for_bt_start = 0; } } else { kbdev->hwcnt.cnt_for_bt_stop++; kbdev->hwcnt.cnt_for_bt_start = 0; - if (kbdev->hwcnt.cnt_for_bt_stop > 5) { + if (kbdev->hwcnt.cnt_for_bt_stop > platform->hwcnt_down_step) { platform->hwcnt_bt_clk = FALSE; kbdev->hwcnt.cnt_for_bt_stop = 0; } @@ -226,14 +235,13 @@ void hwcnt_accumulate_resource(struct kbase_device *kbdev) addr = (unsigned int *)kbdev->hwcnt.kspace_addr; acc_addr = (unsigned int*)kbdev->hwcnt.acc_buffer; + __flush_dcache_area((void *)addr, HWC_ACC_BUFFER_SIZE); + /* following copy code will be optimized soon */ for (i=0; i < HWC_ACC_BUFFER_SIZE / 4; i++) { *(acc_addr + i) += *(addr + i); } - - /* wondering why following buffer clear code is required */ - memset(kbdev->hwcnt.kspace_addr, 0, HWC_ACC_BUFFER_SIZE); } mali_error hwcnt_dump(struct kbase_context *kctx) diff --git a/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.c b/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.c index b06ac51f603b..b17a0f5bfa90 100644 --- a/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.c +++ b/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.c @@ -243,6 +243,15 @@ static int gpu_validate_attrib_data(struct exynos_context *platform) data = gpu_get_attrib_data(attrib, GPU_HWCNT_GPR); platform->hwcnt_gpr_status = data == 0 ? 0 : data; + data = gpu_get_attrib_data(attrib, GPU_HWCNT_POLLING_TIME); + platform->hwcnt_polling_speed = data == 0 ? 0 : (u32) data; + + data = gpu_get_attrib_data(attrib, GPU_HWCNT_UP_STEP); + platform->hwcnt_up_step = data == 0 ? 0 : (u32) data; + + data = gpu_get_attrib_data(attrib, GPU_HWCNT_DOWN_STEP); + platform->hwcnt_down_step = data == 0 ? 0 : (u32) data; + data = gpu_get_attrib_data(attrib, GPU_HWCNT_DUMP_PERIOD); platform->hwcnt_dump_period = data == 0 ? 0 : (u32) data; diff --git a/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.h b/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.h index cd21fa71eda5..17612bcfe8d1 100644 --- a/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.h +++ b/drivers/gpu/arm/t7xx/r5p0/platform/mali_kbase_platform.h @@ -139,6 +139,9 @@ typedef enum { #ifdef MALI_SEC_HWCNT GPU_HWCNT_GATHERING, GPU_HWCNT_GPR, + GPU_HWCNT_POLLING_TIME, + GPU_HWCNT_UP_STEP, + GPU_HWCNT_DOWN_STEP, GPU_HWCNT_DUMP_PERIOD, GPU_HWCNT_CHOOSE_JM, GPU_HWCNT_CHOOSE_SHADER, @@ -280,6 +283,9 @@ struct exynos_context { #ifdef MALI_SEC_HWCNT bool hwcnt_gathering_status; bool hwcnt_gpr_status; + int hwcnt_polling_speed; + int hwcnt_up_step; + int hwcnt_down_step; int hwcnt_dump_period; int hwcnt_choose_jm; int hwcnt_choose_shader; diff --git a/drivers/gud/TlcTui/Makefile b/drivers/gud/TlcTui/Makefile index 794488247d73..8535f5e30fce 100644 --- a/drivers/gud/TlcTui/Makefile +++ b/drivers/gud/TlcTui/Makefile @@ -24,6 +24,7 @@ ccflags-y += -Idrivers/gud/gud-$(PLATFORM)/MobiCoreKernelApi/include ccflags-y += -Idrivers/video/exynos/decon_display ccflags-y += -Idrivers/gud/TlcTui/ ccflags-y += -Idrivers/gud/TlcTui/inc +ccflags-y += -Idrivers/gud/TlcTui/public ifdef MOBICORE_CFLAGS ccflags-y += $(MOBICORE_CFLAGS) diff --git a/drivers/gud/TlcTui/build_tag.h b/drivers/gud/TlcTui/build_tag.h new file mode 100644 index 000000000000..d73600b17ff5 --- /dev/null +++ b/drivers/gud/TlcTui/build_tag.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2013-2014 TRUSTONIC LIMITED + * All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define MOBICORE_COMPONENT_BUILD_TAG \ + "t-base-EXYNOS64-Android-302A-V010-500_500" diff --git a/drivers/gud/TlcTui/inc/dciTui.h b/drivers/gud/TlcTui/inc/dciTui.h index c01869214855..1abfd2c55085 100644 --- a/drivers/gud/TlcTui/inc/dciTui.h +++ b/drivers/gud/TlcTui/inc/dciTui.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 TRUSTONIC LIMITED + * Copyright (c) 2013-2014 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -15,18 +15,12 @@ #ifndef __DCITUI_H__ #define __DCITUI_H__ -typedef volatile uint32_t dciCommandId_t; -typedef volatile uint32_t dciResponseId_t; -typedef volatile uint32_t dciNotificationId_t; -typedef uint32_t dciReturnCode_t; - - /**< Responses have bit 31 set */ #define RSP_ID_MASK (1U << 31) -#define RSP_ID(cmdId) (((uint32_t)(cmdId)) | RSP_ID_MASK) -#define IS_CMD(cmdId) ((((uint32_t)(cmdId)) & RSP_ID_MASK) == 0) -#define IS_RSP(cmdId) ((((uint32_t)(cmdId)) & RSP_ID_MASK) == RSP_ID_MASK) -#define CMD_ID_FROM_RSP(rspId) (rspId & (~RSP_ID_MASK)) +#define RSP_ID(cmd_id) (((uint32_t)(cmd_id)) | RSP_ID_MASK) +#define IS_CMD(cmd_id) ((((uint32_t)(cmd_id)) & RSP_ID_MASK) == 0) +#define IS_RSP(cmd_id) ((((uint32_t)(cmd_id)) & RSP_ID_MASK) == RSP_ID_MASK) +#define CMD_ID_FROM_RSP(rsp_id) (rsp_id & (~RSP_ID_MASK)) /** * Return codes of driver commands. @@ -46,65 +40,69 @@ typedef uint32_t dciReturnCode_t; * Notification ID's for communication Trustlet Connector -> Driver. */ #define NOT_TUI_NONE 0 -#define NOT_TUI_CANCEL_EVENT 1 /* NWd system event that closes the current TUI session*/ +/* NWd system event that closes the current TUI session*/ +#define NOT_TUI_CANCEL_EVENT 1 /** * Command ID's for communication Driver -> Trustlet Connector. */ #define CMD_TUI_SW_NONE 0 -#define CMD_TUI_SW_OPEN_SESSION 1 /* SWd request to NWd to start the TUI session */ -#define CMD_TUI_SW_CLOSE_SESSION 2 /* SWd request to NWd to close the TUI session */ -#define CMD_TUI_SW_STOP_DISPLAY 3 /* SWd request to NWd stop accessing display controler */ +/* SWd request to NWd to start the TUI session */ +#define CMD_TUI_SW_OPEN_SESSION 1 +/* SWd request to NWd to close the TUI session */ +#define CMD_TUI_SW_CLOSE_SESSION 2 +/* SWd request to NWd stop accessing display controller */ +#define CMD_TUI_SW_STOP_DISPLAY 3 /** * Maximum data length. */ -#define MAX_DCI_DATA_LEN 1024*100 +#define MAX_DCI_DATA_LEN (1024*100) -// Command payload -typedef struct { - uint32_t allocSize; - uint32_t numOfBuff; -} tuiAllocData_t, *tuiAllocData_ptr; +/* Command payload */ +struct tui_alloc_data_t { + uint32_t alloc_size; + uint32_t num_of_buff; +}; -typedef union { - tuiAllocData_t allocData; -} dciCmdPayload_t, *dciCmdPayload_ptr; +union dci_cmd_payload_t { + struct tui_alloc_data_t alloc_data; +}; -// Command -typedef struct{ - dciCommandId_t id; - dciCmdPayload_t payload; -} dciCommand_t, *dciCommand_ptr; +/* Command */ +struct dci_command_t { + volatile uint32_t id; + union dci_cmd_payload_t payload; +}; -// TUI frame buffer (output from NWd) +/* TUI frame buffer (output from NWd) */ typedef struct { uint64_t pa; -} tuiAllocBuffer_t, *tuiAllocBuffer_ptr; +} tuiAllocBuffer_t; #define MAX_DCI_BUFFER_NUMBER 4 -// Response -typedef struct{ - dciResponseId_t id; /* must be command ID | RSP_ID_MASK */ - dciReturnCode_t returnCode; +/* Response */ +struct dci_response_t { + volatile uint32_t id; /* must be command ID | RSP_ID_MASK */ + uint32_t return_code; union { - tuiAllocBuffer_t allocBuffer[MAX_DCI_BUFFER_NUMBER]; + tuiAllocBuffer_t alloc_buffer[MAX_DCI_BUFFER_NUMBER]; + }; }; -} dciResponse_t, *dciResponse_ptr; -// DCI buffer -typedef struct { - dciNotificationId_t nwdNotif; /* Notification from TlcTui to DrTui */ - dciCommand_t cmdNwd; /* Command from DrTui to TlcTui */ - dciResponse_t nwdRsp; /* Response from TlcTui to DrTui */ -} tuiDciMsg_t, *tuiDciMsg_ptr; +/* DCI buffer */ +struct tui_dci_msg_t { + volatile uint32_t nwd_notif; /* Notification from TlcTui to DrTui */ + struct dci_command_t cmd_nwd; /* Command from DrTui to TlcTui */ + struct dci_response_t nwd_rsp; /* Response from TlcTui to DrTui */ +}; -extern tuiDciMsg_ptr pDci; /** * Driver UUID. Update accordingly after reserving UUID */ #define DR_TUI_UUID { { 0xff, 0xff, 0xff, 0xff, 0xd0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x14 } } -#endif // __DCITUI_H__ + +#endif /* __DCITUI_H__ */ diff --git a/drivers/gud/TlcTui/inc/t-base-tui.h b/drivers/gud/TlcTui/inc/t-base-tui.h index bd57b0c7f32d..4f34a286ebec 100644 --- a/drivers/gud/TlcTui/inc/t-base-tui.h +++ b/drivers/gud/TlcTui/inc/t-base-tui.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 TRUSTONIC LIMITED + * Copyright (c) 2013-2014 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -21,6 +21,8 @@ #define TRUSTEDUI_MODE_VIDEO_SECURED 0x02 #define TRUSTEDUI_MODE_INPUT_SECURED 0x04 +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + int trustedui_blank_inc(void); int trustedui_blank_dec(void); int trustedui_blank_get_counter(void); @@ -31,161 +33,6 @@ void trustedui_set_mode(int mode); int trustedui_set_mask(int mask); int trustedui_clear_mask(int mask); -/* Use the arch_extension sec pseudo op before switching to secure world */ -#if defined(__GNUC__) && \ - defined(__GNUC_MINOR__) && \ - defined(__GNUC_PATCHLEVEL__) && \ - ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)) \ - >= 40502 -#define MC_ARCH_EXTENSION_SEC -#endif - -/* - * MobiCore SMCs - */ -#define MC_SMC_N_YIELD 0x3 /* Yield to switch from NWd to SWd. */ -#define MC_SMC_N_SIQ 0x4 /* SIQ to switch from NWd to SWd. */ - -/* - * MobiCore fast calls. See MCI documentation - */ -#define MC_FC_INIT -1 -#define MC_FC_INFO -2 -#define MC_FC_POWER -3 -#define MC_FC_DUMP -4 -#define MC_FC_NWD_TRACE -31 /* Mem trace setup fastcall */ - - -/* - * return code for fast calls - */ -#define MC_FC_RET_OK 0 -#define MC_FC_RET_ERR_INVALID 1 -#define MC_FC_RET_ERR_ALREADY_INITIALIZED 5 - - -/* structure wrappers for specific fastcalls */ - -/* generic fast call parameters */ -union fc_generic { - struct { - uint32_t cmd; - uint32_t param[3]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t param[2]; - } as_out; -}; - -/* fast call init */ -union mc_fc_init { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t base; - uint32_t nq_info; - uint32_t mcp_info; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t rfu[2]; - } as_out; -}; - -/* fast call info parameters */ -union mc_fc_info { - union fc_generic as_generic; - struct { - uint32_t cmd; - uint32_t ext_info_id; - uint32_t rfu[2]; - } as_in; - struct { - uint32_t resp; - uint32_t ret; - uint32_t state; - uint32_t ext_info; - } as_out; -}; - -/* - * _smc() - fast call to MobiCore - * - * @data: pointer to fast call data - */ -static inline long _smc(void *data) -{ - int ret = 0; - - if (data == NULL) - return -EPERM; - -#ifdef MC_SMC_FASTCALL - { - ret = smc_fastcall(data, sizeof(union fc_generic)); - } -#else - { - union fc_generic *fc_generic = data; - /* SMC expect values in r0-r3 */ - register u32 reg0 __asm__("r0") = fc_generic->as_in.cmd; - register u32 reg1 __asm__("r1") = fc_generic->as_in.param[0]; - register u32 reg2 __asm__("r2") = fc_generic->as_in.param[1]; - register u32 reg3 __asm__("r3") = fc_generic->as_in.param[2]; - - __asm__ volatile ( -#ifdef MC_ARCH_EXTENSION_SEC - /* This pseudo op is supported and required from - * binutils 2.21 on */ - ".arch_extension sec\n" -#endif - "smc 0\n" - : "+r"(reg0), "+r"(reg1), "+r"(reg2), "+r"(reg3) - ); -#ifdef __ARM_VE_A9X4_QEMU__ - __asm__ volatile ( - "nop\n" - "nop\n" - "nop\n" - "nop" - ); -#endif - - /* set response */ - fc_generic->as_out.resp = reg0; - fc_generic->as_out.ret = reg1; - fc_generic->as_out.param[0] = reg2; - fc_generic->as_out.param[1] = reg3; - } -#endif - return ret; -} - -/* - * convert fast call return code to linux driver module error code - */ -static inline int convert_fc_ret(uint32_t sret) -{ - int ret = -EFAULT; - - switch (sret) { - case MC_FC_RET_OK: - ret = 0; - break; - case MC_FC_RET_ERR_INVALID: - ret = -EINVAL; - break; - case MC_FC_RET_ERR_ALREADY_INITIALIZED: - ret = -EBUSY; - break; - default: - break; - } - return ret; -} - -#endif +#endif /* CONFIG_TRUSTONIC_TRUSTED_UI */ +#endif /* __TBASE_TUI_H__ */ diff --git a/drivers/gud/TlcTui/main.c b/drivers/gud/TlcTui/main.c index f1c852b9ebe1..564e9a3aece5 100644 --- a/drivers/gud/TlcTui/main.c +++ b/drivers/gud/TlcTui/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 TRUSTONIC LIMITED + * Copyright (c) 2013-2014 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -30,19 +29,16 @@ #include "mobicore_driver_api.h" #include "dciTui.h" #include "tui-hal.h" +#include "build_tag.h" -/* extern */ -extern struct mc_session_handle drSessionHandle; -extern struct completion dciComp; -extern uint32_t gCmdId; -extern tlcTuiResponse_t gUserRsp; +/*static int tui_dev_major_number = 122; */ -/* Global variables */ -DECLARE_COMPLETION(ioComp); +/*module_param(tui_dev_major_number, int, 0000); */ +/*MODULE_PARM_DESC(major, */ +/* "The device major number used to register a unique char device driver"); */ /* Static variables */ static struct cdev tui_cdev; -static struct task_struct *threadId; struct switch_dev tui_switch; @@ -54,64 +50,60 @@ static long tui_ioctl(struct file *f, unsigned int cmd, unsigned long arg) if (_IOC_TYPE(cmd) != TUI_IO_MAGIC) return -EINVAL; - pr_err("t-base-tui module: ioctl 0x%x ", cmd); + pr_info("t-base-tui module: ioctl 0x%x ", cmd); switch (cmd) { - case TUI_IO_NOTIFY: - pr_err("TUI_IO_NOTIFY\n"); + pr_info("TUI_IO_NOTIFY\n"); - if (tlcNotifyEvent(arg)) + if (tlc_notify_event(arg)) ret = 0; else ret = -EFAULT; break; - case TUI_IO_WAITCMD: - pr_err("TUI_IO_WAITCMD\n"); + case TUI_IO_WAITCMD: { + uint32_t cmd_id; - /* Create the TlcTui Main thread and start secure driver (only - 1st time) */ - if (drSessionHandle.session_id == 0) { - threadId = kthread_run(mainThread, NULL, "dci_thread"); - if (!threadId) { - pr_debug(KERN_ERR "Unable to start Trusted UI main thread\n"); - return -EFAULT; - } - } + pr_info("TUI_IO_WAITCMD\n"); - /* Wait for signal from DCI handler */ - wait_for_completion_interruptible(&dciComp); - INIT_COMPLETION(dciComp); + ret = tlc_wait_cmd(&cmd_id); + if (ret) + return ret; /* Write command id to user */ - pr_debug("IOCTL: sending command %d to user.\n", gCmdId); + pr_debug("IOCTL: sending command %d to user.\n", cmd_id); - if (copy_to_user(uarg, &gCmdId, sizeof(gCmdId))) + if (copy_to_user(uarg, &cmd_id, sizeof(cmd_id))) ret = -EFAULT; else ret = 0; - /* Reset the value of the command, to ensure that commands send due to - * interrupted wait_for_completion are TLC_TUI_CMD_NONE. + /* Reset the value of the command, to ensure that commands sent + * due to interrupted wait_for_completion are TLC_TUI_CMD_NONE. */ - gCmdId = TLC_TUI_CMD_NONE; + reset_global_command_id(); break; + } - case TUI_IO_ACK: - pr_err("TUI_IO_ACK\n"); + case TUI_IO_ACK: { + struct tlc_tui_response_t rsp_id; + + pr_info("TUI_IO_ACK\n"); /* Read user response */ - if (copy_from_user(&gUserRsp, uarg, sizeof(gUserRsp))) + if (copy_from_user(&rsp_id, uarg, sizeof(rsp_id))) ret = -EFAULT; else ret = 0; - /* Send signal to DCI */ - pr_debug("IOCTL: User completed command %d.\n", gUserRsp.id); - complete(&ioComp); + pr_debug("IOCTL: User completed command %d.\n", rsp_id.id); + ret = tlc_ack_cmd(&rsp_id); + if (ret) + return ret; break; + } default: pr_info("undefined!\n"); @@ -121,16 +113,18 @@ static long tui_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return ret; } -static struct file_operations tui_fops = { +static const struct file_operations tui_fops = { .owner = THIS_MODULE, + /*.unlocked_ioctl = tui_ioctl,*/ .compat_ioctl = tui_ioctl, }; /*--------------------------------------------------------------------------- */ -static int __init tlcTui_init(void) +static int __init tlc_tui_init(void) { - pr_err("Loading t-base-tui module.\n"); + pr_info("Loading t-base-tui module.\n"); pr_debug("\n=============== Running TUI Kernel TLC ===============\n"); + pr_info("%s\n", MOBICORE_COMPONENT_BUILD_TAG); dev_t devno; int err; @@ -179,7 +173,7 @@ static int __init tlcTui_init(void) return 0; } -static void __exit tlcTui_exit(void) +static void __exit tlc_tui_exit(void) { pr_info("Unloading t-base-tui module.\n"); @@ -190,9 +184,8 @@ static void __exit tlcTui_exit(void) hal_tui_exit(); } -module_init(tlcTui_init); -module_exit(tlcTui_exit); +module_init(tlc_tui_init); +module_exit(tlc_tui_exit); -MODULE_AUTHOR("Trustonic"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("TUI Kernel TLC"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(" #include #include -#include "../../../../video/exynos/decon/decon.h" #include +#include +#include +#include "../../../../video/exynos/decon/decon.h" +#include "tui_ioctl.h" #include "dciTui.h" #include "tlcTui.h" #include "tui-hal.h" @@ -46,6 +49,8 @@ #define HSI2C_FIFO_EMPTY (HSI2C_RX_FIFO_EMPTY | HSI2C_TX_FIFO_EMPTY) #define TUI_MEMPOOL_SIZE 0 +extern struct switch_dev tui_switch; + extern phys_addr_t hal_tui_video_space_alloc(void); extern int decon_lpd_block_exit(struct decon_device *decon); @@ -53,6 +58,16 @@ extern int decon_lpd_block_exit(struct decon_device *decon); extern struct ion_device *ion_exynos; /* ------------end ---------- */ +#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE +static int tsp_irq_num = 11; // default value + +void trustedui_set_tsp_irq(int irq_num) +{ + tsp_irq_num = irq_num; + pr_info("%s called![%d]\n",__func__, irq_num); +} +#endif + static struct decon_dma_buf_data dma; struct tui_mempool { @@ -61,7 +76,7 @@ struct tui_mempool { size_t size; }; -extern struct tui_mempool g_tuiMemPool; +static struct tui_mempool g_tuiMemPool; static u32 va; static struct ion_client *client; @@ -178,7 +193,19 @@ static void fb_tui_protection(void) pm_runtime_get_sync(decon->dev); #endif +#if 0 // time check + ktime_t start, end; + long long ns; + + start = ktime_get(); /* get time stamp before execution */ +#endif decon_tui_protection(decon, true); +#if 0 // time check + end = ktime_get(); /* get time stamp after execution */ + + ns = ktime_to_ns( ktime_sub(end, start) ); /* get the elapsed time in nano-seconds */ + printk(KERN_INFO "[TIME_CHECK] blank -> Elapsed time %lld ns\n", ns); /* print it on the console */ +#endif } static void set_va_to_decon(u32 va) @@ -210,8 +237,6 @@ static void fb_tui_unprotection(void) win = fb_info->par; decon = win->decon; -// decon_reg_update_standalone(0); - if (decon->pdata->trig_mode == DECON_HW_TRIG) decon_reg_set_trigger(decon->id, decon->pdata->dsi_mode, decon->pdata->trig_mode, DECON_TRIG_ENABLE); @@ -293,13 +318,14 @@ dma_addr_t decon_map_sec_dma_buf(struct dma_buf *dbuf, int plane) return 0; } -uint32_t hal_tui_alloc(tuiAllocBuffer_t *allocbuffer, size_t allocsize, uint32_t count) +uint32_t hal_tui_alloc(tuiAllocBuffer_t allocbuffer[MAX_DCI_BUFFER_NUMBER], + size_t allocsize, uint32_t count) { int ret = TUI_DCI_ERR_INTERNAL_ERROR; dma_addr_t buf_addr; ion_phys_addr_t phys_addr; unsigned long offset = 0; - size_t size; + unsigned int size; size=allocsize*(count+1); @@ -321,6 +347,15 @@ uint32_t hal_tui_alloc(tuiAllocBuffer_t *allocbuffer, size_t allocsize, uint32_t va = buf_addr + offset; printk("buf_addr : %x\n",va); printk("phys_addr : %lx\n",phys_addr); +#if 0 // this is testing. MUST BE REMOVE + void *kernel_addr; + //kernel_addr = (void*)ion_map_kernel(client, handle); + kernel_addr = phys_to_virt(phys_addr+0x2000000); + *((u32*)kernel_addr) = va; + printk("DATA ON phys_addr : addr[%lx] val[%x]\n" + ,phys_addr+0x2000000 + ,*((u32*)kernel_addr)); +#endif g_tuiMemPool.pa = phys_addr; g_tuiMemPool.size = allocsize*count; @@ -335,7 +370,6 @@ uint32_t hal_tui_alloc(tuiAllocBuffer_t *allocbuffer, size_t allocsize, uint32_t ret = TUI_DCI_ERR_INTERNAL_ERROR; return ret; } - ret = TUI_DCI_OK; return ret; @@ -400,6 +434,10 @@ void hal_tui_free(void) uint32_t hal_tui_deactivate(void) { + switch_set_state(&tui_switch, TRUSTEDUI_MODE_VIDEO_SECURED); + pr_info(KERN_ERR "Disable touch!\n"); + disable_irq(tsp_irq_num); + msleep(100); /* Set linux TUI flag */ trustedui_set_mask(TRUSTEDUI_MODE_TUI_SESSION); trustedui_blank_set_counter(0); @@ -410,6 +448,7 @@ uint32_t hal_tui_deactivate(void) set_va_to_decon(va); #endif trustedui_set_mask(TRUSTEDUI_MODE_VIDEO_SECURED|TRUSTEDUI_MODE_INPUT_SECURED); + pr_info(KERN_ERR "blanking!\n"); return TUI_DCI_OK; } @@ -434,6 +473,9 @@ uint32_t hal_tui_activate(void) // blank_framebuffer(0); } #endif + switch_set_state(&tui_switch, TRUSTEDUI_MODE_OFF); + tui_i2c_reset(); + enable_irq(tsp_irq_num); return TUI_DCI_OK; } diff --git a/drivers/gud/TlcTui/public/tui_ioctl.h b/drivers/gud/TlcTui/public/tui_ioctl.h new file mode 100644 index 000000000000..0e89a1e7b973 --- /dev/null +++ b/drivers/gud/TlcTui/public/tui_ioctl.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2014 TRUSTONIC LIMITED + * All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef TUI_IOCTL_H_ +#define TUI_IOCTL_H_ + +/* Command IDs */ +#define TLC_TUI_CMD_NONE 0 +#define TLC_TUI_CMD_START_ACTIVITY 1 +#define TLC_TUI_CMD_STOP_ACTIVITY 2 + +/* Return codes */ +#define TLC_TUI_OK 0 +#define TLC_TUI_ERROR 1 +#define TLC_TUI_ERR_UNKNOWN_CMD 2 + + +/* + * defines for the ioctl TUI driver module function call from user space. + */ +#define TUI_DEV_NAME "t-base-tui" + +#define TUI_IO_MAGIC 't' + +#define TUI_IO_NOTIFY _IOW(TUI_IO_MAGIC, 1, uint32_t) +#define TUI_IO_WAITCMD _IOR(TUI_IO_MAGIC, 2, uint32_t) +#define TUI_IO_ACK _IOW(TUI_IO_MAGIC, 3, struct tlc_tui_response_t) + +#endif /* TUI_IOCTL_H_ */ diff --git a/drivers/gud/TlcTui/tlcTui.c b/drivers/gud/TlcTui/tlcTui.c index eb27fe2e99b8..3b67e575aa00 100644 --- a/drivers/gud/TlcTui/tlcTui.c +++ b/drivers/gud/TlcTui/tlcTui.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 TRUSTONIC LIMITED + * Copyright (c) 2013-2014 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -17,98 +17,63 @@ #include #include #include -#include -#include -#include +#include #include "mobicore_driver_api.h" +#include "public/tui_ioctl.h" +//#include "tui_ioctl.h" #include "tlcTui.h" #include "dciTui.h" -#include "tui_ioctl.h" #include "tui-hal.h" -#include "trustedui.h" -#define TUI_ALIGN_16MB_SZ 0x1000000 /* 16MB */ -#define TUI_ALIGN_32MB_SZ 0x2000000 /* 32MB */ -#define TUI_TOTAL_ALLOC_SZ 0x2000000 /* 32MB */ -#define TUI_BUFFER_NUM 2 /* Framebuffer and Working buffer */ - -/* ------------------------------------------------------------- */ -/* Externs */ -extern struct completion ioComp; -#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE -extern void tui_i2c_reset(void); +#if defined(CONFIG_SECURE_OS_BOOSTER_API) +#include #endif -extern struct switch_dev tui_switch; /* ------------------------------------------------------------- */ /* Globals */ -const struct mc_uuid_t drUuid = DR_TUI_UUID; -struct mc_session_handle drSessionHandle = {0, 0}; -tuiDciMsg_ptr pDci; -DECLARE_COMPLETION(dciComp); -uint32_t gCmdId = TLC_TUI_CMD_NONE; -tlcTuiResponse_t gUserRsp = {TLC_TUI_CMD_NONE, TLC_TUI_ERR_UNKNOWN_CMD}; +struct tui_dci_msg_t *dci; +DECLARE_COMPLETION(dci_comp); +DECLARE_COMPLETION(io_comp); /* ------------------------------------------------------------- */ /* Static */ static const uint32_t DEVICE_ID = MC_DEVICE_ID_DEFAULT; - -#ifdef CONFIG_SOC_EXYNOS5433 -struct sec_tui_mempool { - void * va; - unsigned long pa; - size_t size; -}; - -static struct sec_tui_mempool g_sec_tuiMemPool; -#else -struct tui_mempool { - void * va; - unsigned long pa; - size_t size; -}; - -struct tui_mempool g_tuiMemPool; -#endif +static struct task_struct *thread_id; +static uint32_t g_cmd_id = TLC_TUI_CMD_NONE; +static struct mc_session_handle dr_session_handle = {0, 0}; +static struct tlc_tui_response_t g_user_rsp = { + TLC_TUI_CMD_NONE, TLC_TUI_ERR_UNKNOWN_CMD}; /* Functions */ -#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE -static int tsp_irq_num = 11; // default value - -void trustedui_set_tsp_irq(int irq_num){ - tsp_irq_num = irq_num; - pr_info("%s called![%d]\n",__func__, irq_num); -} -#endif /* ------------------------------------------------------------- */ -static bool tlcOpenDriver(void) +static bool tlc_open_driver(void) { bool ret = false; - enum mc_result mcRet; + enum mc_result mc_ret; + struct mc_uuid_t dr_uuid = DR_TUI_UUID; /* Allocate WSM buffer for the DCI */ - mcRet = mc_malloc_wsm(DEVICE_ID, 0, sizeof(tuiDciMsg_t), - (uint8_t **)&pDci, 0); - if (MC_DRV_OK != mcRet) { - pr_debug("ERROR tlcOpenDriver: Allocation of DCI WSM failed: %d\n", - mcRet); + mc_ret = mc_malloc_wsm(DEVICE_ID, 0, sizeof(struct tui_dci_msg_t), + (uint8_t **)&dci, 0); + if (MC_DRV_OK != mc_ret) { + pr_debug("ERROR %s: Allocation of DCI WSM failed: %d\n", + __func__, mc_ret); return false; } /* Clear the session handle */ - memset(&drSessionHandle, 0, sizeof(drSessionHandle)); + memset(&dr_session_handle, 0, sizeof(dr_session_handle)); /* The device ID (default device is used */ - drSessionHandle.device_id = DEVICE_ID; + dr_session_handle.device_id = DEVICE_ID; /* Open session with the Driver */ - mcRet = mc_open_session(&drSessionHandle, &drUuid, (uint8_t *)pDci, - (uint32_t)sizeof(tuiDciMsg_t)); - if (MC_DRV_OK != mcRet) { - printk(KERN_ERR "ERROR tlcOpenDriver: Open driver session failed: %d\n", - mcRet); + mc_ret = mc_open_session(&dr_session_handle, &dr_uuid, (uint8_t *)dci, + (uint32_t)sizeof(struct tui_dci_msg_t)); + if (MC_DRV_OK != mc_ret) { + pr_debug("ERROR %s: Open driver session failed: %d\n", + __func__, mc_ret); ret = false; } else { - printk(KERN_ERR "Success tlcOpenDriver: open driver session success!\n"); ret = true; } @@ -117,77 +82,79 @@ static bool tlcOpenDriver(void) /* ------------------------------------------------------------- */ -static bool tlcOpen(void) +static bool tlc_open(void) { bool ret = false; - enum mc_result mcRet; + enum mc_result mc_ret; /* Open the tbase device */ - pr_debug("tlcOpen: Opening tbase device\n"); - mcRet = mc_open_device(DEVICE_ID); + pr_debug("%s: Opening tbase device\n", __func__); + mc_ret = mc_open_device(DEVICE_ID); /* In case the device is already open, mc_open_device will return an * error (MC_DRV_ERR_INVALID_OPERATION). But in this case, we can * continue, even though mc_open_device returned an error. Stop in all * other case of error */ - if (MC_DRV_OK != mcRet && MC_DRV_ERR_INVALID_OPERATION != mcRet) { - pr_debug("ERROR tlcOpen: Error %d opening device\n", mcRet); + if (MC_DRV_OK != mc_ret && MC_DRV_ERR_INVALID_OPERATION != mc_ret) { + pr_debug("ERROR %s: Error %d opening device\n", __func__, + mc_ret); return false; } - pr_debug("tlcOpen: Opening driver session\n"); - ret = tlcOpenDriver(); + pr_debug("%s: Opening driver session\n", __func__); + ret = tlc_open_driver(); return ret; } /* ------------------------------------------------------------- */ -static void tlcWaitCmdFromDriver(void) +static void tlc_wait_cmd_from_driver(void) { uint32_t ret = TUI_DCI_ERR_INTERNAL_ERROR; /* Wait for a command from secure driver */ - ret = mc_wait_notification(&drSessionHandle, -1); + ret = mc_wait_notification(&dr_session_handle, -1); if (MC_DRV_OK == ret) - pr_debug("tlcWaitCmdFromDriver: Got a command\n"); + pr_debug("tlc_wait_cmd_from_driver: Got a command\n"); else - pr_debug("ERROR tlcWaitCmdFromDriver: mc_wait_notification() failed: %d\n", - ret); + pr_debug("ERROR %s: mc_wait_notification() failed: %d\n", + __func__, ret); } -static uint32_t sendCmdToUser(uint32_t commandId) +static uint32_t send_cmd_to_user(uint32_t command_id) { - dciReturnCode_t ret = TUI_DCI_ERR_NO_RESPONSE; + uint32_t ret = TUI_DCI_ERR_NO_RESPONSE; /* Init shared variables */ - gCmdId = commandId; - gUserRsp.id = TLC_TUI_CMD_NONE; - gUserRsp.returnCode = TLC_TUI_ERR_UNKNOWN_CMD; + g_cmd_id = command_id; + g_user_rsp.id = TLC_TUI_CMD_NONE; + g_user_rsp.return_code = TLC_TUI_ERR_UNKNOWN_CMD; + /* S.LSI : Clean up previous response. */ - complete_all(&ioComp); - INIT_COMPLETION(ioComp); + complete_all(&io_comp); + INIT_COMPLETION(io_comp); /* Give way to ioctl thread */ - complete(&dciComp); - pr_debug("sendCmdToUser: give way to ioctl thread\n"); + complete(&dci_comp); + pr_debug("send_cmd_to_user: give way to ioctl thread\n"); /* Wait for ioctl thread to complete */ - wait_for_completion_interruptible(&ioComp); - pr_debug("sendCmdToUser: Got an answer from ioctl thread.\n"); - INIT_COMPLETION(ioComp); - - /* Check id of the cmd processed by ioctl thread (paranoïa) */ - if (gUserRsp.id != commandId) { - pr_debug("sendCmdToUser ERROR: Wrong response id 0x%08x iso 0x%08x\n", - pDci->nwdRsp.id, RSP_ID(commandId)); + wait_for_completion_interruptible(&io_comp); + pr_debug("send_cmd_to_user: Got an answer from ioctl thread.\n"); + INIT_COMPLETION(io_comp); + + /* Check id of the cmd processed by ioctl thread (paranoia) */ + if (g_user_rsp.id != command_id) { + pr_debug("ERROR %s: Wrong response id 0x%08x iso 0x%08x\n", + __func__, dci->nwd_rsp.id, RSP_ID(command_id)); ret = TUI_DCI_ERR_INTERNAL_ERROR; } else { /* retrieve return code */ - switch (gUserRsp.returnCode) { + switch (g_user_rsp.return_code) { case TLC_TUI_OK: ret = TUI_DCI_OK; break; @@ -203,226 +170,182 @@ static uint32_t sendCmdToUser(uint32_t commandId) return ret; } -phys_addr_t hal_tui_video_space_alloc(void) -{ - phys_addr_t base; - size_t size; - - ion_exynos_contig_heap_info(ION_EXYNOS_ID_VIDEO, &base, &size); - - if (size > TUI_TOTAL_ALLOC_SZ) -#ifdef CONFIG_SOC_EXYNOS5433 - g_sec_tuiMemPool.size = TUI_TOTAL_ALLOC_SZ; -#else - g_tuiMemPool.size = TUI_TOTAL_ALLOC_SZ; -#endif - else -#ifdef CONFIG_SOC_EXYNOS5433 - g_sec_tuiMemPool.size = size; -#else - g_tuiMemPool.size = size; -#endif - - /* Align base address by 16MB */ - - base = ((base + (TUI_ALIGN_16MB_SZ-1))/TUI_ALIGN_16MB_SZ * TUI_ALIGN_16MB_SZ); -#ifdef CONFIG_SOC_EXYNOS5433 - g_sec_tuiMemPool.pa = base; -#else - g_tuiMemPool.pa = base; -#endif - - return base; -} - -#define FRAMEBUFFER_SIZE 0x1000000 -#define FRAMEBUFFER_COUNT 2 - /* ------------------------------------------------------------- */ -static void tlcProcessCmd(void) +static void tlc_process_cmd(void) { uint32_t ret = TUI_DCI_ERR_INTERNAL_ERROR; - uint32_t commandId = CMD_TUI_SW_NONE; - - pDci->cmdNwd.payload.allocData.numOfBuff = TUI_BUFFER_NUM; + uint32_t command_id = CMD_TUI_SW_NONE; +#if defined(CONFIG_SECURE_OS_BOOSTER_API) + int ret_val = 0; + u8 retry_cnt = 0; +#endif - if (NULL == pDci) { - pr_debug("ERROR tlcProcessCmd: DCI has not been set up properly - exiting\n"); + if (NULL == dci) { + pr_debug("ERROR %s: DCI has not been set up properly - exiting"\ + "\n", __func__); return; } else { - commandId = pDci->cmdNwd.id; + command_id = dci->cmd_nwd.id; } /* Warn if previous response was not acknowledged */ - if (CMD_TUI_SW_NONE == commandId) { - pr_debug("ERROR tlcProcessCmd: Notified without command\n"); + if (CMD_TUI_SW_NONE == command_id) { + pr_debug("ERROR %s: Notified without command\n", __func__); return; } else { - if (pDci->nwdRsp.id != CMD_TUI_SW_NONE) - pr_debug("tlcProcessCmd: Warning, previous response not ack\n"); + if (dci->nwd_rsp.id != CMD_TUI_SW_NONE) + pr_debug("%s: Warning, previous response not ack\n", + __func__); } /* Handle command */ - switch (commandId) { + switch (command_id) { case CMD_TUI_SW_OPEN_SESSION: - printk(KERN_ERR "tlcProcessCmd: CMD_TUI_SW_OPEN_SESSION.\n"); + pr_debug("%s: CMD_TUI_SW_OPEN_SESSION.\n", __func__); +#if defined(CONFIG_SECURE_OS_BOOSTER_API) + pr_info("%s TUI_CPU_SPEEDUP ON retry: %d\n", + __func__, retry_cnt); + do { + ret_val = secos_booster_start(MAX_PERFORMANCE); + retry_cnt++; + if (ret_val) { + pr_err("%s: booster start failed. (%d) retry: %d\n" + , __func__, ret_val, retry_cnt); + if (retry_cnt < 7) + usleep_range(500, 510); + } + } while (ret_val && retry_cnt < 7); +#endif /* Start android TUI activity */ - ret = sendCmdToUser(TLC_TUI_CMD_START_ACTIVITY); - if (TUI_DCI_OK != ret) { - printk(KERN_ERR "tlcProcessCmd: TLC_TUI_CMD_START_ACTIVITY error : %d\n",ret); + ret = send_cmd_to_user(TLC_TUI_CMD_START_ACTIVITY); + if (TUI_DCI_OK != ret) break; - } -#ifdef CONFIG_SOC_EXYNOS5433 - /* allocate TUI frame buffer */ - ret = hal_tui_alloc(&pDci->nwdRsp.allocBuffer[MAX_DCI_BUFFER_NUMBER], - pDci->cmdNwd.payload.allocData.allocSize, - pDci->cmdNwd.payload.allocData.numOfBuff); -#else /* allocate TUI frame buffer */ - ret = hal_tui_alloc(pDci->nwdRsp.allocBuffer, - FRAMEBUFFER_SIZE, - FRAMEBUFFER_COUNT); -#endif + ret = hal_tui_alloc(dci->nwd_rsp.alloc_buffer, + dci->cmd_nwd.payload.alloc_data.alloc_size, + dci->cmd_nwd.payload.alloc_data.num_of_buff); + if (TUI_DCI_OK != ret) { - printk(KERN_ERR "tlcProcessCmd: hal_tui_alloc error : %d\n",ret); + pr_err("%s: hal_tui_alloc error : %d\n", __func__ ,ret); /* no need to call tui_i2c_reset, because there will be no TUI * session */ //tui_i2c_reset(); - sendCmdToUser(TLC_TUI_CMD_STOP_ACTIVITY); + send_cmd_to_user(TLC_TUI_CMD_STOP_ACTIVITY); break; } -#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE - printk(KERN_ERR "tlcProcessCmd: CMD_TUI_SW_OPEN_SESSION & disable_irq(%d);.\n",tsp_irq_num); - disable_irq(tsp_irq_num); -#endif - msleep(100); // temp code -#ifdef CONFIG_SOC_EXYNOS5433 - - pDci->nwdRsp.allocBuffer[0].pa = g_sec_tuiMemPool.pa; - pDci->nwdRsp.allocBuffer[1].pa = (g_sec_tuiMemPool.pa + g_sec_tuiMemPool.size/2); - - pDci->cmdNwd.payload.allocData.allocSize = g_sec_tuiMemPool.size; -#else - pDci->cmdNwd.payload.allocData.allocSize = (uint32_t)g_tuiMemPool.size; -#endif - switch_set_state(&tui_switch, TRUSTEDUI_MODE_VIDEO_SECURED); - /* Deactivate linux UI drivers */ ret = hal_tui_deactivate(); if (TUI_DCI_OK != ret) { - printk(KERN_ERR "tlcProcessCmd: hal_tui_deactivate error : %d\n",ret); - /* no need to call tui_i2c_reset, because there will be no TUI - * session. Touch screen clock PMU are off */ - //tui_i2c_reset(); - enable_irq(tsp_irq_num); + pr_err("%s: hal_tui_deactivate error : %d\n", __func__ ,ret); hal_tui_free(); - sendCmdToUser(TLC_TUI_CMD_STOP_ACTIVITY); + send_cmd_to_user(TLC_TUI_CMD_STOP_ACTIVITY); break; } break; case CMD_TUI_SW_CLOSE_SESSION: -#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE - printk(KERN_ERR "tlcProcessCmd: CMD_TUI_SW_CLOSE_SESSION & enable_irq(%d).\n", tsp_irq_num); -#endif + pr_debug("%s: CMD_TUI_SW_CLOSE_SESSION.\n", __func__); /* Activate linux UI drivers */ ret = hal_tui_activate(); -#ifdef CONFIG_TRUSTED_UI_TOUCH_ENABLE -// tui_i2c_reset(); - enable_irq(tsp_irq_num); -#endif + hal_tui_free(); - switch_set_state(&tui_switch, TRUSTEDUI_MODE_OFF); +#if defined(CONFIG_SECURE_OS_BOOSTER_API) + ret_val = secos_booster_stop(); + if (ret_val) + pr_err("%s: booster stop failed. (%d)\n" + , __func__, ret_val); +#endif /* Stop android TUI activity */ - ret = sendCmdToUser(TLC_TUI_CMD_STOP_ACTIVITY); + ret = send_cmd_to_user(TLC_TUI_CMD_STOP_ACTIVITY); break; default: - pr_debug("ERROR tlcProcessCmd: Unknown command %d\n", - commandId); + pr_debug("ERROR %s: Unknown command %d\n", + __func__, command_id); break; } /* Fill in response to SWd, fill ID LAST */ - pr_debug("tlcProcessCmd: return 0x%08x to cmd 0x%08x\n", - ret, commandId); - pDci->nwdRsp.returnCode = ret; - pDci->nwdRsp.id = RSP_ID(commandId); + pr_debug("%s: return 0x%08x to cmd 0x%08x\n", + __func__, ret, command_id); + dci->nwd_rsp.return_code = ret; + dci->nwd_rsp.id = RSP_ID(command_id); /* Acknowledge command */ - pDci->cmdNwd.id = CMD_TUI_SW_NONE; + dci->cmd_nwd.id = CMD_TUI_SW_NONE; /* Notify SWd */ pr_debug("DCI RSP NOTIFY CORE\n"); - ret = mc_notify(&drSessionHandle); + ret = mc_notify(&dr_session_handle); if (MC_DRV_OK != ret) - pr_debug("ERROR tlcProcessCmd: Notify failed: %d\n", ret); + pr_debug("ERROR %s: Notify failed: %d\n", __func__, ret); } /* ------------------------------------------------------------- */ -static void tlcCloseDriver(void) +static void tlc_close_driver(void) { enum mc_result ret; /* Close session with the Driver */ - ret = mc_close_session(&drSessionHandle); + ret = mc_close_session(&dr_session_handle); if (MC_DRV_OK != ret) { - pr_debug("ERROR tlcCloseDriver: Closing driver session failed: %d\n", - ret); + pr_debug("ERROR %s: Closing driver session failed: %d\n", + __func__, ret); } } /* ------------------------------------------------------------- */ -static void tlcClose(void) +static void tlc_close(void) { enum mc_result ret; - pr_debug("tlcClose: Closing driver session\n"); - tlcCloseDriver(); + pr_debug("%s: Closing driver session\n", __func__); + tlc_close_driver(); - pr_debug("tlcClose: Closing tbase\n"); + pr_debug("%s: Closing tbase\n", __func__); /* Close the tbase device */ ret = mc_close_device(DEVICE_ID); if (MC_DRV_OK != ret) { - pr_debug("ERROR tlcClose: Closing tbase device failed: %d\n", - ret); + pr_debug("ERROR %s: Closing tbase device failed: %d\n", + __func__, ret); } + } + +void reset_global_command_id(void) +{ + g_cmd_id = TLC_TUI_CMD_NONE; } /* ------------------------------------------------------------- */ -bool tlcNotifyEvent(uint32_t eventType) +bool tlc_notify_event(uint32_t event_type) { bool ret = false; enum mc_result result; - if (NULL == pDci) { - pr_debug("ERROR tlcNotifyEvent: DCI has not been set up properly - exiting\n"); + if (NULL == dci) { + pr_debug("ERROR tlc_notify_event: DCI has not been set up "\ + "properly - exiting\n"); return false; } - /* Wait for previous notification to be acknowledged */ - while (pDci->nwdNotif != NOT_TUI_NONE) { - pr_debug("TLC waiting for previous notification ack\n"); - usleep_range(10000, 10000); - }; - /* Prepare notification message in DCI */ - pr_debug("tlcNotifyEvent: eventType = %d\n", eventType); - pDci->nwdNotif = eventType; + pr_debug("tlc_notify_event: event_type = %d\n", event_type); + dci->nwd_notif = event_type; /* Signal the Driver */ pr_debug("DCI EVENT NOTIFY CORE\n"); - result = mc_notify(&drSessionHandle); + result = mc_notify(&dr_session_handle); if (MC_DRV_OK != result) { - pr_debug("ERROR tlcNotifyEvent: mcNotify failed: %d\n", result); + pr_debug("ERROR tlc_notify_event: mc_notify failed: %d\n", + result); ret = false; } else { ret = true; @@ -434,28 +357,58 @@ bool tlcNotifyEvent(uint32_t eventType) /* ------------------------------------------------------------- */ /** */ -int mainThread(void *uarg) +int main_thread(void *uarg) { - - pr_debug("mainThread: TlcTui start!\n"); + pr_debug("main_thread: TlcTui start!\n"); /* Open session on the driver */ - if (!tlcOpen()) { - pr_debug("ERROR mainThread: open driver failed!\n"); + if (!tlc_open()) { + pr_debug("ERROR main_thread: open driver failed!\n"); return 1; } /* TlcTui main thread loop */ for (;;) { /* Wait for a command from the DrTui on DCI*/ - tlcWaitCmdFromDriver(); + tlc_wait_cmd_from_driver(); /* Something has been received, process it. */ - tlcProcessCmd(); + tlc_process_cmd(); } /* Close tlc. Note that this frees the DCI pointer. - * Do not use this pointer after tlcClose().*/ - tlcClose(); + * Do not use this pointer after tlc_close().*/ + tlc_close(); + + return 0; +} + +int tlc_wait_cmd(uint32_t *cmd_id) +{ + /* Create the TlcTui Main thread and start secure driver (only + 1st time) */ + if (dr_session_handle.session_id == 0) { + thread_id = kthread_run(main_thread, NULL, "dci_thread"); + if (!thread_id) { + pr_debug(KERN_ERR "Unable to start Trusted UI main thread\n"); + return -EFAULT; + } + } + + /* Wait for signal from DCI handler */ + /* In case of an interrupted sys call, return with -EINTR */ + wait_for_completion_interruptible(&dci_comp); + INIT_COMPLETION(dci_comp); + + *cmd_id = g_cmd_id; + return 0; +} + +int tlc_ack_cmd(struct tlc_tui_response_t *rsp_id) +{ + g_user_rsp = *rsp_id; + + /* Send signal to DCI */ + complete(&io_comp); return 0; } diff --git a/drivers/gud/TlcTui/tlcTui.h b/drivers/gud/TlcTui/tlcTui.h index 9c4ab4c1bc2a..d478c38fbe60 100644 --- a/drivers/gud/TlcTui/tlcTui.h +++ b/drivers/gud/TlcTui/tlcTui.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 TRUSTONIC LIMITED + * Copyright (c) 2013-2014 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -12,10 +12,21 @@ * GNU General Public License for more details. */ + +#include "public/tui_ioctl.h" + #ifndef TLCTUI_H_ #define TLCTUI_H_ -int mainThread(void *); -bool tlcNotifyEvent(uint32_t eventType); +/* Response header */ +struct tlc_tui_response_t { + uint32_t id; + uint32_t return_code; +}; + +void reset_global_command_id(void); +int tlc_wait_cmd(uint32_t *cmd_id); +int tlc_ack_cmd(struct tlc_tui_response_t *rsp_id); +bool tlc_notify_event(uint32_t event_type); #endif /* TLCTUI_H_ */ diff --git a/drivers/gud/TlcTui/trustedui.c b/drivers/gud/TlcTui/trustedui.c index 3eda2e8d204d..be04fb1a4bee 100644 --- a/drivers/gud/TlcTui/trustedui.c +++ b/drivers/gud/TlcTui/trustedui.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 TRUSTONIC LIMITED + * Copyright (c) 2013 TRUSTONIC LIMITED * All Rights Reserved. * * This program is free software; you can redistribute it and/or @@ -120,5 +120,5 @@ int trustedui_clear_mask(int mask) } EXPORT_SYMBOL(trustedui_clear_mask); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Trustonic Limited"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION(" SZ_1M) ? (SZ_1M - offset) : len; for (index = 0; index < nb_of_1mb_section; index++) { + mutex_lock(&ctx.bufs_lock); table = mc_alloc_mmu_table(instance, task, buffer, tmp_len, 0); + mutex_unlock(&ctx.bufs_lock); if (IS_ERR(table)) { MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed"); @@ -649,12 +651,14 @@ int mc_register_wsm_mmu(struct mc_instance *instance, mmu_table, nb_of_1mb_section*sizeof(uint64_t)); + mutex_lock(&ctx.bufs_lock); table = mc_alloc_mmu_table( instance, NULL, mmu_table, nb_of_1mb_section*sizeof(uint64_t), MC_MMU_TABLE_TYPE_WSM_FAKE_L1); + mutex_unlock(&ctx.bufs_lock); if (IS_ERR(table)) { MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed"); ret = -EINVAL; diff --git a/drivers/gud/gud-exynos7420/MobiCoreDriver/platforms/EXYNOS_7420_STD/platform.h b/drivers/gud/gud-exynos7420/MobiCoreDriver/platforms/EXYNOS_7420_STD/platform.h index da28dc0cdfbf..c96e22e0a694 100644 --- a/drivers/gud/gud-exynos7420/MobiCoreDriver/platforms/EXYNOS_7420_STD/platform.h +++ b/drivers/gud/gud-exynos7420/MobiCoreDriver/platforms/EXYNOS_7420_STD/platform.h @@ -48,7 +48,8 @@ #define LOCAL_TIMER_PERIOD 50 -#define DEFAULT_SECOS_BOOST_TIME 5000 +#define DEFAULT_SECOS_BOOST_TIME 5000 /* 5 sec */ +#define MAX_SECOS_BOOST_TIME 600000 /* 600 sec */ #define DUMP_TBASE_HALT_STATUS diff --git a/drivers/gud/gud-exynos7420/sec-os-booster/sec_os_booster.c b/drivers/gud/gud-exynos7420/sec-os-booster/sec_os_booster.c index b4ca44d94ed2..e63ac63fa1cf 100644 --- a/drivers/gud/gud-exynos7420/sec-os-booster/sec_os_booster.c +++ b/drivers/gud/gud-exynos7420/sec-os-booster/sec_os_booster.c @@ -38,11 +38,15 @@ #define MID_CPUFREQ 1700000 +#define BOOST_POLICY_OFFSET 0 +#define BOOST_TIME_OFFSET 16 + int mc_switch_core(uint32_t core_num); void mc_set_schedule_policy(int core); uint32_t mc_active_core(void); unsigned int current_core; + struct timer_work { struct kthread_work work; }; @@ -130,21 +134,26 @@ int secos_booster_start(enum secos_boost_policy policy) { int ret = 0; int freq; + uint32_t boost_time; /* mili second */ + enum secos_boost_policy boost_policy; current_core = mc_active_core(); + boost_time = (((uint32_t)policy) >> BOOST_TIME_OFFSET) & 0xFFFF; + boost_policy = (((uint32_t)policy) >> BOOST_POLICY_OFFSET) & 0xFFFF; + /* migrate to big Core */ - if ((policy != MAX_PERFORMANCE) && (policy != MID_PERFORMANCE) - && (policy != MIN_PERFORMANCE)) { - pr_err("%s: wrong secos boost policy:%d\n", __func__, policy); + if ((boost_policy != MAX_PERFORMANCE) && (boost_policy != MID_PERFORMANCE) + && (boost_policy != MIN_PERFORMANCE)) { + pr_err("%s: wrong secos boost policy:%d\n", __func__, boost_policy); ret = -EINVAL; goto error; } /* cpufreq configuration */ - if (policy == MAX_PERFORMANCE) + if (boost_policy == MAX_PERFORMANCE) freq = max_cpu_freq; - else if (policy == MID_PERFORMANCE) + else if (boost_policy == MID_PERFORMANCE) freq = MID_CPUFREQ; else freq = 0; @@ -172,8 +181,13 @@ int secos_booster_start(enum secos_boost_policy policy) mc_set_schedule_policy(DEFAULT_BIG_CORE); /* Restore origin performance policy after default boost time */ + if (boost_time == 0) + boost_time = DEFAULT_SECOS_BOOST_TIME; + else if (boost_time > MAX_SECOS_BOOST_TIME) + boost_time = MAX_SECOS_BOOST_TIME; + hrtimer_cancel(&timer); - hrtimer_start(&timer, ns_to_ktime((u64)DEFAULT_SECOS_BOOST_TIME * NSEC_PER_MSEC), + hrtimer_start(&timer, ns_to_ktime((u64)boost_time * NSEC_PER_MSEC), HRTIMER_MODE_REL); error: diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a054c03606ba..7ebc89409638 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -593,7 +593,7 @@ config HID_SAITEK config HID_SAMSUNG tristate "Samsung InfraRed remote control or keyboards" - depends on (USB_HID || BT_HIDP) + depends on (USB_HID || HID) ---help--- Support for Samsung InfraRed remote control or keyboards. @@ -737,7 +737,7 @@ config HID_WIIMOTE_EXT config HID_ZAGG tristate "ZAGG InfraRed remote control or keyboards" - depends on (USB_HID || BT_HIDP) + depends on (USB_HID || HID) ---help--- Support for ZAGG InfraRed remote control or keyboards. diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 46fcf5cf9563..9fc6fee2ef46 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -732,6 +732,7 @@ #define USB_DEVICE_ID_SAMSUNG_WIRELESS_ACTIONMOUSE 0xa004 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_BOOKCOVER 0xa005 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD 0xa006 +#define USB_DEVICE_ID_SAMSUNG_WIRELESS_BOOKCOVER_TABS2 0xa008 #define USB_VENDOR_ID_SENNHEISER 0x1395 #define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c diff --git a/drivers/hid/hid-ovr.c b/drivers/hid/hid-ovr.c index 115abbcda0a7..a878e2e61220 100644 --- a/drivers/hid/hid-ovr.c +++ b/drivers/hid/hid-ovr.c @@ -23,6 +23,10 @@ #include #include "hid-ids.h" +#ifdef CONFIG_ARCH_EXYNOS7 +#define WLAN0_RPS_CONTROL // 7420 +#endif + #define USB_TRACKER_INTERFACE_PROTOCOL 0 /* number of reports to buffer */ @@ -490,6 +494,29 @@ int ovr_report_event(struct hid_device *hid, u8 *data, int len) return ret; } +#ifdef WLAN0_RPS_CONTROL +#include +#include +#include +#include +#include +#include +#include +static void write_file(char *filename, char *data) +{ + struct file *fp; + loff_t pos = 0; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + fp = filp_open(filename, O_WRONLY, (int)0644); + if (fp) { + fp->f_op->write(fp, data, strlen(data), &pos); + filp_close(fp, current->files); + } + set_fs(old_fs); +} +#endif + int ovr_connect(struct hid_device *hid) { int minor, result; @@ -542,6 +569,10 @@ int ovr_connect(struct hid_device *hid) dev->exist = 1; hid->hidovr = dev; +#ifdef WLAN0_RPS_CONTROL + write_file("/sys/class/net/wlan0/queues/rx-0/rps_cpus","f0"); +#endif + out: return result; } @@ -567,6 +598,10 @@ void ovr_disconnect(struct hid_device *hid) } mutex_unlock(&minors_lock); + +#ifdef WLAN0_RPS_CONTROL + write_file("/sys/class/net/wlan0/queues/rx-0/rps_cpus","0"); +#endif } static long ovr_hidraw_ioctl(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index b3007f1d2458..6fd5fd1cd5be 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -241,6 +241,8 @@ source "drivers/input/tablet/Kconfig" source "drivers/input/touchscreen/Kconfig" +source "drivers/input/wacom/Kconfig" + source "drivers/input/misc/Kconfig" endif diff --git a/drivers/input/Makefile b/drivers/input/Makefile index f2c444a8704d..9ab1eb1ac639 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_INPUT_MOUSE) += mouse/ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ +obj-$(CONFIG_INPUT_WACOM) += wacom/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index bb69eccff6cd..df3f65c16487 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -12,6 +12,12 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD +config KEYBOARD_ABOV_TOUCH + tristate "Abov FT16XX touchkey" + depends on I2C + help + Say Y here if you want to use ABOV MC96FT16XX chip as touchkey. + config KEYBOARD_ADP5520 tristate "Keypad Support for ADP5520 PMIC" depends on PMIC_ADP5520 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 57f2406501f7..09b9eec41f30 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -4,6 +4,7 @@ # Each configuration option enables a list of files. +obj-$(CONFIG_KEYBOARD_ABOV_TOUCH) += abov_touchkey.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o @@ -57,4 +58,4 @@ obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_MBR31X5) += cypress_20075/ -obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_20075) += cypress_20075/ \ No newline at end of file +obj-$(CONFIG_KEYBOARD_CYPRESS_TOUCH_20075) += cypress_20075/ diff --git a/drivers/input/keyboard/abov_touchkey.c b/drivers/input/keyboard/abov_touchkey.c new file mode 100644 index 000000000000..9123810f410c --- /dev/null +++ b/drivers/input/keyboard/abov_touchkey.c @@ -0,0 +1,2003 @@ +/* abov_touchkey.c -- Linux driver for abov chip as touchkey + * + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Author: Junkyeong Kim + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_OF +#include +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +/* registers */ +#define ABOV_BTNSTATUS 0x00 +#define ABOV_FW_VER 0x01 +#define ABOV_PCB_VER 0x02 +#define ABOV_COMMAND 0x03 +#define ABOV_THRESHOLD 0x04 +#define ABOV_SENS 0x05 +#define ABOV_SETIDAC 0x06 +#define ABOV_DIFFDATA 0x0A +#define ABOV_RAWDATA 0x0E +#define ABOV_VENDORID 0x12 +#define ABOV_GLOVE 0x13 + +/* command */ +#define CMD_LED_ON 0x10 +#define CMD_LED_OFF 0x20 +#define CMD_DATA_UPDATE 0x40 +#define CMD_LED_CTRL_ON 0x60 +#define CMD_LED_CTRL_OFF 0x70 +#define CMD_STOP_MODE 0x80 +#define CMD_GLOVE_OFF 0x10 +#define CMD_GLOVE_ON 0x20 + +#define ABOV_BOOT_DELAY 45 +#define ABOV_RESET_DELAY 150 + +//static struct device *sec_touchkey; + +#define FW_VERSION 0x01 +#define FW_CHECKSUM_H 0x02 //noble 01 +#define FW_CHECKSUM_L 0x7A + +#ifdef LED_TWINKLE_BOOTING +static void led_twinkle_work(struct work_struct *work); +#endif + +#define TK_FW_PATH_BIN "abov/abov_noble.fw" +#define TK_FW_PATH_SDCARD "/sdcard/abov_fw.bin" + +#define I2C_M_WR 0 /* for i2c */ + +enum { + BUILT_IN = 0, + SDCARD, +}; + +#define ABOV_ISP_FIRMUP_ROUTINE 0 + +//#ifdef CONFIG_SAMSUNG_LPM_MODE +//extern int poweroff_charging; +//#endif +extern unsigned int system_rev; +extern struct class *sec_class; +static int touchkey_keycode[] = { 0, + KEY_RECENT, KEY_BACK +}; + +struct abov_tk_info { + struct i2c_client *client; + struct input_dev *input_dev; + struct device *dev; + struct abov_touchkey_platform_data *pdata; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct mutex lock; + struct pinctrl *pinctrl; + struct pinctrl *pinctrl_det; + struct pinctrl_state *pins_default; + + const struct firmware *firm_data_bin; + const u8 *firm_data_ums; + char phys[32]; + long firm_size; + int irq; + u16 menu_s; + u16 back_s; + u16 menu_raw; + u16 back_raw; + int (*power) (bool on); + void (*input_event)(void *data); + int touchkey_count; + u8 fw_update_state; + u8 fw_ver; + u8 fw_ver_bin; + u8 checksum_h; + u8 checksum_h_bin; + u8 checksum_l; + u8 checksum_l_bin; + bool enabled; + bool glovemode; +#ifdef LED_TWINKLE_BOOTING + struct delayed_work led_twinkle_work; + bool led_twinkle_check; +#endif +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void abov_tk_early_suspend(struct early_suspend *h); +static void abov_tk_late_resume(struct early_suspend *h); +#endif + +#if 1//def CONFIG_INPUT_ENABLED +static int abov_tk_input_open(struct input_dev *dev); +static void abov_tk_input_close(struct input_dev *dev); +#endif + +static int abov_tk_i2c_read_checksum(struct abov_tk_info *info); + +static int abov_touchkey_led_status; +static int abov_touchled_cmd_reserved; + +static int abov_glove_mode_enable(struct i2c_client *client, u8 cmd) +{ + return i2c_smbus_write_byte_data(client, ABOV_GLOVE, cmd); +} + +#if ABOV_ISP_FIRMUP_ROUTINE +static void abov_config_gpio_i2c(struct abov_tk_info *info, int onoff) +{ + struct device *i2c_dev = info->client->dev.parent->parent; + struct pinctrl *pinctrl_i2c; + + if (onoff) { + pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c"); + if (IS_ERR(pinctrl_i2c)) + printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__); + } else { + pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "off_i2c"); + if (IS_ERR(pinctrl_i2c)) + printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__); + } +} +#endif + +static int abov_tk_i2c_read(struct i2c_client *client, + u8 reg, u8 *val, unsigned int len) +{ + struct abov_tk_info *info = i2c_get_clientdata(client); + struct i2c_msg msg; + int ret; + int retry = 3; + + mutex_lock(&info->lock); + msg.addr = client->addr; + msg.flags = I2C_M_WR; + msg.len = 1; + msg.buf = ® + while (retry--) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + break; + + dev_err(&client->dev, "%s fail(address set)(%d)\n", + __func__, retry); + msleep(10); + } + if (ret < 0) { + mutex_unlock(&info->lock); + return ret; + } + retry = 3; + msg.flags = 1;/*I2C_M_RD*/ + msg.len = len; + msg.buf = val; + while (retry--) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) { + mutex_unlock(&info->lock); + return 0; + } + dev_err(&client->dev, "%s fail(data read)(%d)\n", + __func__, retry); + msleep(10); + } + mutex_unlock(&info->lock); + return ret; +} + +static int abov_tk_i2c_write(struct i2c_client *client, + u8 reg, u8 *val, unsigned int len) +{ + struct abov_tk_info *info = i2c_get_clientdata(client); + struct i2c_msg msg[1]; + unsigned char data[2]; + int ret; + int retry = 3; + + mutex_lock(&info->lock); + data[0] = reg; + data[1] = *val; + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 2; + msg->buf = data; + + while (retry--) { + ret = i2c_transfer(client->adapter, msg, 1); + if (ret >= 0) { + mutex_unlock(&info->lock); + return 0; + } + dev_err(&client->dev, "%s fail(%d)\n", + __func__, retry); + msleep(10); + } + mutex_unlock(&info->lock); + return ret; +} + +static void release_all_fingers(struct abov_tk_info *info) +{ + struct i2c_client *client = info->client; + int i; + + dev_dbg(&client->dev, "[TK] %s\n", __func__); + + for (i = 1; i < info->touchkey_count; i++) { + input_report_key(info->input_dev, + touchkey_keycode[i], 0); + } + input_sync(info->input_dev); +} + +static int abov_tk_reset_for_bootmode(struct abov_tk_info *info) +{ + int ret=0; + + info->pdata->power(info->pdata, false); + msleep(50); + info->pdata->power(info->pdata, true); + + return ret; + +} + +static void abov_tk_reset(struct abov_tk_info *info) +{ + struct i2c_client *client = info->client; + + if (info->enabled == false) + return; + + dev_notice(&client->dev, "%s++\n", __func__); + disable_irq_nosync(info->irq); + + info->enabled = false; + + release_all_fingers(info); + + abov_tk_reset_for_bootmode(info); + msleep(ABOV_RESET_DELAY); + + if (info->glovemode) + abov_glove_mode_enable(client, CMD_GLOVE_ON); + + info->enabled = true; + + enable_irq(info->irq); + dev_notice(&client->dev, "%s--\n", __func__); +} + +static irqreturn_t abov_tk_interrupt(int irq, void *dev_id) +{ + struct abov_tk_info *info = dev_id; + struct i2c_client *client = info->client; + int ret, retry; + u8 buf; + + ret = abov_tk_i2c_read(client, ABOV_BTNSTATUS, &buf, 1); + if (ret < 0) { + retry = 3; + while (retry--) { + dev_err(&client->dev, "%s read fail(%d)\n", + __func__, retry); + ret = abov_tk_i2c_read(client, ABOV_BTNSTATUS, &buf, 1); + if (ret == 0) + break; + else + msleep(10); + } + if (retry == 0) { + abov_tk_reset(info); + return IRQ_HANDLED; + } + } + + { + int menu_data = buf & 0x03; + int back_data = (buf >> 2) & 0x03; + u8 menu_press = !(menu_data % 2); + u8 back_press = !(back_data % 2); + + if (menu_data) + input_report_key(info->input_dev, + touchkey_keycode[1], menu_press); + if (back_data) + input_report_key(info->input_dev, + touchkey_keycode[2], back_press); + +#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP + dev_notice(&client->dev, + "key %s%s ver0x%02x\n", + menu_data ? (menu_press ? "P" : "R") : "", + back_data ? (back_press ? "P" : "R") : "", + info->fw_ver); +#else + dev_notice(&client->dev, + "%s%s%x ver0x%02x\n", + menu_data ? (menu_press ? "menu P " : "menu R ") : "", + back_data ? (back_press ? "back P " : "back R ") : "", + buf, info->fw_ver); +#endif + } + + input_sync(info->input_dev); + + return IRQ_HANDLED; + +} +static int touchkey_led_set(struct abov_tk_info *info, int data) +{ + u8 cmd; + int ret; + + if (data == 1) + cmd = CMD_LED_ON; + else + cmd = CMD_LED_OFF; + + if (!info->enabled) { + abov_touchled_cmd_reserved = 1; + return 1; + } + + ret = abov_tk_i2c_write(info->client, ABOV_BTNSTATUS, &cmd, 1); + if (ret < 0) { + dev_err(&info->client->dev, "%s fail(%d)\n", __func__, ret); + abov_touchled_cmd_reserved = 1; + return 1; + } + + return 0; +} + +static ssize_t touchkey_led_control(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + int data; + u8 cmd; + int ret; + + ret = sscanf(buf, "%d", &data); + if (ret != 1) { + dev_err(&info->client->dev, "%s: cmd read err\n", __func__); + return count; + } + + if (!(data == 0 || data == 1)) { + dev_err(&info->client->dev, "%s: wrong command(%d)\n", + __func__, data); + return count; + } + + if (data == 1) + cmd = CMD_LED_ON; + else + cmd = CMD_LED_OFF; + +#ifdef LED_TWINKLE_BOOTING + if(info->led_twinkle_check == 1){ + info->led_twinkle_check = 0; + cancel_delayed_work(&info->led_twinkle_work); + } +#endif + + if(touchkey_led_set(info, data)) + goto out; + + msleep(20); + + abov_touchled_cmd_reserved = 0; + dev_notice(&info->client->dev, "%s data(%d)\n",__func__,data); + +out: + abov_touchkey_led_status = cmd; + + return count; +} + +static ssize_t touchkey_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + u8 r_buf; + int ret; + + ret = abov_tk_i2c_read(client, ABOV_THRESHOLD, &r_buf, 1); + if (ret < 0) { + dev_err(&client->dev, "%s fail(%d)\n", __func__, ret); + r_buf = 0; + } + return sprintf(buf, "%d\n", r_buf); +} + +static void get_diff_data(struct abov_tk_info *info) +{ + struct i2c_client *client = info->client; + u8 r_buf[4]; + int ret; + + ret = abov_tk_i2c_read(client, ABOV_DIFFDATA, r_buf, 4); + if (ret < 0) { + dev_err(&client->dev, "%s fail(%d)\n", __func__, ret); + info->menu_s = 0; + info->back_s = 0; + return; + } + + info->menu_s = (r_buf[0] << 8) | r_buf[1]; + info->back_s = (r_buf[2] << 8) | r_buf[3]; +} + +static ssize_t touchkey_menu_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + + get_diff_data(info); + + return sprintf(buf, "%d\n", info->menu_s); +} + +static ssize_t touchkey_back_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + + get_diff_data(info); + + return sprintf(buf, "%d\n", info->back_s); +} + +static void get_raw_data(struct abov_tk_info *info) +{ + struct i2c_client *client = info->client; + u8 r_buf[4]; + int ret; + + ret = abov_tk_i2c_read(client, ABOV_RAWDATA, r_buf, 4); + if (ret < 0) { + dev_err(&client->dev, "%s fail(%d)\n", __func__, ret); + info->menu_raw = 0; + info->back_raw = 0; + return; + } + + info->menu_raw = (r_buf[0] << 8) | r_buf[1]; + info->back_raw = (r_buf[2] << 8) | r_buf[3]; +} + +static ssize_t touchkey_menu_raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + + get_raw_data(info); + + return sprintf(buf, "%d\n", info->menu_raw); +} + +static ssize_t touchkey_back_raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + + get_raw_data(info); + + return sprintf(buf, "%d\n", info->back_raw); +} + +static ssize_t bin_fw_ver(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + + dev_dbg(&client->dev, "fw version bin : 0x%x\n", info->fw_ver_bin); + + return sprintf(buf, "0x%02x\n", info->fw_ver_bin); +} + +int get_tk_fw_version(struct abov_tk_info *info, bool bootmode) +{ + struct i2c_client *client = info->client; + u8 buf; + int ret; + int retry = 3; + + ret = abov_tk_i2c_read(client, ABOV_FW_VER, &buf, 1); + if (ret < 0) { + while (retry--) { + dev_err(&client->dev, "%s read fail(%d)\n", + __func__, retry); + if (!bootmode) + abov_tk_reset(info); + else + return -1; + ret = abov_tk_i2c_read(client, ABOV_FW_VER, &buf, 1); + if (ret == 0) + break; + } + if (retry <= 0) + return -1; + } + + info->fw_ver = buf; + dev_notice(&client->dev, "%s : 0x%x\n", __func__, buf); + return 0; +} + +static ssize_t read_fw_ver(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + + ret = get_tk_fw_version(info, false); + if (ret < 0) { + dev_err(&client->dev, "%s read fail\n", __func__); + info->fw_ver = 0; + } + + abov_tk_i2c_read_checksum(info); + + return sprintf(buf, "0x%02x\n", info->fw_ver); +} + +static int abov_load_fw(struct abov_tk_info *info, u8 cmd) +{ + struct i2c_client *client = info->client; + struct file *fp; + mm_segment_t old_fs; + long fsize, nread; + int ret = 0; + + switch(cmd) { + case BUILT_IN: + ret = request_firmware(&info->firm_data_bin, + info->pdata->fw_path, &client->dev); + if (ret) { + dev_err(&client->dev, + "%s request_firmware fail(%d)\n", __func__, cmd); + return ret; + } + info->firm_size = info->firm_data_bin->size; + break; + + case SDCARD: + old_fs = get_fs(); + set_fs(get_ds()); + fp = filp_open(TK_FW_PATH_SDCARD, O_RDONLY, S_IRUSR); + if (IS_ERR(fp)) { + dev_err(&client->dev, + "%s %s open error\n", __func__, TK_FW_PATH_SDCARD); + ret = -ENOENT; + goto fail_sdcard_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + info->firm_data_ums = kzalloc((size_t)fsize, GFP_KERNEL); + if (!info->firm_data_ums) { + dev_err(&client->dev, + "%s fail to kzalloc for fw\n", __func__); + ret = -ENOMEM; + goto fail_sdcard_kzalloc; + } + + nread = vfs_read(fp, + (char __user *)info->firm_data_ums, fsize, &fp->f_pos); + if (nread != fsize) { + dev_err(&client->dev, + "%s fail to vfs_read file\n", __func__); + ret = -EINVAL; + goto fail_sdcard_size; + } + filp_close(fp, current->files); + set_fs(old_fs); + info->firm_size = nread; + break; + + default: + ret = -1; + break; + } + dev_notice(&client->dev, "fw_size : %lu\n", info->firm_size); + dev_notice(&client->dev, "%s success\n", __func__); + return ret; + +fail_sdcard_size: + kfree(&info->firm_data_ums); +fail_sdcard_kzalloc: + filp_close(fp, current->files); +fail_sdcard_open: + set_fs(old_fs); + return ret; +} + +#if ABOV_ISP_FIRMUP_ROUTINE +void abov_i2c_start(int scl, int sda) +{ + gpio_direction_output(sda, 1); + gpio_direction_output(scl, 1); + usleep_range(15, 17); + gpio_direction_output(sda, 0); + usleep_range(10, 12); + gpio_direction_output(scl, 0); + usleep_range(10, 12); +} + +void abov_i2c_stop(int scl, int sda) +{ + gpio_direction_output(scl, 0); + usleep_range(10, 12); + gpio_direction_output(sda, 0); + usleep_range(10, 12); + gpio_direction_output(scl, 1); + usleep_range(10, 12); + gpio_direction_output(sda, 1); +} + +void abov_testdelay(void) +{ + u8 i; + u8 delay; + + /* 120nms */ + for (i = 0; i < 15; i++) + delay = 0; +} + + +void abov_byte_send(u8 data, int scl, int sda) +{ + u8 i; + for (i = 0x80; i != 0; i >>= 1) { + gpio_direction_output(scl, 0); + usleep_range(1,1); + + if (data & i) + gpio_direction_output(sda, 1); + else + gpio_direction_output(sda, 0); + + usleep_range(1,1); + gpio_direction_output(scl, 1); + usleep_range(1,1); + } + usleep_range(1,1); + + gpio_direction_output(scl, 0); + gpio_direction_input(sda); + usleep_range(1,1); + + gpio_direction_output(scl, 1); + usleep_range(1,1); + + gpio_get_value(sda); + abov_testdelay(); + + gpio_direction_output(scl, 0); + gpio_direction_output(sda, 0); + usleep_range(20,20); +} + +u8 abov_byte_read(bool type, int scl, int sda) +{ + u8 i; + u8 data = 0; + u8 index = 0x7; + + gpio_direction_output(scl, 0); + gpio_direction_input(sda); + usleep_range(1,1); + + for (i = 0; i < 8; i++) { + gpio_direction_output(scl, 0); + usleep_range(1,1); + gpio_direction_output(scl, 1); + usleep_range(1,1); + + data = data | (u8)(gpio_get_value(sda) << index); + index -= 1; + } + usleep_range(1,1); + gpio_direction_output(scl, 0); + + gpio_direction_output(sda, 0); + usleep_range(1,1); + + if (type) { /*ACK */ + gpio_direction_output(sda, 0); + usleep_range(1,1); + gpio_direction_output(scl, 1); + usleep_range(1,1); + gpio_direction_output(scl, 0); + usleep_range(1,1); + } else { /* NAK */ + gpio_direction_output(sda, 1); + usleep_range(1,1); + gpio_direction_output(scl, 1); + usleep_range(1,1); + gpio_direction_output(scl, 0); + usleep_range(1,1); + gpio_direction_output(sda, 0); + usleep_range(1,1); + } + usleep_range(20,20); + + return data; +} + +void abov_enter_mode(int scl, int sda) +{ + abov_i2c_start(scl, sda); + abov_testdelay(); + abov_byte_send(ABOV_ID, scl, sda); + abov_byte_send(0xAC, scl, sda); + abov_byte_send(0x5B, scl, sda); + abov_byte_send(0x2D, scl, sda); + abov_i2c_stop(scl, sda); +} + +void abov_firm_write(const u8 *fw_data, int block, int scl, int sda) +{ + int i, j; + u16 pos = 0x20; + u8 addr[2]; + u8 data[32] = {0, }; + + addr[0] = 0x10; + addr[1] = 0x00; + for (i = 0; i < (block - 0x20); i++) { + if (i % 8 == 0) { + addr[0] = 0x10 + i/8; + addr[1] = 0; + } else + addr[1] = addr[1] + 0x20; + memcpy(data, fw_data + pos, 32); + abov_i2c_start(scl, sda); + abov_testdelay(); + abov_byte_send(ABOV_ID, scl, sda); + abov_byte_send(0xAC, scl, sda); + abov_byte_send(0x7A, scl, sda); + abov_byte_send(addr[0], scl, sda); + abov_byte_send(addr[1], scl, sda); + for (j = 0; j < 32; j++) + abov_byte_send(data[j], scl, sda); + abov_i2c_stop(scl, sda); + + pos += 0x20; + + usleep_range(3000,3000);; //usleep(2000); //msleep(2); + } +} + +void abov_read_address_set(int scl, int sda) +{ + abov_i2c_start(scl, sda); + abov_testdelay(); + abov_byte_send(ABOV_ID, scl, sda); + abov_byte_send(0xAC, scl, sda); + abov_byte_send(0x9E, scl, sda); + abov_byte_send(0x10, scl, sda); /* start addr H */ + abov_byte_send(0x00, scl, sda); /* start addr L */ + abov_byte_send(0x3F, scl, sda); /* end addr H */ + abov_byte_send(0xFF, scl, sda); /* end addr L */ + abov_i2c_stop(scl, sda); +} + +void abov_checksum(struct abov_tk_info *info, int scl, int sda) +{ + struct i2c_client *client = info->client; + + u8 status; + u8 bootver; + u8 firmver; + u8 checksumh; + u8 checksuml; + + abov_read_address_set(scl, sda); + msleep(5); + + abov_i2c_start(scl, sda); + abov_testdelay(); + abov_byte_send(ABOV_ID, scl, sda); + abov_byte_send(0x00, scl, sda); + + abov_i2c_start(scl, sda); /* restart */ + abov_testdelay(); + abov_byte_send(ABOV_ID + 1, scl, sda); + status = abov_byte_read(true, scl, sda); + bootver = abov_byte_read(true, scl, sda); + firmver = abov_byte_read(true, scl, sda); + checksumh = abov_byte_read(true, scl, sda); + checksuml = abov_byte_read(false, scl, sda); + abov_i2c_stop(scl, sda); + msleep(3); + + info->checksum_h = checksumh; + info->checksum_l = checksuml; + + dev_err(&client->dev, + "%s status(0x%x), boot(0x%x), firm(0x%x), cs_h(0x%x), cs_l(0x%x)\n", + __func__, status, bootver, firmver, checksumh, checksuml); +} + +void abov_exit_mode(int scl, int sda) +{ + abov_i2c_start(scl, sda); + abov_testdelay(); + abov_byte_send(ABOV_ID, scl, sda); + abov_byte_send(0xAC, scl, sda); + abov_byte_send(0x5B, scl, sda); + abov_byte_send(0xE1, scl, sda); + abov_i2c_stop(scl, sda); +} + +static int abov_fw_update(struct abov_tk_info *info, + const u8 *fw_data, int block, int scl, int sda) +{ +printk("%s + (%d)\n",__func__,__LINE__); + abov_config_gpio_i2c(info, 0); + msleep(ABOV_BOOT_DELAY); + abov_enter_mode(scl, sda); + msleep(1100); //msleep(600); + abov_firm_write(fw_data, block, scl, sda); + abov_checksum(info, scl, sda); + abov_config_gpio_i2c(info, 1); +printk("%s - (%d)\n",__func__,__LINE__); + return 0; +} +#endif + +static int abov_tk_check_busy(struct abov_tk_info *info) +{ + int ret, count = 0; + unsigned char val = 0x00; + + do { + ret = i2c_master_recv(info->client, &val, sizeof(val)); + + if (val) { + count++; + } else { + break; + } + + } while(1); + + if (count > 1000) + pr_err("%s: busy %d\n", __func__, count); + return ret; +} + +static int abov_tk_i2c_read_checksum(struct abov_tk_info *info) +{ + unsigned char data[6] = {0xAC, 0x9E, 0x10, 0x00, 0x3F, 0xFF}; + unsigned char checksum[5] = {0, }; + int ret; + unsigned char reg = 0x00; + + i2c_master_send(info->client, data, 6); + + msleep(5); + + abov_tk_check_busy(info); + + ret = abov_tk_i2c_read(info->client, reg, checksum, 5); + + dev_info(&info->client->dev, "%s: ret:%d [%X][%X][%X][%X][%X]\n", + __func__, ret, checksum[0], checksum[1], checksum[2] + , checksum[3], checksum[4]); + info->checksum_h = checksum[3]; + info->checksum_l = checksum[4]; + return 0; +} + +static int abov_tk_fw_write(struct abov_tk_info *info, unsigned char *addrH, + unsigned char *addrL, unsigned char *val) +{ + int length = 36, ret = 0; + unsigned char data[36]; + + data[0] = 0xAC; + data[1] = 0x7A; + memcpy(&data[2], addrH, 1); + memcpy(&data[3], addrL, 1); + memcpy(&data[4], val, 32); + + ret = i2c_master_send(info->client, data, length); + if (ret != length) { + pr_err("%s: write fail[%x%x], %d\n", __func__, *addrH, *addrL, ret); + return ret; + } + + msleep(2); + + abov_tk_check_busy(info); + + return 0; +} + +static int abov_tk_fw_mode_enter(struct abov_tk_info *info) +{ + unsigned char data[3] = {0xAC, 0x5B, 0x2D}; + int ret = 0; + + ret = i2c_master_send(info->client, data, 3); + if (ret != 3) { + pr_err("%s: write fail\n", __func__); + return -1; + } + + return 0; + +} + +static int abov_tk_fw_update(struct abov_tk_info *info, u8 cmd) +{ + int ret, ii = 0; + int count; + unsigned short address; + unsigned char addrH, addrL; + unsigned char data[32] = {0, }; + + + pr_err("%s:1\n", __func__); + + count = info->firm_size / 32; + address = 0x1000; + + pr_err("%s:2\n", __func__); + abov_tk_reset_for_bootmode(info); + msleep(ABOV_BOOT_DELAY); + ret = abov_tk_fw_mode_enter(info); + + pr_err("%s:3\n", __func__); + + msleep(1100); + + for (ii = 1; ii < count; ii++) { + /* first 32byte is header */ + addrH = (unsigned char)((address >> 8) & 0xFF); + addrL = (unsigned char)(address & 0xFF); + if (cmd == BUILT_IN) + memcpy(data, &info->firm_data_bin->data[ii * 32], 32); + else if (cmd == SDCARD) + memcpy(data, &info->firm_data_ums[ii * 32], 32); + + ret = abov_tk_fw_write(info, &addrH, &addrL, data); + if (ret < 0) { + pr_err("%s: err, no device : %d\n", __func__, ret); + return ret; + } + msleep(2); + + abov_tk_check_busy(info); + + address += 0x20; + + memset(data, 0, 32); + } + + pr_err("%s:4\n", __func__); + ret = abov_tk_i2c_read_checksum(info); + + pr_err("%s:5\n", __func__); + + return ret; +} + +static void abov_release_fw(struct abov_tk_info *info, u8 cmd) +{ + switch(cmd) { + case BUILT_IN: + release_firmware(info->firm_data_bin); + break; + + case SDCARD: + kfree(info->firm_data_ums); + break; + + default: + break; + } +} + +static int abov_flash_fw(struct abov_tk_info *info, bool probe, u8 cmd) +{ + struct i2c_client *client = info->client; + int retry = 2; + int ret; + int block_count; + const u8 *fw_data; + + ret = get_tk_fw_version(info, probe); + if (ret) + info->fw_ver = 0; + + switch(cmd) { + case BUILT_IN: + fw_data = info->firm_data_bin->data; + break; + + case SDCARD: + fw_data = info->firm_data_ums; + break; + + default: + return -1; + break; + } + + block_count = (int)(info->firm_size / 32); + + while (retry--) { + ret = abov_tk_fw_update(info, cmd); + if (ret < 0) + break; +#if ABOV_ISP_FIRMUP_ROUTINE + abov_tk_reset_for_bootmode(info); + abov_fw_update(info, fw_data, block_count, + info->pdata->gpio_scl, info->pdata->gpio_sda); +#endif + + if (cmd == BUILT_IN) { + if ((info->checksum_h != info->checksum_h_bin) || + (info->checksum_l != info->checksum_l_bin)) { + dev_err(&client->dev, + "%s checksum fail.(0x%x,0x%x),(0x%x,0x%x) retry:%d\n", + __func__, info->checksum_h, info->checksum_l, + info->checksum_h_bin, info->checksum_l_bin, retry); + ret = -1; + continue; + } + } + abov_tk_reset_for_bootmode(info); + msleep(ABOV_RESET_DELAY); + ret = get_tk_fw_version(info, true); + if (ret) { + dev_err(&client->dev, "%s fw version read fail\n", __func__); + ret = -1; + continue; + } + + if (info->fw_ver == 0) { + dev_err(&client->dev, "%s fw version fail (0x%x)\n", + __func__, info->fw_ver); + ret = -1; + continue; + } + + if ((cmd == BUILT_IN) && (info->fw_ver != info->fw_ver_bin)){ + dev_err(&client->dev, "%s fw version fail 0x%x, 0x%x\n", + __func__, info->fw_ver, info->fw_ver_bin); + ret = -1; + continue; + } + ret = 0; + break; + } + + return ret; +} + +static ssize_t touchkey_fw_update(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int ret; + u8 cmd; + + switch(*buf) { + case 's': + case 'S': + cmd = BUILT_IN; + break; + case 'i': + case 'I': + cmd = SDCARD; + break; + default: + info->fw_update_state = 2; + goto touchkey_fw_update_out; + } + + ret = abov_load_fw(info, cmd); + if (ret) { + dev_err(&client->dev, + "%s fw load fail\n", __func__); + info->fw_update_state = 2; + goto touchkey_fw_update_out; + } + + info->fw_update_state = 1; + disable_irq(info->irq); + info->enabled = false; + ret = abov_flash_fw(info, false, cmd); + if (info->glovemode) + abov_glove_mode_enable(client, CMD_GLOVE_ON); + info->enabled = true; + enable_irq(info->irq); + if (ret) { + dev_err(&client->dev, "%s fail\n", __func__); +// info->fw_update_state = 2; + info->fw_update_state = 0; + + } else { + dev_notice(&client->dev, "%s success\n", __func__); + info->fw_update_state = 0; + } + + abov_release_fw(info, cmd); + +touchkey_fw_update_out: + dev_dbg(&client->dev, "%s : %d\n", __func__, info->fw_update_state); + + return count; +} + +static ssize_t touchkey_fw_update_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int count = 0; + + dev_info(&client->dev, "%s : %d\n", __func__, info->fw_update_state); + + if (info->fw_update_state == 0) + count = sprintf(buf, "PASS\n"); + else if (info->fw_update_state == 1) + count = sprintf(buf, "Downloading\n"); + else if (info->fw_update_state == 2) + count = sprintf(buf, "Fail\n"); + + return count; +} + +static ssize_t abov_glove_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + struct i2c_client *client = info->client; + int scan_buffer; + int ret; + u8 cmd; + + ret = sscanf(buf, "%d", &scan_buffer); + if (ret != 1) { + dev_err(&client->dev, "%s: cmd read err\n", __func__); + return count; + } + + if (!(scan_buffer == 0 || scan_buffer == 1)) { + dev_err(&client->dev, "%s: wrong command(%d)\n", + __func__, scan_buffer); + return count; + } + + if (!info->enabled) + return count; + + if (info->glovemode == scan_buffer) { + dev_info(&client->dev, "%s same command(%d)\n", + __func__, scan_buffer); + return count; + } + + if (scan_buffer == 1) { + dev_notice(&client->dev, "%s glove mode\n", __func__); + cmd = CMD_GLOVE_ON; + } else { + dev_notice(&client->dev, "%s normal mode\n", __func__); + cmd = CMD_GLOVE_OFF; + } + + ret = abov_glove_mode_enable(client, cmd); + if (ret < 0) { + dev_err(&client->dev, "%s fail(%d)\n", __func__, ret); + return count; + } + + info->glovemode = scan_buffer; + + return count; +} + +static ssize_t abov_glove_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct abov_tk_info *info = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", info->glovemode); +} + +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, touchkey_threshold_show, NULL); +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + touchkey_led_control); +static DEVICE_ATTR(touchkey_recent, S_IRUGO, touchkey_menu_show, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, touchkey_back_show, NULL); +static DEVICE_ATTR(touchkey_recent_raw, S_IRUGO, touchkey_menu_raw_show, NULL); +static DEVICE_ATTR(touchkey_back_raw, S_IRUGO, touchkey_back_raw_show, NULL); +static DEVICE_ATTR(touchkey_firm_version_phone, S_IRUGO, bin_fw_ver, NULL); +static DEVICE_ATTR(touchkey_firm_version_panel, S_IRUGO, read_fw_ver, NULL); +static DEVICE_ATTR(touchkey_firm_update, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + touchkey_fw_update); +static DEVICE_ATTR(touchkey_firm_update_status, S_IRUGO | S_IWUSR | S_IWGRP, + touchkey_fw_update_status, NULL); +static DEVICE_ATTR(glove_mode, S_IRUGO | S_IWUSR | S_IWGRP, + abov_glove_mode_show, abov_glove_mode); + +static struct attribute *sec_touchkey_attributes[] = { + &dev_attr_touchkey_threshold.attr, + &dev_attr_brightness.attr, + &dev_attr_touchkey_recent.attr, + &dev_attr_touchkey_back.attr, + &dev_attr_touchkey_recent_raw.attr, + &dev_attr_touchkey_back_raw.attr, + &dev_attr_touchkey_firm_version_phone.attr, + &dev_attr_touchkey_firm_version_panel.attr, + &dev_attr_touchkey_firm_update.attr, + &dev_attr_touchkey_firm_update_status.attr, + &dev_attr_glove_mode.attr, + NULL, +}; + +static struct attribute_group sec_touchkey_attr_group = { + .attrs = sec_touchkey_attributes, +}; + +extern int get_samsung_lcd_attached(void); + +static int abov_tk_fw_check(struct abov_tk_info *info) +{ + struct i2c_client *client = info->client; + int ret; + + ret = abov_load_fw(info, BUILT_IN); + if (ret) { + dev_err(&client->dev, + "%s fw load fail\n", __func__); + return ret; + } + + /* Header info + * 0x00 0x91 : model info, + * 0x00 0x00 : module info (Rev 0.0), + * 0x00 0xF3 : F/W + * 0x00 0x00 0x17 0x10 : checksum + * ~ 22byte 0x00 */ + info->fw_ver_bin = info->firm_data_bin->data[5]; + info->checksum_h_bin = info->firm_data_bin->data[8]; + info->checksum_l_bin = info->firm_data_bin->data[9]; + info->firm_size = info->firm_data_bin->size; + + dev_info(&client->dev,"%s, bin version:%2X,%2X,%2X crc:%2X,%2X\n", __func__, \ + info->firm_data_bin->data[1], info->firm_data_bin->data[3], info->fw_ver_bin, \ + info->checksum_h_bin, info->checksum_l_bin); + + ret = get_tk_fw_version(info, true); + +#ifdef LED_TWINKLE_BOOTING + if(ret) + dev_err(&client->dev, + "%s: i2c fail...[%d], addr[%d]\n", + __func__, ret, info->client->addr); + dev_err(&client->dev, + "%s: touchkey driver unload\n", __func__); + + if (get_samsung_lcd_attached() == 0) { + dev_err(&client->dev, "%s : get_samsung_lcd_attached()=0 \n", __func__); + abov_release_fw(info, BUILT_IN); + return ret; + } +#endif + + if ((info->fw_ver == 0) || info->fw_ver > 0xF0 || info->fw_ver < info->fw_ver_bin){ + dev_err(&client->dev, "excute tk firmware update (0x%x -> 0x%x\n", + info->fw_ver, info->fw_ver_bin); + ret = abov_flash_fw(info, true, BUILT_IN); + if (ret) { + dev_err(&client->dev, + "failed to abov_flash_fw (%d)\n", ret); + } else { + dev_info(&client->dev, + "fw update success\n"); + } + } + + abov_release_fw(info, BUILT_IN); + + return ret; +} + +int abov_power(struct abov_touchkey_platform_data *pdata, bool on) +{ + int ret = 0; + + pdata->avdd_vreg = regulator_get(NULL, "vtouch_3.3v"); + if (IS_ERR(pdata->avdd_vreg)) { + pdata->avdd_vreg = NULL; + pr_err("[TKEY] pdata->avdd_vreg get error, ignoring\n"); + } + pdata->dvdd_vreg = regulator_get(NULL, "vtouch_2.8v"); + if (IS_ERR(pdata->dvdd_vreg)) { + pdata->dvdd_vreg = NULL; + pr_err("[TKEY] pdata->dvdd_vreg get error, ignoring\n"); + } + + if (on) { + if (pdata->avdd_vreg) { + ret = regulator_enable(pdata->avdd_vreg); + if(ret){ + pr_err("[TKEY] %s: avdd reg enable fail\n", __func__); + } + } + if (pdata->dvdd_vreg) { + ret = regulator_enable(pdata->dvdd_vreg); + if(ret){ + pr_err("[TKEY] %s: dvdd reg enable fail\n", __func__); + } + } + } else { + if (pdata->avdd_vreg) { + ret = regulator_disable(pdata->avdd_vreg); + if(ret){ + pr_err("[TKEY] %s: avdd reg disable fail\n", __func__); + } + } + if (pdata->dvdd_vreg) { + ret = regulator_disable(pdata->dvdd_vreg); + if(ret){ + pr_err("[TKEY] %s: dvdd reg disable fail\n", __func__); + } + } + } + regulator_put(pdata->avdd_vreg); + regulator_put(pdata->dvdd_vreg); + + pr_info("[TKEY] %s: %s:\n", __func__, on ? "on" : "off"); + + return ret; +} + +#if 1 +static int abov_pinctrl_configure(struct abov_tk_info *info, + bool active) +{ + struct pinctrl_state *set_state; + int retval; + + if (active) { + set_state = + pinctrl_lookup_state(info->pinctrl, + "on_irq"); + if (IS_ERR(set_state)) { + pr_err("%s: cannot get ts pinctrl active state\n", __func__); + return PTR_ERR(set_state); + } + } else { + set_state = + pinctrl_lookup_state(info->pinctrl, + "off_irq"); + if (IS_ERR(set_state)) { + pr_err("%s: cannot get gpiokey pinctrl sleep state\n", __func__); + return PTR_ERR(set_state); + } + } + retval = pinctrl_select_state(info->pinctrl, set_state); + if (retval) { + pr_err("%s: cannot set ts pinctrl active state\n", __func__); + return retval; + } + + return 0; +} +#endif +int abov_gpio_reg_init(struct device *dev, + struct abov_touchkey_platform_data *pdata) +{ + int ret = 0; + + ret = gpio_request(pdata->gpio_int, "tkey_gpio_int"); + if(ret < 0){ + dev_err(dev, "unable to request gpio_int\n"); + return ret; + } + + pdata->power = abov_power; + + return ret; +} + +#ifdef CONFIG_OF +static int abov_parse_dt(struct device *dev, + struct abov_touchkey_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + int ret; + //u32 tmp[2] = {0, }; + + pdata->gpio_int = of_get_named_gpio(np, "abov,irq-gpio", 0); + if(pdata->gpio_int < 0){ + dev_err(dev, "unable to get gpio_int\n"); + return pdata->gpio_int; + } + + pdata->gpio_scl = of_get_named_gpio(np, "abov,scl-gpio", 0); + if(pdata->gpio_scl < 0){ + dev_err(dev, "unable to get gpio_scl\n"); + return pdata->gpio_scl; + } + + pdata->gpio_sda = of_get_named_gpio(np, "abov,sda-gpio", 0); + if(pdata->gpio_sda < 0){ + dev_err(dev, "unable to get gpio_sda\n"); + return pdata->gpio_sda; + } + + pdata->sub_det = of_get_named_gpio(np, "abov,sub-det",0); + if(pdata->sub_det < 0){ + dev_info(dev, "unable to get sub_det\n"); + }else{ + dev_info(dev, "%s: sub_det:%d\n",__func__,pdata->sub_det); + } + + ret = of_property_read_string(np, "abov,fw_path", (const char **)&pdata->fw_path); + if (ret) { + printk(KERN_ERR"touchkey:failed to read fw_path %d\n", ret); + pdata->fw_path = TK_FW_PATH_BIN; + } + dev_info(dev, "%s: fw path %s\n", __func__, pdata->fw_path); +/* + ret = of_property_read_u32_array(np, "abov,fw_checksum", tmp, 2); + if (ret) { + printk(KERN_ERR"touchkey:failed to read fw_checksum %d\n", ret); + pdata->fw_checksum_h =FW_CHECKSUM_H; + pdata->fw_checksum_l = FW_CHECKSUM_L; + } + pdata->fw_checksum_h = tmp[0]; + pdata->fw_checksum_l = tmp[1]; + dev_info(dev, "%s: fw_checksum %x %x\n", __func__, pdata->fw_checksum_h, pdata->fw_checksum_l); +*/ + dev_info(dev, "%s: gpio_int:%d, gpio_scl:%d, gpio_sda:%d\n", + __func__, pdata->gpio_int, pdata->gpio_scl, + pdata->gpio_sda); + + return 0; +} +#else +static int abov_parse_dt(struct device *dev, + struct abov_touchkey_platform_data *pdata) +{ + return -ENODEV; +} +#endif + +static int abov_tk_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct abov_tk_info *info; + struct input_dev *input_dev; +#if 0 + struct device *touchkey_dev; + int i; +#endif + int ret = 0; + +#ifdef LED_TWINKLE_BOOTING + if (get_samsung_lcd_attached() == 0) { + dev_err(&client->dev, "%s : get_samsung_lcd_attached()=0 \n", __func__); + return -EIO; + } +#endif + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "i2c_check_functionality fail\n"); + return -EIO; + } + + info = kzalloc(sizeof(struct abov_tk_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&client->dev, + "Failed to allocate memory for input device\n"); + ret = -ENOMEM; + goto err_input_alloc; + } + + info->client = client; + info->input_dev = input_dev; + + if (client->dev.of_node) { + struct abov_touchkey_platform_data *pdata; + pdata = devm_kzalloc(&client->dev, + sizeof(struct abov_touchkey_platform_data), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + ret = -ENOMEM; + goto err_config; + } + + ret = abov_parse_dt(&client->dev, pdata); + if (ret) + return ret; + + info->pdata = pdata; + } else + info->pdata = client->dev.platform_data; + + if (info->pdata == NULL) { + pr_err("failed to get platform data\n"); + goto err_config; + } +#if 1 + /* Get pinctrl if target uses pinctrl */ + info->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR(info->pinctrl)) { + if (PTR_ERR(info->pinctrl) == -EPROBE_DEFER) + goto err_config; + + pr_err("%s: Target does not use pinctrl\n", __func__); + info->pinctrl = NULL; + } + + if (info->pinctrl) { + ret = abov_pinctrl_configure(info, true); + if (ret) + pr_err("%s: cannot set ts pinctrl active state\n", __func__); + } + + /* sub-det pinctrl */ + if (gpio_is_valid(info->pdata->sub_det)) { + info->pinctrl_det = devm_pinctrl_get(&client->dev); + if (IS_ERR(info->pinctrl_det)) { + pr_err("%s: Failed to get pinctrl\n", __func__); + goto err_config; + } + + info->pins_default = pinctrl_lookup_state(info->pinctrl_det, "sub_det"); + if (IS_ERR(info->pins_default)) { + pr_err("%s: Failed to get pinctrl state\n", __func__); + devm_pinctrl_put(info->pinctrl_det); + goto err_config; + } + + ret = pinctrl_select_state(info->pinctrl_det, info->pins_default); + if (ret < 0) + pr_err("%s: Failed to configure sub_det pin\n", __func__); + } +#endif + ret = abov_gpio_reg_init(&client->dev, info->pdata); + if(ret){ + dev_err(&client->dev, "failed to init reg\n"); + goto pwr_config; + } + if (info->pdata->power) + info->pdata->power(info->pdata, true); + msleep(ABOV_RESET_DELAY); + + if (gpio_is_valid(info->pdata->sub_det)) { + ret = gpio_get_value(info->pdata->sub_det); + if (ret) { + dev_err(&client->dev, "Device wasn't connected to board \n"); + ret = -ENODEV; + goto err_i2c_check; + } + } + + info->enabled = true; + info->irq = -1; + client->irq = gpio_to_irq(info->pdata->gpio_int); + + mutex_init(&info->lock); + + info->input_event = info->pdata->input_event; + info->touchkey_count = sizeof(touchkey_keycode) / sizeof(int); + i2c_set_clientdata(client, info); + + ret = abov_tk_fw_check(info); + if (ret) { + dev_err(&client->dev, + "failed to firmware check (%d)\n", ret); + goto err_reg_input_dev; + } + + ret = get_tk_fw_version(info, false); + if (ret < 0) { + dev_err(&client->dev, "%s read fail\n", __func__); + goto err_reg_input_dev; + } + + snprintf(info->phys, sizeof(info->phys), + "%s/input0", dev_name(&client->dev)); + input_dev->name = "sec_touchkey"; + input_dev->phys = info->phys; + input_dev->id.bustype = BUS_HOST; + input_dev->dev.parent = &client->dev; +#if 1 //def CONFIG_INPUT_ENABLED + input_dev->open = abov_tk_input_open; + input_dev->close = abov_tk_input_close; +#endif + set_bit(EV_KEY, input_dev->evbit); + set_bit(KEY_RECENT, input_dev->keybit); + set_bit(KEY_BACK, input_dev->keybit); + set_bit(EV_LED, input_dev->evbit); + set_bit(LED_MISC, input_dev->ledbit); + input_set_drvdata(input_dev, info); + + ret = input_register_device(input_dev); + if (ret) { + dev_err(&client->dev, "failed to register input dev (%d)\n", + ret); + goto err_reg_input_dev; + } + + if (!info->pdata->irq_flag) { + dev_err(&client->dev, "no irq_flag\n"); + ret = request_threaded_irq(client->irq, NULL, abov_tk_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ABOV_TK_NAME, info); + } else { + ret = request_threaded_irq(client->irq, NULL, abov_tk_interrupt, + info->pdata->irq_flag, ABOV_TK_NAME, info); + } + if (ret < 0) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_req_irq; + } + info->irq = client->irq; + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING; + info->early_suspend.suspend = abov_tk_early_suspend; + info->early_suspend.resume = abov_tk_late_resume; + register_early_suspend(&info->early_suspend); +#endif + + info->dev = sec_device_create(info, "sec_touchkey"); + if (IS_ERR(info->dev)) + dev_err(&client->dev, + "Failed to create device for the touchkey sysfs\n"); + + ret = sysfs_create_group(&info->dev ->kobj, + &sec_touchkey_attr_group); + if (ret) + dev_err(&client->dev, "Failed to create sysfs group\n"); + + ret = sysfs_create_link(&info->dev ->kobj, + &info->input_dev->dev.kobj, "input"); + if (ret < 0) { + dev_err(&info->client->dev, + "%s: Failed to create input symbolic link\n", + __func__); + } + + +#ifdef LED_TWINKLE_BOOTING + if (get_samsung_lcd_attached() == 0) { + dev_err(&client->dev, "%s : get_samsung_lcd_attached()=0, so start LED twinkle \n", __func__); + + INIT_DELAYED_WORK(&info->led_twinkle_work, led_twinkle_work); + info->led_twinkle_check = 1; + + schedule_delayed_work(&info->led_twinkle_work, msecs_to_jiffies(400)); + } +#endif + + dev_err(&client->dev, "%s done\n", __func__); + + return 0; + +err_req_irq: + input_unregister_device(input_dev); +err_reg_input_dev: + mutex_destroy(&info->lock); +err_i2c_check: +pwr_config: +err_config: + input_free_device(input_dev); +err_input_alloc: + kfree(info); +err_alloc: + printk("%s fail\n",__func__); + return ret; + +} + + +#ifdef LED_TWINKLE_BOOTING +static void led_twinkle_work(struct work_struct *work) +{ + struct abov_tk_info *info = container_of(work, struct abov_tk_info, + led_twinkle_work.work); + static bool led_on = 1; + static int count = 0; + dev_err(&info->client->dev, "%s, on=%d, c=%d\n",__func__, led_on, count++ ); + + if(info->led_twinkle_check == 1){ + + touchkey_led_set(info,led_on); + if(led_on) led_on = 0; + else led_on = 1; + + schedule_delayed_work(&info->led_twinkle_work, msecs_to_jiffies(400)); + }else{ + + if(led_on == 0) + touchkey_led_set(info, 0); + } + +} +#endif + +static int abov_tk_remove(struct i2c_client *client) +{ + struct abov_tk_info *info = i2c_get_clientdata(client); + +/* if (info->enabled) + info->pdata->power(0); +*/ + info->enabled = false; +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&info->early_suspend); +#endif + if (info->irq >= 0) + free_irq(info->irq, info); + input_unregister_device(info->input_dev); + input_free_device(info->input_dev); + kfree(info); + + return 0; +} + +static void abov_tk_shutdown(struct i2c_client *client) +{ + struct abov_tk_info *info = i2c_get_clientdata(client); + u8 cmd = CMD_LED_OFF; + printk("Inside abov_tk_shutdown \n"); + + if (info->enabled){ + disable_irq(info->irq); + abov_tk_i2c_write(client, ABOV_BTNSTATUS, &cmd, 1); + info->pdata->power(info->pdata, false); + } + info->enabled = false; + +// just power off. +// if (info->irq >= 0) +// free_irq(info->irq, info); +// kfree(info); +} + +#if defined(CONFIG_PM) +static int abov_tk_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct abov_tk_info *info = i2c_get_clientdata(client); + + if (!info->enabled) { + dev_info(&client->dev, "%s: already power off\n", __func__); + return 0; + } + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + + disable_irq(info->irq); + info->enabled = false; + release_all_fingers(info); + + if (info->pdata->power) + info->pdata->power(info->pdata, false); + return 0; +} + +static int abov_tk_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct abov_tk_info *info = i2c_get_clientdata(client); + u8 led_data; + + if (info->enabled) { + dev_info(&client->dev, "%s: already power on\n", __func__); + return 0; + } + + dev_notice(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + + if (info->pdata->power) { + info->pdata->power(info->pdata, true); + msleep(ABOV_RESET_DELAY); + } else /* touchkey on by i2c */ + get_tk_fw_version(info, true); + + info->enabled = true; + + if (abov_touchled_cmd_reserved && \ + abov_touchkey_led_status == CMD_LED_ON) { + abov_touchled_cmd_reserved = 0; + led_data=abov_touchkey_led_status; + + abov_tk_i2c_write(client, ABOV_BTNSTATUS, &led_data, 1); + + dev_notice(&info->client->dev, "%s: LED reserved on\n", __func__); + } + enable_irq(info->irq); + + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void abov_tk_early_suspend(struct early_suspend *h) +{ + struct abov_tk_info *info; + info = container_of(h, struct abov_tk_info, early_suspend); + abov_tk_suspend(&info->client->dev); + +} + +static void abov_tk_late_resume(struct early_suspend *h) +{ + struct abov_tk_info *info; + info = container_of(h, struct abov_tk_info, early_suspend); + abov_tk_resume(&info->client->dev); +} +#endif + +#if 1//def CONFIG_INPUT_ENABLED +static int abov_tk_input_open(struct input_dev *dev) +{ + struct abov_tk_info *info = input_get_drvdata(dev); + +printk("%s %d \n",__func__,__LINE__); + dev_info(&info->client->dev, "%s: users=%d, v:0x%02x, g:%d\n", __func__, + info->input_dev->users, info->fw_ver ,info->glovemode); + + //gpio_direction_input(info->pdata->gpio_scl); + //gpio_direction_input(info->pdata->gpio_sda); + + abov_tk_resume(&info->client->dev); + if (info->pinctrl) + abov_pinctrl_configure(info, true); + + if (info->glovemode) + abov_glove_mode_enable(info->client, CMD_GLOVE_ON); + + return 0; +} +static void abov_tk_input_close(struct input_dev *dev) +{ + struct abov_tk_info *info = input_get_drvdata(dev); + +printk("%s %d \n",__func__,__LINE__); + dev_info(&info->client->dev, "%s: users=%d\n", __func__, + info->input_dev->users); + + abov_tk_suspend(&info->client->dev); + //gpio_set_value(info->pdata->gpio_scl, 1); + //gpio_set_value(info->pdata->gpio_sda, 1); + if (info->pinctrl) + abov_pinctrl_configure(info, false); + +#ifdef LED_TWINKLE_BOOTING + info->led_twinkle_check = 0; +#endif + +} +#endif + +#if 0//defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) &&!defined(CONFIG_INPUT_ENABLED) +static const struct dev_pm_ops abov_tk_pm_ops = { + .suspend = abov_tk_suspend, + .resume = abov_tk_resume, +}; +#endif + +static const struct i2c_device_id abov_tk_id[] = { + {ABOV_TK_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, abov_tk_id); + +#ifdef CONFIG_OF +static struct of_device_id abov_match_table[] = { + { .compatible = "abov,mc96ft16xx",}, + { }, +}; +#else +#define abov_match_table NULL +#endif + +static struct i2c_driver abov_tk_driver = { + .probe = abov_tk_probe, + .remove = abov_tk_remove, + .shutdown = abov_tk_shutdown, + .driver = { + .name = ABOV_TK_NAME, + .of_match_table = abov_match_table, +#if 0//defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND) &&!defined(CONFIG_INPUT_ENABLED) + .pm = &abov_tk_pm_ops, +#endif + }, + .id_table = abov_tk_id, +}; + +static int __init touchkey_init(void) +{ + pr_err("%s: abov,mc96ft16xx\n", __func__); + /* +#ifdef CONFIG_SAMSUNG_LPM_MODE + if (poweroff_charging) { + pr_notice("%s : LPM Charging Mode!!\n", __func__); + return 0; + } +#endif +*/ + return i2c_add_driver(&abov_tk_driver); +} + +static void __exit touchkey_exit(void) +{ + i2c_del_driver(&abov_tk_driver); +} + +module_init(touchkey_init); +module_exit(touchkey_exit); + +/* Module information */ +MODULE_AUTHOR("Samsung Electronics"); +MODULE_DESCRIPTION("Touchkey driver for Abov MF16xx chip"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cypress_20075/cypress-touchkey.c b/drivers/input/keyboard/cypress_20075/cypress-touchkey.c index f1602fa51894..5240dee08338 100644 --- a/drivers/input/keyboard/cypress_20075/cypress-touchkey.c +++ b/drivers/input/keyboard/cypress_20075/cypress-touchkey.c @@ -80,6 +80,7 @@ static void cypress_config_gpio_i2c(struct touchkey_i2c *tkey_i2c, int onoff); static int touchkey_i2c_update(struct touchkey_i2c *tkey_i2c); static bool touchkey_probe; +static bool start_state; static const struct i2c_device_id sec_touchkey_id[] = { {"sec_touchkey", 0}, @@ -1054,6 +1055,8 @@ static irqreturn_t touchkey_interrupt(int irq, void *dev_id) struct touchkey_i2c *tkey_i2c = dev_id; u8 data[3]; int ret; + int i; + int keycode_data[touchkey_count]; if (unlikely(!touchkey_probe)) { tk_debug_err(true, &tkey_i2c->client->dev, "%s: Touchkey is not probed\n", __func__); @@ -1064,75 +1067,29 @@ static irqreturn_t touchkey_interrupt(int irq, void *dev_id) if (ret < 0) return IRQ_HANDLED; - if (tkey_i2c->fw_ver_ic > 0x06) { - int i; - int keycode_data[touchkey_count]; - - keycode_data[1] = data[0] & 0x3; - keycode_data[2] = (data[0] >> 2) & 0x3; + keycode_data[1] = data[0] & 0x3; + keycode_data[2] = (data[0] >> 2) & 0x3; - for (i = 1; i < touchkey_count; i++) { - if (keycode_data[i]) { - input_report_key(tkey_i2c->input_dev, touchkey_keycode[i], (keycode_data[i] % 2)); + for (i = 1; i < touchkey_count; i++) { + if (keycode_data[i]) { + input_report_key(tkey_i2c->input_dev, touchkey_keycode[i], (keycode_data[i] % 2)); #if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) - tk_debug_err(true, &tkey_i2c->client->dev, "keycode: %d %s, %#x %#x %d\n", - touchkey_keycode[i], (keycode_data[i] % 2) ? "PRESS" : "RELEASE", - tkey_i2c->fw_ver_ic, tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); + tk_debug_err(true, &tkey_i2c->client->dev, "keycode: %d %s, %#x %#x %d\n", + touchkey_keycode[i], (keycode_data[i] % 2) ? "PRESS" : "RELEASE", + tkey_i2c->fw_ver_ic, tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); #else - tk_debug_err(true, &tkey_i2c->client->dev, " %s, %#x %#x %d\n", - (keycode_data[i] % 2) ? "PRESS" : "RELEASE", tkey_i2c->fw_ver_ic, - tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); + tk_debug_err(true, &tkey_i2c->client->dev, " %s, %#x %#x %d\n", + (keycode_data[i] % 2) ? "PRESS" : "RELEASE", tkey_i2c->fw_ver_ic, + tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); #endif #if defined(CONFIG_INPUT_BOOSTER) - input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, (keycode_data[i] % 2)); + input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, (keycode_data[i] % 2)); #endif - } } + } - input_sync(tkey_i2c->input_dev); - } else { - int keycode_type = 0; - int pressed; - - keycode_type = (data[0] & TK_BIT_KEYCODE); - pressed = !(data[0] & TK_BIT_PRESS_EV); - - if (keycode_type <= 0 || keycode_type >= touchkey_count) { -#ifdef TK_SUPPORT_MT - if (keycode_type == 0x03) { - input_report_key(tkey_i2c->input_dev, - touchkey_keycode[1], pressed); - input_report_key(tkey_i2c->input_dev, - touchkey_keycode[2], pressed); - input_sync(tkey_i2c->input_dev); -#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) - tk_debug_info(true, &tkey_i2c->client->dev, "keycode(MT):%d %d pressed:%d %#x, %#x %d\n", - touchkey_keycode[1], touchkey_keycode[2], pressed, tkey_i2c->fw_ver_ic, - tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); -#else - tk_debug_info(true, &tkey_i2c->client->dev, "pressed(MT):%d %#x, %#x, %d\n", - pressed, tkey_i2c->fw_ver_ic, tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); -#endif - } else -#endif - { - tk_debug_err(true, &tkey_i2c->client->dev, "keycode_type %d err\n", keycode_type); - } - return IRQ_HANDLED; - } + input_sync(tkey_i2c->input_dev); - input_report_key(tkey_i2c->input_dev, - touchkey_keycode[keycode_type], pressed); - input_sync(tkey_i2c->input_dev); -#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) - tk_debug_info(true, &tkey_i2c->client->dev, "keycode:%d pressed:%d %#x, %#x %d\n", - touchkey_keycode[keycode_type], pressed, tkey_i2c->fw_ver_ic, - tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); -#else - tk_debug_info(true, &tkey_i2c->client->dev, "pressed:%d %#x, %#x, %d\n", - pressed, tkey_i2c->fw_ver_ic, tkey_i2c->md_ver_ic, tkey_i2c->mc_data.cur_mode); -#endif - } return IRQ_HANDLED; } @@ -1228,6 +1185,7 @@ static int touchkey_start(struct touchkey_i2c *tkey_i2c) msleep(tkey_i2c->pdata->stabilizing_time); tkey_i2c->enabled = true; + start_state = true; if (touchled_cmd_reversed) { touchled_cmd_reversed = 0; @@ -1253,6 +1211,8 @@ static int touchkey_start(struct touchkey_i2c *tkey_i2c) #endif enable_irq(tkey_i2c->irq); + start_state = false; + err_start_out: mutex_unlock(&tkey_i2c->lock); @@ -1828,6 +1788,34 @@ static ssize_t flip_cover_mode_enable(struct device *dev, return size; } #endif +static ssize_t keyboard_cover_mode_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct touchkey_i2c *tkey_i2c = dev_get_drvdata(dev); + int keyboard_mode_on; + u8 data[4] = { 0, }; + int ret; + + sscanf(buf, "%d\n", &keyboard_mode_on); + tk_debug_info(true, &tkey_i2c->client->dev, "%s %d\n", __func__, keyboard_mode_on); + + if(!tkey_is_enabled(tkey_i2c) || start_state) { + tk_debug_err(true, &tkey_i2c->client->dev, "%s skip\n", __func__); + return size; + } + + data[1] = 0x80; + data[2] = TK_BIT_WRITE_CONFIRM; + + ret = i2c_touchkey_write(tkey_i2c->client, data, 3); + if (ret < 0) { + tk_debug_err(true, &tkey_i2c->client->dev, "%s, Failed to exit autocal command.\n", __func__); + tkey_i2c->status_update = false; + } + + return size; +} static ssize_t touch_sensitivity_control(struct device *dev, struct device_attribute *attr, @@ -2048,6 +2036,8 @@ static DEVICE_ATTR(flip_mode, S_IRUGO | S_IWUSR | S_IWGRP, NULL, static DEVICE_ATTR(1mm_mode, S_IRUGO | S_IWUSR | S_IWGRP, NULL, touchkey_1mm_mode_enable); #endif +static DEVICE_ATTR(keyboard_mode, S_IRUGO | S_IWUSR | S_IWGRP, NULL, + keyboard_cover_mode_enable); static struct attribute *touchkey_attributes[] = { &dev_attr_brightness.attr, @@ -2099,6 +2089,7 @@ static struct attribute *touchkey_attributes[] = { #ifdef TKEY_FLIP_MODE &dev_attr_flip_mode.attr, #endif + &dev_attr_keyboard_mode.attr, #ifdef TKEY_1MM_MODE &dev_attr_1mm_mode.attr, #endif @@ -2147,11 +2138,8 @@ static int touchkey_pinctrl_init(struct touchkey_i2c *tkey_i2c) tk_debug_err(true, dev, "%s: Failed to configure sub_det pin\n", __func__); } - /* for h/w i2c */ - if (!tkey_i2c->pdata->i2c_gpio) { - dev = tkey_i2c->client->dev.parent->parent; - tk_debug_err(true, dev, "%s: use dev's parent\n", __func__); - } + dev = tkey_i2c->client->dev.parent->parent; + tk_debug_err(true, dev, "%s: use dev's parent\n", __func__); tkey_i2c->pinctrl_i2c = devm_pinctrl_get(dev); if (IS_ERR(tkey_i2c->pinctrl_i2c)) { @@ -2186,8 +2174,7 @@ int touchkey_pinctrl(struct touchkey_i2c *tkey_i2c, int state) int ret = 0; if (state >= I_STATE_ON_I2C) - if (false == tkey_i2c->pdata->i2c_gpio) - pinctrl = tkey_i2c->pinctrl_i2c; + pinctrl = tkey_i2c->pinctrl_i2c; ret = pinctrl_select_state(pinctrl, tkey_i2c->pin_state[state]); if (ret < 0) { diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index cd41035bc802..a2dceb836ec4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -402,8 +402,10 @@ static ssize_t wakeup_enable(struct device *dev, struct gpio_button_data *bdata = &ddata->data[i]; if (test_bit(bdata->button->code, bits)) bdata->button->wakeup = 1; - else - bdata->button->wakeup = 0; + else { + if (!bdata->button->always_wakeup) + bdata->button->wakeup = 0; + } } out: @@ -454,6 +456,8 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) #ifdef CONFIG_INPUT_BOOSTER if (button->code == KEY_HOMEPAGE) input_booster_send_event(BOOSTER_DEVICE_KEY, !!state); + if ((button->code == KEY_RECENT) || (button->code == KEY_BACK)) + input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, !!state); #endif } @@ -700,6 +704,9 @@ static void gpio_keys_close(struct input_dev *input) if (bdata->button->code == KEY_HOMEPAGE) { input_booster_send_event(BOOSTER_DEVICE_KEY, BOOSTER_MODE_FORCE_OFF); } + if ((bdata->button->code == KEY_RECENT) ||(bdata->button->code == KEY_BACK)) { + input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, BOOSTER_MODE_FORCE_OFF); + } } #endif } @@ -784,7 +791,8 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "linux,input-type", &button->type)) button->type = EV_KEY; - button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->always_wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->wakeup = button->always_wakeup; if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) diff --git a/drivers/input/misc/input_booster.c b/drivers/input/misc/input_booster.c index f551e87cd0ae..fa3105d883b4 100644 --- a/drivers/input/misc/input_booster.c +++ b/drivers/input/misc/input_booster.c @@ -1031,14 +1031,46 @@ static ssize_t input_booster_set_dvfs_time(struct device *dev, return count; } +static ssize_t input_booster_set_dvfs_control(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct booster_dvfs *dvfs = dev_get_drvdata(dev); + struct input_booster *data = dev_get_drvdata(dvfs->parent_dev); + int value; + unsigned int type; + + if (sscanf(buf, "%u%d", + &type, &value) != 2) { + dev_err(data->dev, "### Keep this format : [type value] (Ex: 2 1 ###\n"); + goto out; + } + + if (type >= BOOSTER_DEVICE_MAX) { + dev_err(data->dev, "%s : Entered type is not permitted\n", __func__); + goto out; + } + + if (value > BOOSTER_MODE_FORCE_OFF) { + dev_err(data->dev, "%s : Entered value is not permitted\n", __func__); + goto out; + } + + input_booster_send_event(type, value); + +out: + return count; +} + static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, input_booster_get_dvfs_level, input_booster_set_dvfs_level); static DEVICE_ATTR(freq, S_IRUGO | S_IWUSR, input_booster_get_dvfs_freq, input_booster_set_dvfs_freq); static DEVICE_ATTR(time, S_IRUGO | S_IWUSR, input_booster_get_dvfs_time, input_booster_set_dvfs_time); +static DEVICE_ATTR(control, S_IRUGO | S_IWUSR, NULL, input_booster_set_dvfs_control); static struct attribute *dvfs_attributes[] = { &dev_attr_level.attr, &dev_attr_freq.attr, &dev_attr_time.attr, + &dev_attr_control.attr, NULL, }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1970656a923f..3a481a8a67a7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -898,6 +898,7 @@ config TOUCHSCREEN_MXT540E module will be called mxt540e. source "drivers/input/touchscreen/synaptics_dsx/Kconfig" - +source "drivers/input/touchscreen/synaptics_dsx2/Kconfig" source "drivers/input/touchscreen/stm/Kconfig" +source "drivers/input/touchscreen/stm/fts5ad56/Kconfig" endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index c36528b578b4..944c46986be6 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX) += synaptics_dsx/ +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX2) += synaptics_dsx2/ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o @@ -75,3 +76,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_FTS) += stm/ +obj-$(CONFIG_TOUCHSCREEN_FTS5AD56) += stm/fts5ad56/ diff --git a/drivers/input/touchscreen/stm/fts5ad56/Kconfig b/drivers/input/touchscreen/stm/fts5ad56/Kconfig new file mode 100644 index 000000000000..253a3581e261 --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/Kconfig @@ -0,0 +1,12 @@ +# +# STMicroelectronics TOUCH driver configuration +# + +config TOUCHSCREEN_FTS5AD56 + tristate "STMicroelectronics i2c multitouch touchscreen with FingerTipS" + depends on I2C + help + Say Y here to enable STMicroelectronics touchscreen support. + If unsure, say N. + To compile this driver as a module, choose M here: the + module will be called STM_ts. \ No newline at end of file diff --git a/drivers/input/touchscreen/stm/fts5ad56/Makefile b/drivers/input/touchscreen/stm/fts5ad56/Makefile new file mode 100644 index 000000000000..df988cff598e --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TOUCHSCREEN_FTS5AD56) += fts_ts.o fts_fwu.o \ No newline at end of file diff --git a/drivers/input/touchscreen/stm/fts5ad56/fts_fwu.c b/drivers/input/touchscreen/stm/fts5ad56/fts_fwu.c new file mode 100644 index 000000000000..75bb183252f9 --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/fts_fwu.c @@ -0,0 +1,739 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fts_ts.h" + +#define WRITE_CHUNK_SIZE 64 +#define FTS_DEFAULT_UMS_FW "/sdcard/stm.fw" +#define FTS_DEFAULT_FFU_FW "ffu_tsp.bin" +#define FTS64FILE_SIGNATURE 0xaaaa5555 + +enum { + BUILT_IN = 0, + UMS, + NONE, + FFU, +}; + +struct fts64_header { + unsigned int signature; + unsigned short fw_ver; + unsigned char fw_id; + unsigned char reserved1; + unsigned char internal_ver[8]; + unsigned char released_ver[8]; + unsigned int reserved2; + unsigned int checksum; +}; + +static int fts_fw_wait_for_flash_ready(struct fts_ts_info *info) +{ + unsigned char regAdd; + unsigned char buf[3]; + int retry = 0; + + regAdd = FTS_CMD_READ_FLASH_STAT; + + while (info->fts_read_reg + (info, ®Add, 1, (unsigned char *)buf, 1)) { + if ((buf[0] & 0x01) == 0) + break; + + if (retry++ > FTS_RETRY_COUNT * 10) { + tsp_debug_err(true, info->dev, + "%s: Time Over\n", + __func__); + return -FTS_ERROR_TIMEOUT; + } + msleep(20); + } + + return 0; +} + +#define FW_IMAGE_SIZE_D1 64 * 1024 +#define FW_IMAGE_SIZE_D2 128 * 1024 +#define SIGNEDKEY_SIZE 256 + +static int fts_fw_burn(struct fts_ts_info *info, unsigned char *fw_data) +{ + unsigned char regAdd[WRITE_CHUNK_SIZE + 3]; + int section; + int fsize = FW_IMAGE_SIZE_D1; + + /* Check busy Flash */ + if (fts_fw_wait_for_flash_ready(info)<0) + return -1; + + /* FTS_CMD_UNLOCK_FLASH */ + tsp_debug_info(true, info->dev, "%s: Unlock Flash\n", __func__); + regAdd[0] = FTS_CMD_UNLOCK_FLASH; + regAdd[1] = 0x74; + regAdd[2] = 0x45; + info->fts_write_reg(info, ®Add[0], 3); + msleep(500); + + /* Copy to PRAM */ + if (info->digital_rev == FTS_DIGITAL_REV_2) + fsize = FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header); + + tsp_debug_info(true, info->dev, "%s: Copy to PRAM [Size : %d]\n", __func__, fsize); + + for (section = 0; section < (fsize / WRITE_CHUNK_SIZE); section++) { + regAdd[0] = FTS_CMD_WRITE_PRAM + (((section * WRITE_CHUNK_SIZE) >> 16) & 0x0f); + regAdd[1] = ((section * WRITE_CHUNK_SIZE) >> 8) & 0xff; + regAdd[2] = (section * WRITE_CHUNK_SIZE) & 0xff; + memcpy(®Add[3], + &fw_data[section * WRITE_CHUNK_SIZE + + sizeof(struct fts64_header)], + WRITE_CHUNK_SIZE); + + info->fts_write_reg(info, ®Add[0], WRITE_CHUNK_SIZE + 3); + } + + msleep(100); + + /* Erase Program Flash */ + tsp_debug_info(true, info->dev, "%s: Erase Program Flash\n", __func__); + info->fts_command(info, FTS_CMD_ERASE_PROG_FLASH); + msleep(100); + + /* Check busy Flash */ + if (fts_fw_wait_for_flash_ready(info)<0) + return -1; + + /* Burn Program Flash */ + tsp_debug_info(true, info->dev, "%s: Burn Program Flash\n", __func__); + info->fts_command(info, FTS_CMD_BURN_PROG_FLASH); + msleep(100); + + /* Check busy Flash */ + if (fts_fw_wait_for_flash_ready(info)<0) + return -1; + + /* Reset FTS */ + info->fts_systemreset(info); + return 0; +} + +static int fts_get_system_status(struct fts_ts_info *info, unsigned char *val1, unsigned char *val2) +{ + bool rc = -1; + unsigned char regAdd1[4] = { 0xb2, 0x07, 0xfb, 0x04 }; + unsigned char regAdd2[4] = { 0xb2, 0x17, 0xfb, 0x04 }; + unsigned char data[FTS_EVENT_SIZE]; + int retry = 0; + + if (info->digital_rev == FTS_DIGITAL_REV_2) + regAdd2[1] = 0x1f; + + info->fts_write_reg(info, ®Add1[0], 4); + info->fts_write_reg(info, ®Add2[0], 4); + + memset(data, 0x0, FTS_EVENT_SIZE); + regAdd1[0] = READ_ONE_EVENT; + + while (info->fts_read_reg(info, ®Add1[0], 1, (unsigned char *)data, + FTS_EVENT_SIZE)) { + if ((data[0] == 0x12) && (data[1] == regAdd1[1]) + && (data[2] == regAdd1[2])) { + rc = 0; + *val1 = data[3]; + tsp_debug_info(true, info->dev, + "%s: System Status 1 : 0x%02x\n", + __func__, data[3]); + } + else if ((data[0] == 0x12) && (data[1] == regAdd2[1]) + && (data[2] == regAdd2[2])) { + rc = 0; + *val2 = data[3]; + tsp_debug_info(true, info->dev, + "%s: System Status 2 : 0x%02x\n", + __func__, data[3]); + break; + } + + if (retry++ > FTS_RETRY_COUNT) { + rc = -1; + tsp_debug_err(true, info->dev, + "%s: Time Over\n", __func__); + break; + } + } + return rc; +} + +int fts_fw_wait_for_event(struct fts_ts_info *info, unsigned char eid) +{ + int rc; + unsigned char regAdd; + unsigned char data[FTS_EVENT_SIZE]; + int retry = 0; + + memset(data, 0x0, FTS_EVENT_SIZE); + + regAdd = READ_ONE_EVENT; + rc = -1; + while (info->fts_read_reg + (info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + if ((data[0] == EVENTID_STATUS_EVENT) && + (data[1] == eid)) { + rc = 0; + break; + } + + if (retry++ > FTS_RETRY_COUNT * 15) { + rc = -1; + tsp_debug_info(true, info->dev, "%s: Time Over\n", __func__); + break; + } + msleep(20); + } + + return rc; +} + +void fts_execute_autotune(struct fts_ts_info *info) +{ + info->fts_command(info, CX_TUNNING); + msleep(300); + fts_fw_wait_for_event(info, STATUS_EVENT_MUTUAL_AUTOTUNE_DONE); + +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event (info, STATUS_EVENT_WATER_SELF_AUTOTUNE_DONE); + fts_fw_wait_for_event(info, STATUS_EVENT_SELF_AUTOTUNE_DONE); +#endif +#ifdef FTS_SUPPORT_SELF_MODE + info->fts_command(info, SELF_AUTO_TUNE); + msleep(300); + fts_fw_wait_for_event(info, STATUS_EVENT_SELF_AUTOTUNE_DONE); +#endif + + info->fts_command(info, FTS_CMD_SAVE_CX_TUNING); + msleep(230); + fts_fw_wait_for_event(info, STATUS_EVENT_FLASH_WRITE_CXTUNE_VALUE); +} + +void fts_fw_init(struct fts_ts_info *info) +{ + info->fts_command(info, SLEEPOUT); + msleep(50); + + if (info->digital_rev == FTS_DIGITAL_REV_2) { + info->fts_command(info, FTS_CMD_TRIM_LOW_POWER_OSCILLATOR); + msleep(300); + } + + fts_execute_autotune(info); + + info->fts_command(info, SLEEPOUT); + msleep(50); + + info->fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event (info, STATUS_EVENT_FORCE_CAL_DONE); +#endif + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + info->fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif +} + +const int fts_fw_updater(struct fts_ts_info *info, unsigned char *fw_data) +{ + const struct fts64_header *header; + int retval; + int retry; + unsigned short fw_main_version; + + if (!fw_data) { + tsp_debug_err(true, info->dev, "%s: Firmware data is NULL\n", + __func__); + return -ENODEV; + } + + header = (struct fts64_header *)fw_data; + fw_main_version = (header->released_ver[0] << 8) + + (header->released_ver[1]); + + tsp_debug_info(true, info->dev, + "Starting firmware update : 0x%04X\n", + fw_main_version); + + retry = 0; + while (1) { + retval = fts_fw_burn(info, fw_data); + if (retval >= 0) { + info->fts_wait_for_ready(info); + info->fts_get_version_info(info); + +#ifdef FTS_SUPPORT_NOISE_PARAM + info->fts_get_noise_param_address(info); +#endif + + if (fw_main_version == info->fw_main_version_of_ic) { + tsp_debug_info(true, info->dev, + "%s: Success Firmware update\n", + __func__); + fts_fw_init(info); + retval = 0; + break; + } + } + + if (retry++ > 3) { + tsp_debug_err(true, info->dev, "%s: Fail Firmware update\n", + __func__); + retval = -1; + break; + } + } + + return retval; +} +EXPORT_SYMBOL(fts_fw_updater); + +#define FW_IMAGE_NAME_D2_TB_INTEG "tsp_stm/stm_tb_integ.fw" +#define FW_IMAGE_NAME_D2_Z2A "tsp_stm/stm_z2a.fw" +#define FW_IMAGE_NAME_D2_Z2I "tsp_stm/stm_z2i.fw" +#define FW_IMAGE_NAME_D2_Z1 "tsp_stm/stm_z1.fw" +#define FW_IMAGE_NAME_NOBLE "tsp_stm/noble.fw" +#define FW_IMAGE_NAME_ZEN "tsp_stm/zen.fw" + +#define CONFIG_ID_D1_S 0x2C +#define CONFIG_ID_D2_TR 0x2E +#define CONFIG_ID_D2_TB 0x30 +#define CONFIG_OFFSET_BIN_D1 0xf822 +#define CONFIG_OFFSET_BIN_D2 0x1E822 +#define RX_OFFSET_BIN_D2 0x1E834 +#define TX_OFFSET_BIN_D2 0x1E835 + +static bool fts_skip_firmware_update(struct fts_ts_info *info, unsigned char *fw_data) +{ + int config_id, num_rx, num_tx; + + config_id = fw_data[CONFIG_OFFSET_BIN_D2]; + num_rx = fw_data[RX_OFFSET_BIN_D2]; + num_tx = fw_data[TX_OFFSET_BIN_D2]; + + if (strncmp(info->board->project_name, "TB", 2) == 0) { + if (config_id != CONFIG_ID_D2_TB) { + tsp_debug_info(true, info->dev, "%s: Skip update because config ID(%0x2X) is mismatched.\n", + __func__,config_id); + // return true; // tempory blocking to update f/w for TB, it will be remove later.. Xtopher + } + + if ((num_rx != info->board->SenseChannelLength) + || (num_tx != info->board->ForceChannelLength)) { + tsp_debug_info(true, info->dev, + "%s: Skip update because revision is mismatched. rx[%d] tx[%d]\n", + __func__, num_rx, num_tx); + //return true; // tempory blocking to update f/w for TB, it will be remove later.. Xtopher + } + } else if (strncmp(info->board->project_name, "TR", 2) == 0) { + if (config_id != CONFIG_ID_D2_TR) { + tsp_debug_info(true, info->dev, + "%s: Skip update because config ID is mismatched. config_id[%d]\n", + __func__, config_id); + return true; + } + } else + goto out; + +out: + return false; +} + +int fts_fw_update_on_probe(struct fts_ts_info *info) +{ + int retval = 0; + const struct firmware *fw_entry = NULL; + unsigned char *fw_data = NULL; + char fw_path[FTS_MAX_FW_PATH]; + const struct fts64_header *header; + unsigned char SYS_STAT[2] = {0, }; + int tspid = 0; + + if (info->board->firmware_name){ + tsp_debug_err(true, info->dev,"%s:firmware name exgist in dts\n", __func__); + info->firmware_name = info->board->firmware_name; + } + else { + if(((lcdtype & LCD_ID2_MODEL_MASK) == MODEL_NOBLE) && ((lcdtype & LCD_ID3_DIC_MASK) == S6E3HA3_NOBLE) ){ + tsp_debug_err(true, info->dev,"%s:FTS5AD56 - NOBLE\n", __func__); + info->firmware_name = FW_IMAGE_NAME_NOBLE; + } + else if(((lcdtype & LCD_ID2_MODEL_MASK) == MODEL_ZEN) && ((lcdtype & LCD_ID3_DIC_MASK) == S6E3HA3_ZEN) ){ + tsp_debug_err(true, info->dev,"%s:FTS5AD56 - ZEN\n", __func__); + info->firmware_name = FW_IMAGE_NAME_ZEN; + } + else if(lcdtype == ZEN_UB_VZW){ + tsp_debug_err(true, info->dev,"%s:FTS5AD56 - ZEN\n", __func__); + info->firmware_name = FW_IMAGE_NAME_ZEN; + } + else { + /* ZERO's module is reused at NOBLE/ZEN */ + if((strncmp(info->board->project_name, "NOBLE", 5) == 0) || (strncmp(info->board->project_name, "ZEN", 3) == 0)){ + if((lcdtype == S6E3HA2_WQXGA_ZERO)||(lcdtype == S6E3HA2_WQXGA_ZERO1)||(lcdtype == S6E3HA2_WQXGA_ZERO2)){ + tsp_debug_err(true, info->dev,"%s:Reused ZEROF module\n", __func__); + info->firmware_name = FW_IMAGE_NAME_D2_Z1; // f/w name is zerof + } + else if((lcdtype & 0xf0ff00) == 0x400000){ + tsp_debug_err(true, info->dev,"%s:Reused ZEROF other module\n", __func__); + info->firmware_name = FW_IMAGE_NAME_D2_Z1; // f/w name is zerof + } + else{ + tsp_debug_err(true, info->dev,"%s:There is not avaiable firmware or model for fts5\n", __func__); + goto exit_fwload; + } + } + else{ + tsp_debug_err(true, info->dev,"%s:There is not avaiable firmware or model for fts5\n", __func__); + goto exit_fwload; + } + } + } + + snprintf(fw_path, FTS_MAX_FW_PATH, "%s", info->firmware_name); + tsp_debug_info(true, info->dev, "%s: Load firmware : %s, Digital_rev : %d, TSP_ID : %d\n", __func__, + fw_path, info->digital_rev, tspid); + retval = request_firmware(&fw_entry, fw_path, info->dev); + if (retval) { + tsp_debug_err(true, info->dev, + "%s: Firmware image %s not available\n", __func__, + fw_path); + goto done; + } + + if (info->digital_rev == FTS_DIGITAL_REV_1 && fw_entry->size!=(FW_IMAGE_SIZE_D1 + sizeof(struct fts64_header))) { + tsp_debug_err(true, info->dev, + "%s: Firmware image %s not available for FTS D1\n", __func__, + fw_path); + goto done; + } + + if (info->digital_rev == FTS_DIGITAL_REV_2 && fw_entry->size!=(FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header))) { + tsp_debug_err(true, info->dev, + "%s: Firmware image %s not available for FTS D2\n", __func__, + fw_path); + goto done; + } + + fw_data = (unsigned char *)fw_entry->data; + header = (struct fts64_header *)fw_data; + + info->fw_version_of_bin = (fw_data[5] << 8)+fw_data[4]; + info->fw_main_version_of_bin = (header->released_ver[0] << 8) + + (header->released_ver[1]); + if (info->digital_rev == FTS_DIGITAL_REV_1) + info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D1] << 8) + fw_data[CONFIG_OFFSET_BIN_D1 - 1]; + else + info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D2] << 8) + fw_data[CONFIG_OFFSET_BIN_D2 - 1]; + + tsp_debug_info(true, info->dev, + "Bin Firmware Version : 0x%04X " + "Bin Config Version : 0x%04X " + "Bin Main Version : 0x%04X\n", + info->fw_version_of_bin, + info->config_version_of_bin, + info->fw_main_version_of_bin); + + if (fts_skip_firmware_update(info, fw_data)) + goto done; + + if ((info->fw_main_version_of_ic < info->fw_main_version_of_bin) + || ((info->config_version_of_ic < info->config_version_of_bin)) + || ((info->fw_version_of_ic < info->fw_version_of_bin))) + retval = fts_fw_updater(info, fw_data); + else + retval = FTS_NOT_ERROR; + + if (fts_get_system_status(info, &SYS_STAT[0], &SYS_STAT[1]) >= 0) { + if (SYS_STAT[0] != SYS_STAT[1]) { + info->fts_systemreset(info); + msleep(20); + info->fts_wait_for_ready(info); + fts_fw_init(info); + } + } + +done: + if (fw_entry) + release_firmware(fw_entry); +exit_fwload: + return retval; +} +EXPORT_SYMBOL(fts_fw_update_on_probe); + +static int fts_load_fw_from_kernel(struct fts_ts_info *info, + const char *fw_path) +{ + int retval; + const struct firmware *fw_entry = NULL; + unsigned char *fw_data = NULL; + + if (!fw_path) { + tsp_debug_err(true, info->dev, "%s: Firmware name is not defined\n", + __func__); + return -EINVAL; + } + + tsp_debug_info(true, info->dev, "%s: Load firmware : %s\n", __func__, + fw_path); + + retval = request_firmware(&fw_entry, fw_path, info->dev); + + if (retval) { + tsp_debug_err(true, info->dev, + "%s: Firmware image %s not available\n", __func__, + fw_path); + goto done; + } + + fw_data = (unsigned char *)fw_entry->data; + + if (fts_skip_firmware_update(info, fw_data)) + goto done; + + if (info->irq) + disable_irq(info->irq); + else + hrtimer_cancel(&info->timer); + + info->fts_systemreset(info); + info->fts_wait_for_ready(info); + + retval = fts_fw_updater(info, fw_data); + if (retval) + tsp_debug_err(true, info->dev, "%s: failed update firmware\n", + __func__); + + if (info->irq) + enable_irq(info->irq); + else + hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + done: + if (fw_entry) + release_firmware(fw_entry); + + return retval; +} + +static int fts_load_fw_from_ums(struct fts_ts_info *info) +{ + struct file *fp; + mm_segment_t old_fs; + long fw_size, nread; + int error = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(FTS_DEFAULT_UMS_FW, O_RDONLY, S_IRUSR); + if (IS_ERR(fp)) { + tsp_debug_err(true, info->dev, "%s: failed to open %s.\n", __func__, + FTS_DEFAULT_UMS_FW); + error = -ENOENT; + goto open_err; + } + + fw_size = fp->f_path.dentry->d_inode->i_size; + + if (0 < fw_size) { + unsigned char *fw_data; + const struct fts64_header *header; + fw_data = kzalloc(fw_size, GFP_KERNEL); + nread = vfs_read(fp, (char __user *)fw_data, + fw_size, &fp->f_pos); + + tsp_debug_info(true, info->dev, + "%s: start, file path %s, size %ld Bytes\n", + __func__, FTS_DEFAULT_UMS_FW, fw_size); + + if (nread != fw_size) { + tsp_debug_err(true, info->dev, + "%s: failed to read firmware file, nread %ld Bytes\n", + __func__, nread); + error = -EIO; + } else { + if (fts_skip_firmware_update(info, fw_data)) + goto done; + + header = (struct fts64_header *)fw_data; + if (header->signature == FTS64FILE_SIGNATURE) { + if (info->irq) + disable_irq(info->irq); + else + hrtimer_cancel(&info->timer); + + info->fts_systemreset(info); + info->fts_wait_for_ready(info); + + tsp_debug_info(true, info->dev, + "[UMS] Firmware Version : 0x%04X " + "[UMS] Main Version : 0x%04X\n", + (fw_data[5] << 8)+fw_data[4], + (header->released_ver[0] << 8) + + (header->released_ver[1])); + + error = fts_fw_updater(info, fw_data); + + if (info->irq) + enable_irq(info->irq); + else + hrtimer_start(&info->timer, + ktime_set(1, 0), + HRTIMER_MODE_REL); + } else { + error = -1; + tsp_debug_err(true, info->dev, + "%s: File type is not match with FTS64 file. [%8x]\n", + __func__, header->signature); + } + } + + if (error < 0) + tsp_debug_err(true, info->dev, "%s: failed update firmware\n", + __func__); + +done: + kfree(fw_data); + } + + filp_close(fp, NULL); + + open_err: + set_fs(old_fs); + return error; +} + +static int fts_load_fw_from_ffu(struct fts_ts_info *info) +{ + int retval; + const struct firmware *fw_entry = NULL; + unsigned char *fw_data = NULL; + const char *fw_path = FTS_DEFAULT_FFU_FW; + const struct fts64_header *header; + + if (!fw_path) { + tsp_debug_err(true, info->dev, "%s: Firmware name is not defined\n", + __func__); + return -EINVAL; + } + + tsp_debug_info(true, info->dev, "%s: Load firmware : %s\n", __func__, + fw_path); + + retval = request_firmware(&fw_entry, fw_path, info->dev); + + if (retval) { + tsp_debug_err(true, info->dev, + "%s: Firmware image %s not available\n", __func__, + fw_path); + goto done; + } + + if ((info->digital_rev == FTS_DIGITAL_REV_2) && + (fw_entry->size != (FW_IMAGE_SIZE_D2 + sizeof(struct fts64_header) + SIGNEDKEY_SIZE))) { + tsp_debug_err(true, info->dev, + "%s: Unsigned firmware %s is not available, %ld\n", __func__, + fw_path, fw_entry->size); + retval = -EPERM; + goto done; + } + + fw_data = (unsigned char *)fw_entry->data; + header = (struct fts64_header *)fw_data; + + info->fw_version_of_bin = (fw_data[5] << 8)+fw_data[4]; + info->fw_main_version_of_bin = (header->released_ver[0] << 8) + + (header->released_ver[1]); + if (info->digital_rev == FTS_DIGITAL_REV_1) + info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D1] << 8) + fw_data[CONFIG_OFFSET_BIN_D1 - 1]; + else + info->config_version_of_bin = (fw_data[CONFIG_OFFSET_BIN_D2] << 8) + fw_data[CONFIG_OFFSET_BIN_D2 - 1]; + + tsp_debug_info(true, info->dev, + "FFU Firmware Version : 0x%04X " + "FFU Config Version : 0x%04X " + "FFU Main Version : 0x%04X\n", + info->fw_version_of_bin, + info->config_version_of_bin, + info->fw_main_version_of_bin); + + /* TODO : if you need to check firmware version between IC and Binary, + * add it this position. + */ + + if (info->irq) + disable_irq(info->irq); + else + hrtimer_cancel(&info->timer); + + info->fts_systemreset(info); + info->fts_wait_for_ready(info); + + retval = fts_fw_updater(info, fw_data); + if (retval) + tsp_debug_err(true, info->dev, "%s: failed update firmware\n", + __func__); + + if (info->irq) + enable_irq(info->irq); + else + hrtimer_start(&info->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + done: + if (fw_entry) + release_firmware(fw_entry); + + return retval; +} + +int fts_fw_update_on_hidden_menu(struct fts_ts_info *info, int update_type) +{ + int retval = 0; + + /* Factory cmd for firmware update + * argument represent what is source of firmware like below. + * + * 0 : [BUILT_IN] Getting firmware which is for user. + * 1 : [UMS] Getting firmware from sd card. + * 2 : none + * 3 : [FFU] Getting firmware from air. + */ + switch (update_type) { + case BUILT_IN: + retval = fts_load_fw_from_kernel(info, info->firmware_name); + break; + + case UMS: + retval = fts_load_fw_from_ums(info); + break; + + case FFU: + retval = fts_load_fw_from_ffu(info); + break; + + default: + tsp_debug_err(true, info->dev, "%s: Not support command[%d]\n", + __func__, update_type); + break; + } + + return retval; +} +EXPORT_SYMBOL(fts_fw_update_on_hidden_menu); + diff --git a/drivers/input/touchscreen/stm/fts5ad56/fts_sec.c b/drivers/input/touchscreen/stm/fts5ad56/fts_sec.c new file mode 100644 index 000000000000..c30c03576838 --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/fts_sec.c @@ -0,0 +1,4243 @@ +#ifdef SEC_TSP_FACTORY_TEST + +#define TSP_FACTEST_RESULT_PASS 2 +#define TSP_FACTEST_RESULT_FAIL 1 +#define TSP_FACTEST_RESULT_NONE 0 + +#define BUFFER_MAX (256 * 1024) - 16 +#define READ_CHUNK_SIZE 128 // (2 * 1024) - 16 + +enum { + TYPE_RAW_DATA = 0, + TYPE_FILTERED_DATA = 2, + TYPE_STRENGTH_DATA = 4, + TYPE_BASELINE_DATA = 6 +}; + +enum { + BUILT_IN = 0, + UMS, +}; + +enum CMD_STATUS { + CMD_STATUS_WAITING = 0, + CMD_STATUS_RUNNING, + CMD_STATUS_OK, + CMD_STATUS_FAIL, + CMD_STATUS_NOT_APPLICABLE, +}; + +#ifdef FTS_SUPPORT_TOUCH_KEY +enum { + TYPE_TOUCHKEY_RAW = 0x34, + TYPE_TOUCHKEY_STRENGTH = 0x36, + TYPE_TOUCHKEY_THRESHOLD = 0x48, +}; +#endif + +static void fw_update(void *device_data); +static void get_fw_ver_bin(void *device_data); +static void get_fw_ver_ic(void *device_data); +static void get_config_ver(void *device_data); +static void get_threshold(void *device_data); +static void module_off_master(void *device_data); +static void module_on_master(void *device_data); +static void get_chip_vendor(void *device_data); +static void get_chip_name(void *device_data); +static void get_x_num(void *device_data); +static void get_y_num(void *device_data); +static void get_checksum_data(void *device_data); +static void run_reference_read(void *device_data); +static void get_reference(void *device_data); +static void run_rawcap_read(void *device_data); +static void get_rawcap(void *device_data); +static void run_delta_read(void *device_data); +static void get_delta(void *device_data); +static void run_abscap_read(void *device_data); +static void run_absdelta_read(void *device_data); +static void run_ix_data_read(void *device_data); +static void run_ix_data_read_all(void *device_data); +static void run_self_raw_read(void *device_data); +static void run_self_raw_read_all(void *device_data); +static void run_trx_short_test(void *device_data); +static void get_cx_data(void *device_data); +static void run_cx_data_read(void *device_data); +static void get_cx_all_data(void *device_data); +static void get_strength_all_data(void *device_data); +#ifdef FTS_SUPPORT_TOUCH_KEY +static void run_key_cx_data_read(void *device_data); +#endif +static void set_tsp_test_result(void *device_data); +static void get_tsp_test_result(void *device_data); +static void hover_enable(void *device_data); +/* static void hover_no_sleep_enable(void *device_data); */ +static void glove_mode(void *device_data); +static void get_glove_sensitivity(void *device_data); +static void clear_cover_mode(void *device_data); +static void fast_glove_mode(void *device_data); +static void report_rate(void *device_data); +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +static void interrupt_control(void *device_data); +#endif + +#if defined(CONFIG_INPUT_BOOSTER) || defined(TOUCH_BOOSTER_DVFS) +static void boost_level(void *device_data); +#endif +static void set_lowpower_mode(void *device_data); +static void set_deepsleep_mode(void *device_data); +static void active_sleep_enable(void *device_data); +static void second_screen_enable(void *device_data); +static void set_longpress_enable(void *device_data); +static void set_sidescreen_x_length(void *device_data); +static void set_dead_zone(void *device_data); +static void dead_zone_enable(void *device_data); + +#ifdef SMARTCOVER_COVER +static void smartcover_cmd(void *device_data); +#endif +#ifdef FTS_SUPPORT_STRINGLIB +static void quick_shot_enable(void *device_data); +static void scrub_enable(void *device_data); +static void quick_app_access_enable(void *device_data); +static void direct_indicator_enable(void *device_data); +static void spay_enable(void *device_data); +#endif +static void delay(void *device_data); +static void debug(void *device_data); +static void run_autotune_enable(void *device_data); +static void run_autotune(void *device_data); + +static void set_mainscreen_disable(void *device_data); +static void set_rotation_status(void *device_data); + +static void not_support_cmd(void *device_data); + +static ssize_t store_cmd(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count); +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_cmd_result(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t cmd_list_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fts_scrub_position(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fts_edge_x_position(struct device *dev, + struct device_attribute *attr, char *buf); + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI +static void tui_mode_cmd(struct fts_ts_info *info); +#endif + +#ifdef FTS_SUPPROT_MULTIMEDIA +static void brush_enable(void *device_data); +static void velocity_enable(void *device_data); +#endif + +#define FT_CMD(name, func) .cmd_name = name, .cmd_func = func +struct ft_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func) (void *device_data); +}; +struct ft_cmd ft_commands[] = { + {FT_CMD("fw_update", fw_update),}, + {FT_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {FT_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {FT_CMD("get_config_ver", get_config_ver),}, + {FT_CMD("get_threshold", get_threshold),}, + {FT_CMD("module_off_master", module_off_master),}, + {FT_CMD("module_on_master", module_on_master),}, + {FT_CMD("module_off_slave", not_support_cmd),}, + {FT_CMD("module_on_slave", not_support_cmd),}, + {FT_CMD("get_chip_vendor", get_chip_vendor),}, + {FT_CMD("get_chip_name", get_chip_name),}, + {FT_CMD("get_x_num", get_x_num),}, + {FT_CMD("get_y_num", get_y_num),}, + {FT_CMD("get_checksum_data", get_checksum_data),}, + {FT_CMD("run_reference_read", run_reference_read),}, + {FT_CMD("get_reference", get_reference),}, + {FT_CMD("run_rawcap_read", run_rawcap_read),}, + {FT_CMD("get_rawcap", get_rawcap),}, + {FT_CMD("run_delta_read", run_delta_read),}, + {FT_CMD("get_delta", get_delta),}, + {FT_CMD("run_abscap_read" , run_abscap_read),}, + {FT_CMD("run_absdelta_read", run_absdelta_read),}, + {FT_CMD("run_ix_data_read", run_ix_data_read),}, + {FT_CMD("run_ix_data_read_all", run_ix_data_read_all),}, + {FT_CMD("run_self_raw_read", run_self_raw_read),}, + {FT_CMD("run_self_raw_read_all", run_self_raw_read_all),}, + {FT_CMD("run_trx_short_test", run_trx_short_test),}, + {FT_CMD("get_cx_data", get_cx_data),}, + {FT_CMD("run_cx_data_read", run_cx_data_read),}, + {FT_CMD("get_cx_all_data", get_cx_all_data),}, + {FT_CMD("get_strength_all_data", get_strength_all_data),}, +#ifdef FTS_SUPPORT_TOUCH_KEY + {FT_CMD("run_key_cx_data_read", run_key_cx_data_read),}, +#endif + {FT_CMD("set_tsp_test_result", set_tsp_test_result),}, + {FT_CMD("get_tsp_test_result", get_tsp_test_result),}, + {FT_CMD("hover_enable", hover_enable),}, + {FT_CMD("hover_no_sleep_enable", not_support_cmd),}, + {FT_CMD("glove_mode", glove_mode),}, + {FT_CMD("get_glove_sensitivity", get_glove_sensitivity),}, + {FT_CMD("clear_cover_mode", clear_cover_mode),}, + {FT_CMD("fast_glove_mode", fast_glove_mode),}, + {FT_CMD("report_rate", report_rate),}, +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + {FT_CMD("interrupt_control", interrupt_control),}, +#endif +#if defined(CONFIG_INPUT_BOOSTER)|| defined(TOUCH_BOOSTER_DVFS) + {FT_CMD("boost_level", boost_level),}, +#endif + {FT_CMD("set_lowpower_mode", set_lowpower_mode),}, + {FT_CMD("set_deepsleep_mode", set_deepsleep_mode),}, + {FT_CMD("active_sleep_enable", active_sleep_enable),}, + {FT_CMD("second_screen_enable", second_screen_enable),}, + {FT_CMD("set_longpress_enable", set_longpress_enable),}, + {FT_CMD("set_sidescreen_x_length", set_sidescreen_x_length),}, + {FT_CMD("set_dead_zone", set_dead_zone),}, + {FT_CMD("dead_zone_enable", dead_zone_enable),}, +#ifdef FTS_SUPPORT_STRINGLIB + {FT_CMD("quick_shot_enable", quick_shot_enable),}, + {FT_CMD("scrub_enable", scrub_enable),}, + {FT_CMD("quick_app_access_enable", quick_app_access_enable),}, + {FT_CMD("direct_indicator_enable", direct_indicator_enable),}, + {FT_CMD("spay_enable", spay_enable),}, +#endif +#ifdef SMARTCOVER_COVER + {FT_CMD("smartcover_cmd", smartcover_cmd),}, +#endif + {FT_CMD("delay", delay),}, + {FT_CMD("debug", debug),}, + {FT_CMD("run_autotune_enable", run_autotune_enable),}, + {FT_CMD("run_autotune", run_autotune),}, + {FT_CMD("set_mainscreen_disable", set_mainscreen_disable),}, + {FT_CMD("set_rotation_status", set_rotation_status),}, +#ifdef FTS_SUPPROT_MULTIMEDIA + {FT_CMD("brush_enable", brush_enable),}, + {FT_CMD("velocity_enable", velocity_enable),}, +#endif + {FT_CMD("not_support_cmd", not_support_cmd),}, +}; + +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd); +static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL); +static DEVICE_ATTR(cmd_list, S_IRUGO, cmd_list_show, NULL); +static DEVICE_ATTR(scrub_pos, S_IRUGO, fts_scrub_position, NULL); +static DEVICE_ATTR(edge_pos, S_IRUGO, fts_edge_x_position, NULL); + +static struct attribute *sec_touch_facotry_attributes[] = { + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, + &dev_attr_cmd_list.attr, + &dev_attr_scrub_pos.attr, + &dev_attr_edge_pos.attr, + NULL, +}; + +static struct attribute_group sec_touch_factory_attr_group = { + .attrs = sec_touch_facotry_attributes, +}; + +static int fts_check_index(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + int node; + if (info->cmd_param[0] < 0 + || info->cmd_param[0] >= info->SenseChannelLength + || info->cmd_param[1] < 0 + || info->cmd_param[1] >= info->ForceChannelLength) { + snprintf(buff, sizeof(buff), "%s", "NG"); + strncat(info->cmd_result, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_FAIL; + tsp_debug_info(true, &info->client->dev, "%s: parameter error: %u,%u\n", + __func__, info->cmd_param[0], info->cmd_param[1]); + node = -1; + return node; + } + node = info->cmd_param[1] * info->SenseChannelLength + info->cmd_param[0]; + tsp_debug_info(true, &info->client->dev, "%s: node = %d\n", __func__, node); + return node; +} + +static ssize_t fts_scrub_position(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + char buff[CMD_STR_LEN] = { 0 }; + + if (!info) { + printk(KERN_ERR "%s: No platform data found\n", + __func__); + return -EINVAL; + } + + if (!info->input_dev) { + printk(KERN_ERR "%s: No input_dev data found\n", + __func__); + return -EINVAL; + } + + tsp_debug_info(true, &info->client->dev, "%s: %d %d %d\n", + __func__, info->scrub_id, info->scrub_x, info->scrub_y); + snprintf(buff, sizeof(buff), "%d %d %d", info->scrub_id, info->scrub_x, info->scrub_y); + + info->scrub_id = 0; + info->scrub_x = 0; + info->scrub_y = 0; + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t fts_edge_x_position(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + char buff[CMD_STR_LEN] = { 0 }; + int edge_position_left, edge_position_right; + + if (!info) { + printk(KERN_ERR "%s: No platform data found\n", + __func__); + return -EINVAL; + } + + if (!info->input_dev) { + printk(KERN_ERR "%s: No input_dev data found\n", + __func__); + return -EINVAL; + } + + if ((lcdtype == S6E3HF2_WQXGA_ID1) || (lcdtype == S6E3HF2_WQXGA_ID2)) { + edge_position_left = -1; + edge_position_right = info->board->max_x + 1 - info->board->grip_area; + } else { + edge_position_left = info->board->grip_area; + edge_position_right = info->board->max_x + 1 - info->board->grip_area; + } + + tsp_debug_info(true, &info->client->dev, "%s: %d,%d\n", __func__, edge_position_left, edge_position_right); + snprintf(buff, sizeof(buff), "%d,%d", edge_position_left, edge_position_right); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static void clear_cover_cmd_work(struct work_struct *work) +{ + struct fts_ts_info *info = container_of(work, struct fts_ts_info, + cover_cmd_work.work); + + if (info->cmd_is_running) { + schedule_delayed_work(&info->cover_cmd_work, msecs_to_jiffies(5)); + } else { + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = CMD_STATUS_RUNNING; + tsp_debug_err(true, &info->client->dev, + "%s param = %d, %d\n", __func__, + info->delayed_cmd_param[0], info->delayed_cmd_param[1]); + + info->cmd_param[0] = info->delayed_cmd_param[0]; + if (info->delayed_cmd_param[0] > 1) + info->cmd_param[1] = info->delayed_cmd_param[1]; + strcpy(info->cmd, "clear_cover_mode"); + clear_cover_mode(info); + } +} + +static ssize_t store_cmd(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + char *cur, *start, *end; + char buff[CMD_STR_LEN] = { 0 }; + int len, i; + struct ft_cmd *ft_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + if (!info) { + printk(KERN_ERR "%s: No platform data found\n", + __func__); + return -EINVAL; + } + + if (!info->input_dev) { + printk(KERN_ERR "%s: No input_dev data found\n", + __func__); + return -EINVAL; + } + + if (count > CMD_STR_LEN) { + printk(KERN_ERR "%s: overflow command length\n", + __func__); + return -EINVAL; + } + + if (info->cmd_is_running == true) { + tsp_debug_err(true, &info->client->dev, "ft_cmd: other cmd is running.\n"); + if (strncmp("clear_cover_mode", buf, 16) == 0) { + cancel_delayed_work(&info->cover_cmd_work); + tsp_debug_err(true, &info->client->dev, + "[cmd is delayed] %d, param = %d, %d\n", __LINE__, buf[17]-'0', buf[19]-'0'); + info->delayed_cmd_param[0] = buf[17]-'0'; + if (info->delayed_cmd_param[0] > 1) + info->delayed_cmd_param[1] = buf[19]-'0'; + + schedule_delayed_work(&info->cover_cmd_work, msecs_to_jiffies(10)); + } + return -EBUSY; + } + else if (info->reinit_done == false) { + tsp_debug_err(true, &info->client->dev, "ft_cmd: reinit is working\n"); + if (strncmp("clear_cover_mode", buf, 16) == 0) { + cancel_delayed_work(&info->cover_cmd_work); + tsp_debug_err(true, &info->client->dev, + "[cmd is delayed] %d, param = %d, %d\n", __LINE__, buf[17]-'0', buf[19]-'0'); + info->delayed_cmd_param[0] = buf[17]-'0'; + if (info->delayed_cmd_param[0] > 1) + info->delayed_cmd_param[1] = buf[19]-'0'; + + if(info->delayed_cmd_param[0] == 0) schedule_delayed_work(&info->cover_cmd_work, msecs_to_jiffies(300)); + } + } + + /* check lock */ + mutex_lock(&info->cmd_lock); + info->cmd_is_running = true; + mutex_unlock(&info->cmd_lock); + info->cmd_state = 1; + memset(info->cmd_param, 0x00, ARRAY_SIZE(info->cmd_param)); + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + memset(info->cmd, 0x00, ARRAY_SIZE(info->cmd)); + memcpy(info->cmd, buf, len); + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + + else + memcpy(buff, buf, len); + tsp_debug_info(true, &info->client->dev, "COMMAND : %s\n", buff); + + /* find command */ + list_for_each_entry(ft_cmd_ptr, &info->cmd_list_head, list) { + if (!strncmp(buff, ft_cmd_ptr->cmd_name, CMD_STR_LEN)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(ft_cmd_ptr, &info->cmd_list_head, list) { + if (!strncmp + ("not_support_cmd", ft_cmd_ptr->cmd_name, + CMD_STR_LEN)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strnlen(buff, ARRAY_SIZE(buff))) = + '\0'; + if (kstrtoint + (buff, 10, + info->cmd_param + param_cnt) < 0) + goto err_out; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while (cur - buf <= len); + } + tsp_debug_info(true, &info->client->dev, "cmd = %s\n", ft_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) + tsp_debug_info(true, &info->client->dev, "cmd param %d= %d\n", i, + info->cmd_param[i]); + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) + tui_mode_cmd(info); + else +#endif + ft_cmd_ptr->cmd_func(info); + +err_out: + return count; +} + +static ssize_t show_cmd_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + char buff[16] = { 0 }; + + if (!info) { + printk(KERN_ERR "%s: No platform data found\n", + __func__); + return -EINVAL; + } + + if (!info->input_dev) { + printk(KERN_ERR "%s: No input_dev data found\n", + __func__); + return -EINVAL; + } + + tsp_debug_info(true, &info->client->dev, "tsp cmd: status:%d\n", info->cmd_state); + if (info->cmd_state == CMD_STATUS_WAITING) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (info->cmd_state == CMD_STATUS_RUNNING) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (info->cmd_state == CMD_STATUS_OK) + snprintf(buff, sizeof(buff), "OK"); + + else if (info->cmd_state == CMD_STATUS_FAIL) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (info->cmd_state == CMD_STATUS_NOT_APPLICABLE) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buff); +} + +static ssize_t show_cmd_result(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + if (!info) { + printk(KERN_ERR "%s: No platform data found\n", + __func__); + return -EINVAL; + } + + if (!info->input_dev) { + printk(KERN_ERR "%s: No input_dev data found\n", + __func__); + return -EINVAL; + } + + tsp_debug_info(true, &info->client->dev, "tsp cmd: result: %s\n", + info->cmd_result); + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = 0; + return snprintf(buf, TSP_BUF_SIZE, "%s\n", info->cmd_result); +} + +static ssize_t cmd_list_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + int ii = 0; + char buffer[info->cmd_buffer_size+CMD_STR_LEN]; + char buffer_name[CMD_STR_LEN]; + + snprintf(buffer, CMD_STR_LEN, "++factory command list++\n"); + while (strncmp(ft_commands[ii].cmd_name, "not_support_cmd", 16) != 0) { + snprintf(buffer_name, CMD_STR_LEN, "%s\n", ft_commands[ii].cmd_name); + strcat(buffer, buffer_name); + ii++; + } + + tsp_debug_info(true, &info->client->dev, + "%s: length : %u / %d\n", __func__, + (unsigned int)strlen(buffer), info->cmd_buffer_size+CMD_STR_LEN); + + return snprintf(buf, TSP_BUF_SIZE, "%s\n", buffer); +} + +static void set_default_result(struct fts_ts_info *info) +{ + char delim = ':'; + memset(info->cmd_result, 0x00, ARRAY_SIZE(info->cmd_result)); + memcpy(info->cmd_result, info->cmd, strnlen(info->cmd, CMD_STR_LEN)); + strncat(info->cmd_result, &delim, 1); +} + +static void set_cmd_result(struct fts_ts_info *info, char *buff, int len) +{ + strncat(info->cmd_result, buff, len); +} + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI +static void tui_mode_cmd(struct fts_ts_info *info) +{ + char buff[16] = "TUImode:FAIL"; + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} +#endif + +static void not_support_cmd(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + set_default_result(info); + snprintf(buff, sizeof(buff), "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + tsp_debug_info(true, &info->client->dev, "%s: \"%s\"\n", __func__, buff); +} + +static void fw_update(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[64] = { 0 }; + int retval = 0; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + retval = fts_fw_update_on_hidden_menu(info, info->cmd_param[0]); + + if (retval < 0) { + sprintf(buff, "%s", "NA"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_FAIL; + tsp_debug_info(true, &info->client->dev, "%s: failed [%d]\n", __func__, retval); + } else { + sprintf(buff, "%s", "OK"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: success [%d]\n", __func__, retval); + } + + return; +} + +static int fts_get_channel_info(struct fts_ts_info *info) +{ + int rc; + unsigned char cmd[4] = + { 0xB2, 0x00, 0x14, 0x02 }; + unsigned char data[FTS_EVENT_SIZE]; + int retry = 0; + + memset(data, 0x0, FTS_EVENT_SIZE); + + rc = -1; + fts_write_reg(info, &cmd[0], 4); + cmd[0]=READ_ONE_EVENT; + while (fts_read_reg + (info, &cmd[0], 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + + if (data[0] == EVENTID_RESULT_READ_REGISTER) { + if ((data[1] == cmd[1]) && (data[2] == cmd[2])) + { + info->SenseChannelLength = data[3]; + info->ForceChannelLength = data[4]; + + rc = 0; + break; + } + } + + if (retry++ > 30) { + rc = -1; + tsp_debug_info(true, &info->client->dev, "Time over - wait for channel info\n"); + break; + } + mdelay(5); + } + + return rc; +} + +static void procedure_cmd_event(struct fts_ts_info *info, unsigned char *data) +{ + char buff[16] = { 0 }; + + if ((data[1] == 0x00) && (data[2] == 0x62)) + { + snprintf(buff, sizeof(buff), "%d", + *(unsigned short *)&data[3]); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", "get_threshold", buff); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + + } + else if ((data[1] == 0x01) && (data[2] == 0xC6)) + { + snprintf(buff, sizeof(buff), "%d", + *(unsigned short *)&data[3]); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", "get_glove_sensitivity", buff); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + + } + else if ((data[1] == 0x07) && (data[2] == 0xE7)) + { + if (data[3] <= TSP_FACTEST_RESULT_PASS) { + sprintf(buff, "%s", + data[3] == TSP_FACTEST_RESULT_PASS ? "PASS" : + data[3] == TSP_FACTEST_RESULT_FAIL ? "FAIL" : "NONE"); + tsp_debug_info(true, &info->client->dev, "%s: success [%s][%d]", "get_tsp_test_result", + data[3] == TSP_FACTEST_RESULT_PASS ? "PASS" : + data[3] == TSP_FACTEST_RESULT_FAIL ? "FAIL" : + "NONE", data[3]); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + } + else + { + snprintf(buff, sizeof(buff), "%s", "NG"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_FAIL; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", + "get_tsp_test_result", + buff); + } + + } +} + +void fts_print_frame(struct fts_ts_info *info, short *min, short *max) +{ + int i = 0; + int j = 0; + unsigned char *pStr = NULL; + unsigned char pTmp[16] = { 0 }; + + pStr = kzalloc(6 * (info->SenseChannelLength + 1), GFP_KERNEL); + if (pStr == NULL) { + tsp_debug_info(true, &info->client->dev, "FTS pStr kzalloc failed\n"); + return; + } + + memset(pStr, 0x0, 6 * (info->SenseChannelLength + 1)); + snprintf(pTmp, sizeof(pTmp), " "); + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + + for (i = 0; i < info->SenseChannelLength; i++) { + snprintf(pTmp, sizeof(pTmp), "Rx%02d ", i); + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + } + + tsp_debug_info(true, &info->client->dev, "FTS %s\n", pStr); + memset(pStr, 0x0, 6 * (info->SenseChannelLength + 1)); + snprintf(pTmp, sizeof(pTmp), " +"); + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + + for (i = 0; i < info->SenseChannelLength; i++) { + snprintf(pTmp, sizeof(pTmp), "------"); + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + } + + tsp_debug_info(true, &info->client->dev, "FTS %s\n", pStr); + + for (i = 0; i < info->ForceChannelLength; i++) { + memset(pStr, 0x0, 6 * (info->SenseChannelLength + 1)); + snprintf(pTmp, sizeof(pTmp), "Tx%02d | ", i); + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + + for (j = 0; j < info->SenseChannelLength; j++) { + snprintf(pTmp, sizeof(pTmp), "%5d ", info->pFrame[(i * info->SenseChannelLength) + j]); + + if (i > 0) { + if (info->pFrame[(i * info->SenseChannelLength) + j] < *min) + *min = info->pFrame[(i * info->SenseChannelLength) + j]; + + if (info->pFrame[(i * info->SenseChannelLength) + j] > *max) + *max = info->pFrame[(i * info->SenseChannelLength) + j]; + } + strncat(pStr, pTmp, 6 * info->SenseChannelLength); + } + tsp_debug_info(true, &info->client->dev, "FTS %s\n", pStr); + } + + kfree(pStr); +} + +int fts_read_frame(struct fts_ts_info *info, unsigned char type, short *min, + short *max) +{ + unsigned char pFrameAddress[8] = + { 0xD0, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00 }; + unsigned int FrameAddress = 0; + unsigned int writeAddr = 0; + unsigned int start_addr = 0; + unsigned int end_addr = 0; + unsigned int totalbytes = 0; + unsigned int remained = 0; + unsigned int readbytes = 0xFF; + unsigned int dataposition = 0; + unsigned char *pRead = NULL; + int rc = 0; + int ret = 0; + int i = 0; + pRead = kzalloc(BUFFER_MAX, GFP_KERNEL); + + if (pRead == NULL) { + tsp_debug_info(true, &info->client->dev, "FTS pRead kzalloc failed\n"); + rc = 1; + goto ErrorExit; + } + + pFrameAddress[2] = type; + totalbytes = info->SenseChannelLength * info->ForceChannelLength * 2; + ret = fts_read_reg(info, &pFrameAddress[0], 3, pRead, pFrameAddress[3]); + + if (ret >= 0) { + if (info->digital_rev == FTS_DIGITAL_REV_1) + FrameAddress = pRead[0] + (pRead[1] << 8); + else if (info->digital_rev == FTS_DIGITAL_REV_2) + FrameAddress = pRead[1] + (pRead[2] << 8); + + start_addr = FrameAddress+info->SenseChannelLength * 2; + end_addr = start_addr + totalbytes; + } else { + tsp_debug_info(true, &info->client->dev, "FTS read failed rc = %d \n", ret); + rc = 2; + goto ErrorExit; + } + +#ifdef DEBUG_MSG + tsp_debug_info(true, &info->client->dev, "FTS FrameAddress = %X \n", FrameAddress); + tsp_debug_info(true, &info->client->dev, "FTS start_addr = %X, end_addr = %X \n", start_addr, end_addr); +#endif + + remained = totalbytes; + for (writeAddr = start_addr; writeAddr < end_addr; writeAddr += READ_CHUNK_SIZE) { + pFrameAddress[1] = (writeAddr >> 8) & 0xFF; + pFrameAddress[2] = writeAddr & 0xFF; + + if (remained >= READ_CHUNK_SIZE) + readbytes = READ_CHUNK_SIZE; + else + readbytes = remained; + + memset(pRead, 0x0, readbytes); + +#ifdef DEBUG_MSG + tsp_debug_info(true, &info->client->dev, "FTS %02X%02X%02X readbytes=%d\n", + pFrameAddress[0], pFrameAddress[1], + pFrameAddress[2], readbytes); + +#endif + if (info->digital_rev == FTS_DIGITAL_REV_1) { + fts_read_reg(info, &pFrameAddress[0], 3, pRead, readbytes); + remained -= readbytes; + + for (i = 0; i < readbytes; i += 2) { + info->pFrame[dataposition++] = + pRead[i] + (pRead[i + 1] << 8); + } + } else if (info->digital_rev == FTS_DIGITAL_REV_2) { + fts_read_reg(info, &pFrameAddress[0], 3, pRead, readbytes + 1); + remained -= readbytes; + + for (i = 1; i < (readbytes+1); i += 2) { + info->pFrame[dataposition++] = + pRead[i] + (pRead[i + 1] << 8); + } + } + } + kfree(pRead); + +#ifdef DEBUG_MSG + tsp_debug_info(true, &info->client->dev, + "FTS writeAddr = %X, start_addr = %X, end_addr = %X \n", + writeAddr, start_addr, end_addr); +#endif + + switch (type) { + case TYPE_RAW_DATA: + tsp_debug_info(true, &info->client->dev, "FTS [Raw Data : 0x%X%X] \n", pFrameAddress[0], + FrameAddress); + break; + case TYPE_FILTERED_DATA: + tsp_debug_info(true, &info->client->dev, "FTS [Filtered Data : 0x%X%X] \n", + pFrameAddress[0], FrameAddress); + break; + case TYPE_STRENGTH_DATA: + tsp_debug_info(true, &info->client->dev, "FTS [Strength Data : 0x%X%X] \n", + pFrameAddress[0], FrameAddress); + break; + case TYPE_BASELINE_DATA: + tsp_debug_info(true, &info->client->dev, "FTS [Baseline Data : 0x%X%X] \n", + pFrameAddress[0], FrameAddress); + break; + } + fts_print_frame(info, min, max); + +ErrorExit: + return rc; +} + +static int fts_panel_ito_test(struct fts_ts_info *info) +{ + unsigned char cmd = READ_ONE_EVENT; + unsigned char data[FTS_EVENT_SIZE]; + unsigned char regAdd[4] = {0xB0, 0x03, 0x60, 0xFB}; + int retry = 0; + int result = -1; + + fts_systemreset(info); + fts_wait_for_ready(info); + fts_command(info, SLEEPOUT); + fts_delay(20); + + disable_irq(info->irq); + fts_interrupt_set(info, INT_DISABLE); + fts_write_reg(info, ®Add[0], 4); + fts_command(info, FLUSHBUFFER); + fts_command(info, 0xA7); + fts_delay(200); + memset(data, 0x0, FTS_EVENT_SIZE); + while (fts_read_reg + (info, &cmd, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + + if ((data[0] == 0x0F) && (data[1] == 0x05)) { + switch (data[2]) { + case 0x00 : + result = 0; + break; + case 0x01 : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Force channel [%d] open.\n", + data[3]); + break; + case 0x02 : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Sense channel [%d] open.\n", + data[3]); + break; + case 0x03 : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Force channel [%d] short to GND.\n", + data[3]); + break; + case 0x04 : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Sense channel [%d] short to GND.\n", + data[3]); + break; + case 0x07 : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Force channel [%d] short to force.\n", + data[3]); + break; + case 0x0E : + tsp_debug_info(true, &info->client->dev, "[FTS] ITO Test result : Sennse channel [%d] short to sense.\n", + data[3]); + break; + default: + break; + } + + break; + } + + if (retry++ > 30) { + tsp_debug_info(true, &info->client->dev, "Time over - wait for result of ITO test\n"); + break; + } + fts_delay(10); + } + + fts_systemreset(info); + + /* wait for ready event */ + fts_wait_for_ready(info); + +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_set_noise_param(info); +#endif + + fts_command(info, SLEEPOUT); + fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + if (info->hover_enabled) + fts_command(info, FTS_CMD_HOVER_ON); + + if (info->flip_enable) { + fts_set_cover_type(info, true); + } else { + if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + } +#ifdef FTS_SUPPORT_TA_MODE + if (info->TA_Pluged) + fts_command(info, FTS_CMD_CHARGER_PLUGGED); +#endif + + info->touch_count = 0; + + fts_command(info, FLUSHBUFFER); + fts_interrupt_set(info, INT_ENABLE); + enable_irq(info->irq); + + return result; +} + +static void get_fw_ver_bin(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + set_default_result(info); + + if (strncmp(info->board->model_name, "G925", 4) == 0) { + info->tspid_val= gpio_get_value(info->board->tspid); + info->tspid2_val= gpio_get_value(info->board->tspid2); + + sprintf(buff, "ST%01X%01X%04X", + info->tspid_val, info->tspid2_val, + info->fw_main_version_of_bin); + } else { + sprintf(buff, "ST%02X%04X", + info->panel_revision, + info->fw_main_version_of_bin); + } + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_fw_ver_ic(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + set_default_result(info); + + if (strncmp(info->board->model_name, "G925", 4) == 0) { + info->tspid_val= gpio_get_value(info->board->tspid); + info->tspid2_val= gpio_get_value(info->board->tspid2); + + sprintf(buff, "ST%01X%01X%04X", + info->tspid_val, info->tspid2_val, + info->fw_main_version_of_ic); + } else { + sprintf(buff, "ST%02X%04X", + info->panel_revision, + info->fw_main_version_of_ic); + } + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_config_ver(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[20] = { 0 }; + + snprintf(buff, sizeof(buff), "%s_ST_%04X", + info->board->model_name ?: info->board->project_name ?: STM_DEVICE_NAME, + info->config_version_of_ic); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_threshold(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned char cmd[4] = + { 0xB2, 0x00, 0x62, 0x02 }; + int timeout=0; + + set_default_result(info); + + if (info->touch_stopped) { + char buff[CMD_STR_LEN] = { 0 }; + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_write_reg(info, &cmd[0], 4); + info->cmd_state = CMD_STATUS_RUNNING; + + while (info->cmd_state == CMD_STATUS_RUNNING) { + if (timeout++>30) { + info->cmd_state = CMD_STATUS_FAIL; + break; + } + msleep(10); + } +} + +static void module_off_master(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[3] = { 0 }; + int ret = 0; + + mutex_lock(&info->lock); + if (info->enabled) { + disable_irq(info->irq); + info->enabled = false; + } + mutex_unlock(&info->lock); + + if (info->board->power) + info->board->power(info, false); + else + ret = 1; + + if (ret == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = CMD_STATUS_OK; + else + info->cmd_state = CMD_STATUS_FAIL; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void module_on_master(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[3] = { 0 }; + int ret = 0; + + mutex_lock(&info->lock); + if (!info->enabled) { + enable_irq(info->irq); + info->enabled = true; + } + mutex_unlock(&info->lock); + + if (info->board->power) + info->board->power(info, true); + else + ret = 1; + + if (ret == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "NG"); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + if (strncmp(buff, "OK", 2) == 0) + info->cmd_state = CMD_STATUS_OK; + else + info->cmd_state = CMD_STATUS_FAIL; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_chip_vendor(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + strncpy(buff, "STM", sizeof(buff)); + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_chip_name(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + + if (info->ic_product_id) + strncpy(buff, "FTS4BD056", sizeof(buff)); + else + strncpy(buff, "FTS4BD062", sizeof(buff)); + + set_default_result(info); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_x_num(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + + set_default_result(info); + snprintf(buff, sizeof(buff), "%d", info->SenseChannelLength); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = 2; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_y_num(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + + set_default_result(info); + snprintf(buff, sizeof(buff), "%d", info->ForceChannelLength); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_checksum_data(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[16] = { 0 }; + int rc; + unsigned char regAdd[3]; + unsigned char buf[5]; + + set_default_result(info); + + regAdd[0] = 0xb3; + regAdd[1] = 0x00; + regAdd[2] = 0x01; + info->fts_write_reg(info, regAdd, 3); + fts_delay(1); + + regAdd[0] = 0xb1; + regAdd[1] = 0xEF; + regAdd[2] = 0xFC; + rc = info->fts_read_reg(info, regAdd, 3, buf, 5); + + snprintf(buff, sizeof(buff), "%02X%02X%02X%02X", buf[1], buf[2], buf[3], buf[4]); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void run_reference_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short min = 0x7FFF; + short max = 0x8000; + + set_default_result(info); + if (info->touch_stopped) { + char buff[CMD_STR_LEN] = { 0 }; + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_read_frame(info, TYPE_BASELINE_DATA, &min, &max); + snprintf(buff, sizeof(buff), "%d,%d", min, max); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_reference(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short val = 0; + int node = 0; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + node = fts_check_index(info); + if (node < 0) + return; + + val = info->pFrame[node]; + snprintf(buff, sizeof(buff), "%d", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void run_rawcap_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short min = 0x7FFF; + short max = 0x8000; + unsigned char regAdd[4] = {0xB0, 0x04, 0x49, 0x00}; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + if (!info->run_autotune && (info->digital_rev == FTS_DIGITAL_REV_2)) + goto rawcap_read; + else + tsp_debug_info(true, &info->client->dev, "%s: set autotune\n\n", __func__); + + disable_irq(info->irq); + + if (info->digital_rev == FTS_DIGITAL_REV_1) { + unsigned char data[FTS_EVENT_SIZE]; + unsigned char regAdd; + int fail_retry = 0; + + fts_interrupt_set(info, INT_DISABLE); + fts_command(info, CX_TUNNING); + fts_delay(300); + + regAdd = READ_ONE_EVENT; + while (fts_read_reg(info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + if ((data[0] == EVENTID_STATUS_EVENT) && + (data[1] == STATUS_EVENT_MUTUAL_AUTOTUNE_DONE)) { + break; + } + + if (fail_retry++ > FTS_RETRY_COUNT * 15) { + tsp_debug_info(true, info->dev, "%s: Raw data read Time Over\n", __func__); + break; + } + fts_delay(10); + } + + fts_fw_wait_for_event(info, STATUS_EVENT_MUTUAL_AUTOTUNE_DONE); + fts_fw_wait_for_event (info, STATUS_EVENT_WATER_SELF_AUTOTUNE_DONE); + + fts_interrupt_set(info, INT_ENABLE); + } else if ((info->digital_rev == FTS_DIGITAL_REV_2) +#ifdef CONFIG_SEC_DEBUG_TSP_LOG + && !info->rawdata_read_lock +#endif + ) { + fts_interrupt_set(info, INT_DISABLE); + + fts_command(info, SENSEOFF); + fts_delay(50); +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); // Key Sensor OFF + } +#endif + fts_command(info, FLUSHBUFFER); + + fts_release_all_finger(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + fts_release_all_key(info); +#endif + + fts_execute_autotune(info); + + //STMicro Auto-tune protection disable + fts_write_reg(info, regAdd, 4); + fts_delay(1); + + fts_command(info, SLEEPOUT); + fts_delay(1); + fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event (info, STATUS_EVENT_FORCE_CAL_DONE); +#endif +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + fts_interrupt_set(info, INT_ENABLE); + } + enable_irq(info->irq); + +rawcap_read: + fts_delay(50); + fts_read_frame(info, TYPE_FILTERED_DATA, &min, &max); + + snprintf(buff, sizeof(buff), "%d,%d", min, max); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_rawcap(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short val = 0; + int node = 0; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + node = fts_check_index(info); + if (node < 0) + return; + + val = info->pFrame[node]; + snprintf(buff, sizeof(buff), "%d", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void run_delta_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short min = 0x7FFF; + short max = 0x8000; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_read_frame(info, TYPE_STRENGTH_DATA, &min, &max); + snprintf(buff, sizeof(buff), "%d,%d", min, max); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_strength_all_data(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short min = 0x7FFF; + short max = 0x8000; + char all_strbuff[(info->ForceChannelLength)*(info->SenseChannelLength)*5]; + int i, j; + + memset(all_strbuff,0,sizeof(char)*((info->ForceChannelLength)*(info->SenseChannelLength)*5)); //size 5 ex(1125,) + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_read_frame(info, TYPE_STRENGTH_DATA, &min, &max); + + + for (i = 0; i < info->ForceChannelLength; i++) { + for (j = 0; j < info->SenseChannelLength; j++) { + + sprintf(buff, "%d,", info->pFrame[(i * info->SenseChannelLength) + j]); + strcat(all_strbuff, buff); + } + } + + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, all_strbuff, strnlen(all_strbuff, sizeof(all_strbuff))); + tsp_debug_info(true, &info->client->dev, "%ld (%ld)\n", strnlen(all_strbuff, sizeof(all_strbuff)),sizeof(all_strbuff)); +} + +static void get_delta(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short val = 0; + int node = 0; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + node = fts_check_index(info); + if (node < 0) + return; + + val = info->pFrame[node]; + snprintf(buff, sizeof(buff), "%d", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +void fts_read_self_frame(struct fts_ts_info *info, unsigned short oAddr) +{ + char buff[66] = {0, }; + short *data = 0; + char temp[9] = {0, }; + char temp2[512] = {0, }; + int i; + int rc; + int retry=1; + unsigned char regAdd[6] = {0xD0, 0x00, 0x00, 0xD0, 0x00, 0x00}; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + if (!info->hover_enabled) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Hover is disabled\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP Hover disabled"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + while (!info->hover_ready) { + if (retry++ > 500) { + tsp_debug_info(true, &info->client->dev, "%s: [FTS] Timeout - Abs Raw Data Ready Event\n", + __func__); + break; + } + fts_delay(10); + } + + regAdd[1] = (oAddr >> 8) & 0xff; + regAdd[2] = oAddr & 0xff; + rc = info->fts_read_reg(info, ®Add[0], 3, (unsigned char *)&buff[0], 5); + if (!rc) { + info->cmd_state = CMD_STATUS_FAIL; + return; + } + + if (info->digital_rev == FTS_DIGITAL_REV_1) { + tsp_debug_info(true, &info->client->dev, "%s: Force Address : %02x%02x\n", + __func__, buff[1], buff[0]); + tsp_debug_info(true, &info->client->dev, "%s: Sense Address : %02x%02x\n", + __func__, buff[3], buff[2]); + regAdd[1] = buff[3]; + regAdd[2] = buff[2]; + regAdd[4] = buff[1]; + regAdd[5] = buff[0]; + } else if (info->digital_rev == FTS_DIGITAL_REV_2) { + tsp_debug_info(true, &info->client->dev, "%s: Force Address : %02x%02x\n", + __func__, buff[2], buff[1]); + tsp_debug_info(true, &info->client->dev, "%s: Sense Address : %02x%02x\n", + __func__, buff[4], buff[3]); + regAdd[1] = buff[4]; + regAdd[2] = buff[3]; + regAdd[4] = buff[2]; + regAdd[5] = buff[1]; + } + + rc = info->fts_read_reg(info, ®Add[0], 3, + (unsigned char *)&buff[0], + info->SenseChannelLength * 2 + 1); + if (!rc) { + info->cmd_state = CMD_STATUS_FAIL; + return; + } + + if (info->digital_rev == FTS_DIGITAL_REV_1) + data = (short *)&buff[0]; + else + data = (short *)&buff[1]; + + memset(temp, 0x00, ARRAY_SIZE(temp)); + memset(temp2, 0x00, ARRAY_SIZE(temp2)); + + for (i = 0; i < info->SenseChannelLength; i++) { + tsp_debug_info(true, &info->client->dev, + "%s: Rx [%d] = %d\n", __func__, + i, + *data); + sprintf(temp, "%d,", *data); + strncat(temp2, temp, 9); + data++; + } + + rc = info->fts_read_reg(info, ®Add[3], 3, + (unsigned char *)&buff[0], + info->ForceChannelLength * 2 + 1); + if (!rc) { + info->cmd_state = CMD_STATUS_FAIL; + return; + } + + if (info->digital_rev == FTS_DIGITAL_REV_1) + data = (short *)&buff[0]; + else + data = (short *)&buff[1]; + + for (i = 0; i < info->ForceChannelLength; i++) { + tsp_debug_info(true, &info->client->dev, + "%s: Tx [%d] = %d\n", __func__, i, *data); + sprintf(temp, "%d,", *data); + strncat(temp2, temp, 9); + data++; + } + + set_cmd_result(info, temp2, strnlen(temp2, sizeof(temp2))); + + info->cmd_state = CMD_STATUS_OK; +} + +static void run_abscap_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_self_frame(info, 0x000E); +} + +static void run_absdelta_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_self_frame(info, 0x0012); +} + +#define FTS_F_WIX1_ADDR 0x1FE7 +#define FTS_S_WIX1_ADDR 0x1FE8 +#define FTS_F_WIX2_ADDR 0x18FD +#define FTS_S_WIX2_ADDR 0x1929 +#define FTS_WATER_SELF_RAW_ADDR 0x1A + +static void fts_read_ix_data(struct fts_ts_info *info, bool allnode) +{ + char buff[CMD_STR_LEN] = { 0 }; + + unsigned short max_tx_ix_sum = 0; + unsigned short min_tx_ix_sum = 0xFFFF; + + unsigned short max_rx_ix_sum = 0; + unsigned short min_rx_ix_sum = 0xFFFF; + + unsigned char tx_ix2[info->ForceChannelLength + 4]; + unsigned char rx_ix2[info->SenseChannelLength + 4]; + + unsigned short ix1_addr = FTS_F_WIX1_ADDR; + unsigned short ix2_tx_addr = FTS_F_WIX2_ADDR; + unsigned short ix2_rx_addr = FTS_S_WIX2_ADDR; + + unsigned char regAdd[FTS_EVENT_SIZE]; + unsigned char tx_ix1 = 0, rx_ix1 = 0; + unsigned char buf[FTS_EVENT_SIZE] = {0}; + unsigned char r_addr = READ_ONE_EVENT; + + unsigned short force_ix_data[info->ForceChannelLength * 2 + 1]; + unsigned short sense_ix_data[info->SenseChannelLength * 2 + 1]; + int buff_size,j; + char *mbuff = NULL; + int num,n,a,fzero; + char cnum; + int retry = 0, i = 0; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + +// fts_command(info, SLEEPIN); // Sleep In for INT disable + + disable_irq(info->irq); + + fts_interrupt_set(info, INT_DISABLE); + fts_command(info, SENSEOFF); + + fts_delay(50); + + #ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + } + #endif + + fts_command(info, FLUSHBUFFER); // Clear FIFO + fts_delay(50); + + regAdd[0] = 0xB2; + regAdd[1] = (ix1_addr >> 8)&0xff; + regAdd[2] = (ix1_addr&0xff); + regAdd[3] = 0x04; + + fts_write_reg(info, ®Add[0], 4); + fts_delay(1); + + retry = FTS_RETRY_COUNT * 3; + do { + if (retry < 0) { + tsp_debug_err(true, &info->client->dev, "%s: failed to compare buf,[%x][%x][%x][%x] break1!\n", + __func__, buf[1], buf[2], regAdd[1], regAdd[2]); + break; + } + fts_delay(10); + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + //read fifo + tx_ix1 = buf[3] * 2; + rx_ix1 = buf[4] * 2; + + regAdd[0] = 0xB2; + regAdd[1] = (ix2_tx_addr >>8)&0xff; + regAdd[2] = (ix2_tx_addr & 0xff); + + for (i = 0; i < info->ForceChannelLength / 4 + 1; i++) { + fts_write_reg(info, ®Add[0], 4); + fts_delay(1); + + retry = FTS_RETRY_COUNT * 3; + do { + if (retry < 0) { + tsp_debug_err(true, &info->client->dev, "%s: failed to compare buf,[%x][%x][%x][%x] break2!\n", + __func__, buf[1], buf[2], regAdd[1], regAdd[2]); + break; + } + fts_delay(10); + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + //read fifo + tx_ix2[i*4] = buf[3]; + tx_ix2[i*4+1] = buf[4]; + tx_ix2[i*4+2] = buf[5]; + tx_ix2[i*4+3] = buf[6]; + + ix2_tx_addr += 4; + regAdd[0] = 0xB2; + regAdd[1] = (ix2_tx_addr >>8)&0xff; + regAdd[2] = (ix2_tx_addr & 0xff); + } + + regAdd[0] = 0xB2; + regAdd[1] = (ix2_rx_addr >>8)&0xff; + regAdd[2] = (ix2_rx_addr & 0xff); + + for(i = 0; i < info->SenseChannelLength / 4 + 1;i++) { + fts_write_reg(info, ®Add[0], 4); + fts_delay(1); + + retry = FTS_RETRY_COUNT * 3; + do { + if (retry < 0) { + tsp_debug_err(true, &info->client->dev, "%s: failed to compare buf,[%x][%x][%x][%x] break3!\n", + __func__, buf[1], buf[2], regAdd[1], regAdd[2]); + + break; + } + fts_delay(10); + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + //read fifo + rx_ix2[i*4] = buf[3]; + rx_ix2[i*4+1] = buf[4]; + rx_ix2[i*4+2] = buf[5]; + rx_ix2[i*4+3] = buf[6]; + + ix2_rx_addr += 4; + regAdd[0] = 0xB2; + regAdd[1] = (ix2_rx_addr >>8)&0xff; + regAdd[2] = (ix2_rx_addr & 0xff); + } + + for(i = 0; i < info->ForceChannelLength; i++) { + force_ix_data[i] = tx_ix1 + tx_ix2[i]; + if(max_tx_ix_sum < tx_ix1 + tx_ix2[i] ) + max_tx_ix_sum = tx_ix1 + tx_ix2[i]; + if(min_tx_ix_sum > tx_ix1 + tx_ix2[i] ) + min_tx_ix_sum = tx_ix1 + tx_ix2[i]; + } + + for(i = 0; i < info->SenseChannelLength; i++) { + sense_ix_data[i] = rx_ix1 + rx_ix2[i]; + if(max_rx_ix_sum < rx_ix1 + rx_ix2[i] ) + max_rx_ix_sum = rx_ix1 + rx_ix2[i]; + if(min_rx_ix_sum > rx_ix1 + rx_ix2[i] ) + min_rx_ix_sum = rx_ix1 + rx_ix2[i]; + } + + tsp_debug_info(true, &info->client->dev, "%s MIN_TX_IX_SUM : %d MAX_TX_IX_SUM : %d\n", + __func__, min_tx_ix_sum, max_tx_ix_sum ); + tsp_debug_info(true, &info->client->dev, "%s MIN_RX_IX_SUM : %d MAX_RX_IX_SUM : %d\n", + __func__, min_rx_ix_sum, max_rx_ix_sum ); + + fts_systemreset(info); + fts_wait_for_ready(info); + + fts_command(info, SLEEPOUT); + fts_delay(1); + fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE); +#endif +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + enable_irq(info->irq); + fts_interrupt_set(info, INT_ENABLE); + + if(allnode == true){ + buff_size = (info->ForceChannelLength + info->SenseChannelLength + 2)*5; + mbuff = kzalloc(buff_size, GFP_KERNEL); + } + if (mbuff != NULL) { + char *pBuf = mbuff; + for(i = 0; i < info->ForceChannelLength; i++) { + num = force_ix_data[i]; + n = 100000; + fzero = 0; + for(j=5;j>0;j--){ + n = n/10; + a = num/n; + if(a) fzero = 1; + cnum = a + '0'; + num = num - a*n; + if(fzero)*pBuf++ = cnum; + } + if(!fzero) *pBuf++ = '0'; + *pBuf++ = ','; + tsp_debug_info(true, &info->client->dev, "%d ", force_ix_data[i]); + } + for(i = 0; i < info->SenseChannelLength; i++) { + num = sense_ix_data[i]; + n = 100000; + fzero = 0; + for(j=5;j>0;j--){ + n = n/10; + a = num/n; + if(a) fzero = 1; + cnum = a + '0'; + num = num - a*n; + if(fzero)*pBuf++ = cnum; + } + if(!fzero) *pBuf++ = '0'; + if(i < (info->SenseChannelLength-1)) *pBuf++ = ','; + tsp_debug_info(true, &info->client->dev, "%d ", sense_ix_data[i]); + } + + set_cmd_result(info, mbuff, buff_size); + info->cmd_state = CMD_STATUS_OK; + kfree(mbuff); + } + else { + if(allnode == true){ + snprintf(buff, sizeof(buff), "%s", "kzalloc failed"); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + } + else{ + snprintf(buff, sizeof(buff), "%d,%d,%d,%d", min_tx_ix_sum, max_tx_ix_sum, min_rx_ix_sum, max_rx_ix_sum); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); + } +} + +static void run_ix_data_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_ix_data(info, false); +} + +static void run_ix_data_read_all(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_ix_data(info, true); +} + +static void fts_read_self_raw_frame(struct fts_ts_info *info, unsigned short oAddr, bool allnode) +{ + char buff[CMD_STR_LEN] = { 0 }; + unsigned char D0_offset = 1; + unsigned char regAdd[3] = {0xD0, 0x00, 0x00}; + unsigned char ReadData[info->SenseChannelLength * 2 + 1]; + unsigned short self_force_raw_data[info->ForceChannelLength * 2 + 1]; + unsigned short self_sense_raw_data[info->SenseChannelLength * 2 + 1]; + unsigned int FrameAddress = 0; + unsigned char count=0; + int buff_size,i,j; + char *mbuff = NULL; + int num,n,a,fzero; + char cnum; + unsigned short min_tx_self_raw_data = 0xFFFF; + unsigned short max_tx_self_raw_data = 0; + unsigned short min_rx_self_raw_data = 0xFFFF; + unsigned short max_rx_self_raw_data = 0; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + +// fts_command(info, SLEEPIN); // Sleep In for INT disable + + disable_irq(info->irq); + fts_interrupt_set(info, INT_DISABLE); + fts_command(info, SENSEOFF); + + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + } +#endif + + fts_command(info, FLUSHBUFFER); // Clear FIFO + fts_delay(50); + + regAdd[1] = 0x00; + regAdd[2] = oAddr; + fts_read_reg(info, regAdd, 3, &ReadData[0], 4); + + FrameAddress = ReadData[D0_offset] + (ReadData[D0_offset + 1] << 8); // D1 : DOFFSET = 0, D2 : DOFFSET : 1 + + regAdd[1] = (FrameAddress >> 8) & 0xFF; + regAdd[2] = FrameAddress & 0xFF; + + fts_read_reg(info, regAdd, 3, &ReadData[0], info->ForceChannelLength * 2 + 1); + + for(count = 0; count < info->ForceChannelLength; count++) { + self_force_raw_data[count] = ReadData[count*2+D0_offset] + (ReadData[count*2+D0_offset+1]<<8); + + if(max_tx_self_raw_data < self_force_raw_data[count]) + max_tx_self_raw_data = self_force_raw_data[count]; + if(min_tx_self_raw_data > self_force_raw_data[count]) + min_tx_self_raw_data = self_force_raw_data[count]; + } + + regAdd[1] = 0x00; + regAdd[2] = oAddr + 2; + fts_read_reg(info, regAdd, 3, &ReadData[0], 4); + + FrameAddress = ReadData[D0_offset] + (ReadData[D0_offset + 1] << 8); // D1 : DOFFSET = 0, D2 : DOFFSET : 1 + + regAdd[1] = (FrameAddress >> 8) & 0xFF; + regAdd[2] = FrameAddress & 0xFF; + + fts_read_reg(info, regAdd, 3, &ReadData[0], info->SenseChannelLength * 2 + 1); + + for(count = 0; count < info->SenseChannelLength; count++) { + self_sense_raw_data[count] = ReadData[count*2+D0_offset] + (ReadData[count*2+D0_offset+1]<<8); + + if(max_rx_self_raw_data < self_sense_raw_data[count]) + max_rx_self_raw_data = self_sense_raw_data[count]; + if(min_rx_self_raw_data > self_sense_raw_data[count]) + min_rx_self_raw_data = self_sense_raw_data[count]; + } + + tsp_debug_info(true, &info->client->dev, "%s MIN_TX_SELF_RAW: %d MAX_TX_SELF_RAW : %d\n", + __func__, min_tx_self_raw_data, max_tx_self_raw_data ); + tsp_debug_info(true, &info->client->dev, "%s MIN_RX_SELF_RAW : %d MIN_RX_SELF_RAW : %d\n", + __func__, min_rx_self_raw_data, max_rx_self_raw_data ); + + fts_command(info, SLEEPOUT); + fts_delay(1); + fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE); +#endif +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + enable_irq(info->irq); + fts_interrupt_set(info, INT_ENABLE); + + if(allnode == true){ + buff_size = (info->ForceChannelLength + info->SenseChannelLength + 2)*5; + mbuff = kzalloc(buff_size, GFP_KERNEL); + } + if (mbuff != NULL) { + char *pBuf = mbuff; + for(i = 0; i < info->ForceChannelLength; i++) { + num = self_force_raw_data[i]; + n = 100000; + fzero = 0; + for(j=5;j>0;j--){ + n = n/10; + a = num/n; + if(a) fzero = 1; + cnum = a + '0'; + num = num - a*n; + if(fzero)*pBuf++ = cnum; + } + if(!fzero) *pBuf++ = '0'; + *pBuf++ = ','; + tsp_debug_info(true, &info->client->dev, "%d ", self_force_raw_data[i]); + } + for(i = 0; i < info->SenseChannelLength; i++) { + num = self_sense_raw_data[i]; + n = 100000; + fzero = 0; + for(j=5;j>0;j--){ + n = n/10; + a = num/n; + if(a) fzero = 1; + cnum = a + '0'; + num = num - a*n; + if(fzero)*pBuf++ = cnum; + } + if(!fzero) *pBuf++ = '0'; + if(i < (info->SenseChannelLength-1)) *pBuf++ = ','; + tsp_debug_info(true, &info->client->dev, "%d ", self_sense_raw_data[i]); + } + + + set_cmd_result(info, mbuff, buff_size); + info->cmd_state = CMD_STATUS_OK; + kfree(mbuff); + } + else { + if(allnode == true){ + snprintf(buff, sizeof(buff), "%s", "kzalloc failed"); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + } + else{ + snprintf(buff, sizeof(buff), "%d,%d,%d,%d", min_tx_self_raw_data, max_tx_self_raw_data, min_rx_self_raw_data, max_rx_self_raw_data); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); + } +} + +static void run_self_raw_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_self_raw_frame(info, FTS_WATER_SELF_RAW_ADDR,false); +} + +static void run_self_raw_read_all(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + + set_default_result(info); + fts_read_self_raw_frame(info, FTS_WATER_SELF_RAW_ADDR,true); +} + +static void run_trx_short_test(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + int ret = 0; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + disable_irq(info->irq); + ret = fts_panel_ito_test(info); + if (ret == 0) + snprintf(buff, sizeof(buff), "%s", "OK"); + else + snprintf(buff, sizeof(buff), "%s", "FAIL"); + enable_irq(info->irq); + + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +#define FTS_MAX_TX_LENGTH 44 +#define FTS_MAX_RX_LENGTH 64 + +#define FTS_CX2_READ_LENGTH 4 +#define FTS_CX2_ADDR_OFFSET 3 +#define FTS_CX2_TX_START 0 +#define FTS_CX2_BASE_ADDR 0x1000 + +static void get_cx_data(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + short val = 0; + int node = 0; + + set_default_result(info); + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + node = fts_check_index(info); + if (node < 0) + return; + + val = info->cx_data[node]; + snprintf(buff, sizeof(buff), "%d", val); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); + +} + +static void run_cx_data_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char ReadData[info->ForceChannelLength][info->SenseChannelLength + FTS_CX2_READ_LENGTH]; + unsigned char regAdd[8]; + unsigned char buf[8]; + unsigned char r_addr = READ_ONE_EVENT; + unsigned int addr, rx_num, tx_num; + int i, j, cx_rx_length, max_tx_length, max_rx_length, address_offset = 0, start_tx_offset = 0, retry = 0; + unsigned char *pStr = NULL; + unsigned char pTmp[16] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + pStr = kzalloc(4 * (info->SenseChannelLength + 1), GFP_KERNEL); + if (pStr == NULL) { + tsp_debug_info(true, &info->client->dev, "FTS pStr kzalloc failed\n"); + return; + } + + tsp_debug_info(true, &info->client->dev, "%s: start \n", __func__); + + fts_command(info, SENSEOFF); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); // Key Sensor OFF + } +#endif + disable_irq(info->irq); + fts_command(info, FLUSHBUFFER); + fts_delay(50); + + tx_num = info->ForceChannelLength; + rx_num = info->SenseChannelLength; + + if (info->digital_rev == FTS_DIGITAL_REV_1) { + max_tx_length = FTS_MAX_TX_LENGTH -4; + max_rx_length = FTS_MAX_RX_LENGTH -4; + } else { + max_tx_length = FTS_MAX_TX_LENGTH; + max_rx_length = FTS_MAX_RX_LENGTH; + } + + start_tx_offset = FTS_CX2_TX_START * max_rx_length / FTS_CX2_READ_LENGTH * FTS_CX2_ADDR_OFFSET; + address_offset = max_rx_length /FTS_CX2_READ_LENGTH; + + for(j = 0; j < tx_num; j++) { + memset(pStr, 0x0, 4 * (rx_num + 1)); + snprintf(pTmp, sizeof(pTmp), "Tx%02d | ", j); + strncat(pStr, pTmp, 4 * rx_num); + + addr = FTS_CX2_BASE_ADDR + (j * address_offset * FTS_CX2_ADDR_OFFSET) + start_tx_offset; + + if(rx_num % FTS_CX2_READ_LENGTH != 0) + cx_rx_length = rx_num / FTS_CX2_READ_LENGTH + 1; + else + cx_rx_length = rx_num / FTS_CX2_READ_LENGTH; + + for(i = 0; i < cx_rx_length; i++) { + regAdd[0] = 0xB2; + regAdd[1] = (addr >> 8) & 0xff; + regAdd[2] = (addr & 0xff); + regAdd[3] = 0x04; + fts_write_reg(info, ®Add[0], 4); + + retry = FTS_RETRY_COUNT * 3; + do { + if (retry < 0) { + tsp_debug_err(true, &info->client->dev, + "%s: failed to compare buf, break!\n", __func__); + break; + } + + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + ReadData[j][i * 4] = buf[3] & 0x3F; + ReadData[j][i * 4 + 1] = (buf[3] & 0xC0) >> 6 | (buf[4] & 0x0F) << 2; + ReadData[j][i * 4 + 2] = ((buf[4] & 0xF0)>> 4) | ((buf[5] & 0x03) << 4); + ReadData[j][i * 4 + 3] = buf[5] >> 2; + addr = addr + 3; + + snprintf(pTmp, sizeof(pTmp), "%3d%3d%3d%3d ", + ReadData[j][i*4], ReadData[j][i*4+1], ReadData[j][i*4+2], ReadData[j][i*4+3]); + strncat(pStr, pTmp, 4 *rx_num); + } + + tsp_debug_info(true, &info->client->dev, "FTS %s\n", pStr); + } + + if (info->cx_data) { + for (j = 0; j < tx_num; j++) { + for(i = 0; i < rx_num; i++) + info->cx_data[(j * rx_num) + i] = ReadData[j][i]; + } + } + + kfree(pStr); + + snprintf(buff, sizeof(buff), "%s", "OK"); + enable_irq(info->irq); + fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_ON); + } +#endif + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_cx_all_data(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char ReadData[info->ForceChannelLength][info->SenseChannelLength + FTS_CX2_READ_LENGTH]; + unsigned char regAdd[8]; + unsigned char buf[8]; + unsigned char r_addr = READ_ONE_EVENT; + unsigned int addr, rx_num, tx_num; + int i, j, cx_rx_length, max_tx_length, max_rx_length, address_offset = 0, start_tx_offset = 0, retry = 0; + char all_strbuff[(info->ForceChannelLength)*(info->SenseChannelLength)*3]; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + tsp_debug_info(true, &info->client->dev, "%s: start \n", __func__); + + fts_command(info, SENSEOFF); +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); // Key Sensor OFF + } +#endif + disable_irq(info->irq); + fts_command(info, FLUSHBUFFER); + fts_delay(50); + + tx_num = info->ForceChannelLength; + rx_num = info->SenseChannelLength; + + memset(all_strbuff,0,sizeof(char)*(tx_num*rx_num*3)); //size 3 ex(45,) + + if (info->digital_rev == FTS_DIGITAL_REV_1) { + max_tx_length = FTS_MAX_TX_LENGTH -4; + max_rx_length = FTS_MAX_RX_LENGTH -4; + } else { + max_tx_length = FTS_MAX_TX_LENGTH; + max_rx_length = FTS_MAX_RX_LENGTH; + } + + start_tx_offset = FTS_CX2_TX_START * max_rx_length / FTS_CX2_READ_LENGTH * FTS_CX2_ADDR_OFFSET; + address_offset = max_rx_length /FTS_CX2_READ_LENGTH; + + for(j = 0; j < tx_num; j++) { + addr = FTS_CX2_BASE_ADDR + (j * address_offset * FTS_CX2_ADDR_OFFSET) + start_tx_offset; + + if(rx_num % FTS_CX2_READ_LENGTH != 0) + cx_rx_length = rx_num / FTS_CX2_READ_LENGTH + 1; + else + cx_rx_length = rx_num / FTS_CX2_READ_LENGTH; + + for(i = 0; i < cx_rx_length; i++) { + regAdd[0] = 0xB2; + regAdd[1] = (addr >> 8) & 0xff; + regAdd[2] = (addr & 0xff); + regAdd[3] = 0x04; + fts_write_reg(info, ®Add[0], 4); + retry = FTS_RETRY_COUNT * 3; + do { + if (retry < 0) { + tsp_debug_err(true, &info->client->dev, + "%s: failed to compare buf, break!\n", __func__); + break; + } + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + ReadData[j][i * 4] = buf[3] & 0x3F; + ReadData[j][i * 4 + 1] = (buf[3] & 0xC0) >> 6 | (buf[4] & 0x0F) << 2; + ReadData[j][i * 4 + 2] = ((buf[4] & 0xF0)>> 4) | ((buf[5] & 0x03) << 4); + ReadData[j][i * 4 + 3] = buf[5] >> 2; + addr = addr + 3; + } + } + + if (info->cx_data) { + for (j = 0; j < tx_num; j++) { + for(i = 0; i < rx_num; i++){ + info->cx_data[(j * rx_num) + i] = ReadData[j][i]; + sprintf(buff, "%d,", ReadData[j][i]); + strcat(all_strbuff, buff); + } + } + } + + enable_irq(info->irq); + fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_ON); + } +#endif + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, all_strbuff, strnlen(all_strbuff, sizeof(all_strbuff))); + tsp_debug_info(true, &info->client->dev, "%ld (%ld)\n", strnlen(all_strbuff, sizeof(all_strbuff)),sizeof(all_strbuff)); +} + +#ifdef FTS_SUPPORT_TOUCH_KEY +#define USE_KEY_NUM 2 +static void run_key_cx_data_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char key_cx2_data[2]; + unsigned char ReadData[USE_KEY_NUM * FTS_CX2_READ_LENGTH]; + unsigned char regAdd[8]; + unsigned char buf[8]; + unsigned char r_addr = READ_ONE_EVENT; + unsigned int addr; + int i = 0, retry = 0; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + disable_irq(info->irq); + + addr = FTS_CX2_BASE_ADDR; + + regAdd[0] = 0xB2; + regAdd[1] = (addr >> 8) & 0xff; + regAdd[2] = (addr & 0xff); + regAdd[3] = 0x04; + + fts_write_reg(info, ®Add[0], 4); + fts_delay(1); + + retry = FTS_RETRY_COUNT * 10; + do { + if (retry < 0) { + tsp_debug_info(true, &info->client->dev,"%s: failed to compare buf, break!\n", __func__); + break; + } + + fts_read_reg(info, &r_addr, 1, &buf[0], FTS_EVENT_SIZE); + retry--; + } while (buf[1] != regAdd[1] || buf[2] != regAdd[2]); + + + ReadData[i * 4] = buf[3] & 0x3F; + ReadData[i * 4 + 1] = (buf[3] & 0xC0) >> 6 | (buf[4] & 0x0F) << 2; + ReadData[i * 4 + 2] = ((buf[4] & 0xF0)>> 4) | ((buf[5] & 0x03) << 4); + ReadData[i * 4 + 3] = buf[5] >> 2; + + key_cx2_data[0] = ReadData[2]; key_cx2_data[1] = ReadData[3]; + + tsp_debug_info(true, &info->client->dev, "%s: [Key 1:%d][Key 2:%d]\n", __func__, + key_cx2_data[0], key_cx2_data[1]); + + //snprintf(buff, sizeof(buff), "%s", "OK"); + snprintf(buff, sizeof(buff), "%d,%d", key_cx2_data[0], key_cx2_data[1]); + enable_irq(info->irq); + + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} +#endif + +static void set_tsp_test_result(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char regAdd[4] = {0xB0, 0x07, 0xE7, 0x00}; + + set_default_result(info); + + if (info->cmd_param[0] < TSP_FACTEST_RESULT_NONE + || info->cmd_param[0] > TSP_FACTEST_RESULT_PASS) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + return; + } + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + disable_irq(info->irq); + fts_interrupt_set(info, INT_DISABLE); + + regAdd[3] = info->cmd_param[0]; + fts_write_reg(info, ®Add[0], 4); + fts_delay(100); + fts_command(info, FTS_CMD_SAVE_FWCONFIG); + + fts_delay(230); + fts_fw_wait_for_event(info, STATUS_EVENT_FLASH_WRITE_CONFIG); + + enable_irq(info->irq); + fts_interrupt_set(info, INT_ENABLE); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_tsp_test_result(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned char cmd[4] = {0xB2, 0x07, 0xE7, 0x01}; + int timeout = 0; + + set_default_result(info); + + if (info->touch_stopped) { + char buff[CMD_STR_LEN] = { 0 }; + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_command(info, FLUSHBUFFER); + fts_write_reg(info, &cmd[0], 4); + info->cmd_state = CMD_STATUS_RUNNING; + + while (info->cmd_state == CMD_STATUS_RUNNING) { + if (timeout++>30) { + info->cmd_state = CMD_STATUS_FAIL; + break; + } + fts_delay(10); + } +} + +static void hover_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped || !(info->reinit_done) || (info->fts_power_state == FTS_POWER_STATE_LOWPOWER)) { + tsp_debug_info(true, &info->client->dev, + "%s: [ERROR] Touch is stopped:%d, reinit_done:%d, power_state:%d\n", + __func__, info->touch_stopped, info->reinit_done, info->fts_power_state); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + + if(info->cmd_param[0]==1){ + info->retry_hover_enable_after_wakeup = 1; + tsp_debug_info(true, &info->client->dev, "%s: retry_hover_on_after_wakeup \n", __func__); + } + + goto out; + } + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + int enables; + enables = info->cmd_param[0]; + if (enables == info->hover_enabled) { + tsp_debug_dbg(true, &info->client->dev, + "%s: Skip duplicate command. Hover is already %s.\n", + __func__, info->hover_enabled ? "enabled" : "disabled"); + } else { + if (enables) { + unsigned char regAdd[4] = {0xB0, 0x01, 0x29, 0x41}; + unsigned char Dly_regAdd[4] = {0xB0, 0x01, 0x72, 0x04}; + fts_write_reg(info, &Dly_regAdd[0], 4); + fts_write_reg(info, ®Add[0], 4); + fts_command(info, FTS_CMD_HOVER_ON); + info->hover_enabled = true; + info->hover_ready = false; + } else { + unsigned char Dly_regAdd[4] = {0xB0, 0x01, 0x72, 0x08}; + fts_write_reg(info, &Dly_regAdd[0], 4); + fts_command(info, FTS_CMD_HOVER_OFF); + info->hover_enabled = false; + info->hover_ready = false; + } + } + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + +out: + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +/* static void hover_no_sleep_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned char regAdd[4] = {0xB0, 0x01, 0x18, 0x00}; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]) { + regAdd[3]=0x0F; + } else { + regAdd[3]=0x08; + } + fts_write_reg(info, ®Add[0], 4); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} */ + +static void glove_mode(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + info->mshover_enabled = info->cmd_param[0]; + + if (!info->touch_stopped && info->reinit_done) { + if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + else + fts_command(info, FTS_CMD_MSHOVER_OFF); + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void get_glove_sensitivity(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned char cmd[4] = + { 0xB2, 0x01, 0xC6, 0x02 }; + int timeout=0; + + set_default_result(info); + + if (info->touch_stopped) { + char buff[CMD_STR_LEN] = { 0 }; + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + fts_write_reg(info, &cmd[0], 4); + info->cmd_state = CMD_STATUS_RUNNING; + + while (info->cmd_state == CMD_STATUS_RUNNING) { + if (timeout++>30) { + info->cmd_state = CMD_STATUS_FAIL; + break; + } + msleep(10); + } +} + +static void clear_cover_mode(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 3) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0] > 1) { + info->flip_enable = true; + info->cover_type = info->cmd_param[1]; + } else { + info->flip_enable = false; + } + + if (!info->touch_stopped && info->reinit_done) { + if (info->flip_enable) { + if (info->mshover_enabled + && (strncmp(info->board->project_name, "TB", 2) != 0)) + fts_command(info, FTS_CMD_MSHOVER_OFF); + + fts_set_cover_type(info, true); + } else { + fts_set_cover_type(info, false); + + if (info->fast_mshover_enabled) + fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); + else if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + } + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; + +static void fast_glove_mode(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + info->fast_mshover_enabled = info->cmd_param[0]; + + if (!info->touch_stopped && info->reinit_done) { + if (info->fast_mshover_enabled) + fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); + else + fts_command(info, FTS_CMD_SET_NOR_GLOVE_MODE); + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; + +static void report_rate(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 2) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0] == REPORT_RATE_90HZ) + fts_change_scan_rate(info, FTS_CMD_FAST_SCAN); + else if (info->cmd_param[0] == REPORT_RATE_60HZ) + fts_change_scan_rate(info, FTS_CMD_SLOW_SCAN); + else if (info->cmd_param[0] == REPORT_RATE_30HZ) + fts_change_scan_rate(info, FTS_CMD_USLOW_SCAN); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + +out: + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +static void interrupt_control(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + int enables; + enables = info->cmd_param[0]; + if (enables) + fts_irq_enable(info, true); + else + fts_irq_enable(info, false); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + +out: + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} +#endif + +#if defined(CONFIG_INPUT_BOOSTER) +static void boost_level(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char max_level = 4; + +#ifdef CONFIG_INPUT_BOOSTER + max_level = BOOSTER_LEVEL_MAX; +#endif + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] >= max_level) { + snprintf(buff, sizeof(buff), "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { +#ifdef CONFIG_INPUT_BOOSTER + change_booster_level_for_tsp(info->cmd_param[0]); +#endif + tsp_debug_dbg(false, &info->client->dev, + "%s %d\n", + __func__, info->cmd_param[0]); + + snprintf(buff, sizeof(buff), "OK"); + info->cmd_state = CMD_STATUS_OK; + } + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_WAITING; + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + return; +} +#endif + +bool check_lowpower_mode(struct fts_ts_info *info) +{ + bool ret = 0; + unsigned char flag = info->lowpower_flag & 0xFF; + + if (flag) + ret = 1; + + tsp_debug_info(true, &info->client->dev, + "%s: lowpower_mode flag : %d, ret:%d\n", __func__, flag, ret); + + if (flag & FTS_LOWP_FLAG_QUICK_CAM) + tsp_debug_info(true, &info->client->dev, "%s: quick cam *- on\n", __func__); + if (flag & FTS_LOWP_FLAG_2ND_SCREEN) + tsp_debug_info(true, &info->client->dev, "%s: 2nd screen on\n", __func__); + if (flag & FTS_LOWP_FLAG_BLACK_UI) + tsp_debug_info(true, &info->client->dev, "%s: swipe finger on\n", __func__); + if (flag & FTS_LOWP_FLAG_QUICK_APP_ACCESS) + tsp_debug_info(true, &info->client->dev, "%s: quick app cmd on\n", __func__); + if (flag & FTS_LOWP_FLAG_DIRECT_INDICATOR) + tsp_debug_info(true, &info->client->dev, "%s: direct indicator cmd on\n", __func__); + if (flag & FTS_LOWP_FLAG_SPAY) + tsp_debug_info(true, &info->client->dev, "%s: spay cmd on\n", __func__); + if (flag & FTS_LOWP_FLAG_TEMP_CMD) + tsp_debug_info(true, &info->client->dev, "%s: known cmd on\n", __func__); + + return ret; + +} + +static void set_lowpower_mode(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) + info->lowpower_mode = info->cmd_param[0]; +#endif + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; + +static void set_deepsleep_mode(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + info->deepsleep_mode = info->cmd_param[0]; + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; + +static void active_sleep_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + /* To do here */ + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; + + +static void second_screen_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if(info->cmd_param[0]) + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_2ND_SCREEN; + else + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_2ND_SCREEN); + +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) + info->lowpower_mode = check_lowpower_mode(info); +#endif + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void set_longpress_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char regAdd[4] = {0xB0, 0x07, 0x10, 0x03}; + int ret; + int bflag = 0; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]) + bflag = 1; + else + bflag = 0; + + if (bflag) + regAdd[3] = 0x03; + else + regAdd[3] = 0x02; + + ret = fts_write_reg(info, regAdd, 4); + + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: on/off:%d, ret: %d\n", __func__, bflag, ret); + + fts_delay(1); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void set_sidescreen_x_length(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + /* TB Side screen area length */ + unsigned char regAdd[4] = {0xB0, 0x07, 0x1C, 0xA0}; //default Side screen x length setting + int ret; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 0xA0) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + regAdd[3] = info->cmd_param[0]; // Change Side screen x length + + ret = fts_write_reg(info, regAdd, 4); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: x length:%d, ret: %d\n", __func__, regAdd[3], ret); + fts_delay(1); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void set_dead_zone(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char regAdd[2] = {0xC4, 0x00}; + int ret; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 6) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]==1) + regAdd[1] = 0x01; /* side edge top */ + else if (info->cmd_param[0]==2) + regAdd[1] = 0x02; /* side edge bottom */ + else if (info->cmd_param[0]==3) + regAdd[1] = 0x03; /* side edge All On */ + else if (info->cmd_param[0]==4) + regAdd[1] = 0x04; /* side edge Left Off */ + else if (info->cmd_param[0]==5) + regAdd[1] = 0x05; /* side edge Right Off */ + else if (info->cmd_param[0]==6) + regAdd[1] = 0x06; /* side edge All Off */ + else + regAdd[1] = 0x0; /* none */ + + ret = fts_write_reg(info, regAdd, 2); + + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: reg:%d, ret: %d\n", __func__, info->cmd_param[0], ret); + + fts_delay(1); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void dead_zone_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char regAdd[2] = {0xC2, 0x0C}; + int ret; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]==0) { + regAdd[0] = 0xC1; /* dead zone disable */ + } else { + regAdd[0] = 0xC2; /* dead zone enable */ + } + + ret = fts_write_reg(info, regAdd, 2); + + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: reg:%d, ret: %d\n", __func__, info->cmd_param[0], ret); + + fts_delay(1); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void set_mainscreen_disable_cmd(struct fts_ts_info *info, bool on) +{ + int ret; + unsigned char regAdd[2] = {0xC2, 0x07}; + + if (on){ + regAdd[0] = 0xC1; // main screen disable + info->mainscr_disable = true; + }else{ + regAdd[0] = 0xC2; // enable like normal + info->mainscr_disable = false; + } + + ret = fts_write_reg(info, regAdd, 2); + + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: reg:%d, ret: %d\n", __func__, info->cmd_param[0], ret); + fts_delay(1); +} + +static void set_mainscreen_disable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 2) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]==1){ + set_mainscreen_disable_cmd(info, 1); + }else{ + set_mainscreen_disable_cmd(info, 0); + } + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +#ifdef SMARTCOVER_COVER +void change_smartcover_table(struct fts_ts_info *info) +{ + u8 i, j, k, h, temp, temp_sum; + + for(i=0; ichanged_table[j][i] = info->smart_cover[i][j]; + + #if 1 // debug + tsp_debug_info(true, &info->client->dev, "%s smart_cover value\n", __func__); + for(i=0; ismart_cover[i][j]); + pr_cont("\n"); + } + + tsp_debug_info(true, &info->client->dev, "%s changed_table value\n", __func__); + for(j=0; jchanged_table[j][i]); + pr_cont("\n"); + } + #endif + + tsp_debug_info(true, &info->client->dev, "%s %d\n", __func__, __LINE__); + + for(i=0; isend_table[i][j] = 0; + tsp_debug_info(true, &info->client->dev, "%s %d\n", __func__, __LINE__); + + for(i=0; ichanged_table[i][j]; + if(temp == 0 ) continue; + + for(k=0; k<4; k++){ + temp_sum = 0; + for(h=0; h<8; h++){ + temp_sum += ((u8)(info->changed_table[i][h+8*k])) << (7-h); + } + info->send_table[i][k] = temp_sum; + } + + tsp_debug_info(true, &info->client->dev, "i:%2d, %2X %2X %2X %2X \n", \ + i,info->send_table[i][0],info->send_table[i][1],info->send_table[i][2],info->send_table[i][3]); + } + tsp_debug_info(true, &info->client->dev, "%s %d\n", __func__, __LINE__); + + +} +void set_smartcover_mode(struct fts_ts_info *info, bool on) +{ + int ret; + unsigned char regMon[2] = {0xC1, 0x0A}; + unsigned char regMoff[2] = {0xC2, 0x0A}; + + if(on ==1){ + ret = fts_write_reg(info, regMon, 2); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s mode on failed. ret: %d\n", __func__, ret); + }else{ + ret = fts_write_reg(info, regMoff, 2); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s mode off failed. ret: %d\n", __func__, ret); + } +} +void set_smartcover_clear(struct fts_ts_info *info) +{ + int ret; + unsigned char regClr[6] = {0xC5, 0xFF, 0x00, 0x00, 0x00, 0x00}; + + ret = fts_write_reg(info, regClr, 6); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s data clear failed. ret: %d\n", __func__, ret); +} + + +void set_smartcover_data(struct fts_ts_info *info) +{ + int ret; + u8 i, j; + u8 temp=0; + unsigned char regData[6] = {0xC5, 0x00, 0x00, 0x00, 0x00, 0x00}; + + + for(i=0; isend_table[i][j]; + if(temp == 0 ) continue; + + regData[1] = i; + + for(j=0; j<4; j++) + regData[2+j] = info->send_table[i][j]; + + tsp_debug_info(true, &info->client->dev, "i:%2d, %2X %2X %2X %2X \n", \ + regData[1],regData[2],regData[3],regData[4], regData[5]); + + // data write + ret = fts_write_reg(info, regData, 6); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s data write[%d] failed. ret: %d\n", __func__,i, ret); + + + } + +} + +/* #################################################### + func : smartcover_cmd [0] [1] [2] [3] + index 0 + vlaue 0 : off (normal) + vlaue 1 : off (globe mode) + vlaue 2 : X + vlaue 3 : on + clear -> data send(send_table value) -> mode on + vlaue 4 : clear smart_cover value + vlaue 5 : data save to smart_cover value + index 1 : tx channel num + index 2 : data 0xFF + index 3 : data 0xFF + value 6 : table value change, smart_cover -> changed_table -> send_table + + ex) + // clear + echo smartcover_cmd,4 > cmd + // data write (hart) + echo smartcover_cmd,5,3,16,16 > cmd + echo smartcover_cmd,5,4,56,56 > cmd + echo smartcover_cmd,5,5,124,124 > cmd + echo smartcover_cmd,5,6,126,252 > cmd + echo smartcover_cmd,5,7,127,252 > cmd + echo smartcover_cmd,5,8,63,248 > cmd + echo smartcover_cmd,5,9,31,240 > cmd + echo smartcover_cmd,5,10,15,224 > cmd + echo smartcover_cmd,5,11,7,192 > cmd + echo smartcover_cmd,5,12,3,128 > cmd + // data change + echo smartcover_cmd,6 > cmd + // mode on + echo smartcover_cmd,3 > cmd + +###################################################### */ + +void smartcover_cmd(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + u8 i, j, t; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 6) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + + if(info->cmd_param[0]==0){ // off + + set_smartcover_mode(info, 0); + tsp_debug_info(true, &info->client->dev, "%s mode off, normal\n", __func__); + + } else if(info->cmd_param[0]==1){ // off, globe mode + + set_smartcover_mode(info, 0); + tsp_debug_info(true, &info->client->dev, "%s mode off, globe mode\n", __func__); + + if (info->fast_mshover_enabled) + fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); + else if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + + } else if(info->cmd_param[0]==3){ // on + + set_smartcover_clear(info); + set_smartcover_data(info); + tsp_debug_info(true, &info->client->dev, "%s data send\n", __func__); + set_smartcover_mode(info, 1); + tsp_debug_info(true, &info->client->dev, "%s mode on\n", __func__); + + } else if(info->cmd_param[0]==4){ // clear + + for(i=0; ismart_cover[i][j] = 0; + tsp_debug_info(true, &info->client->dev, "%s data clear\n", __func__); + + } else if(info->cmd_param[0]==5){ // data write + + if(info->cmd_param[1]<0 || info->cmd_param[1]>= 32){ + tsp_debug_info(true, &info->client->dev, "%s data tx size is over[%d]\n", \ + __func__,info->cmd_param[1]); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + goto fail; + } + tsp_debug_info(true, &info->client->dev, "%s data %2X, %2X, %2X\n", __func__, \ + info->cmd_param[1],info->cmd_param[2],info->cmd_param[3] ); + + t = info->cmd_param[1]; + info->smart_cover[t][0] = (info->cmd_param[2]&0x80)>>7; + info->smart_cover[t][1] = (info->cmd_param[2]&0x40)>>6; + info->smart_cover[t][2] = (info->cmd_param[2]&0x20)>>5; + info->smart_cover[t][3] = (info->cmd_param[2]&0x10)>>4; + info->smart_cover[t][4] = (info->cmd_param[2]&0x08)>>3; + info->smart_cover[t][5] = (info->cmd_param[2]&0x04)>>2; + info->smart_cover[t][6] = (info->cmd_param[2]&0x02)>>1; + info->smart_cover[t][7] = (info->cmd_param[2]&0x01); + info->smart_cover[t][8] = (info->cmd_param[3]&0x80)>>7; + info->smart_cover[t][9] = (info->cmd_param[3]&0x40)>>6; + info->smart_cover[t][10] = (info->cmd_param[3]&0x20)>>5; + info->smart_cover[t][11] = (info->cmd_param[3]&0x10)>>4; + info->smart_cover[t][12] = (info->cmd_param[3]&0x08)>>3; + info->smart_cover[t][13] = (info->cmd_param[3]&0x04)>>2; + info->smart_cover[t][14] = (info->cmd_param[3]&0x02)>>1; + info->smart_cover[t][15] = (info->cmd_param[3]&0x01); + + } else if(info->cmd_param[0]==6){ // data change + + change_smartcover_table(info); + tsp_debug_info(true, &info->client->dev, "%s data change\n", __func__); + + } else { + + tsp_debug_info(true, &info->client->dev, "%s cmd[%d] not use\n", __func__, info->cmd_param[0] ); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + goto fail; + + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } +fail: + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +}; +#endif + +static void set_rotation_status(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 3) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + int status = info->cmd_param[0] % 2; + + if (status) + fts_enable_feature(info, FTS_FEATURE_DUAL_SIDE_GUSTURE, true); + else + fts_enable_feature(info, FTS_FEATURE_DUAL_SIDE_GUSTURE, false); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +#ifdef FTS_SUPPORT_STRINGLIB +static void quick_shot_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (info->cmd_param[0]) { + info->fts_mode |= FTS_MODE_QUICK_SHOT; + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_QUICK_CAM; + } else { + info->fts_mode &= ~FTS_MODE_QUICK_SHOT; + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_QUICK_CAM); + } + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) { + dev_err(&info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + + goto out; + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + +out: + info->lowpower_mode = check_lowpower_mode(info); + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void scrub_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + char buff[CMD_STR_LEN] = { 0 }; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + set_default_result(info); + + if (info->cmd_param[0]) { + info->fts_mode |= FTS_MODE_SCRUB; + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_BLACK_UI; + + } else { + info->fts_mode &= ~FTS_MODE_SCRUB; + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_BLACK_UI); + } + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) { + dev_err(&info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + + goto out; + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + +out: + info->lowpower_mode = check_lowpower_mode(info); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void quick_app_access_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + char buff[CMD_STR_LEN] = { 0 }; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + set_default_result(info); + + if (info->cmd_param[0]) { + info->fts_mode |= FTS_MODE_QUICK_APP_ACCESS; + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_QUICK_APP_ACCESS; + + } else { + info->fts_mode &= ~FTS_MODE_QUICK_APP_ACCESS; + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_QUICK_APP_ACCESS); + } + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) { + dev_err(&info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + + goto out; + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + +out: + info->lowpower_mode = check_lowpower_mode(info); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void direct_indicator_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + char buff[CMD_STR_LEN] = { 0 }; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + set_default_result(info); + + if (info->cmd_param[0]) { + info->fts_mode |= FTS_MODE_DIRECT_INDICATOR; + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_DIRECT_INDICATOR; + + } else { + info->fts_mode &= ~FTS_MODE_DIRECT_INDICATOR; + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_DIRECT_INDICATOR); + } + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) { + dev_err(&info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + + goto out; + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + +out: + info->lowpower_mode = check_lowpower_mode(info); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void spay_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + char buff[CMD_STR_LEN] = { 0 }; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + set_default_result(info); + + if (info->cmd_param[0]) { + info->fts_mode |= FTS_MODE_SPAY; + info->lowpower_flag = info->lowpower_flag | FTS_LOWP_FLAG_SPAY; + } else { + info->fts_mode &= ~FTS_MODE_SPAY; + info->lowpower_flag = info->lowpower_flag & ~(FTS_LOWP_FLAG_SPAY); + } + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) { + tsp_debug_info(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + + goto out; + } + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + +out: + info->lowpower_mode = check_lowpower_mode(info); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} +#endif + +#ifdef FTS_SUPPROT_MULTIMEDIA +static void brush_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char value; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 2) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + }else { + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + + if (info->brush_enable != (info->cmd_param[0]? true : false)){ + info->brush_enable = info->cmd_param[0] ? true : false; + } + tsp_debug_info(true, &info->client->dev, "%s: brush_enable[%d] \n", __func__, info->brush_enable); + + value = info->cmd_param[0] ? 0x01 : 0x00; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + + +static void velocity_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char value; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 2) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + }else { + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + + if (info->velocity_enable != (info->cmd_param[0]? true : false)){ + info->velocity_enable = info->cmd_param[0] ? true : false; + } + tsp_debug_info(true, &info->client->dev, "%s: velocity_enable[%d] \n", __func__, info->velocity_enable); + + value = info->cmd_param[0] ? 0x01 : 0x00; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} +#endif + +static void delay(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + info->delay_time = info->cmd_param[0]; + + tsp_debug_info(true, &info->client->dev, "%s: delay time is %d\n", __func__, info->delay_time); + snprintf(buff, sizeof(buff), "%d", info->delay_time); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void debug(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + info->debug_string = info->cmd_param[0]; + + tsp_debug_info(true, &info->client->dev, "%s: command is %d\n", __func__, info->debug_string); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void run_autotune_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + info->run_autotune = info->cmd_param[0]; + + tsp_debug_info(true, &info->client->dev, "%s: command is %s\n", + __func__, info->run_autotune ? "ENABLE" : "DISABLE"); + + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + +static void run_autotune(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + + set_default_result(info); + + if (info->touch_stopped) { + dev_info(&info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + } + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + if (!info->run_autotune){ + tsp_debug_info(true, &info->client->dev, "%s: autotune is disabled, %d\n", __func__, info->run_autotune); + goto autotune_fail; + } + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG + if(info->rawdata_read_lock == 1){ + tsp_debug_info(true, &info->client->dev, "%s: ramdump mode is runing, %d\n", __func__, info->rawdata_read_lock); + goto autotune_fail; + } +#endif + + disable_irq(info->irq); + + if (info->digital_rev == FTS_DIGITAL_REV_2) { + fts_interrupt_set(info, INT_DISABLE); + + fts_command(info, SENSEOFF); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + } +#endif + fts_command(info, FLUSHBUFFER); + + fts_release_all_finger(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + fts_release_all_key(info); +#endif + + fts_execute_autotune(info); + + fts_command(info, SLEEPOUT); + fts_delay(1); + fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE); +#endif +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + fts_interrupt_set(info, INT_ENABLE); + }else { + tsp_debug_info(true, &info->client->dev, "%s: digital_rev not matched, %d\n", __func__, info->digital_rev); + goto autotune_fail; + } + + enable_irq(info->irq); + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); + return; + +autotune_fail: + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); + return; +} + +#ifdef FTS_SUPPORT_TOUCH_KEY +int read_touchkey_data(struct fts_ts_info *info, unsigned char type, unsigned int keycode) +{ + unsigned char pCMD[3] = { 0xD0, 0x00, 0x00}; + unsigned char buf[9] = { 0 }; + int i; + int ret = 0; + + pCMD[2] = type; + + ret = fts_read_reg(info, &pCMD[0], 3, buf, 3); + if (ret >= 0) { + if (info->digital_rev == FTS_DIGITAL_REV_1) { + pCMD[1] = buf[1]; + pCMD[2] = buf[0]; + } + else { + pCMD[1] = buf[2]; + pCMD[2] = buf[1]; + } + } else + return -1; + + ret = fts_read_reg(info, &pCMD[0], 3, buf, 9); + if (ret < 0) + return -2; + + for (i = 0 ; i < info->board->num_touchkey ; i++) + if (info->board->touchkey[i].keycode == keycode) { + if (info->digital_rev == FTS_DIGITAL_REV_1) + return *(short *)&buf[(info->board->touchkey[i].value - 1) * 2]; + else + return *(short *)&buf[(info->board->touchkey[i].value - 1) * 2 + 1]; + } + + return -3; +} + +static ssize_t touchkey_recent_strength(struct device *dev, + struct device_attribute *attr, char *buf) { + struct fts_ts_info *info = dev_get_drvdata(dev); + int value = 0; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + return sprintf(buf, "%d\n", value); + } + + value = read_touchkey_data(info, TYPE_TOUCHKEY_STRENGTH, KEY_RECENT); + + return sprintf(buf, "%d\n", value); +} + +static ssize_t touchkey_back_strength(struct device *dev, + struct device_attribute *attr, char *buf) { + struct fts_ts_info *info = dev_get_drvdata(dev); + int value = 0; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + return sprintf(buf, "%d\n", value); + } + + value = read_touchkey_data(info, TYPE_TOUCHKEY_STRENGTH, KEY_BACK); + + return sprintf(buf, "%d\n", value); +} + +static ssize_t touchkey_recent_raw(struct device *dev, + struct device_attribute *attr, char *buf) { + struct fts_ts_info *info = dev_get_drvdata(dev); + int value = 0; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + return sprintf(buf, "%d\n", value); + } + + value = read_touchkey_data(info, TYPE_TOUCHKEY_RAW, KEY_RECENT); + + return sprintf(buf, "%d\n", value); +} + +static ssize_t touchkey_back_raw(struct device *dev, + struct device_attribute *attr, char *buf) { + struct fts_ts_info *info = dev_get_drvdata(dev); + int value = 0; + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); + return sprintf(buf, "%d\n", value); + } + + value = read_touchkey_data(info, TYPE_TOUCHKEY_RAW, KEY_BACK); + + return sprintf(buf, "%d\n", value); +} + +static ssize_t touchkey_threshold(struct device *dev, + struct device_attribute *attr, char *buf) { + struct fts_ts_info *info = dev_get_drvdata(dev); + unsigned char pCMD[3] = { 0xD0, 0x00, 0x00}; + int value; + int ret = 0; + + value = -1; + pCMD[2] = TYPE_TOUCHKEY_THRESHOLD; + ret = fts_read_reg(info, &pCMD[0], 3, buf, 3); + if (ret >= 0) { + if (info->digital_rev == FTS_DIGITAL_REV_1) + value = *(unsigned short *)&buf[0]; + else + value = *(unsigned short *)&buf[1]; + } + + info->touchkey_threshold = value; + return sprintf(buf, "%d\n", info->touchkey_threshold); +} + +static ssize_t fts_touchkey_led_control(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + int data, ret; + + ret = sscanf(buf, "%d", &data); + tsp_debug_dbg(true, &info->client->dev, "%s, %d\n", __func__, data); + + if (ret != 1) { + tsp_debug_err(true, &info->client->dev, "%s, %d err\n", + __func__, __LINE__); + return size; + } + + if (data != 0 && data != 1) { + tsp_debug_err(true, &info->client->dev, "%s wrong cmd %x\n", + __func__, data); + return size; + } + + ret = info->board->led_power(info, (bool)data); + if (ret) { + tsp_debug_err(true, &info->client->dev, "%s: Error turn on led %d\n", + __func__, ret); + + goto out; + } + msleep(30); + +out: + return size; +} + +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, NULL, fts_touchkey_led_control); +static DEVICE_ATTR(touchkey_recent, S_IRUGO, touchkey_recent_strength, NULL); +static DEVICE_ATTR(touchkey_back, S_IRUGO, touchkey_back_strength, NULL); +static DEVICE_ATTR(touchkey_recent_raw, S_IRUGO, touchkey_recent_raw, NULL); +static DEVICE_ATTR(touchkey_back_raw, S_IRUGO, touchkey_back_raw, NULL); +static DEVICE_ATTR(touchkey_threshold, S_IRUGO, touchkey_threshold, NULL); + +static struct attribute *sec_touchkey_factory_attributes[] = { + &dev_attr_touchkey_recent.attr, + &dev_attr_touchkey_back.attr, + &dev_attr_touchkey_recent_raw.attr, + &dev_attr_touchkey_back_raw.attr, + &dev_attr_touchkey_threshold.attr, + &dev_attr_brightness.attr, + NULL, +}; + +static struct attribute_group sec_touchkey_factory_attr_group = { + .attrs = sec_touchkey_factory_attributes, +}; +#endif + +#endif diff --git a/drivers/input/touchscreen/stm/fts5ad56/fts_ts.c b/drivers/input/touchscreen/stm/fts5ad56/fts_ts.c new file mode 100644 index 000000000000..b185118d723e --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/fts_ts.c @@ -0,0 +1,2975 @@ +/******************** (C) COPYRIGHT 2012 STMicroelectronics ******************** +* +* File Name : fts.c +* Authors : AMS(Analog Mems Sensor) Team +* Description : FTS Capacitive touch screen controller (FingerTipS) +* +******************************************************************************** +* +* 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. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. +******************************************************************************** +* REVISON HISTORY +* DATE | DESCRIPTION +* 03/09/2012| First Release +* 08/11/2012| Code migration +* 23/01/2013| SEC Factory Test +* 29/01/2013| Support Hover Events +* 08/04/2013| SEC Factory Test Add more - hover_enable, glove_mode, clear_cover_mode, fast_glove_mode +* 09/04/2013| Support Blob Information +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI +#include +#endif + +#ifdef CONFIG_OF +#ifndef USE_OPEN_CLOSE +#define USE_OPEN_CLOSE +#undef CONFIG_HAS_EARLYSUSPEND +#undef CONFIG_PM +#endif +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include "fts_ts.h" + +static struct i2c_driver fts_i2c_driver; + +#ifdef FTS_SUPPORT_TOUCH_KEY +struct fts_touchkey fts_touchkeys[] = { + { + .value = 0x01, + .keycode = KEY_RECENT, + .name = "recent", + }, + { + .value = 0x02, + .keycode = KEY_BACK, + .name = "back", + }, +}; +#endif + +#ifdef CONFIG_GLOVE_TOUCH +enum TOUCH_MODE { + FTS_TM_NORMAL = 0, + FTS_TM_GLOVE, +}; +#endif + +#ifdef FTS_SUPPROT_MULTIMEDIA +/* Brush Table : 230= 255-25 step */ +short tableX[2][256] = + {{ + 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + + 15, 15, 15, 20, 20, 23, 24, 30, 33, 34, 40, + 44, 45, 50, 53, 54, 57, 62, 66, 67, 72, + 78, 84, 87, 92, 96, 98, 100, 102, 104, 106, + 109, 112, 115, 118, 121, 124, 127, 130, 133, 136, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, //100 + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, + 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, //200 + 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 320, 320, 320, 320, 320 + }, + { + + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, //100 + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, //200 + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127 + } }; +#endif + +#ifdef USE_OPEN_CLOSE +static int fts_input_open(struct input_dev *dev); +static void fts_input_close(struct input_dev *dev); +#ifdef USE_OPEN_DWORK +static void fts_open_work(struct work_struct *work); +#endif +#endif + +static int fts_stop_device(struct fts_ts_info *info); +static int fts_start_device(struct fts_ts_info *info); +static int fts_irq_enable(struct fts_ts_info *info, bool enable); +static void fts_reset_work(struct work_struct *work); +void fts_recovery_cx(struct fts_ts_info *info); +void fts_release_all_finger(struct fts_ts_info *info); + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +static void dump_tsp_rawdata(struct work_struct *work); +struct delayed_work * p_debug_work; +#endif + +#if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) +static int fts_suspend(struct i2c_client *client, pm_message_t mesg); +static int fts_resume(struct i2c_client *client); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void fts_early_suspend(struct early_suspend *h) +{ + struct fts_ts_info *info; + info = container_of(h, struct fts_ts_info, early_suspend); + fts_suspend(info->client, PMSG_SUSPEND); +} + +static void fts_late_resume(struct early_suspend *h) +{ + struct fts_ts_info *info; + info = container_of(h, struct fts_ts_info, early_suspend); + fts_resume(info->client); +} +#endif + +int fts_write_reg(struct fts_ts_info *info, + unsigned char *reg, unsigned short num_com) +{ + struct i2c_msg xfer_msg[2]; + int ret; + + if (info->touch_stopped) { + tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); + goto exit; + } + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { + tsp_debug_err(true, &info->client->dev, + "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); + return -EIO; + } +#endif + + mutex_lock(&info->i2c_mutex); + + xfer_msg[0].addr = info->client->addr; + xfer_msg[0].len = num_com; + xfer_msg[0].flags = 0; + xfer_msg[0].buf = reg; + + ret = i2c_transfer(info->client->adapter, xfer_msg, 1); + + mutex_unlock(&info->i2c_mutex); + return ret; + + exit: + return 0; +} + +int fts_read_reg(struct fts_ts_info *info, unsigned char *reg, int cnum, + unsigned char *buf, int num) +{ + struct i2c_msg xfer_msg[2]; + int ret; + + if (info->touch_stopped) { + tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); + goto exit; + } + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { + tsp_debug_err(true, &info->client->dev, + "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); + return -EIO; + } +#endif + + mutex_lock(&info->i2c_mutex); + + xfer_msg[0].addr = info->client->addr; + xfer_msg[0].len = cnum; + xfer_msg[0].flags = 0; + xfer_msg[0].buf = reg; + + xfer_msg[1].addr = info->client->addr; + xfer_msg[1].len = num; + xfer_msg[1].flags = I2C_M_RD; + xfer_msg[1].buf = buf; + + ret = i2c_transfer(info->client->adapter, xfer_msg, 2); + + mutex_unlock(&info->i2c_mutex); + return ret; + + exit: + return 0; +} + +#ifdef FTS_SUPPORT_STRINGLIB +static int fts_read_from_string(struct fts_ts_info *info, + unsigned short *reg, unsigned char *data, int length) +{ + unsigned char string_reg[3]; + unsigned char *buf; + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + if (TRUSTEDUI_MODE_INPUT_SECURED & trustedui_get_current_mode()) { + tsp_debug_err(true, &info->client->dev, + "%s TSP no accessible from Linux, TUI is enabled!\n", __func__); + return -EIO; + } +#endif + + string_reg[0] = 0xD0; + string_reg[1] = (*reg >> 8) & 0xFF; + string_reg[2] = *reg & 0xFF; + + if (info->digital_rev == FTS_DIGITAL_REV_1) { + return fts_read_reg(info, string_reg, 3, data, length); + } else { + int rtn; + buf = kzalloc(length + 1, GFP_KERNEL); + if (buf == NULL) { + tsp_debug_info(true, &info->client->dev, + "%s: kzalloc error.\n", __func__); + return -1; + } + + rtn = fts_read_reg(info, string_reg, 3, buf, length + 1); + if (rtn >= 0) + memcpy(data, &buf[1], length); + + kfree(buf); + return rtn; + } +} +/* + * int fts_write_to_string(struct fts_ts_info *, unsigned short *, unsigned char *, int) + * send command or write specfic value to the string area. + * string area means guest image or brane firmware.. etc.. + */ +static int fts_write_to_string(struct fts_ts_info *info, + unsigned short *reg, unsigned char *data, int length) +{ + struct i2c_msg xfer_msg[3]; + unsigned char *regAdd; + int ret; + + if (info->touch_stopped) { + tsp_debug_err(true, &info->client->dev, "%s: Sensor stopped\n", __func__); + return 0; + } + + regAdd = kzalloc(length + 6, GFP_KERNEL); + if (regAdd == NULL) { + tsp_debug_info(true, &info->client->dev, + "%s: kzalloc error.\n", __func__); + return -1; + } + + mutex_lock(&info->i2c_mutex); + +/* msg[0], length 3*/ + regAdd[0] = 0xb3; + regAdd[1] = 0x20; + regAdd[2] = 0x01; + + xfer_msg[0].addr = info->client->addr; + xfer_msg[0].len = 3; + xfer_msg[0].flags = 0; + xfer_msg[0].buf = ®Add[0]; +/* msg[0], length 3*/ + +/* msg[1], length 4*/ + regAdd[3] = 0xb1; + regAdd[4] = (*reg >> 8) & 0xFF; + regAdd[5] = *reg & 0xFF; + + memcpy(®Add[6], data, length); + +/*regAdd[3] : B1 address, [4], [5] : String Address, [6]...: data */ + + xfer_msg[1].addr = info->client->addr; + xfer_msg[1].len = 3 + length; + xfer_msg[1].flags = 0; + xfer_msg[1].buf = ®Add[3]; +/* msg[1], length 4*/ + + ret = i2c_transfer(info->client->adapter, xfer_msg, 2); + if (ret == 2) { + tsp_debug_info(true, &info->client->dev, + "%s: string command is OK.\n", __func__); + + regAdd[0] = FTS_CMD_NOTIFY; + regAdd[1] = *reg & 0xFF; + regAdd[2] = (*reg >> 8) & 0xFF; + + xfer_msg[0].addr = info->client->addr; + xfer_msg[0].len = 3; + xfer_msg[0].flags = 0; + xfer_msg[0].buf = regAdd; + + ret = i2c_transfer(info->client->adapter, xfer_msg, 1); + if (ret != 1) + tsp_debug_info(true, &info->client->dev, + "%s: string notify is failed.\n", __func__); + else + tsp_debug_info(true, &info->client->dev, + "%s: string notify is OK[%X].\n", __func__, *data); + + } else + tsp_debug_info(true, &info->client->dev, + "%s: string command is failed. ret: %d\n", __func__, ret); + + mutex_unlock(&info->i2c_mutex); + kfree(regAdd); + + return ret; +} +#endif + +static void fts_delay(unsigned int ms) +{ + if (ms < 20) + usleep_range(ms * 1000, ms * 1000); + else + msleep(ms); +} + +void fts_command(struct fts_ts_info *info, unsigned char cmd) +{ + unsigned char regAdd = 0; + int ret = 0; + + regAdd = cmd; + ret = fts_write_reg(info, ®Add, 1); + tsp_debug_info(true, &info->client->dev, "FTS Command (%02X) , ret = %d \n", cmd, ret); +} + +void fts_enable_feature(struct fts_ts_info *info, unsigned char cmd, int enable) +{ + unsigned char regAdd[2] = {0xC1, 0x00}; + int ret = 0; + + if (!enable) + regAdd[0] = 0xC2; + regAdd[1] = cmd; + ret = fts_write_reg(info, ®Add[0], 2); + tsp_debug_info(true, &info->client->dev, "FTS %s Feature (%02X %02X) , ret = %d \n", (enable)?"Enable":"Disable", regAdd[0], regAdd[1], ret); +} + +static void fts_set_cover_type(struct fts_ts_info *info, bool enable) +{ + tsp_debug_info(true, &info->client->dev, "%s: %d\n", __func__, info->cover_type); + + switch (info->cover_type) { + case FTS_VIEW_WIRELESS: + case FTS_VIEW_COVER: + fts_enable_feature(info, FTS_FEATURE_COVER_GLASS, enable); + break; + case FTS_VIEW_WALLET: + fts_enable_feature(info, FTS_FEATURE_COVER_WALLET, enable); + break; + case FTS_FLIP_WALLET: + case FTS_LED_COVER: + case FTS_MONTBLANC_COVER: + fts_enable_feature(info, FTS_FEATURE_COVER_LED, enable); + break; + case FTS_CLEAR_FLIP_COVER : + fts_enable_feature(info, FTS_FEATURE_COVER_CLEAR_FLIP, enable); + break; + case FTS_QWERTY_KEYBOARD_EUR : + case FTS_QWERTY_KEYBOARD_KOR : + fts_enable_feature(info, 0x0D, enable); + break; + case FTS_CHARGER_COVER: + case FTS_COVER_NOTHING1: + case FTS_COVER_NOTHING2: + default: + tsp_debug_err(true, &info->client->dev, "%s: not change touch state, %d\n", + __func__, info->cover_type); + break; + } +} + +void fts_change_scan_rate(struct fts_ts_info *info, unsigned char cmd) +{ + unsigned char regAdd[2] = {0xC3, 0x00}; + int ret = 0; + + regAdd[1] = cmd; + ret = fts_write_reg(info, ®Add[0], 2); + + tsp_debug_dbg(true, &info->client->dev, "FTS %s Scan Rate (%02X %02X) , ret = %d \n", + (cmd == FTS_CMD_FAST_SCAN) ? "90Hz" : (cmd == FTS_CMD_SLOW_SCAN) ? "60Hz" : "30Hz", + regAdd[0], regAdd[1], ret); +} + +void fts_systemreset(struct fts_ts_info *info) +{ + unsigned char regAdd[4] = { 0xB6, 0x00, 0x23, 0x01 }; + tsp_debug_info(true, &info->client->dev, "FTS SystemReset\n"); + fts_write_reg(info, ®Add[0], 4); + fts_delay(10); +} + +static void fts_interrupt_set(struct fts_ts_info *info, int enable) +{ + unsigned char regAdd[4] = { 0xB6, 0x00, 0x1C, enable }; + + if (enable) + tsp_debug_info(true, &info->client->dev, "FTS INT Enable\n"); + else + tsp_debug_info(true, &info->client->dev, "FTS INT Disable\n"); + + fts_write_reg(info, ®Add[0], 4); +} + +static int fts_read_chip_id(struct fts_ts_info *info) { + + unsigned char regAdd[3] = {0xB6, 0x00, 0x07}; + unsigned char val[7] = {0}; + int ret; + + ret = fts_read_reg(info, regAdd, 3, (unsigned char *)val, 7); + if (ret < 0) { + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", + __func__, ret); + return ret; + } + + tsp_debug_info(true, &info->client->dev, "FTS %02X%02X%02X = %02X %02X %02X %02X %02X %02X\n", + regAdd[0], regAdd[1], regAdd[2], val[1], val[2], val[3], val[4], val[5], val[6]); + + if(val[1] == FTS_ID0 && val[2] == FTS_ID2) + { + if(val[4] == 0x00 && val[5] == 0x00) // 00 39 6C 03 00 00 + { + // Cx Corruption + fts_recovery_cx(info); + } + else + { + tsp_debug_info(true, &info->client->dev,"FTS Chip ID : %02X %02X\n", val[1], val[2]); + } + } + + if (val[1] != FTS_ID0) + return -FTS_ERROR_INVALID_CHIP_ID; + if (val[2] == FTS_ID1) + info->digital_rev = FTS_DIGITAL_REV_1; + else if (val[2] == FTS_ID2) + info->digital_rev = FTS_DIGITAL_REV_2; + else + return -FTS_ERROR_INVALID_CHIP_VERSION_ID; + + return ret; +} + +static int fts_wait_for_ready(struct fts_ts_info *info) +{ + int rc; + unsigned char regAdd; + unsigned char data[FTS_EVENT_SIZE]; + int retry = 0; + int err_cnt=0; + + memset(data, 0x0, FTS_EVENT_SIZE); + + regAdd = READ_ONE_EVENT; + rc = -1; + while (fts_read_reg(info, ®Add, 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + if (data[0] == EVENTID_CONTROLLER_READY) { + rc = 0; + break; + } + + if (data[0] == EVENTID_ERROR) { + if (err_cnt++ > 32) { + rc = -FTS_ERROR_EVENT_ID; + break; + } + continue; + } + + if (retry++ > FTS_RETRY_COUNT) { + rc = -FTS_ERROR_TIMEOUT; + tsp_debug_err(true, &info->client->dev, "%s: Time Over\n", __func__); + if (info->lowpower_mode) { + schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); + } + break; + } + fts_delay(20); + } + + tsp_debug_info(true, &info->client->dev, + "%s: %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", + __func__, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + + return rc; +} + +int fts_get_version_info(struct fts_ts_info *info) +{ + int rc; + unsigned char regAdd[3]; + unsigned char data[FTS_EVENT_SIZE]; + int retry = 0; + + fts_command(info, FTS_CMD_RELEASEINFO); + + memset(data, 0x0, FTS_EVENT_SIZE); + + regAdd[0] = READ_ONE_EVENT; + rc = -1; + while (fts_read_reg(info, ®Add[0], 1, (unsigned char *)data, FTS_EVENT_SIZE)) { + if (data[0] == EVENTID_INTERNAL_RELEASE_INFO) { + // Internal release Information + info->fw_version_of_ic = (data[3] << 8) + data[4]; + info->config_version_of_ic = (data[6] << 8) + data[5]; + info->ic_product_id = data[2]; + } else if (data[0] == EVENTID_EXTERNAL_RELEASE_INFO) { + // External release Information + info->fw_main_version_of_ic = (data[1] << 8) + data[2]; + rc = 0; + break; + } + + if (retry++ > FTS_RETRY_COUNT) { + rc = -FTS_ERROR_TIMEOUT; + tsp_debug_err(true, &info->client->dev, "%s: Time Over\n", __func__); + break; + } + } + + tsp_debug_info(true, &info->client->dev, + "IC product id : 0x%02X " + "IC Firmware Version : 0x%04X " + "IC Config Version : 0x%04X " + "IC Main Version : 0x%04X\n", + info->ic_product_id, + info->fw_version_of_ic, + info->config_version_of_ic, + info->fw_main_version_of_ic); + + return rc; +} + +#ifdef FTS_SUPPORT_NOISE_PARAM +int fts_get_noise_param_address(struct fts_ts_info *info) +{ + int rc; + unsigned char regAdd[3]; + unsigned char rData[3]; + struct fts_noise_param *noise_param; + int i; + + noise_param = (struct fts_noise_param *)&info->noise_param; + + regAdd[0] = 0xd0; + regAdd[1] = 0x00; + regAdd[2] = 32 * 2; + + if (info->digital_rev == FTS_DIGITAL_REV_1) + rc = fts_read_reg(info, regAdd, 3, (unsigned char *)noise_param->pAddr, 2); + else { + rc = fts_read_reg(info, regAdd, 3, (unsigned char *)rData, 3); + noise_param->pAddr[0] = rData[1] + (rData[2]<<8); + } + + for (i = 1; i < MAX_NOISE_PARAM; i++) { + noise_param->pAddr[i] = noise_param->pAddr[0] + i * 2; + } + + for (i = 0; i < MAX_NOISE_PARAM; i++) { + tsp_debug_dbg(true, &info->client->dev, "Get Noise Param%d Address = 0x%4x\n", i, + noise_param->pAddr[i]); + } + + return rc; +} + +static int fts_get_noise_param(struct fts_ts_info *info) +{ + int rc; + unsigned char regAdd[3]; + unsigned char data[MAX_NOISE_PARAM * 2]; + struct fts_noise_param *noise_param; + int i; + unsigned char buf[3]; + + noise_param = (struct fts_noise_param *)&info->noise_param; + memset(data, 0x0, MAX_NOISE_PARAM * 2); + + for (i = 0; i < MAX_NOISE_PARAM; i++) { + regAdd[0] = 0xb3; + regAdd[1] = 0x00; + regAdd[2] = 0x10; + fts_write_reg(info, regAdd, 3); + + regAdd[0] = 0xb1; + regAdd[1] = (noise_param->pAddr[i] >> 8) & 0xff; + regAdd[2] = noise_param->pAddr[i] & 0xff; + rc = fts_read_reg(info, regAdd, 3, &buf[0], 3); + + noise_param->pData[i] = buf[1]+(buf[2]<<8); + //tsp_debug_info(true, &info->client->dev, "0x%2x%2x%2x 0x%2x 0x%2x\n", regAdd[0],regAdd[1],regAdd[2], buf[1], buf[2]); + } + + for (i = 0; i < MAX_NOISE_PARAM; i++) { + tsp_debug_dbg(true, &info->client->dev, "Get Noise Param%d Address [ 0x%04x ] = 0x%04x\n", i, + noise_param->pAddr[i], noise_param->pData[i]); + } + + return rc; +} + +static int fts_set_noise_param(struct fts_ts_info *info) +{ + int i; + unsigned char regAdd[5]; + struct fts_noise_param *noise_param; + + noise_param = (struct fts_noise_param *)&info->noise_param; + + for (i = 0; i < MAX_NOISE_PARAM; i++) { + regAdd[0] = 0xb3; + regAdd[1] = 0x00; + regAdd[2] = 0x10; + fts_write_reg(info, regAdd, 3); + + regAdd[0] = 0xb1; + regAdd[1] = (noise_param->pAddr[i] >> 8) & 0xff; + regAdd[2] = noise_param->pAddr[i] & 0xff; + regAdd[3] = noise_param->pData[i] & 0xff; + regAdd[4] = (noise_param->pData[i] >> 8) & 0xff; + fts_write_reg(info, regAdd, 5); + } + + for (i = 0; i < MAX_NOISE_PARAM; i++) { + tsp_debug_dbg(true, &info->client->dev, "Set Noise Param%d Address [ 0x%04x ] = 0x%04x\n", i, + noise_param->pAddr[i], noise_param->pData[i]); + } + + return 0; +} +#endif + +#ifdef FTS_SUPPORT_TOUCH_KEY +void fts_release_all_key(struct fts_ts_info *info) +{ + unsigned char key_recent = TOUCH_KEY_RECENT; + unsigned char key_back = TOUCH_KEY_BACK; + + if (info->board->support_mskey && info->tsp_keystatus != TOUCH_KEY_NULL) { + if (info->tsp_keystatus & key_recent) { + input_report_key(info->input_dev, KEY_RECENT, KEY_RELEASE); + tsp_debug_info(true, &info->client->dev, "[TSP_KEY] Recent R!\n"); + } + + if (info->tsp_keystatus & key_back) { + input_report_key(info->input_dev, KEY_BACK, KEY_RELEASE); + tsp_debug_info(true, &info->client->dev, "[TSP_KEY] back R!\n"); + } + + input_sync(info->input_dev); + + info->tsp_keystatus = TOUCH_KEY_NULL; +#if defined (CONFIG_INPUT_BOOSTER) + input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, BOOSTER_MODE_OFF); +#endif + } +} +#endif + +/* Added for samsung dependent codes such as Factory test, + * Touch booster, Related debug sysfs. + */ +#include "fts_sec.c" + +static int fts_init(struct fts_ts_info *info) +{ + unsigned char val[16]; + unsigned char regAdd[8]; + int rc; + + fts_systemreset(info); + + rc = fts_wait_for_ready(info); + if (rc == -FTS_ERROR_EVENT_ID) { + info->fw_version_of_ic = 0; + info->config_version_of_ic = 0; + info->fw_main_version_of_ic = 0; + } else + fts_get_version_info(info); + + rc = fts_read_chip_id(info); + if (rc < 0) + return 1; + + rc = fts_fw_update_on_probe(info); + if (rc < 0) + tsp_debug_err(true, &info->client->dev, "%s: Failed to firmware update\n", + __func__); + + fts_command(info, SLEEPOUT); + + fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_get_noise_param_address(info); +#endif + /* fts driver set functional feature */ + info->touch_count = 0; + info->hover_enabled = false; + info->hover_ready = false; + info->flip_enable = false; + info->mainscr_disable = false; + + info->deepsleep_mode = false; + info->lowpower_mode = false; + info->lowpower_flag = 0x00; + info->fts_power_state = 0; + +#ifdef FTS_SUPPORT_TOUCH_KEY + info->tsp_keystatus = 0x00; +#endif + +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + info->SIDE_Flag = 0; + info->previous_SIDE_value = 0; + info->run_autotune = true; + } +#endif + +#ifdef SEC_TSP_FACTORY_TEST + rc = fts_get_channel_info(info); + if (rc >= 0) { + tsp_debug_info(true, &info->client->dev, "FTS Sense(%02d) Force(%02d)\n", + info->SenseChannelLength, info->ForceChannelLength); + } else { + tsp_debug_info(true, &info->client->dev, "FTS read failed rc = %d\n", rc); + tsp_debug_info(true, &info->client->dev, "FTS Initialise Failed\n"); + return 1; + } + + info->pFrame = + kzalloc(info->SenseChannelLength * info->ForceChannelLength * 2, + GFP_KERNEL); + if (info->pFrame == NULL) { + tsp_debug_info(true, &info->client->dev, "FTS pFrame kzalloc Failed\n"); + return 1; + } + + info->cx_data = kzalloc(info->SenseChannelLength * info->ForceChannelLength, GFP_KERNEL); + if (!info->cx_data) + tsp_debug_err(true, &info->client->dev, "%s: cx_data kzalloc Failed\n", __func__); +#endif + + fts_command(info, FORCECALIBRATION); + fts_command(info, FLUSHBUFFER); + + fts_interrupt_set(info, INT_ENABLE); + + memset(val, 0x0, 4); + regAdd[0] = READ_STATUS; + fts_read_reg(info, regAdd, 1, (unsigned char *)val, 4); + tsp_debug_info(true, &info->client->dev, "FTS ReadStatus(0x84) : %02X %02X %02X %02X\n", val[0], + val[1], val[2], val[3]); + + tsp_debug_info(true, &info->client->dev, "FTS Initialized\n"); + + return 0; +} + +static void fts_debug_msg_event_handler(struct fts_ts_info *info, + unsigned char data[]) +{ + tsp_debug_dbg(true, &info->client->dev, + "%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", __func__, + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); +} + +static unsigned char fts_event_handler_type_b(struct fts_ts_info *info, + unsigned char data[], + unsigned char LeftEvent) +{ + unsigned char EventNum = 0; + unsigned char NumTouches = 0; + unsigned char TouchID = 0, EventID = 0, status = 0; + unsigned char LastLeftEvent = 0; + int x = 0, y = 0, z = 0; + int bw = 0, bh = 0, palm = 0, sumsize = 0; +#if defined (CONFIG_INPUT_BOOSTER) + bool booster_restart = false; +#endif +#ifdef FTS_SUPPORT_2NDSCREEN + u8 currentSideFlag = 0; +#endif +#ifdef FTS_SUPPORT_SIDE_GESTURE + static int longpress_release[FINGER_MAX] = {0, }; +#endif +#ifdef FTS_SUPPORT_STRINGLIB + unsigned short string_addr; + unsigned char string_data[10] = {0, }; + unsigned char string_clear = 0; +#endif + + for (EventNum = 0; EventNum < LeftEvent; EventNum++) { +#if 0 + tsp_debug_info(true, &info->client->dev, "%d %2x %2x %2x %2x %2x %2x %2x %2x\n", + EventNum, + data[EventNum * FTS_EVENT_SIZE], + data[EventNum * FTS_EVENT_SIZE+1], + data[EventNum * FTS_EVENT_SIZE+2], + data[EventNum * FTS_EVENT_SIZE+3], + data[EventNum * FTS_EVENT_SIZE+4], + data[EventNum * FTS_EVENT_SIZE+5], + data[EventNum * FTS_EVENT_SIZE+6], + data[EventNum * FTS_EVENT_SIZE+7]); +#endif + EventID = data[EventNum * FTS_EVENT_SIZE] & 0x0F; + + if ((EventID >= 3) && (EventID <= 5)) { + LastLeftEvent = 0; + NumTouches = 1; + + TouchID = (data[EventNum * FTS_EVENT_SIZE] >> 4) & 0x0F; + } else { + LastLeftEvent = + data[7 + EventNum * FTS_EVENT_SIZE] & 0x0F; + NumTouches = + (data[1 + EventNum * FTS_EVENT_SIZE] & 0xF0) >> 4; + TouchID = data[1 + EventNum * FTS_EVENT_SIZE] & 0x0F; + EventID = data[EventNum * FTS_EVENT_SIZE] & 0xFF; + status = data[1 + EventNum * FTS_EVENT_SIZE] & 0xFF; + } + + switch (EventID) { + case EVENTID_NO_EVENT: + break; + +#ifdef FTS_SUPPORT_TOUCH_KEY + case EVENTID_MSKEY: + if (info->board->support_mskey) { + unsigned char input_keys; + + input_keys = data[2 + EventNum * FTS_EVENT_SIZE]; + + if (input_keys == 0x00) + fts_release_all_key(info); + else { + unsigned char change_keys; + unsigned char key_state; + unsigned char key_recent = TOUCH_KEY_RECENT; + unsigned char key_back = TOUCH_KEY_BACK; + + change_keys = input_keys ^ info->tsp_keystatus; + + if (change_keys & key_recent) { + key_state = input_keys & key_recent; + + input_report_key(info->input_dev, KEY_RECENT, key_state != 0 ? KEY_PRESS : KEY_RELEASE); + tsp_debug_info(true, &info->client->dev, "[TSP_KEY] RECENT %s\n", key_state != 0 ? "P" : "R"); + } + + if (change_keys & key_back) { + key_state = input_keys & key_back; + + input_report_key(info->input_dev, KEY_BACK, key_state != 0 ? KEY_PRESS : KEY_RELEASE); + tsp_debug_info(true, &info->client->dev, "[TSP_KEY] BACK %s\n" , key_state != 0 ? "P" : "R"); + } + +#if defined (CONFIG_INPUT_BOOSTER) + if ((change_keys & key_recent)||(change_keys & key_back)) { + input_booster_send_event(BOOSTER_DEVICE_TOUCHKEY, (key_state != 0 ? KEY_PRESS : KEY_RELEASE)); + } +#endif + input_sync(info->input_dev); + } + + info->tsp_keystatus = input_keys; + } + break; +#endif +#ifdef FTS_SUPPORT_SIDE_GESTURE + case EVENTID_SIDE_TOUCH: + case EVENTID_SIDE_TOUCH_DEBUG: + if (info->board->support_sidegesture) { + unsigned char event_type = data[1 + EventNum * FTS_EVENT_SIZE]; + + if ((event_type == FTS_SIDEGESTURE_EVENT_SINGLE_STROKE) || + (event_type == FTS_SIDEGESTURE_EVENT_DOUBLE_STROKE) || + (event_type == FTS_SIDEGESTURE_EVENT_INNER_STROKE)) { + int direction, distance; + direction = data[2 + EventNum * FTS_EVENT_SIZE]; + distance = *(int *)&data[3 + EventNum * FTS_EVENT_SIZE]; + + if (direction) + input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 1); + else + input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 1); + + tsp_debug_info(true, &info->client->dev, + "%s: [Gesture] %02X %02X %02X %02X %02X %02X %02X %02X\n", + __func__, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + + input_sync(info->input_dev); + fts_delay(1); + + if (direction) + input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); + else + input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); + } + else if (event_type == FTS_SIDETOUCH_EVENT_LONG_PRESS) { + int sideLongPressfingerID = 0; + sideLongPressfingerID = data[2 + EventNum * FTS_EVENT_SIZE]; + + //Todo : event processing + longpress_release[sideLongPressfingerID - 1] = 1; + + tsp_debug_info(true, &info->client->dev, + "%s: [Side Long Press] id:%d %02X %02X %02X %02X %02X %02X %02X %02X\n", + __func__, sideLongPressfingerID, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + } + else if(event_type == FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD) { + tsp_debug_info(true, &info->client->dev, + "%s: ESD detected! %02X %02X %02X %02X %02X %02X %02X %02X\n", + __func__, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + + schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); + } + else { + fts_debug_msg_event_handler(info, + &data[EventNum * + FTS_EVENT_SIZE]); + } + } else { + unsigned char event_type = data[1 + EventNum * FTS_EVENT_SIZE]; + if(event_type == FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD) { + tsp_debug_info(true, &info->client->dev, + "%s: ESD detected! %02X %02X %02X %02X %02X %02X %02X %02X\n", + __func__, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + + schedule_delayed_work(&info->reset_work, msecs_to_jiffies(10)); + } + else { + fts_debug_msg_event_handler(info, + &data[EventNum * + FTS_EVENT_SIZE]); + } + + } + break; +#endif + case EVENTID_ERROR: + if (data[1 + EventNum * FTS_EVENT_SIZE] == 0x08) { // Get Auto tune fail event + if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x00) { + tsp_debug_info(true, &info->client->dev, "[FTS] Fail Mutual Auto tune\n"); + } + else if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x01) { + tsp_debug_info(true, &info->client->dev, "[FTS] Fail Self Auto tune\n"); + } + } else if (data[1 + EventNum * FTS_EVENT_SIZE] == 0x09) // Get detect SYNC fail event + tsp_debug_info(true, &info->client->dev, "[FTS] Fail detect SYNC\n"); + break; + + case EVENTID_HOVER_ENTER_POINTER: + case EVENTID_HOVER_MOTION_POINTER: + x = ((data[4 + EventNum * FTS_EVENT_SIZE] & 0xF0) >> 4) + | ((data[2 + EventNum * FTS_EVENT_SIZE]) << 4); + y = ((data[4 + EventNum * FTS_EVENT_SIZE] & 0x0F) | + ((data[3 + EventNum * FTS_EVENT_SIZE]) << 4)); + + z = data[5 + EventNum * FTS_EVENT_SIZE]; + + input_mt_slot(info->input_dev, 0); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, 1); + + input_report_key(info->input_dev, BTN_TOUCH, 0); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + info->SIDE_Flag = 0; + info->previous_SIDE_value = 0; + input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); + } +#endif + + input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(info->input_dev, ABS_MT_DISTANCE, 255 - z); + break; + + case EVENTID_HOVER_LEAVE_POINTER: + input_mt_slot(info->input_dev, 0); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, 0); + break; + + case EVENTID_ENTER_POINTER: + if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) + break; + + info->touch_count++; +#if defined (CONFIG_INPUT_BOOSTER) + booster_restart = true; +#endif + case EVENTID_MOTION_POINTER: + if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) { + tsp_debug_info(true, &info->client->dev, "%s: low power mode\n", __func__); + fts_release_all_finger(info); + break; + } + + if (info->touch_count == 0) { + tsp_debug_info(true, &info->client->dev, "%s: count 0\n", __func__); + fts_release_all_finger(info); + break; + } + + if ((EventID == EVENTID_MOTION_POINTER) && + (info->finger[TouchID].state == EVENTID_LEAVE_POINTER)) { + tsp_debug_info(true, &info->client->dev, "%s: state leave but point is moved.\n", __func__); + break; + } + + if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) + break; + + x = data[1 + EventNum * FTS_EVENT_SIZE] + + ((data[2 + EventNum * FTS_EVENT_SIZE] & + 0x0f) << 8); + y = ((data[2 + EventNum * FTS_EVENT_SIZE] & + 0xf0) >> 4) + (data[3 + + EventNum * + FTS_EVENT_SIZE] << 4); + bw = data[4 + EventNum * FTS_EVENT_SIZE]; + bh = data[5 + EventNum * FTS_EVENT_SIZE]; + palm = + (data[6 + EventNum * FTS_EVENT_SIZE] >> 7) & 0x01; + + sumsize = (data[6 + EventNum * FTS_EVENT_SIZE] & 0x7f) << 1; + + if ((info->touch_count == 1) && (sumsize < 40)) + sumsize = 39; +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + currentSideFlag = (data[7 + EventNum * FTS_EVENT_SIZE] >> 7) & 0x01; + z = data[7 + EventNum * FTS_EVENT_SIZE] & 0x7f; + } else + z = data[7 + EventNum * FTS_EVENT_SIZE]; +#else + z = data[7 + EventNum * FTS_EVENT_SIZE]; +#endif +#ifdef FTS_SUPPROT_MULTIMEDIA + if(info->brush_enable) info->brush_size = tableX[Brush][z]; + else if(info->velocity_enable) info->brush_size = tableX[Velocity][z]; +#endif + input_mt_slot(info->input_dev, TouchID); + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, + 1 + (palm << 1)); + + input_report_key(info->input_dev, BTN_TOUCH, 1); + input_report_key(info->input_dev, + BTN_TOOL_FINGER, 1); + input_report_abs(info->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, + ABS_MT_POSITION_Y, y); + + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MAJOR, max(bw, + bh)); + + input_report_abs(info->input_dev, + ABS_MT_TOUCH_MINOR, min(bw, + bh)); +#ifdef FTS_SUPPROT_MULTIMEDIA + input_report_abs(info->input_dev, + ABS_BRUSH, info->brush_size); +#endif +#ifdef FTS_SUPPORT_SEC_SWIPE + input_report_abs(info->input_dev, ABS_MT_PALM, + palm); +#endif +#if defined(FTS_SUPPORT_SIDE_GESTURE) + if (info->board->support_sidegesture) + input_report_abs(info->input_dev, ABS_MT_GRIP, 0); +#endif + +#ifdef SEC_TSP_FACTORY_TEST + input_report_abs(info->input_dev, + ABS_MT_PRESSURE, z & 0x3F); +#endif + + info->finger[TouchID].lx = x; + info->finger[TouchID].ly = y; + + break; + + case EVENTID_LEAVE_POINTER: + if (info->fts_power_state == FTS_POWER_STATE_LOWPOWER) + break; + + if (info->touch_count <= 0) { + tsp_debug_info(true, &info->client->dev, "%s: count 0\n", __func__); + fts_release_all_finger(info); + break; + } + + info->touch_count--; + + input_mt_slot(info->input_dev, TouchID); + +#if defined(FTS_SUPPORT_SIDE_GESTURE) + if (info->board->support_sidegesture) { + if (longpress_release[TouchID] == 1) { + input_report_abs(info->input_dev, ABS_MT_GRIP, 1); + tsp_debug_info(true, &info->client->dev, + "[FTS] GRIP [%d] %s\n", TouchID, + longpress_release[TouchID] ? "LONGPRESS" : "RELEASE"); + longpress_release[TouchID] = 0; + + input_sync(info->input_dev); + } + } +#endif + + input_mt_report_slot_state(info->input_dev, + MT_TOOL_FINGER, 0); + + if (info->touch_count == 0) { + /* Clear BTN_TOUCH when All touch are released */ + input_report_key(info->input_dev, BTN_TOUCH, 0); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); +#ifdef FTS_SUPPORT_SIDE_SCROLL + if (info->board->support_sidescroll) { + input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); + input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); + } +#endif +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + info->SIDE_Flag = 0; + info->previous_SIDE_value = 0; + input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); + } +#endif +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) { + input_report_key(info->input_dev, KEY_SIDE_GESTURE, 0); + input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); + input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); + } +#endif + } + break; + case EVENTID_STATUS_EVENT: + if (status == STATUS_EVENT_GLOVE_MODE) { +#ifdef CONFIG_GLOVE_TOUCH + int tm; + if (data[2 + EventNum * FTS_EVENT_SIZE] == 0x01) + info->touch_mode = FTS_TM_GLOVE; + else + info->touch_mode = FTS_TM_NORMAL; + + tm = info->touch_mode; + input_report_switch(info->input_dev, SW_GLOVE, tm); +#endif + } else if (status == STATUS_EVENT_RAW_DATA_READY) { + unsigned char regAdd[4] = {0xB0, 0x01, 0x29, 0x01}; + fts_write_reg(info, ®Add[0], 4); + + info->hover_ready = true; + + tsp_debug_info(true, &info->client->dev, "[FTS] Received the Hover Raw Data Ready Event\n"); + } else if (status == STATUS_EVENT_FORCE_CAL_MUTUAL) { + tsp_debug_dbg(true, &info->client->dev, "[FTS] Received Force Calibration Mutual only Event\n"); + } else if (status == STATUS_EVENT_FORCE_CAL_SELF) { + tsp_debug_dbg(true, &info->client->dev, "[FTS] Received Force Calibration Self only Event\n"); + } else if (status == STATUS_EVENT_WATERMODE_ON) { + tsp_debug_info(true, &info->client->dev, "[FTS] Received Water Mode On Event\n"); + } else if (status == STATUS_EVENT_WATERMODE_OFF) { + tsp_debug_info(true, &info->client->dev, "[FTS] Received Water Mode Off Event\n"); + } else if (status == STATUS_EVENT_MUTUAL_CAL_FRAME_CHECK) { + tsp_debug_info(true, &info->client->dev, "[FTS] Received Mutual Calib Frame Check Event\n"); + } else if (status == STATUS_EVENT_SELF_CAL_FRAME_CHECK) { + tsp_debug_info(true, &info->client->dev, "[FTS] Received Self Calib Frame Check Event\n"); + } else { + fts_debug_msg_event_handler(info, + &data[EventNum * + FTS_EVENT_SIZE]); + } + break; + +#ifdef SEC_TSP_FACTORY_TEST + case EVENTID_RESULT_READ_REGISTER: + procedure_cmd_event(info, &data[EventNum * FTS_EVENT_SIZE]); + break; +#endif + +#ifdef FTS_SUPPORT_SIDE_SCROLL + case EVENTID_SIDE_SCROLL: + if (info->board->support_sidescroll) { + int scroll_flag = data[3 + EventNum * FTS_EVENT_SIZE]; + int scroll_thr = data[6 + EventNum * FTS_EVENT_SIZE]; + tsp_debug_info(true, &info->client->dev,"[TB] side scroll flag: event: %02X, thr: %02X\n", scroll_flag, scroll_thr); + + // TODO : Report function call this area + + if (scroll_flag == 1) { + input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 1); + input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); + input_sync(info->input_dev); + } else if (scroll_flag == 2) { + input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); + input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 1); + input_sync(info->input_dev); + } + } + break; +#endif +#ifdef FTS_SUPPORT_STRINGLIB + case EVENTID_FROM_STRING: + string_addr = FTS_CMD_STRING_ACCESS; + fts_read_from_string(info, &string_addr, string_data, 6); + tsp_debug_info(true, &info->client->dev, + "%s: [String] %02X %02X %02X %02X %02X %02X %02X %02X || %04X: %02X, %02X\n", + __func__, data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7], + string_addr, string_data[0], string_data[1]); + + switch(string_data[1]) { + case FTS_STRING_EVENT_REAR_CAM: + tsp_debug_info(true, &info->client->dev, "%s: REAR_CAM\n", __func__); + break; + case FTS_STRING_EVENT_FRONT_CAM: + tsp_debug_info(true, &info->client->dev, "%s: FRONT_CAM\n", __func__); + break; + case FTS_STRING_EVENT_WATCH_STATUS: + case FTS_STRING_EVENT_FAST_ACCESS: + case FTS_STRING_EVENT_DIRECT_INDICATOR: + tsp_debug_info(true, &info->client->dev, "%s: SCRUB[%X]\n", __func__, string_data[1]); + input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 1); + info->scrub_id = (string_data[1] >> 2) & 0x3; + info->scrub_x = string_data[2] | (string_data[3] << 8); + info->scrub_y = string_data[4] | (string_data[5] << 8); + break; + case FTS_STRING_EVENT_SPAY: + case FTS_STRING_EVENT_SPAY1: + case FTS_STRING_EVENT_SPAY2: + dev_info(&info->client->dev, "%s: SPAY[%X]\n", __func__, string_data[1]); + input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 1); + info->scrub_id = (string_data[1] >> 2) & 0xF; + break; + default: + tsp_debug_info(true, &info->client->dev, "%s: no event:%X\n", __func__, string_data[1]); + break; + } + + input_sync(info->input_dev); + + if (!info->debug_string) { + /* request by display lab, buf clear */ + string_clear |= string_data[1]; + + string_addr = FTS_CMD_STRING_ACCESS + 1; + string_data[1] &= ~(string_clear); + + tsp_debug_info(true, &info->client->dev, + "%s: clear bit : string_data[1]: %X, string_clear: %X\n", + __func__, string_data[1], string_clear); + + fts_write_to_string(info, &string_addr, &string_data[1], 1); + } else { + tsp_debug_info(true, &info->client->dev, + "%s: do not clear string_bit\n", + __func__); + } + + input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 0); + + break; +#endif + + default: + fts_debug_msg_event_handler(info, + &data[EventNum * + FTS_EVENT_SIZE]); + continue; + } +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + if (currentSideFlag != info->previous_SIDE_value) { + tsp_debug_info(true, &info->client->dev,"[TB] 2nd screen flag was changed, old:%d c:%d f:%d\n", info->previous_SIDE_value, currentSideFlag, info->SIDE_Flag); + info->SIDE_Flag = currentSideFlag; + // TODO : Report function call this area + + input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, !(!(info->SIDE_Flag)) ); + } + info->previous_SIDE_value = currentSideFlag; + } +#endif + +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + if (EventID == EVENTID_ENTER_POINTER) +#ifdef FTS_SUPPROT_MULTIMEDIA + tsp_debug_info(true, &info->client->dev, + "[P] tID:%d x:%d y:%d w:%d h:%d z:%d s:%d p:%d tc:%d tm:%d brush_enable = %d velocity_enable = %d\n", + TouchID, x, y, bw, bh, z, sumsize, palm, info->touch_count, info->touch_mode, info->brush_enable, info->velocity_enable); +#else + tsp_debug_info(true, &info->client->dev, + "[P] tID:%d x:%d y:%d w:%d h:%d z:%d s:%d p:%d tc:%d tm:%d\n", + TouchID, x, y, bw, bh, z, sumsize, palm, info->touch_count, info->touch_mode); +#endif + else if (EventID == EVENTID_HOVER_ENTER_POINTER) + tsp_debug_dbg(true, &info->client->dev, + "[HP] tID:%d x:%d y:%d z:%d\n", + TouchID, x, y, z); +#else + if (EventID == EVENTID_ENTER_POINTER) + tsp_debug_info(true, &info->client->dev, + "[P] tID:%d tc:%d tm:%d\n", + TouchID, info->touch_count, info->touch_mode); + else if (EventID == EVENTID_HOVER_ENTER_POINTER) + tsp_debug_dbg(true, &info->client->dev, + "[HP] tID:%d\n", TouchID); +#endif + else if (EventID == EVENTID_LEAVE_POINTER) { +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + if (strncmp(info->board->model_name, "G925", 4) == 0) { + tsp_debug_info(true, &info->client->dev, + "[R] tID:%d mc: %d tc:%d lx: %d ly: %d Ver[%01X%01X%04X%01X%01X%01X]\n", + TouchID, info->finger[TouchID].mcount, info->touch_count, + info->finger[TouchID].lx, info->finger[TouchID].ly, + info->tspid_val,info->tspid2_val, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled, info->mainscr_disable); + }else{ + tsp_debug_info(true, &info->client->dev, + "[R] tID:%d mc: %d tc:%d lx: %d ly: %d Ver[%02X%04X%01X%01X%01X]\n", + TouchID, info->finger[TouchID].mcount, info->touch_count, + info->finger[TouchID].lx, info->finger[TouchID].ly, + info->panel_revision, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled, info->mainscr_disable); + } +#else + if (strncmp(info->board->model_name, "G925", 4) == 0) { + + tsp_debug_info(true, &info->client->dev, + "[R] tID:%d mc: %d tc:%d Ver[%01X%01X%04X%01X%01X%01X]\n", + TouchID, info->finger[TouchID].mcount, info->touch_count, + info->tspid_val,info->tspid2_val, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled, info->mainscr_disable); + }else{ + tsp_debug_info(true, &info->client->dev, + "[R] tID:%d mc: %d tc:%d Ver[%02X%04X%01X%01X%01X]\n", + TouchID, info->finger[TouchID].mcount, info->touch_count, + info->panel_revision, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled, info->mainscr_disable); + } +#endif + info->finger[TouchID].mcount = 0; + } else if (EventID == EVENTID_HOVER_LEAVE_POINTER) { + tsp_debug_dbg(true, &info->client->dev, + "[HR] tID:%d Ver[%02X%04X%01X%01X]\n", + TouchID, + info->panel_revision, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled); + info->finger[TouchID].mcount = 0; + } else if (EventID == EVENTID_MOTION_POINTER) + info->finger[TouchID].mcount++; + + if ((EventID == EVENTID_ENTER_POINTER) || + (EventID == EVENTID_MOTION_POINTER) || + (EventID == EVENTID_LEAVE_POINTER)) + info->finger[TouchID].state = EventID; + } + + input_sync(info->input_dev); + +#if defined (CONFIG_INPUT_BOOSTER) + if ((EventID == EVENTID_ENTER_POINTER) + || (EventID == EVENTID_LEAVE_POINTER)) { + if (booster_restart) + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_ON); + if (!info->touch_count) + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_OFF); + } +#endif + + return LastLeftEvent; +} + +#ifdef FTS_SUPPORT_TA_MODE +static void fts_ta_cb(struct fts_callbacks *cb, int ta_status) +{ + struct fts_ts_info *info = + container_of(cb, struct fts_ts_info, callbacks); + + if (ta_status == 0x01 || ta_status == 0x03) { + fts_command(info, FTS_CMD_CHARGER_PLUGGED); + info->TA_Pluged = true; + tsp_debug_info(true, &info->client->dev, + "%s: device_control : CHARGER CONNECTED, ta_status : %x\n", + __func__, ta_status); + } else { + fts_command(info, FTS_CMD_CHARGER_UNPLUGGED); + info->TA_Pluged = false; + tsp_debug_info(true, &info->client->dev, + "%s: device_control : CHARGER DISCONNECTED, ta_status : %x\n", + __func__, ta_status); + } +} +#endif + +/** + * fts_interrupt_handler() + * + * Called by the kernel when an interrupt occurs (when the sensor + * asserts the attention irq). + * + * This function is the ISR thread and handles the acquisition + * and the reporting of finger data when the presence of fingers + * is detected. + */ +static irqreturn_t fts_interrupt_handler(int irq, void *handle) +{ + struct fts_ts_info *info = handle; + unsigned char regAdd[4] = {0xb6, 0x00, 0x45, READ_ALL_EVENT}; + unsigned short evtcount = 0; +#ifdef FTS_SUPPORT_SIDE_GESTURE + if ((info->board->support_sidegesture) && + (info->fts_power_state == FTS_POWER_STATE_LOWPOWER)) { + pm_wakeup_event(info->input_dev->dev.parent, 1000); + } +#endif + evtcount = 0; + fts_read_reg(info, ®Add[0], 3, (unsigned char *)&evtcount, 2); + evtcount = evtcount >> 10; + + if (evtcount > FTS_FIFO_MAX) + evtcount = FTS_FIFO_MAX; + + if (evtcount > 0) { + memset(info->data, 0x0, FTS_EVENT_SIZE * evtcount); + fts_read_reg(info, ®Add[3], 1, (unsigned char *)info->data, + FTS_EVENT_SIZE * evtcount); + fts_event_handler_type_b(info, info->data, evtcount); + } +#ifdef FTS_SUPPORT_SIDE_GESTURE + if ((info->board->support_sidegesture) && + (info->fts_power_state == FTS_POWER_STATE_LOWPOWER)) + pm_relax(info->input_dev->dev.parent); +#endif + + return IRQ_HANDLED; +} + +static int fts_irq_enable(struct fts_ts_info *info, + bool enable) +{ + int retval = 0; + + if (enable) { + if (info->irq_enabled) + return retval; + + retval = request_threaded_irq(info->irq, NULL, + fts_interrupt_handler, info->board->irq_type, + FTS_TS_DRV_NAME, info); + if (retval < 0) { + tsp_debug_info(true, &info->client->dev, + "%s: Failed to create irq thread %d\n", + __func__, retval); + return retval; + } + + info->irq_enabled = true; + } else { + if (info->irq_enabled) { + disable_irq(info->irq); + free_irq(info->irq, info); + info->irq_enabled = false; + } + } + + return retval; +} + +#ifdef CONFIG_OF +#ifdef FTS_SUPPORT_TA_MODE +struct fts_callbacks *fts_charger_callbacks; +void tsp_charger_infom(bool en) +{ + + pr_err("[TSP]%s: ta:%d\n", __func__, en); + + if (fts_charger_callbacks && fts_charger_callbacks->inform_charger) + fts_charger_callbacks->inform_charger(fts_charger_callbacks, en); +} +static void fts_tsp_register_callback(void *cb) +{ + fts_charger_callbacks = cb; +} +#endif + +#ifdef FTS_SUPPORT_TOUCH_KEY +static int fts_led_power_ctrl(void *data, bool on) +{ + struct fts_ts_info *info = (struct fts_ts_info *)data; + const struct fts_i2c_platform_data *pdata = info->board; + struct device *dev = &info->client->dev; + struct regulator *regulator_tk_led = NULL; + static bool enabled; + int retval = 0; + + if (enabled == on) + return retval; + + regulator_tk_led = regulator_get(NULL, pdata->regulator_tk_led); + if (IS_ERR_OR_NULL(regulator_tk_led)) { + tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", + __func__, pdata->regulator_tk_led); + goto out; + } + + tsp_debug_info(true, dev, "%s: %s\n", __func__, on ? "on" : "off"); + + if (on) { + retval = regulator_enable(regulator_tk_led); + if (retval) { + tsp_debug_err(true, dev, "%s: Failed to enable led%d\n", __func__, retval); + goto out; + } + } else { + if (regulator_is_enabled(regulator_tk_led)) + regulator_disable(regulator_tk_led); + } + + enabled = on; +out: + regulator_put(regulator_tk_led); + + return retval; +} +#endif + +static int fts_power_ctrl(void *data, bool on) +{ + struct fts_ts_info *info = (struct fts_ts_info *)data; + const struct fts_i2c_platform_data *pdata = info->board; + struct device *dev = &info->client->dev; + struct regulator *regulator_dvdd = NULL; + struct regulator *regulator_avdd = NULL; + static bool enabled; + int retval = 0; + + if (enabled == on) + return retval; + + regulator_dvdd = regulator_get(NULL, pdata->regulator_dvdd); + if (IS_ERR_OR_NULL(regulator_dvdd)) { + tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", + __func__, pdata->regulator_dvdd); + goto out; + } + + regulator_avdd = regulator_get(NULL, pdata->regulator_avdd); + if (IS_ERR_OR_NULL(regulator_avdd)) { + tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", + __func__, pdata->regulator_avdd); + goto out; + } + + tsp_debug_info(true, dev, "%s: %s\n", __func__, on ? "on" : "off"); + + if (on) { + retval = regulator_enable(regulator_avdd); + if (retval) { + tsp_debug_err(true, dev, "%s: Failed to enable avdd: %d\n", __func__, retval); + goto out; + } + retval = regulator_enable(regulator_dvdd); + if (retval) { + tsp_debug_err(true, dev, "%s: Failed to enable vdd: %d\n", __func__, retval); + goto out; + } + + retval = pinctrl_select_state(pdata->pinctrl, pdata->pins_default); + if (retval < 0) + tsp_debug_err(true, dev, "%s: Failed to configure tsp_attn pin\n", __func__); + + fts_delay(5); + } else { + if (regulator_is_enabled(regulator_dvdd)) + regulator_disable(regulator_dvdd); + if (regulator_is_enabled(regulator_avdd)) + regulator_disable(regulator_avdd); + + retval = pinctrl_select_state(pdata->pinctrl, pdata->pins_sleep); + if (retval < 0) + tsp_debug_err(true, dev, "%s: Failed to configure tsp_attn pin\n", __func__); + } + + enabled = on; +out: + regulator_put(regulator_dvdd); + regulator_put(regulator_avdd); + + return retval; +} + +static int fts_parse_dt(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct fts_i2c_platform_data *pdata = dev->platform_data; + struct device_node *np = dev->of_node; + u32 coords[2], lines[2]; + int retval = 0; + + pdata->tspid = of_get_named_gpio(np, "stm,tspid_gpio", 0); + if (gpio_is_valid(pdata->tspid)) + tsp_debug_info(true, dev, "TSP_ID : %d\n", gpio_get_value(pdata->tspid)); + else + tsp_debug_err(true, dev, "Failed to get tspid gpio\n"); + + pdata->tspid2 = of_get_named_gpio(np, "stm,tspid2_gpio", 0); + if (gpio_is_valid(pdata->tspid2)) + tsp_debug_info(true, dev, "TSP_ID2 : %d\n", gpio_get_value(pdata->tspid2)); + else + tsp_debug_err(true, dev, "Failed to get tspid2 gpio\n"); + + pdata->gpio = of_get_named_gpio(np, "stm,irq_gpio", 0); + if (gpio_is_valid(pdata->gpio)) { + retval = gpio_request_one(pdata->gpio, GPIOF_DIR_IN, "stm,tsp_int"); + if (retval) { + tsp_debug_err(true, dev, "Unable to request tsp_int [%d]\n", pdata->gpio); + return -EINVAL; + } + } else { + tsp_debug_err(true, dev, "Failed to get irq gpio\n"); + return -EINVAL; + } + client->irq = gpio_to_irq(pdata->gpio); + + if (of_property_read_u32(np, "stm,irq_type", &pdata->irq_type)) { + tsp_debug_err(true, dev, "Failed to get irq_type property\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "stm,grip_area", &pdata->grip_area)) + tsp_debug_err(true, dev, "Failed to get grip_area property\n"); + + if (of_property_read_u32_array(np, "stm,max_coords", coords, 2)) { + tsp_debug_err(true, dev, "Failed to get max_coords property\n"); + return -EINVAL; + } + pdata->max_x = coords[0]; + pdata->max_y = coords[1]; + + if ((lcdtype == S6E3HF2_WQXGA_ID1) || (lcdtype == S6E3HF2_WQXGA_ID2)) { + pdata->max_x = 1439; + pdata->max_y = 2559; + pdata->grip_area = 160; + } + + /* fix resolution temporary, it will be move to dts later */ + if(((lcdtype & LCD_ID2_MODEL_MASK) == MODEL_NOBLE) && ((lcdtype & LCD_ID3_DIC_MASK) == S6E3HA3_NOBLE) ){ + pdata->max_x = 1439; + pdata->max_y = 2559; + } + else if(((lcdtype & LCD_ID2_MODEL_MASK) == MODEL_ZEN) && ((lcdtype & LCD_ID3_DIC_MASK) == S6E3HA3_ZEN) ){ + pdata->max_x = 1439; + pdata->max_y = 2559; + } + else if(lcdtype == ZEN_UB_VZW){ + pdata->max_x = 1439; + pdata->max_y = 2559; + } + + if (of_property_read_u32_array(np, "stm,num_lines", lines, 2)) + tsp_debug_dbg(true, dev, "skipped to get num_lines property\n"); + else { + pdata->SenseChannelLength = lines[0]; + pdata->ForceChannelLength = lines[1]; + tsp_debug_info(true, dev, "num_of[rx,tx]: [%d,%d]\n", + pdata->SenseChannelLength, pdata->ForceChannelLength); + } + + if (of_property_read_string(np, "stm,regulator_dvdd", &pdata->regulator_dvdd)) { + tsp_debug_err(true, dev, "Failed to get regulator_dvdd name property\n"); + return -EINVAL; + } + if (of_property_read_string(np, "stm,regulator_avdd", &pdata->regulator_avdd)) { + tsp_debug_err(true, dev, "Failed to get regulator_avdd name property\n"); + return -EINVAL; + } + pdata->power = fts_power_ctrl; + + /* Optional parmeters(those values are not mandatory) + * do not return error value even if fail to get the value + */ + of_property_read_string(np, "stm,firmware_name", &pdata->firmware_name); + + if (of_property_read_string_index(np, "stm,project_name", 0, &pdata->project_name)) + tsp_debug_dbg(true, dev, "skipped to get project_name property\n"); + if (of_property_read_string_index(np, "stm,project_name", 1, &pdata->model_name)) + tsp_debug_dbg(true, dev, "skipped to get model_name property\n"); + + pdata->max_width = 28; + pdata->support_hover = true; + pdata->support_mshover = true; +#ifdef FTS_SUPPORT_TA_MODE + pdata->register_cb = fts_tsp_register_callback; +#endif + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (of_property_read_u32(np, "stm,num_touchkey", &pdata->num_touchkey)) + tsp_debug_dbg(true, dev, "skipped to get num_touchkey property\n"); + else { +#ifdef FTS_SUPPORT_SIDE_GESTURE + pdata->support_sidegesture = true; +#endif + pdata->support_mskey = true; + pdata->touchkey = fts_touchkeys; + + if (of_property_read_string(np, "stm,regulator_tk_led", &pdata->regulator_tk_led)) + tsp_debug_dbg(true, dev, "skipped to get regulator_tk_led name property\n"); + else + pdata->led_power = fts_led_power_ctrl; + } +#endif + + pdata->panel_revision = (lcdtype & 0xF000) >> 12; + tsp_debug_info(true, dev, + "irq :%d, irq_type: 0x%04x, max[x,y]: [%d,%d], grip_area :%d, project/model_name: %s/%s, panel_revision: %d, lcdtype: 0x%06X\n", + pdata->gpio, pdata->irq_type, pdata->max_x, pdata->max_y, pdata->grip_area, + pdata->project_name, pdata->model_name, + pdata->panel_revision, lcdtype); + + return retval; +} +#endif + +static int fts_setup_drv_data(struct i2c_client *client) +{ + int retval = 0; + struct fts_i2c_platform_data *pdata; + struct fts_ts_info *info; + + /* parse dt */ + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct fts_i2c_platform_data), GFP_KERNEL); + + if (!pdata) { + tsp_debug_err(true, &client->dev, "Failed to allocate platform data\n"); + return -ENOMEM; + } + + client->dev.platform_data = pdata; + retval = fts_parse_dt(client); + if (retval) { + tsp_debug_err(true, &client->dev, "Failed to parse dt\n"); + return retval; + } + } else { + pdata = client->dev.platform_data; + } + + if (!pdata) { + tsp_debug_err(true, &client->dev, "No platform data found\n"); + return -EINVAL; + } + if (!pdata->power) { + tsp_debug_err(true, &client->dev, "No power contorl found\n"); + return -EINVAL; + } + + pdata->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR(pdata->pinctrl)) { + tsp_debug_err(true, &client->dev, "could not get pinctrl\n"); + return PTR_ERR(pdata->pinctrl); + } + + pdata->pins_default = pinctrl_lookup_state(pdata->pinctrl, "on_state"); + if (IS_ERR(pdata->pins_default)) + tsp_debug_err(true, &client->dev, "could not get default pinstate\n"); + + pdata->pins_sleep = pinctrl_lookup_state(pdata->pinctrl, "off_state"); + if (IS_ERR(pdata->pins_sleep)) + tsp_debug_err(true, &client->dev, "could not get sleep pinstate\n"); + + info = kzalloc(sizeof(struct fts_ts_info), GFP_KERNEL); + if (!info) { + tsp_debug_err(true, &client->dev, + "%s: Failed to alloc mem for info\n", + __func__); + return -ENOMEM; + } + + info->client = client; + info->board = pdata; + info->irq = client->irq; + info->irq_type = info->board->irq_type; + info->irq_enabled = false; + info->touch_stopped = false; + info->panel_revision = info->board->panel_revision; + info->stop_device = fts_stop_device; + info->start_device = fts_start_device; + info->fts_command = fts_command; + info->fts_enable_feature = fts_enable_feature; + info->fts_read_reg = fts_read_reg; + info->fts_write_reg = fts_write_reg; + info->fts_systemreset = fts_systemreset; + info->fts_get_version_info = fts_get_version_info; + info->fts_wait_for_ready = fts_wait_for_ready; +#ifdef FTS_SUPPORT_STRINGLIB + info->fts_read_from_string = fts_read_from_string; + info->fts_write_to_string = fts_write_to_string; +#endif +#ifdef FTS_SUPPORT_NOISE_PARAM + info->fts_get_noise_param_address = fts_get_noise_param_address; +#endif + +#ifdef USE_OPEN_DWORK + INIT_DELAYED_WORK(&info->open_work, fts_open_work); +#endif + info->delay_time = 300; + INIT_DELAYED_WORK(&info->reset_work, fts_reset_work); + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG + INIT_DELAYED_WORK(&info->debug_work, dump_tsp_rawdata); + p_debug_work = &info->debug_work; +#endif +#ifdef SEC_TSP_FACTORY_TEST + INIT_DELAYED_WORK(&info->cover_cmd_work, clear_cover_cmd_work); +#endif + + if (info->board->support_hover) + tsp_debug_info(true, &info->client->dev, "FTS Support Hover Event \n"); + else + tsp_debug_info(true, &info->client->dev, "FTS Not support Hover Event \n"); + + i2c_set_clientdata(client, info); + + if (pdata->get_ddi_type) { + info->ddi_type = pdata->get_ddi_type(); + tsp_debug_info(true, &client->dev, "%s: DDI Type is %s[%d]\n", + __func__, info->ddi_type ? "MAGNA" : "SDC", info->ddi_type); + } + + return retval; +} +#ifdef CONFIG_BATTERY_SAMSUNG +extern unsigned int lpcharge; +#endif +static int fts_probe(struct i2c_client *client, const struct i2c_device_id *idp) +{ + int retval; + struct fts_ts_info *info = NULL; + static char fts_ts_phys[64] = { 0 }; + int i = 0; + long j = 0; + + tsp_debug_info(true, &client->dev, "FTS Driver [12%s] %s %s\n", + FTS_TS_DRV_VERSION, __DATE__, __TIME__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + tsp_debug_err(true, &client->dev, "FTS err = EIO!\n"); + return -EIO; + } +#ifdef CONFIG_BATTERY_SAMSUNG + if (lpcharge == 1) { + tsp_debug_err(true, &client->dev, "%s : Do not load driver due to : lpm %d\n", + __func__, lpcharge); + return -ENODEV; + } +#endif + /* Build up driver data */ + retval = fts_setup_drv_data(client); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to set up driver data\n", __func__); + goto err_setup_drv_data; + } + + info = (struct fts_ts_info *)i2c_get_clientdata(client); + if (!info) { + tsp_debug_err(true, &client->dev, "%s: Failed to get driver data\n", __func__); + retval = -ENODEV; + goto err_get_drv_data; + } + + if (info->board->power) + info->board->power(info, true); + + info->dev = &info->client->dev; + info->input_dev = input_allocate_device(); + if (!info->input_dev) { + tsp_debug_info(true, &info->client->dev, "FTS err = ENOMEM!\n"); + retval = -ENOMEM; + goto err_input_allocate_device; + } + + info->input_dev->dev.parent = &client->dev; + info->input_dev->name = "sec_touchscreen"; + snprintf(fts_ts_phys, sizeof(fts_ts_phys), "%s/input1", + info->input_dev->name); + info->input_dev->phys = fts_ts_phys; + info->input_dev->id.bustype = BUS_I2C; + +#ifdef USE_OPEN_CLOSE + info->input_dev->open = fts_input_open; + info->input_dev->close = fts_input_close; +#endif + +#ifdef CONFIG_GLOVE_TOUCH + input_set_capability(info->input_dev, EV_SW, SW_GLOVE); +#endif + set_bit(EV_SYN, info->input_dev->evbit); + set_bit(EV_KEY, info->input_dev->evbit); + set_bit(EV_ABS, info->input_dev->evbit); +#ifdef INPUT_PROP_DIRECT + set_bit(INPUT_PROP_DIRECT, info->input_dev->propbit); +#endif + set_bit(BTN_TOUCH, info->input_dev->keybit); + set_bit(BTN_TOOL_FINGER, info->input_dev->keybit); +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) + set_bit(BTN_SUBSCREEN_FLAG, info->input_dev->keybit); +#endif +#ifdef FTS_SUPPORT_SIDE_SCROLL + if (info->board->support_sidescroll) { + set_bit(BTN_R_FLICK_FLAG, info->input_dev->keybit); + set_bit(BTN_L_FLICK_FLAG, info->input_dev->keybit); + } +#endif +#ifdef FTS_SUPPORT_STRINGLIB + set_bit(KEY_BLACK_UI_GESTURE, info->input_dev->keybit); +#endif +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + for (i = 0 ; i < info->board->num_touchkey ; i++) + set_bit(info->board->touchkey[i].keycode, info->input_dev->keybit); + + set_bit(EV_LED, info->input_dev->evbit); + set_bit(LED_MISC, info->input_dev->ledbit); + } +#endif +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) { + set_bit(KEY_SIDE_GESTURE, info->input_dev->keybit); + set_bit(KEY_SIDE_GESTURE_RIGHT, info->input_dev->keybit); + set_bit(KEY_SIDE_GESTURE_LEFT, info->input_dev->keybit); + } +#endif + +#ifdef FTS_SUPPROT_MULTIMEDIA + set_bit(ABS_BRUSH, info->input_dev->absbit); +#endif + input_mt_init_slots(info->input_dev, FINGER_MAX, INPUT_MT_DIRECT); + input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, + 0, info->board->max_x, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, + 0, info->board->max_y, 0, 0); +#ifdef FTS_SUPPROT_MULTIMEDIA + input_set_abs_params(info->input_dev, ABS_BRUSH, + 0, 255, 0, 0); +#endif +#ifdef SEC_TSP_FACTORY_TEST + input_set_abs_params(info->input_dev, ABS_MT_PRESSURE, + 0, 0x3F, 0, 0); +#endif + mutex_init(&info->lock); + mutex_init(&info->device_mutex); + mutex_init(&info->i2c_mutex); + + info->enabled = false; + mutex_lock(&info->lock); + retval = fts_init(info); + info->reinit_done = true; + mutex_unlock(&info->lock); + if (retval) { + tsp_debug_err(true, &info->client->dev, "FTS fts_init fail!\n"); + goto err_fts_init; + } + + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, + 0, 255, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MINOR, + 0, 255, 0, 0); +#ifdef FTS_SUPPORT_SEC_SWIPE + input_set_abs_params(info->input_dev, ABS_MT_PALM, 0, 1, 0, 0); +#endif +#if defined(FTS_SUPPORT_SIDE_GESTURE) + if (info->board->support_sidegesture) + input_set_abs_params(info->input_dev, ABS_MT_GRIP, 0, 1, 0, 0); +#endif + input_set_abs_params(info->input_dev, ABS_MT_DISTANCE, + 0, 255, 0, 0); + + input_set_drvdata(info->input_dev, info); + i2c_set_clientdata(client, info); + + retval = input_register_device(info->input_dev); + if (retval) { + tsp_debug_err(true, &info->client->dev, "FTS input_register_device fail!\n"); + goto err_register_input; + } + + for (i = 0; i < FINGER_MAX; i++) { + info->finger[i].state = EVENTID_LEAVE_POINTER; + info->finger[i].mcount = 0; + } + + info->enabled = true; + + retval = fts_irq_enable(info, true); + if (retval < 0) { + tsp_debug_info(true, &info->client->dev, + "%s: Failed to enable attention interrupt\n", + __func__); + goto err_enable_irq; + } + +#ifdef CONFIG_TRUSTONIC_TRUSTED_UI + trustedui_set_tsp_irq(info->irq); + tsp_debug_info(true, &client->dev, "%s[%d] called!\n", + __func__, info->irq); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND + info->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + info->early_suspend.suspend = fts_early_suspend; + info->early_sfts_start_deviceuspend.resume = fts_late_resume; + register_early_suspend(&info->early_suspend); +#endif + +#ifdef FTS_SUPPORT_TA_MODE + info->register_cb = info->board->register_cb; + + info->callbacks.inform_charger = fts_ta_cb; + if (info->register_cb) + info->register_cb(&info->callbacks); +#endif + +#ifdef SEC_TSP_FACTORY_TEST + INIT_LIST_HEAD(&info->cmd_list_head); + + info->cmd_buffer_size = 0; + for (j = 0; j < ARRAY_SIZE(ft_commands); j++) { + list_add_tail(&ft_commands[j].list, &info->cmd_list_head); + if(ft_commands[j].cmd_name) + info->cmd_buffer_size += strlen(ft_commands[j].cmd_name) + 1; + } + + mutex_init(&info->cmd_lock); + info->cmd_is_running = false; + + info->fac_dev_ts = sec_device_create(info, "tsp"); + if (IS_ERR(info->fac_dev_ts)) { + tsp_debug_err(true, &info->client->dev, "FTS Failed to create device for the sysfs\n"); + retval = -ENOENT; + goto err_sysfs; + } + + dev_set_drvdata(info->fac_dev_ts, info); + + retval = sysfs_create_group(&info->fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + if (retval < 0) { + tsp_debug_err(true, &info->client->dev, "FTS Failed to create sysfs group\n"); + goto err_sysfs; + } + + retval = sysfs_create_link(&info->fac_dev_ts->kobj, + &info->input_dev->dev.kobj, "input"); + + if (retval < 0) { + tsp_debug_err(true, &info->client->dev, + "%s: Failed to create link\n", __func__); + goto err_sysfs; + } + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + info->fac_dev_tk = sec_device_create(info, "sec_touchkey"); + if (IS_ERR(info->fac_dev_tk)) + tsp_debug_err(true, &info->client->dev, "Failed to create device for the touchkey sysfs\n"); + else { + dev_set_drvdata(info->fac_dev_tk, info); + + retval = sysfs_create_group(&info->fac_dev_tk->kobj, + &sec_touchkey_factory_attr_group); + if (retval < 0) + tsp_debug_err(true, &info->client->dev, "FTS Failed to create sysfs group\n"); + else { + retval = sysfs_create_link(&info->fac_dev_tk->kobj, + &info->input_dev->dev.kobj, "input"); + + if (retval < 0) + tsp_debug_err(true, &info->client->dev, + "%s: Failed to create link\n", __func__); + } + } + } +#endif +#endif + + device_init_wakeup(&client->dev, true); + + return 0; + +#ifdef SEC_TSP_FACTORY_TEST +err_sysfs: + if (info->irq_enabled) + fts_irq_enable(info, false); + mutex_destroy(&info->cmd_lock); +#endif + +err_enable_irq: + input_unregister_device(info->input_dev); + info->input_dev = NULL; + +err_register_input: + if (info->input_dev) + input_free_device(info->input_dev); + +err_fts_init: + mutex_destroy(&info->lock); + mutex_destroy(&info->device_mutex); + mutex_destroy(&info->i2c_mutex); +err_input_allocate_device: + info->board->power(info, false); + kfree(info); +err_get_drv_data: +err_setup_drv_data: + return retval; +} + +static int fts_remove(struct i2c_client *client) +{ + struct fts_ts_info *info = i2c_get_clientdata(client); + + tsp_debug_info(true, &info->client->dev, "FTS removed \n"); + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&info->early_suspend); +#endif + + fts_interrupt_set(info, INT_DISABLE); + fts_command(info, FLUSHBUFFER); + + fts_irq_enable(info, false); + + input_mt_destroy_slots(info->input_dev); + +#ifdef SEC_TSP_FACTORY_TEST +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + sysfs_remove_link(&info->fac_dev_tk->kobj, "input"); + sysfs_remove_group(&info->fac_dev_tk->kobj, + &sec_touchkey_factory_attr_group); + sec_device_destroy(info->fac_dev_tk->devt); + } +#endif + sysfs_remove_link(&info->fac_dev_ts->kobj, "input"); + sysfs_remove_group(&info->fac_dev_ts->kobj, + &sec_touch_factory_attr_group); + sec_device_destroy(info->fac_dev_ts->devt); + + list_del(&info->cmd_list_head); + + mutex_destroy(&info->cmd_lock); + + if (info->cx_data) + kfree(info->cx_data); + + if (info->pFrame) + kfree(info->pFrame); +#endif + + mutex_destroy(&info->lock); + + input_unregister_device(info->input_dev); + info->input_dev = NULL; + + info->board->power(info, false); + + kfree(info); + + return 0; +} + +#ifdef USE_OPEN_CLOSE +#ifdef USE_OPEN_DWORK +static void fts_open_work(struct work_struct *work) +{ + int retval; + struct fts_ts_info *info = container_of(work, struct fts_ts_info, + open_work.work); + + tsp_debug_info(true, &info->client->dev, "%s\n", __func__); + + retval = fts_start_device(info); + if (retval < 0) + tsp_debug_err(true, &info->client->dev, + "%s: Failed to start device\n", __func__); +} +#endif +static int fts_input_open(struct input_dev *dev) +{ + struct fts_ts_info *info = input_get_drvdata(dev); + int retval; + + tsp_debug_dbg(false, &info->client->dev, "%s\n", __func__); + +#ifdef USE_OPEN_DWORK + schedule_delayed_work(&info->open_work, + msecs_to_jiffies(TOUCH_OPEN_DWORK_TIME)); +#else + retval = fts_start_device(info); + if (retval < 0){ + tsp_debug_err(true, &info->client->dev, + "%s: Failed to start device\n", __func__); + goto out; + } +#endif + + tsp_debug_err(true, &info->client->dev, "FTS cmd after wakeup : h%d \n", info->retry_hover_enable_after_wakeup); + + if(info->retry_hover_enable_after_wakeup == 1){ + unsigned char regAdd[4] = {0xB0, 0x01, 0x29, 0x41}; + fts_write_reg(info, ®Add[0], 4); + fts_command(info, FTS_CMD_HOVER_ON); + info->hover_enabled = true; + } + +out: + return 0; +} + +static void fts_input_close(struct input_dev *dev) +{ + struct fts_ts_info *info = input_get_drvdata(dev); + + tsp_debug_dbg(false, &info->client->dev, "%s\n", __func__); + +#ifdef USE_OPEN_DWORK + cancel_delayed_work(&info->open_work); +#endif + + fts_stop_device(info); + + info->retry_hover_enable_after_wakeup = 0; +} +#endif + +#ifdef CONFIG_SEC_FACTORY +#include +#define LCD_LDI_FILE_PATH "/sys/class/lcd/panel/window_type" +static int fts_get_panel_revision(struct fts_ts_info *info) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *window_type; + unsigned char lcdtype[4] = {0,}; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + window_type = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + if (IS_ERR(window_type)) { + iRet = PTR_ERR(window_type); + if (iRet != -ENOENT) + tsp_debug_err(true, &info->client->dev, "%s: window_type file open fail\n", __func__); + set_fs(old_fs); + goto exit; + } + + iRet = window_type->f_op->read(window_type, (u8 *)lcdtype, sizeof(u8) * 4, &window_type->f_pos); + if (iRet != (sizeof(u8) * 4)) { + tsp_debug_err(true, &info->client->dev, "%s: Can't read the lcd ldi data\n", __func__); + iRet = -EIO; + } + + /* The variable of lcdtype has ASCII values(40 81 45) at 0x08 OCTA, + * so if someone need a TSP panel revision then to read third parameter.*/ + info->panel_revision = lcdtype[3] & 0x0F; + tsp_debug_info(true, &info->client->dev, + "%s: update panel_revision 0x%02X\n", __func__, info->panel_revision); + + filp_close(window_type, current->files); + set_fs(old_fs); + +exit: + return iRet; +} + +static void fts_reinit_fac(struct fts_ts_info *info) +{ + int rc; + + info->touch_count = 0; + + fts_command(info, SLEEPOUT); + fts_delay(50); + + fts_command(info, SENSEON); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + info->fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_get_noise_param_address(info); +#endif + + if (info->flip_enable) + fts_set_cover_type(info, true); + + /* enable glove touch when flip cover is closed */ + if (info->fast_mshover_enabled) + fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); + else if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + + rc = fts_get_channel_info(info); + if (rc >= 0) { + tsp_debug_info(true, &info->client->dev, "FTS Sense(%02d) Force(%02d)\n", + info->SenseChannelLength, info->ForceChannelLength); + } else { + tsp_debug_info(true, &info->client->dev, "FTS read failed rc = %d\n", rc); + tsp_debug_info(true, &info->client->dev, "FTS Initialise Failed\n"); + return; + } + + info->pFrame = + kzalloc(info->SenseChannelLength * info->ForceChannelLength * 2, + GFP_KERNEL); + if (info->pFrame == NULL) { + tsp_debug_info(true, &info->client->dev, "FTS pFrame kzalloc Failed\n"); + return; + } + + info->cx_data = kzalloc(info->SenseChannelLength * info->ForceChannelLength, GFP_KERNEL); + if (!info->cx_data) + tsp_debug_err(true, &info->client->dev, "%s: cx_data kzalloc Failed\n", __func__); + + fts_command(info, FORCECALIBRATION); + fts_command(info, FLUSHBUFFER); + + fts_interrupt_set(info, INT_ENABLE); + + tsp_debug_info(true, &info->client->dev, "FTS Re-Initialised\n"); +} +#endif + +static void fts_reinit(struct fts_ts_info *info) +{ + if (!info->lowpower_mode) { + fts_wait_for_ready(info); + fts_read_chip_id(info); + } + + fts_systemreset(info); + + fts_wait_for_ready(info); + +#ifdef CONFIG_SEC_FACTORY + /* Read firmware version from IC when every power up IC. + * During Factory process touch panel can be changed manually. + */ + { + unsigned short orig_fw_main_version_of_ic = info->fw_main_version_of_ic; + + fts_get_panel_revision(info); + fts_get_version_info(info); + + if (info->fw_main_version_of_ic != orig_fw_main_version_of_ic) { + fts_fw_init(info); + fts_reinit_fac(info); + return; + } + } +#endif + +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_set_noise_param(info); +#endif + + fts_command(info, SLEEPOUT); + fts_delay(50); + + fts_command(info, SENSEON); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + info->fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + if (info->flip_enable) + fts_set_cover_type(info, true); + else if (info->fast_mshover_enabled) + fts_command(info, FTS_CMD_SET_FAST_GLOVE_MODE); + else if (info->mshover_enabled) + fts_command(info, FTS_CMD_MSHOVER_ON); + +#ifdef FTS_SUPPORT_TA_MODE + if (info->TA_Pluged) + fts_command(info, FTS_CMD_CHARGER_PLUGGED); +#endif + + info->touch_count = 0; +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + info->SIDE_Flag = 0; + info->previous_SIDE_value = 0; + } +#endif + + fts_command(info, FLUSHBUFFER); + fts_interrupt_set(info, INT_ENABLE); +} + +void fts_release_all_finger(struct fts_ts_info *info) +{ + int i; + + for (i = 0; i < FINGER_MAX; i++) { + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); + + if ((info->finger[i].state == EVENTID_ENTER_POINTER) || + (info->finger[i].state == EVENTID_MOTION_POINTER)) { + info->touch_count--; + if (info->touch_count < 0) + info->touch_count = 0; + + tsp_debug_info(true, &info->client->dev, + "[RA] tID:%d mc: %d tc:%d Ver[%02X%04X%01X%01X%01X]\n", + i, info->finger[i].mcount, info->touch_count, + info->panel_revision, info->fw_main_version_of_ic, + info->flip_enable, info->mshover_enabled, info->mainscr_disable); + } + + info->finger[i].state = EVENTID_LEAVE_POINTER; + info->finger[i].mcount = 0; + } + + input_report_key(info->input_dev, BTN_TOUCH, 0); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); + +#ifdef FTS_SUPPORT_2NDSCREEN + if (info->board->support_2ndscreen) { + info->SIDE_Flag = 0; + info->previous_SIDE_value = 0; + input_report_key(info->input_dev, BTN_SUBSCREEN_FLAG, 0); + } +#endif +#ifdef FTS_SUPPORT_SIDE_SCROLL + if (info->board->support_sidescroll) { + input_report_key(info->input_dev, BTN_R_FLICK_FLAG, 0); + input_report_key(info->input_dev, BTN_L_FLICK_FLAG, 0); + } +#endif + +#ifdef CONFIG_GLOVE_TOUCH + input_report_switch(info->input_dev, SW_GLOVE, false); + info->touch_mode = FTS_TM_NORMAL; +#endif +#ifdef FTS_SUPPORT_STRINGLIB + input_report_key(info->input_dev, KEY_BLACK_UI_GESTURE, 0); +#endif +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) { + input_report_key(info->input_dev, KEY_SIDE_GESTURE, 0); + input_report_key(info->input_dev, KEY_SIDE_GESTURE_RIGHT, 0); + input_report_key(info->input_dev, KEY_SIDE_GESTURE_LEFT, 0); + } +#endif + +#ifdef CONFIG_INPUT_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_FORCE_OFF); +#endif + + input_sync(info->input_dev); +} + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +static void dump_tsp_rawdata(struct work_struct *work) +{ + struct fts_ts_info *info = container_of(work, struct fts_ts_info, + debug_work.work); + int i; + + if (info->rawdata_read_lock == true) + tsp_debug_err(true, &info->client->dev, "%s, ## checking.. ignored.\n", __func__); + + info->rawdata_read_lock = true; + tsp_debug_info(true, &info->client->dev, "%s, ## run CX data ##, %d\n", __func__, __LINE__); + run_cx_data_read((void *)info); + + for (i = 0; i < 5; i++) { + tsp_debug_info(true, &info->client->dev, "%s, ## run Raw Cap data ##, %d\n", __func__, __LINE__); + run_rawcap_read((void *)info); + + tsp_debug_info(true, &info->client->dev, "%s, ## run Delta ##, %d\n", __func__, __LINE__); + run_delta_read((void *)info); + fts_delay(50); + } + tsp_debug_info(true, &info->client->dev, "%s, ## Done ##, %d\n", __func__, __LINE__); + + info->rawdata_read_lock = false; +} + +void tsp_dump(void) +{ +#ifdef CONFIG_BATTERY_SAMSUNG + if (lpcharge) + return; +#endif + if (!p_debug_work) + return; + + printk(KERN_ERR "FTS %s: start \n", __func__); + schedule_delayed_work(p_debug_work, msecs_to_jiffies(100)); +} +#endif + +static void fts_reset_work(struct work_struct *work) +{ + struct fts_ts_info *info = container_of(work, struct fts_ts_info, + reset_work.work); + bool temp_lpm; + + temp_lpm = info->lowpower_mode; + /* Reset-routine must go to power off state */ + info->lowpower_mode = 0; + + tsp_debug_info(true, &info->client->dev,"%s, Call Power-Off to recover IC, lpm:%d\n", __func__, temp_lpm); + fts_stop_device(info); + + msleep(100); /* Delay to discharge the IC from ESD or On-state.*/ + if (fts_start_device(info) < 0) { + tsp_debug_err(true, &info->client->dev, "%s: Failed to start device\n", __func__); + } + + info->lowpower_mode = temp_lpm; +} + + +static int fts_stop_device(struct fts_ts_info *info) +{ + tsp_debug_info(true, &info->client->dev, "%s\n", __func__); + + mutex_lock(&info->device_mutex); + + if (info->touch_stopped) { + tsp_debug_err(true, &info->client->dev, "%s already power off\n", __func__); + goto out; + } + + if (info->lowpower_mode) { +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) { + tsp_debug_info(true, &info->client->dev, "%s mainscreen disable flag:%d, clear\n", __func__, info->mainscr_disable); + set_mainscreen_disable_cmd((void *)info, 0); + } +#endif + tsp_debug_info(true, &info->client->dev, "%s lowpower flag:%d\n", __func__, info->lowpower_flag); + + info->fts_power_state = FTS_POWER_STATE_LOWPOWER; + + fts_command(info, FLUSHBUFFER); + +#ifdef FTS_SUPPORT_SIDE_GESTURE + if (info->board->support_sidegesture) { + fts_enable_feature(info, FTS_FEATURE_SIDE_GUSTURE, true); + fts_delay(20); + } +#endif + fts_command(info, FTS_CMD_LOWPOWER_MODE); + + if (device_may_wakeup(&info->client->dev)) + enable_irq_wake(info->irq); + + fts_command(info, FLUSHBUFFER); + + fts_release_all_finger(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + fts_release_all_key(info); +#endif +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_get_noise_param(info); +#endif + +#ifdef FTS_SUPPORT_STRINGLIB + if (info->fts_mode) + fts_enable_feature(info, 0x0B, true); +#endif + } else { + fts_interrupt_set(info, INT_DISABLE); + disable_irq(info->irq); + + fts_command(info, FLUSHBUFFER); + fts_command(info, SLEEPIN); + fts_release_all_finger(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + fts_release_all_key(info); +#endif +#ifdef FTS_SUPPORT_NOISE_PARAM + fts_get_noise_param(info); +#endif + info->touch_stopped = true; + info->hover_enabled = false; + info->hover_ready = false; + + if (info->board->power) + info->board->power(info, false); + + info->fts_power_state = FTS_POWER_STATE_POWERDOWN; + } + out: + mutex_unlock(&info->device_mutex); + return 0; +} + +static int fts_start_device(struct fts_ts_info *info) +{ + tsp_debug_info(true, &info->client->dev, "%s %s\n", + __func__, info->lowpower_mode ? "exit low power mode" : ""); + + mutex_lock(&info->device_mutex); + + if (!info->touch_stopped && !info->lowpower_mode) { + tsp_debug_err(true, &info->client->dev, "%s already power on\n", __func__); + goto out; + } + + fts_release_all_finger(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + fts_release_all_key(info); +#endif + + if (info->lowpower_mode) { + /* low power mode command is sent after LCD OFF. turn on touch power @ LCD ON */ + if (info->touch_stopped) + goto tsp_power_on; + + disable_irq(info->irq); + + info->reinit_done = false; + fts_reinit(info); + info->reinit_done = true; + + enable_irq(info->irq); + + if (device_may_wakeup(&info->client->dev)) + disable_irq_wake(info->irq); + } else { +tsp_power_on: + if (info->board->power) + info->board->power(info, true); + info->touch_stopped = false; + info->reinit_done = false; + + fts_reinit(info); + info->reinit_done = true; + + enable_irq(info->irq); + } + +#ifdef FTS_SUPPORT_STRINGLIB + if (info->fts_mode) { + unsigned short addr = FTS_CMD_STRING_ACCESS; + int ret; + + ret = info->fts_write_to_string(info, &addr, &info->fts_mode, sizeof(info->fts_mode)); + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s: failed. ret: %d\n", __func__, ret); + } +#endif + if (strncmp(info->board->model_name, "G925", 4) == 0) { + info->tspid_val= gpio_get_value(info->board->tspid); + info->tspid2_val= gpio_get_value(info->board->tspid2); + } + + out: + mutex_unlock(&info->device_mutex); + + info->fts_power_state = FTS_POWER_STATE_ACTIVE; + + return 0; +} + +static void fts_shutdown(struct i2c_client *client) +{ + struct fts_ts_info *info = i2c_get_clientdata(client); + + tsp_debug_info(true, &info->client->dev, "FTS %s called!\n", __func__); + + if (info->lowpower_mode) { + info->lowpower_mode = 0; + tsp_debug_info(true, &info->client->dev, "FTS lowpower_mode off!\n"); + } + + fts_stop_device(info); +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->led_power) + info->board->led_power(info, false); +#endif +} + +void fts_recovery_cx(struct fts_ts_info *info) +{ + unsigned char regAdd[4] = {0}; + unsigned char buf[8] = {0}; + unsigned char cnt = 100; + + regAdd[0] = 0xB6; + regAdd[1] = 0x00; + regAdd[2] = 0x1E; + regAdd[3] = 0x08; + fts_write_reg(info,®Add[0], 4); // Loading FW to PRAM without CRC Check + fts_delay(30); + + + fts_command(info,CX_TUNNING); + fts_delay(300); + + fts_command(info,FTS_CMD_SAVE_CX_TUNING); + fts_delay(200); + + do + { + int ret; + regAdd[0] = READ_ONE_EVENT; + ret = fts_read_reg(info, regAdd, 1, &buf[0], FTS_EVENT_SIZE); + + fts_delay(10); + if(cnt-- == 0) break; + }while(buf[0] != 0x16 || buf[1] != 0x04); + + + fts_command(info, SLEEPOUT); + fts_delay(50); + + fts_command(info, SENSEON); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) + fts_command(info, FTS_CMD_KEY_SENSE_ON); +#endif + + fts_command(info, FLUSHBUFFER); +} + +#ifdef CONFIG_PM +static int fts_pm_suspend(struct device *dev) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + tsp_debug_err(true, &info->client->dev, "%s\n", __func__);; + + mutex_lock(&info->input_dev->mutex); + + if (info->input_dev->users) + fts_stop_device(info); + + mutex_unlock(&info->input_dev->mutex); + + return 0; +} + +static int fts_pm_resume(struct device *dev) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + tsp_debug_err(true, &info->client->dev, "%s\n", __func__); + + mutex_lock(&info->input_dev->mutex); + + if (info->input_dev->users) + fts_start_device(info); + + mutex_unlock(&info->input_dev->mutex); + + return 0; +} +#endif + +#if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) +static int fts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct fts_ts_info *info = i2c_get_clientdata(client); + + tsp_debug_info(true, &info->client->dev, "%s\n", __func__); + + fts_stop_device(info); + + return 0; +} + +static int fts_resume(struct i2c_client *client) +{ + + struct fts_ts_info *info = i2c_get_clientdata(client); + + tsp_debug_info(true, &info->client->dev, "%s\n", __func__); + + fts_start_device(info); + + return 0; +} +#endif + +static const struct i2c_device_id fts_device_id[] = { + {FTS_TS_DRV_NAME, 0}, + {} +}; + +#ifdef CONFIG_PM +static const struct dev_pm_ops fts_dev_pm_ops = { + .suspend = fts_pm_suspend, + .resume = fts_pm_resume, +}; +#endif + +#ifdef CONFIG_OF +static struct of_device_id fts_match_table[] = { + { .compatible = "stm,fts_touch",}, + { }, +}; +#else +#define fts_match_table NULL +#endif + +static struct i2c_driver fts_i2c_driver = { + .driver = { + .name = FTS_TS_DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = fts_match_table, +#endif +#ifdef CONFIG_PM + .pm = &fts_dev_pm_ops, +#endif + }, + .probe = fts_probe, + .remove = fts_remove, + .shutdown = fts_shutdown, +#if (!defined(CONFIG_HAS_EARLYSUSPEND)) && (!defined(CONFIG_PM)) && !defined(USE_OPEN_CLOSE) + .suspend = fts_suspend, + .resume = fts_resume, +#endif + .id_table = fts_device_id, +}; + +static int __init fts_driver_init(void) +{ + return i2c_add_driver(&fts_i2c_driver); +} + +static void __exit fts_driver_exit(void) +{ + i2c_del_driver(&fts_i2c_driver); +} + +MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver"); +MODULE_AUTHOR("STMicroelectronics, Inc."); +MODULE_LICENSE("GPL v2"); + +module_init(fts_driver_init); +module_exit(fts_driver_exit); diff --git a/drivers/input/touchscreen/stm/fts5ad56/fts_ts.h b/drivers/input/touchscreen/stm/fts5ad56/fts_ts.h new file mode 100644 index 000000000000..74b32b49071f --- /dev/null +++ b/drivers/input/touchscreen/stm/fts5ad56/fts_ts.h @@ -0,0 +1,494 @@ +#ifndef _LINUX_FTS_TS_H_ +#define _LINUX_FTS_TS_H_ + +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +#include +#endif +#ifdef CONFIG_INPUT_BOOSTER +#include +#endif + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +#define tsp_debug_dbg(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_dbg(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_dbg(dev, fmt, ## __VA_ARGS__); \ +}) + +#define tsp_debug_info(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_info(dev, fmt, ## __VA_ARGS__); \ +}) + +#define tsp_debug_err(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_err(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_err(dev, fmt, ## __VA_ARGS__); \ +}) +#else +#define tsp_debug_dbg(mode, dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__) +#define tsp_debug_info(mode, dev, fmt, ...) dev_info(dev, fmt, ## __VA_ARGS__) +#define tsp_debug_err(mode, dev, fmt, ...) dev_err(dev, fmt, ## __VA_ARGS__) +#endif + +#define USE_OPEN_CLOSE + +#ifdef USE_OPEN_DWORK +#define TOUCH_OPEN_DWORK_TIME 10 +#endif + +//#define FTS_SUPPROT_MULTIMEDIA + +/* +#define FTS_SUPPORT_STRINGLIB +*/ +#define FIRMWARE_IC "fts_ic" + +#define FTS_MAX_FW_PATH 64 + +#define FTS_TS_DRV_NAME "fts_touch" +#define FTS_TS_DRV_VERSION "0132" + +#define STM_DEVICE_NAME "STM" + +#define FTS_ID0 0x39 +#define FTS_ID1 0x80 +#define FTS_ID2 0x6C + +#define FTS_DIGITAL_REV_1 0x01 +#define FTS_DIGITAL_REV_2 0x02 +#define FTS_FIFO_MAX 32 +#define FTS_EVENT_SIZE 8 + +#define PRESSURE_MIN 0 +#define PRESSURE_MAX 127 +#define P70_PATCH_ADDR_START 0x00420000 +#define FINGER_MAX 10 +#define AREA_MIN PRESSURE_MIN +#define AREA_MAX PRESSURE_MAX + +#define EVENTID_NO_EVENT 0x00 +#define EVENTID_ENTER_POINTER 0x03 +#define EVENTID_LEAVE_POINTER 0x04 +#define EVENTID_MOTION_POINTER 0x05 +#define EVENTID_HOVER_ENTER_POINTER 0x07 +#define EVENTID_HOVER_LEAVE_POINTER 0x08 +#define EVENTID_HOVER_MOTION_POINTER 0x09 +#define EVENTID_PROXIMITY_IN 0x0B +#define EVENTID_PROXIMITY_OUT 0x0C +#define EVENTID_MSKEY 0x0E +#define EVENTID_ERROR 0x0F +#define EVENTID_CONTROLLER_READY 0x10 +#define EVENTID_SLEEPOUT_CONTROLLER_READY 0x11 +#define EVENTID_RESULT_READ_REGISTER 0x12 +#define EVENTID_STATUS_EVENT 0x16 +#define EVENTID_INTERNAL_RELEASE_INFO 0x19 +#define EVENTID_EXTERNAL_RELEASE_INFO 0x1A + +#define EVENTID_FROM_STRING 0x80 +#define EVENTID_GESTURE 0x20 + +#define EVENTID_SIDE_SCROLL 0x40 +#define EVENTID_SIDE_TOUCH_DEBUG 0xDB /* side touch event-id for debug, remove after f/w fixed */ +#define EVENTID_SIDE_TOUCH 0x0B + +#define STATUS_EVENT_MUTUAL_AUTOTUNE_DONE 0x01 +#define STATUS_EVENT_SELF_AUTOTUNE_DONE 0x42 +#define STATUS_EVENT_WATER_SELF_AUTOTUNE_DONE 0x4E +#define STATUS_EVENT_FORCE_CAL_DONE 0x15 +#ifdef FTS_SUPPORT_WATER_MODE +#define STATUS_EVENT_WATER_SELF_DONE 0x17 +#endif +#define STATUS_EVENT_FLASH_WRITE_CONFIG 0x03 +#define STATUS_EVENT_FLASH_WRITE_CXTUNE_VALUE 0x04 +#define STATUS_EVENT_FORCE_CAL_MUTUAL_SELF 0x05 +#define STATUS_EVENT_FORCE_CAL_MUTUAL 0x15 +#define STATUS_EVENT_FORCE_CAL_SELF 0x06 +#define STATUS_EVENT_WATERMODE_ON 0x07 +#define STATUS_EVENT_WATERMODE_OFF 0x08 +#define STATUS_EVENT_RTUNE_MUTUAL 0x09 +#define STATUS_EVENT_RTUNE_SELF 0x0A +#define STATUS_EVENT_PANEL_TEST_RESULT 0x0B +#define STATUS_EVENT_GLOVE_MODE 0x0C +#define STATUS_EVENT_RAW_DATA_READY 0x0D +#define STATUS_EVENT_MUTUAL_CAL_FRAME_CHECK 0xC1 +#define STATUS_EVENT_SELF_CAL_FRAME_CHECK 0xC2 +#define STATUS_EVENT_CHARGER_CONNECTED 0xCC +#define STATUS_EVENT_CHARGER_DISCONNECTED 0xCD + +#define INT_ENABLE 0x41 +#define INT_DISABLE 0x00 + +#define READ_STATUS 0x84 +#define READ_ONE_EVENT 0x85 +#define READ_ALL_EVENT 0x86 + +#define SLEEPIN 0x90 +#define SLEEPOUT 0x91 +#define SENSEOFF 0x92 +#define SENSEON 0x93 +#define FTS_CMD_HOVER_OFF 0x94 +#define FTS_CMD_HOVER_ON 0x95 + +#define FTS_CMD_MSKEY_AUTOTUNE 0x96 +#define FTS_CMD_TRIM_LOW_POWER_OSCILLATOR 0x97 + +#define FTS_CMD_KEY_SENSE_OFF 0x9A +#define FTS_CMD_KEY_SENSE_ON 0x9B +#define FTS_CMD_SET_FAST_GLOVE_MODE 0x9D + +#define FTS_CMD_MSHOVER_OFF 0x9E +#define FTS_CMD_MSHOVER_ON 0x9F +#define FTS_CMD_SET_NOR_GLOVE_MODE 0x9F + +#define FLUSHBUFFER 0xA1 +#define FORCECALIBRATION 0xA2 +#define CX_TUNNING 0xA3 +#define SELF_AUTO_TUNE 0xA4 + +#define FTS_CMD_CHARGER_PLUGGED 0xA8 +#define FTS_CMD_CHARGER_UNPLUGGED 0xAB + +#define FTS_CMD_RELEASEINFO 0xAA +#define FTS_CMD_STYLUS_OFF 0xAB +#define FTS_CMD_STYLUS_ON 0xAC +#define FTS_CMD_LOWPOWER_MODE 0xAD + +#define FTS_CMS_ENABLE_FEATURE 0xC1 +#define FTS_CMS_DISABLE_FEATURE 0xC2 + +#define FTS_CMD_WRITE_PRAM 0xF0 +#define FTS_CMD_BURN_PROG_FLASH 0xF2 +#define FTS_CMD_ERASE_PROG_FLASH 0xF3 +#define FTS_CMD_READ_FLASH_STAT 0xF4 +#define FTS_CMD_UNLOCK_FLASH 0xF7 +#define FTS_CMD_SAVE_FWCONFIG 0xFB +#define FTS_CMD_SAVE_CX_TUNING 0xFC + +#define FTS_CMD_FAST_SCAN 0x01 +#define FTS_CMD_SLOW_SCAN 0x02 +#define FTS_CMD_USLOW_SCAN 0x03 + +#define REPORT_RATE_90HZ 0 +#define REPORT_RATE_60HZ 1 +#define REPORT_RATE_30HZ 2 + +#define FTS_CMD_STRING_ACCESS 0xEC00 +#define FTS_CMD_NOTIFY 0xC0 + +#define FTS_RETRY_COUNT 10 + +/* QUICK SHOT : Quick Camera Launching */ +#define FTS_STRING_EVENT_REAR_CAM (1 << 0) +#define FTS_STRING_EVENT_FRONT_CAM (1 << 1) + +/* SCRUB : Display Watch, Event Status / Fast Access Event */ +#define FTS_STRING_EVENT_WATCH_STATUS (1 << 2) +#define FTS_STRING_EVENT_FAST_ACCESS (1 << 3) +#define FTS_STRING_EVENT_DIRECT_INDICATOR (1 << 3) | (1 << 2) +#define FTS_STRING_EVENT_SPAY (1 << 4) +#define FTS_STRING_EVENT_SPAY1 (1 << 5) +#define FTS_STRING_EVENT_SPAY2 (1 << 4) | (1 << 5) + +#define FTS_SIDEGESTURE_EVENT_SINGLE_STROKE 0xE0 +#define FTS_SIDEGESTURE_EVENT_DOUBLE_STROKE 0xE1 +#define FTS_SIDEGESTURE_EVENT_INNER_STROKE 0xE3 + +#define FTS_SIDETOUCH_EVENT_LONG_PRESS 0xBB +#define FTS_SIDETOUCH_EVENT_REBOOT_BY_ESD 0xED + +#define FTS_ENABLE 1 +#define FTS_DISABLE 0 + +#define FTS_MODE_QUICK_SHOT (1 << 0) +#define FTS_MODE_SCRUB (1 << 1) +#define FTS_MODE_SPAY (1 << 1) +#define FTS_MODE_QUICK_APP_ACCESS (1 << 2) +#define FTS_MODE_DIRECT_INDICATOR (1 << 3) + +#define TSP_BUF_SIZE 3000 +#define CMD_STR_LEN 32 +#define CMD_RESULT_STR_LEN 3000 +#define CMD_PARAM_NUM 8 + +#define FTS_LOWP_FLAG_QUICK_CAM (1 << 0) +#define FTS_LOWP_FLAG_2ND_SCREEN (1 << 1) +#define FTS_LOWP_FLAG_BLACK_UI (1 << 2) +#define FTS_LOWP_FLAG_QUICK_APP_ACCESS (1 << 3) +#define FTS_LOWP_FLAG_DIRECT_INDICATOR (1 << 4) +#define FTS_LOWP_FLAG_SPAY (1 << 5) +#define FTS_LOWP_FLAG_TEMP_CMD (1 << 6) + + +/* refer to lcd driver to support TB UB */ +#define S6E3HF2_WQXGA_ID1 0x404013 +#define S6E3HF2_WQXGA_ID2 0x404014 + +/* refer to lcd driver to support ZEROF module at NOBLE/ZEN */ +#define S6E3HA2_WQXGA_ZERO 0x410013 +#define S6E3HA2_WQXGA_ZERO1 0x400013 +#define S6E3HA2_WQXGA_ZERO2 0x410012 + +// ZEN Temp for UB VZW +#define ZEN_UB_VZW 0x000010 + +/* LCD ID 0x ID1 ID2 ID3 */ +#define LCD_ID2_MODEL_MASK 0x003000 // ID2 - 00110000 +#define LCD_ID3_DIC_MASK 0x0000C0 // ID3 - 11000000 + +#define MODEL_ZERO 0x000000 +#define MODEL_NOBLE 0x001000 +#define MODEL_ZEN 0x002000 + +#define S6E3HF2_ZERO 0x000000 +#define S6E3HA3_NOBLE 0x000040 +#define S6E3HA3_ZEN 0x000080 + +#define SMARTCOVER_COVER // for Various Cover +#ifdef SMARTCOVER_COVER +#define MAX_W 16 // zero is 16 x 28 +#define MAX_H 32 // byte size to IC +#define MAX_TX MAX_W +#define MAX_BYTE MAX_H +#endif + +#ifdef FTS_SUPPROT_MULTIMEDIA +#define MAX_BRUSH_STEP 230 +#endif + +enum fts_error_return { + FTS_NOT_ERROR = 0, + FTS_ERROR_INVALID_CHIP_ID, + FTS_ERROR_INVALID_CHIP_VERSION_ID, + FTS_ERROR_INVALID_SW_VERSION, + FTS_ERROR_EVENT_ID, + FTS_ERROR_TIMEOUT, + FTS_ERROR_FW_UPDATE_FAIL, +}; +#define RAW_MAX 3750 +/** + * struct fts_finger - Represents fingers. + * @ state: finger status (Event ID). + * @ mcount: moving counter for debug. + */ +struct fts_finger { + unsigned char state; + unsigned short mcount; + int lx; + int ly; +}; + +enum tsp_power_mode { + FTS_POWER_STATE_ACTIVE = 0, + FTS_POWER_STATE_LOWPOWER, + FTS_POWER_STATE_POWERDOWN, + FTS_POWER_STATE_DEEPSLEEP, +}; + +enum fts_cover_id { + FTS_FLIP_WALLET = 0, + FTS_VIEW_COVER, + FTS_COVER_NOTHING1, + FTS_VIEW_WIRELESS, + FTS_COVER_NOTHING2, + FTS_CHARGER_COVER, + FTS_VIEW_WALLET, + FTS_LED_COVER, + FTS_CLEAR_FLIP_COVER, + FTS_QWERTY_KEYBOARD_EUR, + FTS_QWERTY_KEYBOARD_KOR, + FTS_MONTBLANC_COVER = 100, +}; + +enum fts_customer_feature { + FTS_FEATURE_ORIENTATION_GESTURE = 1, + FTS_FEATURE_STYLUS, + FTS_FEATURE_QUICK_SHORT_CAMERA_ACCESS, + FTS_FEATURE_SIDE_GUSTURE, + FTS_FEATURE_COVER_GLASS, + FTS_FEATURE_COVER_WALLET, + FTS_FEATURE_COVER_LED, + FTS_FEATURE_COVER_CLEAR_FLIP, + FTS_FEATURE_DUAL_SIDE_GUSTURE, + FTS_FEATURE_CUSTOM_COVER_GLASS_ON, +}; + +#ifdef FTS_SUPPROT_MULTIMEDIA +enum BRUSH_MODE { + Brush = 0, + Velocity, +}; +#endif + +struct fts_ts_info { + struct device *dev; + struct i2c_client *client; + struct input_dev *input_dev; + struct hrtimer timer; + struct timer_list timer_charger; + struct timer_list timer_firmware; + struct work_struct work; + + int irq; + int irq_type; + bool irq_enabled; + struct fts_i2c_platform_data *board; + void (*register_cb) (void *); + struct fts_callbacks callbacks; + struct mutex lock; + bool enabled; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +#ifdef SEC_TSP_FACTORY_TEST + struct device *fac_dev_ts; + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[CMD_STR_LEN]; + int cmd_param[CMD_PARAM_NUM]; + char cmd_result[CMD_RESULT_STR_LEN]; + int cmd_buffer_size; + struct mutex cmd_lock; + bool cmd_is_running; + int SenseChannelLength; + int ForceChannelLength; + short *pFrame; + unsigned char *cx_data; + struct delayed_work cover_cmd_work; + int delayed_cmd_param[2]; +#endif + + bool hover_ready; + bool hover_enabled; + bool mshover_enabled; + bool fast_mshover_enabled; + bool flip_enable; + bool run_autotune; + bool mainscr_disable; + unsigned int cover_type; + + unsigned char lowpower_flag; + bool lowpower_mode; + bool deepsleep_mode; + int fts_power_state; +#ifdef FTS_SUPPORT_STRINGLIB + unsigned char fts_mode; +#endif +#ifdef FTS_SUPPORT_TA_MODE + bool TA_Pluged; +#endif + +#ifdef FTS_SUPPORT_2NDSCREEN + u8 SIDE_Flag; + u8 previous_SIDE_value; +#endif + +#ifdef FTS_SUPPORT_TOUCH_KEY + unsigned char tsp_keystatus; + int touchkey_threshold; + struct device *fac_dev_tk; +#endif + + int digital_rev; + int touch_count; + struct fts_finger finger[FINGER_MAX]; + + int touch_mode; + int retry_hover_enable_after_wakeup; + + int ic_product_id; /* product id of ic */ + int ic_revision_of_ic; /* revision of reading from IC */ + int fw_version_of_ic; /* firmware version of IC */ + int ic_revision_of_bin; /* revision of reading from binary */ + int fw_version_of_bin; /* firmware version of binary */ + int config_version_of_ic; /* Config release data from IC */ + int config_version_of_bin; /* Config release data from IC */ + unsigned short fw_main_version_of_ic; /* firmware main version of IC */ + unsigned short fw_main_version_of_bin; /* firmware main version of binary */ + int panel_revision; /* Octa panel revision */ + int tspid_val; + int tspid2_val; + +#ifdef USE_OPEN_DWORK + struct delayed_work open_work; +#endif + +#ifdef FTS_SUPPORT_NOISE_PARAM + struct fts_noise_param noise_param; + int (*fts_get_noise_param_address) (struct fts_ts_info *info); +#endif + unsigned int delay_time; + unsigned int debug_string; + struct delayed_work reset_work; +#ifdef CONFIG_SEC_DEBUG_TSP_LOG + struct delayed_work debug_work; + bool rawdata_read_lock; +#endif + + unsigned int scrub_id; + unsigned int scrub_x; + unsigned int scrub_y; + + struct mutex i2c_mutex; + struct mutex device_mutex; + bool touch_stopped; + bool reinit_done; + + unsigned char data[FTS_EVENT_SIZE * FTS_FIFO_MAX]; + unsigned char ddi_type; + + const char *firmware_name; + +#ifdef SMARTCOVER_COVER + bool smart_cover[MAX_BYTE][MAX_TX]; + bool changed_table[MAX_TX][MAX_BYTE]; + u8 send_table[MAX_TX][4]; +#endif +#ifdef FTS_SUPPROT_MULTIMEDIA + bool brush_enable; + bool velocity_enable; + int brush_size; +#endif + + int (*stop_device) (struct fts_ts_info * info); + int (*start_device) (struct fts_ts_info * info); + + int (*fts_write_reg)(struct fts_ts_info *info, unsigned char *reg, unsigned short num_com); + int (*fts_read_reg)(struct fts_ts_info *info, unsigned char *reg, int cnum, unsigned char *buf, int num); + void (*fts_systemreset)(struct fts_ts_info *info); + int (*fts_wait_for_ready)(struct fts_ts_info *info); + void (*fts_command)(struct fts_ts_info *info, unsigned char cmd); + void (*fts_enable_feature)(struct fts_ts_info *info, unsigned char cmd, int enable); + int (*fts_get_version_info)(struct fts_ts_info *info); +#ifdef FTS_SUPPORT_STRINGLIB + int (*fts_read_from_string)(struct fts_ts_info *info, unsigned short *reg, unsigned char *data, int length); + int (*fts_write_to_string)(struct fts_ts_info *info, unsigned short *reg, unsigned char *data, int length); +#endif +}; + +int fts_fw_update_on_probe(struct fts_ts_info *info); +int fts_fw_update_on_hidden_menu(struct fts_ts_info *info, int update_type); +void fts_fw_init(struct fts_ts_info *info); +void fts_execute_autotune(struct fts_ts_info *info); +int fts_fw_wait_for_event(struct fts_ts_info *info, unsigned char eid); + +#endif //_LINUX_FTS_TS_H_ diff --git a/drivers/input/touchscreen/stm/fts_fwu.c b/drivers/input/touchscreen/stm/fts_fwu.c index 2ea95414e4ed..bf3c9adabd97 100644 --- a/drivers/input/touchscreen/stm/fts_fwu.c +++ b/drivers/input/touchscreen/stm/fts_fwu.c @@ -240,6 +240,12 @@ void fts_fw_init(struct fts_ts_info *info) info->fts_command(info, SENSEON); +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else + fts_fw_wait_for_event (info, STATUS_EVENT_FORCE_CAL_DONE); +#endif + #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) info->fts_command(info, FTS_CMD_KEY_SENSE_ON); diff --git a/drivers/input/touchscreen/stm/fts_sec.c b/drivers/input/touchscreen/stm/fts_sec.c index be5e23300b3f..80aa3d64fff5 100644 --- a/drivers/input/touchscreen/stm/fts_sec.c +++ b/drivers/input/touchscreen/stm/fts_sec.c @@ -65,6 +65,7 @@ static void get_cx_all_data(void *device_data); static void run_cx_data_read(void *device_data); #ifdef FTS_SUPPORT_TOUCH_KEY static void run_key_cx_data_read(void *device_data); +static void run_key_cm_data_read(void *device_data); #endif static void set_tsp_test_result(void *device_data); static void get_tsp_test_result(void *device_data); @@ -89,6 +90,8 @@ static void second_screen_enable(void *device_data); static void set_longpress_enable(void *device_data); static void set_sidescreen_x_length(void *device_data); static void set_dead_zone(void *device_data); +static void dead_zone_enable(void *device_data); + #ifdef SMARTCOVER_COVER static void smartcover_cmd(void *device_data); #endif @@ -165,6 +168,7 @@ struct ft_cmd ft_commands[] = { {FT_CMD("run_cx_data_read", run_cx_data_read),}, #ifdef FTS_SUPPORT_TOUCH_KEY {FT_CMD("run_key_cx_data_read", run_key_cx_data_read),}, + {FT_CMD("run_key_cm_data_read", run_key_cm_data_read),}, #endif {FT_CMD("set_tsp_test_result", set_tsp_test_result),}, {FT_CMD("get_tsp_test_result", get_tsp_test_result),}, @@ -188,6 +192,7 @@ struct ft_cmd ft_commands[] = { {FT_CMD("set_longpress_enable", set_longpress_enable),}, {FT_CMD("set_sidescreen_x_length", set_sidescreen_x_length),}, {FT_CMD("set_dead_zone", set_dead_zone),}, + {FT_CMD("dead_zone_enable", dead_zone_enable),}, #ifdef FTS_SUPPORT_STRINGLIB {FT_CMD("quick_shot_enable", quick_shot_enable),}, {FT_CMD("scrub_enable", scrub_enable),}, @@ -1013,13 +1018,10 @@ static void get_fw_ver_bin(void *device_data) sprintf(buff, "ST%01X%01X%04X", info->tspid_val, info->tspid2_val, info->fw_main_version_of_bin); - } else if (strncmp(info->board->model_name, "G920", 4) == 0) { + } else { sprintf(buff, "ST%02X%04X", info->panel_revision, info->fw_main_version_of_bin); - } else { - tsp_debug_info(true, &info->client->dev, "%s: Check model name[%s]!\n", - __func__, info->board->model_name); } set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); @@ -1040,13 +1042,10 @@ static void get_fw_ver_ic(void *device_data) sprintf(buff, "ST%01X%01X%04X", info->tspid_val, info->tspid2_val, info->fw_main_version_of_ic); - } else if (strncmp(info->board->model_name, "G920", 4) == 0) { + } else { sprintf(buff, "ST%02X%04X", info->panel_revision, info->fw_main_version_of_ic); - } else { - tsp_debug_info(true, &info->client->dev, "%s: Check model name[%s]!\n", - __func__, info->board->model_name); } set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); @@ -1301,6 +1300,7 @@ static void run_rawcap_read(void *device_data) char buff[CMD_STR_LEN] = { 0 }; short min = 0x7FFF; short max = 0x8000; + unsigned char regAdd[4] = {0xB0, 0x04, 0x49, 0x00}; set_default_result(info); @@ -1370,7 +1370,12 @@ static void run_rawcap_read(void *device_data) fts_execute_autotune(info); + //STMicro Auto-tune protection disable + fts_write_reg(info, regAdd, 4); + fts_delay(1); + fts_command(info, SLEEPOUT); + fts_delay(1); fts_command(info, SENSEON); #ifdef FTS_SUPPORT_WATER_MODE fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); @@ -1658,11 +1663,20 @@ static void fts_read_ix_data(struct fts_ts_info *info, bool allnode) return; } - fts_command(info, SLEEPIN); // Sleep In for INT disable +// fts_command(info, SLEEPIN); // Sleep In for INT disable disable_irq(info->irq); fts_interrupt_set(info, INT_DISABLE); + fts_command(info, SENSEOFF); + + fts_delay(50); + + #ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + } + #endif fts_command(info, FLUSHBUFFER); // Clear FIFO fts_delay(50); @@ -1777,6 +1791,9 @@ static void fts_read_ix_data(struct fts_ts_info *info, bool allnode) tsp_debug_info(true, &info->client->dev, "%s MIN_RX_IX_SUM : %d MAX_RX_IX_SUM : %d\n", __func__, min_rx_ix_sum, max_rx_ix_sum ); + fts_systemreset(info); + fts_wait_for_ready(info); + fts_command(info, SLEEPOUT); fts_delay(1); fts_command(info, SENSEON); @@ -1894,10 +1911,19 @@ static void fts_read_self_raw_frame(struct fts_ts_info *info, unsigned short oAd return; } - fts_command(info, SLEEPIN); // Sleep In for INT disable +// fts_command(info, SLEEPIN); // Sleep In for INT disable disable_irq(info->irq); fts_interrupt_set(info, INT_DISABLE); + fts_command(info, SENSEOFF); + + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + } +#endif fts_command(info, FLUSHBUFFER); // Clear FIFO fts_delay(50); @@ -2181,6 +2207,8 @@ static void run_cx_data_read(void *device_data) tsp_debug_info(true, &info->client->dev, "%s: start \n", __func__); fts_command(info, SENSEOFF); + fts_delay(50); + #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) { fts_command(info, FTS_CMD_KEY_SENSE_OFF); // Key Sensor OFF @@ -2338,6 +2366,126 @@ static void run_key_cx_data_read(void *device_data) set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } + +#define KEY_CHANNEL_LENGTH 4 +#define USING_KEY_CHANNEL_LENGTH 2 + +static void run_key_cm_data_read(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char data[4] = { 0 }; + unsigned char addr[4] = {0xD0, 0x00, 0x32, 0x00};// key channel address is 0xD0, 0x00, 0x32 + unsigned int start_addr; + unsigned int end_addr; + unsigned int length; + unsigned int len; + unsigned char *buffer = NULL; + unsigned char *pbuffer = NULL; + int ii; + unsigned int cm_value; + unsigned int max_val = 0; + unsigned int min_val = 32767; + + set_default_result(info); + + if (info->touch_stopped) { + tsp_debug_info(true, &info->client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(buff, sizeof(buff), "%s", "TSP turned off"); + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + info->cmd_state = CMD_STATUS_NOT_APPLICABLE; + return; + } + + disable_irq(info->irq); + + fts_command(info, SENSEOFF); + fts_delay(50); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_OFF); + fts_delay(50); + } +#endif + + fts_command(info, FLUSHBUFFER); + fts_delay(50); + + fts_read_reg(info, addr, 3, data, 4); + tsp_debug_info(true, &info->client->dev, "%s: %X, %X, %X, %X\n", + __func__, data[0], data[1], data[2], data[3]); + + fts_delay(10); + + // key channel length : 4 + start_addr = data[1] + (data[2] << 8); + length = KEY_CHANNEL_LENGTH * 2 + 1; + end_addr = start_addr + length; + + buffer = kzalloc(length, GFP_KERNEL); + if (!buffer) { + snprintf(buff, sizeof(buff), "%s", "FAIL"); + goto err_key_cm_out; + } + + tsp_debug_info(true, &info->client->dev, "%s: start: %X, end: %X, length: %X, len: %X\n", + __func__, start_addr, end_addr, length, len); + + addr[0] = 0xD0; + addr[1] = (start_addr >> 8) & 0xff; + addr[2] = (start_addr & 0xff); + + memset(buffer, 0x00, length); + pbuffer = buffer; + fts_read_reg(info, addr, 3, buffer, length); + + tsp_debug_info(true, &info->client->dev, "%s: %X\n", __func__, *pbuffer); + + pbuffer++; + + for (ii = 0; ii < USING_KEY_CHANNEL_LENGTH; ii++) { + cm_value = 0; + + tsp_debug_info(true, &info->client->dev, "%s: (D2) %X\n", __func__, *pbuffer); + + cm_value |= (*pbuffer & 0xFF); + pbuffer++; + + tsp_debug_info(true, &info->client->dev, "%s: (D1) %X\n", __func__, *pbuffer); + + cm_value |= (*pbuffer << 8); + pbuffer++; + + tsp_debug_info(true, &info->client->dev, "%s: [%d]: %d(%X)\n", __func__, ii, cm_value, cm_value); + + max_val = max(max_val, cm_value); + min_val = min(min_val, cm_value); + + } + + tsp_debug_info(true, &info->client->dev, "max: %d, min: %d\n", max_val, min_val); + + snprintf(buff, CMD_STR_LEN, "%d,%d", max_val, min_val); + + kfree(buffer); + +err_key_cm_out: + enable_irq(info->irq); + fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_TOUCH_KEY + if (info->board->support_mskey) { + fts_command(info, FTS_CMD_KEY_SENSE_ON); + fts_delay(50); + } +#endif + + info->cmd_state = CMD_STATUS_OK; + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} #endif static void set_tsp_test_result(void *device_data) @@ -3060,6 +3208,47 @@ static void set_dead_zone(void *device_data) tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); } +static void dead_zone_enable(void *device_data) +{ + struct fts_ts_info *info = (struct fts_ts_info *)device_data; + char buff[CMD_STR_LEN] = { 0 }; + unsigned char regAdd[2] = {0xC2, 0x0C}; + int ret; + + set_default_result(info); + + if (info->cmd_param[0] < 0 || info->cmd_param[0] > 1) { + snprintf(buff, sizeof(buff), "%s", "NG"); + info->cmd_state = CMD_STATUS_FAIL; + } else { + if (info->cmd_param[0]==0) { + regAdd[0] = 0xC1; /* dead zone disable */ + } else { + regAdd[0] = 0xC2; /* dead zone enable */ + } + + ret = fts_write_reg(info, regAdd, 2); + + if (ret < 0) + tsp_debug_err(true, &info->client->dev, "%s failed. ret: %d\n", __func__, ret); + else + tsp_debug_info(true, &info->client->dev, "%s: reg:%d, ret: %d\n", __func__, info->cmd_param[0], ret); + + fts_delay(1); + + snprintf(buff, sizeof(buff), "%s", "OK"); + info->cmd_state = CMD_STATUS_OK; + } + set_cmd_result(info, buff, strnlen(buff, sizeof(buff))); + + mutex_lock(&info->cmd_lock); + info->cmd_is_running = false; + mutex_unlock(&info->cmd_lock); + info->cmd_state = CMD_STATUS_WAITING; + + tsp_debug_info(true, &info->client->dev, "%s: %s\n", __func__, buff); +} + static void set_mainscreen_disable_cmd(struct fts_ts_info *info, bool on) { int ret; @@ -3777,8 +3966,14 @@ static void run_autotune(void *device_data) fts_execute_autotune(info); fts_command(info, SLEEPOUT); + fts_delay(1); fts_command(info, SENSEON); + +#ifdef FTS_SUPPORT_WATER_MODE + fts_fw_wait_for_event(info, STATUS_EVENT_WATER_SELF_DONE); +#else fts_fw_wait_for_event(info, STATUS_EVENT_FORCE_CAL_DONE); +#endif #ifdef FTS_SUPPORT_TOUCH_KEY if (info->board->support_mskey) fts_command(info, FTS_CMD_KEY_SENSE_ON); diff --git a/drivers/input/touchscreen/stm/fts_ts.c b/drivers/input/touchscreen/stm/fts_ts.c index 4452e21fb265..7c730a36e982 100644 --- a/drivers/input/touchscreen/stm/fts_ts.c +++ b/drivers/input/touchscreen/stm/fts_ts.c @@ -385,6 +385,10 @@ static void fts_set_cover_type(struct fts_ts_info *info, bool enable) case FTS_CLEAR_FLIP_COVER : fts_enable_feature(info, FTS_FEATURE_COVER_CLEAR_FLIP, enable); break; + case FTS_QWERTY_KEYBOARD_EUR : + case FTS_QWERTY_KEYBOARD_KOR : + fts_enable_feature(info, 0x0D, enable); + break; case FTS_CHARGER_COVER: case FTS_COVER_NOTHING1: case FTS_COVER_NOTHING2: @@ -2582,6 +2586,11 @@ static int fts_stop_device(struct fts_ts_info *info) #ifdef FTS_SUPPORT_NOISE_PARAM fts_get_noise_param(info); #endif + +#ifdef FTS_SUPPORT_STRINGLIB + if (info->fts_mode) + fts_enable_feature(info, 0x0B, true); +#endif } else { fts_interrupt_set(info, INT_DISABLE); disable_irq(info->irq); diff --git a/drivers/input/touchscreen/stm/fts_ts.h b/drivers/input/touchscreen/stm/fts_ts.h index ffcd76ff9e36..cd6ff7c3fb42 100644 --- a/drivers/input/touchscreen/stm/fts_ts.h +++ b/drivers/input/touchscreen/stm/fts_ts.h @@ -288,6 +288,8 @@ enum fts_cover_id { FTS_VIEW_WALLET, FTS_LED_COVER, FTS_CLEAR_FLIP_COVER, + FTS_QWERTY_KEYBOARD_EUR, + FTS_QWERTY_KEYBOARD_KOR, FTS_MONTBLANC_COVER = 100, }; diff --git a/drivers/input/touchscreen/synaptics_dsx2/Kconfig b/drivers/input/touchscreen/synaptics_dsx2/Kconfig new file mode 100644 index 000000000000..6437ceb18329 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/Kconfig @@ -0,0 +1,9 @@ +# +# SYNAPTICS TOUCH driver configuration +# + +config TOUCHSCREEN_SYNAPTICS_I2C_DSX2 + tristate "Synaptics DSX2 i2c touchscreen base on bootloader Ver7" + depends on I2C + help + This enables support for Synaptics DSX2 over I2C based touchscreens. diff --git a/drivers/input/touchscreen/synaptics_dsx2/Makefile b/drivers/input/touchscreen/synaptics_dsx2/Makefile new file mode 100644 index 000000000000..7c0cfa63cf02 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_DSX2) += synaptics_i2c_rmi.o rmi_dev.o rmi_fw_update.o rmi_f54.o diff --git a/drivers/input/touchscreen/synaptics_dsx2/rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx2/rmi_dev.c new file mode 100644 index 000000000000..f70036bca8be --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/rmi_dev.c @@ -0,0 +1,736 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "synaptics_i2c_rmi.h" + +#define CHAR_DEVICE_NAME "rmi" +#define DEVICE_CLASS_NAME "rmidev" +#define ATTRIBUTE_FOLDER_NAME "rmidev" +#define DEV_NUMBER 1 +#define REG_ADDR_LIMIT 0xFFFF + +static ssize_t rmidev_sysfs_data_show(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmidev_sysfs_data_store(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmidev_sysfs_open_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_release_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_attn_state_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static struct bin_attribute attr_data = { + .attr = { + .name = "data", + .mode = (S_IRUGO | S_IWUSR | S_IWGRP), + }, + .size = 0, + .read = rmidev_sysfs_data_show, + .write = rmidev_sysfs_data_store, +}; + +RMI_KOBJ_ATTR(open, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, rmidev_sysfs_open_store); +RMI_KOBJ_ATTR(release, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, rmidev_sysfs_release_store); +RMI_KOBJ_ATTR(attn_state, S_IRUGO, rmidev_sysfs_attn_state_show, synaptics_rmi4_store_error); + +static struct attribute *attrs[] = { + &kobj_attr_open.attr, + &kobj_attr_release.attr, + &kobj_attr_attn_state.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static struct class *rmidev_device_class; +static int rmidev_major_num; + +static irqreturn_t rmidev_sysfs_irq(int irq, void *data) +{ + struct synaptics_rmi4_data *rmi4_data = data; + + sysfs_notify(&rmi4_data->input_dev->dev.kobj, + ATTRIBUTE_FOLDER_NAME, "attn_state"); + + return IRQ_HANDLED; +} + +static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, + bool enable) +{ + int retval = 0; + unsigned char intr_status[MAX_INTR_REGISTERS]; + unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING; + struct rmidev_handle *rmidev = rmi4_data->rmidev; + + if (enable) { + if (rmidev->irq_enabled) + return retval; + + /* Clear interrupts first */ + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr + 1, + intr_status, + rmi4_data->num_of_intr_regs); + if (retval < 0) + return retval; + + retval = request_threaded_irq(rmi4_data->irq, NULL, + rmidev_sysfs_irq, irq_flags, + "synaptics_dsx_rmidev", rmi4_data); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create irq thread\n", + __func__); + return retval; + } + + rmidev->irq_enabled = true; + } else { + if (rmidev->irq_enabled) { + disable_irq(rmi4_data->irq); + free_irq(rmi4_data->irq, rmi4_data); + rmidev->irq_enabled = false; + } + } + + return retval; +} + +static ssize_t rmidev_sysfs_data_show(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + int retval; + unsigned int length = (unsigned int)count; + unsigned short address = (unsigned short)pos; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + if (length > (REG_ADDR_LIMIT - address)) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Out of register map limit\n", + __func__); + return -EINVAL; + } + + if (length) { + retval = rmi4_data->i2c_read(rmi4_data, + address, + (unsigned char *)buf, + length); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to read data\n", + __func__); + return retval; + } + } else { + return -EINVAL; + } + + return length; +} + +static ssize_t rmidev_sysfs_data_store(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + int retval; + unsigned int length = (unsigned int)count; + unsigned short address = (unsigned short)pos; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + if (length > (REG_ADDR_LIMIT - address)) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Out of register map limit\n", + __func__); + return -EINVAL; + } + + if (length) { + retval = rmi4_data->i2c_write(rmi4_data, + address, + (unsigned char *)buf, + length); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to write data\n", + __func__); + return retval; + } + } else { + return -EINVAL; + } + + return length; +} + +static ssize_t rmidev_sysfs_open_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input != 1) + return -EINVAL; + + rmi4_data->irq_enable(rmi4_data, false); + rmidev_sysfs_irq_enable(rmi4_data, true); + + dev_dbg(&rmi4_data->i2c_client->dev, + "%s: Attention interrupt disabled\n", + __func__); + + return count; +} + +static ssize_t rmidev_sysfs_release_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input != 1) + return -EINVAL; + + rmidev_sysfs_irq_enable(rmi4_data, false); + rmi4_data->irq_enable(rmi4_data, true); + + dev_dbg(&rmi4_data->i2c_client->dev, + "%s: Attention interrupt enabled\n", + __func__); + + return count; +} + +static ssize_t rmidev_sysfs_attn_state_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int attn_state; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + attn_state = gpio_get_value(rmi4_data->board->gpio); + + return snprintf(buf, PAGE_SIZE, "%u\n", attn_state); +} + +/* + * rmidev_llseek - used to set up register address + * + * @filp: file structure for seek + * @off: offset + * if whence == SEEK_SET, + * high 16 bits: page address + * low 16 bits: register address + * if whence == SEEK_CUR, + * offset from current position + * if whence == SEEK_END, + * offset from end position (0xFFFF) + * @whence: SEEK_SET, SEEK_CUR, or SEEK_END + */ +static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) +{ + loff_t newpos; + struct rmidev_data *dev_data = filp->private_data; + struct rmidev_handle *rmidev = NULL; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + rmi4_data = rmidev->rmi4_data; + + mutex_lock(&(dev_data->file_mutex)); + + switch (whence) { + case SEEK_SET: + newpos = off; + break; + case SEEK_CUR: + newpos = filp->f_pos + off; + break; + case SEEK_END: + newpos = REG_ADDR_LIMIT + off; + break; + default: + newpos = -EINVAL; + goto clean_up; + } + + if (newpos < 0 || newpos > REG_ADDR_LIMIT) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: New position 0x%04x is invalid\n", + __func__, (unsigned int)newpos); + newpos = -EINVAL; + goto clean_up; + } + + filp->f_pos = newpos; + +clean_up: + mutex_unlock(&(dev_data->file_mutex)); + + return newpos; +} + +/* + * rmidev_read: - use to read data from rmi device + * + * @filp: file structure for read + * @buf: user space buffer pointer + * @count: number of bytes to read + * @f_pos: offset (starting register address) + */ +static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + ssize_t retval; + unsigned char tmpbuf[count + 1]; + struct rmidev_data *dev_data = filp->private_data; + struct rmidev_handle *rmidev = NULL; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + if (count == 0) + return 0; + + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + rmi4_data = rmidev->rmi4_data; + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + mutex_lock(&(dev_data->file_mutex)); + + retval = rmi4_data->i2c_read(rmi4_data, + *f_pos, + tmpbuf, + count); + if (retval < 0) + goto clean_up; + + if (copy_to_user(buf, tmpbuf, count)) + retval = -EFAULT; + else + *f_pos += retval; + +clean_up: + mutex_unlock(&(dev_data->file_mutex)); + + return retval; +} + +/* + * rmidev_write: - used to write data to rmi device + * + * @filep: file structure for write + * @buf: user space buffer pointer + * @count: number of bytes to write + * @f_pos: offset (starting register address) + */ +static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + ssize_t retval; + unsigned char tmpbuf[count + 1]; + struct rmidev_data *dev_data = filp->private_data; + struct rmidev_handle *rmidev = NULL; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + if (count == 0) + return 0; + + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + rmi4_data = rmidev->rmi4_data; + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + if (copy_from_user(tmpbuf, buf, count)) + return -EFAULT; + + mutex_lock(&(dev_data->file_mutex)); + + retval = rmi4_data->i2c_write(rmi4_data, + *f_pos, + tmpbuf, + count); + if (retval >= 0) + *f_pos += retval; + + mutex_unlock(&(dev_data->file_mutex)); + + return retval; +} + +/* + * rmidev_open: enable access to rmi device + * @inp: inode struture + * @filp: file structure + */ +static int rmidev_open(struct inode *inp, struct file *filp) +{ + int retval = 0; + struct rmidev_data *dev_data = + container_of(inp->i_cdev, struct rmidev_data, main_dev); + struct rmidev_handle *rmidev = NULL; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (!dev_data) + return -EACCES; + + filp->private_data = dev_data; + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + rmi4_data = rmidev->rmi4_data; + + mutex_lock(&(dev_data->file_mutex)); + + rmi4_data->irq_enable(rmi4_data, false); + dev_dbg(&rmi4_data->i2c_client->dev, + "%s: Attention interrupt disabled\n", + __func__); + + if (dev_data->ref_count < 1) + dev_data->ref_count++; + else + retval = -EACCES; + + mutex_unlock(&(dev_data->file_mutex)); + + return retval; +} + +/* + * rmidev_release: - release access to rmi device + * @inp: inode structure + * @filp: file structure + */ +static int rmidev_release(struct inode *inp, struct file *filp) +{ + struct rmidev_data *dev_data = + container_of(inp->i_cdev, struct rmidev_data, main_dev); + struct rmidev_handle *rmidev = NULL; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (!dev_data) + return -EACCES; + + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + rmi4_data = rmidev->rmi4_data; + + mutex_lock(&(dev_data->file_mutex)); + + dev_data->ref_count--; + if (dev_data->ref_count < 0) + dev_data->ref_count = 0; + + rmi4_data->irq_enable(rmi4_data, true); + dev_dbg(&rmi4_data->i2c_client->dev, + "%s: Attention interrupt enabled\n", + __func__); + + mutex_unlock(&(dev_data->file_mutex)); + + return 0; +} + +static const struct file_operations rmidev_fops = { + .owner = THIS_MODULE, + .llseek = rmidev_llseek, + .read = rmidev_read, + .write = rmidev_write, + .open = rmidev_open, + .release = rmidev_release, +}; + +static void rmidev_device_cleanup(struct rmidev_data *dev_data) +{ + dev_t devno; + struct rmidev_handle *rmidev = NULL; + + if (dev_data) { + rmidev = container_of(dev_data, struct rmidev_handle, dev_data); + + devno = dev_data->main_dev.dev; + + if (dev_data->device_class) + device_destroy(dev_data->device_class, devno); + + cdev_del(&dev_data->main_dev); + + unregister_chrdev_region(devno, 1); + + dev_dbg(&rmidev->rmi4_data->i2c_client->dev, + "%s: rmidev device removed\n", + __func__); + } + + return; +} + +static char *rmi_char_devnode(struct device *dev, umode_t *mode) +{ + if (!mode) + return NULL; + + *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); +} + +static int rmidev_create_device_class(struct synaptics_rmi4_data *rmi4_data) +{ + /* If class is not created, create first it. */ + if (!rmidev_device_class) { + rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); + + if (IS_ERR(rmidev_device_class)) { + dev_err(&rmi4_data->i2c_client->dev, "%s: Failed to create /dev/%s\n", + __func__, CHAR_DEVICE_NAME); + return -ENODEV; + } + + rmidev_device_class->devnode = rmi_char_devnode; + } + + return 0; +} + +static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + dev_t dev_no; + struct device *device_ptr; + struct rmidev_handle *rmidev = NULL; + + rmidev = kzalloc(sizeof(struct rmidev_handle), GFP_KERNEL); + if (!rmidev) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for rmidev\n", + __func__); + retval = -ENOMEM; + goto err_rmidev; + } + + rmi4_data->rmidev = rmidev; + rmidev->rmi4_data = rmi4_data; + + retval = rmidev_create_device_class(rmi4_data); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create device class\n", + __func__); + goto err_device_class; + } + + if (rmidev_major_num) { + dev_no = MKDEV(rmidev_major_num, DEV_NUMBER); + retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); + } else { + retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to allocate char device region\n", + __func__); + goto err_device_region; + } + + rmidev_major_num = MAJOR(dev_no); + dev_dbg(&rmi4_data->i2c_client->dev, + "%s: Major number of rmidev = %d\n", + __func__, rmidev_major_num); + } + + mutex_init(&rmidev->dev_data.file_mutex); + cdev_init(&rmidev->dev_data.main_dev, &rmidev_fops); + + retval = cdev_add(&rmidev->dev_data.main_dev, dev_no, 1); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to add rmi char device\n", + __func__); + goto err_char_device; + } + + dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no)); + rmidev->dev_data.device_class = rmidev_device_class; + + device_ptr = device_create(rmidev->dev_data.device_class, NULL, dev_no, + NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no)); + if (IS_ERR(device_ptr)) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create rmi char device\n", + __func__); + retval = -ENODEV; + goto err_char_device; + } + + retval = gpio_export(rmi4_data->board->gpio, false); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to export attention gpio\n", + __func__); + } else { + retval = gpio_export_link(&(rmi4_data->input_dev->dev), + "attn", rmi4_data->board->gpio); + if (retval < 0) { + dev_err(&rmi4_data->input_dev->dev, + "%s Failed to create gpio symlink\n", + __func__); + } else { + dev_dbg(&rmi4_data->input_dev->dev, + "%s: Exported attention gpio %d\n", + __func__, rmi4_data->board->gpio); + } + } + + rmidev->attr_dir = kobject_create_and_add(ATTRIBUTE_FOLDER_NAME, + &rmi4_data->input_dev->dev.kobj); + if (!rmidev->attr_dir) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs directory\n", + __func__); + retval = -ENODEV; + goto err_attr_dir; + } + + retval = sysfs_create_bin_file(rmidev->attr_dir, + &attr_data); + if (retval < 0) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs bin file\n", + __func__); + goto err_sysfs_bin; + } + + retval = sysfs_create_group(rmidev->attr_dir, &attr_group); + if (retval < 0) { + dev_err(&rmi4_data->input_dev->dev, + "%s: Failed to create sysfs attributes\n", __func__); + retval = -ENODEV; + goto err_sysfs_attrs; + } + + return 0; + +err_sysfs_attrs: + sysfs_remove_group(rmidev->attr_dir, &attr_group); + sysfs_remove_bin_file(rmidev->attr_dir, &attr_data); + +err_sysfs_bin: + kobject_put(rmidev->attr_dir); + +err_attr_dir: +err_char_device: + rmidev_device_cleanup(&rmidev->dev_data); + mutex_destroy(&rmidev->dev_data.file_mutex); + unregister_chrdev_region(dev_no, 1); + +err_device_region: + class_destroy(rmidev_device_class); + +err_device_class: + kfree(rmidev); + rmi4_data->rmidev = NULL; + +err_rmidev: + return retval; +} + +static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data) +{ + struct rmidev_handle *rmidev = rmi4_data->rmidev; + struct rmidev_data *dev_data = NULL; + + if (!rmidev) + goto exit; + + sysfs_remove_group(rmidev->attr_dir, &attr_group); + + sysfs_remove_bin_file(rmidev->attr_dir, &attr_data); + + kobject_put(rmidev->attr_dir); + + dev_data = &rmidev->dev_data; + if (dev_data) { + rmidev_device_cleanup(dev_data); + mutex_destroy(&dev_data->file_mutex); + } + + unregister_chrdev_region(rmidev->dev_no, 1); + + class_destroy(rmidev_device_class); + + kfree(rmidev); + rmi4_data->rmidev = NULL; + +exit: + return; +} + +int rmidev_module_register(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + + retval = synaptics_rmi4_new_function(RMI_DEV, + rmi4_data, + rmidev_init_device, + NULL, + rmidev_remove_device, + NULL); + + return retval; +} diff --git a/drivers/input/touchscreen/synaptics_dsx2/rmi_f54.c b/drivers/input/touchscreen/synaptics_dsx2/rmi_f54.c new file mode 100644 index 000000000000..e021c3b15641 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/rmi_f54.c @@ -0,0 +1,5750 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "synaptics_i2c_rmi.h" + +#define USE_ACTIVE_REPORT_RATE + +#define CMD_GET_REPORT 1 + +#define TSP_RAWCAP_MAX 6000 +#define TSP_RAWCAP_MIN 300 +#define TSP_DELTA_MAX 10 +#define TSP_DELTA_MIN -10 + +#define WATCHDOG_HRTIMER +#define WATCHDOG_TIMEOUT_S 2 +#define FORCE_TIMEOUT_100MS 10 +#define STATUS_WORK_INTERVAL 20 /* ms */ + +#define DO_PREPATION_RETRY_COUNT 2 + +/* +#define RAW_HEX +#define HUMAN_READABLE + */ + +#define STATUS_IDLE 0 +#define STATUS_BUSY 1 +#define STATUS_ERROR 2 + +#define DATA_REPORT_INDEX_OFFSET 1 +#define DATA_REPORT_DATA_OFFSET 3 + +#define SENSOR_RX_MAPPING_OFFSET 1 +#define SENSOR_TX_MAPPING_OFFSET 2 + +#define COMMAND_GET_REPORT 1 +#define COMMAND_FORCE_CAL 2 +#define COMMAND_FORCE_UPDATE 4 + +#define CONTROL_42_SIZE 2 +#define CONTROL_43_54_SIZE 13 +#define CONTROL_55_56_SIZE 2 +#define CONTROL_58_SIZE 1 +#define CONTROL_59_SIZE 2 +#define CONTROL_60_62_SIZE 3 +#define CONTROL_63_SIZE 1 +#define CONTROL_64_67_SIZE 4 +#define CONTROL_68_73_SIZE 8 +#define CONTROL_74_SIZE 2 +#define CONTROL_76_SIZE 1 +#define CONTROL_77_78_SIZE 2 +#define CONTROL_79_83_SIZE 5 +#define CONTROL_84_85_SIZE 2 +#define CONTROL_86_SIZE 1 +#define CONTROL_87_SIZE 1 +#define CONTROL_89_SIZE 1 +#define CONTROL_90_SIZE 1 +#define CONTROL_91_SIZE 1 +#define CONTROL_92_SIZE 1 +#define CONTROL_93_SIZE 1 + +#define HIGH_RESISTANCE_DATA_SIZE 6 +#define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4 +#define TREX_DATA_SIZE 7 + +#define NO_AUTO_CAL_MASK 0x01 +#define ATTRIBUTE_FOLDER_NAME "f54" + +#define concat(a, b) a##b +#define tostring(x) (#x) + +#define GROUP(_attrs) {\ + .attrs = _attrs,\ +} + +#define attrify(propname) (&kobj_attr_##propname.attr) + +#define show_prototype(propname)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + char *buf);\ +\ +static struct kobj_attribute kobj_attr_##propname =\ + __ATTR(propname, S_IRUGO,\ + concat(synaptics_rmi4_f54, _##propname##_show),\ + synaptics_rmi4_store_error); + +#define store_prototype(propname)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + const char *buf, size_t count);\ +\ +static struct kobj_attribute kobj_attr_##propname =\ + __ATTR(propname, S_IWUSR | S_IWGRP,\ + synaptics_rmi4_show_error,\ + concat(synaptics_rmi4_f54, _##propname##_store)); + +#define show_store_prototype(propname)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + char *buf);\ +\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + const char *buf, size_t count);\ +\ +struct kobj_attribute kobj_attr_##propname =\ + __ATTR(propname, (S_IRUGO | S_IWUSR | S_IWGRP),\ + concat(synaptics_rmi4_f54, _##propname##_show),\ + concat(synaptics_rmi4_f54, _##propname##_store)); + +#define simple_show_func(rtype, propname, fmt)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + char *buf)\ +{\ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj);\ + return snprintf(buf, PAGE_SIZE, fmt, rmi4_data->f54->rtype.propname);\ +} \ + +#define simple_show_func_unsigned(rtype, propname)\ +simple_show_func(rtype, propname, "%u\n") + +#define show_func(rtype, rgrp, propname, fmt)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + char *buf)\ +{\ + int retval;\ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj);\ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54;\ +\ + mutex_lock(&f54->rtype##_mutex);\ +\ + retval = rmi4_data->i2c_read(rmi4_data,\ + f54->rtype.rgrp->address,\ + f54->rtype.rgrp->data,\ + sizeof(f54->rtype.rgrp->data));\ + mutex_unlock(&f54->rtype##_mutex);\ + if (retval < 0) {\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Failed to read " #rtype\ + " " #rgrp "\n",\ + __func__);\ + return retval;\ + } \ +\ + return snprintf(buf, PAGE_SIZE, fmt,\ + f54->rtype.rgrp->propname);\ +} \ + +#define show_store_func(rtype, rgrp, propname, fmt)\ +show_func(rtype, rgrp, propname, fmt)\ +\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + const char *buf, size_t count)\ +{\ + int retval;\ + unsigned long setting;\ + unsigned long o_setting;\ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj);\ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54;\ + \ + retval = kstrtoul(buf, 10, &setting);\ + if (retval)\ + return retval;\ +\ + mutex_lock(&f54->rtype##_mutex);\ + retval = rmi4_data->i2c_read(rmi4_data,\ + f54->rtype.rgrp->address,\ + f54->rtype.rgrp->data,\ + sizeof(f54->rtype.rgrp->data));\ + if (retval < 0) {\ + mutex_unlock(&f54->rtype##_mutex);\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Failed to read " #rtype\ + " " #rgrp "\n",\ + __func__);\ + return retval;\ + } \ +\ + if (f54->rtype.rgrp->propname == setting) {\ + mutex_unlock(&f54->rtype##_mutex);\ + return count;\ + } \ +\ + o_setting = f54->rtype.rgrp->propname;\ + f54->rtype.rgrp->propname = setting;\ +\ + retval = rmi4_data->i2c_write(rmi4_data,\ + f54->rtype.rgrp->address,\ + f54->rtype.rgrp->data,\ + sizeof(f54->rtype.rgrp->data));\ + if (retval < 0) {\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Failed to write " #rtype\ + " " #rgrp "\n",\ + __func__);\ + f54->rtype.rgrp->propname = o_setting;\ + mutex_unlock(&f54->rtype##_mutex);\ + return retval;\ + } \ +\ + mutex_unlock(&f54->rtype##_mutex);\ + return count;\ +} \ + +#define show_store_func_unsigned(rtype, rgrp, propname)\ +show_store_func(rtype, rgrp, propname, "%u\n") + +#define show_replicated_func(rtype, rgrp, propname, fmt)\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_show)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + char *buf)\ +{\ + int retval;\ + int size = 0;\ + unsigned char ii;\ + unsigned char length;\ + unsigned char *temp;\ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj);\ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54;\ +\ + mutex_lock(&f54->rtype##_mutex);\ +\ + length = f54->rtype.rgrp->length;\ +\ + retval = rmi4_data->i2c_read(rmi4_data,\ + f54->rtype.rgrp->address,\ + (unsigned char *)f54->rtype.rgrp->data,\ + length);\ + mutex_unlock(&f54->rtype##_mutex);\ + if (retval < 0) {\ + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev,\ + "%s: Failed to read " #rtype\ + " " #rgrp "\n",\ + __func__);\ + } \ +\ + temp = buf;\ +\ + for (ii = 0; ii < length; ii++) {\ + retval = snprintf(temp, PAGE_SIZE - size, fmt " ",\ + f54->rtype.rgrp->data[ii].propname);\ + if (retval < 0) {\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Faild to write output\n",\ + __func__);\ + return retval;\ + } \ + size += retval;\ + temp += retval;\ + } \ +\ + retval = snprintf(temp, PAGE_SIZE - size, "\n");\ + if (retval < 0) {\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Faild to write null terminator\n",\ + __func__);\ + return retval;\ + } \ +\ + return size + retval;\ +} \ + +#define show_replicated_func_unsigned(rtype, rgrp, propname)\ +show_replicated_func(rtype, rgrp, propname, "%u") + +#define show_store_replicated_func(rtype, rgrp, propname, fmt)\ +show_replicated_func(rtype, rgrp, propname, fmt)\ +\ +static ssize_t concat(synaptics_rmi4_f54, _##propname##_store)(\ + struct kobject *kobj,\ + struct kobj_attribute *attr,\ + const char *buf, size_t count)\ +{\ + int retval;\ + unsigned int setting;\ + unsigned char ii;\ + unsigned char length;\ + const unsigned char *temp;\ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj);\ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54;\ +\ + mutex_lock(&f54->rtype##_mutex);\ +\ + length = f54->rtype.rgrp->length;\ +\ + retval = rmi4_data->i2c_read(rmi4_data,\ + f54->rtype.rgrp->address,\ + (unsigned char *)f54->rtype.rgrp->data,\ + length);\ + if (retval < 0) {\ + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev,\ + "%s: Failed to read " #rtype\ + " " #rgrp "\n",\ + __func__);\ + } \ +\ + temp = buf;\ +\ + for (ii = 0; ii < length; ii++) {\ + if (sscanf(temp, fmt, &setting) == 1) {\ + f54->rtype.rgrp->data[ii].propname = setting;\ + } else {\ + retval = rmi4_data->i2c_read(rmi4_data,\ + f54->rtype.rgrp->address,\ + (unsigned char *)f54->rtype.rgrp->data,\ + length);\ + mutex_unlock(&f54->rtype##_mutex);\ + return -EINVAL;\ + } \ +\ + while (*temp != 0) {\ + temp++;\ + if (isspace(*(temp - 1)) && !isspace(*temp))\ + break;\ + } \ + } \ +\ + retval = rmi4_data->i2c_write(rmi4_data,\ + f54->rtype.rgrp->address,\ + (unsigned char *)f54->rtype.rgrp->data,\ + length);\ + mutex_unlock(&f54->rtype##_mutex);\ + if (retval < 0) {\ + tsp_debug_err(true, &rmi4_data->i2c_client->dev,\ + "%s: Failed to write " #rtype\ + " " #rgrp "\n",\ + __func__);\ + return retval;\ + } \ +\ + return count;\ +} \ + +#define show_store_replicated_func_unsigned(rtype, rgrp, propname)\ +show_store_replicated_func(rtype, rgrp, propname, "%u") + +#ifdef FACTORY_MODE +static int synaptics_rmi4_f54_get_report_type(struct synaptics_rmi4_data *rmi4_data, int type); + +static ssize_t cmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +static ssize_t cmd_status_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t cmd_result_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t cmd_list_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t debug_address_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t debug_register_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t debug_register_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count); + +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, cmd_store); +static DEVICE_ATTR(cmd_status, S_IRUGO, cmd_status_show, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, cmd_result_show, NULL); +static DEVICE_ATTR(cmd_list, S_IRUGO, cmd_list_show, NULL); +static DEVICE_ATTR(debug_address, S_IRUGO, debug_address_show, NULL); +static DEVICE_ATTR(debug_register, S_IRUGO | S_IWUSR, debug_register_show, debug_register_store); + +static struct attribute *cmd_attributes[] = { + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, + &dev_attr_cmd_list.attr, + &dev_attr_debug_address.attr, + &dev_attr_debug_register.attr, + NULL, +}; + +static struct attribute_group cmd_attr_group = { + .attrs = cmd_attributes, +}; + +/* + * Factory CMD for Synaptics IC. + * + * fw_update : 0 (Update with internal firmware). + * 1 (Update with external firmware). + * 2 (Update with Internal factory firmware). + * get_fw_ver_bin : Display firmware version in binary. + * get_fw_ver_ic : Display firmware version in IC. + * get_config_ver : Display configuration version. + * get_checksum_data : Display PR number. + * get_threshold : Display threshold of mutual. + * module_off/on_master/slave : Control ot touch IC's power. + * get_chip_vendor : Display vendor name. + * get_chip_name : Display chip name. + * get_x/y_num : Return RX/TX line of IC. + * get_rawcap : Return the rawcap(mutual) about selected. + * run_rawcap_read : Get the rawcap(mutual value about entire screen. + * get_delta : Return the delta(mutual jitter) about selected. + * run_delta_read : Get the delta value about entire screen. + * run_abscap_read : Get the abscap(self) value about entire screen. + * get_abscap_read_test : Return the abscap(self) RX/TX MIN & MAX value about entire screen. + * run_absdelta_read : Get the absdelta(self jitter) value about entire screen. + * run_trx_short_test : Test for open/short state each node. + * (each node return the valu -> 0: ok 1: not ok). + * dead_zone_enable : Set dead zone mode on(1)/off(0). + * hover_enable : To control the hover functionality dinamically. + * ( 0: disalbe, 1: enable) + * hover_no_sleep_enable : To keep the no sleep state before enter the hover test. + * This command was requested by Display team /HW. + * hover_set_edge_rx : To change grip edge exclustion RX value during hover factory test. + * glove_mode : Set glove mode on/off + * clear_cover_mode : Set the touch sensitivity mode. we are supporting various mode + in sensitivity such as (glove, flip cover, clear cover mode) and they are controled + by this sysfs. + * get_glove_sensitivity : Display glove's sensitivity. + * fast_glove_mode : Set the fast glove mode such as incomming screen. + * secure_mode : Set the secure mode. + * boost_level : Control touch booster level. + * handgrip_enable : Enable reporting the grip infomation based on hover shape. + * set_tsp_test_result : Write the result of tsp test in config area. + * get_tsp_test_result : Read the result of tsp test in config area. + */ + +static void fw_update(void *dev_data); +static void get_fw_ver_bin(void *dev_data); +static void get_fw_ver_ic(void *dev_data); +static void get_config_ver(void *dev_data); +static void get_checksum_data(void *dev_data); +static void get_threshold(void *dev_data); +static void module_off_master(void *dev_data); +static void module_on_master(void *dev_data); +static void get_chip_vendor(void *dev_data); +static void get_chip_name(void *dev_data); +static void get_x_num(void *dev_data); +static void get_y_num(void *dev_data); +static void get_rawcap(void *dev_data); +static void run_rawcap_read(void *dev_data); +static void get_delta(void *dev_data); +static void run_delta_read(void *dev_data); +static void run_abscap_read(void *dev_data); +static void get_abscap_read_test(void *dev_data); +static void run_absdelta_read(void *dev_data); +static void run_trx_short_test(void *dev_data); +static void dead_zone_enable(void *dev_data); +#ifdef PROXIMITY_MODE +static void hover_enable(void *dev_data); +static void hover_no_sleep_enable(void *dev_data); +static void hover_set_edge_rx(void *dev_data); +#endif +static void set_jitter_level(void *dev_data); +#ifdef GLOVE_MODE +static void glove_mode(void *dev_data); +static void clear_cover_mode(void *dev_data); +static void fast_glove_mode(void *dev_data); +#endif +#ifdef TSP_BOOSTER +static void boost_level(void *dev_data); +#endif +#ifdef SIDE_TOUCH +static void sidekey_enable(void *dev_data); +static void set_sidekey_only_enable(void *dev_data); +static void get_sidekey_threshold(void *dev_data); +static void run_sidekey_delta_read(void *dev_data); +static void run_sidekey_abscap_read(void *dev_data); +static void set_deepsleep_mode(void *dev_data); +static void lozemode_enable(void *dev_data); +#endif +static void set_tsp_test_result(void *dev_data); +static void get_tsp_test_result(void *dev_data); +#ifdef USE_ACTIVE_REPORT_RATE +static void report_rate(void *dev_data); +#endif +#ifdef USE_STYLUS +static void stylus_enable(void *dev_data); +#endif + +static void not_support_cmd(void *dev_data); + +static struct ft_cmd ft_cmds[] = { + {FT_CMD("fw_update", fw_update),}, + {FT_CMD("get_fw_ver_bin", get_fw_ver_bin),}, + {FT_CMD("get_fw_ver_ic", get_fw_ver_ic),}, + {FT_CMD("get_config_ver", get_config_ver),}, + {FT_CMD("get_checksum_data", get_checksum_data),}, + {FT_CMD("get_threshold", get_threshold),}, + {FT_CMD("module_off_master", module_off_master),}, + {FT_CMD("module_on_master", module_on_master),}, + {FT_CMD("module_off_slave", not_support_cmd),}, + {FT_CMD("module_on_slave", not_support_cmd),}, + {FT_CMD("get_chip_vendor", get_chip_vendor),}, + {FT_CMD("get_chip_name", get_chip_name),}, + {FT_CMD("get_x_num", get_x_num),}, + {FT_CMD("get_y_num", get_y_num),}, + {FT_CMD("get_rawcap", get_rawcap),}, + {FT_CMD("run_rawcap_read", run_rawcap_read),}, + {FT_CMD("get_delta", get_delta),}, + {FT_CMD("run_delta_read", run_delta_read),}, + {FT_CMD("run_abscap_read", run_abscap_read),}, + {FT_CMD("get_abscap_read_test", get_abscap_read_test),}, + {FT_CMD("run_absdelta_read", run_absdelta_read),}, + {FT_CMD("run_trx_short_test", run_trx_short_test),}, + {FT_CMD("dead_zone_enable", dead_zone_enable),}, +#ifdef PROXIMITY_MODE + {FT_CMD("hover_enable", hover_enable),}, + {FT_CMD("hover_no_sleep_enable", hover_no_sleep_enable),}, + {FT_CMD("hover_set_edge_rx", hover_set_edge_rx),}, +#endif + {FT_CMD("set_jitter_level", set_jitter_level),}, + {FT_CMD("handgrip_enable", not_support_cmd),}, +#ifdef GLOVE_MODE + {FT_CMD("glove_mode", glove_mode),}, + {FT_CMD("clear_cover_mode", clear_cover_mode),}, + {FT_CMD("fast_glove_mode", fast_glove_mode),}, + {FT_CMD("get_glove_sensitivity", not_support_cmd),}, +#endif +#ifdef TSP_BOOSTER + {FT_CMD("boost_level", boost_level),}, +#endif +#ifdef SIDE_TOUCH + {FT_CMD("sidekey_enable", sidekey_enable),}, + {FT_CMD("set_sidekey_only_enable", set_sidekey_only_enable),}, + {FT_CMD("get_sidekey_threshold", get_sidekey_threshold),}, + {FT_CMD("run_sidekey_delta_read", run_sidekey_delta_read),}, + {FT_CMD("run_sidekey_abscap_read", run_sidekey_abscap_read),}, + {FT_CMD("set_deepsleep_mode", set_deepsleep_mode),}, + {FT_CMD("lozemode_enable", lozemode_enable),}, +#endif + {FT_CMD("set_tsp_test_result", set_tsp_test_result),}, + {FT_CMD("get_tsp_test_result", get_tsp_test_result),}, +#ifdef USE_ACTIVE_REPORT_RATE + {FT_CMD("report_rate", report_rate),}, +#endif +#ifdef USE_STYLUS + {FT_CMD("stylus_enable", stylus_enable),}, +#endif + {FT_CMD("not_support_cmd", not_support_cmd),}, +}; +#endif + +show_prototype(status) +show_prototype(report_size) +show_store_prototype(no_auto_cal) +show_store_prototype(report_type) +show_store_prototype(fifoindex) +store_prototype(do_preparation) +store_prototype(get_report) +store_prototype(force_cal) +show_prototype(num_of_mapped_rx) +show_prototype(num_of_mapped_tx) +show_prototype(num_of_rx_electrodes) +show_prototype(num_of_tx_electrodes) +show_prototype(has_image16) +show_prototype(has_image8) +show_prototype(has_baseline) +show_prototype(clock_rate) +show_prototype(touch_controller_family) +show_prototype(has_pixel_touch_threshold_adjustment) +show_prototype(has_sensor_assignment) +show_prototype(has_interference_metric) +show_prototype(has_sense_frequency_control) +show_prototype(has_firmware_noise_mitigation) +show_prototype(has_two_byte_report_rate) +show_prototype(has_one_byte_report_rate) +show_prototype(has_relaxation_control) +show_prototype(curve_compensation_mode) +show_prototype(has_iir_filter) +show_prototype(has_cmn_removal) +show_prototype(has_cmn_maximum) +show_prototype(has_touch_hysteresis) +show_prototype(has_edge_compensation) +show_prototype(has_per_frequency_noise_control) +show_prototype(has_signal_clarity) +show_prototype(number_of_sensing_frequencies) + +show_store_prototype(no_relax) +show_store_prototype(no_scan) +show_store_prototype(bursts_per_cluster) +show_store_prototype(saturation_cap) +show_store_prototype(pixel_touch_threshold) +show_store_prototype(rx_feedback_cap) +show_store_prototype(low_ref_cap) +show_store_prototype(low_ref_feedback_cap) +show_store_prototype(low_ref_polarity) +show_store_prototype(high_ref_cap) +show_store_prototype(high_ref_feedback_cap) +show_store_prototype(high_ref_polarity) +show_store_prototype(cbc_cap) +show_store_prototype(cbc_polarity) +show_store_prototype(cbc_tx_carrier_selection) +show_store_prototype(integration_duration) +show_store_prototype(reset_duration) +show_store_prototype(noise_sensing_bursts_per_image) +show_store_prototype(slow_relaxation_rate) +show_store_prototype(fast_relaxation_rate) +show_store_prototype(rxs_on_xaxis) +show_store_prototype(curve_comp_on_txs) +show_prototype(sensor_rx_assignment) +show_prototype(sensor_tx_assignment) +show_prototype(burst_count) +show_prototype(disable) +show_prototype(filter_bandwidth) +show_prototype(stretch_duration) +show_store_prototype(disable_noise_mitigation) +show_store_prototype(freq_shift_noise_threshold) +show_store_prototype(medium_noise_threshold) +show_store_prototype(high_noise_threshold) +show_store_prototype(noise_density) +show_store_prototype(frame_count) +show_store_prototype(iir_filter_coef) +show_store_prototype(quiet_threshold) +show_store_prototype(cmn_filter_disable) +show_store_prototype(cmn_filter_max) +show_store_prototype(touch_hysteresis) +show_store_prototype(rx_low_edge_comp) +show_store_prototype(rx_high_edge_comp) +show_store_prototype(tx_low_edge_comp) +show_store_prototype(tx_high_edge_comp) +show_store_prototype(axis1_comp) +show_store_prototype(axis2_comp) +show_prototype(noise_control_1) +show_prototype(noise_control_2) +show_prototype(noise_control_3) +show_store_prototype(no_signal_clarity) +show_store_prototype(cbc_cap_0d) +show_store_prototype(cbc_polarity_0d) +show_store_prototype(cbc_tx_carrier_selection_0d) + +static struct attribute *attrs[] = { + attrify(status), + attrify(report_size), + attrify(no_auto_cal), + attrify(report_type), + attrify(fifoindex), + attrify(do_preparation), + attrify(get_report), + attrify(force_cal), + attrify(num_of_mapped_rx), + attrify(num_of_mapped_tx), + attrify(num_of_rx_electrodes), + attrify(num_of_tx_electrodes), + attrify(has_image16), + attrify(has_image8), + attrify(has_baseline), + attrify(clock_rate), + attrify(touch_controller_family), + attrify(has_pixel_touch_threshold_adjustment), + attrify(has_sensor_assignment), + attrify(has_interference_metric), + attrify(has_sense_frequency_control), + attrify(has_firmware_noise_mitigation), + attrify(has_two_byte_report_rate), + attrify(has_one_byte_report_rate), + attrify(has_relaxation_control), + attrify(curve_compensation_mode), + attrify(has_iir_filter), + attrify(has_cmn_removal), + attrify(has_cmn_maximum), + attrify(has_touch_hysteresis), + attrify(has_edge_compensation), + attrify(has_per_frequency_noise_control), + attrify(has_signal_clarity), + attrify(number_of_sensing_frequencies), + NULL, +}; + +static struct attribute_group attr_group = GROUP(attrs); + +static struct attribute *attrs_reg_0[] = { + attrify(no_relax), + attrify(no_scan), + NULL, +}; + +static struct attribute *attrs_reg_1[] = { + attrify(bursts_per_cluster), + NULL, +}; + +static struct attribute *attrs_reg_2[] = { + attrify(saturation_cap), + NULL, +}; + +static struct attribute *attrs_reg_3[] = { + attrify(pixel_touch_threshold), + NULL, +}; + +static struct attribute *attrs_reg_4__6[] = { + attrify(rx_feedback_cap), + attrify(low_ref_cap), + attrify(low_ref_feedback_cap), + attrify(low_ref_polarity), + attrify(high_ref_cap), + attrify(high_ref_feedback_cap), + attrify(high_ref_polarity), + NULL, +}; + +static struct attribute *attrs_reg_7[] = { + attrify(cbc_cap), + attrify(cbc_polarity), + attrify(cbc_tx_carrier_selection), + NULL, +}; + +static struct attribute *attrs_reg_8__9[] = { + attrify(integration_duration), + attrify(reset_duration), + NULL, +}; + +static struct attribute *attrs_reg_10[] = { + attrify(noise_sensing_bursts_per_image), + NULL, +}; + +static struct attribute *attrs_reg_11[] = { + NULL, +}; + +static struct attribute *attrs_reg_12__13[] = { + attrify(slow_relaxation_rate), + attrify(fast_relaxation_rate), + NULL, +}; + +static struct attribute *attrs_reg_14__16[] = { + attrify(rxs_on_xaxis), + attrify(curve_comp_on_txs), + attrify(sensor_rx_assignment), + attrify(sensor_tx_assignment), + NULL, +}; + +static struct attribute *attrs_reg_17__19[] = { + attrify(burst_count), + attrify(disable), + attrify(filter_bandwidth), + attrify(stretch_duration), + NULL, +}; + +static struct attribute *attrs_reg_20[] = { + attrify(disable_noise_mitigation), + NULL, +}; + +static struct attribute *attrs_reg_21[] = { + attrify(freq_shift_noise_threshold), + NULL, +}; + +static struct attribute *attrs_reg_22__26[] = { + attrify(medium_noise_threshold), + attrify(high_noise_threshold), + attrify(noise_density), + attrify(frame_count), + NULL, +}; + +static struct attribute *attrs_reg_27[] = { + attrify(iir_filter_coef), + NULL, +}; + +static struct attribute *attrs_reg_28[] = { + attrify(quiet_threshold), + NULL, +}; + +static struct attribute *attrs_reg_29[] = { + attrify(cmn_filter_disable), + NULL, +}; + +static struct attribute *attrs_reg_30[] = { + attrify(cmn_filter_max), + NULL, +}; + +static struct attribute *attrs_reg_31[] = { + attrify(touch_hysteresis), + NULL, +}; + +static struct attribute *attrs_reg_32__35[] = { + attrify(rx_low_edge_comp), + attrify(rx_high_edge_comp), + attrify(tx_low_edge_comp), + attrify(tx_high_edge_comp), + NULL, +}; + +static struct attribute *attrs_reg_36[] = { + attrify(axis1_comp), + NULL, +}; + +static struct attribute *attrs_reg_37[] = { + attrify(axis2_comp), + NULL, +}; + +static struct attribute *attrs_reg_38__40[] = { + attrify(noise_control_1), + attrify(noise_control_2), + attrify(noise_control_3), + NULL, +}; + +static struct attribute *attrs_reg_41[] = { + attrify(no_signal_clarity), + NULL, +}; + +static struct attribute *attrs_reg_57[] = { + attrify(cbc_cap_0d), + attrify(cbc_polarity_0d), + attrify(cbc_tx_carrier_selection_0d), + NULL, +}; + +static struct attribute_group attrs_ctrl_regs[] = { + GROUP(attrs_reg_0), + GROUP(attrs_reg_1), + GROUP(attrs_reg_2), + GROUP(attrs_reg_3), + GROUP(attrs_reg_4__6), + GROUP(attrs_reg_7), + GROUP(attrs_reg_8__9), + GROUP(attrs_reg_10), + GROUP(attrs_reg_11), + GROUP(attrs_reg_12__13), + GROUP(attrs_reg_14__16), + GROUP(attrs_reg_17__19), + GROUP(attrs_reg_20), + GROUP(attrs_reg_21), + GROUP(attrs_reg_22__26), + GROUP(attrs_reg_27), + GROUP(attrs_reg_28), + GROUP(attrs_reg_29), + GROUP(attrs_reg_30), + GROUP(attrs_reg_31), + GROUP(attrs_reg_32__35), + GROUP(attrs_reg_36), + GROUP(attrs_reg_37), + GROUP(attrs_reg_38__40), + GROUP(attrs_reg_41), + GROUP(attrs_reg_57), +}; + +static bool attrs_ctrl_regs_exist[ARRAY_SIZE(attrs_ctrl_regs)]; + +static ssize_t synaptics_rmi4_f54_data_read(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static struct bin_attribute dev_report_data = { + .attr = { + .name = "report_data", + .mode = S_IRUGO, + }, + .size = 0, + .read = synaptics_rmi4_f54_data_read, +}; + +static bool is_report_type_valid(struct synaptics_rmi4_data *rmi4_data, enum f54_report_types report_type) +{ + switch (report_type) { + case F54_8BIT_IMAGE: + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_HIGH_RESISTANCE: + case F54_TX_TO_TX_SHORT: + case F54_RX_TO_RX1: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP_MIN_MAX: + case F54_RX_OPENS1: + case F54_TX_OPEN: + case F54_TX_TO_GROUND: + case F54_RX_TO_RX2: + case F54_RX_OPENS2: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + case F54_SENSOR_SPEED: + case F54_ADC_RANGE: + case F54_TREX_OPENS: + case F54_TREX_TO_GND: + case F54_TREX_SHORTS: + case F54_ABS_CAP: + case F54_ABS_DELTA: + case F54_ABS_ADC: + return true; + break; + default: + rmi4_data->f54->report_type = INVALID_REPORT_TYPE; + rmi4_data->f54->report_size = 0; + return false; + + } +} + +static void set_report_size(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + int retval; + unsigned char rx = f54->rx_assigned; + unsigned char tx = f54->tx_assigned; + + switch (f54->report_type) { + case F54_8BIT_IMAGE: + f54->report_size = rx * tx; + break; + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + case F54_SENSOR_SPEED: + f54->report_size = 2 * rx * tx; + break; + case F54_HIGH_RESISTANCE: + f54->report_size = HIGH_RESISTANCE_DATA_SIZE; + break; + case F54_TX_TO_TX_SHORT: + case F54_TX_OPEN: + case F54_TX_TO_GROUND: + f54->report_size = (tx + 7) / 8; + break; + case F54_RX_TO_RX1: + case F54_RX_OPENS1: + if (rx < tx) + f54->report_size = 2 * rx * rx; + else + f54->report_size = 2 * rx * tx; + break; + case F54_FULL_RAW_CAP_MIN_MAX: + f54->report_size = FULL_RAW_CAP_MIN_MAX_DATA_SIZE; + break; + case F54_RX_TO_RX2: + case F54_RX_OPENS2: + if (rx <= tx) + f54->report_size = 0; + else + f54->report_size = 2 * rx * (rx - tx); + break; + case F54_ADC_RANGE: + if (f54->query.has_signal_clarity) { + mutex_lock(&f54->control_mutex); + retval = rmi4_data->i2c_read(rmi4_data, + f54->control.reg_41->address, + f54->control.reg_41->data, + sizeof(f54->control.reg_41->data)); + mutex_unlock(&f54->control_mutex); + if (retval < 0) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Failed to read control reg_41\n", + __func__); + f54->report_size = 0; + break; + } + if (!f54->control.reg_41->no_signal_clarity) { + if (tx % 4) + tx += 4 - (tx % 4); + } + } + f54->report_size = 2 * rx * tx; + break; + case F54_TREX_OPENS: + case F54_TREX_TO_GND: + case F54_TREX_SHORTS: + f54->report_size = TREX_DATA_SIZE; + break; + case F54_ABS_CAP: + case F54_ABS_DELTA: +#ifdef SIDE_TOUCH + f54->report_size = 4 * (rx + tx + NUM_OF_ACTIVE_SIDE_BUTTONS); +#else + f54->report_size = 4 * (rx + tx); +#endif + break; + case F54_ABS_ADC: + f54->report_size = 2 * (rx + tx); + break; + default: + f54->report_size = 0; + } + + return; +} + +static int set_interrupt(struct synaptics_rmi4_data *rmi4_data, bool set) +{ + int retval; + unsigned char ii; + unsigned char zero = 0x00; + unsigned char *intr_mask; + unsigned short f01_ctrl_reg; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + intr_mask = rmi4_data->intr_mask; + f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num; + + if (!set) { + retval = rmi4_data->i2c_write(rmi4_data, + f01_ctrl_reg, + &zero, + sizeof(zero)); + if (retval < 0) + return retval; + } + + for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) { + if (intr_mask[ii] != 0x00) { + f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + ii; + if (set) { + retval = rmi4_data->i2c_write(rmi4_data, + f01_ctrl_reg, + &zero, + sizeof(zero)); + if (retval < 0) + return retval; + } else { + retval = rmi4_data->i2c_write(rmi4_data, + f01_ctrl_reg, + &(intr_mask[ii]), + sizeof(intr_mask[ii])); + if (retval < 0) + return retval; + } + } + } + + f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num; + + if (set) { + retval = rmi4_data->i2c_write(rmi4_data, + f01_ctrl_reg, + &f54->intr_mask, + 1); + if (retval < 0) + return retval; + } + + return 0; +} + +static int do_preparation(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char value; + unsigned char command; + unsigned char timeout_count; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + mutex_lock(&f54->control_mutex); + + if (f54->query.touch_controller_family == 1) { + value = 0; + retval = rmi4_data->i2c_write(rmi4_data, + f54->control.reg_7->address, + &value, + sizeof(f54->control.reg_7->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to disable CBC\n", + __func__); + mutex_unlock(&f54->control_mutex); + return retval; + } + } else if (f54->query.has_ctrl88 == 1) { + retval = rmi4_data->i2c_read(rmi4_data, + f54->control.reg_88->address, + f54->control.reg_88->data, + sizeof(f54->control.reg_88->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to disable CBC (read ctrl88)\n", + __func__); + mutex_unlock(&f54->control_mutex); + return retval; + } + f54->control.reg_88->cbc_polarity = 0; + f54->control.reg_88->cbc_tx_carrier_selection = 0; + retval = rmi4_data->i2c_write(rmi4_data, + f54->control.reg_88->address, + f54->control.reg_88->data, + sizeof(f54->control.reg_88->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to disable CBC (write ctrl88)\n", + __func__); + mutex_unlock(&f54->control_mutex); + return retval; + } + } + /* check this code to using S5000 and S5050 */ + if (f54->query.has_0d_acquisition_control) { + value = 0; + retval = rmi4_data->i2c_write(rmi4_data, + f54->control.reg_57->address, + &value, + sizeof(f54->control.reg_57->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to disable 0D CBC\n", + __func__); + mutex_unlock(&f54->control_mutex); + return retval; + } + } + + if (f54->query.has_signal_clarity) { + value = 1; + retval = rmi4_data->i2c_write(rmi4_data, + f54->control.reg_41->address, + &value, + sizeof(f54->control.reg_41->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to disable signal clarity\n", + __func__); + mutex_unlock(&f54->control_mutex); + return retval; + } + } + + mutex_unlock(&f54->control_mutex); + + command = (unsigned char)COMMAND_FORCE_UPDATE; + + retval = rmi4_data->i2c_write(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write force update command\n", + __func__); + return retval; + } + + timeout_count = 0; + do { + retval = rmi4_data->i2c_read(rmi4_data, + f54->command_base_addr, + &value, + sizeof(value)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read command register\n", + __func__); + return retval; + } + + if (value == 0x00) + break; + + msleep(100); + timeout_count++; + } while (timeout_count < FORCE_TIMEOUT_100MS); + + if (timeout_count == FORCE_TIMEOUT_100MS) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Timed out waiting for force update\n", + __func__); + return -ETIMEDOUT; + } + + command = (unsigned char)COMMAND_FORCE_CAL; + + retval = rmi4_data->i2c_write(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write force cal command\n", + __func__); + return retval; + } + + timeout_count = 0; + do { + retval = rmi4_data->i2c_read(rmi4_data, + f54->command_base_addr, + &value, + sizeof(value)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read command register\n", + __func__); + return retval; + } + + if (value == 0x00) + break; + + msleep(100); + timeout_count++; + } while (timeout_count < FORCE_TIMEOUT_100MS); + + if (timeout_count == FORCE_TIMEOUT_100MS) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Timed out waiting for force cal\n", + __func__); + return -ETIMEDOUT; + } + + return 0; +} + +#ifdef WATCHDOG_HRTIMER +static void timeout_set_status(struct work_struct *work) +{ + int retval; + unsigned char command; + struct synaptics_rmi4_f54_handle *f54 = + container_of(work, struct synaptics_rmi4_f54_handle, timeout_work); + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)f54->rmi4_data; + + mutex_lock(&f54->status_mutex); + if (f54->status == STATUS_BUSY) { + retval = rmi4_data->i2c_read(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read command register\n", + __func__); + f54->status = STATUS_ERROR; + } else if (command & COMMAND_GET_REPORT) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Report type not supported by FW\n", + __func__); + f54->status = STATUS_ERROR; + } else { + queue_delayed_work(f54->status_workqueue, + &f54->status_work, + 0); + mutex_unlock(&f54->status_mutex); + return; + } + f54->report_type = INVALID_REPORT_TYPE; + f54->report_size = 0; + } + mutex_unlock(&f54->status_mutex); + + /* read fail : need ic reset */ + if (f54->status == STATUS_ERROR) { + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + f54->status = STATUS_IDLE; + return; + } + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: reset device\n", + __func__); + + retval = rmi4_data->reset_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + + mutex_lock(&f54->status_mutex); + f54->status = STATUS_IDLE; + mutex_unlock(&f54->status_mutex); + } + + return; +} + +static enum hrtimer_restart get_report_timeout(struct hrtimer *timer) +{ + struct synaptics_rmi4_f54_handle *f54 = + container_of(timer, struct synaptics_rmi4_f54_handle, watchdog); + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)f54->rmi4_data; + + schedule_work(&(rmi4_data->f54->timeout_work)); + + return HRTIMER_NORESTART; +} +#endif + +#ifdef RAW_HEX +static void print_raw_hex_report(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + unsigned int ii; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Report data (raw hex)\n", __func__); + + switch (f54->report_type) { + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_HIGH_RESISTANCE: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP_MIN_MAX: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + case F54_SENSOR_SPEED: + case F54_ADC_RANGE: + case F54_ABS_ADC: + for (ii = 0; ii < f54->report_size; ii += 2) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%03d: 0x%02x%02x\n", + ii / 2, + f54->report_data[ii + 1], + f54->report_data[ii]); + } + break; + case F54_ABS_CAP: + case F54_ABS_DELTA: + for (ii = 0; ii < f54->report_size; ii += 4) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%03d: 0x%02x%02x%02x%02x\n", + ii / 4, + f54->report_data[ii + 3], + f54->report_data[ii + 2], + f54->report_data[ii + 1], + f54->report_data[ii]); + } + break; + default: + for (ii = 0; ii < f54->report_size; ii++) + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%03d: 0x%02x\n", ii, f54->report_data[ii]); + break; + } + + return; +} +#endif + +#ifdef HUMAN_READABLE +static void print_image_report(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned int ii; + unsigned int jj; + short *report_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + switch (f54->report_type) { + case F54_16BIT_IMAGE: + case F54_RAW_16BIT_IMAGE: + case F54_TRUE_BASELINE: + case F54_FULL_RAW_CAP: + case F54_FULL_RAW_CAP_RX_COUPLING_COMP: + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Report data (image)\n", __func__); + + report_data = (short *)f54->report_data; + + for (ii = 0; ii < f54->tx_assigned; ii++) { + for (jj = 0; jj < f54->rx_assigned; jj++) { + if (*report_data < -64) + pr_cont("."); + else if (*report_data < 0) + pr_cont("-"); + else if (*report_data > 64) + pr_cont("*"); + else if (*report_data > 0) + pr_cont("+"); + else + pr_cont("0"); + + report_data++; + } + tsp_debug_info(true, &rmi4_data->i2c_client->dev, ""); + } + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: End of report\n", __func__); + break; + default: + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Image not supported for report type %d\n", + __func__, f54->report_type); + } + + return; +} +#endif + +static void free_control_mem(struct synaptics_rmi4_f54_handle *f54) +{ + struct f54_control control = f54->control; + + kfree(control.reg_0); + kfree(control.reg_1); + kfree(control.reg_2); + kfree(control.reg_3); + kfree(control.reg_4__6); + kfree(control.reg_7); + kfree(control.reg_8__9); + kfree(control.reg_10); + kfree(control.reg_11); + kfree(control.reg_12__13); + kfree(control.reg_14); + if (control.reg_15) + kfree(control.reg_15->data); + kfree(control.reg_15); + if (control.reg_16) + kfree(control.reg_16->data); + kfree(control.reg_16); + if (control.reg_17) + kfree(control.reg_17->data); + kfree(control.reg_17); + if (control.reg_18) + kfree(control.reg_18->data); + kfree(control.reg_18); + if (control.reg_19) + kfree(control.reg_19->data); + kfree(control.reg_19); + kfree(control.reg_20); + kfree(control.reg_21); + kfree(control.reg_22__26); + kfree(control.reg_27); + kfree(control.reg_28); + kfree(control.reg_29); + kfree(control.reg_30); + kfree(control.reg_31); + kfree(control.reg_32__35); + if (control.reg_36) + kfree(control.reg_36->data); + kfree(control.reg_36); + if (control.reg_37) + kfree(control.reg_37->data); + kfree(control.reg_37); + if (control.reg_38) + kfree(control.reg_38->data); + kfree(control.reg_38); + if (control.reg_39) + kfree(control.reg_39->data); + kfree(control.reg_39); + if (control.reg_40) + kfree(control.reg_40->data); + kfree(control.reg_40); + kfree(control.reg_41); + kfree(control.reg_57); + kfree(control.reg_88); + kfree(control.reg_94); + + return; +} + +static void remove_sysfs(struct synaptics_rmi4_f54_handle *f54) +{ + int reg_num; + + sysfs_remove_bin_file(f54->attr_dir, &dev_report_data); + + sysfs_remove_group(f54->attr_dir, &attr_group); + + for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); reg_num++) + sysfs_remove_group(f54->attr_dir, &attrs_ctrl_regs[reg_num]); + + kobject_put(f54->attr_dir); + + return; +} + +#ifdef FACTORY_MODE +static void set_default_result(struct factory_data *data) +{ + char delim = ':'; + + memset(data->cmd_buff, 0x00, sizeof(data->cmd_buff)); + memset(data->cmd_result, 0x00, sizeof(data->cmd_result)); + memcpy(data->cmd_result, data->cmd, strlen(data->cmd)); + strncat(data->cmd_result, &delim, 1); + + return; +} + +static void set_cmd_result(struct factory_data *data, char *buf, int length) +{ + strncat(data->cmd_result, buf, length); + + return; +} + +static ssize_t cmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char param_cnt = 0; + char *start; + char *end; + char *pos; + char delim = ','; + char buffer[CMD_STR_LEN]; + bool cmd_found = false; + int *param; + int length; + struct ft_cmd *ft_cmd_ptr; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct factory_data *data = rmi4_data->f54->factory_data; + + if (data->cmd_is_running == true) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Still servicing previous command. Skip cmd :%s\n", + __func__, buf); + return count; + } + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = true; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_RUNNING; + + length = (int)count; + if (*(buf + length - 1) == '\n') + length--; + + memset(data->cmd, 0x00, sizeof(data->cmd)); + memcpy(data->cmd, buf, length); + memset(data->cmd_param, 0, sizeof(data->cmd_param)); + + memset(buffer, 0x00, sizeof(buffer)); + pos = strchr(buf, (int)delim); + if (pos) + memcpy(buffer, buf, pos - buf); + else + memcpy(buffer, buf, length); + + /* find command */ + list_for_each_entry(ft_cmd_ptr, &data->cmd_list_head, list) { + if (!ft_cmd_ptr) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: ft_cmd_ptr is NULL\n", + __func__); + return count; + } + if (!ft_cmd_ptr->cmd_name) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: ft_cmd_ptr->cmd_name is NULL\n", + __func__); + return count; + } + + if (!strcmp(buffer, ft_cmd_ptr->cmd_name)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(ft_cmd_ptr, + &data->cmd_list_head, list) { + if (!strcmp("not_support_cmd", ft_cmd_ptr->cmd_name)) + break; + } + } + + /* parsing parameters */ + if (cmd_found && pos) { + pos++; + start = pos; + do { + if ((*pos == delim) || (pos - buf == length)) { + end = pos; + memset(buffer, 0x00, sizeof(buffer)); + memcpy(buffer, start, end - start); + *(buffer + strlen(buffer)) = '\0'; + param = data->cmd_param + param_cnt; + if (kstrtoint(buffer, 10, param) < 0) + break; + param_cnt++; + start = pos + 1; + } + pos++; + } while (pos - buf <= length); + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Command = %s\n", + __func__, buf); + + ft_cmd_ptr->cmd_func(rmi4_data); + + return count; +} + +static ssize_t cmd_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buffer[CMD_RESULT_STR_LEN]; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct factory_data *data = rmi4_data->f54->factory_data; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Command status = %d\n", + __func__, data->cmd_state); + + switch (data->cmd_state) { + case CMD_STATUS_WAITING: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(WAITING)); + break; + case CMD_STATUS_RUNNING: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(RUNNING)); + break; + case CMD_STATUS_OK: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(OK)); + break; + case CMD_STATUS_FAIL: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(FAIL)); + break; + case CMD_STATUS_NOT_APPLICABLE: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(NOT_APPLICABLE)); + break; + default: + snprintf(buffer, CMD_RESULT_STR_LEN, "%s", tostring(NOT_APPLICABLE)); + break; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", buffer); +} + +static ssize_t cmd_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct factory_data *data = rmi4_data->f54->factory_data; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Command result = %s\n", + __func__, data->cmd_result); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; + + return snprintf(buf, PAGE_SIZE, "%s\n", data->cmd_result); +} + +static char debug_buffer[DEBUG_RESULT_STR_LEN]; + +static ssize_t cmd_list_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ii = 0; + char buffer_name[CMD_STR_LEN] = {0,}; + + memset(debug_buffer, 0, DEBUG_RESULT_STR_LEN); + + DEBUG_PRNT_SCREEN(debug_buffer, buffer_name, CMD_STR_LEN, "++factory command list++\n"); + while (strncmp(ft_cmds[ii].cmd_name, "not_support_cmd", 16) != 0) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_name, CMD_STR_LEN, "%s\n", ft_cmds[ii].cmd_name); + ii++; + } + + return snprintf(buf, PAGE_SIZE, "%s\n", debug_buffer); +} + +static ssize_t debug_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + char buffer_temp[DEBUG_STR_LEN] = {0,}; + + memset(debug_buffer, 0, DEBUG_RESULT_STR_LEN); + + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### F12 User control Registers ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F12_2D_CTRL11(jitter)\t 0x%04x, 0x%02x\n", + rmi4_data->f12.ctrl11_addr, 0xFF); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F12_2D_CTRL15(threshold)\t 0x%04x, 0x%02x\n", + rmi4_data->f12.ctrl15_addr, 0xFF); +#ifdef GLOVE_MODE + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F12_2D_CTRL23(obj_type)\t 0x%04x, 0x%02x\n", + rmi4_data->f12.ctrl23_addr, rmi4_data->f12.obj_report_enable); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F12_2D_CTRL26(glove)\t 0x%04x, 0x%02x\n", + rmi4_data->f12.ctrl26_addr, rmi4_data->f12.feature_enable); +#endif + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F12_2D_CTRL28(report)\t 0x%04x, 0x%02x\n", + rmi4_data->f12.ctrl28_addr, rmi4_data->f12.report_enable); + + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### F51 User control Registers ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL00(proximity)\t 0x%04x, 0x%02x\n", + f51->proximity_enables_addr, f51->proximity_enables); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL01(general)\t 0x%04x, 0x%02x\n", + f51->general_control_addr, f51->general_control); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL02(general2)\t 0x%04x, 0x%02x\n", + f51->general_control_2_addr, f51->general_control_2); +#ifdef SIDE_TOUCH + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_DATA (Side button)\t 0x%04x, 0x%02x\n", + f51->side_button_data_addr, 0xFF); +#endif +#ifdef USE_DETECTION_FLAG_2 + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_DATA (Detection flag2)\t 0x%04x, 0x%02x\n", + f51->detection_flag_2_addr, 0xFF); +#endif +#ifdef EDGE_SWIPE + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_DATA (Edge swipe)\t 0x%04x, 0x%02x\n", + f51->edge_swipe_data_addr, 0xFF); +#endif + + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Manual defined offset ###\n"); +#ifdef PROXIMITY_MODE + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL24(Grip edge exclusion RX)\t 0x%04x\n", + f51->grip_edge_exclusion_rx_addr); +#endif +#ifdef SIDE_TOUCH + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL78(Side button tap threshold)\t 0x%04x\n", + f51->sidebutton_tapthreshold_addr); +#endif +#ifdef USE_STYLUS + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "#F51_CUSTOM_CTRL87(ForceFingeronEdge)\t 0x%04x\n", + f51->forcefinger_onedge_addr); +#endif + + return snprintf(buf, PAGE_SIZE, "%s\n", debug_buffer); +} + +static ssize_t debug_register_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", debug_buffer); +} + +static ssize_t debug_register_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + unsigned int mode, page, addr, offset, param; + unsigned char i; + unsigned short register_addr; + unsigned char *register_val; + + char buffer_temp[DEBUG_STR_LEN] = {0,}; + + int retval = 0; + + memset(debug_buffer, 0, DEBUG_RESULT_STR_LEN); + + if (sscanf(buf, "%x%x%x%x%x", &mode, &page, &addr, &offset, ¶m) != 5) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### keep below format !!!! ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### mode page_num address offset data ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### (EX: 1 4 15 1 10 > debug_address) ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### Write 0x10 value at 0x415[1] address ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### if packet register, offset mean [register/offset] ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### (EX: 0 4 15 0 a > debug_address) ###\n"); + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### Read 10byte from 0x415 address ###\n"); + goto out; + } + + if (rmi4_data->touch_stopped) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### ERROR : Sensor stopped\n"); + goto out; + } + + register_addr = (page << 8) | addr; + + if (mode) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Write [0x%02x]value at [0x%04x/0x%02x]address.\n", + param, register_addr, offset); + + if (offset) { + if (offset > MAX_VAL_OFFSET_AND_LENGTH) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### offset is too large. [ < %d]\n", MAX_VAL_OFFSET_AND_LENGTH); + goto out; + } + register_val = kzalloc(offset + 1, GFP_KERNEL); + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_READ, register_addr, offset + 1, register_val); + if (retval < 0) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Failed to read\n"); + goto free_mem; + } + register_val[offset] = param; + + for (i = 0; i < offset + 1; i++) + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### offset[%d] --> 0x%02x ###\n", i, register_val[i]); + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_WRITE, register_addr, offset + 1, register_val); + if (retval < 0) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Failed to write\n"); + goto free_mem; + } + } else { + register_val = kzalloc(1, GFP_KERNEL); + + *register_val = param; + + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### 0x%04x --> 0x%02x ###\n", register_addr, *register_val); + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_WRITE, register_addr, 1, register_val); + if (retval < 0) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Failed to write\n"); + goto free_mem; + } + } + } else { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Read [%u]byte from [0x%04x]address.\n", + param, register_addr); + + if (param > MAX_VAL_OFFSET_AND_LENGTH) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### length is too large. [ < %d]\n", MAX_VAL_OFFSET_AND_LENGTH); + goto out; + } + + register_val = kzalloc(param, GFP_KERNEL); + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_READ, register_addr, param, register_val); + if (retval < 0) { + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "\n### Failed to read\n"); + goto free_mem; + } + + for (i = 0; i < param; i++) + DEBUG_PRNT_SCREEN(debug_buffer, buffer_temp, DEBUG_STR_LEN, "### offset[%d] --> 0x%02x ###\n", i, register_val[i]); + } + +free_mem: + kfree(register_val); + +out: + return count; +} + +/* TODO: Below functions are added to check that firmware update is needed or not. + * During development period, we need to support test firmware and various H/W + * type such as A0/A1/B0.... So Below conditions are very compex, maybe we need to + * simplify this function.. + * + * synaptics_get_firmware_name : get firmware name according to board enviroment. + * synaptics_check_pr_number : to check that configuration block is correct or not. + * synaptics_skip_firmware_update : check condition(according to requiremnt by CS). + */ + +/* Define for board specific firmware name....*/ +#define FW_IMAGE_NAME_NONE NULL + +static void synaptics_get_firmware_name(struct synaptics_rmi4_data *rmi4_data) +{ + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + if (pdata->firmware_name) { + rmi4_data->firmware_name = pdata->firmware_name; + goto out; + } + + /* + * Get the firmware name.. for your board. + * I recommend to get the firmware name from platform data(board or dt data) + * instead of using below code. + * If firmware is FW_IMAGE_NAME_NONE, firmware update will be skipped.. + */ + rmi4_data->firmware_name = FW_IMAGE_NAME_NONE; + +out: + return; +} + +#ifdef CHECK_PR_NUMBER +static bool synaptics_check_pr_number_v7(struct synaptics_rmi4_data *rmi4_data, + const struct firmware *fw_entry) +{ + unsigned int fw_pr_number = 0; + + /* Check base fw version. base fw version is PR number. ex)PR1566790_...img */ + fw_pr_number = ((int)(fw_entry->data[PR_NUMBER_0TH_BYTE_BIN_OFFSET_V7+ 3] & 0xFF) << 24) | + ((int)(fw_entry->data[PR_NUMBER_0TH_BYTE_BIN_OFFSET_V7 + 2] & 0xFF) << 16) | + ((int)(fw_entry->data[PR_NUMBER_0TH_BYTE_BIN_OFFSET_V7 + 1] & 0xFF) << 8) | + (int)(fw_entry->data[PR_NUMBER_0TH_BYTE_BIN_OFFSET_V7] & 0xFF); + + if (fw_pr_number != rmi4_data->rmi4_mod_info.pr_number) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: pr_number mismatched[IC/BIN] : %X / %X, excute update!!\n", + __func__, rmi4_data->rmi4_mod_info.pr_number, fw_pr_number); + return false; + } + + tsp_debug_info(false, &rmi4_data->i2c_client->dev, "%s: pr_number[IC/BIN] : %X / %X\n", + __func__, rmi4_data->rmi4_mod_info.pr_number, fw_pr_number); + + return true; +} + +#endif + +static bool synaptics_skip_firmware_update_v7(struct synaptics_rmi4_data *rmi4_data, + const struct firmware *fw_entry) +{ + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: FW size. revision, version [%d, 0x%02X/0x%02X(BIN/IC), 0x%02X/0x%02X(BIN/IC)]\n", + __func__, (int)fw_entry->size, + rmi4_data->ic_revision_of_bin, rmi4_data->ic_revision_of_ic, + rmi4_data->fw_version_of_bin, rmi4_data->fw_version_of_ic); + + if (strncmp(rmi4_data->rmi4_mod_info.product_id_string, rmi4_data->product_id_string_of_bin, 5) != 0) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Skip update because FW file is mismatched.\n", + __func__); + return true; + } + + if (rmi4_data->flash_prog_mode) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Force firmware update : Flash prog bit is setted fw\n", + __func__); + goto out; + } + + if (rmi4_data->ic_revision_of_ic != 0x00 && (rmi4_data->ic_revision_of_bin != rmi4_data->ic_revision_of_ic)) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Skip update because revision is mismatched.\n", + __func__); + return true; + } + + /* Temporary code */ + if (rmi4_data->fw_version_of_ic > 0xF0) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Force firmware update : Test FW[%X] in TSP IC.\n", + __func__, rmi4_data->fw_version_of_ic); + goto out; + } + + if (rmi4_data->fw_version_of_bin < rmi4_data->fw_version_of_ic) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Do not need to update\n", + __func__); + return true; + } + + if (rmi4_data->fw_version_of_bin == rmi4_data->fw_version_of_ic) { +#ifdef CHECK_PR_NUMBER + if (!synaptics_check_pr_number_v7(rmi4_data, fw_entry)) + goto out; +#endif + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Do not need to update\n", + __func__); + return true; + } + +out: + return false; +} + +int synaptics_rmi4_fw_update_on_probe(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + const struct firmware *fw_entry = NULL; + unsigned char *fw_data = NULL; + + synaptics_get_firmware_name(rmi4_data); + + if (rmi4_data->firmware_name == NULL) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: firmware name is NULL!, Skip update firmware.\n", + __func__); + return 0; + } else { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Load firmware : %s\n", + __func__, rmi4_data->firmware_name); + } + +#ifdef SKIP_UPDATE_FW_ON_PROBE + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Intentionally skip update firmware.\n", + __func__); + goto done; +#endif + + retval = request_firmware(&fw_entry, rmi4_data->firmware_name, &rmi4_data->i2c_client->dev); + if (retval) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Firmware image %s not available\n", + __func__, rmi4_data->firmware_name); + goto done; + } + + fw_data = (unsigned char *) fw_entry->data; + fwu_parse_image_header_10_simple(rmi4_data, fw_data); + + if (synaptics_skip_firmware_update_v7(rmi4_data, fw_entry)) + goto done; + + retval = synaptics_fw_updater(rmi4_data, fw_data); + if (retval) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed update firmware\n", + __func__); +done: + if (fw_entry) + release_firmware(fw_entry); + + return retval; +} +EXPORT_SYMBOL(synaptics_rmi4_fw_update_on_probe); + +static int synaptics_load_fw_from_kernel(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + const struct firmware *fw_entry = NULL; + unsigned char *fw_data = NULL; + + synaptics_get_firmware_name(rmi4_data); + + if (rmi4_data->firmware_name == NULL) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: firmware name is NULL!, Skip update firmware.\n", + __func__); + return 0; + } else { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Load firmware : %s\n", + __func__, rmi4_data->firmware_name); + } + + retval = request_firmware(&fw_entry, rmi4_data->firmware_name, + &rmi4_data->i2c_client->dev); + + if (retval) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Firmware image %s not available\n", + __func__, rmi4_data->firmware_name); + goto done; + } + + fw_data = (unsigned char *) fw_entry->data; + fwu_parse_image_header_10_simple(rmi4_data, fw_data); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: FW size. revision, version [%d, 0x%02X/0x%02X(BIN/IC), 0x%02X/0x%02X(BIN/IC)]\n", + __func__, (int)fw_entry->size, + rmi4_data->ic_revision_of_bin, rmi4_data->ic_revision_of_ic, + rmi4_data->fw_version_of_bin, rmi4_data->fw_version_of_ic); + + retval = synaptics_fw_updater(rmi4_data, fw_data); + if (retval) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed update firmware\n", + __func__); +done: + if (fw_entry) + release_firmware(fw_entry); + + return retval; +} + +static int synaptics_load_fw_from_ums(struct synaptics_rmi4_data *rmi4_data) +{ + struct file *fp; + mm_segment_t old_fs; + int fw_size, nread; + int error = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(SYNAPTICS_DEFAULT_UMS_FW, O_RDONLY, S_IRUSR); + if (IS_ERR(fp)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed to open %s.\n", + __func__, SYNAPTICS_DEFAULT_UMS_FW); + error = -ENOENT; + goto open_err; + } + + fw_size = fp->f_path.dentry->d_inode->i_size; + + if (0 < fw_size) { + unsigned char *fw_data; + fw_data = kzalloc(fw_size, GFP_KERNEL); + nread = vfs_read(fp, (char __user *)fw_data, + fw_size, &fp->f_pos); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: start, file path %s, size %u Bytes\n", __func__, + SYNAPTICS_DEFAULT_UMS_FW, fw_size); + + if (nread != fw_size) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed to read firmware file, nread %u Bytes\n", + __func__, nread); + error = -EIO; + } else { + /* UMS case */ + error = synaptics_fw_updater(rmi4_data, fw_data); + } + + if (error < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed update firmware\n", + __func__); + + kfree(fw_data); + } + + filp_close(fp, current->files); + + open_err: + set_fs(old_fs); + return error; +} + +static int synaptics_rmi4_fw_update_on_hidden_menu(struct synaptics_rmi4_data *rmi4_data, + int update_type) +{ + int retval = 0; + + /* Factory cmd for firmware update + * argument represent what is source of firmware like below. + * + * 0, 2 : Getting firmware which is for user. + * 1 : Getting firmware from sd card. + */ + switch (update_type) { + case 2: + case 0: + retval = synaptics_load_fw_from_kernel(rmi4_data); + break; + case 1: + retval = synaptics_load_fw_from_ums(rmi4_data); + break; + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Not support command[%d]\n", + __func__, update_type); + break; + } + + return retval; +} + +static void fw_update(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + + set_default_result(data); + + retval = synaptics_rmi4_fw_update_on_hidden_menu(rmi4_data, + data->cmd_param[0]); + msleep(1000); + + if (retval < 0) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + data->cmd_state = CMD_STATUS_FAIL; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed [%d]\n", + __func__, retval); + goto out; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(OK)); + data->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: success [%d]\n", + __func__, retval); + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_fw_ver_bin(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "SY%02X%02X%02X", + rmi4_data->ic_revision_of_bin, + rmi4_data->panel_revision, + rmi4_data->fw_version_of_bin); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_fw_ver_ic(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "SY%02X%02X%02X", + rmi4_data->ic_revision_of_ic, + rmi4_data->panel_revision, + rmi4_data->fw_version_of_ic); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_config_ver(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + set_default_result(data); + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s_SY_%02d%02d", + pdata->model_name ?: pdata->project_name ?:SYNAPTICS_DEVICE_NAME, (rmi4_data->fw_release_date_of_ic >> 8) & 0x0F, + rmi4_data->fw_release_date_of_ic & 0x00FF); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} +static void get_checksum_data(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%X", rmi4_data->rmi4_mod_info.pr_number); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_threshold(void *dev_data) +{ + unsigned char saturationcap_lsb; + unsigned char saturationcap_msb; + unsigned char amplitudethreshold; + unsigned int saturationcap; + unsigned int threshold_integer; + unsigned int threshold_fraction; + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + + rmi4_data->i2c_read(rmi4_data, + rmi4_data->f12.ctrl15_addr, + &litudethreshold, + sizeof(amplitudethreshold)); + rmi4_data->i2c_read(rmi4_data, + f54->control.reg_2->address, + &saturationcap_lsb, + sizeof(saturationcap_lsb)); + rmi4_data->i2c_read(rmi4_data, + f54->control.reg_2->address + 1, + &saturationcap_msb, + sizeof(saturationcap_msb)); + + saturationcap = (saturationcap_lsb & 0xFF) | ((saturationcap_msb & 0xFF) << 8); + threshold_integer = (amplitudethreshold * saturationcap)/256; + threshold_fraction = ((amplitudethreshold * saturationcap * 1000)/256)%1000; + + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: FingerAmp : %d, Satruration cap : %d\n", + __func__, amplitudethreshold, saturationcap); + + set_default_result(data); + sprintf(data->cmd_buff, "%u.%u", + threshold_integer, threshold_fraction); + data->cmd_state = CMD_STATUS_OK; + + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void module_off_master(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + mutex_lock(&rmi4_data->input_dev->mutex); + + rmi4_data->stop_device(rmi4_data); + + mutex_unlock(&rmi4_data->input_dev->mutex); + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(OK)); + data->cmd_state = CMD_STATUS_OK; + + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void module_on_master(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + int retval; + + set_default_result(data); + + mutex_lock(&rmi4_data->input_dev->mutex); + + retval = rmi4_data->start_device(rmi4_data); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to start device\n", __func__); + + mutex_unlock(&rmi4_data->input_dev->mutex); + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(OK)); + data->cmd_state = CMD_STATUS_OK; + + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_chip_vendor(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(SYNAPTICS)); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_chip_name(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + switch (rmi4_data->product_id) { + case SYNAPTICS_PRODUCT_ID_S5807: + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(S5807)); + break; + case SYNAPTICS_PRODUCT_ID_S5806: + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(S5806)); + break; + case SYNAPTICS_PRODUCT_ID_S5300: + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(S5300)); + break; + default: + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + } + + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_x_num(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d", rmi4_data->f54->tx_assigned); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_y_num(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d", rmi4_data->f54->rx_assigned); + data->cmd_state = CMD_STATUS_OK; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static int check_rx_tx_num(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + int node; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: param[0] = %d, param[1] = %d\n", + __func__, data->cmd_param[0], data->cmd_param[1]); + + if (data->cmd_param[0] < 0 || + data->cmd_param[0] >= f54->tx_assigned || + data->cmd_param[1] < 0 || + data->cmd_param[1] >= f54->rx_assigned) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: parameter error: %u,%u\n", + __func__, data->cmd_param[0], data->cmd_param[1]); + node = -1; + } else { + node = data->cmd_param[0] * f54->rx_assigned + + data->cmd_param[1]; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: node = %d\n", + __func__, node); + } + return node; +} + +static void get_rawcap(void *dev_data) +{ + int node; + short report_data; + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + node = check_rx_tx_num(rmi4_data); + + if (node < 0) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + report_data = data->rawcap_data[node]; + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d", report_data); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_rawcap_read(void *dev_data) +{ + int retval; + int kk = 0; + unsigned char ii; + unsigned char jj; + unsigned char num_of_tx; + unsigned char num_of_rx; + short *report_data; + short max_value; + short min_value; + short cur_value; + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned char cmd_state = CMD_STATUS_RUNNING; + unsigned char no_sleep = 0; + int retry = DO_PREPATION_RETRY_COUNT; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + do { + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &no_sleep, sizeof(no_sleep)); + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: fail to read no_sleep[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, + "%s", "Error read of f01_ctrl00"); + cmd_state = CMD_STATUS_FAIL; + goto out; + } + + no_sleep |= NO_SLEEP_ON; + + retval = rmi4_data->i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &no_sleep, sizeof(no_sleep)); + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: fail to write no_sleep[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, + "%s", "Error write to f01_ctrl00"); + cmd_state = CMD_STATUS_FAIL; + goto out; + } + + retval = do_preparation(rmi4_data); + if (retval >= 0) + break; + + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to do preparation. reset and retry again.\n", + __func__); + retval = rmi4_data->reset_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + retry--; + } while (retry > 0); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to do preparation\n", + __func__); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error preparation"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_FULL_RAW_CAP_RX_COUPLING_COMP)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + cmd_state = CMD_STATUS_FAIL; + goto sw_reset; + } + + report_data = data->rawcap_data; + memcpy(report_data, f54->report_data, f54->report_size); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + max_value = min_value = report_data[0]; + + for (ii = 0; ii < num_of_tx; ii++) { + for (jj = 0; jj < num_of_rx; jj++) { + cur_value = *report_data; + max_value = max(max_value, cur_value); + min_value = min(min_value, cur_value); + report_data++; + + if (cur_value > TSP_RAWCAP_MAX || cur_value < TSP_RAWCAP_MIN) + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "tx = %02d, rx = %02d, data[%d] = %d\n", + ii, jj, kk, cur_value); + kk++; + } + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d,%d", min_value, max_value); + cmd_state = CMD_STATUS_OK; + +sw_reset: + retval = rmi4_data->reset_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_delta(void *dev_data) +{ + int node; + short report_data; + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + node = check_rx_tx_num(rmi4_data); + if (node < 0) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + report_data = data->delta_data[node]; + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d", report_data); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_delta_read(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + short *report_data; + short cur_value; + unsigned char ii; + unsigned char jj; + unsigned char num_of_tx; + unsigned char num_of_rx; + int kk = 0; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_16BIT_IMAGE)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + report_data = data->delta_data; + memcpy(report_data, f54->report_data, f54->report_size); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + + for (ii = 0; ii < num_of_tx; ii++) { + for (jj = 0; jj < num_of_rx; jj++) { + cur_value = *report_data; + report_data++; + if (cur_value > TSP_DELTA_MAX || cur_value < TSP_DELTA_MIN) + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "tx = %02d, rx = %02d, data[%d] = %d\n", + ii, jj, kk, cur_value); + kk++; + } + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_abscap_read(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned int *report_data; + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + unsigned char ii; + unsigned short num_of_tx; + unsigned short num_of_rx; + int retval; + unsigned char cmd_state = CMD_STATUS_RUNNING; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_ABS_CAP)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + cmd_state = CMD_STATUS_FAIL; + goto sw_reset; + } + + report_data = data->abscap_data; + memcpy(report_data, f54->report_data, f54->report_size); + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + + data->abscap_rx_min = data->abscap_rx_max = report_data[0]; + data->abscap_tx_min = data->abscap_tx_max = report_data[num_of_rx]; + + for (ii = 0; ii < num_of_rx + num_of_tx ; ii++) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: %s [%d] = %d\n", + __func__, ii >= num_of_rx ? "Tx" : "Rx", + ii < num_of_rx ? ii : ii - num_of_rx, + *report_data); + + if (ii >= num_of_rx) { + data->abscap_tx_min = min(data->abscap_tx_min , *report_data); + data->abscap_tx_max = max(data->abscap_tx_max , *report_data); + } else { + data->abscap_rx_min = min(data->abscap_rx_min , *report_data); + data->abscap_rx_max = max(data->abscap_rx_max , *report_data); + } + + if (ii == num_of_rx + num_of_tx -1) + snprintf(temp, CMD_STR_LEN, "%d", *report_data); + else + snprintf(temp, CMD_STR_LEN, "%d,", *report_data); + strncat(temp2, temp, RPT_DATA_STRNCAT_LENGTH); + report_data++; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: RX:[%d][%d], TX:[%d][%d]\n", + __func__, data->abscap_rx_min, data->abscap_rx_max, + data->abscap_tx_min, data->abscap_tx_max); + + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + cmd_state = CMD_STATUS_OK; + +sw_reset: + retval = rmi4_data->reset_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_abscap_read_test(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned char cmd_state = CMD_STATUS_RUNNING; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: RX:[%d][%d], TX:[%d][%d]\n", + __func__, data->abscap_rx_min, data->abscap_rx_max, + data->abscap_tx_min, data->abscap_tx_max); + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%d,%d,%d,%d", + data->abscap_rx_min, data->abscap_rx_max, + data->abscap_tx_min, data->abscap_tx_max); + cmd_state = CMD_STATUS_OK; + + data->abscap_rx_min = data->abscap_rx_max = data->abscap_tx_min = data->abscap_tx_max = 0; + +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_absdelta_read(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + struct factory_data *data = f54->factory_data; + + int *report_data; + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + unsigned char ii; + unsigned short num_of_tx; + unsigned short num_of_rx; + unsigned char proximity_enables = FINGER_HOVER_EN; + + int retval; + unsigned char cmd_state = CMD_STATUS_RUNNING; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + /* Enable hover before read abs delta */ + retval = rmi4_data->i2c_write(rmi4_data, f51->proximity_enables_addr, + &proximity_enables, sizeof(proximity_enables)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write proximity_enables\n", + __func__); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "NG"); + cmd_state = CMD_STATUS_FAIL; + goto out; + } + /* at least 5 frame time are needed after enable hover + * to get creadible abs delta data( 16.6 * 5 = 88 msec ) + */ + msleep(150); + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_ABS_DELTA)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + cmd_state = CMD_STATUS_FAIL; + goto sw_reset; + } + + report_data = data->absdelta_data; + memcpy(report_data, f54->report_data, f54->report_size); + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + + for (ii = 0; ii < num_of_rx + num_of_tx; ii++) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: %s [%d] = %d\n", + __func__, ii >= num_of_rx ? "Tx" : "Rx", + ii < num_of_rx ? ii : ii - num_of_rx, + *report_data); + snprintf(temp, CMD_STR_LEN, "%d,", *report_data); + strncat(temp2, temp, RPT_DATA_STRNCAT_LENGTH); + report_data++; + } + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + cmd_state = CMD_STATUS_OK; + +sw_reset: + retval = rmi4_data->reset_device(rmi4_data); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +/* trx_short_test register mapping + * 0 : not used ( using 5.2 inch) + * 1 ~ 28 : Rx + * 29 ~ 31 : Side Button 0, 1, 2 + * 32 ~ 33 : Guard + * 34 : Charge Substraction + * 35 ~ 50 : Tx + * 51 ~ 53 : Side Button 3, 4, 5 + */ + +static void run_trx_short_test(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + char *report_data; + unsigned char ii, jj; + int retval = 0; + unsigned char cmd_state = CMD_STATUS_RUNNING; + + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + disable_irq(rmi4_data->i2c_client->irq); + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_TREX_SHORTS)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + cmd_state = CMD_STATUS_FAIL; + goto sw_reset; + } + + report_data = data->trx_short; + memcpy(report_data, f54->report_data, f54->report_size); + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + for (ii = 0; ii < f54->report_size; ii++) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [%d]: [%x][%x][%x][%x][%x][%x][%x][%x]\n", + __func__, ii, *report_data & 0x1, (*report_data & 0x2) >> 1, + (*report_data & 0x4) >> 2, (*report_data & 0x8) >> 3, + (*report_data & 0x10) >> 4, (*report_data & 0x20) >> 5, + (*report_data & 0x40) >> 6, (*report_data & 0x80) >> 7); + + for (jj = 0; jj < 8; jj++) { + snprintf(temp, CMD_STR_LEN, "%d,", (*report_data >> jj) & 0x01); + strncat(temp2, temp, RPT_DATA_STRNCAT_LENGTH); + } + report_data++; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + cmd_state = CMD_STATUS_OK; + +sw_reset: + enable_irq(rmi4_data->i2c_client->irq); + retval = rmi4_data->reset_device(rmi4_data); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void dead_zone_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + unsigned char dead_zone_en = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 2) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f51->general_control_addr, &dead_zone_en, sizeof(dead_zone_en)); + + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to read no_sleep[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + /* 0: Disable dead Zone for factory app , 1: Enable dead Zone (default) */ + if (data->cmd_param[0]) + dead_zone_en |= DEAD_ZONE_EN; + else + dead_zone_en &= ~(DEAD_ZONE_EN); + + retval = rmi4_data->i2c_write(rmi4_data, + rmi4_data->f51->general_control_addr, &dead_zone_en, sizeof(dead_zone_en)); + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to read dead_zone_en[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +#ifdef PROXIMITY_MODE +static void hover_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0, enables = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + enables = data->cmd_param[0]; + retval = synaptics_rmi4_proximity_enables(rmi4_data, enables); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, retval = %d\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +static void hover_no_sleep_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned char no_sleep = 0; + int retval = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &no_sleep, sizeof(no_sleep)); + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to read no_sleep[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]) + no_sleep |= NO_SLEEP_ON; + else + no_sleep &= ~(NO_SLEEP_ON); + + retval = rmi4_data->i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &no_sleep, sizeof(no_sleep)); + if (retval <= 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to read no_sleep[ret:%d]\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void hover_set_edge_rx(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + unsigned char edge_exculsion_rx = 0x10; + int retval = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]) + edge_exculsion_rx = 0x0; + else + edge_exculsion_rx = 0x10; + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_WRITE, + rmi4_data->f51->grip_edge_exclusion_rx_addr, sizeof(edge_exculsion_rx), &edge_exculsion_rx); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write grip edge exclustion rx with [0x%02X].\n", + __func__, edge_exculsion_rx); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} +#endif + +static void set_jitter_level(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0, level = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 255) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, the range of jitter level is 0~255\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + level = data->cmd_param[0]; + + retval = synaptics_rmi4_f12_ctrl11_set(rmi4_data, level); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, retval = %d\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +#ifdef GLOVE_MODE +static void glove_mode(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + + set_default_result(data); + + if (rmi4_data->f12.feature_enable & CLOSED_COVER_EN) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s Skip glove mode set (cover bit enabled)\n", + __func__); + goto out; + } + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]){ + rmi4_data->f12.feature_enable |= GLOVE_DETECTION_EN; + rmi4_data->f12.obj_report_enable |= OBJ_TYPE_GLOVE; + } else { + rmi4_data->f12.feature_enable &= ~(GLOVE_DETECTION_EN); + rmi4_data->f12.obj_report_enable &= ~(OBJ_TYPE_GLOVE); + } + + retval = synaptics_rmi4_glove_mode_enables(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, retval = %d\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +static void fast_glove_mode(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]) { + rmi4_data->f12.feature_enable |= FAST_GLOVE_DECTION_EN | GLOVE_DETECTION_EN; + rmi4_data->f12.obj_report_enable |= OBJ_TYPE_GLOVE; + rmi4_data->fast_glove_state = true; + } else { + rmi4_data->f12.feature_enable &= ~(FAST_GLOVE_DECTION_EN); + rmi4_data->f12.obj_report_enable |= OBJ_TYPE_GLOVE; + rmi4_data->fast_glove_state = false; + } + + retval = synaptics_rmi4_glove_mode_enables(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, retval = %d\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +static void clear_cover_mode(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 3) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + rmi4_data->f12.feature_enable = data->cmd_param[0]; + + if (data->cmd_param[0] && rmi4_data->fast_glove_state) + rmi4_data->f12.feature_enable |= FAST_GLOVE_DECTION_EN; + + retval = synaptics_rmi4_glove_mode_enables(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s failed, retval = %d\n", + __func__, retval); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + + /* Sync user setting value when wakeup with flip cover opened */ + if (rmi4_data->f12.feature_enable == CLOSED_COVER_EN + || rmi4_data->f12.feature_enable == (CLOSED_COVER_EN | FAST_GLOVE_DECTION_EN)) { + + rmi4_data->f12.feature_enable &= ~(CLOSED_COVER_EN); + if (rmi4_data->fast_glove_state) + rmi4_data->f12.feature_enable |= GLOVE_DETECTION_EN; + } + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} +#endif + +#ifdef TSP_BOOSTER +static void boost_level(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] >= BOOSTER_LEVEL_MAX) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + change_booster_level_for_tsp(data->cmd_param[0]); + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s %d\n", + __func__, data->cmd_param[0]); + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} +#endif + +#ifdef SIDE_TOUCH +static void sidekey_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + int retval = 0; + unsigned char general_control_2; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + retval = rmi4_data->i2c_read(rmi4_data, rmi4_data->f51->general_control_2_addr, + &general_control_2, sizeof(general_control_2)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read general control 2.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]) + general_control_2 |= SIDE_BUTTONS_EN; + else + general_control_2 &= ~(SIDE_BUTTONS_EN); + + retval = rmi4_data->i2c_write(rmi4_data, rmi4_data->f51->general_control_2_addr, + &general_control_2, sizeof(general_control_2)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write general control 2 register with [0x%02X].\n", + __func__, general_control_2); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + rmi4_data->f51->general_control_2 = general_control_2; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: General Control2 [0x%02X]\n", + __func__, rmi4_data->f51->general_control_2); + + if (!data->cmd_param[0]) + synpatics_rmi4_release_all_event(rmi4_data, RELEASE_TYPE_SIDEKEY); + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} + +static void set_sidekey_only_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + int retval = 0; + unsigned char device_control = 0; + bool sidekey_only_enable; + + set_default_result(data); + + mutex_lock(&rmi4_data->rmi4_device_mutex); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 1) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + sidekey_only_enable = data->cmd_param[0] ? true : false; + + /* Control device_control value */ + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &device_control, sizeof(device_control)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read Device Control register.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (sidekey_only_enable) + device_control &= ~(SENSOR_SLEEP); + else + device_control |= SENSOR_SLEEP; + + retval = rmi4_data->i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, &device_control, sizeof(device_control)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write Device Control register [0x%02X].\n", + __func__, device_control); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (sidekey_only_enable) + rmi4_data->sensor_sleep = false; + else + rmi4_data->sensor_sleep = true; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s : [F01_CTRL] 0x%02X, [F51_CTRL] 0x%02X/0x%02X/0x%02X]\n", + __func__, device_control, rmi4_data->f51->proximity_enables, rmi4_data->f51->general_control, rmi4_data->f51->general_control_2); + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + mutex_unlock(&rmi4_data->rmi4_device_mutex); + + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_sidekey_threshold(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + unsigned char sidekey_threshold[NUM_OF_ACTIVE_SIDE_BUTTONS]; + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + int retval = 0, ii = 0; + + set_default_result(data); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "TSP turned off"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_READ, + rmi4_data->f51->sidebutton_tapthreshold_addr, + NUM_OF_ACTIVE_SIDE_BUTTONS, sidekey_threshold); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write general control 2 register with [0x%02X].\n", + __func__, rmi4_data->f51->general_control_2); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + while (ii < NUM_OF_ACTIVE_SIDE_BUTTONS) { + snprintf(temp, CMD_STR_LEN, "%u ", sidekey_threshold[ii]); + strcat(temp2, temp); + ii++; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_sidekey_delta_read(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + int *report_data; + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + unsigned char ii; + unsigned short num_of_tx; + unsigned short num_of_rx; + unsigned char sidekey_production_test; + int retval; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + /* Set sidekey production test */ + retval = rmi4_data->i2c_read(rmi4_data, rmi4_data->f51->general_control_2_addr, + &sidekey_production_test, sizeof(sidekey_production_test)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read general control 2.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + sidekey_production_test |= SIDE_BUTTONS_PRODUCTION_TEST; + + retval = rmi4_data->i2c_write(rmi4_data, rmi4_data->f51->general_control_2_addr, + &sidekey_production_test, + sizeof(sidekey_production_test)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write general control 2 register with [0x%02X].\n", + __func__, sidekey_production_test); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + msleep(100); + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_ABS_DELTA)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + report_data = f54->factory_data->absdelta_data; + memcpy(report_data, f54->report_data, f54->report_size); + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + + for (ii = 0; ii < (num_of_rx + num_of_tx + NUM_OF_ACTIVE_SIDE_BUTTONS); ii++) { + if (rmi4_data->product_id < SYNAPTICS_PRODUCT_ID_S5100) + *report_data &= 0x0FFFF; + + if (ii < (num_of_rx + num_of_tx)) { + report_data++; + continue; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: %s [%d] = %d\n", __func__, "SIDE", + ii - (num_of_rx + num_of_tx), *report_data); + snprintf(temp, CMD_STR_LEN, "%d,", *report_data); + strncat(temp2, temp, RPT_DATA_STRNCAT_LENGTH); + report_data++; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void run_sidekey_abscap_read(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned int *report_data; + char temp[CMD_STR_LEN]; + char temp2[CMD_RESULT_STR_LEN]; + unsigned char ii; + unsigned short num_of_tx; + unsigned short num_of_rx; + unsigned char cmd_state = CMD_STATUS_RUNNING; + + unsigned char sidekey_production_test; + int retval; + + set_default_result(data); + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + /* Set sidekey production test */ + retval = rmi4_data->i2c_read(rmi4_data, rmi4_data->f51->general_control_2_addr, + &sidekey_production_test, sizeof(sidekey_production_test)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read general control 2.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + cmd_state = CMD_STATUS_FAIL; + goto out; + } + + sidekey_production_test |= SIDE_BUTTONS_PRODUCTION_TEST; + + retval = rmi4_data->i2c_write(rmi4_data, rmi4_data->f51->general_control_2_addr, + &sidekey_production_test, + sizeof(sidekey_production_test)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write general control 2 register with [0x%02X].\n", + __func__, sidekey_production_test); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + cmd_state = CMD_STATUS_FAIL; + goto out; + } + + msleep(100); + + if (!synaptics_rmi4_f54_get_report_type(rmi4_data, F54_ABS_CAP)) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "Error get report type"); + cmd_state = CMD_STATUS_FAIL; + goto sw_reset; + } + + report_data = f54->factory_data->abscap_data; + memcpy(report_data, f54->report_data, f54->report_size); + memset(temp, 0, CMD_STR_LEN); + memset(temp2, 0, CMD_RESULT_STR_LEN); + + num_of_tx = f54->tx_assigned; + num_of_rx = f54->rx_assigned; + + for (ii = 0; ii < num_of_rx + num_of_tx + NUM_OF_ACTIVE_SIDE_BUTTONS; ii++) { + if (rmi4_data->product_id < SYNAPTICS_PRODUCT_ID_S5100) + *report_data &= 0x0FFFF; + + if (ii < (num_of_rx + num_of_tx)) { + report_data++; + continue; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: %s [%d] = %d\n", __func__, "SIDE", + ii - (num_of_rx + num_of_tx), *report_data); + snprintf(temp, CMD_STR_LEN, "%d,", *report_data); + strncat(temp2, temp, RPT_DATA_STRNCAT_LENGTH); + report_data++; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", temp2); + cmd_state = CMD_STATUS_OK; + +sw_reset: + retval = rmi4_data->reset_device(rmi4_data); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + } + +out: + data->cmd_state = cmd_state; + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void set_sidekey_only_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + rmi4_data->use_deepsleep = data->cmd_param[0] ? true : false; + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void lozemode_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + unsigned char general_control_2 = 0; + int retval; + + set_default_result(data); + + retval = rmi4_data->i2c_read(rmi4_data, rmi4_data->f51->general_control_2_addr, + &general_control_2, sizeof(general_control_2)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read general control 2.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (data->cmd_param[0]) + general_control_2 |= ENTER_SLEEP_MODE; + else + general_control_2 &= ~ENTER_SLEEP_MODE; + + retval = rmi4_data->i2c_write(rmi4_data, rmi4_data->f51->general_control_2_addr, + &general_control_2, sizeof(general_control_2)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write general control 2 register with [0x%02X].\n", + __func__, general_control_2); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NA"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + rmi4_data->f51->general_control_2 = general_control_2; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: General Control2 [0x%02X]\n", + __func__, rmi4_data->f51->general_control_2); + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} +#endif + +static void set_tsp_test_result(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int retval = 0; + unsigned char device_status = 0; + + set_default_result(data); + + if (data->cmd_param[0] < TSP_FACTEST_RESULT_NONE + || data->cmd_param[0] > TSP_FACTEST_RESULT_PASS) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + return; + } + + if (rmi4_data->touch_stopped || rmi4_data->sensor_sleep) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is %s\n", + __func__, rmi4_data->touch_stopped ? "stopped" : "Sleep state"); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "TSP is %s", + rmi4_data->touch_stopped ? "off" : "sleep"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr, + &device_status, + sizeof(device_status)); + if (device_status != 0) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NR)); + data->cmd_state = CMD_STATUS_FAIL; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: IC not ready[%d]\n", + __func__, device_status); + goto out; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: check status register[%d]\n", + __func__, device_status); + + retval = synaptics_rmi4_set_tsp_test_result_in_config(rmi4_data, data->cmd_param[0]); + msleep(200); + + if (retval < 0) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + data->cmd_state = CMD_STATUS_FAIL; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed [%d]\n", + __func__, retval); + goto out; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(OK)); + data->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: success to save test result\n", + __func__); + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +static void get_tsp_test_result(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + int result = 0; + + set_default_result(data); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "TSP turned off"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + result = synaptics_rmi4_read_tsp_test_result(rmi4_data); + + if (result < TSP_FACTEST_RESULT_NONE || result > TSP_FACTEST_RESULT_PASS) { + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NG)); + data->cmd_state = CMD_STATUS_FAIL; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: failed [%d]\n", + __func__, result); + goto out; + } + + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", + result == TSP_FACTEST_RESULT_PASS ? tostring(PASS) : + result == TSP_FACTEST_RESULT_FAIL ? tostring(FAIL) : + tostring(NONE)); + data->cmd_state = CMD_STATUS_OK; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: success [%s][%d]", __func__, + result == TSP_FACTEST_RESULT_PASS ? "PASS" : + result == TSP_FACTEST_RESULT_FAIL ? "FAIL" : + "NONE", result); + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} + +#ifdef USE_ACTIVE_REPORT_RATE +static void report_rate(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct factory_data *data = f54->factory_data; + + int retval; + unsigned char command = COMMAND_FORCE_UPDATE; + unsigned char rpt_rate = 0; + + set_default_result(data); + + if (data->cmd_param[0] < SYNAPTICS_RPT_RATE_START + || data->cmd_param[0] >= SYNAPTICS_RPT_RATE_END) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: [ERROR] Touch is stopped\n", + __func__); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", "TSP turned off"); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + goto out; + } + + retval = rmi4_data->i2c_read(rmi4_data, f54->control.reg_94->address, + f54->control.reg_94->data, sizeof(f54->control.reg_94->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read control_94 register.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + switch (data->cmd_param[0]) { + case SYNAPTICS_RPT_RATE_90HZ: + rpt_rate = SYNAPTICS_RPT_RATE_90HZ_VAL; + break; + case SYNAPTICS_RPT_RATE_60HZ: + rpt_rate = SYNAPTICS_RPT_RATE_60HZ_VAL; + break; + case SYNAPTICS_RPT_RATE_30HZ: + rpt_rate = SYNAPTICS_RPT_RATE_30HZ_VAL; + break; + } + + if (f54->control.reg_94->noise_bursts_per_cluster == rpt_rate) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + goto out; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Set report rate %sHz [0x%02X->0x%02X]\n", __func__, + data->cmd_param[0] == SYNAPTICS_RPT_RATE_90HZ ? "90" : + data->cmd_param[0] == SYNAPTICS_RPT_RATE_60HZ ? "60" : "30", + f54->control.reg_94->noise_bursts_per_cluster, rpt_rate); + + f54->control.reg_94->noise_bursts_per_cluster = rpt_rate; + + retval = rmi4_data->i2c_write(rmi4_data, f54->control.reg_94->address, + f54->control.reg_94->data, sizeof(f54->control.reg_94->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write control_94 register.\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + retval = rmi4_data->i2c_write(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write force update command\n", + __func__); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = CMD_STATUS_WAITING; +} +#endif + +#ifdef USE_STYLUS +static void stylus_enable(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + unsigned char value; + int retval = 0; + + set_default_result(data); + + if (data->cmd_param[0] < 0 || data->cmd_param[0] > 2) { + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + if (rmi4_data->use_stylus != (data->cmd_param[0] ? true : false)) { + rmi4_data->use_stylus = data->cmd_param[0] ? true : false; + synpatics_rmi4_release_all_event(rmi4_data, RELEASE_TYPE_FINGER); + } + + value = data->cmd_param[0] ? 0x01 : 0x00; + + retval = synaptics_rmi4_access_register(rmi4_data, SYNAPTICS_ACCESS_WRITE, + rmi4_data->f51->forcefinger_onedge_addr, sizeof(value), &value); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write force finger on edge with [0x%02X].\n", + __func__, value); + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "NG"); + data->cmd_state = CMD_STATUS_FAIL; + goto out; + } + + snprintf(data->cmd_buff, sizeof(data->cmd_buff), "OK"); + data->cmd_state = CMD_STATUS_OK; + +out: + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); +} +#endif + +static void not_support_cmd(void *dev_data) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)dev_data; + struct factory_data *data = rmi4_data->f54->factory_data; + + set_default_result(data); + snprintf(data->cmd_buff, CMD_RESULT_STR_LEN, "%s", tostring(NA)); + set_cmd_result(data, data->cmd_buff, strlen(data->cmd_buff)); + data->cmd_state = CMD_STATUS_NOT_APPLICABLE; + + /* Some cmds are supported in specific IC and they are clear the cmd_is running flag + * itself(without show_cmd_result_) in their function such as hover_enable, glove_mode. + * So we need to clear cmd_is runnint flag if that command is replaced with + * not_support_cmd */ + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); +} +#endif + +static ssize_t synaptics_rmi4_f54_status_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->status); +} + +static ssize_t synaptics_rmi4_f54_report_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->report_size); +} + +static ssize_t synaptics_rmi4_f54_no_auto_cal_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->no_auto_cal); +} + +static ssize_t synaptics_rmi4_f54_no_auto_cal_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned char data; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + if (setting > 1) + return -EINVAL; + + retval = rmi4_data->i2c_read(rmi4_data, + f54->control_base_addr, + &data, + sizeof(data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read control register\n", + __func__); + return retval; + } + + if ((data & NO_AUTO_CAL_MASK) == setting) + return count; + + data = (data & ~NO_AUTO_CAL_MASK) | (data & NO_AUTO_CAL_MASK); + + retval = rmi4_data->i2c_write(rmi4_data, + f54->control_base_addr, + &data, + sizeof(data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write control register\n", + __func__); + return retval; + } + + f54->no_auto_cal = (setting == 1); + + return count; +} + +static ssize_t synaptics_rmi4_f54_report_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->report_type); +} + +static ssize_t synaptics_rmi4_f54_report_type_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned char data; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + if (!is_report_type_valid(rmi4_data, (enum f54_report_types)setting)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Report type not supported by driver\n", + __func__); + return -EINVAL; + } + + mutex_lock(&f54->status_mutex); + + if (f54->status != STATUS_BUSY) { + f54->report_type = (enum f54_report_types)setting; + data = (unsigned char)setting; + retval = rmi4_data->i2c_write(rmi4_data, + f54->data_base_addr, + &data, + sizeof(data)); + mutex_unlock(&f54->status_mutex); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write data register\n", + __func__); + return retval; + } + return count; + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Previous get report still ongoing\n", + __func__); + mutex_unlock(&f54->status_mutex); + return -EINVAL; + } +} + +static ssize_t synaptics_rmi4_f54_fifoindex_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int retval; + unsigned char data[2]; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = rmi4_data->i2c_read(rmi4_data, + f54->data_base_addr + DATA_REPORT_INDEX_OFFSET, + data, + sizeof(data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read data registers\n", + __func__); + return retval; + } + + batohs(&f54->fifoindex, data); + + return snprintf(buf, PAGE_SIZE, "%u\n", f54->fifoindex); +} +static ssize_t synaptics_rmi4_f54_fifoindex_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned char data[2]; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + f54->fifoindex = setting; + + hstoba(data, (unsigned short)setting); + + retval = rmi4_data->i2c_write(rmi4_data, + f54->data_base_addr + DATA_REPORT_INDEX_OFFSET, + data, + sizeof(data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write data registers\n", + __func__); + return retval; + } + + return count; +} + +static ssize_t synaptics_rmi4_f54_do_preparation_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + if (setting != 1) + return -EINVAL; + + mutex_lock(&f54->status_mutex); + + if (f54->status != STATUS_IDLE) { + if (f54->status != STATUS_BUSY) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Invalid status (%d)\n", + __func__, f54->status); + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Previous get report still ongoing\n", + __func__); + } + mutex_unlock(&f54->status_mutex); + return -EBUSY; + } + + mutex_unlock(&f54->status_mutex); + + retval = do_preparation(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to do preparation\n", + __func__); + return retval; + } + + return count; +} + +static ssize_t synaptics_rmi4_f54_get_report_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned char command; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + if (setting != 1) + return -EINVAL; + + command = (unsigned char)COMMAND_GET_REPORT; + + if (!is_report_type_valid(rmi4_data, f54->report_type)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Invalid report type\n", + __func__); + return -EINVAL; + } + + mutex_lock(&f54->status_mutex); + + if (f54->status != STATUS_IDLE) { + if (f54->status != STATUS_BUSY) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Invalid status (%d)\n", + __func__, f54->status); + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Previous get report still ongoing\n", + __func__); + } + mutex_unlock(&f54->status_mutex); + return -EBUSY; + } + + set_interrupt(rmi4_data, true); + + f54->status = STATUS_BUSY; + + retval = rmi4_data->i2c_write(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + mutex_unlock(&f54->status_mutex); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write get report command\n", + __func__); + return retval; + } + +#ifdef WATCHDOG_HRTIMER + hrtimer_start(&f54->watchdog, + ktime_set(WATCHDOG_TIMEOUT_S, 0), + HRTIMER_MODE_REL); +#endif + + return count; +} + +static ssize_t synaptics_rmi4_f54_force_cal_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned char command; + unsigned long setting; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = kstrtoul(buf, 10, &setting); + if (retval) + return retval; + + if (setting != 1) + return count; + + command = (unsigned char)COMMAND_FORCE_CAL; + + if (f54->status == STATUS_BUSY) + return -EBUSY; + + retval = rmi4_data->i2c_write(rmi4_data, + f54->command_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write force cal command\n", + __func__); + return retval; + } + + return count; +} + +static ssize_t synaptics_rmi4_f54_num_of_mapped_rx_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->rx_assigned); +} + +static ssize_t synaptics_rmi4_f54_num_of_mapped_tx_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + return snprintf(buf, PAGE_SIZE, "%u\n", rmi4_data->f54->tx_assigned); +} + +simple_show_func_unsigned(query, num_of_rx_electrodes) +simple_show_func_unsigned(query, num_of_tx_electrodes) +simple_show_func_unsigned(query, has_image16) +simple_show_func_unsigned(query, has_image8) +simple_show_func_unsigned(query, has_baseline) +simple_show_func_unsigned(query, clock_rate) +simple_show_func_unsigned(query, touch_controller_family) +simple_show_func_unsigned(query, has_pixel_touch_threshold_adjustment) +simple_show_func_unsigned(query, has_sensor_assignment) +simple_show_func_unsigned(query, has_interference_metric) +simple_show_func_unsigned(query, has_sense_frequency_control) +simple_show_func_unsigned(query, has_firmware_noise_mitigation) +simple_show_func_unsigned(query, has_two_byte_report_rate) +simple_show_func_unsigned(query, has_one_byte_report_rate) +simple_show_func_unsigned(query, has_relaxation_control) +simple_show_func_unsigned(query, curve_compensation_mode) +simple_show_func_unsigned(query, has_iir_filter) +simple_show_func_unsigned(query, has_cmn_removal) +simple_show_func_unsigned(query, has_cmn_maximum) +simple_show_func_unsigned(query, has_touch_hysteresis) +simple_show_func_unsigned(query, has_edge_compensation) +simple_show_func_unsigned(query, has_per_frequency_noise_control) +simple_show_func_unsigned(query, has_signal_clarity) +simple_show_func_unsigned(query, number_of_sensing_frequencies) + +show_store_func_unsigned(control, reg_0, no_relax) +show_store_func_unsigned(control, reg_0, no_scan) +show_store_func_unsigned(control, reg_1, bursts_per_cluster) +show_store_func_unsigned(control, reg_2, saturation_cap) +show_store_func_unsigned(control, reg_3, pixel_touch_threshold) +show_store_func_unsigned(control, reg_4__6, rx_feedback_cap) +show_store_func_unsigned(control, reg_4__6, low_ref_cap) +show_store_func_unsigned(control, reg_4__6, low_ref_feedback_cap) +show_store_func_unsigned(control, reg_4__6, low_ref_polarity) +show_store_func_unsigned(control, reg_4__6, high_ref_cap) +show_store_func_unsigned(control, reg_4__6, high_ref_feedback_cap) +show_store_func_unsigned(control, reg_4__6, high_ref_polarity) +show_store_func_unsigned(control, reg_7, cbc_cap) +show_store_func_unsigned(control, reg_7, cbc_polarity) +show_store_func_unsigned(control, reg_7, cbc_tx_carrier_selection) +show_store_func_unsigned(control, reg_8__9, integration_duration) +show_store_func_unsigned(control, reg_8__9, reset_duration) +show_store_func_unsigned(control, reg_10, noise_sensing_bursts_per_image) +show_store_func_unsigned(control, reg_12__13, slow_relaxation_rate) +show_store_func_unsigned(control, reg_12__13, fast_relaxation_rate) +show_store_func_unsigned(control, reg_14, rxs_on_xaxis) +show_store_func_unsigned(control, reg_14, curve_comp_on_txs) +show_store_func_unsigned(control, reg_20, disable_noise_mitigation) +show_store_func_unsigned(control, reg_21, freq_shift_noise_threshold) +show_store_func_unsigned(control, reg_22__26, medium_noise_threshold) +show_store_func_unsigned(control, reg_22__26, high_noise_threshold) +show_store_func_unsigned(control, reg_22__26, noise_density) +show_store_func_unsigned(control, reg_22__26, frame_count) +show_store_func_unsigned(control, reg_27, iir_filter_coef) +show_store_func_unsigned(control, reg_28, quiet_threshold) +show_store_func_unsigned(control, reg_29, cmn_filter_disable) +show_store_func_unsigned(control, reg_30, cmn_filter_max) +show_store_func_unsigned(control, reg_31, touch_hysteresis) +show_store_func_unsigned(control, reg_32__35, rx_low_edge_comp) +show_store_func_unsigned(control, reg_32__35, rx_high_edge_comp) +show_store_func_unsigned(control, reg_32__35, tx_low_edge_comp) +show_store_func_unsigned(control, reg_32__35, tx_high_edge_comp) +show_store_func_unsigned(control, reg_41, no_signal_clarity) +show_store_func_unsigned(control, reg_57, cbc_cap_0d) +show_store_func_unsigned(control, reg_57, cbc_polarity_0d) +show_store_func_unsigned(control, reg_57, cbc_tx_carrier_selection_0d) + +show_replicated_func_unsigned(control, reg_15, sensor_rx_assignment) +show_replicated_func_unsigned(control, reg_16, sensor_tx_assignment) +show_replicated_func_unsigned(control, reg_17, disable) +show_replicated_func_unsigned(control, reg_17, filter_bandwidth) +show_replicated_func_unsigned(control, reg_19, stretch_duration) +show_replicated_func_unsigned(control, reg_38, noise_control_1) +show_replicated_func_unsigned(control, reg_39, noise_control_2) +show_replicated_func_unsigned(control, reg_40, noise_control_3) + +show_store_replicated_func_unsigned(control, reg_36, axis1_comp) +show_store_replicated_func_unsigned(control, reg_37, axis2_comp) + +static ssize_t synaptics_rmi4_f54_burst_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int retval; + int size = 0; + unsigned char ii; + unsigned char *temp; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + mutex_lock(&f54->control_mutex); + + retval = rmi4_data->i2c_read(rmi4_data, + f54->control.reg_17->address, + (unsigned char *)f54->control.reg_17->data, + f54->control.reg_17->length); + if (retval < 0) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Failed to read control reg_17\n", + __func__); + } + + retval = rmi4_data->i2c_read(rmi4_data, + f54->control.reg_18->address, + (unsigned char *)f54->control.reg_18->data, + f54->control.reg_18->length); + if (retval < 0) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Failed to read control reg_18\n", + __func__); + } + + mutex_unlock(&f54->control_mutex); + + temp = buf; + + for (ii = 0; ii < f54->control.reg_17->length; ii++) { + retval = snprintf(temp, PAGE_SIZE - size, "%u ", (1 << 8) * + f54->control.reg_17->data[ii].burst_count_b8__10 + + f54->control.reg_18->data[ii].burst_count_b0__7); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Faild to write output\n", + __func__); + return retval; + } + size += retval; + temp += retval; + } + + retval = snprintf(temp, PAGE_SIZE - size, "\n"); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Faild to write null terminator\n", + __func__); + return retval; + } + + return size + retval; +} + +static ssize_t synaptics_rmi4_f54_data_read(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + mutex_lock(&f54->data_mutex); + + if (count < f54->report_size) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Report type %d data size (%d) too large\n", + __func__, f54->report_type, f54->report_size); + mutex_unlock(&f54->data_mutex); + return -EINVAL; + } + + if (f54->report_data) { + memcpy(buf, f54->report_data, f54->report_size); + mutex_unlock(&f54->data_mutex); + return f54->report_size; + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Report type %d data not available\n", + __func__, f54->report_type); + mutex_unlock(&f54->data_mutex); + return -EINVAL; + } +} + +static int synaptics_rmi4_f54_set_sysfs(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + int reg_num; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + f54->attr_dir = kobject_create_and_add(ATTRIBUTE_FOLDER_NAME, + &rmi4_data->input_dev->dev.kobj); + if (!f54->attr_dir) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs directory\n", + __func__); + goto exit_1; + } + + retval = sysfs_create_bin_file(f54->attr_dir, &dev_report_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs bin file\n", + __func__); + goto exit_2; + } + + retval = sysfs_create_group(f54->attr_dir, &attr_group); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs attributes\n", + __func__); + goto exit_3; + } + + for (reg_num = 0; reg_num < ARRAY_SIZE(attrs_ctrl_regs); reg_num++) { + if (attrs_ctrl_regs_exist[reg_num]) { + retval = sysfs_create_group(f54->attr_dir, + &attrs_ctrl_regs[reg_num]); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs attributes\n", + __func__); + goto exit_4; + } + } + } + + return 0; + +exit_4: + sysfs_remove_group(f54->attr_dir, &attr_group); + + for (reg_num--; reg_num >= 0; reg_num--) + sysfs_remove_group(f54->attr_dir, &attrs_ctrl_regs[reg_num]); + +exit_3: + sysfs_remove_bin_file(f54->attr_dir, &dev_report_data); + +exit_2: + kobject_put(f54->attr_dir); + +exit_1: + return -ENODEV; +} + +static int synaptics_rmi4_f54_set_ctrl(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned char length; + unsigned char reg_num = 0; + unsigned char num_of_sensing_freqs; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + struct f54_control *control = &f54->control; + + unsigned short reg_addr = f54->control_base_addr; + + num_of_sensing_freqs = f54->query.number_of_sensing_frequencies; + + /* control 0 */ + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_0 = kzalloc(sizeof(*(control->reg_0)), + GFP_KERNEL); + if (!control->reg_0) + goto exit_no_mem; + control->reg_0->address = reg_addr; + reg_addr += sizeof(control->reg_0->data); + reg_num++; + + /* control 1 */ + if ((f54->query.touch_controller_family == 0) || + (f54->query.touch_controller_family == 1)) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_1 = kzalloc(sizeof(*(control->reg_1)), + GFP_KERNEL); + if (!control->reg_1) + goto exit_no_mem; + control->reg_1->address = reg_addr; + reg_addr += sizeof(control->reg_1->data); + } + reg_num++; + + /* control 2 */ + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_2 = kzalloc(sizeof(*(control->reg_2)), + GFP_KERNEL); + if (!control->reg_2) + goto exit_no_mem; + control->reg_2->address = reg_addr; + reg_addr += sizeof(control->reg_2->data); + reg_num++; + + /* control 3 */ + if (f54->query.has_pixel_touch_threshold_adjustment == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_3 = kzalloc(sizeof(*(control->reg_3)), + GFP_KERNEL); + if (!control->reg_3) + goto exit_no_mem; + control->reg_3->address = reg_addr; + reg_addr += sizeof(control->reg_3->data); + } + reg_num++; + + /* controls 4 5 6 */ + if ((f54->query.touch_controller_family == 0) || + (f54->query.touch_controller_family == 1)) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_4__6 = kzalloc(sizeof(*(control->reg_4__6)), + GFP_KERNEL); + if (!control->reg_4__6) + goto exit_no_mem; + control->reg_4__6->address = reg_addr; + reg_addr += sizeof(control->reg_4__6->data); + } + reg_num++; + + /* control 7 */ + if (f54->query.touch_controller_family == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_7 = kzalloc(sizeof(*(control->reg_7)), + GFP_KERNEL); + if (!control->reg_7) + goto exit_no_mem; + control->reg_7->address = reg_addr; + reg_addr += sizeof(control->reg_7->data); + } + reg_num++; + + /* controls 8 9 */ + if ((f54->query.touch_controller_family == 0) || + (f54->query.touch_controller_family == 1)) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_8__9 = kzalloc(sizeof(*(control->reg_8__9)), + GFP_KERNEL); + if (!control->reg_8__9) + goto exit_no_mem; + control->reg_8__9->address = reg_addr; + reg_addr += sizeof(control->reg_8__9->data); + } + reg_num++; + + /* control 10 */ + if (f54->query.has_interference_metric == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_10 = kzalloc(sizeof(*(control->reg_10)), + GFP_KERNEL); + if (!control->reg_10) + goto exit_no_mem; + control->reg_10->address = reg_addr; + reg_addr += sizeof(control->reg_10->data); + } + reg_num++; + + /* control 11 */ + if (f54->query.has_ctrl11 == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_11 = kzalloc(sizeof(*(control->reg_11)), + GFP_KERNEL); + if (!control->reg_11) + goto exit_no_mem; + control->reg_11->address = reg_addr; + reg_addr += sizeof(control->reg_11->data); + } + reg_num++; + + /* controls 12 13 */ + if (f54->query.has_relaxation_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_12__13 = kzalloc(sizeof(*(control->reg_12__13)), + GFP_KERNEL); + if (!control->reg_12__13) + goto exit_no_mem; + control->reg_12__13->address = reg_addr; + reg_addr += sizeof(control->reg_12__13->data); + } + reg_num++; + + /* controls 14 15 16 */ + if (f54->query.has_sensor_assignment == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_14 = kzalloc(sizeof(*(control->reg_14)), + GFP_KERNEL); + if (!control->reg_14) + goto exit_no_mem; + control->reg_14->address = reg_addr; + reg_addr += sizeof(control->reg_14->data); + + control->reg_15 = kzalloc(sizeof(*(control->reg_15)), + GFP_KERNEL); + if (!control->reg_15) + goto exit_no_mem; + control->reg_15->length = f54->query.num_of_rx_electrodes; + control->reg_15->data = kzalloc(control->reg_15->length * + sizeof(*(control->reg_15->data)), GFP_KERNEL); + if (!control->reg_15->data) + goto exit_no_mem; + control->reg_15->address = reg_addr; + reg_addr += control->reg_15->length; + + control->reg_16 = kzalloc(sizeof(*(control->reg_16)), + GFP_KERNEL); + if (!control->reg_16) + goto exit_no_mem; + control->reg_16->length = f54->query.num_of_tx_electrodes; + control->reg_16->data = kzalloc(control->reg_16->length * + sizeof(*(control->reg_16->data)), GFP_KERNEL); + if (!control->reg_16->data) + goto exit_no_mem; + control->reg_16->address = reg_addr; + reg_addr += control->reg_16->length; + } + reg_num++; + + /* controls 17 18 19 */ + if (f54->query.has_sense_frequency_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + + length = num_of_sensing_freqs; + + control->reg_17 = kzalloc(sizeof(*(control->reg_17)), + GFP_KERNEL); + if (!control->reg_17) + goto exit_no_mem; + control->reg_17->length = length; + control->reg_17->data = kzalloc(length * + sizeof(*(control->reg_17->data)), GFP_KERNEL); + if (!control->reg_17->data) + goto exit_no_mem; + control->reg_17->address = reg_addr; + reg_addr += length; + + control->reg_18 = kzalloc(sizeof(*(control->reg_18)), + GFP_KERNEL); + if (!control->reg_18) + goto exit_no_mem; + control->reg_18->length = length; + control->reg_18->data = kzalloc(length * + sizeof(*(control->reg_18->data)), GFP_KERNEL); + if (!control->reg_18->data) + goto exit_no_mem; + control->reg_18->address = reg_addr; + reg_addr += length; + + control->reg_19 = kzalloc(sizeof(*(control->reg_19)), + GFP_KERNEL); + if (!control->reg_19) + goto exit_no_mem; + control->reg_19->length = length; + control->reg_19->data = kzalloc(length * + sizeof(*(control->reg_19->data)), GFP_KERNEL); + if (!control->reg_19->data) + goto exit_no_mem; + control->reg_19->address = reg_addr; + reg_addr += length; + } + reg_num++; + + /* control 20 */ + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_20 = kzalloc(sizeof(*(control->reg_20)), + GFP_KERNEL); + if (!control->reg_20) + goto exit_no_mem; + control->reg_20->address = reg_addr; + reg_addr += sizeof(control->reg_20->data); + reg_num++; + + /* control 21 */ + if (f54->query.has_sense_frequency_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_21 = kzalloc(sizeof(*(control->reg_21)), + GFP_KERNEL); + if (!control->reg_21) + goto exit_no_mem; + control->reg_21->address = reg_addr; + reg_addr += sizeof(control->reg_21->data); + } + reg_num++; + + /* controls 22 23 24 25 26 */ + if (f54->query.has_firmware_noise_mitigation == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_22__26 = kzalloc(sizeof(*(control->reg_22__26)), + GFP_KERNEL); + if (!control->reg_22__26) + goto exit_no_mem; + control->reg_22__26->address = reg_addr; + reg_addr += sizeof(control->reg_22__26->data); + } + reg_num++; + + /* control 27 */ + if (f54->query.has_iir_filter == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_27 = kzalloc(sizeof(*(control->reg_27)), + GFP_KERNEL); + if (!control->reg_27) + goto exit_no_mem; + control->reg_27->address = reg_addr; + reg_addr += sizeof(control->reg_27->data); + } + reg_num++; + + /* control 28 */ + if (f54->query.has_firmware_noise_mitigation == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_28 = kzalloc(sizeof(*(control->reg_28)), + GFP_KERNEL); + if (!control->reg_28) + goto exit_no_mem; + control->reg_28->address = reg_addr; + reg_addr += sizeof(control->reg_28->data); + } + reg_num++; + + /* control 29 */ + if (f54->query.has_cmn_removal == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_29 = kzalloc(sizeof(*(control->reg_29)), + GFP_KERNEL); + if (!control->reg_29) + goto exit_no_mem; + control->reg_29->address = reg_addr; + reg_addr += sizeof(control->reg_29->data); + } + reg_num++; + + /* control 30 */ + if (f54->query.has_cmn_maximum == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_30 = kzalloc(sizeof(*(control->reg_30)), + GFP_KERNEL); + if (!control->reg_30) + goto exit_no_mem; + control->reg_30->address = reg_addr; + reg_addr += sizeof(control->reg_30->data); + } + reg_num++; + + /* control 31 */ + if (f54->query.has_touch_hysteresis == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_31 = kzalloc(sizeof(*(control->reg_31)), + GFP_KERNEL); + if (!control->reg_31) + goto exit_no_mem; + control->reg_31->address = reg_addr; + reg_addr += sizeof(control->reg_31->data); + } + reg_num++; + + /* controls 32 33 34 35 */ + if (f54->query.has_edge_compensation == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_32__35 = kzalloc(sizeof(*(control->reg_32__35)), + GFP_KERNEL); + if (!control->reg_32__35) + goto exit_no_mem; + control->reg_32__35->address = reg_addr; + reg_addr += sizeof(control->reg_32__35->data); + } + reg_num++; + + /* control 36 */ + if ((f54->query.curve_compensation_mode == 1) || + (f54->query.curve_compensation_mode == 2)) { + attrs_ctrl_regs_exist[reg_num] = true; + + if (f54->query.curve_compensation_mode == 1) { + length = max(f54->query.num_of_rx_electrodes, + f54->query.num_of_tx_electrodes); + } else if (f54->query.curve_compensation_mode == 2) { + length = f54->query.num_of_rx_electrodes; + } + + control->reg_36 = kzalloc(sizeof(*(control->reg_36)), + GFP_KERNEL); + if (!control->reg_36) + goto exit_no_mem; + control->reg_36->length = length; + control->reg_36->data = kzalloc(length * + sizeof(*(control->reg_36->data)), GFP_KERNEL); + if (!control->reg_36->data) + goto exit_no_mem; + control->reg_36->address = reg_addr; + reg_addr += length; + } + reg_num++; + + /* control 37 */ + if (f54->query.curve_compensation_mode == 2) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_37 = kzalloc(sizeof(*(control->reg_37)), + GFP_KERNEL); + if (!control->reg_37) + goto exit_no_mem; + control->reg_37->length = f54->query.num_of_tx_electrodes; + control->reg_37->data = kzalloc(control->reg_37->length * + sizeof(*(control->reg_37->data)), GFP_KERNEL); + if (!control->reg_37->data) + goto exit_no_mem; + + control->reg_37->address = reg_addr; + reg_addr += control->reg_37->length; + } + reg_num++; + + /* controls 38 39 40 */ + if (f54->query.has_per_frequency_noise_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + + control->reg_38 = kzalloc(sizeof(*(control->reg_38)), + GFP_KERNEL); + if (!control->reg_38) + goto exit_no_mem; + control->reg_38->length = num_of_sensing_freqs; + control->reg_38->data = kzalloc(control->reg_38->length * + sizeof(*(control->reg_38->data)), GFP_KERNEL); + if (!control->reg_38->data) + goto exit_no_mem; + control->reg_38->address = reg_addr; + reg_addr += control->reg_38->length; + + control->reg_39 = kzalloc(sizeof(*(control->reg_39)), + GFP_KERNEL); + if (!control->reg_39) + goto exit_no_mem; + control->reg_39->length = num_of_sensing_freqs; + control->reg_39->data = kzalloc(control->reg_39->length * + sizeof(*(control->reg_39->data)), GFP_KERNEL); + if (!control->reg_39->data) + goto exit_no_mem; + control->reg_39->address = reg_addr; + reg_addr += control->reg_39->length; + + control->reg_40 = kzalloc(sizeof(*(control->reg_40)), + GFP_KERNEL); + if (!control->reg_40) + goto exit_no_mem; + control->reg_40->length = num_of_sensing_freqs; + control->reg_40->data = kzalloc(control->reg_40->length * + sizeof(*(control->reg_40->data)), GFP_KERNEL); + if (!control->reg_40->data) + goto exit_no_mem; + control->reg_40->address = reg_addr; + reg_addr += control->reg_40->length; + } + reg_num++; + + /* control 41 */ + if (f54->query.has_signal_clarity == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_41 = kzalloc(sizeof(*(control->reg_41)), + GFP_KERNEL); + if (!control->reg_41) + goto exit_no_mem; + control->reg_41->address = reg_addr; + reg_addr += sizeof(control->reg_41->data); + } + reg_num++; + + /* control 42 */ + if (f54->query.has_variance_metric == 1) + reg_addr += CONTROL_42_SIZE; + + /* controls 43 44 45 46 47 48 49 50 51 52 53 54 */ + if (f54->query.has_multi_metric_state_machine == 1) + reg_addr += CONTROL_43_54_SIZE; + + /* controls 55 56 */ + if (f54->query.has_0d_relaxation_control == 1) + reg_addr += CONTROL_55_56_SIZE; + + /* control 57 */ + if (f54->query.has_0d_acquisition_control == 1) { + attrs_ctrl_regs_exist[reg_num] = true; + control->reg_57 = kzalloc(sizeof(*(control->reg_57)), + GFP_KERNEL); + if (!control->reg_57) + goto exit_no_mem; + control->reg_57->address = reg_addr; + reg_addr += sizeof(control->reg_57->data); + } + reg_num++; + + /* control 58 */ + if (f54->query.has_0d_acquisition_control == 1) + reg_addr += CONTROL_58_SIZE; + + /* control 59 */ + if (f54->query.has_h_blank == 1) + reg_addr += CONTROL_59_SIZE; + + /* controls 60 61 62 */ + if ((f54->query.has_h_blank == 1) || + (f54->query.has_v_blank == 1) || + (f54->query.has_long_h_blank == 1)) + reg_addr += CONTROL_60_62_SIZE; + + /* control 63 */ + if ((f54->query.has_h_blank == 1) || + (f54->query.has_v_blank == 1) || + (f54->query.has_long_h_blank == 1) || + (f54->query.has_slew_metric == 1) || + (f54->query.has_slew_option == 1) || + (f54->query.has_noise_mitigation2 == 1)) + reg_addr += CONTROL_63_SIZE; + + /* controls 64 65 66 67 */ + if (f54->query.has_h_blank == 1) + reg_addr += CONTROL_64_67_SIZE * 7; + else if ((f54->query.has_v_blank == 1) || + (f54->query.has_long_h_blank == 1)) + reg_addr += CONTROL_64_67_SIZE; + + /* controls 68 69 70 71 72 73 */ + if ((f54->query.has_h_blank == 1) || + (f54->query.has_v_blank == 1) || + (f54->query.has_long_h_blank == 1)) + reg_addr += CONTROL_68_73_SIZE; + + /* control 74 */ + if (f54->query.has_slew_metric == 1) + reg_addr += CONTROL_74_SIZE; + + /* control 75 */ + if (f54->query.has_enhanced_stretch == 1) + reg_addr += num_of_sensing_freqs; + + /* control 76 */ + if (f54->query.has_startup_fast_relaxation == 1) + reg_addr += CONTROL_76_SIZE; + + /* controls 77 78 */ + if (f54->query.has_esd_control == 1) + reg_addr += CONTROL_77_78_SIZE; + + /* controls 79 80 81 82 83 */ + if (f54->query.has_noise_mitigation2 == 1) + reg_addr += CONTROL_79_83_SIZE; + + /* controls 84 85 */ + if (f54->query.has_energy_ratio_relaxation == 1) + reg_addr += CONTROL_84_85_SIZE; + + /* control 86 */ + if ((f54->query.has_query13 == 1) && (f54->query_13.has_ctrl86 == 1)) + reg_addr += CONTROL_86_SIZE; + + /* control 87 */ + if ((f54->query.has_query13 == 1) && (f54->query_13.has_ctrl87 == 1)) + reg_addr += CONTROL_87_SIZE; + + /* control 88 */ + if (f54->query.has_ctrl88 == 1) { + control->reg_88 = kzalloc(sizeof(*(control->reg_88)), + GFP_KERNEL); + if (!control->reg_88) + goto exit_no_mem; + control->reg_88->address = reg_addr; + reg_addr += sizeof(control->reg_88->data); + } + + /* control 89 */ + if ((f54->query.has_query13 == 1) && + ((f54->query_13.has_cidim == 1) || + (f54->query_13.has_noise_mitigation_enhancement == 1) || + (f54->query_13.has_rail_im))) + reg_addr += CONTROL_89_SIZE; + + /* control 90 */ + if ((f54->query.has_query15) && (f54->query_15.has_ctrl90)) + reg_addr += CONTROL_90_SIZE; + + /* control 91 */ + if (f54->query_21.has_ctrl91) + reg_addr += CONTROL_91_SIZE; + + /* control 92 */ + if (f54->query_16.has_ctrl92) + reg_addr += CONTROL_92_SIZE; + + /* control 93 */ + if (f54->query_16.has_ctrl93) + reg_addr += CONTROL_93_SIZE; + + /* control 94 */ + if (f54->query_16.has_ctrl94_query18) { + control->reg_94 = kzalloc(sizeof(*(control->reg_94)), + GFP_KERNEL); + if (!control->reg_94) + goto exit_no_mem; + control->reg_94->address = reg_addr; + } + + return 0; + +exit_no_mem: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for control registers\n", + __func__); + return -ENOMEM; +} + +static int synaptics_rmi4_f54_set_query(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char offset; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + retval = rmi4_data->i2c_read(rmi4_data, + f54->query_base_addr, + f54->query.data, + sizeof(f54->query.data)); + if (retval < 0) + return retval; + + offset = sizeof(f54->query.data); + + /* query 12 */ + if (f54->query.has_sense_frequency_control == 0) + offset -= 1; + + /* query 13 */ + if (f54->query.has_query13) { + retval = rmi4_data->i2c_read(rmi4_data, + f54->query_base_addr + offset, + f54->query_13.data, + sizeof(f54->query_13.data)); + if (retval < 0) + return retval; + offset += 1; + } + + /* query 14 */ + if ((f54->query.has_query13) && (f54->query_13.has_ctrl87)) + offset += 1; + + /* query 15 */ + if (f54->query.has_query15) { + retval = rmi4_data->i2c_read(rmi4_data, + f54->query_base_addr + offset, + f54->query_15.data, + sizeof(f54->query_15.data)); + if (retval < 0) + return retval; + offset += 1; + } + + /* query 16 */ + retval = rmi4_data->i2c_read(rmi4_data, + f54->query_base_addr + offset, + f54->query_16.data, + sizeof(f54->query_16.data)); + if (retval < 0) + return retval; + offset += 1; + + /* query 17 */ + if (f54->query_16.has_query17) + offset += 1; + + /* query 18 */ + if (f54->query_16.has_ctrl94_query18) + offset += 1; + + /* query 19 */ + if (f54->query_16.has_ctrl95_query19) + offset += 1; + + /* query 20 */ + if ((f54->query.has_query15) && (f54->query_15.has_query20)) + offset += 1; + + /* query 21 */ + retval = rmi4_data->i2c_read(rmi4_data, + f54->query_base_addr + offset, + f54->query_21.data, + sizeof(f54->query_21.data)); + if (retval < 0) + return retval; + + return 0; +} + +static int synaptics_rmi4_f54_reinit(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned short ii; + unsigned char page; + unsigned char intr_count = 0; + unsigned char intr_offset; + struct synaptics_rmi4_fn_desc rmi_fd; + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + for (page = 0; page < PAGES_TO_SERVICE; page++) { + for (ii = PDT_START; ii > PDT_END; ii -= PDT_ENTRY_SIZE) { + ii |= (page << 8); + + retval = rmi4_data->i2c_read(rmi4_data, + ii, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read page description table\n", + __func__); + goto err_out; + } + + if (rmi_fd.fn_number == SYNAPTICS_RMI4_F54) + goto f54_found; + + if (!rmi_fd.fn_number) + break; + + intr_count += (rmi_fd.intr_src_count & MASK_3BIT); + } + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: Can not find F54 in descripttion table\n", __func__); + goto pdt_done; + +f54_found: + f54->query_base_addr = rmi_fd.query_base_addr | (page << 8); + f54->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8); + f54->data_base_addr = rmi_fd.data_base_addr | (page << 8); + f54->command_base_addr = rmi_fd.cmd_base_addr | (page << 8); + + f54->intr_reg_num = (intr_count + 7) / 8; + if (f54->intr_reg_num != 0) + f54->intr_reg_num -= 1; + + f54->intr_mask = 0; + intr_offset = intr_count % 8; + for (ii = intr_offset; + ii < ((rmi_fd.intr_src_count & MASK_3BIT) + + intr_offset); + ii++) { + f54->intr_mask |= 1 << ii; + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: F54 found : NUM_INT_REG[%02X] INT_MASK[%02x] BASE_ADDRS[%04x,%04x,%04x,%04x]\n", + __func__, f54->intr_reg_num, f54->intr_mask, + f54->query_base_addr, f54->control_base_addr, f54->data_base_addr, f54->command_base_addr); + + retval = synaptics_rmi4_f54_set_query(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read query registers\n", + __func__); + goto err_out; + } + +#if 0 + f54->rx_assigned = f54->query.num_of_rx_electrodes; + f54->tx_assigned = f54->query.num_of_tx_electrodes; +#else + f54->rx_assigned = rmi4_data->num_of_rx; + f54->tx_assigned = rmi4_data->num_of_tx; +#endif + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: F54 rx,tx = %d, %d\n", __func__, f54->rx_assigned, f54->tx_assigned); + + free_control_mem(rmi4_data->f54); + retval = synaptics_rmi4_f54_set_ctrl(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to set up control registers\n", + __func__); + goto err_set_ctrl; + } + + return 0; + +err_set_ctrl: + free_control_mem(rmi4_data->f54); + +err_out: +pdt_done: + return retval; +} + +#ifdef FACTORY_MODE +static int synaptics_rmi4_f54_get_report_type(struct synaptics_rmi4_data *rmi4_data, int type) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + int retval; + char buf[3]; + unsigned int patience = 250; + + if (!f54) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: F54 is Null\n", + __func__); + return 0; + } + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, 3, "%u\n", type); + retval = synaptics_rmi4_f54_report_type_store(f54->attr_dir, NULL, buf, 2); + if (retval != 2) + return 0; + + memset(buf, 0x00, sizeof(buf)); + snprintf(buf, 3, "%u\n", CMD_GET_REPORT); + retval = synaptics_rmi4_f54_get_report_store(f54->attr_dir, NULL, buf, 2); + if (retval != 2) + return 0; + + do { + msleep(20); + if (f54->status == STATUS_IDLE) + break; + } while (--patience > 0); + + if ((f54->report_size == 0) || (f54->status != STATUS_IDLE)) + return 0; + else + return 1; +} +#endif + +static void synaptics_rmi4_f54_status_work(struct work_struct *work) +{ + int retval; + unsigned char report_index[2]; + + struct synaptics_rmi4_f54_handle *f54 = + container_of(work, struct synaptics_rmi4_f54_handle, status_work.work); + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)f54->rmi4_data; + + if (f54->status != STATUS_BUSY) + return; + + set_report_size(rmi4_data); + if (f54->report_size == 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Report data size = 0\n", + __func__); + retval = -EINVAL; + goto error_exit; + } + + if (f54->data_buffer_size < f54->report_size) { + mutex_lock(&f54->data_mutex); + if (f54->data_buffer_size) + kfree(f54->report_data); + f54->report_data = kzalloc(f54->report_size, GFP_KERNEL); + if (!f54->report_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for data buffer\n", + __func__); + f54->data_buffer_size = 0; + mutex_unlock(&f54->data_mutex); + retval = -ENOMEM; + goto error_exit; + } + f54->data_buffer_size = f54->report_size; + mutex_unlock(&f54->data_mutex); + } + + report_index[0] = 0; + report_index[1] = 0; + + retval = rmi4_data->i2c_write(rmi4_data, + f54->data_base_addr + DATA_REPORT_INDEX_OFFSET, + report_index, + sizeof(report_index)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write report data index\n", + __func__); + retval = -EINVAL; + goto error_exit; + } + + retval = rmi4_data->i2c_read(rmi4_data, + f54->data_base_addr + DATA_REPORT_DATA_OFFSET, + f54->report_data, + f54->report_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read report data\n", + __func__); + retval = -EINVAL; + goto error_exit; + } + + retval = STATUS_IDLE; + +#ifdef RAW_HEX + print_raw_hex_report(rmi4_data); +#endif + +#ifdef HUMAN_READABLE + print_image_report(rmi4_data); +#endif + +error_exit: + mutex_lock(&f54->status_mutex); + set_interrupt(rmi4_data, false); + f54->status = retval; + mutex_unlock(&f54->status_mutex); + + return; +} + +static void synaptics_rmi4_f54_attn(struct synaptics_rmi4_data *rmi4_data, + unsigned char intr_mask) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + if (!f54) + return; + + if (f54->intr_mask & intr_mask) { + queue_delayed_work(f54->status_workqueue, + &f54->status_work, + msecs_to_jiffies(STATUS_WORK_INTERVAL)); + } + + return; +} + +#ifdef FACTORY_MODE +static void synaptics_rmi4_remove_factory_mode(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + if (!f54) + return; + + sysfs_remove_link(&f54->factory_data->fac_dev_ts->kobj, "input"); + sysfs_remove_group(f54->attr_dir, &cmd_attr_group); + sec_device_destroy(f54->factory_data->fac_dev_ts->devt); + + kfree(f54->factory_data->trx_short); + kfree(f54->factory_data->abscap_data); + kfree(f54->factory_data->absdelta_data); + kfree(f54->factory_data->rawcap_data); + kfree(f54->factory_data->delta_data); + kfree(f54->factory_data); +} + +static int synaptics_rmi4_init_factory_mode(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + unsigned char rx; + unsigned char tx; + int retval = 0, ii; + struct factory_data *factory_data; + char fac_dir_name[20] = {0, }; + + if (!f54) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: F54 data is null\n", __func__); + return -ENOMEM; + } + + rx = f54->rx_assigned; + tx = f54->tx_assigned; + + factory_data = kzalloc(sizeof(*factory_data), GFP_KERNEL); + if (!factory_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for factory_data\n", + __func__); + retval = -ENOMEM; + goto exit_factory_data; + } + + factory_data->rawcap_data = kzalloc(2 * rx * tx, GFP_KERNEL); + if (!factory_data->rawcap_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for rawcap_data\n", + __func__); + retval = -ENOMEM; + goto exit_rawcap_data; + } + + factory_data->delta_data = kzalloc(2 * rx * tx, GFP_KERNEL); + if (!factory_data->delta_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for delta_data\n", + __func__); + retval = -ENOMEM; + goto exit_delta_data; + } + + factory_data->abscap_data = kzalloc(4 * rx * tx, GFP_KERNEL); + if (!factory_data->abscap_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for abscap_data\n", + __func__); + retval = -ENOMEM; + goto exit_abscap_data; + } + factory_data->absdelta_data = kzalloc(4 * rx * tx, GFP_KERNEL); + if (!factory_data->abscap_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for abscap_data\n", + __func__); + retval = -ENOMEM; + goto exit_absdelta_data; + } + + factory_data->trx_short = kzalloc(TREX_DATA_SIZE, GFP_KERNEL); + if (!factory_data->trx_short) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for trx_short\n", + __func__); + retval = -ENOMEM; + goto exit_trx_short; + } + + INIT_LIST_HEAD(&factory_data->cmd_list_head); + for (ii = 0; ii < ARRAY_SIZE(ft_cmds); ii++) + list_add_tail(&ft_cmds[ii].list, &factory_data->cmd_list_head); + + mutex_init(&factory_data->cmd_lock); + factory_data->cmd_is_running = false; + + if (rmi4_data->board->device_num > DEFAULT_DEVICE_NUM) + sprintf(fac_dir_name, "tsp%d", rmi4_data->board->device_num); + else + sprintf(fac_dir_name, "tsp"); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: fac_dir_name : %s\n", + __func__, fac_dir_name); + + factory_data->fac_dev_ts = sec_device_create(rmi4_data, fac_dir_name); + + retval = IS_ERR(factory_data->fac_dev_ts); + if (retval) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to create device for the sysfs\n", + __func__); + retval = IS_ERR(factory_data->fac_dev_ts); + goto exit_sec_device_create; + } + + retval = sysfs_create_group(&factory_data->fac_dev_ts->kobj, + &cmd_attr_group); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs attributes\n", + __func__); + goto exit_cmd_attr_group; + } + + retval = sysfs_create_link(&factory_data->fac_dev_ts->kobj, + &rmi4_data->input_dev->dev.kobj, "input"); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create link\n", __func__); + goto exit_cmd_attr_group; + } + + f54->factory_data = factory_data; + + return 0; + +exit_cmd_attr_group: + sysfs_remove_group(&factory_data->fac_dev_ts->kobj, &cmd_attr_group); +exit_sec_device_create: + sec_device_destroy(factory_data->fac_dev_ts->devt); + kfree(factory_data->trx_short); +exit_trx_short: + kfree(factory_data->absdelta_data); +exit_absdelta_data: + kfree(factory_data->abscap_data); +exit_abscap_data: + kfree(factory_data->delta_data); +exit_delta_data: + kfree(factory_data->rawcap_data); +exit_rawcap_data: + kfree(factory_data); + factory_data = NULL; +exit_factory_data: + + return retval; +} +#endif + +static int synaptics_rmi4_f54_init(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_f54_handle *f54 = NULL; + + f54 = kzalloc(sizeof(struct synaptics_rmi4_f54_handle), GFP_KERNEL); + if (!f54) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for f54\n", + __func__); + retval = -ENOMEM; + return retval; + } + + rmi4_data->f54 = f54; + f54->rmi4_data = rmi4_data; + f54->rx_assigned = rmi4_data->num_of_rx; + f54->tx_assigned = rmi4_data->num_of_tx; + + retval = synaptics_rmi4_f54_reinit(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to reinit f54.\n", + __func__); + goto err_reinit; + } + + mutex_init(&f54->status_mutex); + mutex_init(&f54->data_mutex); + mutex_init(&f54->control_mutex); + + retval = synaptics_rmi4_f54_set_sysfs(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs entries\n", + __func__); + goto err_set_sysfs; + } + + f54->status_workqueue = + create_singlethread_workqueue("f54_status_workqueue"); + INIT_DELAYED_WORK(&f54->status_work, + synaptics_rmi4_f54_status_work); + +#ifdef WATCHDOG_HRTIMER + /* Watchdog timer to catch unanswered get report commands */ + hrtimer_init(&f54->watchdog, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + f54->watchdog.function = get_report_timeout; + + /* Work function to do actual cleaning up */ + INIT_WORK(&f54->timeout_work, timeout_set_status); +#endif + + f54->status = STATUS_IDLE; + +#ifdef FACTORY_MODE + synaptics_rmi4_init_factory_mode(rmi4_data); +#endif + + return 0; + +err_set_sysfs: + remove_sysfs(f54); + +err_reinit: + free_control_mem(f54); + kfree(f54); + rmi4_data->f54 = NULL; + + return retval; +} + +static void synaptics_rmi4_f54_remove(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f54_handle *f54 = rmi4_data->f54; + + if (!f54) + goto exit; + +#ifdef WATCHDOG_HRTIMER + hrtimer_cancel(&f54->watchdog); +#endif + + cancel_delayed_work_sync(&f54->status_work); + flush_workqueue(f54->status_workqueue); + destroy_workqueue(f54->status_workqueue); + +#ifdef FACTORY_MODE + synaptics_rmi4_remove_factory_mode(rmi4_data); +#endif + remove_sysfs(f54); + free_control_mem(f54); + + if (f54->data_buffer_size) + kfree(f54->report_data); + + kfree(f54); + rmi4_data->f54 = NULL; + +exit: + return; +} + +int rmi4_f54_module_register(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + + retval = synaptics_rmi4_new_function(RMI_F54, + rmi4_data, + synaptics_rmi4_f54_init, + synaptics_rmi4_f54_reinit, + synaptics_rmi4_f54_remove, + synaptics_rmi4_f54_attn); + + return retval; +} diff --git a/drivers/input/touchscreen/synaptics_dsx2/rmi_fw_update.c b/drivers/input/touchscreen/synaptics_dsx2/rmi_fw_update.c new file mode 100644 index 000000000000..f705756931bb --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/rmi_fw_update.c @@ -0,0 +1,3647 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "synaptics_i2c_rmi.h" + +#define DO_STARTUP_FW_UPDATE +#define STARTUP_FW_UPDATE_DELAY_MS 1000 /* ms */ +#define FORCE_UPDATE false +#define DO_LOCKDOWN false + +#define MAX_IMAGE_NAME_LEN 256 +#define MAX_FIRMWARE_ID_LEN 10 + +#define F01_DEVICE_STATUS 0X0004 + +#define BOOTLOADER_ID_OFFSET 0 +#define BLOCK_NUMBER_OFFSET 0 + +#define V5_PROPERTIES_OFFSET 2 +#define V5_BLOCK_SIZE_OFFSET 3 +#define V5_BLOCK_COUNT_OFFSET 5 +#define V5_BLOCK_DATA_OFFSET 2 + +#define V6_PROPERTIES_OFFSET 1 +#define V6_BLOCK_SIZE_OFFSET 2 +#define V6_BLOCK_COUNT_OFFSET 3 +#define V6_BLOCK_DATA_OFFSET 1 +#define V6_FLASH_COMMAND_OFFSET 2 +#define V6_FLASH_STATUS_OFFSET 3 + +#define V7_FLASH_STATUS_OFFSET 0 +#define V7_PARTITION_ID_OFFSET 1 +#define V7_BLOCK_NUMBER_OFFSET 2 +#define V7_TRANSFER_LENGTH_OFFSET 3 +#define V7_COMMAND_OFFSET 4 +#define V7_PAYLOAD_OFFSET 5 + +#define V7_PARTITION_SUPPORT_BYTES 4 + +#define IMG_VERSION_OFFSET 0x07 +#define IMG_X10_TOP_CONTAINER_OFFSET 0x0C +#define IMG_X0_X6_FW_OFFSET 0x100 + +#define UI_CONFIG_AREA 0x00 +#define PERM_CONFIG_AREA 0x01 +#define BL_CONFIG_AREA 0x02 +#define DISP_CONFIG_AREA 0x03 + +#define SLEEP_MODE_NORMAL (0x00) +#define SLEEP_MODE_SENSOR_SLEEP (0x01) +#define SLEEP_MODE_RESERVED0 (0x02) +#define SLEEP_MODE_RESERVED1 (0x03) + +#define ENABLE_WAIT_MS (1 * 1000) +#define WRITE_WAIT_MS (3 * 1000) +#define ERASE_WAIT_MS (5 * 1000) + +#define MIN_SLEEP_TIME_US 50 +#define MAX_SLEEP_TIME_US 100 +#define STATUS_POLLING_PERIOD_US 3000 + +#define POLLING_MODE_DEFAULT 0 + +#define ATTRIBUTE_FOLDER_NAME "fwu" + +enum f34_version { + F34_V0 = 0, + F34_V1, + F34_V2, +}; + +static ssize_t fwu_sysfs_show_image(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t fwu_sysfs_store_image(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t fwu_sysfs_do_reflash_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t fwu_sysfs_write_config_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t fwu_sysfs_read_config_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t fwu_sysfs_config_area_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t fwu_sysfs_image_size_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static ssize_t fwu_sysfs_block_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_firmware_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_configuration_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_perm_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_bl_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_disp_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_guest_code_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); + +static ssize_t fwu_sysfs_write_guest_code_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static void fwu_img_parse_format(struct synaptics_rmi4_data *rmi4_data); +static int fwu_do_write_guest_code(struct synaptics_rmi4_data *rmi4_data); + + +static struct bin_attribute dev_attr_data = { + .attr = { + .name = "data", + .mode = (S_IRUGO | S_IWUSR | S_IWGRP), + }, + .size = 0, + .read = fwu_sysfs_show_image, + .write = fwu_sysfs_store_image, +}; + +RMI_KOBJ_ATTR(doreflash, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_do_reflash_store); +RMI_KOBJ_ATTR(writeconfig, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_write_config_store); +RMI_KOBJ_ATTR(readconfig, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_read_config_store); +RMI_KOBJ_ATTR(configarea, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_config_area_store); +RMI_KOBJ_ATTR(imagesize, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_image_size_store); +RMI_KOBJ_ATTR(blocksize, S_IRUGO, fwu_sysfs_block_size_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(fwblockcount, S_IRUGO, fwu_sysfs_firmware_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(configblockcount, S_IRUGO, fwu_sysfs_configuration_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(permconfigblockcount, S_IRUGO, fwu_sysfs_perm_config_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(blconfigblockcount, S_IRUGO, fwu_sysfs_bl_config_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(dispconfigblockcount, S_IRUGO, fwu_sysfs_disp_config_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(guestcodeblockcount, S_IRUGO, fwu_sysfs_guest_code_block_count_show, synaptics_rmi4_store_error); +RMI_KOBJ_ATTR(writeguestcode, S_IWUSR | S_IWGRP, synaptics_rmi4_show_error, fwu_sysfs_write_guest_code_store); + +static struct attribute *attrs[] = { + &kobj_attr_doreflash.attr, + &kobj_attr_writeconfig.attr, + &kobj_attr_readconfig.attr, + &kobj_attr_configarea.attr, + &kobj_attr_imagesize.attr, + &kobj_attr_blocksize.attr, + &kobj_attr_fwblockcount.attr, + &kobj_attr_configblockcount.attr, + &kobj_attr_permconfigblockcount.attr, + &kobj_attr_blconfigblockcount.attr, + &kobj_attr_dispconfigblockcount.attr, + &kobj_attr_guestcodeblockcount.attr, + &kobj_attr_writeguestcode.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static unsigned int extract_uint_le(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + + (unsigned int)ptr[1] * 0x100 + + (unsigned int)ptr[2] * 0x10000 + + (unsigned int)ptr[3] * 0x1000000; +} + +#ifdef FW_UPDATE_GO_NOGO +static unsigned int extract_uint_be(const unsigned char *ptr) +{ + return (unsigned int)ptr[3] + + (unsigned int)ptr[2] * 0x100 + + (unsigned int)ptr[1] * 0x10000 + + (unsigned int)ptr[0] * 0x1000000; +} +#endif + +static unsigned int le_to_uint(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + + (unsigned int)ptr[1] * 0x100 + + (unsigned int)ptr[2] * 0x10000 + + (unsigned int)ptr[3] * 0x1000000; +} + +static unsigned short extract_ushort_le(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + (unsigned int)ptr[1] * 0x100; +} + +static int fwu_read_f01_device_status(struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_f01_device_status *status) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f01_fd.data_base_addr, + status->data, + sizeof(status->data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read F01 device status\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_wait_for_idle(struct synaptics_rmi4_data *rmi4_data, int timeout_ms); + + +static int fwu_write_f34_command_single_transaction_v7(struct synaptics_rmi4_data *rmi4_data, unsigned char cmd) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + int retval; + unsigned char base; + struct f34_v7_data_1_5 data_1_5; + + base = fwu->f34_fd.data_base_addr; + + memset(data_1_5.data, 0x00, sizeof(data_1_5.data)); + + switch (cmd) { + case v7_CMD_ERASE_ALL: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE_AP; + break; + case v7_CMD_ERASE_UI_FIRMWARE: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_BL_CONFIG: + data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_UI_CONFIG: + data_1_5.partition_id = CORE_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_DISP_CONFIG: + data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_FLASH_CONFIG: + data_1_5.partition_id = FLASH_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_GUEST_CODE: + data_1_5.partition_id = GUEST_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ENABLE_FLASH_PROG: + data_1_5.partition_id = BOOTLOADER_PARTITION; + data_1_5.command = CMD_V7_ENTER_BL; + break; + }; + + data_1_5.payload_0 = fwu->bootloader_id[0]; + data_1_5.payload_1 = fwu->bootloader_id[1]; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.partition_id, + data_1_5.data, + sizeof(data_1_5.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write single transaction command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_command_v7(struct synaptics_rmi4_data *rmi4_data, unsigned char cmd) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + int retval; + unsigned char base; + unsigned char command; + + base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case v7_CMD_WRITE_FW: + case v7_CMD_WRITE_CONFIG: + case v7_CMD_WRITE_GUEST_CODE: + command = CMD_V7_WRITE; + break; + case v7_CMD_READ_CONFIG: + command = CMD_V7_READ; + break; + case v7_CMD_ERASE_ALL: + command = CMD_V7_ERASE_AP; + break; + case v7_CMD_ERASE_UI_FIRMWARE: + case v7_CMD_ERASE_BL_CONFIG: + case v7_CMD_ERASE_UI_CONFIG: + case v7_CMD_ERASE_DISP_CONFIG: + case v7_CMD_ERASE_FLASH_CONFIG: + case v7_CMD_ERASE_GUEST_CODE: + command = CMD_V7_ERASE; + break; + case v7_CMD_ENABLE_FLASH_PROG: + command = CMD_V7_ENTER_BL; + break; + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + fwu->command = command; + + switch (cmd) { + case v7_CMD_ERASE_ALL: + case v7_CMD_ERASE_UI_FIRMWARE: + case v7_CMD_ERASE_BL_CONFIG: + case v7_CMD_ERASE_UI_CONFIG: + case v7_CMD_ERASE_DISP_CONFIG: + case v7_CMD_ERASE_FLASH_CONFIG: + case v7_CMD_ERASE_GUEST_CODE: + case v7_CMD_ENABLE_FLASH_PROG: + retval = fwu_write_f34_command_single_transaction_v7(rmi4_data, cmd); + if (retval < 0) + return retval; + else + return 0; + default: + break; + }; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.flash_cmd, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write flash command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_v7_partition_id(struct synaptics_rmi4_data *rmi4_data, unsigned char cmd) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + int retval; + unsigned char base; + unsigned char partition; + + base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case v7_CMD_WRITE_FW: + partition = CORE_CODE_PARTITION; + break; + case v7_CMD_WRITE_CONFIG: + case v7_CMD_READ_CONFIG: + if (fwu->config_area == v7_UI_CONFIG_AREA) + partition = CORE_CONFIG_PARTITION; + else if (fwu->config_area == v7_DP_CONFIG_AREA) + partition = DISPLAY_CONFIG_PARTITION; + else if (fwu->config_area == v7_PM_CONFIG_AREA) + partition = GUEST_SERIALIZATION_PARTITION; + else if (fwu->config_area == v7_BL_CONFIG_AREA) + partition = GLOBAL_PARAMETERS_PARTITION; + else if (fwu->config_area == v7_FLASH_CONFIG_AREA) + partition = FLASH_CONFIG_PARTITION; + break; + case v7_CMD_WRITE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case v7_CMD_ERASE_ALL: + partition = CORE_CODE_PARTITION; + break; + case v7_CMD_ERASE_BL_CONFIG: + partition = GLOBAL_PARAMETERS_PARTITION; + break; + case v7_CMD_ERASE_UI_CONFIG: + partition = CORE_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_DISP_CONFIG: + partition = DISPLAY_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_FLASH_CONFIG: + partition = FLASH_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case v7_CMD_ENABLE_FLASH_PROG: + partition = BOOTLOADER_PARTITION; + break; + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.partition_id, + &partition, + sizeof(partition)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write partition ID\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_partition_id(struct synaptics_rmi4_data *rmi4_data, unsigned char cmd) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + int retval; + + if (fwu->bl_version == BL_V7) + retval = fwu_write_f34_v7_partition_id(rmi4_data, cmd); + else + retval = 0; + + return retval; +} + +static int fwu_read_f34_v7_partition_table(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short block_number = 0; + + base = fwu->f34_fd.data_base_addr; + + fwu->config_area = v7_FLASH_CONFIG_AREA; + + retval = fwu_write_f34_partition_id(rmi4_data, v7_CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write block number\n", + __func__); + return retval; + } + + length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT); + length[1] = (unsigned char)(fwu->flash_config_length >> 8); + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write transfer length\n", + __func__); + return retval; + } + + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_READ_CONFIG); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write command\n", + __func__); + return retval; + } + + fwu->polling_mode = true; + retval = fwu_wait_for_idle(rmi4_data, WRITE_WAIT_MS); + fwu->polling_mode = false; + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wait for idle status\n", + __func__); + return retval; + } + + retval = rmi4_data->i2c_read(rmi4_data, + base + fwu->off.payload, + fwu->read_config_buf, + fwu->partition_table_bytes); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block data\n", + __func__); + return retval; + } + + return 0; +} + +static void fwu_parse_partition_table(struct synaptics_rmi4_data *rmi4_data, + const unsigned char *partition_table, + struct block_count *blkcount, struct physical_address *phyaddr) +{ + unsigned char ii; + unsigned char index; + unsigned char offset; + unsigned short partition_length; + unsigned short physical_address; + struct partition_table *ptable; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + for (ii = 0; ii < fwu->partitions; ii++) { + index = ii * 8 + 2; + ptable = (struct partition_table *)&partition_table[index]; + partition_length = ptable->partition_length_15_8 << 8 | + ptable->partition_length_7_0; + physical_address = ptable->start_physical_address_15_8 << 8 | + ptable->start_physical_address_7_0; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Partition entry %d:\n", + __func__, ii); + for (offset = 0; offset < 8; offset++) { + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, + "%s: 0x%02x\n", + __func__, + partition_table[index + offset]); + } + switch (ptable->partition_id) { + case CORE_CODE_PARTITION: + blkcount->ui_firmware = partition_length; + phyaddr->ui_firmware = physical_address; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Core code block count: %d\n", + __func__, blkcount->ui_firmware); + break; + case CORE_CONFIG_PARTITION: + blkcount->ui_config = partition_length; + phyaddr->ui_config = physical_address; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Core config block count: %d\n", + __func__, blkcount->ui_config); + break; + case DISPLAY_CONFIG_PARTITION: + blkcount->dp_config = partition_length; + phyaddr->dp_config = physical_address; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Display config block count: %d\n", + __func__, blkcount->dp_config); + break; + case FLASH_CONFIG_PARTITION: + blkcount->fl_config = partition_length; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Flash config block count: %d\n", + __func__, blkcount->fl_config); + break; + case GUEST_CODE_PARTITION: + blkcount->guest_code = partition_length; + phyaddr->guest_code = physical_address; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Guest code block count: %d\n", + __func__, blkcount->guest_code); + break; + case GUEST_SERIALIZATION_PARTITION: + blkcount->pm_config = partition_length; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Guest serialization block count: %d\n", + __func__, blkcount->pm_config); + break; + case GLOBAL_PARAMETERS_PARTITION: + blkcount->bl_config = partition_length; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Global parameters block count: %d\n", + __func__, blkcount->bl_config); + break; + case DEVICE_CONFIG_PARTITION: + blkcount->lockdown = partition_length; + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Device config block count: %d\n", + __func__, blkcount->lockdown); + break; + }; + } + + return; +} + +static int fwu_read_f34_queries_bl_version(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + int retval; + unsigned char base; + unsigned char offset; + struct f34_v7_query_0 query_0; + struct f34_v7_query_1_7 query_1_7; + + base = rmi4_data->fwu->f34_fd.query_base_addr; + + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: base[%x]\n", + __func__, base); + + retval = rmi4_data->i2c_read(rmi4_data, + base, + query_0.data, + sizeof(query_0.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read query 0\n", + __func__); + return retval; + } + + offset = query_0.subpacket_1_size + 1; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: offset[%x]\n", + __func__, offset); + + retval = rmi4_data->i2c_read(rmi4_data, + base + offset, + query_1_7.data, + sizeof(query_1_7.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read queries 1 to 7\n", + __func__); + return retval; + } + + fwu->bootloader_id[0] = query_1_7.bl_minor_revision; + fwu->bootloader_id[1] = query_1_7.bl_major_revision; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Bootloader ver : [%d,%d]\n", + __func__, fwu->bootloader_id[0],fwu->bootloader_id[1]); + return 0; +} + +static int fwu_read_f34_queries_v7(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + int retval; + unsigned char ii; + unsigned char base; + unsigned char index; + unsigned char offset; + unsigned char *ptable; + struct f34_v7_query_0 query_0; + struct f34_v7_query_1_7 query_1_7; + + base = rmi4_data->fwu->f34_fd.query_base_addr; + + retval = rmi4_data->i2c_read(rmi4_data, + base, + query_0.data, + sizeof(query_0.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read query 0\n", + __func__); + return retval; + } + + offset = query_0.subpacket_1_size + 1; + + retval = rmi4_data->i2c_read(rmi4_data, + base + offset, + query_1_7.data, + sizeof(query_1_7.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read queries 1 to 7\n", + __func__); + return retval; + } + + fwu->bootloader_id_ic[0] = fwu->bootloader_id[0] = query_1_7.bl_minor_revision; + fwu->bootloader_id_ic[1] = fwu->bootloader_id[1] = query_1_7.bl_major_revision; + + fwu->block_size = query_1_7.block_size_15_8 << 8 | + query_1_7.block_size_7_0; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: fwu->block_size = %d, [%d,%d]\n", + __func__, fwu->block_size, fwu->bootloader_id[0],fwu->bootloader_id[1]); + + fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 | + query_1_7.flash_config_length_7_0; + + fwu->payload_length = query_1_7.payload_length_15_8 << 8 | + query_1_7.payload_length_7_0; + + fwu->off.flash_status = V7_FLASH_STATUS_OFFSET; + fwu->off.partition_id = V7_PARTITION_ID_OFFSET; + fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET; + fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; + fwu->off.flash_cmd = V7_COMMAND_OFFSET; + fwu->off.payload = V7_PAYLOAD_OFFSET; + + fwu->flash_properties.has_disp_config = query_1_7.has_display_config; + fwu->flash_properties.has_perm_config = query_1_7.has_guest_serialization; + fwu->flash_properties.has_bl_config = query_1_7.has_global_parameters; + + fwu->has_guest_code = query_1_7.has_guest_code; + + index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES; + + fwu->partitions = 0; + for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) { + for (ii = 0; ii < 8; ii++) { + if (query_1_7.data[index + offset] & (1 << ii)) + fwu->partitions++; + } + + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, + "%s: Supported partitions: 0x%02x\n", + __func__, query_1_7.data[index + offset]); + } + + fwu->partition_table_bytes = fwu->partitions * 8 + 2; + + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(fwu->partition_table_bytes, GFP_KERNEL); + if (!fwu->read_config_buf) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for fwu->read_config_buf\n", + __func__); + fwu->read_config_buf_size = 0; + return -ENOMEM; + } + fwu->read_config_buf_size = fwu->partition_table_bytes; + ptable = fwu->read_config_buf; + + retval = fwu_read_f34_v7_partition_table(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read partition table\n", + __func__); + return retval; + } + + fwu_parse_partition_table(rmi4_data, ptable, &fwu->blkcount, &fwu->phyaddr); + + return 0; +} + + +static int fwu_read_f34_queries(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char count; + unsigned char buf[10]; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if ( fwu->bl_version == BL_V7) { + dev_info(&rmi4_data->i2c_client->dev, + "%s: bl_version == BL_V7\n",__func__); + retval = fwu_read_f34_queries_v7(rmi4_data); + } else { + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET, + fwu->bootloader_id, + sizeof(fwu->bootloader_id)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read bootloader ID\n", + __func__); + return retval; + } + + if (fwu->bootloader_id[1] == '5') { + fwu->bl_version = V5; + } else if (fwu->bootloader_id[1] == '6') { + fwu->bl_version = V6; + } else if (fwu->bootloader_id[1] == 7) { + fwu->bl_version = BL_V7; + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Unrecognized bootloader version\n", + __func__); + return -EINVAL; + } + } + + tsp_debug_info(false, &rmi4_data->i2c_client->dev, + "%s: F34 Query : ID: %s\n", __func__, fwu->bootloader_id); + + if (fwu->bl_version == V5) { + fwu->properties_off = V5_PROPERTIES_OFFSET; + fwu->blk_size_off = V5_BLOCK_SIZE_OFFSET; + fwu->blk_count_off = V5_BLOCK_COUNT_OFFSET; + fwu->blk_data_off = V5_BLOCK_DATA_OFFSET; + } else if (fwu->bl_version == V6) { + fwu->properties_off = V6_PROPERTIES_OFFSET; + fwu->blk_size_off = V6_BLOCK_SIZE_OFFSET; + fwu->blk_count_off = V6_BLOCK_COUNT_OFFSET; + fwu->blk_data_off = V6_BLOCK_DATA_OFFSET; + fwu->properties2_off = fwu->blk_count_off + 1; + fwu->guest_blk_count_off = fwu->properties2_off + 1; + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + fwu->properties_off, + fwu->flash_properties.data, + sizeof(fwu->flash_properties.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read flash properties\n", + __func__); + return retval; + } + + count = 4; + + if (fwu->flash_properties.has_perm_config) { + fwu->has_perm_config = 1; + count += 2; + } + + if (fwu->flash_properties.has_bl_config) { + fwu->has_bl_config = 1; + count += 2; + } + + if (fwu->flash_properties.has_disp_config) { + fwu->has_disp_config = 1; + count += 2; + } + + if (fwu->flash_properties.has_flash_query4) { + struct synaptics_rmi4_f34_query_04 query4; + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + fwu->properties2_off, + query4.data, + sizeof(query4.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block size info\n", + __func__); + return retval; + } + + if (query4.has_guest_code) { + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + fwu->guest_blk_count_off, + buf, + 2); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block size info\n", + __func__); + return retval; + } + batohs(&fwu->guest_code_block_count, buf); + fwu->has_guest_code = 1; + } else { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: query data do not supply quest image.\n", + __func__); + + } + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + fwu->blk_size_off, + buf, + 2); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block size info\n", + __func__); + return retval; + } + + batohs(&fwu->block_size, &(buf[0])); + + if (fwu->bl_version == V5) { + fwu->flash_cmd_off = fwu->blk_data_off + fwu->block_size; + fwu->flash_status_off = fwu->flash_cmd_off; + } else if (fwu->bl_version == V6) { + fwu->flash_cmd_off = V6_FLASH_COMMAND_OFFSET; + fwu->flash_status_off = V6_FLASH_STATUS_OFFSET; + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.query_base_addr + fwu->blk_count_off, + buf, + count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block count info\n", + __func__); + return retval; + } + + batohs(&fwu->fw_block_count, &(buf[0])); + batohs(&fwu->config_block_count, &(buf[2])); + + count = 4; + + if (fwu->has_perm_config) { + batohs(&fwu->perm_config_block_count, &(buf[count])); + count += 2; + } + + if (fwu->has_bl_config) { + batohs(&fwu->bl_config_block_count, &(buf[count])); + count += 2; + } + + if (fwu->has_disp_config) + batohs(&fwu->disp_config_block_count, &(buf[count])); + + return 0; +} + +static int fwu_read_flash_status_v7(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char status; + unsigned char command; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->off.flash_status, + &status, + sizeof(status)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read flash status\n", + __func__); + return retval; + } + + fwu->in_bl_mode = status >> 7; + + fwu->flash_status = status & MASK_5BIT; + + if (fwu->flash_status != 0x00) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Flash status = %d, command = 0x%02x\n", + __func__, fwu->flash_status, fwu->command); + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->off.flash_cmd, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read flash command\n", + __func__); + return retval; + } + + fwu->command = command; + + return 0; +} + + +static int fwu_read_f34_flash_status(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char status; + unsigned char command; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->flash_status_off, + &status, + sizeof(status)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read flash status\n", + __func__); + return retval; + } + + fwu->program_enabled = status >> 7; + + if (fwu->bl_version == V5) + fwu->flash_status = (status >> 4) & MASK_3BIT; + else if (fwu->bl_version == V6) + fwu->flash_status = status & MASK_3BIT; + else if (fwu->bl_version == BL_V7) + fwu->flash_status = status & MASK_5BIT; + + if (fwu->flash_status != 0x00) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Flash status = %d, command = 0x%02x\n", + __func__, fwu->flash_status, fwu->command); + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->flash_cmd_off, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read flash command\n", + __func__); + return retval; + } + +// fwu->command = command & MASK_4BIT; +// if (fwu->bl_version == BL_V7) + fwu->command = command; + + return 0; +} + +static int fwu_write_f34_command(struct synaptics_rmi4_data *rmi4_data, unsigned char cmd) +{ + int retval; + unsigned char command = cmd & MASK_4BIT; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + fwu->command = cmd; + + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->flash_cmd_off, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write command 0x%02x\n", + __func__, command); + return retval; + } + + return 0; +} + +static int fwu_wait_for_idle(struct synaptics_rmi4_data *rmi4_data, int timeout_ms) +{ + int count = 0; + int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, + "%s: fwu->polling_mode = %d, timeout_count = %d\n", + __func__, fwu->polling_mode, timeout_count ); +#if 1 + do { + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); + + count++; + if (fwu->polling_mode || (count == timeout_count)) + fwu_read_flash_status_v7(rmi4_data); + + if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00)) + return 0; + } while (count < timeout_count); + +#else + do { + if (fwu->polling_mode || count == timeout_count) +// fwu_read_f34_flash_status(rmi4_data); + fwu_read_flash_status_v7(rmi4_data); + if ((fwu->command == 0x00) && (fwu->flash_status == 0x00)) { + if (count == timeout_count) + fwu->polling_mode = true; + return 0; + } + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); + count++; + + } while (count <= timeout_count); +#endif + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Timed out waiting for idle status\n", + __func__); + + return -ETIMEDOUT; +} + +#ifdef FW_UPDATE_GO_NOGO +static enum flash_area fwu_go_nogo(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + enum flash_area flash_area = NONE; + unsigned char index = 0; + unsigned char config_id[4]; + unsigned int device_config_id; + unsigned int image_config_id; + unsigned int device_fw_id; + unsigned long image_fw_id; + char *strptr; + char *firmware_id; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (fwu->force_update) { + flash_area = UI_FIRMWARE; + goto exit; + } + + /* Update both UI and config if device is in bootloader mode */ + if (fwu->in_flash_prog_mode) { + flash_area = UI_FIRMWARE; + goto exit; + } + + /* Get device firmware ID */ + device_fw_id = rmi4_data->rmi4_mod_info.build_id[0] + + rmi4_data->rmi4_mod_info.build_id[1] * 0x100 + + rmi4_data->rmi4_mod_info.build_id[2] * 0x10000; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Device firmware ID = %d\n", + __func__, device_fw_id); + + /* Get image firmware ID */ + if (fwu->img.firmwareId != NULL) { + image_fw_id = extract_uint_le(fwu->img.firmwareId); + } else { + strptr = strstr(fwu->img.image_name, "PR"); + if (!strptr) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: No valid PR number (PRxxxxxxx) " + "found in image file name (%s)\n", + __func__, fwu->img.image_name); + flash_area = NONE; + goto exit; + } + + strptr += 2; + firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL); + while (strptr[index] >= '0' && strptr[index] <= '9') { + firmware_id[index] = strptr[index]; + index++; + } + + retval = kstrtoul(firmware_id, 10, &image_fw_id); + kfree(firmware_id); + if (retval) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to obtain image firmware ID\n", + __func__); + flash_area = NONE; + goto exit; + } + } + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Image firmware ID = %d\n", + __func__, (unsigned int)image_fw_id); + + if (image_fw_id > device_fw_id) { + flash_area = UI_FIRMWARE; + goto exit; + } else if (image_fw_id < device_fw_id) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Image firmware ID older than device firmware ID\n", + __func__); + flash_area = NONE; + goto exit; + } + + /* Get device config ID */ + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.ctrl_base_addr, + config_id, + sizeof(config_id)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read device config ID\n", + __func__); + flash_area = NONE; + goto exit; + } + device_config_id = extract_uint_be(config_id); + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Device config ID = 0x%02x 0x%02x 0x%02x 0x%02x\n", + __func__, + config_id[0], + config_id[1], + config_id[2], + config_id[3]); + + /* Get image config ID */ + image_config_id = extract_uint_be(fwu->img.configId); + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Image config ID = 0x%02x 0x%02x 0x%02x 0x%02x\n", + __func__, + fwu->img.configId[0], + fwu->img.configId[1], + fwu->img.configId[2], + fwu->img.configId[3]); + + if (image_config_id > device_config_id) { + flash_area = CONFIG_AREA; + goto exit; + } + +exit: + if (flash_area == NONE) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: No need to do reflash\n", + __func__); + } else { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Updating %s\n", + __func__, + flash_area == UI_FIRMWARE ? + "UI firmware" : + "config only"); + } + return flash_area; +} +#endif + +static int fwu_scan_pdt(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char ii; + unsigned char intr_count = 0; + unsigned char intr_off; + unsigned char intr_src; + unsigned short addr; + bool f01found = false; + bool f34found = false; + struct synaptics_rmi4_fn_desc rmi_fd; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { + retval = rmi4_data->i2c_read(rmi4_data, + addr, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval < 0) + return retval; + + if (rmi_fd.fn_number) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Found F%02x\n", + __func__, rmi_fd.fn_number); + switch (rmi_fd.fn_number) { + case SYNAPTICS_RMI4_F01: + f01found = true; + fwu->f01_fd.query_base_addr = + rmi_fd.query_base_addr; + fwu->f01_fd.ctrl_base_addr = + rmi_fd.ctrl_base_addr; + fwu->f01_fd.data_base_addr = + rmi_fd.data_base_addr; + fwu->f01_fd.cmd_base_addr = + rmi_fd.cmd_base_addr; + break; + case SYNAPTICS_RMI4_F34: + f34found = true; + fwu->f34_fd.query_base_addr = + rmi_fd.query_base_addr; + fwu->f34_fd.ctrl_base_addr = + rmi_fd.ctrl_base_addr; + fwu->f34_fd.data_base_addr = + rmi_fd.data_base_addr; + + switch (rmi_fd.fn_version) { + case F34_V0: + fwu->bl_version = BL_V5; + break; + case F34_V1: + fwu->bl_version = BL_V6; + break; + case F34_V2: + fwu->bl_version = BL_V7; + break; + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Unrecognized F34 version\n", + __func__); + return -EINVAL; + } + + fwu->intr_mask = 0; + intr_src = rmi_fd.intr_src_count; + intr_off = intr_count % 8; + for (ii = intr_off; ii < ((intr_src & MASK_3BIT) + intr_off); ii++) + fwu->intr_mask |= 1 << ii; + break; + } + } else { + break; + } + + intr_count += (rmi_fd.intr_src_count & MASK_3BIT); + } + + if (!f01found || !f34found) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to find both F01 and F34\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_write_blocks(struct synaptics_rmi4_data *rmi4_data, unsigned char *block_ptr, unsigned int block_size, + enum flash_command command) +{ + int retval; + unsigned char block_offset[] = {0, 0}; + unsigned short block_num; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + unsigned short block_cnt = block_size / fwu->block_size; + + if (block_ptr == NULL) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Cannot find block data (%x)\n", + __func__, command); + return -EINVAL; + } + + if (command == CMD_WRITE_CONFIG_BLOCK) + block_offset[1] |= (fwu->config_area << 5); + + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET, + block_offset, + sizeof(block_offset)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write to block number registers\n", + __func__); + return retval; + } + + for (block_num = 0; block_num < block_cnt; block_num++) { + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->blk_data_off, + block_ptr, + fwu->block_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write block data (block %d)\n", + __func__, block_num); + return retval; + } + + retval = fwu_write_f34_command(rmi4_data, command); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write command for block %d\n", + __func__, block_num); + return retval; + } + + retval = fwu_wait_for_idle(rmi4_data, WRITE_WAIT_MS); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wait for idle status (block %d)\n", + __func__, block_num); + return retval; + } + + block_ptr += fwu->block_size; + } + + return 0; +} + +static int fwu_write_config_block(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: size : %d, cmd : %d\n", __func__, fwu->img.uiConfig.size, CMD_WRITE_CONFIG_BLOCK); + + return fwu_write_blocks(rmi4_data, fwu->img.uiConfig.data, + fwu->img.uiConfig.size, CMD_WRITE_CONFIG_BLOCK); +} + +static int fwu_write_guest_code_block(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return fwu_write_blocks(rmi4_data, fwu->img.guestCode.data, + fwu->img.guestCode.size, CMD_WRITE_GUEST_CODE); +} + +static int fwu_write_bootloader_id(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->blk_data_off, + fwu->bootloader_id, + sizeof(fwu->bootloader_id)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write bootloader ID\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_enter_flash_prog(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_f01_device_status f01_device_status; + struct synaptics_rmi4_f01_device_control f01_device_control; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + unsigned char int_enable = 0x00; + + retval = fwu_read_f34_flash_status(rmi4_data); + if (retval < 0) + return retval; + + if (fwu->program_enabled) + return 0; + + /* To block interrupt from finger or hovering during enter flash program mode + * 1. F01_RMI_CTRL1(Interrupt Enable 0) register is cleared on this position. + * 2. After enter flash program mode, interrupt occured only by Flash bit(0x01) + * 3. After finish all flashing and reset, Interrupt enable register will be set as default value + */ + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f01_fd.ctrl_base_addr + 1, + &int_enable, sizeof(int_enable)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write interrupt enable register\n", __func__); + return retval; + } + msleep(20); + + retval = fwu_write_bootloader_id(rmi4_data); + if (retval < 0) + return retval; + + retval = fwu_write_f34_command(rmi4_data, CMD_ENABLE_FLASH_PROG); + if (retval < 0) + return retval; + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) + return retval; + + if (!fwu->program_enabled) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Program enabled bit not set\n", + __func__); + return -EINVAL; + } + + retval = fwu_scan_pdt(rmi4_data); + if (retval < 0) + return retval; + + retval = fwu_read_f01_device_status(rmi4_data, &f01_device_status); + if (retval < 0) + return retval; + + if (!f01_device_status.flash_prog) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Not in flash prog mode\n", + __func__); + return -EINVAL; + } + + retval = fwu_read_f34_queries(rmi4_data); + if (retval < 0) + return retval; + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f01_fd.ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read F01 device control\n", + __func__); + return retval; + } + + f01_device_control.nosleep = true; + f01_device_control.sleep_mode = SLEEP_MODE_NORMAL; + + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f01_fd.ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write F01 device control\n", + __func__); + return retval; + } + + return retval; +} + +static int fwu_check_ui_firmware_size(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + block_count = fwu->v7_img.ui_firmware.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_firmware) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: UI firmware size mismatch, block_count=%d,fwu->blkcount.ui_firmware=%d\n", + __func__, block_count, fwu->blkcount.ui_firmware); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_ui_configuration_size(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + block_count = fwu->v7_img.ui_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_config) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: UI configuration size mismatch\n", + __func__); + return -EINVAL; + } + return 0; +} +static int fwu_check_dp_configuration_size(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + + block_count = fwu->v7_img.dp_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.dp_config) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Display configuration size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} +static int fwu_check_guest_code_size(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + + block_count = fwu->v7_img.guest_code.size / fwu->block_size; + if (block_count != fwu->blkcount.guest_code) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Guest code size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} +static int fwu_check_bl_configuration_size(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + + block_count = fwu->v7_img.bl_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.bl_config) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Bootloader configuration size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} +static int fwu_erase_configuration(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + + switch (fwu->config_area) { + case v7_UI_CONFIG_AREA: + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ERASE_UI_CONFIG); + if (retval < 0) + return retval; + break; + case v7_DP_CONFIG_AREA: + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ERASE_DISP_CONFIG); + if (retval < 0) + return retval; + break; + case v7_BL_CONFIG_AREA: + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ERASE_BL_CONFIG); + if (retval < 0) + return retval; + break; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + return retval; +} +static int fwu_erase_guest_code(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + + retval = fwu_write_f34_command_v7(rmi4_data, CMD_ERASE_GUEST_CODE); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + return 0; +} + +static int fwu_erase_all(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ERASE_UI_FIRMWARE); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + fwu->config_area = v7_UI_CONFIG_AREA; + retval = fwu_erase_configuration(rmi4_data); + if (retval < 0) + return retval; + + if (fwu->flash_properties.has_disp_config) { + fwu->config_area = v7_DP_CONFIG_AREA; + retval = fwu_erase_configuration(rmi4_data); + if (retval < 0) + return retval; + } + + if (fwu->new_partition_table && fwu->has_guest_code) { + retval = fwu_erase_guest_code(rmi4_data); + if (retval < 0) + return retval; + } + + return 0; +} + +static int fwu_read_f34_v7_blocks(struct synaptics_rmi4_data *rmi4_data, + unsigned short block_cnt, + unsigned char command) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short transfer; + unsigned short max_transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + unsigned short index = 0; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + + base = fwu->f34_fd.data_base_addr; + + retval = fwu_write_f34_partition_id(rmi4_data, command); + if (retval < 0) + return retval; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write block number\n", + __func__); + return retval; + } + + if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) + max_transfer = PAGE_SIZE / fwu->block_size; + else + max_transfer = fwu->payload_length; + + do { + if (remaining / max_transfer) + transfer = max_transfer; + else + transfer = remaining; + + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write transfer length (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command_v7(rmi4_data, command); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write command (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wait for idle status (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = rmi4_data->i2c_read(rmi4_data, + base + fwu->off.payload, + &fwu->read_config_buf[index], + transfer * fwu->block_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block data (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + index += (transfer * fwu->block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int fwu_write_f34_v7_blocks(struct synaptics_rmi4_data *rmi4_data, + unsigned char *block_ptr, + unsigned short block_cnt, unsigned char command) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short transfer; + unsigned short max_transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + base = fwu->f34_fd.data_base_addr; + + retval = fwu_write_f34_partition_id(rmi4_data, command); + if (retval < 0) + return retval; + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write block number\n", + __func__); + return retval; + } + + if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) + max_transfer = PAGE_SIZE / fwu->block_size; + else + max_transfer = fwu->payload_length; + + do { + if (remaining / max_transfer) + transfer = max_transfer; + else + transfer = remaining; + + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write transfer length (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command_v7(rmi4_data, command); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write command (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = rmi4_data->i2c_write(rmi4_data, + base + fwu->off.payload, + block_ptr, + transfer * fwu->block_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write block data (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wait for idle status (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + block_ptr += (transfer * fwu->block_size); + remaining -= transfer; + } while (remaining); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Write END !!!!\n", __func__); + + return 0; +} + +static int fwu_write_f34_blocks(struct synaptics_rmi4_data *rmi4_data, + unsigned char *block_ptr, + unsigned short block_cnt, unsigned char cmd) +{ + int retval; + + retval = fwu_write_f34_v7_blocks(rmi4_data, block_ptr, block_cnt, cmd); + + return retval; +} + +static int fwu_write_configuration(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return fwu_write_f34_blocks(rmi4_data, (unsigned char *)fwu->config_data, + fwu->config_block_count, v7_CMD_WRITE_CONFIG); +} + +static int fwu_write_ui_configuration(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + fwu->config_area = v7_UI_CONFIG_AREA; + fwu->config_data = fwu->v7_img.ui_config.data; + fwu->config_size = fwu->v7_img.ui_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + return fwu_write_configuration(rmi4_data); +} + +static int fwu_write_dp_configuration(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + fwu->config_area = v7_DP_CONFIG_AREA; + fwu->config_data = fwu->v7_img.dp_config.data; + fwu->config_size = fwu->v7_img.dp_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + return fwu_write_configuration(rmi4_data); +} +static int fwu_write_guest_code(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + int retval; + unsigned short guest_code_block_count; + + guest_code_block_count = fwu->v7_img.guest_code.size / fwu->block_size; + + retval = fwu_write_f34_blocks(rmi4_data, (unsigned char *)fwu->v7_img.guest_code.data, + guest_code_block_count, CMD_WRITE_GUEST_CODE); + if (retval < 0) + return retval; + + return 0; +} +static int fwu_write_flash_configuration(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + fwu->config_area = v7_FLASH_CONFIG_AREA; + fwu->config_data = fwu->v7_img.fl_config.data; + fwu->config_size = fwu->v7_img.fl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + if (fwu->config_block_count != fwu->blkcount.fl_config) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Flash configuration size mismatch\n", + __func__); + return -EINVAL; + } + + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ERASE_FLASH_CONFIG); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Erase flash configuration command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS);//fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + retval = fwu_write_configuration(rmi4_data); + if (retval < 0) + return retval; + + rmi4_data->reset_device(rmi4_data); + + return 0; +} + +static int fwu_write_partition_table(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + block_count = fwu->blkcount.bl_config; + fwu->config_area = v7_BL_CONFIG_AREA; + fwu->config_size = fwu->block_size * block_count; + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL); + if (!fwu->read_config_buf) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for fwu->read_config_buf\n", + __func__); + fwu->read_config_buf_size = 0; + return -ENOMEM; + } + fwu->read_config_buf_size = fwu->config_size; + + retval = fwu_read_f34_v7_blocks(rmi4_data, block_count, v7_CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = fwu_erase_configuration(rmi4_data); + if (retval < 0) + return retval; + + retval = fwu_write_flash_configuration(rmi4_data); + if (retval < 0) + return retval; + + fwu->config_area = v7_BL_CONFIG_AREA; + fwu->config_data = fwu->read_config_buf; + fwu->config_size = fwu->v7_img.bl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + retval = fwu_write_configuration(rmi4_data); + if (retval < 0) + return retval; + + return 0; +} +static int fwu_write_firmware(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + unsigned short firmware_block_count; + + firmware_block_count = fwu->v7_img.ui_firmware.size / fwu->block_size; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Write Run!!!\n", + __func__); + + return fwu_write_f34_blocks(rmi4_data, (unsigned char *)fwu->v7_img.ui_firmware.data, + firmware_block_count, v7_CMD_WRITE_FW); +} + +static int fwu_do_reflash_v7(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu->new_partition_table) { + retval = fwu_check_ui_firmware_size(rmi4_data); + if (retval < 0) + return retval; + + retval = fwu_check_ui_configuration_size(rmi4_data); + if (retval < 0) + return retval; + + if (fwu->flash_properties.has_disp_config && + fwu->v7_img.contains_disp_config) { + retval = fwu_check_dp_configuration_size(rmi4_data); + if (retval < 0) + return retval; + } + + if (fwu->has_guest_code && fwu->v7_img.contains_guest_code) { + retval = fwu_check_guest_code_size(rmi4_data); + if (retval < 0) + return retval; + } + } else { + retval = fwu_check_bl_configuration_size(rmi4_data); + if (retval < 0) + return retval; + } + + retval = fwu_erase_all(rmi4_data); + if (retval < 0) + return retval; + + if (fwu->new_partition_table) { + retval = fwu_write_partition_table(rmi4_data); + if (retval < 0) + return retval; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Partition table programmed\n", __func__); + } + + retval = fwu_write_firmware(rmi4_data); + if (retval < 0) + return retval; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Firmware programmed\n", __func__); + + fwu->config_area = v7_UI_CONFIG_AREA; + retval = fwu_write_ui_configuration(rmi4_data); + if (retval < 0) + return retval; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Configuration programmed\n", __func__); + + if (fwu->flash_properties.has_disp_config && + fwu->v7_img.contains_disp_config) { + retval = fwu_write_dp_configuration(rmi4_data); + if (retval < 0) + return retval; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Display configuration programmed\n", __func__); + } + + if (fwu->new_partition_table) { + if (fwu->has_guest_code && fwu->v7_img.contains_guest_code) { + retval = fwu_write_guest_code(rmi4_data); + if (retval < 0) + return retval; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Guest code programmed\n", __func__); + } + } + + return retval; +} + +static int fwu_do_write_config(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = fwu_enter_flash_prog(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Entered flash prog mode\n", + __func__); + + if (fwu->config_area == PERM_CONFIG_AREA) { + fwu->config_block_count = fwu->perm_config_block_count; + goto write_config; + } + + retval = fwu_write_bootloader_id(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Bootloader ID written, AREA : %d\n", + __func__, fwu->config_area); + + switch (fwu->config_area) { + case UI_CONFIG_AREA: + retval = fwu_write_f34_command(rmi4_data, CMD_ERASE_CONFIG); + break; + case BL_CONFIG_AREA: + retval = fwu_write_f34_command(rmi4_data, CMD_ERASE_BL_CONFIG); + fwu->config_block_count = fwu->bl_config_block_count; + break; + case DISP_CONFIG_AREA: + retval = fwu_write_f34_command(rmi4_data, CMD_ERASE_DISP_CONFIG); + fwu->config_block_count = fwu->disp_config_block_count; + break; + } + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ERASE_WAIT_MS); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + +write_config: + retval = fwu_write_config_block(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Config written\n", + __func__); + + return retval; +} + +static void fwu_parse_image_header_10_bl_container(struct synaptics_rmi4_data *rmi4_data, unsigned char *image) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int container_id; + unsigned int length; + unsigned char *content; + struct container_descriptor *descriptor; + + num_of_containers = (fwu->v7_img.bootloader.size - 4) / 4; + + for (ii = 1; ii <= num_of_containers; ii++) { + addr = le_to_uint(fwu->v7_img.bootloader.data + (ii * 4)); + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case BL_CONFIG_CONTAINER: + case GLOBAL_PARAMETERS_CONTAINER: + fwu->v7_img.bl_config.data = content; + fwu->v7_img.bl_config.size = length; + break; + case BL_LOCKDOWN_INFO_CONTAINER: + case DEVICE_CONFIG_CONTAINER: + fwu->v7_img.lockdown.data = content; + fwu->v7_img.lockdown.size = length; + break; + default: + break; + }; + } + + return; +} + +void fwu_parse_image_header_10_simple(struct synaptics_rmi4_data *rmi4_data, unsigned char *image) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int offset; + unsigned int container_id; + unsigned int length; + unsigned char *content; + struct container_descriptor *descriptor; + struct image_header_10 *header; + + header = (struct image_header_10 *)image; + + /* address of top level container */ + offset = le_to_uint(header->top_level_container_start_addr); + descriptor = (struct container_descriptor *)(image + offset); + + /* address of top level container content */ + offset = le_to_uint(descriptor->content_address); + num_of_containers = le_to_uint(descriptor->content_length) / 4; + + for (ii = 0; ii < num_of_containers; ii++) { + addr = le_to_uint(image + offset); + offset += 4; + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + + if(container_id == UI_CONFIG_CONTAINER || container_id == CORE_CONFIG_CONTAINER){ + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: container_id=%d, length=%d data=[0x%02x/0x%02x/0x%02x/0x%02x]\n", + __func__, container_id, length, + content[0], content[1], content[2], content[3]); + + rmi4_data->ic_revision_of_bin = (int)content[2]; + rmi4_data->fw_version_of_bin = (int)content[3]; + } + if(container_id == GENERAL_INFORMATION_CONTAINER){ + snprintf(rmi4_data->product_id_string_of_bin, SYNAPTICS_RMI4_PRODUCT_ID_SIZE, "%c%c%c%c%c", + content[24], content[25], content[26], content[27], content[28]); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: container_id=%d, length=%d data=[%s]\n", + __func__, container_id, length, + rmi4_data->product_id_string_of_bin); + } + } + + return; +} +EXPORT_SYMBOL(fwu_parse_image_header_10_simple); + + +static void fwu_parse_image_header_10(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int offset; + unsigned int container_id; + unsigned int length; + unsigned char *image; + unsigned char *content; + struct container_descriptor *descriptor; + struct image_header_10 *header; + + image = fwu->image; + header = (struct image_header_10 *)image; + + fwu->v7_img.checksum = le_to_uint(header->checksum); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: fwu->v7_img.checksum=%d\n", + __func__, fwu->v7_img.checksum); + + /* address of top level container */ + offset = le_to_uint(header->top_level_container_start_addr); + descriptor = (struct container_descriptor *)(image + offset); + + /* address of top level container content */ + offset = le_to_uint(descriptor->content_address); + num_of_containers = le_to_uint(descriptor->content_length) / 4; + + for (ii = 0; ii < num_of_containers; ii++) { + addr = le_to_uint(image + offset); + offset += 4; + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: container_id=%d, length=%d\n", + __func__, container_id, length); + + + switch (container_id) { + case UI_CONTAINER: + case CORE_CODE_CONTAINER: + fwu->v7_img.ui_firmware.data = content; + fwu->v7_img.ui_firmware.size = length; + break; + case UI_CONFIG_CONTAINER: + case CORE_CONFIG_CONTAINER: + fwu->v7_img.ui_config.data = content; + fwu->v7_img.ui_config.size = length; + break; + case BL_CONTAINER: + fwu->v7_img.bl_version = *content; + fwu->v7_img.bootloader.data = content; + fwu->v7_img.bootloader.size = length; + fwu_parse_image_header_10_bl_container(rmi4_data, image); + break; + case GUEST_CODE_CONTAINER: + fwu->v7_img.contains_guest_code = true; + fwu->v7_img.guest_code.data = content; + fwu->v7_img.guest_code.size = length; + break; + case DISPLAY_CONFIG_CONTAINER: + fwu->v7_img.contains_disp_config = true; + fwu->v7_img.dp_config.data = content; + fwu->v7_img.dp_config.size = length; + break; + case FLASH_CONFIG_CONTAINER: + fwu->v7_img.contains_flash_config = true; + fwu->v7_img.fl_config.data = content; + fwu->v7_img.fl_config.size = length; + break; + case GENERAL_INFORMATION_CONTAINER: + fwu->v7_img.contains_firmware_id = true; + fwu->v7_img.firmware_id = le_to_uint(content + 4); + break; + default: + break; + } + } + + return; +} + +static void fwu_compare_partition_tables(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (fwu->phyaddr.ui_firmware != fwu->v7_img.phyaddr.ui_firmware) { + fwu->new_partition_table = true; + return; + } + + if (fwu->phyaddr.ui_config != fwu->v7_img.phyaddr.ui_config) { + fwu->new_partition_table = true; + return; + } + + if (fwu->flash_properties.has_disp_config) { + if (fwu->phyaddr.dp_config != fwu->v7_img.phyaddr.dp_config) { + fwu->new_partition_table = true; + return; + } + } + + if (fwu->flash_properties.has_disp_config) { + if (fwu->phyaddr.dp_config != fwu->v7_img.phyaddr.dp_config) { + fwu->new_partition_table = true; + return; + } + } + + if (fwu->has_guest_code) { + if (fwu->phyaddr.guest_code != fwu->v7_img.phyaddr.guest_code) { + fwu->new_partition_table = true; + return; + } + } + + fwu->new_partition_table = false; + + return; +} + +static int fwu_parse_image_info_v7(struct synaptics_rmi4_data *rmi4_data) +{ + struct image_header_10 *header; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + header = (struct image_header_10 *)fwu->image; + + memset(&fwu->v7_img, 0x00, sizeof(fwu->v7_img)); + + tsp_debug_info(false, &rmi4_data->i2c_client->dev, + "%s: header->major_header_version = %d\n", + __func__, header->major_header_version); + + switch (header->major_header_version) { + case IMAGE_HEADER_VERSION_10: + fwu_parse_image_header_10(rmi4_data); + break; + default: + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: Unsupported image file format (0x%02x)\n", + __func__, header->major_header_version); + return -EINVAL; + } + + if (fwu->bl_version == BL_V7) { + if (!fwu->v7_img.contains_flash_config) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: No flash config found in firmware image\n", + __func__); + return -EINVAL; + } + + fwu_parse_partition_table(rmi4_data, fwu->v7_img.fl_config.data, + &fwu->v7_img.blkcount, &fwu->v7_img.phyaddr); + + fwu_compare_partition_tables(rmi4_data); + } else { + fwu->new_partition_table = false; + } + + return 0; +} + +static int fwu_enter_flash_prog_v7(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct f01_device_control f01_device_control; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + unsigned char int_enable = 0x00; + + retval = fwu_read_flash_status_v7(rmi4_data); + if (retval < 0) + return retval; + + if (fwu->in_bl_mode) + return 0; + + + /* To block interrupt from finger or hovering during enter flash program mode + * 1. F01_RMI_CTRL1(Interrupt Enable 0) register is cleared on this position. + * 2. After enter flash program mode, interrupt occured only by Flash bit(0x01) + * 3. After finish all flashing and reset, Interrupt enable register will be set as default value + */ + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f01_fd.ctrl_base_addr + 1, + &int_enable, sizeof(int_enable)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write interrupt enable register\n", __func__); + return retval; + } + msleep(20); + + retval = fwu_write_f34_command_v7(rmi4_data, v7_CMD_ENABLE_FLASH_PROG); + if (retval < 0) + return retval; + + retval = fwu_wait_for_idle(rmi4_data, ENABLE_WAIT_MS); + if (retval < 0) + return retval; + + if (!fwu->in_bl_mode) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: BL mode not entered\n", + __func__); + return -EINVAL; + } + + retval = fwu_scan_pdt(rmi4_data); + if (retval < 0) + return retval; + + /* TSP IC Bootloader sub version will use programming key on Bootloader mode. + * UI mode BL sub version and BL sub version can be different, + * so read and use BL sub version after entering BL mode. + After flash fw, restore BL version for UI mode. + */ + fwu_read_f34_queries_bl_version(rmi4_data); + + retval = rmi4_data->i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: Failed to read F01 device control\n", + __func__); + return retval; + } + + f01_device_control.nosleep = true; + f01_device_control.sleep_mode = SLEEP_MODE_NORMAL; + + retval = rmi4_data->i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: Failed to write F01 device control\n", + __func__); + return retval; + } + + msleep(20); + + return retval; +} + +static int fwu_start_reflash_v7(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + enum flash_area flash_area; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (rmi4_data->sensor_sleep) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: Sensor sleeping\n", + __func__); + return -ENODEV; + } + + rmi4_data->stay_awake = true; + + mutex_lock(&rmi4_data->rmi4_reflash_mutex); + + tsp_debug_info(false, &rmi4_data->i2c_client->dev, + "%s: Start of reflash process\n", __func__); + + retval = fwu_parse_image_info_v7(rmi4_data); + if (retval < 0) + goto exit; + + if (fwu->bl_version != fwu->v7_img.bl_version) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Bootloader version mismatch\n", + __func__); + retval = -EINVAL; + goto exit; + } + + fwu->force_update = true; + + if (!fwu->force_update && fwu->new_partition_table) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Partition table mismatch\n", + __func__); + retval = -EINVAL; + goto exit; + } + + retval = fwu_read_flash_status_v7(rmi4_data); + if (retval < 0) + goto exit; + + if (fwu->in_bl_mode) { + tsp_debug_info(false, &rmi4_data->i2c_client->dev, + "%s: Device in bootloader mode\n", + __func__); + } + + flash_area = UI_FIRMWARE; + rmi4_data->doing_reflash = true; + fwu_enter_flash_prog_v7(rmi4_data); + + retval = fwu_do_reflash_v7(rmi4_data); + + if (retval < 0) { + tsp_debug_err(false, &rmi4_data->i2c_client->dev, + "%s: Failed to do reflash\n", + __func__); + } + + rmi4_data->reset_device(rmi4_data); + rmi4_data->doing_reflash = false; + + fwu->bootloader_id[0] = fwu->bootloader_id_ic[0]; + fwu->bootloader_id[1] = fwu->bootloader_id_ic[1]; + +exit: + tsp_debug_info(false, &rmi4_data->i2c_client->dev, + "%s: End of reflash process\n", __func__); + + mutex_unlock(&rmi4_data->rmi4_reflash_mutex); + + return retval; +} + +static int fwu_do_write_guest_code(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu->has_guest_code) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Firmware does not support Guest Code.\n", + __func__); + retval = -EINVAL; + } + if (fwu->guest_code_block_count != + (fwu->img.guestCode.size/fwu->block_size)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Size of Guest Code not match (dev: %x, img: %x).\n", + __func__, fwu->guest_code_block_count, + fwu->img.guestCode.size/fwu->block_size); + retval = -EINVAL; + } + + retval = fwu_enter_flash_prog(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Entered flash prog mode\n", + __func__); + + retval = fwu_write_bootloader_id(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Bootloader ID written\n", + __func__); + + retval = fwu_write_f34_command(rmi4_data, CMD_ERASE_GUEST_CODE); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ERASE_WAIT_MS); + if (retval < 0) + return retval; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + retval = fwu_write_guest_code_block(rmi4_data); + if (retval < 0) + return retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: guest code written\n", + __func__); + + return retval; +} + +static int fwu_start_write_config(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned short block_count; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + switch (fwu->config_area) { + case UI_CONFIG_AREA: + block_count = fwu->config_block_count; + break; + case PERM_CONFIG_AREA: + if (!fwu->has_perm_config) + return -EINVAL; + block_count = fwu->perm_config_block_count; + break; + case BL_CONFIG_AREA: + if (!fwu->has_bl_config) + return -EINVAL; + block_count = fwu->bl_config_block_count; + break; + case DISP_CONFIG_AREA: + if (!fwu->has_disp_config) + return -EINVAL; + block_count = fwu->disp_config_block_count; + break; + default: + return -EINVAL; + } + + if (fwu->ext_data_source) + fwu->img.uiConfig.data = fwu->ext_data_source; + else + return -EINVAL; + + fwu->config_size = fwu->block_size * block_count; + + /* Jump to the config area if given a packrat image */ + if ((fwu->config_area == UI_CONFIG_AREA) && + (fwu->config_size != fwu->img.image_size)) { + fwu_img_parse_format(rmi4_data); + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Start of write config process\n", + __func__); + + rmi4_data->doing_reflash = true; + retval = fwu_do_write_config(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write config\n", + __func__); + } + + rmi4_data->reset_device(rmi4_data); + rmi4_data->doing_reflash = false; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: End of write config process\n", + __func__); + + return retval; +} + +#define CHECKSUM_SIZE 4 +static void synaptics_rmi_calculate_checksum(unsigned short *data, + unsigned short len, unsigned long *result) +{ + unsigned long temp; + unsigned long sum1 = 0xffff; + unsigned long sum2 = 0xffff; + + *result = 0xffffffff; + + while (len--) { + temp = *data; + sum1 += temp; + sum2 += sum1; + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + data++; + } + + *result = sum2 << 16 | sum1; + + return; +} + +static void synaptics_rmi_rewrite_checksum(unsigned char *dest, + unsigned long src) +{ + dest[0] = (unsigned char)(src & 0xff); + dest[1] = (unsigned char)((src >> 8) & 0xff); + dest[2] = (unsigned char)((src >> 16) & 0xff); + dest[3] = (unsigned char)((src >> 24) & 0xff); + + return; +} + +int synaptics_rmi4_set_tsp_test_result_in_config(struct synaptics_rmi4_data *rmi4_data, int value) + +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + int retval; + unsigned char buf[10] = {0, }; + unsigned long checksum; + + /* read config from IC */ + memset(buf, 0, sizeof(buf)); + snprintf(buf, 2, "%u\n", 1); + fwu_sysfs_read_config_store(fwu->attr_dir, NULL, buf, 1); + + /* set test result value + * MSB 4bit of Customr derined config ID 0 used for factory test in TSP. + * PASS : 2, FAIL : 1, NONE: 0. + */ + fwu->read_config_buf[0] &= 0x0F; + fwu->read_config_buf[0] |= value << 4; + + /* check CRC checksum value and re-write checksum in config */ + synaptics_rmi_calculate_checksum((unsigned short *)fwu->read_config_buf, + (fwu->config_size - CHECKSUM_SIZE) / 2, &checksum); + + synaptics_rmi_rewrite_checksum(&fwu->read_config_buf[fwu->config_size - CHECKSUM_SIZE], + checksum); + + rmi4_data->doing_reflash = true; + + retval = fwu_enter_flash_prog(rmi4_data); + if (retval < 0) + goto err_config_write; + + + retval = fwu_write_bootloader_id(rmi4_data); + if (retval < 0) + goto err_config_write; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Bootloader ID written\n", + __func__); + + retval = fwu_write_f34_command(rmi4_data, CMD_ERASE_CONFIG); + if (retval < 0) + goto err_config_write; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(rmi4_data, ERASE_WAIT_MS); + if (retval < 0) + goto err_config_write; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Idle status detected\n", + __func__); + + fwu_write_blocks(rmi4_data, fwu->read_config_buf, + fwu->config_size, CMD_WRITE_CONFIG_BLOCK); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Config written\n", + __func__); + +err_config_write: + rmi4_data->reset_device(rmi4_data); + rmi4_data->doing_reflash = false; + + return retval; +} + +static int fwu_start_write_guest_code(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu->ext_data_source) + return -EINVAL; + + fwu_img_parse_format(rmi4_data); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Start of update guest code process\n", __func__); + + retval = fwu_do_write_guest_code(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write config\n", + __func__); + } + + rmi4_data->reset_device(rmi4_data); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: End of write guest code process\n", __func__); + + return retval; +} + +static int fwu_do_read_config(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char block_offset[] = {0, 0}; + unsigned short block_num; + unsigned short block_count; + unsigned short index = 0; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = fwu_enter_flash_prog(rmi4_data); + if (retval < 0) + goto exit; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Entered flash prog mode\n", + __func__); + + switch (fwu->config_area) { + case UI_CONFIG_AREA: + block_count = fwu->config_block_count; + break; + case PERM_CONFIG_AREA: + if (!fwu->has_perm_config) { + retval = -EINVAL; + goto exit; + } + block_count = fwu->perm_config_block_count; + break; + case BL_CONFIG_AREA: + if (!fwu->has_bl_config) { + retval = -EINVAL; + goto exit; + } + block_count = fwu->bl_config_block_count; + break; + case DISP_CONFIG_AREA: + if (!fwu->has_disp_config) { + retval = -EINVAL; + goto exit; + } + block_count = fwu->disp_config_block_count; + break; + default: + retval = -EINVAL; + goto exit; + } + + fwu->config_size = fwu->block_size * block_count; + + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL); + if (!fwu->read_config_buf) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for config size data\n", + __func__); + return -ENOMEM; + } + + block_offset[1] |= (fwu->config_area << 5); + + retval = rmi4_data->i2c_write(rmi4_data, + fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET, + block_offset, + sizeof(block_offset)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write to block number registers\n", + __func__); + goto exit; + } + + for (block_num = 0; block_num < block_count; block_num++) { + retval = fwu_write_f34_command(rmi4_data, CMD_READ_CONFIG_BLOCK); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write read config command\n", + __func__); + goto exit; + } + + retval = fwu_wait_for_idle(rmi4_data, WRITE_WAIT_MS); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wait for idle status\n", + __func__); + goto exit; + } + + retval = rmi4_data->i2c_read(rmi4_data, + fwu->f34_fd.data_base_addr + fwu->blk_data_off, + &fwu->read_config_buf[index], + fwu->block_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read block data (block %d)\n", + __func__, block_num); + goto exit; + } + + index += fwu->block_size; + } + +exit: + rmi4_data->reset_device(rmi4_data); + + return retval; +} + +int synaptics_fw_updater(struct synaptics_rmi4_data *rmi4_data, unsigned char *fw_data) +{ + int retval; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu) + return -ENODEV; + + if (!fwu->initialized) + return -ENODEV; + + if (!fw_data) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Firmware data is NULL\n", __func__); + return -ENODEV; + } + + fwu->ext_data_source = fw_data; + fwu->config_area = UI_CONFIG_AREA; + + fwu->image = fw_data; + retval = fwu_start_reflash_v7(rmi4_data); + if (retval < 0) + goto out_fw_update; + +out_fw_update: + return retval; +} +EXPORT_SYMBOL(synaptics_fw_updater); + +static ssize_t fwu_sysfs_show_image(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (count < fwu->config_size) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Not enough space (%d bytes) in buffer\n", + __func__, (int)count); + return -EINVAL; + } + + memcpy(buf, fwu->read_config_buf, fwu->config_size); + + return fwu->config_size; +} + +static ssize_t fwu_sysfs_store_image(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]), + (const void *)buf, + count); + + fwu->data_pos += count; + fwu->img.fw_image = fwu->ext_data_source; + return count; +} + +static ssize_t fwu_sysfs_do_reflash_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (sscanf(buf, "%u", &input) != 1) { + retval = -EINVAL; + goto exit; + } + + if (input & UPDATE_MODE_LOCKDOWN) { + fwu->do_lockdown = true; + input &= ~UPDATE_MODE_LOCKDOWN; + } + + if ((input != UPDATE_MODE_NORMAL) && (input != UPDATE_MODE_FORCE)) { + retval = -EINVAL; + goto exit; + } + + if (input == UPDATE_MODE_FORCE) + fwu->force_update = true; + + retval = synaptics_fw_updater(rmi4_data, fwu->ext_data_source); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to do reflash\n", + __func__); + goto exit; + } + + retval = count; + +exit: + kfree(fwu->ext_data_source); + fwu->ext_data_source = NULL; + fwu->force_update = FORCE_UPDATE; + fwu->do_lockdown = DO_LOCKDOWN; + return retval; +} + +static ssize_t fwu_sysfs_write_config_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (sscanf(buf, "%u", &input) != 1) { + retval = -EINVAL; + goto exit; + } + + if (input != 1) { + retval = -EINVAL; + goto exit; + } + + retval = fwu_start_write_config(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write config\n", + __func__); + goto exit; + } + + retval = count; + +exit: + kfree(fwu->ext_data_source); + fwu->ext_data_source = NULL; + return retval; +} + +static ssize_t fwu_sysfs_read_config_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input != 1) + return -EINVAL; + + retval = fwu_do_read_config(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read config\n", + __func__); + return retval; + } + + return count; +} + +static ssize_t fwu_sysfs_config_area_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned long config_area; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = kstrtoul(buf, 10, &config_area); + if (retval) + return retval; + + fwu->config_area = config_area; + + return count; +} + +static ssize_t fwu_sysfs_image_size_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned long size; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + retval = kstrtoul(buf, 10, &size); + if (retval) + return retval; + + fwu->img.image_size = size; + fwu->data_pos = 0; + + kfree(fwu->ext_data_source); + fwu->ext_data_source = kzalloc(fwu->img.image_size, GFP_KERNEL); + if (!fwu->ext_data_source) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for image data\n", + __func__); + return -ENOMEM; + } + + return count; +} + +static ssize_t fwu_sysfs_block_size_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size); +} + +static ssize_t fwu_sysfs_firmware_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->fw_block_count); +} + +static ssize_t fwu_sysfs_configuration_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->config_block_count); +} + +static ssize_t fwu_sysfs_perm_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->perm_config_block_count); +} + +static ssize_t fwu_sysfs_bl_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->bl_config_block_count); +} + +static ssize_t fwu_sysfs_disp_config_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count); +} + +static ssize_t fwu_sysfs_guest_code_block_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + return snprintf(buf, PAGE_SIZE, "%u\n", fwu->guest_code_block_count); +} + +static ssize_t fwu_sysfs_write_guest_code_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = rmi_attr_kobj_to_drvdata(kobj); + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (sscanf(buf, "%u", &input) != 1) { + retval = -EINVAL; + goto exit; + } + + if (input != 1) { + retval = -EINVAL; + goto exit; + } + + retval = fwu_start_write_guest_code(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to write guest code\n", + __func__); + goto exit; + } + + retval = count; + +exit: + kfree(fwu->ext_data_source); + fwu->ext_data_source = NULL; + return retval; +} + +static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data, + unsigned char intr_mask) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu) + return; + + if (fwu->intr_mask & intr_mask) + fwu_read_flash_status_v7(rmi4_data); + + return; +} + +static void fwu_img_scan_x10_container(struct synaptics_rmi4_data *rmi4_data, + unsigned int list_length, unsigned char *start_addr) +{ + unsigned int i; + unsigned int length; + unsigned int contentAddr, addr; + unsigned short containerId; + struct block_data block; + struct img_x10_descriptor *containerDescriptor; + struct img_x10_bl_container *blContainer; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + for (i = 0; i < list_length; i += 4) { + contentAddr = extract_uint_le(start_addr + i); + containerDescriptor = + (struct img_x10_descriptor *)(fwu->img.fw_image + contentAddr); + containerId = extract_ushort_le(containerDescriptor->containerID); + addr = extract_uint_le(containerDescriptor->contentAddress); + length = extract_uint_le(containerDescriptor->contentLength); + block.data = fwu->img.fw_image + addr; + block.size = length; + switch (containerId) { + case ID_UI_CONTAINER: + fwu->img.uiFirmware = block; + break; + case ID_UI_CONFIGURATION: + fwu->img.uiConfig = block; + fwu->img.configId = fwu->img.uiConfig.data; + break; + case ID_BOOTLOADER_LOCKDOWN_INFORMATION_CONTAINER: + fwu->img.lockdown = block; + break; + case ID_GUEST_CODE_CONTAINER: + fwu->img.guestCode = block; + break; + case ID_BOOTLOADER_CONTAINER: + blContainer = + (struct img_x10_bl_container *)(fwu->img.fw_image + addr); + fwu->img.blMajorVersion = blContainer->majorVersion; + fwu->img.blMinorVersion = blContainer->minorVersion; + fwu->img.bootloaderInfo = block; + break; + case ID_PERMANENT_CONFIGURATION_CONTAINER: + fwu->img.permanent = block; + break; + case ID_GENERAL_INFORMATION_CONTAINER: + fwu->img.packageId = fwu->img.fw_image + addr + 0; + fwu->img.firmwareId = fwu->img.fw_image + addr + 4; + fwu->img.dsFirmwareInfo = fwu->img.fw_image + addr + 8; + break; + default: + break; + } + } +} + +static void fwu_img_parse_x10_topcontainer(struct synaptics_rmi4_data *rmi4_data) +{ + struct img_x10_descriptor *descriptor; + unsigned int topAddr; + unsigned int list_length, bl_length; + unsigned char *start_addr; + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + topAddr = extract_uint_le(fwu->img.fw_image + + IMG_X10_TOP_CONTAINER_OFFSET); + descriptor = (struct img_x10_descriptor *) + (fwu->img.fw_image + topAddr); + list_length = extract_uint_le(descriptor->contentLength); + start_addr = fwu->img.fw_image + + extract_uint_le(descriptor->contentAddress); + fwu_img_scan_x10_container(rmi4_data, list_length, start_addr); + /* scan sub bootloader container (lockdown container) */ + if (fwu->img.bootloaderInfo.data != NULL) { + bl_length = fwu->img.bootloaderInfo.size - 4; + if (bl_length) + fwu_img_scan_x10_container(rmi4_data, bl_length, + fwu->img.bootloaderInfo.data); + } +} + +static void fwu_img_parse_x10(struct synaptics_rmi4_data *rmi4_data) +{ + fwu_img_parse_x10_topcontainer(rmi4_data); +} + +static void fwu_img_parse_x0_x6(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + struct img_x0x6_header *header = (struct img_x0x6_header *)fwu->img.fw_image; + + if (header->bootloader_version > 6) + return; + fwu->img.blMajorVersion = header->bootloader_version; + fwu->img.uiFirmware.size = extract_uint_le(header->firmware_size); + fwu->img.uiFirmware.data = fwu->img.fw_image + IMG_X0_X6_FW_OFFSET; + fwu->img.uiConfig.size = extract_uint_le(header->config_size); + fwu->img.uiConfig.data = fwu->img.uiFirmware.data + fwu->img.uiFirmware.size; + fwu->img.configId = fwu->img.uiConfig.data; + switch (fwu->img.imageFileVersion) { + case 0x2: + fwu->img.lockdown.size = 0x30; + break; + case 0x3: + case 0x4: + fwu->img.lockdown.size = 0x40; + break; + case 0x5: + case 0x6: + fwu->img.lockdown.size = 0x50; + if (header->options_firmware_id) { + fwu->img.firmwareId = header->firmware_id; + fwu->img.packageId = header->package_id; + fwu->img.dsFirmwareInfo = header->ds_firmware_info; + } + break; + default: + break; + } + fwu->img.lockdown.data = fwu->img.fw_image + + IMG_X0_X6_FW_OFFSET - fwu->img.lockdown.size; +} + +static void fwu_img_parse_format(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + fwu->polling_mode = POLLING_MODE_DEFAULT; + fwu->img.firmwareId = NULL; + fwu->img.packageId = NULL; + fwu->img.dsFirmwareInfo = NULL; + fwu->img.uiFirmware.data = NULL; + fwu->img.uiConfig.data = NULL; + fwu->img.lockdown.data = NULL; + fwu->img.guestCode.data = NULL; + fwu->img.uiConfig.size = 0; + fwu->img.uiFirmware.size = 0; + fwu->img.lockdown.size = 0; + fwu->img.guestCode.size = 0; + + fwu->img.imageFileVersion = fwu->img.fw_image[IMG_VERSION_OFFSET]; + + switch (fwu->img.imageFileVersion) { + case 0x10: + fwu_img_parse_x10(rmi4_data); + break; + case 0x5: + case 0x6: + fwu_img_parse_x0_x6(rmi4_data); + break; + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Unsupported image file format $%X\n", + __func__, fwu->img.imageFileVersion); + break; + } + + if (fwu->bl_version == BL_V7) { + + memset(&fwu->v7_img, 0x00, sizeof(fwu->v7_img)); + + if (!fwu->v7_img.contains_flash_config) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: No flash config found in firmware image\n", + __func__); + return; + } + + fwu_parse_partition_table(rmi4_data, fwu->v7_img.fl_config.data, + &fwu->v7_img.blkcount, &fwu->v7_img.phyaddr); + + fwu_compare_partition_tables(rmi4_data); + } else { + fwu->new_partition_table = false; + } +} + +static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct pdt_properties pdt_props; + struct synaptics_rmi4_fwu_handle *fwu = NULL; + + fwu = kzalloc(sizeof(struct synaptics_rmi4_fwu_handle), GFP_KERNEL); + if (!fwu) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for fwu\n", + __func__); + retval = -ENOMEM; + goto exit; + } + + rmi4_data->fwu = fwu; + fwu->rmi4_data = rmi4_data; + + memset(&fwu->img, 0, sizeof(struct img_file_content)); + + fwu->img.image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL); + if (!fwu->img.image_name) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for image name\n", + __func__); + retval = -ENOMEM; + goto err_free_fwu; + } + + retval = rmi4_data->i2c_read(rmi4_data, + PDT_PROPS, + pdt_props.data, + sizeof(pdt_props.data)); + if (retval < 0) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read PDT properties, assuming 0x00\n", + __func__); + } else if (pdt_props.has_bsr) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Reflash for LTS not currently supported\n", + __func__); + retval = -ENODEV; + goto err_free_mem; + } + + retval = fwu_scan_pdt(rmi4_data); + if (retval < 0) + goto err_free_mem; + + memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount)); + memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr)); + fwu_read_f34_queries_v7(rmi4_data); + + fwu->force_update = FORCE_UPDATE; + fwu->do_lockdown = DO_LOCKDOWN; + fwu->initialized = true; + + fwu->attr_dir = kobject_create_and_add(ATTRIBUTE_FOLDER_NAME, + &rmi4_data->input_dev->dev.kobj); + if (!fwu->attr_dir) { + dev_err(&rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs directory\n", + __func__); + retval = -ENODEV; + goto err_attr_dir; + } + + retval = sysfs_create_bin_file(fwu->attr_dir, &dev_attr_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs bin file\n", + __func__); + goto err_sysfs_bin; + } + + retval = sysfs_create_group(fwu->attr_dir, &attr_group); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create sysfs attributes\n", __func__); + retval = -ENODEV; + goto err_sysfs_attrs; + } + + return 0; + +err_sysfs_attrs: + sysfs_remove_group(fwu->attr_dir, &attr_group); + sysfs_remove_bin_file(fwu->attr_dir, &dev_attr_data); + +err_sysfs_bin: + kobject_put(fwu->attr_dir); + +err_attr_dir: +err_free_mem: + kfree(fwu->img.image_name); + +err_free_fwu: + kfree(fwu); + rmi4_data->fwu = NULL; + +exit: + return retval; +} + +static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fwu_handle *fwu = rmi4_data->fwu; + + if (!fwu) + goto exit; + + sysfs_remove_group(fwu->attr_dir, &attr_group); + sysfs_remove_bin_file(fwu->attr_dir, &dev_attr_data); + + kobject_put(fwu->attr_dir); + + kfree(fwu->read_config_buf); + kfree(fwu->img.image_name); + kfree(fwu); + rmi4_data->fwu = NULL; + +exit: + return; +} + +int rmi4_fw_update_module_register(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + + retval = synaptics_rmi4_new_function(RMI_FW_UPDATER, + rmi4_data, + synaptics_rmi4_fwu_init, + NULL, + synaptics_rmi4_fwu_remove, + synaptics_rmi4_fwu_attn); + + return retval; +} diff --git a/drivers/input/touchscreen/synaptics_dsx2/rmi_register_map.h b/drivers/input/touchscreen/synaptics_dsx2/rmi_register_map.h new file mode 100644 index 000000000000..5d537037273e --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/rmi_register_map.h @@ -0,0 +1,1065 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + *************************************************** + * Structures for F01 registers. + *************************************************** + */ + +struct synaptics_rmi4_f01_device_status { + union { + struct { + unsigned char status_code:4; + unsigned char reserved:2; + unsigned char flash_prog:1; + unsigned char unconfigured:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_f01_device_control { + union { + struct { + unsigned char sleep_mode:2; + unsigned char nosleep:1; + unsigned char reserved:2; + unsigned char charger_connected:1; + unsigned char report_rate:1; + unsigned char configured:1; + } __packed; + unsigned char data[1]; + }; +}; +/* + *************************************************** + * Structures for F12 registers. + *************************************************** + */ +struct synaptics_rmi4_f12_query_5 { + union { + struct { + unsigned char size_of_query6; + struct { + unsigned char ctrl0_is_present:1; + unsigned char ctrl1_is_present:1; + unsigned char ctrl2_is_present:1; + unsigned char ctrl3_is_present:1; + unsigned char ctrl4_is_present:1; + unsigned char ctrl5_is_present:1; + unsigned char ctrl6_is_present:1; + unsigned char ctrl7_is_present:1; + } __packed; + struct { + unsigned char ctrl8_is_present:1; + unsigned char ctrl9_is_present:1; + unsigned char ctrl10_is_present:1; + unsigned char ctrl11_is_present:1; + unsigned char ctrl12_is_present:1; + unsigned char ctrl13_is_present:1; + unsigned char ctrl14_is_present:1; + unsigned char ctrl15_is_present:1; + } __packed; + struct { + unsigned char ctrl16_is_present:1; + unsigned char ctrl17_is_present:1; + unsigned char ctrl18_is_present:1; + unsigned char ctrl19_is_present:1; + unsigned char ctrl20_is_present:1; + unsigned char ctrl21_is_present:1; + unsigned char ctrl22_is_present:1; + unsigned char ctrl23_is_present:1; + } __packed; + struct { + unsigned char ctrl24_is_present:1; + unsigned char ctrl25_is_present:1; + unsigned char ctrl26_is_present:1; + unsigned char ctrl27_is_present:1; + unsigned char ctrl28_is_present:1; + unsigned char ctrl29_is_present:1; + unsigned char ctrl30_is_present:1; + unsigned char ctrl31_is_present:1; + } __packed; + }; + unsigned char data[5]; + }; +}; + +struct synaptics_rmi4_f12_query_8 { + union { + struct { + unsigned char size_of_query9; + struct { + unsigned char data0_is_present:1; + unsigned char data1_is_present:1; + unsigned char data2_is_present:1; + unsigned char data3_is_present:1; + unsigned char data4_is_present:1; + unsigned char data5_is_present:1; + unsigned char data6_is_present:1; + unsigned char data7_is_present:1; + } __packed; + struct { + unsigned char data8_is_present:1; + unsigned char data9_is_present:1; + unsigned char data10_is_present:1; + unsigned char data11_is_present:1; + unsigned char data12_is_present:1; + unsigned char data13_is_present:1; + unsigned char data14_is_present:1; + unsigned char data15_is_present:1; + } __packed; + }; + unsigned char data[3]; + }; +}; + +struct synaptics_rmi4_f12_query_10 { + union { + struct { + unsigned char f12_query10_b0__4:5; + unsigned char glove_mode_feature:1; + unsigned char f12_query10_b6__7:2; + } __packed; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_f12_ctrl_8 { + union { + struct { + unsigned char max_x_coord_lsb; + unsigned char max_x_coord_msb; + unsigned char max_y_coord_lsb; + unsigned char max_y_coord_msb; + unsigned char rx_pitch_lsb; + unsigned char rx_pitch_msb; + unsigned char tx_pitch_lsb; + unsigned char tx_pitch_msb; + unsigned char low_rx_clip; + unsigned char high_rx_clip; + unsigned char low_tx_clip; + unsigned char high_tx_clip; + unsigned char num_of_rx; + unsigned char num_of_tx; + }; + unsigned char data[14]; + }; +}; + +struct synaptics_rmi4_f12_ctrl_9 { + union { + struct { + unsigned char touch_threshold; + unsigned char lift_hysteresis; + unsigned char small_z_scale_factor_lsb; + unsigned char small_z_scale_factor_msb; + unsigned char large_z_scale_factor_lsb; + unsigned char large_z_scale_factor_msb; + unsigned char small_large_boundary; + unsigned char wx_scale; + unsigned char wx_offset; + unsigned char wy_scale; + unsigned char wy_offset; + unsigned char x_size_lsb; + unsigned char x_size_msb; + unsigned char y_size_lsb; + unsigned char y_size_msb; + unsigned char gloved_finger; + }; + unsigned char data[16]; + }; +}; + +struct synaptics_rmi4_f12_ctrl_11 { + union { + struct { + unsigned char small_corner; + unsigned char large_corner; + unsigned char jitter_filter_strength; + unsigned char x_minimum_z; + unsigned char y_minimum_z; + unsigned char x_maximum_z; + unsigned char y_maximum_z; + unsigned char x_amplitude; + unsigned char y_amplitude; + unsigned char gloved_finger_jitter_filter_strength; + }; + unsigned char data[10]; + }; +}; + +struct synaptics_rmi4_f12_ctrl_23 { + union { + struct { + unsigned char obj_type_enable; + unsigned char max_reported_objects; + }; + unsigned char data[2]; + }; +}; + +struct synaptics_rmi4_f12_ctrl_26 { + union { + struct { + unsigned char feature_enable; + }; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_f12_finger_data { + unsigned char object_type_and_status; + unsigned char x_lsb; + unsigned char x_msb; + unsigned char y_lsb; + unsigned char y_msb; +#ifdef REPORT_2D_Z + unsigned char z; +#endif +#ifdef REPORT_2D_W + unsigned char wx; + unsigned char wy; +#endif +}; + +struct synaptics_rmi4_f12_extra_data { + unsigned char data1_offset; + unsigned char data15_offset; + unsigned char data15_size; + unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8]; +}; +/* + *************************************************** + * Structures for F1A registers. + *************************************************** + */ +struct synaptics_rmi4_f1a_query { + union { + struct { + unsigned char max_button_count:3; + unsigned char reserved:5; + unsigned char has_general_control:1; + unsigned char has_interrupt_enable:1; + unsigned char has_multibutton_select:1; + unsigned char has_tx_rx_map:1; + unsigned char has_perbutton_threshold:1; + unsigned char has_release_threshold:1; + unsigned char has_strongestbtn_hysteresis:1; + unsigned char has_filter_strength:1; + } __packed; + unsigned char data[2]; + }; +}; + +struct synaptics_rmi4_f1a_control_0 { + union { + struct { + unsigned char multibutton_report:2; + unsigned char filter_mode:2; + unsigned char reserved:4; + } __packed; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_f1a_control { + struct synaptics_rmi4_f1a_control_0 general_control; + unsigned char button_int_enable; + unsigned char multi_button; + unsigned char *txrx_map; + unsigned char *button_threshold; + unsigned char button_release_threshold; + unsigned char strongest_button_hysteresis; + unsigned char filter_strength; +}; + +/* + *************************************************** + * Structures for F34 registers. + *************************************************** + */ +struct synaptics_rmi4_f34_ctrl_0 { + union { + struct { + unsigned char fw_release_month; + unsigned char fw_release_date; + unsigned char fw_release_revision; + unsigned char fw_release_version; + }; + unsigned char data[4]; + }; +}; + +struct synaptics_rmi4_f34_query_01 { + union { + struct { + unsigned char reg_map:1; + unsigned char unlocked:1; + unsigned char has_config_id:1; + unsigned char has_perm_config:1; + unsigned char has_bl_config:1; + unsigned char has_disp_config:1; + unsigned char has_ctrl1:1; + unsigned char has_flash_query4:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_f34_query_04 { + union { + struct { + unsigned char has_guest_code:1; + unsigned char reserved:1; + } __packed; + unsigned char data[1]; + }; +}; +/* + *************************************************** + * Structures for F51 registers. + *************************************************** + */ +struct synaptics_rmi4_f51_query { + union { + struct { + unsigned char query_register_count; + unsigned char data_register_count; + unsigned char control_register_count; + unsigned char command_register_count; + unsigned char proximity_controls; + unsigned char proximity_controls_2; + }; + unsigned char data[6]; + }; +}; + +struct synaptics_rmi4_f51_data { + union { + struct { + unsigned char finger_hover_det:1; + unsigned char air_swipe_det:1; + unsigned char large_obj_det:1; + unsigned char hover_pinch_det:1; + unsigned char lowg_detected:1; + unsigned char profile_handedness_status:2; + unsigned char face_detect:1; + + unsigned char hover_finger_x_4__11; + unsigned char hover_finger_y_4__11; + unsigned char hover_finger_xy_0__3; + unsigned char hover_finger_z; + } __packed; + unsigned char proximity_data[5]; + }; + +#ifdef EDGE_SWIPE + union { + struct { + unsigned char edge_swipe_x_lsb; + unsigned char edge_swipe_x_msb; + unsigned char edge_swipe_y_lsb; + unsigned char edge_swipe_y_msb; + unsigned char edge_swipe_z; + unsigned char edge_swipe_wx; + unsigned char edge_swipe_wy; + unsigned char edge_swipe_mm; + signed char edge_swipe_dg; + } __packed; + unsigned char edge_swipe_data[9]; + }; +#endif +#ifdef SIDE_TOUCH + union { + struct { + unsigned char side_button_leading; + unsigned char side_button_trailing; + } __packed; + unsigned char side_button_data[2]; + }; +#endif +}; + +/* + *************************************************** + * Structures for F54 registers. + *************************************************** + */ +struct f54_query { + union { + struct { + /* query 0 */ + unsigned char num_of_rx_electrodes; + + /* query 1 */ + unsigned char num_of_tx_electrodes; + + /* query 2 */ + unsigned char f54_query2_b0__1:2; + unsigned char has_baseline:1; + unsigned char has_image8:1; + unsigned char f54_query2_b4__5:2; + unsigned char has_image16:1; + unsigned char f54_query2_b7:1; + + /* queries 3.0 and 3.1 */ + unsigned short clock_rate; + + /* query 4 */ + unsigned char touch_controller_family; + + /* query 5 */ + unsigned char has_pixel_touch_threshold_adjustment:1; + unsigned char f54_query5_b1__7:7; + + /* query 6 */ + unsigned char has_sensor_assignment:1; + unsigned char has_interference_metric:1; + unsigned char has_sense_frequency_control:1; + unsigned char has_firmware_noise_mitigation:1; + unsigned char has_ctrl11:1; + unsigned char has_two_byte_report_rate:1; + unsigned char has_one_byte_report_rate:1; + unsigned char has_relaxation_control:1; + + /* query 7 */ + unsigned char curve_compensation_mode:2; + unsigned char f54_query7_b2__7:6; + + /* query 8 */ + unsigned char f54_query8_b0:1; + unsigned char has_iir_filter:1; + unsigned char has_cmn_removal:1; + unsigned char has_cmn_maximum:1; + unsigned char has_touch_hysteresis:1; + unsigned char has_edge_compensation:1; + unsigned char has_per_frequency_noise_control:1; + unsigned char has_enhanced_stretch:1; + + /* query 9 */ + unsigned char has_force_fast_relaxation:1; + unsigned char has_multi_metric_state_machine:1; + unsigned char has_signal_clarity:1; + unsigned char has_variance_metric:1; + unsigned char has_0d_relaxation_control:1; + unsigned char has_0d_acquisition_control:1; + unsigned char has_status:1; + unsigned char has_slew_metric:1; + + /* query 10 */ + unsigned char has_h_blank:1; + unsigned char has_v_blank:1; + unsigned char has_long_h_blank:1; + unsigned char has_startup_fast_relaxation:1; + unsigned char has_esd_control:1; + unsigned char has_noise_mitigation2:1; + unsigned char has_noise_state:1; + unsigned char has_energy_ratio_relaxation:1; + + /* query 11 */ + unsigned char has_excessive_noise_reporting:1; + unsigned char has_slew_option:1; + unsigned char has_two_overhead_bursts:1; + unsigned char has_query13:1; + unsigned char has_one_overhead_burst:1; + unsigned char f54_query11_b5:1; + unsigned char has_ctrl88:1; + unsigned char has_query15:1; + + /* query 12 */ + unsigned char number_of_sensing_frequencies:4; + unsigned char f54_query12_b4__7:4; + } __packed; + unsigned char data[14]; + }; +}; + +struct f54_query_13 { + union { + struct { + /* query 13 */ + unsigned char has_ctrl86:1; + unsigned char has_ctrl87:1; + unsigned char has_ctrl87_sub0:1; + unsigned char has_ctrl87_sub1:1; + unsigned char has_ctrl87_sub2:1; + unsigned char has_cidim:1; + unsigned char has_noise_mitigation_enhancement:1; + unsigned char has_rail_im:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f54_query_15 { + union { + struct { + unsigned char has_ctrl90:1; + unsigned char has_transmit_strength:1; + unsigned char has_ctrl87_sub3:1; + unsigned char has_query16:1; + unsigned char has_query20:1; + unsigned char has_query21:1; + unsigned char has_query22:1; + unsigned char has_query25:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f54_query_16 { + union { + struct { + unsigned char has_query17:1; + unsigned char has_data17:1; + unsigned char has_ctrl92:1; + unsigned char has_ctrl93:1; + unsigned char has_ctrl94_query18:1; + unsigned char has_ctrl95_query19:1; + unsigned char has_ctrl99:1; + unsigned char has_ctrl100:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f54_query_21 { + union { + struct { + unsigned char has_abs_rx:1; + unsigned char has_abs_tx:1; + unsigned char has_ctrl91:1; + unsigned char has_ctrl96:1; + unsigned char has_ctrl97:1; + unsigned char has_ctrl98:1; + unsigned char has_data19:1; + unsigned char has_query24_data18:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f54_control_0 { + union { + struct { + unsigned char no_relax:1; + unsigned char no_scan:1; + unsigned char force_fast_relaxation:1; + unsigned char startup_fast_relaxation:1; + unsigned char gesture_cancels_sfr:1; + unsigned char enable_energy_ratio_relaxation:1; + unsigned char excessive_noise_attn_enable:1; + unsigned char f54_control0_b7:1; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_1 { + union { + struct { + unsigned char bursts_per_cluster:4; + unsigned char f54_ctrl1_b4__7:4; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_2 { + union { + struct { + unsigned short saturation_cap; + } __packed; + struct { + unsigned char data[2]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_3 { + union { + struct { + unsigned char pixel_touch_threshold; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_4__6 { + union { + struct { + /* control 4 */ + unsigned char rx_feedback_cap:2; + unsigned char bias_current:2; + unsigned char f54_ctrl4_b4__7:4; + + /* control 5 */ + unsigned char low_ref_cap:2; + unsigned char low_ref_feedback_cap:2; + unsigned char low_ref_polarity:1; + unsigned char f54_ctrl5_b5__7:3; + + /* control 6 */ + unsigned char high_ref_cap:2; + unsigned char high_ref_feedback_cap:2; + unsigned char high_ref_polarity:1; + unsigned char f54_ctrl6_b5__7:3; + } __packed; + struct { + unsigned char data[3]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_7 { + union { + struct { + unsigned char cbc_cap:3; + unsigned char cbc_polarity:1; + unsigned char cbc_tx_carrier_selection:1; + unsigned char f54_ctrl7_b5__7:3; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_8__9 { + union { + struct { + /* control 8 */ + unsigned short integration_duration:10; + unsigned short f54_ctrl8_b10__15:6; + + /* control 9 */ + unsigned char reset_duration; + } __packed; + struct { + unsigned char data[3]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_10 { + union { + struct { + unsigned char noise_sensing_bursts_per_image:4; + unsigned char f54_ctrl10_b4__7:4; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_11 { + union { + struct { + unsigned short f54_ctrl11; + } __packed; + struct { + unsigned char data[2]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_12__13 { + union { + struct { + /* control 12 */ + unsigned char slow_relaxation_rate; + + /* control 13 */ + unsigned char fast_relaxation_rate; + } __packed; + struct { + unsigned char data[2]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_14 { + union { + struct { + unsigned char rxs_on_xaxis:1; + unsigned char curve_comp_on_txs:1; + unsigned char f54_ctrl14_b2__7:6; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_15n { + unsigned char sensor_rx_assignment; +}; + +struct f54_control_15 { + struct f54_control_15n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_16n { + unsigned char sensor_tx_assignment; +}; + +struct f54_control_16 { + struct f54_control_16n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_17n { + unsigned char burst_count_b8__10:3; + unsigned char disable:1; + unsigned char f54_ctrl17_b4:1; + unsigned char filter_bandwidth:3; +}; + +struct f54_control_17 { + struct f54_control_17n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_18n { + unsigned char burst_count_b0__7; +}; + +struct f54_control_18 { + struct f54_control_18n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_19n { + unsigned char stretch_duration; +}; + +struct f54_control_19 { + struct f54_control_19n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_20 { + union { + struct { + unsigned char disable_noise_mitigation:1; + unsigned char f54_ctrl20_b1__7:7; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_21 { + union { + struct { + unsigned short freq_shift_noise_threshold; + } __packed; + struct { + unsigned char data[2]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_22__26 { + union { + struct { + /* control 22 */ + unsigned char f54_ctrl22; + + /* control 23 */ + unsigned short medium_noise_threshold; + + /* control 24 */ + unsigned short high_noise_threshold; + + /* control 25 */ + unsigned char noise_density; + + /* control 26 */ + unsigned char frame_count; + } __packed; + struct { + unsigned char data[7]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_27 { + union { + struct { + unsigned char iir_filter_coef; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_28 { + union { + struct { + unsigned short quiet_threshold; + } __packed; + struct { + unsigned char data[2]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_29 { + union { + struct { + /* control 29 */ + unsigned char f54_ctrl29_b0__6:7; + unsigned char cmn_filter_disable:1; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_30 { + union { + struct { + unsigned char cmn_filter_max; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_31 { + union { + struct { + unsigned char touch_hysteresis; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_32__35 { + union { + struct { + /* control 32 */ + unsigned short rx_low_edge_comp; + + /* control 33 */ + unsigned short rx_high_edge_comp; + + /* control 34 */ + unsigned short tx_low_edge_comp; + + /* control 35 */ + unsigned short tx_high_edge_comp; + } __packed; + struct { + unsigned char data[8]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_36n { + unsigned char axis1_comp; +}; + +struct f54_control_36 { + struct f54_control_36n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_37n { + unsigned char axis2_comp; +}; + +struct f54_control_37 { + struct f54_control_37n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_38n { + unsigned char noise_control_1; +}; + +struct f54_control_38 { + struct f54_control_38n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_39n { + unsigned char noise_control_2; +}; + +struct f54_control_39 { + struct f54_control_39n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_40n { + unsigned char noise_control_3; +}; + +struct f54_control_40 { + struct f54_control_40n *data; + unsigned short address; + unsigned char length; +}; + +struct f54_control_41 { + union { + struct { + unsigned char no_signal_clarity:1; + unsigned char f54_ctrl41_b1__7:7; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_57 { + union { + struct { + unsigned char cbc_cap_0d:3; + unsigned char cbc_polarity_0d:1; + unsigned char cbc_tx_carrier_selection_0d:1; + unsigned char f54_ctrl57_b5__7:3; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_88 { + union { + struct { + unsigned char tx_low_reference_polarity:1; + unsigned char tx_high_reference_polarity:1; + unsigned char abs_low_reference_polarity:1; + unsigned char abs_polarity:1; + unsigned char cbc_polarity:1; + unsigned char cbc_tx_carrier_selection:1; + unsigned char charge_pump_enable:1; + unsigned char cbc_abs_auto_servo:1; + } __packed; + struct { + unsigned char data[1]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control_94 { + union { + struct { + unsigned char abs_rx_bursts_per_cluster; + unsigned char abs_tx_bursts_per_cluster; + unsigned char trans_cap_bursts_per_cluster; + unsigned char noise_bursts_per_cluster; + } __packed; + struct { + unsigned char data[4]; + unsigned short address; + } __packed; + }; +}; + +struct f54_control { + struct f54_control_0 *reg_0; + struct f54_control_1 *reg_1; + struct f54_control_2 *reg_2; + struct f54_control_3 *reg_3; + struct f54_control_4__6 *reg_4__6; + struct f54_control_7 *reg_7; + struct f54_control_8__9 *reg_8__9; + struct f54_control_10 *reg_10; + struct f54_control_11 *reg_11; + struct f54_control_12__13 *reg_12__13; + struct f54_control_14 *reg_14; + struct f54_control_15 *reg_15; + struct f54_control_16 *reg_16; + struct f54_control_17 *reg_17; + struct f54_control_18 *reg_18; + struct f54_control_19 *reg_19; + struct f54_control_20 *reg_20; + struct f54_control_21 *reg_21; + struct f54_control_22__26 *reg_22__26; + struct f54_control_27 *reg_27; + struct f54_control_28 *reg_28; + struct f54_control_29 *reg_29; + struct f54_control_30 *reg_30; + struct f54_control_31 *reg_31; + struct f54_control_32__35 *reg_32__35; + struct f54_control_36 *reg_36; + struct f54_control_37 *reg_37; + struct f54_control_38 *reg_38; + struct f54_control_39 *reg_39; + struct f54_control_40 *reg_40; + struct f54_control_41 *reg_41; + struct f54_control_57 *reg_57; + struct f54_control_88 *reg_88; + struct f54_control_94 *reg_94; +}; diff --git a/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.c b/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.c new file mode 100644 index 000000000000..bf79309d1ce3 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.c @@ -0,0 +1,4494 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include + +#include + +#include "synaptics_i2c_rmi.h" + +static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, + unsigned short addr, unsigned char *data, + unsigned short length); + +static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, + unsigned short addr, unsigned char *data, + unsigned short length); + +static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data); +static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data); +static int synaptics_rmi4_stop_device(struct synaptics_rmi4_data *rmi4_data); +static int synaptics_rmi4_start_device(struct synaptics_rmi4_data *rmi4_data); +#ifdef USE_SENSOR_SLEEP +static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data); +static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data); +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static void synaptics_rmi4_early_suspend(struct early_suspend *h); + +static void synaptics_rmi4_late_resume(struct early_suspend *h); + +#else + +static int synaptics_rmi4_suspend(struct device *dev); + +static int synaptics_rmi4_resume(struct device *dev); +#endif + +#ifdef PROXIMITY_MODE +static void synaptics_rmi4_f51_finger_timer(unsigned long data); + +static ssize_t synaptics_rmi4_f51_enables_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_f51_enables_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +#endif + +static int synaptics_rmi4_input_open(struct input_dev *dev); +static void synaptics_rmi4_input_close(struct input_dev *dev); + +static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static DEVICE_ATTR(full_pm_cycle, (S_IRUGO | S_IWUSR | S_IWGRP), + synaptics_rmi4_full_pm_cycle_show, synaptics_rmi4_full_pm_cycle_store); +#endif +#ifdef PROXIMITY_MODE +static DEVICE_ATTR(proximity_enables, (S_IRUGO | S_IWUSR | S_IWGRP), + synaptics_rmi4_f51_enables_show, synaptics_rmi4_f51_enables_store); +#endif +static DEVICE_ATTR(reset, S_IWUSR | S_IWGRP, NULL, synaptics_rmi4_f01_reset_store); +static DEVICE_ATTR(productinfo, S_IRUGO, synaptics_rmi4_f01_productinfo_show, NULL); +static DEVICE_ATTR(buildid, S_IRUGO, synaptics_rmi4_f01_buildid_show, NULL); +static DEVICE_ATTR(flashprog, S_IRUGO, synaptics_rmi4_f01_flashprog_show, NULL); +static DEVICE_ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP), synaptics_rmi4_0dbutton_show, synaptics_rmi4_0dbutton_store); + +static struct attribute *attrs[] = { +#ifdef CONFIG_HAS_EARLYSUSPEND + &dev_attr_full_pm_cycle.attr, +#endif +#ifdef PROXIMITY_MODE + &dev_attr_proximity_enables.attr, +#endif + &dev_attr_reset.attr, + &dev_attr_productinfo.attr, + &dev_attr_buildid.attr, + &dev_attr_flashprog.attr, + &dev_attr_0dbutton.attr, + NULL, +}; + +static struct attribute_group attr_group = { + .name = "rmii2c", + .attrs = attrs, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static ssize_t synaptics_rmi4_full_pm_cycle_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + rmi4_data->full_pm_cycle); +} + +static ssize_t synaptics_rmi4_full_pm_cycle_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + rmi4_data->full_pm_cycle = input > 0 ? 1 : 0; + + return count; +} +#endif + +#ifdef PRINT_DEBUG_INFO +static void print_debug_log(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned short delta_min; + unsigned short delta_max; + unsigned short delta_avg; + unsigned short cid_im; + unsigned short freq_im; + unsigned char fast_relax; + unsigned char noise_state; + struct synaptics_rmi4_f51_delta_info f51_data40; + struct synaptics_rmi4_f54_cid_im f54_data14; + struct synaptics_rmi4_f54_freq_im f54_data16; + + synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f51_delta_info_addr, + f51_data40.data, + sizeof(f51_data40.data)); + + synaptics_rmi4_i2c_read(rmi4_data, + F54_DATA10_ADDR, + &noise_state, + sizeof(noise_state)); + + synaptics_rmi4_i2c_read(rmi4_data, + F54_DATA14_ADDR, + f54_data14.data, + sizeof(f54_data14.data)); + + synaptics_rmi4_i2c_read(rmi4_data, + F54_DATA16_ADDR, + f54_data16.data, + sizeof(f54_data16.data)); + + delta_min = f51_data40.deltamin_lsb | + (f51_data40.deltamin_msb << 8); + delta_max = f51_data40.deltamax_lsb | + (f51_data40.deltamax_msb << 8); + delta_avg = f51_data40.deltaavg_lsb | + (f51_data40.deltaavg_msb << 8); + cid_im = f54_data14.cid_im_low | + (f54_data14.cid_im_high << 8); + freq_im = f54_data16.freq_im_low | + (f54_data16.freq_im_high << 8); + + fast_relax = f51_data40.fast_relax; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "delta_min = %d, " + "delta_max = %d, " + "delta_avg = %d, " + "cid_im = %d, " + "freq_im = %d, " + "noise_state = %d, " + "fast_relax = %d\n", + delta_min, delta_max, delta_avg, + cid_im, freq_im, noise_state, + fast_relax); + return; +} +#endif + +#ifdef PROXIMITY_MODE +static ssize_t synaptics_rmi4_f51_enables_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + if (!f51) + return -ENODEV; + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", + f51->proximity_enables); +} + +static ssize_t synaptics_rmi4_f51_enables_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + if (!f51) + return -ENODEV; + + if (sscanf(buf, "%x", &input) != 1) + return -EINVAL; + + f51->proximity_enables = (unsigned char)input; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + f51->proximity_enables_addr, + &f51->proximity_enables, + sizeof(f51->proximity_enables)); + if (retval < 0) { + tsp_debug_err(true, dev, "%s: Failed to write proximity enables, error = %d\n", + __func__, retval); + return retval; + } + + return count; +} +#endif + +static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int reset; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + if (sscanf(buf, "%u", &reset) != 1) + return -EINVAL; + + if (reset != 1) + return -EINVAL; + + retval = synaptics_rmi4_reset_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, dev, + "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + return retval; + } + + return count; +} + +static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n", + (rmi4_data->rmi4_mod_info.product_info[0]), + (rmi4_data->rmi4_mod_info.product_info[1])); +} + +static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int build_id; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); + + build_id = (unsigned int)rmi->build_id[0] + + (unsigned int)rmi->build_id[1] * 0x100 + + (unsigned int)rmi->build_id[2] * 0x10000; + + return snprintf(buf, PAGE_SIZE, "%u\n", + build_id); +} + +static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int retval; + struct synaptics_rmi4_f01_device_status device_status; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr, + device_status.data, + sizeof(device_status.data)); + if (retval < 0) { + tsp_debug_err(true, dev, + "%s: Failed to read device status, error = %d\n", + __func__, retval); + return retval; + } + + return snprintf(buf, PAGE_SIZE, "%u\n", + device_status.flash_prog); +} + +static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + rmi4_data->button_0d_enabled); +} + +static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + unsigned char ii; + unsigned char intr_enable; + struct synaptics_rmi4_fn *fhandler; + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + input = input > 0 ? 1 : 0; + + if (rmi4_data->button_0d_enabled == input) + return count; + + if (list_empty(&rmi->support_fn_list)) + return -ENODEV; + + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { + ii = fhandler->intr_reg_num; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr + 1 + ii, + &intr_enable, + sizeof(intr_enable)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + if (input == 1) + intr_enable |= fhandler->intr_mask; + else + intr_enable &= ~fhandler->intr_mask; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr + 1 + ii, + &intr_enable, + sizeof(intr_enable)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + } + } + + rmi4_data->button_0d_enabled = input; + + return count; +} + +/** + * synaptics_rmi4_i2c_read() + * + * Called by various functions in this driver, and also exported to + * other expansion Function modules such as rmi_dev. + * + * This function reads data of an arbitrary length from the sensor, + * starting from an assigned register address of the sensor, via I2C + * with a retry mechanism. + */ +static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, + unsigned short addr, unsigned char *data, unsigned short length) +{ + int retval; + unsigned char retry; + unsigned char buf; + unsigned char buf_page[PAGE_SELECT_LEN]; + unsigned char page; + + struct i2c_msg msg[] = { + { + .addr = rmi4_data->i2c_client->addr, + .flags = 0, + .len = PAGE_SELECT_LEN, + .buf = buf_page, + }, + { + .addr = rmi4_data->i2c_client->addr, + .flags = 0, + .len = 1, + .buf = &buf, + }, + { + .addr = rmi4_data->i2c_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + }, + }; + + page = ((addr >> 8) & MASK_8BIT); + buf_page[0] = MASK_8BIT; + buf_page[1] = page; + + buf = addr & MASK_8BIT; + + mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex)); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Sensor stopped\n", + __func__); + retval = 0; + goto exit; + } + + for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { + if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 3) == 3) { + retval = length; + break; + } + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: I2C retry %d\n", + __func__, retry + 1); + msleep(20); + } + + if (retry == SYN_I2C_RETRY_TIMES) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: I2C read over retry limit\n", + __func__); + retval = -EIO; + } + +exit: + mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex)); + + return retval; +} + +/** + * synaptics_rmi4_i2c_write() + * + * Called by various functions in this driver, and also exported to + * other expansion Function modules such as rmi_dev. + * + * This function writes data of an arbitrary length to the sensor, + * starting from an assigned register address of the sensor, via I2C with + * a retry mechanism. + */ +static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, + unsigned short addr, unsigned char *data, unsigned short length) +{ + int retval; + unsigned char retry; + unsigned char buf[length + 1]; + unsigned char buf_page[PAGE_SELECT_LEN]; + unsigned char page; + + struct i2c_msg msg[] = { + { + .addr = rmi4_data->i2c_client->addr, + .flags = 0, + .len = PAGE_SELECT_LEN, + .buf = buf_page, + }, + { + .addr = rmi4_data->i2c_client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + page = ((addr >> 8) & MASK_8BIT); + buf_page[0] = MASK_8BIT; + buf_page[1] = page; + + mutex_lock(&(rmi4_data->rmi4_io_ctrl_mutex)); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Sensor stopped\n", + __func__); + retval = 0; + goto exit; + } + + buf[0] = addr & MASK_8BIT; + memcpy(&buf[1], &data[0], length); + + for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { + if (i2c_transfer(rmi4_data->i2c_client->adapter, msg, 2) == 2) { + retval = length; + break; + } + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: I2C retry %d\n", + __func__, retry + 1); + msleep(20); + } + + if (retry == SYN_I2C_RETRY_TIMES) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: I2C write over retry limit\n", + __func__); + retval = -EIO; + } + +exit: + mutex_unlock(&(rmi4_data->rmi4_io_ctrl_mutex)); + + return retval; +} + + +/* Below function acess the register manually. so please keep caution when use this. + * I do not recommend to use this function except special case.... + * mode[0 / 1] 0: read, 1: write + */ +int synaptics_rmi4_access_register(struct synaptics_rmi4_data *rmi4_data, + bool mode, unsigned short address, int length, unsigned char *value) +{ + int retval = 0, ii = 0; + unsigned char data[10] = {0, }; + char temp[70] = {0, }; + char t_temp[7] = {0, }; + + if (mode == SYNAPTICS_ACCESS_WRITE) { + retval = synaptics_rmi4_i2c_write(rmi4_data, + address, value, length); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to write 0x%X ~ %d byte\n", + __func__, address, length); + goto out; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + address, data, length); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read 0x%04X\n", + __func__, address); + goto out; + } + snprintf(temp, 1, ":"); + while (ii < length) { + snprintf(t_temp, 7, "0x%X, ", data[ii]); + strcat(temp, t_temp); + ii++; + } + } else { + retval = synaptics_rmi4_i2c_read(rmi4_data, + address, data, length); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read 0x%04X\n", + __func__, address); + goto out; + } + memcpy(value, data, length); + + snprintf(temp, 1, ":"); + while (ii < length) { + snprintf(t_temp, 7, "0x%X, ", data[ii]); + strcat(temp, t_temp); + ii++; + } + } + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [%c]0x%04X, length:%d, data: %s\n", + __func__, mode ? 'W' : 'R', address, length, temp); + +out: + return retval; +} + +static void synaptics_rmi4_release_all_finger(struct synaptics_rmi4_data *rmi4_data) +{ + unsigned char ii; + + if (!rmi4_data->tsp_probe) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: it is not probed or f51 is null.\n", + __func__); + return; + } + + for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) { + input_mt_slot(rmi4_data->input_dev, ii); + if (rmi4_data->finger[ii].state) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "[%d][RA] 0x%02x M[%d], Ver[%02X%02X, 0x%02X, 0x%02X/0x%02X/0x%02X]\n", + ii, rmi4_data->finger[ii].state, rmi4_data->finger[ii].mcount, + rmi4_data->ic_revision_of_ic, rmi4_data->fw_version_of_ic, rmi4_data->f12.feature_enable, +#ifdef PROXIMITY_MODE + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->proximity_enables, + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->general_control, + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->general_control_2); +#else + 0, 0, 0); +#endif +#ifdef EDGE_SWIPE + input_report_abs(rmi4_data->input_dev, + ABS_MT_PALM, 0); +#endif + } + input_mt_report_slot_state(rmi4_data->input_dev, MT_TOOL_FINGER, 0); + + rmi4_data->finger[ii].state = 0; + rmi4_data->finger[ii].mcount = 0; +#ifdef USE_STYLUS + rmi4_data->finger[ii].stylus = false; +#endif + } + + input_report_key(rmi4_data->input_dev, + BTN_TOUCH, 0); + input_report_key(rmi4_data->input_dev, + BTN_TOOL_FINGER, 0); +#ifdef GLOVE_MODE + input_report_switch(rmi4_data->input_dev, + SW_GLOVE, false); + rmi4_data->touchkey_glove_mode_status = false; +#endif +#ifdef TSP_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_FORCE_OFF); +#endif + input_sync(rmi4_data->input_dev); + + rmi4_data->fingers_on_2d = false; +#ifdef PROXIMITY_MODE + rmi4_data->f51_finger = false; +#endif +#ifdef EDGE_SWIPE + if ((rmi4_data->f51 != NULL) && (rmi4_data->f51->edge_swipe_data.palm)) + rmi4_data->f51->edge_swipe_data.palm = 0; +#endif +} + +void synpatics_rmi4_release_all_event(struct synaptics_rmi4_data *rmi4_data, unsigned char type) +{ + if (type & RELEASE_TYPE_FINGER) + synaptics_rmi4_release_all_finger(rmi4_data); +} + +/** + * synaptics_rmi4_f11_abs_report() + * + * Called by synaptics_rmi4_report_touch() when valid Function $11 + * finger data has been detected. + * + * This function reads the Function $11 data registers, determines the + * status of each finger supported by the Function, processes any + * necessary coordinate manipulation, reports the finger data to + * the input subsystem, and returns the number of fingers detected. + */ +static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + unsigned char touch_count = 0; /* number of touch points */ + unsigned char reg_index; + unsigned char finger; + unsigned char fingers_supported; + unsigned char num_of_finger_status_regs; + unsigned char finger_shift; + unsigned char finger_status; + unsigned char data_reg_blk_size; + unsigned char finger_status_reg[3]; + unsigned char data[F11_STD_DATA_LEN]; + unsigned short data_addr; + unsigned short data_offset; + int x; + int y; + int wx; + int wy; + + /* + * The number of finger status registers is determined by the + * maximum number of fingers supported - 2 bits per finger. So + * the number of finger status registers to read is: + * register_count = ceil(max_num_of_fingers / 4) + */ + fingers_supported = fhandler->num_of_data_points; + num_of_finger_status_regs = (fingers_supported + 3) / 4; + data_addr = fhandler->full_addr.data_base; + data_reg_blk_size = fhandler->size_of_data_register_block; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + data_addr, + finger_status_reg, + num_of_finger_status_regs); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return 0; + } + + for (finger = 0; finger < fingers_supported; finger++) { + reg_index = finger / 4; + finger_shift = (finger % 4) * 2; + finger_status = (finger_status_reg[reg_index] >> finger_shift) + & MASK_2BIT; + + /* + * Each 2-bit finger status field represents the following: + * 00 = finger not present + * 01 = finger present and data accurate + * 10 = finger present but data may be inaccurate + * 11 = reserved + */ + input_mt_slot(rmi4_data->input_dev, finger); + input_mt_report_slot_state(rmi4_data->input_dev, + MT_TOOL_FINGER, finger_status ? true : false); + + if (finger_status) { + data_offset = data_addr + + num_of_finger_status_regs + + (finger * data_reg_blk_size); + retval = synaptics_rmi4_i2c_read(rmi4_data, + data_offset, + data, + data_reg_blk_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return 0; + } + + x = (data[0] << 4) | (data[2] & MASK_4BIT); + y = (data[1] << 4) | ((data[2] >> 4) & MASK_4BIT); + wx = (data[3] & MASK_4BIT); + wy = (data[3] >> 4) & MASK_4BIT; + + if (rmi4_data->board->x_flip) + x = rmi4_data->sensor_max_x - x; + if (rmi4_data->board->y_flip) + y = rmi4_data->sensor_max_y - y; + + input_report_key(rmi4_data->input_dev, + BTN_TOUCH, 1); + input_report_key(rmi4_data->input_dev, + BTN_TOOL_FINGER, 1); + input_report_abs(rmi4_data->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(rmi4_data->input_dev, + ABS_MT_POSITION_Y, y); +#ifdef REPORT_2D_W + input_report_abs(rmi4_data->input_dev, + ABS_MT_TOUCH_MAJOR, max(wx, wy)); + input_report_abs(rmi4_data->input_dev, + ABS_MT_TOUCH_MINOR, min(wx, wy)); +#endif + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Finger %d:\n" + "status = 0x%02x\n" + "x = %d\n" + "y = %d\n" + "wx = %d\n" + "wy = %d\n", + __func__, finger, + finger_status, + x, y, wx, wy); + + touch_count++; + } + } + input_sync(rmi4_data->input_dev); + + return touch_count; +} + +/** + * synaptics_rmi4_f12_abs_report() + * + * Called by synaptics_rmi4_report_touch() when valid Function $12 + * finger data has been detected. + * + * This function reads the Function $12 data registers, determines the + * status of each finger supported by the Function, processes any + * necessary coordinate manipulation, reports the finger data to + * the input subsystem, and returns the number of fingers detected. + */ +static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + unsigned char touch_count = 0; + unsigned char finger; + unsigned char fingers_to_process; + unsigned char finger_status; + unsigned char size_of_2d_data; + unsigned short data_addr; + int x; + int y; + int wx; + int wy; + int x_y_tmp; +#ifdef REPORT_2D_Z + int z = 0; +#endif + struct synaptics_rmi4_f12_extra_data *extra_data; + struct synaptics_rmi4_f12_finger_data *data; + struct synaptics_rmi4_f12_finger_data *finger_data; + bool new_finger_pressed = false; +#ifdef EDGE_SWIPE + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; +#endif + unsigned char tool_type = MT_TOOL_FINGER; +#ifdef PRINT_DEBUG_INFO + bool print_debug_info = false; +#endif + + fingers_to_process = fhandler->num_of_data_points; + data_addr = fhandler->full_addr.data_base; + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; + size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); + + /* Determine the total number of fingers to process */ + if (extra_data->data15_size) { + unsigned short object_attention = 0; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + data_addr + extra_data->data15_offset, + extra_data->data15_data, + extra_data->data15_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return 0; + } + + /* Object_attention : [000000xx xxxxxxxxx] : "x" represent that finger is on or not + * Get the highest finger number to read finger data efficently. + */ + object_attention = extra_data->data15_data[0]; + if (extra_data->data15_size > 1) + object_attention |= (extra_data->data15_data[1] & MASK_3BIT) << 8; + + for (; fingers_to_process > 0; fingers_to_process--) { + if (object_attention & (1 << (fingers_to_process - 1))) + break; + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "fingers[%d, %d] object_attention[0x%02x]\n", + fingers_to_process, rmi4_data->fingers_already_present, object_attention); + } + + fingers_to_process = max(fingers_to_process, rmi4_data->fingers_already_present); + + if (!fingers_to_process) { + synaptics_rmi4_release_all_finger(rmi4_data); + return 0; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + data_addr + extra_data->data1_offset, + (unsigned char *)fhandler->data, + fingers_to_process * size_of_2d_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return 0; + } + data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data; + + for (finger = 0; finger < fingers_to_process; finger++) { + finger_data = data + finger; + finger_status = (finger_data->object_type_and_status & MASK_3BIT); + x = (finger_data->x_msb << 8) | (finger_data->x_lsb); + y = (finger_data->y_msb << 8) | (finger_data->y_lsb); + if ((x == INVALID_X) && (y == INVALID_Y)) + finger_status = OBJECT_NOT_PRESENT; + + if ((x > rmi4_data->sensor_max_x) || (y > rmi4_data->sensor_max_y) || finger_status == OBJECT_UNCLASSIFIED) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "[%d][%d] 0x%02x [%d:%d], Ver[%02X%02X]\n", + finger, rmi4_data->board->device_num, finger_status, x, y, rmi4_data->ic_revision_of_ic, rmi4_data->fw_version_of_ic); + finger_status = OBJECT_NOT_PRESENT; + } + +#ifdef USE_STYLUS + tool_type = MT_TOOL_FINGER; + rmi4_data->finger[finger].stylus = false; + + if (finger_status == OBJECT_PASSIVE_STYLUS && rmi4_data->use_stylus) { + tool_type = MT_TOOL_PEN; + rmi4_data->finger[finger].stylus = true; + } +#endif + input_mt_slot(rmi4_data->input_dev, finger); + input_mt_report_slot_state(rmi4_data->input_dev, tool_type, finger_status ? true : false); + + if (finger_status != OBJECT_NOT_PRESENT) { + rmi4_data->fingers_already_present = finger + 1; +#ifdef GLOVE_MODE + if ((finger_status == OBJECT_GLOVE || finger_status == OBJECT_PASSIVE_STYLUS) + && !rmi4_data->touchkey_glove_mode_status) { + rmi4_data->touchkey_glove_mode_status = true; + input_report_switch(rmi4_data->input_dev, SW_GLOVE, true); + } + if ((finger_status != OBJECT_GLOVE && finger_status != OBJECT_PASSIVE_STYLUS) + && rmi4_data->touchkey_glove_mode_status) { + rmi4_data->touchkey_glove_mode_status = false; + input_report_switch(rmi4_data->input_dev, SW_GLOVE, false); + } +#endif +#ifdef REPORT_2D_W + wx = finger_data->wx; + wy = finger_data->wy; +#endif +#ifdef REPORT_2D_Z + z = finger_data->z; +#endif + +#ifdef EDGE_SWIPE + if (f51) { +#if !defined(CONFIG_SEC_FACTORY) + if (f51->proximity_controls & HAS_EDGE_SWIPE) { + if (finger_status == OBJECT_PALM) { + wx = f51->edge_swipe_data.wx; + wy = f51->edge_swipe_data.wy; + } + input_report_abs(rmi4_data->input_dev, + ABS_MT_PALM, f51->edge_swipe_data.palm); + } +#endif + } +#endif + if (rmi4_data->board->x_flip) + x = rmi4_data->sensor_max_x - x; + if (rmi4_data->board->y_flip) + y = rmi4_data->sensor_max_y - y; + if (rmi4_data->board->x_y_chnage) { + x_y_tmp = x; + x = y; + y = x_y_tmp; + } + + if (rmi4_data->board->x_offset) { + x = x - rmi4_data->board->x_offset; + } + + input_report_key(rmi4_data->input_dev, + BTN_TOUCH, finger_status == OBJECT_HOVER ? 0 : 1); + input_report_key(rmi4_data->input_dev, + BTN_TOOL_FINGER, 1); + input_report_abs(rmi4_data->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(rmi4_data->input_dev, + ABS_MT_POSITION_Y, y); +#ifdef REPORT_2D_W + input_report_abs(rmi4_data->input_dev, + ABS_MT_TOUCH_MAJOR, max(wx, wy)); + input_report_abs(rmi4_data->input_dev, + ABS_MT_TOUCH_MINOR, min(wx, wy)); +#ifdef REPORT_2D_Z + input_report_abs(rmi4_data->input_dev, + ABS_MT_PRESSURE, z); +#endif + +#ifdef REPORT_ORIENTATION + input_report_abs(rmi4_data->input_dev, + ABS_MT_ORIENTATION, (wx > wy) ? 1 : 0); +#endif +#endif + if (rmi4_data->finger[finger].state) { + rmi4_data->finger[finger].mcount++; + if (rmi4_data->finger[finger].state != finger_status) + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "[%d][C][%d] 0x%02x T[%d/%u] M[%d]" +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +#ifdef REPORT_2D_Z + ", x = %d, y = %d, wx = %d, wy = %d, z = %d\n", finger, rmi4_data->board->device_num, finger_status, tool_type, + rmi4_data->use_stylus, rmi4_data->finger[finger].mcount, x, y, wx, wy, z); +#else + ", x = %d, y = %d, wx = %d, wy = %d\n", finger, rmi4_data->board->device_num, finger_status, tool_type, + rmi4_data->use_stylus, rmi4_data->finger[finger].mcount, x, y, wx, wy); +#endif +#else + "\n", finger, rmi4_data->board->device_num, finger_status, tool_type, rmi4_data->use_stylus, + rmi4_data->finger[finger].mcount); +#endif + } else { + new_finger_pressed = true; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "[%d][P][%d] 0x%02x T[%d/%u]" +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +#ifdef REPORT_2D_Z + ", x = %d, y = %d, wx = %d, wy = %d, z = %d\n", finger, rmi4_data->board->device_num, finger_status, tool_type, + rmi4_data->use_stylus, x, y, wx, wy, z); +#else + ", x = %d, y = %d, wx = %d, wy = %d\n", finger, rmi4_data->board->device_num, finger_status, tool_type, + rmi4_data->use_stylus, x, y, wx, wy); +#endif +#else + "\n", finger, rmi4_data->board->device_num, finger_status, tool_type, rmi4_data->use_stylus); +#endif +#ifdef PRINT_DEBUG_INFO + print_debug_info = true; +#endif + } + touch_count++; + + } else { + if (rmi4_data->finger[finger].state) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "[%d][R][%d] 0x%02x M[%d], Ver[%02X%02X, 0x%02X, 0x%02X/0x%02X/0x%02X]\n", + finger, rmi4_data->board->device_num, finger_status, rmi4_data->finger[finger].mcount, + rmi4_data->ic_revision_of_ic, rmi4_data->fw_version_of_ic, rmi4_data->f12.feature_enable, +#ifdef PROXIMITY_MODE + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->proximity_enables, + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->general_control, + rmi4_data->f51 == NULL ? 0 : rmi4_data->f51->general_control_2); +#else + 0, 0, 0); +#endif + + rmi4_data->finger[finger].mcount = 0; +#ifdef PRINT_DEBUG_INFO + print_debug_info = true; +#endif + } + } + + rmi4_data->finger[finger].state = finger_status; + } + + /* Clear BTN_TOUCH when All touch are released */ + if (touch_count == 0) { + input_report_key(rmi4_data->input_dev, BTN_TOUCH, 0); + rmi4_data->fingers_already_present = 0; + } + + input_sync(rmi4_data->input_dev); + +#ifdef PRINT_DEBUG_INFO + if(print_debug_info) + print_debug_log(rmi4_data); +#endif + +#ifdef TSP_BOOSTER + if (new_finger_pressed) + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_ON); + if (!touch_count) + input_booster_send_event(BOOSTER_DEVICE_TOUCH, BOOSTER_MODE_OFF); +#endif + return touch_count; +} + +static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + unsigned char touch_count = 0; + unsigned char button; + unsigned char index; + unsigned char shift; + unsigned char status; + unsigned char *data; + unsigned short data_addr = fhandler->full_addr.data_base; + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; + static unsigned char do_once = 1; + static bool current_status[MAX_NUMBER_OF_BUTTONS]; +#ifdef NO_0D_WHILE_2D + static bool before_2d_status[MAX_NUMBER_OF_BUTTONS]; + static bool while_2d_status[MAX_NUMBER_OF_BUTTONS]; +#endif + + if (do_once) { + memset(current_status, 0, sizeof(current_status)); +#ifdef NO_0D_WHILE_2D + memset(before_2d_status, 0, sizeof(before_2d_status)); + memset(while_2d_status, 0, sizeof(while_2d_status)); +#endif + do_once = 0; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + data_addr, + f1a->button_data_buffer, + f1a->button_bitmask_size); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read button data registers\n", + __func__); + return; + } + + data = f1a->button_data_buffer; + + for (button = 0; button < f1a->valid_button_count; button++) { + index = button / 8; + shift = button % 8; + status = ((data[index] >> shift) & MASK_1BIT); + + if (current_status[button] == status) + continue; + else + current_status[button] = status; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Button %d (code %d) ->%d\n", + __func__, button, + f1a->button_map[button], + status); +#ifdef NO_0D_WHILE_2D + if (rmi4_data->fingers_on_2d == false) { + if (status == 1) { + before_2d_status[button] = 1; + } else { + if (while_2d_status[button] == 1) { + while_2d_status[button] = 0; + continue; + } else { + before_2d_status[button] = 0; + } + } + touch_count++; + input_report_key(rmi4_data->input_dev, + f1a->button_map[button], + status); + } else { + if (before_2d_status[button] == 1) { + before_2d_status[button] = 0; + touch_count++; + input_report_key(rmi4_data->input_dev, + f1a->button_map[button], + status); + } else { + if (status == 1) + while_2d_status[button] = 1; + else + while_2d_status[button] = 0; + } + } +#else + touch_count++; + input_report_key(rmi4_data->input_dev, + f1a->button_map[button], + status); +#endif + } + + if (touch_count) + input_sync(rmi4_data->input_dev); + + return; +} + +#ifdef PROXIMITY_MODE +#ifdef EDGE_SWIPE +static int synaptics_rmi4_f51_edge_swipe(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval = 0; + struct synaptics_rmi4_f51_data *data; + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + if (!(f51->general_control & EDGE_SWIPE_EN)) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s : Edge swipe report is disabled. General control[0x%02x]\n", + __func__, f51->general_control); + goto out; + } + + data = (struct synaptics_rmi4_f51_data *)fhandler->data; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + f51->edge_swipe_data_addr, + data->edge_swipe_data, + sizeof(data->edge_swipe_data)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + goto out; + } + + f51->edge_swipe_data.sumsize = data->edge_swipe_mm; + f51->edge_swipe_data.wx = data->edge_swipe_wx; + f51->edge_swipe_data.wy = data->edge_swipe_wy; + f51->edge_swipe_data.palm = data->edge_swipe_z; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: edge_data : x[%d], y[%d], z[%d] ,wx[%d], wy[%d], area[%d]\n", __func__, + data->edge_swipe_x_msb << 8 | data->edge_swipe_x_lsb, + data->edge_swipe_y_msb << 8 | data->edge_swipe_y_lsb, + data->edge_swipe_z, data->edge_swipe_wx, data->edge_swipe_wy, + data->edge_swipe_mm); + +out: + return retval; +} +#endif + +static int synaptics_rmi4_f51_lookup_detection_flag_2(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval = 0; + +#ifdef EDGE_SWIPE + retval = synaptics_rmi4_f51_edge_swipe(rmi4_data, fhandler); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read edge swipe data\n", + __func__); + goto out; + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: edge_swipe_detected : sumsize[%d], palm[%d], wx[%d] ,wy[%d]\n", + __func__, rmi4_data->f51->edge_swipe_data.sumsize, + rmi4_data->f51->edge_swipe_data.palm, rmi4_data->f51->edge_swipe_data.wx, + rmi4_data->f51->edge_swipe_data.wy); +out: +#endif + return retval; +} + +static void synaptics_rmi4_f51_report(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + if (f51->proximity_controls & HAS_EDGE_SWIPE) { + retval = synaptics_rmi4_f51_lookup_detection_flag_2(rmi4_data, fhandler); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to treat proximity data\n", + __func__); + return; + } + } + + return; +} +#endif + +/** + * synaptics_rmi4_report_touch() + * + * Called by synaptics_rmi4_sensor_report(). + * + * This function calls the appropriate finger data reporting function + * based on the function handler it receives and returns the number of + * fingers detected. + */ +static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + unsigned char touch_count_2d; + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Function %02x reporting\n", + __func__, fhandler->fn_number); + + switch (fhandler->fn_number) { + case SYNAPTICS_RMI4_F11: + touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data, + fhandler); + if (touch_count_2d) + rmi4_data->fingers_on_2d = true; + else + rmi4_data->fingers_on_2d = false; + break; + case SYNAPTICS_RMI4_F12: + touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data, + fhandler); + if (touch_count_2d) + rmi4_data->fingers_on_2d = true; + else + rmi4_data->fingers_on_2d = false; + break; + case SYNAPTICS_RMI4_F1A: + synaptics_rmi4_f1a_report(rmi4_data, fhandler); + break; +#ifdef PROXIMITY_MODE + case SYNAPTICS_RMI4_F51: + synaptics_rmi4_f51_report(rmi4_data, fhandler); + break; +#endif + default: + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Undefined RMI function number[0X%02X]\n", + __func__, fhandler->fn_number); + break; + } + + return; +} + +/** + * synaptics_rmi4_sensor_report() + * + * Called by synaptics_rmi4_irq(). + * + * This function determines the interrupt source(s) from the sensor + * and calls synaptics_rmi4_report_touch() with the appropriate + * function handler for each function with valid data inputs. + */ +static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char data[MAX_INTR_REGISTERS + 1]; + unsigned char *intr = &data[1]; + struct synaptics_rmi4_f01_device_status status; + struct synaptics_rmi4_fn *fhandler; + struct synaptics_rmi4_exp_fn *exp_fhandler; + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); + + /* + * Get interrupt status information from F01 Data1 register to + * determine the source(s) that are flagging the interrupt. + */ + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr, + data, + rmi4_data->num_of_intr_regs + 1); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read interrupt status\n", + __func__); + return retval; + } + + status.data[0] = data[0]; + if (status.unconfigured) { + if (rmi4_data->doing_reflash) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "Spontaneous reset detected during reflash.\n"); + return 0; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "Spontaneous reset detected\n"); + retval = synaptics_rmi4_reinit_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to reinit device\n", + __func__); + } + return 0; + } + + /* + * Traverse the function handler list and service the source(s) + * of the interrupt accordingly. + */ + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->num_of_data_sources) { + if (fhandler->intr_mask & + intr[fhandler->intr_reg_num]) { + synaptics_rmi4_report_touch(rmi4_data, + fhandler); + } + } + } + } + + if (!list_empty(&rmi->exp_fn_list)) { + list_for_each_entry(exp_fhandler, &rmi->exp_fn_list, link) { + if (exp_fhandler->initialized && + (exp_fhandler->func_attn != NULL)) + exp_fhandler->func_attn(rmi4_data, intr[0]); + } + } + + return 0; +} + +/** + * synaptics_rmi4_irq() + * + * Called by the kernel when an interrupt occurs (when the sensor + * asserts the attention irq). + * + * This function is the ISR thread and handles the acquisition + * and the reporting of finger data when the presence of fingers + * is detected. + */ +static irqreturn_t synaptics_rmi4_irq(int irq, void *data) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data = data; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + do { + retval = synaptics_rmi4_sensor_report(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read", + __func__); + goto out; + } + + if (rmi4_data->touch_stopped) + goto out; + + } while (!gpio_get_value(pdata->gpio)); + +out: + return IRQ_HANDLED; +} + +/** + * synaptics_rmi4_irq_enable() + * + * Called by synaptics_rmi4_probe() and the power management functions + * in this driver and also exported to other expansion Function modules + * such as rmi_dev. + * + * This function handles the enabling and disabling of the attention + * irq including the setting up of the ISR thread. + */ +static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data, + bool enable) +{ + int retval = 0; + unsigned char intr_status[MAX_INTR_REGISTERS]; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + if (enable) { + if (rmi4_data->irq_enabled) + return retval; + + /* Clear interrupts first */ + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr + 1, + intr_status, + rmi4_data->num_of_intr_regs); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + retval = request_threaded_irq(rmi4_data->irq, NULL, + synaptics_rmi4_irq, pdata->irq_type, + DRIVER_NAME, rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to create irq thread\n", + __func__); + return retval; + } + + rmi4_data->irq_enabled = true; + } else { + if (rmi4_data->irq_enabled) { + disable_irq(rmi4_data->irq); + free_irq(rmi4_data->irq, rmi4_data); + rmi4_data->irq_enabled = false; + } + } + + return retval; +} + +/** + * synaptics_rmi4_f11_init() + * + * Called by synaptics_rmi4_query_device(). + * + * This funtion parses information from the Function 11 registers + * and determines the number of fingers supported, x and y data ranges, + * offset to the associated interrupt status register, interrupt bit + * mask, and gathers finger data acquisition capabilities from the query + * registers. + */ +static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler, + struct synaptics_rmi4_fn_desc *fd, + unsigned int intr_count) +{ + int retval; + unsigned char ii; + unsigned char intr_offset; + unsigned char abs_data_size; + unsigned char abs_data_blk_size; + unsigned char query[F11_STD_QUERY_LEN]; + unsigned char control[F11_STD_CTRL_LEN]; + + fhandler->fn_number = fd->fn_number; + fhandler->num_of_data_sources = fd->intr_src_count; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base, + query, + sizeof(query)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* Maximum number of fingers supported */ + if ((query[1] & MASK_3BIT) <= 4) + fhandler->num_of_data_points = (query[1] & MASK_3BIT) + 1; + else if ((query[1] & MASK_3BIT) == 5) + fhandler->num_of_data_points = 10; + + rmi4_data->num_of_fingers = fhandler->num_of_data_points; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base, + control, + sizeof(control)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* Maximum x and y */ + rmi4_data->sensor_max_x = ((control[6] & MASK_8BIT) << 0) | + ((control[7] & MASK_4BIT) << 8); + rmi4_data->sensor_max_y = ((control[8] & MASK_8BIT) << 0) | + ((control[9] & MASK_4BIT) << 8); + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Function %02x max x = %d max y = %d\n", + __func__, fhandler->fn_number, + rmi4_data->sensor_max_x, + rmi4_data->sensor_max_y); + if (rmi4_data->sensor_max_x <= 0 || rmi4_data->sensor_max_y <= 0) { + rmi4_data->sensor_max_x = rmi4_data->board->sensor_max_x; + rmi4_data->sensor_max_y = rmi4_data->board->sensor_max_y; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Function %02x read failed, run dtsi coords. max x = %d max y = %d\n", + __func__, fhandler->fn_number, + rmi4_data->sensor_max_x, + rmi4_data->sensor_max_y); + } + + rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH; + + fhandler->intr_reg_num = (intr_count + 7) / 8; + if (fhandler->intr_reg_num != 0) + fhandler->intr_reg_num -= 1; + + /* Set an enable bit for each data source */ + intr_offset = intr_count % 8; + fhandler->intr_mask = 0; + for (ii = intr_offset; ii < ((fd->intr_src_count & MASK_3BIT) + intr_offset); ii++) + fhandler->intr_mask |= 1 << ii; + + abs_data_size = query[5] & MASK_2BIT; + abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0)); + fhandler->size_of_data_register_block = abs_data_blk_size; + fhandler->data = NULL; + fhandler->extra = NULL; + + return retval; +} + +int synaptics_rmi4_f12_ctrl11_set(struct synaptics_rmi4_data *rmi4_data, + unsigned char data) +{ + struct synaptics_rmi4_f12_ctrl_11 ctrl_11; + + int retval; + + if (rmi4_data->touch_stopped) + return 0; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f12.ctrl11_addr, + ctrl_11.data, + sizeof(ctrl_11.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + ctrl_11.data[2] = data; /* set a value of jitter filter */ + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f12.ctrl11_addr, + ctrl_11.data, + sizeof(ctrl_11.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + return 0; +} + +static int synaptics_rmi4_f12_set_feature(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + + if (!rmi4_data->f12.glove_mode_feature) + goto out; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f12.ctrl26_addr, + &rmi4_data->f12.feature_enable, + sizeof(rmi4_data->f12.feature_enable)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: write fail[%d]\n", + __func__, retval); + goto out; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [0x%02X], Set %s\n", + __func__, rmi4_data->f12.feature_enable, + (rmi4_data->f12.feature_enable == (CLEAR_COVER_MODE_EN | FAST_GLOVE_DECTION_EN)) ? "Clear cover & Fast glove mode" : + (rmi4_data->f12.feature_enable == (FLIP_COVER_MODE_EN | FAST_GLOVE_DECTION_EN)) ? "Flip cover & Fast glove mode" : + (rmi4_data->f12.feature_enable == (GLOVE_DETECTION_EN | FAST_GLOVE_DECTION_EN)) ? "Fast glove mode" : + (rmi4_data->f12.feature_enable == CLEAR_COVER_MODE_EN) ? "Clear cover" : + (rmi4_data->f12.feature_enable == FLIP_COVER_MODE_EN) ? "Flip cover" : + (rmi4_data->f12.feature_enable == GLOVE_DETECTION_EN) ? "Glove mode" : "All disabled"); + +out: + return retval; +} + +static int synaptics_rmi4_f12_set_report(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f12.ctrl28_addr, + &rmi4_data->f12.report_enable, + sizeof(rmi4_data->f12.report_enable)); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: write fail[%d]\n", + __func__, retval); + + return retval; +} + +#ifdef GLOVE_MODE +static int synaptics_rmi4_f12_obj_report_enable(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f12.ctrl23_addr, + &rmi4_data->f12.obj_report_enable, + sizeof(rmi4_data->f12.obj_report_enable)); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: write fail[%d]\n", + __func__, retval); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [0x%02X], Glove mode %s\n", + __func__, rmi4_data->f12.obj_report_enable, + (rmi4_data->f12.obj_report_enable & OBJ_TYPE_GLOVE) ? "enabled" : "disabled"); + + return retval; +} + +int synaptics_rmi4_glove_mode_enables(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + + if (!rmi4_data->f12.glove_mode_feature) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Ver[%02X%02X%02X] FW does not support glove mode %02X\n", + __func__, rmi4_data->panel_revision, rmi4_data->ic_revision_of_ic, + rmi4_data->fw_version_of_ic, rmi4_data->f12.glove_mode_feature); + goto out; + } + + if (rmi4_data->touch_stopped) + goto out; + + retval = synaptics_rmi4_f12_set_feature(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + } + + retval = synaptics_rmi4_f12_obj_report_enable(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + } + + +out: + return retval; +} +#endif + +static int synaptics_rmi4_f12_set_init(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + + retval = synaptics_rmi4_f12_set_feature(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, Failed to set featrue. [%d]\n", + __func__, retval); + goto out; + } + + if(rmi4_data->f12.obj_report_enable == 0) { + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f12.ctrl23_addr, + &rmi4_data->f12.obj_report_enable, + sizeof(rmi4_data->f12.obj_report_enable)); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: obj_report_enable default val[0x%x]\n", + __func__, rmi4_data->f12.obj_report_enable); + } + +#ifdef GLOVE_MODE + retval = synaptics_rmi4_f12_obj_report_enable(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s, Failed to set object. [%d]\n", + __func__, retval); + goto out; + } +#endif + + retval = synaptics_rmi4_f12_set_report(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to set report. [%d]\n", + __func__, retval); + goto out; + } + +out: + return retval; +} + +/** + * synaptics_rmi4_f12_init() + * + * Called by synaptics_rmi4_query_device(). + * + * This funtion parses information from the Function 12 registers and + * determines the number of fingers supported, offset to the data1 + * register, x and y data ranges, offset to the associated interrupt + * status register, interrupt bit mask, and allocates memory resources + * for finger data acquisition. + */ +static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler, + struct synaptics_rmi4_fn_desc *fd, + unsigned int intr_count) +{ + int retval; + unsigned char ii; + unsigned char intr_offset; + unsigned char size_of_2d_data; + unsigned char size_of_query8; + unsigned char ctrl_8_offset; + unsigned char ctrl_9_offset; + unsigned char ctrl_11_offset; + unsigned char ctrl_15_offset; + unsigned char ctrl_23_offset; + unsigned char ctrl_26_offset; + unsigned char ctrl_28_offset; + struct synaptics_rmi4_f12_extra_data *extra_data; + struct synaptics_rmi4_f12_query_5 query_5; + struct synaptics_rmi4_f12_query_8 query_8; + struct synaptics_rmi4_f12_query_10 query_10; + struct synaptics_rmi4_f12_ctrl_8 ctrl_8; + struct synaptics_rmi4_f12_ctrl_9 ctrl_9; + struct synaptics_rmi4_f12_ctrl_23 ctrl_23; + + fhandler->fn_number = fd->fn_number; + fhandler->num_of_data_sources = fd->intr_src_count; + fhandler->extra = kzalloc(sizeof(*extra_data), GFP_KERNEL); + extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; + size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base + 5, + query_5.data, + sizeof(query_5.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + ctrl_8_offset = query_5.ctrl0_is_present + + query_5.ctrl1_is_present + + query_5.ctrl2_is_present + + query_5.ctrl3_is_present + + query_5.ctrl4_is_present + + query_5.ctrl5_is_present + + query_5.ctrl6_is_present + + query_5.ctrl7_is_present; + + ctrl_9_offset = ctrl_8_offset + + query_5.ctrl8_is_present; + + ctrl_11_offset = ctrl_9_offset + + query_5.ctrl9_is_present + + query_5.ctrl10_is_present; + + ctrl_15_offset = ctrl_11_offset + + query_5.ctrl11_is_present + + query_5.ctrl12_is_present + + query_5.ctrl13_is_present + + query_5.ctrl14_is_present; + + ctrl_23_offset = ctrl_15_offset + + query_5.ctrl15_is_present + + query_5.ctrl16_is_present + + query_5.ctrl17_is_present + + query_5.ctrl18_is_present + + query_5.ctrl19_is_present + + query_5.ctrl20_is_present + + query_5.ctrl21_is_present + + query_5.ctrl22_is_present; + + ctrl_26_offset = ctrl_23_offset + + query_5.ctrl23_is_present + + query_5.ctrl24_is_present + + query_5.ctrl25_is_present; + + ctrl_28_offset = ctrl_26_offset + + query_5.ctrl26_is_present + + query_5.ctrl27_is_present; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base + ctrl_23_offset, + ctrl_23.data, + sizeof(ctrl_23.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* Maximum number of fingers supported */ + fhandler->num_of_data_points = min(ctrl_23.max_reported_objects, + (unsigned char)F12_FINGERS_TO_SUPPORT); + + rmi4_data->num_of_fingers = fhandler->num_of_data_points; + /* for protection num of finger is going to zero value */ + if (!rmi4_data->num_of_fingers) + rmi4_data->num_of_fingers = MAX_NUMBER_OF_FINGERS; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base + 7, + &size_of_query8, + sizeof(size_of_query8)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base + 8, + query_8.data, + size_of_query8); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* Determine the presence of the Data0 register */ + extra_data->data1_offset = query_8.data0_is_present; + + if ((size_of_query8 >= 3) && (query_8.data15_is_present)) { + extra_data->data15_offset = query_8.data0_is_present + + query_8.data1_is_present + + query_8.data2_is_present + + query_8.data3_is_present + + query_8.data4_is_present + + query_8.data5_is_present + + query_8.data6_is_present + + query_8.data7_is_present + + query_8.data8_is_present + + query_8.data9_is_present + + query_8.data10_is_present + + query_8.data11_is_present + + query_8.data12_is_present + + query_8.data13_is_present + + query_8.data14_is_present; + extra_data->data15_size = (rmi4_data->num_of_fingers + 7) / 8; + } else { + extra_data->data15_size = 0; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base + 10, + query_10.data, + sizeof(query_10.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s:%4d read fail[%d]\n", + __func__, __LINE__, retval); + return retval; + } +/* + * Set f12 control register address. + * control register address : cntrol base register address + offset + */ + rmi4_data->f12.ctrl11_addr = fhandler->full_addr.ctrl_base + ctrl_11_offset; + rmi4_data->f12.ctrl15_addr = fhandler->full_addr.ctrl_base + ctrl_15_offset; + rmi4_data->f12.ctrl23_addr = fhandler->full_addr.ctrl_base + ctrl_23_offset; + rmi4_data->f12.ctrl26_addr = fhandler->full_addr.ctrl_base + ctrl_26_offset; + rmi4_data->f12.ctrl28_addr = fhandler->full_addr.ctrl_base + ctrl_28_offset; +#ifdef GLOVE_MODE + rmi4_data->f12.glove_mode_feature = query_10.glove_mode_feature; +#endif + rmi4_data->f12.report_enable = RPT_DEFAULT; +// rmi4_data->f12.obj_report_enable = OBJ_TYPE_DEFAULT; /* depend on models */ +#ifdef REPORT_2D_Z + rmi4_data->f12.report_enable |= RPT_Z; +#endif +#ifdef REPORT_2D_W + rmi4_data->f12.report_enable |= (RPT_WX | RPT_WY); +#endif +#ifdef REPORT_2D_Z + rmi4_data->f12.report_enable |= RPT_Z; +#endif + + retval = synaptics_rmi4_f12_set_init(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to int F12. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base + ctrl_8_offset, + ctrl_8.data, + sizeof(ctrl_8.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* Maximum x and y */ + rmi4_data->sensor_max_x = + ((unsigned short)ctrl_8.max_x_coord_lsb << 0) | + ((unsigned short)ctrl_8.max_x_coord_msb << 8); + rmi4_data->sensor_max_y = + ((unsigned short)ctrl_8.max_y_coord_lsb << 0) | + ((unsigned short)ctrl_8.max_y_coord_msb << 8); + if (rmi4_data->sensor_max_x <= 0 || rmi4_data->sensor_max_y <= 0) { + rmi4_data->sensor_max_x = rmi4_data->board->sensor_max_x; + rmi4_data->sensor_max_y = rmi4_data->board->sensor_max_y; + } + + if (ctrl_8.num_of_rx) + rmi4_data->num_of_rx = ctrl_8.num_of_rx; + if (ctrl_8.num_of_tx) + rmi4_data->num_of_tx = ctrl_8.num_of_tx; + + if (rmi4_data->num_of_rx != rmi4_data->board->num_of_rx + || rmi4_data->num_of_tx != rmi4_data->board->num_of_tx) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Num of rx/tx is not matched. IC(%d,%d) != DT(%d,%d)\n", + __func__, rmi4_data->num_of_rx, rmi4_data->num_of_tx, + rmi4_data->board->num_of_rx, rmi4_data->board->num_of_tx); + + rmi4_data->max_touch_width = max(rmi4_data->num_of_rx, + rmi4_data->num_of_tx); + rmi4_data->num_of_node = ctrl_8.num_of_rx * ctrl_8.num_of_tx; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base + ctrl_9_offset, + ctrl_9.data, + sizeof(ctrl_9.data)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: %02x max_x,y(%d,%d) num_Rx,Tx(%d,%d), num_finger(%d), node:%d, threshold:%d, gloved sensitivity:%x\n", + __func__, fhandler->fn_number, + rmi4_data->sensor_max_x, rmi4_data->sensor_max_y, + rmi4_data->num_of_rx, rmi4_data->num_of_tx, + rmi4_data->num_of_fingers, + rmi4_data->num_of_node, ctrl_9.touch_threshold, + ctrl_9.gloved_finger); + + fhandler->intr_reg_num = (intr_count + 7) / 8; + if (fhandler->intr_reg_num != 0) + fhandler->intr_reg_num -= 1; + + /* Set an enable bit for each data source */ + intr_offset = intr_count % 8; + fhandler->intr_mask = 0; + for (ii = intr_offset; ii < ((fd->intr_src_count & MASK_3BIT) + intr_offset); ii++) + fhandler->intr_mask |= 1 << ii; + + /* Allocate memory for finger data storage space */ + fhandler->data_size = rmi4_data->num_of_fingers * size_of_2d_data; + fhandler->data = kzalloc(fhandler->data_size, GFP_KERNEL); + + return retval; +} + +static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + struct synaptics_rmi4_f1a_handle *f1a; + + f1a = kzalloc(sizeof(*f1a), GFP_KERNEL); + if (!f1a) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for function handle\n", + __func__); + return -ENOMEM; + } + + fhandler->data = (void *)f1a; + fhandler->extra = NULL; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base, + f1a->button_query.data, + sizeof(f1a->button_query.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read query registers\n", + __func__); + return retval; + } + + f1a->max_count = f1a->button_query.max_button_count + 1; + + f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL); + if (!f1a->button_control.txrx_map) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for tx rx mapping\n", + __func__); + return -ENOMEM; + } + + f1a->button_bitmask_size = (f1a->max_count + 7) / 8; + + f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size, + sizeof(*(f1a->button_data_buffer)), GFP_KERNEL); + if (!f1a->button_data_buffer) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for data buffer\n", + __func__); + return -ENOMEM; + } + + f1a->button_map = kcalloc(f1a->max_count, + sizeof(*(f1a->button_map)), GFP_KERNEL); + if (!f1a->button_map) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for button map\n", + __func__); + return -ENOMEM; + } + + return 0; +} + +static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + unsigned char ii; + unsigned char mapping_offset = 0; + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + mapping_offset = f1a->button_query.has_general_control + + f1a->button_query.has_interrupt_enable + + f1a->button_query.has_multibutton_select; + + if (f1a->button_query.has_tx_rx_map) { + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base + mapping_offset, + f1a->button_control.txrx_map, + sizeof(f1a->button_control.txrx_map)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read tx rx mapping\n", + __func__); + return retval; + } + + rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map; + } + + if (!pdata->f1a_button_map) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: f1a_button_map is NULL in board file\n", + __func__); + return -ENODEV; + } else if (!pdata->f1a_button_map->map) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Button map is missing in board file\n", + __func__); + return -ENODEV; + } else { + if (pdata->f1a_button_map->nbuttons != f1a->max_count) { + f1a->valid_button_count = min(f1a->max_count, + pdata->f1a_button_map->nbuttons); + } else { + f1a->valid_button_count = f1a->max_count; + } + + for (ii = 0; ii < f1a->valid_button_count; ii++) + f1a->button_map[ii] = pdata->f1a_button_map->map[ii]; + } + + return 0; +} + +static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler) +{ + struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; + + if (f1a) { + kfree(f1a->button_control.txrx_map); + kfree(f1a->button_data_buffer); + kfree(f1a->button_map); + kfree(f1a); + fhandler->data = NULL; + } + + return; +} + +static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler, + struct synaptics_rmi4_fn_desc *fd, + unsigned int intr_count) +{ + int retval; + unsigned char ii; + unsigned short intr_offset; + + fhandler->fn_number = fd->fn_number; + fhandler->num_of_data_sources = fd->intr_src_count; + + fhandler->intr_reg_num = (intr_count + 7) / 8; + if (fhandler->intr_reg_num != 0) + fhandler->intr_reg_num -= 1; + + /* Set an enable bit for each data source */ + intr_offset = intr_count % 8; + fhandler->intr_mask = 0; + for (ii = intr_offset; ii < ((fd->intr_src_count & MASK_3BIT) + intr_offset); ii++) + fhandler->intr_mask |= 1 << ii; + + retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Fail to alloc mem. error = %d\n", + __func__, retval); + goto error_exit; + } + retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to make button map. error = %d\n", + __func__, __LINE__, retval); + goto error_exit; + } + rmi4_data->button_0d_enabled = 1; + + return 0; + +error_exit: + synaptics_rmi4_f1a_kfree(fhandler); + + return retval; +} + +int synaptics_rmi4_read_tsp_test_result(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char data; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f34_ctrl_base_addr, + &data, + sizeof(data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: read fail[%d]\n", + __func__, retval); + return retval; + } + + return data >> 4; +} +EXPORT_SYMBOL(synaptics_rmi4_read_tsp_test_result); + +static int synaptics_rmi4_f34_read_version(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + struct synaptics_rmi4_f34_ctrl_0 custom_config_id; + + /* Read bootloader version */ + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base, + rmi4_data->bootloader_id, + sizeof(rmi4_data->bootloader_id)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + rmi4_data->f34_ctrl_base_addr = fhandler->full_addr.ctrl_base; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base, + custom_config_id.data, + sizeof(custom_config_id.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* custom_config_id.fw_release_month is composed + * MSB 4bit are used for factory test in TSP. and LSB 4bit represent month of fw release + */ + rmi4_data->fw_release_date_of_ic = + ((custom_config_id.fw_release_month << 8) | custom_config_id.fw_release_date); + rmi4_data->ic_revision_of_ic = custom_config_id.fw_release_revision; + rmi4_data->fw_version_of_ic = custom_config_id.fw_release_version; + + return retval; +} + +/* hava to check it!(fw_release_month) */ +static int synaptics_rmi4_f34_read_version_v7(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ + int retval; + struct synaptics_rmi4_f34_ctrl_0 custom_config_id; + + /* Read bootloader version */ + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base, + rmi4_data->bootloader_revision, + sizeof(rmi4_data->bootloader_revision)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + msleep(10); + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Read Bootloader revision Major[%x]Minor[%x]Prop[%x]\n", + __func__, rmi4_data->bootloader_revision[SYNAPTICS_BL_MAJOR_REV_OFFSET_V7] + ,rmi4_data->bootloader_revision[SYNAPTICS_BL_MINOR_REV_OFFSET_V7] + ,rmi4_data->bootloader_revision[SYNAPTICS_BL_PROPERTIES_V7]); + + rmi4_data->f34_ctrl_base_addr = fhandler->full_addr.ctrl_base; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.ctrl_base, + custom_config_id.data, + sizeof(custom_config_id.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* custom_config_id.fw_release_month is composed + * MSB 4bit are used for factory test in TSP. and LSB 4bit represent month of fw release + */ + rmi4_data->fw_release_date_of_ic = + ((custom_config_id.fw_release_month << 8) | custom_config_id.fw_release_date); + rmi4_data->ic_revision_of_ic = custom_config_id.fw_release_revision; + rmi4_data->fw_version_of_ic = custom_config_id.fw_release_version; + + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, + "%s: fw_release_date_of_ic=[%X],ic_revision_of_ic[%X],fw_version_of_ic[%X]\n", + __func__, rmi4_data->fw_release_date_of_ic + ,rmi4_data->ic_revision_of_ic + ,rmi4_data->fw_version_of_ic); + + return retval; +} + +static int synaptics_rmi4_f34_init(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler, + struct synaptics_rmi4_fn_desc *fd, + unsigned int intr_count) +{ + int retval; + + fhandler->fn_number = fd->fn_number; + fhandler->num_of_data_sources = fd->intr_src_count; + + if(rmi4_data->bootloader_version == BL_V7) { + retval = synaptics_rmi4_f34_read_version_v7(rmi4_data, fhandler); + } else { + retval = synaptics_rmi4_f34_read_version(rmi4_data, fhandler); + } + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read version. error = %d\n", + __func__, retval); + return retval; + } + + fhandler->data = NULL; + + return retval; +} + +#ifdef PROXIMITY_MODE +int synaptics_proximity_no_sleep_set(struct synaptics_rmi4_data *rmi4_data, bool enables) +{ + int retval; + unsigned char no_sleep = 0; + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + if (!f51) + return -ENODEV; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &no_sleep, + sizeof(no_sleep)); + + if (retval <= 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to read no_sleep[ret:%d]\n", + __func__, retval); + + if (enables) + no_sleep |= NO_SLEEP_ON; + else + no_sleep &= ~(NO_SLEEP_ON); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &no_sleep, + sizeof(no_sleep)); + if (retval <= 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: fail to set no_sleep[%X][ret:%d]\n", + __func__, no_sleep, retval); + + return retval; +} +EXPORT_SYMBOL(synaptics_proximity_no_sleep_set); + +static int synaptics_rmi4_f51_set_proximity_enables(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + int retval; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [0x%02X], Hover is %s\n", __func__, + f51->proximity_enables, (f51->proximity_enables & FINGER_HOVER_EN) ? "enabled" : "disabled"); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + f51->proximity_enables_addr, + &f51->proximity_enables, + sizeof(f51->proximity_enables)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + return 0; +} + +static int synaptics_rmi4_f51_set_init(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + + retval = synaptics_rmi4_i2c_read(rmi4_data, f51->general_control_addr, + &f51->general_control, sizeof(f51->general_control)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s, %4d: Failed to read (use default general control data) = %d\n", + __func__, __LINE__, retval); + f51->general_control = EDGE_SWIPE_EN; + } + + /* Read default general_control_2 register */ + synaptics_rmi4_i2c_read(rmi4_data, f51->general_control_2_addr, + &f51->general_control_2, sizeof(f51->general_control_2)); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: General control[0x%02X],2[0x%02X]\n", + __func__, f51->general_control, f51->general_control_2); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + f51->general_control_addr, + &f51->general_control, + sizeof(f51->general_control)); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + + retval = synaptics_rmi4_f51_set_proximity_enables(rmi4_data); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to set proximity enables\n", __func__); + + return retval; +} + +static int synaptics_rmi4_f51_init(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler, + struct synaptics_rmi4_fn_desc *fd, + unsigned int intr_count) +{ + int retval; + unsigned char ii; + unsigned short intr_offset; + struct synaptics_rmi4_f51_data *data; + struct synaptics_rmi4_f51_query query; + struct synaptics_rmi4_f51_handle *f51; + unsigned char data_addr_offset = 0; + + fhandler->fn_number = fd->fn_number; + fhandler->num_of_data_sources = fd->intr_src_count; + + fhandler->intr_reg_num = (intr_count + 7) / 8; + if (fhandler->intr_reg_num != 0) + fhandler->intr_reg_num -= 1; + + /* Set an enable bit for each data source */ + intr_offset = intr_count % 8; + fhandler->intr_mask = 0; + for (ii = intr_offset; + ii < ((fd->intr_src_count & MASK_3BIT) + intr_offset); + ii++) + fhandler->intr_mask |= 1 << ii; + + fhandler->data_size = sizeof(*data); + data = kzalloc(fhandler->data_size, GFP_KERNEL); + fhandler->data = (void *)data; + fhandler->extra = NULL; + + rmi4_data->f51 = kzalloc(sizeof(*rmi4_data->f51), GFP_KERNEL); + f51 = rmi4_data->f51; + +// f51->proximity_enables = AIR_SWIPE_EN | SLEEP_PROXIMITY; + f51->proximity_enables_addr = fhandler->full_addr.ctrl_base + + F51_PROXIMITY_ENABLES_OFFSET; + f51->general_control_addr = fhandler->full_addr.ctrl_base + + F51_GENERAL_CONTROL_OFFSET; + f51->general_control_2_addr = fhandler->full_addr.ctrl_base + + F51_GENERAL_CONTROL_2_OFFSET; +#ifdef PROXIMITY_MODE + f51->grip_edge_exclusion_rx_addr = fhandler->full_addr.ctrl_base + + MANUAL_DEFINED_OFFSET_GRIP_EDGE_EXCLUSION_RX; +#endif +#ifdef USE_STYLUS + f51->forcefinger_onedge_addr = fhandler->full_addr.ctrl_base + + MANUAL_DEFINED_OFFSET_FORCEFINGER_ON_EDGE; +#endif + + retval = synaptics_rmi4_i2c_read(rmi4_data, + fhandler->full_addr.query_base, + query.data, + sizeof(query.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + /* query proximity controls to get which functions + * are supported by firmware and save start address + * of each feature's data. + */ + f51->proximity_controls = query.proximity_controls; + f51->proximity_controls_2 = query.proximity_controls_2; + + f51->edge_swipe_data_addr = fhandler->full_addr.data_base + data_addr_offset; + + retval = synaptics_rmi4_f51_set_init(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to set proximity set init\n", + __func__); + return retval; + } + + return 0; +} + +int synaptics_rmi4_proximity_enables(struct synaptics_rmi4_data *rmi4_data, + unsigned char enables) +{ + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; + int retval; + + if (!f51) + return -ENODEV; + + if (enables) { + f51->proximity_enables |= FINGER_HOVER_EN; + f51->proximity_enables &= ~(SLEEP_PROXIMITY); + } else { + f51->proximity_enables |= SLEEP_PROXIMITY; + f51->proximity_enables &= ~(FINGER_HOVER_EN); + } + + if (rmi4_data->touch_stopped) + return 0; + + retval = synaptics_rmi4_f51_set_proximity_enables(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + return 0; +} +EXPORT_SYMBOL(synaptics_rmi4_proximity_enables); +#endif + +static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + int timeout = CHECK_STATUS_TIMEOUT_MS; + unsigned char intr_status; + struct synaptics_rmi4_f01_device_status status; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr, + status.data, + sizeof(status.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s:%4d read fail[%d]\n", + __func__, __LINE__, retval); + return retval; + } + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Device status[0x%02x] status.code[%d]\n", + __func__, status.data[0], status.status_code); + + while (status.status_code == STATUS_CRC_IN_PROGRESS) { + if (timeout > 0) + msleep(20); + else + return -1; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr, + status.data, + sizeof(status.data)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + timeout -= 20; + } + + if (status.flash_prog == 1) { + rmi4_data->flash_prog_mode = true; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: In flash prog mode, status = 0x%02x\n", + __func__, status.status_code); + } else { + rmi4_data->flash_prog_mode = false; + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_data_base_addr + 1, + &intr_status, + sizeof(intr_status)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to read interrupt status\n", + __func__); + return retval; + } + + return 0; +} + +static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char device_ctrl; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &(rmi4_data->i2c_client->dev), + "%s: Failed to set configured\n", + __func__); + return; + } + + device_ctrl |= CONFIGURED; + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &(rmi4_data->i2c_client->dev), + "%s: Failed to set configured\n", + __func__); + } + + return; +} + +static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler, + struct synaptics_rmi4_fn_desc *rmi_fd, int page_number) +{ + *fhandler = kzalloc(sizeof(**fhandler), GFP_KERNEL); + if (!(*fhandler)) + return -ENOMEM; + + (*fhandler)->full_addr.data_base = + (rmi_fd->data_base_addr | + (page_number << 8)); + (*fhandler)->full_addr.ctrl_base = + (rmi_fd->ctrl_base_addr | + (page_number << 8)); + (*fhandler)->full_addr.cmd_base = + (rmi_fd->cmd_base_addr | + (page_number << 8)); + (*fhandler)->full_addr.query_base = + (rmi_fd->query_base_addr | + (page_number << 8)); + + return 0; +} + +static void synaptics_rmi4_free_fh(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler) +{ +#ifdef PROXIMITY_MODE + struct synaptics_rmi4_f51_handle *f51 = rmi4_data->f51; +#endif + + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) { + synaptics_rmi4_f1a_kfree(fhandler); + } else { +#ifdef PROXIMITY_MODE + if (fhandler->fn_number == SYNAPTICS_RMI4_F51) { + kfree(f51); + f51 = NULL; + } +#endif + kfree(fhandler->data); + } + kfree(fhandler); +} +static void synaptics_init_product_info_v7(struct synaptics_rmi4_data *rmi4_data) +{ + + /* Get production info for Bootloader Version 7. */ + if (strncmp(rmi4_data->rmi4_mod_info.product_id_string, "s5807", 5) == 0) { + rmi4_data->product_id = SYNAPTICS_PRODUCT_ID_S5807; + } else if (strncmp(rmi4_data->rmi4_mod_info.product_id_string, "s5806", 5) == 0) { + rmi4_data->product_id = SYNAPTICS_PRODUCT_ID_S5806; + } else { + rmi4_data->product_id = SYNAPTICS_PRODUCT_ID_NONE; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, Undefined product id: %s\n", + __func__, rmi4_data->rmi4_mod_info.product_id_string); + } + +} + +/** + * synaptics_rmi4_query_device() + * + * Called by synaptics_rmi4_probe(). + * + * This funtion scans the page description table, records the offsets + * to the register types of Function $01, sets up the function handlers + * for Function $11 and Function $12, determines the number of interrupt + * sources from the sensor, adds valid Functions with data inputs to the + * Function linked list, parses information from the query registers of + * Function $01, and enables the interrupt sources from the valid Functions + * with data inputs. + */ +static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char ii = 0; + unsigned char page_number; + unsigned char intr_count = 0; + unsigned char f01_query[F01_STD_QUERY_LEN]; + unsigned char f01_pr_number[4]; + unsigned short pdt_entry_addr; + unsigned short intr_addr; + struct synaptics_rmi4_fn_desc rmi_fd; + struct synaptics_rmi4_fn *fhandler; + struct synaptics_rmi4_device_info *rmi; +#ifdef PRINT_DEBUG_INFO + unsigned char query4; +#endif + + rmi = &(rmi4_data->rmi4_mod_info); + + INIT_LIST_HEAD(&rmi->support_fn_list); + + /* Scan the page description tables of the pages to service */ + for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) { + for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END; + pdt_entry_addr -= PDT_ENTRY_SIZE) { + pdt_entry_addr |= (page_number << 8); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + pdt_entry_addr, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + fhandler = NULL; + + if (rmi_fd.fn_number == 0) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, + "%s: Reached end of PDT\n", + __func__); + break; + } + + /* Display function description infomation */ + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: F%02x found (page %d): INT_SRC[VER:%02X, NUM:%02x] BASE_ADDRS[%02X,%02X,%02X,%02x]\n", + __func__, rmi_fd.fn_number, page_number, + (rmi_fd.intr_src_count & 0xF0) >> 4, rmi_fd.intr_src_count & MASK_3BIT, + rmi_fd.data_base_addr, rmi_fd.ctrl_base_addr, + rmi_fd.cmd_base_addr, rmi_fd.query_base_addr); + + switch (rmi_fd.fn_number) { + case SYNAPTICS_RMI4_F01: + rmi4_data->f01_query_base_addr = + rmi_fd.query_base_addr; + rmi4_data->f01_ctrl_base_addr = + rmi_fd.ctrl_base_addr; + rmi4_data->f01_data_base_addr = + rmi_fd.data_base_addr; + rmi4_data->f01_cmd_base_addr = + rmi_fd.cmd_base_addr; + + retval = synaptics_rmi4_check_status(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to check status\n", + __func__); + return retval; + } + if (rmi4_data->flash_prog_mode) + goto flash_prog_mode; + break; + case SYNAPTICS_RMI4_F11: + if (rmi_fd.intr_src_count == 0) + break; + + retval = synaptics_rmi4_alloc_fh(&fhandler, + &rmi_fd, page_number); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc for F%d\n", + __func__, + rmi_fd.fn_number); + return retval; + } + retval = synaptics_rmi4_f11_init(rmi4_data, + fhandler, &rmi_fd, intr_count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to init for F%d\n", + __func__, rmi_fd.fn_number); + synaptics_rmi4_free_fh(rmi4_data, fhandler); + return retval; + } + break; + case SYNAPTICS_RMI4_F12: + if (rmi_fd.intr_src_count == 0) + break; + retval = synaptics_rmi4_alloc_fh(&fhandler, + &rmi_fd, page_number); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc for F%d\n", + __func__, + rmi_fd.fn_number); + return retval; + } + retval = synaptics_rmi4_f12_init(rmi4_data, + fhandler, &rmi_fd, intr_count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to init for F%d\n", + __func__, rmi_fd.fn_number); + synaptics_rmi4_free_fh(rmi4_data, fhandler); + return retval; + } + break; + case SYNAPTICS_RMI4_F1A: + if (rmi_fd.intr_src_count == 0) + break; + retval = synaptics_rmi4_alloc_fh(&fhandler, + &rmi_fd, page_number); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc for F%d\n", + __func__, + rmi_fd.fn_number); + return retval; + } + retval = synaptics_rmi4_f1a_init(rmi4_data, + fhandler, &rmi_fd, intr_count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to init for F%d\n", + __func__, rmi_fd.fn_number); + synaptics_rmi4_free_fh(rmi4_data, fhandler); + return retval; + } + break; + case SYNAPTICS_RMI4_F34: + if (rmi_fd.intr_src_count == 0) + break; + + retval = synaptics_rmi4_alloc_fh(&fhandler, + &rmi_fd, page_number); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc for F%d\n", + __func__, + rmi_fd.fn_number); + return retval; + } + + if (rmi_fd.fn_version == 2) { + rmi4_data->bootloader_version = BL_V7; + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: F34 version : Bootloader Ver7.0\n", + __func__); + } else { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Unrecognized F34 version[%d]\n", __func__, rmi_fd.fn_version); + } + + retval = synaptics_rmi4_f34_init(rmi4_data, + fhandler, &rmi_fd, intr_count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to init for F%d\n", + __func__, rmi_fd.fn_number); + synaptics_rmi4_free_fh(rmi4_data, fhandler); + return retval; + } + break; + +#ifdef PROXIMITY_MODE + case SYNAPTICS_RMI4_F51: + if (rmi_fd.intr_src_count == 0) + break; + retval = synaptics_rmi4_alloc_fh(&fhandler, + &rmi_fd, page_number); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc for F%d\n", + __func__, + rmi_fd.fn_number); + return retval; + } + retval = synaptics_rmi4_f51_init(rmi4_data, + fhandler, &rmi_fd, intr_count); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to init for F%d\n", + __func__, rmi_fd.fn_number); + synaptics_rmi4_free_fh(rmi4_data, fhandler); + return retval; + } +#ifdef PRINT_DEBUG_INFO + rmi4_data->f51_query_base = fhandler->full_addr.query_base; + rmi4_data->f51_data_base = fhandler->full_addr.data_base; + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f51_query_base + 4, + &query4, sizeof(query4)); + if (retval < 0) + return retval; + rmi4_data->f51_delta_info_addr = rmi4_data->f51_data_base; + if (query4 & F51_HAS_HAND_EDGE) { + rmi4_data->f51_delta_info_addr += F51_HAND_EDGE_DATA_SIZE; + } +#endif + + break; +#endif + } + + /* Accumulate the interrupt count */ + intr_count += (rmi_fd.intr_src_count & MASK_3BIT); + + if (fhandler && rmi_fd.intr_src_count) { + list_add_tail(&fhandler->link, + &rmi->support_fn_list); + } + } + } + +flash_prog_mode: + rmi4_data->num_of_intr_regs = (intr_count + 7) / 8; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Number of interrupt registers = %d sum of intr_count = %d\n", + __func__, rmi4_data->num_of_intr_regs, intr_count); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_query_base_addr, + f01_query, + sizeof(f01_query)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + /* RMI Version 4.0 currently supported */ + rmi->version_major = 4; + rmi->version_minor = 0; + + rmi->manufacturer_id = f01_query[0]; + rmi->product_props = f01_query[1]; + rmi->product_info[0] = f01_query[2] & MASK_7BIT; + rmi->product_info[1] = f01_query[3] & MASK_7BIT; + rmi->date_code[0] = f01_query[4] & MASK_5BIT; + rmi->date_code[1] = f01_query[5] & MASK_4BIT; + rmi->date_code[2] = f01_query[6] & MASK_5BIT; + rmi->tester_id = ((f01_query[7] & MASK_7BIT) << 8) | + (f01_query[8] & MASK_7BIT); + rmi->serial_number = ((f01_query[9] & MASK_7BIT) << 8) | + (f01_query[10] & MASK_7BIT); + memcpy(rmi->product_id_string, &f01_query[11], 10); + + synaptics_init_product_info_v7(rmi4_data); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Product ID [%s. %d]\n", + __func__, rmi4_data->rmi4_mod_info.product_id_string, rmi4_data->product_id); + + /* F01_RMI_QUERY18 ,Product ID Query 7~9 */ + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_query_base_addr + 18, + f01_pr_number, + sizeof(f01_pr_number)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s:%4d read fail[%d]\n", + __func__, __LINE__, retval); + return retval; + } + memcpy(&rmi->pr_number, f01_pr_number, 3); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Result[%d],date[%02d/%02d], revision[0x%02X], version[0x%02X], pr_num[PR%X]\n", + __func__, rmi4_data->fw_release_date_of_ic >> 12, + (rmi4_data->fw_release_date_of_ic >> 8) & 0x0F, + rmi4_data->fw_release_date_of_ic & 0x00FF, + rmi4_data->ic_revision_of_ic, rmi4_data->fw_version_of_ic, + rmi4_data->rmi4_mod_info.pr_number); + + if (rmi->manufacturer_id != 1) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Non-Synaptics device found, manufacturer ID = %d\n", + __func__, rmi->manufacturer_id); + } + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET, + rmi->build_id, + sizeof(rmi->build_id)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to read. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + + memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask)); + + /* + * Map out the interrupt bit masks for the interrupt sources + * from the registered function handlers. + */ + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->num_of_data_sources) { + rmi4_data->intr_mask[fhandler->intr_reg_num] |= + fhandler->intr_mask; + } + + /* To display each fhandler data */ + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: F%02x : NUM_SOURCE[VER:%02X, NUM:%02X] NUM_INT_REG[%02X] INT_MASK[%02X]\n", + __func__, fhandler->fn_number, + (fhandler->num_of_data_sources & 0xF0) >> 4, fhandler->num_of_data_sources & MASK_3BIT, + fhandler->intr_reg_num, fhandler->intr_mask); + } + } + + /* Enable the interrupt sources */ + for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) { + if (rmi4_data->intr_mask[ii] != 0x00) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: Interrupt enable[%d] = 0x%02x\n", + __func__, ii, rmi4_data->intr_mask[ii]); + intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii; + retval = synaptics_rmi4_i2c_write(rmi4_data, + intr_addr, + &(rmi4_data->intr_mask[ii]), + sizeof(rmi4_data->intr_mask[ii])); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + return retval; + } + } + } + + synaptics_rmi4_set_configured(rmi4_data); + + return 0; +} + +static void synaptics_rmi4_release_support_fn(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_fn *fhandler, *n; + struct synaptics_rmi4_device_info *rmi; + rmi = &(rmi4_data->rmi4_mod_info); + + if (list_empty(&rmi->support_fn_list)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: support_fn_list is empty\n", + __func__); + return; + } + + list_for_each_entry_safe(fhandler, n, &rmi->support_fn_list, link) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: fn_number = %x\n", + __func__, fhandler->fn_number); + + synaptics_rmi4_free_fh(rmi4_data, fhandler); + } +} + +static int synaptics_rmi4_set_input_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char ii; + struct synaptics_rmi4_f1a_handle *f1a; + struct synaptics_rmi4_fn *fhandler; + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); + + rmi4_data->input_dev = input_allocate_device(); + if (rmi4_data->input_dev == NULL) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to allocate input device\n", + __func__); + retval = -ENOMEM; + goto err_input_device; + } + + if (rmi4_data->board->device_num == 2) { + rmi4_data->input_dev->name = "sec_touchscreen2"; + } else { + rmi4_data->input_dev->name = "sec_touchscreen"; + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: device_name : %s\n", + __func__, rmi4_data->input_dev->name); + + rmi4_data->input_dev->id.bustype = BUS_I2C; + rmi4_data->input_dev->dev.parent = &rmi4_data->i2c_client->dev; + rmi4_data->input_dev->open = synaptics_rmi4_input_open; + rmi4_data->input_dev->close = synaptics_rmi4_input_close; + + input_set_drvdata(rmi4_data->input_dev, rmi4_data); +#ifdef GLOVE_MODE + input_set_capability(rmi4_data->input_dev, EV_SW, SW_GLOVE); +#endif + set_bit(EV_SYN, rmi4_data->input_dev->evbit); + set_bit(EV_KEY, rmi4_data->input_dev->evbit); + set_bit(EV_ABS, rmi4_data->input_dev->evbit); + set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit); + set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit); + + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_POSITION_X, 0, + rmi4_data->board->sensor_max_x - 1, 0, 0); + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_POSITION_Y, 0, + rmi4_data->board->sensor_max_y - 1, 0, 0); +#ifdef REPORT_2D_W +#ifdef EDGE_SWIPE + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_TOUCH_MAJOR, 0, + EDGE_SWIPE_WIDTH_MAX, 0, 0); + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_TOUCH_MINOR, 0, + EDGE_SWIPE_WIDTH_MAX, 0, 0); +#else + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_TOUCH_MAJOR, 0, + rmi4_data->max_touch_width, 0, 0); + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_TOUCH_MINOR, 0, + rmi4_data->max_touch_width, 0, 0); +#endif +#ifdef REPORT_2D_Z + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_PRESSURE, 0, + DSX_PRESSURE_MAX, 0, 0); +#endif +#ifdef REPORT_ORIENTATION + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_ORIENTATION, 0, 1, 0, 0); +#endif +#endif +#ifdef USE_STYLUS + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); +#endif +#ifdef PROXIMITY_MODE + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_DISTANCE, 0, + HOVER_Z_MAX, 0, 0); +#ifdef EDGE_SWIPE + input_set_abs_params(rmi4_data->input_dev, + ABS_MT_PALM, 0, + EDGE_SWIPE_PALM_MAX, 0, 0); +#endif + setup_timer(&rmi4_data->f51_finger_timer, + synaptics_rmi4_f51_finger_timer, + (unsigned long)rmi4_data); +#endif + + retval = input_mt_init_slots(rmi4_data->input_dev, + rmi4_data->num_of_fingers, INPUT_MT_DIRECT); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to input_mt_init_slots - num_of_fingers:%d, retval:%d\n", + __func__, rmi4_data->num_of_fingers, retval); + } + + f1a = NULL; + if (!list_empty(&rmi->support_fn_list)) { + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) + f1a = fhandler->data; + } + } + + if (f1a) { + for (ii = 0; ii < f1a->valid_button_count; ii++) { + set_bit(f1a->button_map[ii], + rmi4_data->input_dev->keybit); + input_set_capability(rmi4_data->input_dev, + EV_KEY, f1a->button_map[ii]); + } + } + + retval = input_register_device(rmi4_data->input_dev); + if (retval) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to register input device\n", + __func__); + goto err_register_input; + } + + return 0; + +err_register_input: + input_free_device(rmi4_data->input_dev); + +err_input_device: + return retval; +} + +static int synaptics_rmi4_reinit_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + unsigned char ii = 0; + unsigned short intr_addr; + struct synaptics_rmi4_fn *fhandler; + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); + + mutex_lock(&(rmi4_data->rmi4_reset_mutex)); + + if (list_empty(&rmi->support_fn_list)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Support function list is empty!!\n", + __func__); + retval = -EINVAL; + goto exit; + } + + list_for_each_entry(fhandler, &rmi->support_fn_list, link) { + if (fhandler->fn_number == SYNAPTICS_RMI4_F12) { + retval = synaptics_rmi4_f12_set_init(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to initialize F12 = %d\n", + __func__, retval); + goto exit; + } + } +#ifdef CONFIG_SEC_FACTORY + /* Read firmware version from IC when every power up IC. + * During Factory process touch panel can be changed manually. + */ + if (fhandler->fn_number == SYNAPTICS_RMI4_F34) { + retval = synaptics_rmi4_f34_read_version(rmi4_data, fhandler); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to read version error = %d\n", + __func__, retval); + goto exit; + } + } +#endif +#ifdef PROXIMITY_MODE + if (fhandler->fn_number == SYNAPTICS_RMI4_F51) { + retval = synaptics_rmi4_f51_set_init(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to initialize F51 = %d\n", + __func__, retval); + goto exit; + } + } +#endif + } + + for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) { + if (rmi4_data->intr_mask[ii] != 0x00) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: Interrupt enable mask register[%d] = 0x%02x\n", + __func__, ii, rmi4_data->intr_mask[ii]); + intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii; + retval = synaptics_rmi4_i2c_write(rmi4_data, + intr_addr, + &(rmi4_data->intr_mask[ii]), + sizeof(rmi4_data->intr_mask[ii])); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s, %4d: Failed to write. error = %d\n", + __func__, __LINE__, retval); + goto exit; + } + } + } + + synaptics_rmi4_set_configured(rmi4_data); + +exit: + mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); + return retval; +} + +static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char command = 0x01; + struct synaptics_rmi4_device_info *rmi = &(rmi4_data->rmi4_mod_info); + struct synaptics_rmi4_exp_fn *exp_fhandler = NULL; + + mutex_lock(&(rmi4_data->rmi4_reset_mutex)); + + disable_irq(rmi4_data->i2c_client->irq); + + synpatics_rmi4_release_all_event(rmi4_data, RELEASE_TYPE_ALL); + + if (!rmi4_data->stay_awake) { + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_cmd_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to issue reset command, error = %d\n", + __func__, retval); + goto out; + } + + msleep(SYNAPTICS_HW_RESET_TIME); + } else { + rmi4_data->board->power(rmi4_data, false); + msleep(30); + rmi4_data->board->power(rmi4_data, true); + msleep(SYNAPTICS_HW_RESET_TIME); + } + + synaptics_rmi4_release_support_fn(rmi4_data); + retval = synaptics_rmi4_query_device(rmi4_data); + + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to query device\n", + __func__); + + if (rmi4_data->stay_awake) { + if (!list_empty(&rmi->exp_fn_list)) { + list_for_each_entry(exp_fhandler, &rmi->exp_fn_list, link) { + if (exp_fhandler->initialized && (exp_fhandler->func_reinit != NULL)) { + exp_fhandler->func_reinit(rmi4_data); + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: %d exp fun re_init\n", + __func__, exp_fhandler->fn_type); + } + } + } + } +out: + enable_irq(rmi4_data->i2c_client->irq); + mutex_unlock(&(rmi4_data->rmi4_reset_mutex)); + + return 0; +} + +#ifdef SYNAPTICS_RMI_INFORM_CHARGER +static void synaptics_charger_conn(struct synaptics_rmi4_data *rmi4_data, + int ta_status) +{ + int retval; + unsigned char charger_connected; + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &charger_connected, + sizeof(charger_connected)); + if (retval < 0) { + tsp_debug_err(true, &(rmi4_data->input_dev->dev), + "%s: Failed to set configured\n", + __func__); + return; + } + + if (ta_status == 0x01 || ta_status == 0x03) + charger_connected |= CHARGER_CONNECTED; + else + charger_connected &= ~(CHARGER_CONNECTED); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &charger_connected, + sizeof(charger_connected)); + + if (retval < 0) { + tsp_debug_err(true, &(rmi4_data->input_dev->dev), + "%s: Failed to set configured\n", + __func__); + } + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: device_control : 0x%x, ta_status : %x\n", + __func__, charger_connected, ta_status); +} + +static void synaptics_ta_cb(struct synaptics_rmi_callbacks *cb, int ta_status) +{ + struct synaptics_rmi4_data *rmi4_data = + container_of(cb, struct synaptics_rmi4_data, callbacks); + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, + "%s: ta_status : %x\n", __func__, ta_status); + + rmi4_data->ta_status = ta_status; + + /* if do not completed driver loading, ta_cb will not run. */ + if (!rmi4_data->init_done.done) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: until driver loading done.\n", + __func__); + return; + } + if (rmi4_data->touch_stopped || rmi4_data->doing_reflash) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: device is in suspend state or reflash.\n", + __func__); + return; + } + + if (pdata->charger_noti_type) + synaptics_charger_conn(rmi4_data, ta_status); +} +#endif + +#ifdef PROXIMITY_MODE +static void synaptics_rmi4_f51_finger_timer(unsigned long data) +{ + struct synaptics_rmi4_data *rmi4_data = + (struct synaptics_rmi4_data *)data; + + if (rmi4_data->f51_finger) { + rmi4_data->f51_finger = false; + mod_timer(&rmi4_data->f51_finger_timer, + jiffies + msecs_to_jiffies(F51_FINGER_TIMEOUT)); + return; + } + + if (!rmi4_data->fingers_on_2d) { + input_mt_slot(rmi4_data->input_dev, 0); + input_mt_report_slot_state(rmi4_data->input_dev, + MT_TOOL_FINGER, 0); + input_report_key(rmi4_data->input_dev, + BTN_TOUCH, 0); + input_report_key(rmi4_data->input_dev, + BTN_TOOL_FINGER, 0); + input_sync(rmi4_data->input_dev); + } + + return; +} +#endif + +static void synaptics_rmi4_remove_exp_fn(struct synaptics_rmi4_data *rmi4_data) +{ + struct synaptics_rmi4_exp_fn *exp_fhandler, *n; + struct synaptics_rmi4_device_info *rmi = &(rmi4_data->rmi4_mod_info); + + if (list_empty(&rmi->exp_fn_list)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: exp_fn_list empty\n", + __func__); + return; + } + + list_for_each_entry_safe(exp_fhandler, n, &rmi->exp_fn_list, link) { + if (exp_fhandler->initialized && + (exp_fhandler->func_remove != NULL)) { + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: [%d]\n", + __func__, exp_fhandler->fn_type); + exp_fhandler->func_remove(rmi4_data); + } + list_del(&exp_fhandler->link); + kfree(exp_fhandler); + } +} + +static int synaptics_rmi4_init_exp_fn(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + struct synaptics_rmi4_exp_fn *exp_fhandler; + struct synaptics_rmi4_device_info *rmi = &(rmi4_data->rmi4_mod_info); + + INIT_LIST_HEAD(&rmi->exp_fn_list); + + retval = rmidev_module_register(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to register rmidev module\n", + __func__); + goto error_exit; + } + + retval = rmi4_f54_module_register(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to register f54 module\n", + __func__); + goto error_exit; + } + + retval = rmi4_fw_update_module_register(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to register fw update module\n", + __func__); + goto error_exit; + } + + if (list_empty(&rmi->exp_fn_list)) + return -ENODEV; + + list_for_each_entry(exp_fhandler, &rmi->exp_fn_list, link) { + if (exp_fhandler->initialized) { + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s: [%d] is already initialzied.\n", + __func__, exp_fhandler->fn_type); + continue; + } + if (exp_fhandler->func_init != NULL) { + retval = exp_fhandler->func_init(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to init exp [%d] fn\n", + __func__, exp_fhandler->fn_type); + goto error_exit; + } else { + exp_fhandler->initialized = true; + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s: run [%d]'s init function\n", + __func__, exp_fhandler->fn_type); + } + } + return 0; + +error_exit: + synaptics_rmi4_remove_exp_fn(rmi4_data); + + return retval; +} + +/** + * synaptics_rmi4_new_function() + * + * Called by other expansion Function modules in their module init and + * module exit functions. + * + * This function is used by other expansion Function modules such as + * rmi_dev to register themselves with the driver by providing their + * initialization and removal callback function pointers so that they + * can be inserted or removed dynamically at module init and exit times, + * respectively. + */ +int synaptics_rmi4_new_function(enum exp_fn fn_type, + struct synaptics_rmi4_data *rmi4_data, + int (*func_init)(struct synaptics_rmi4_data *rmi4_data), + int (*func_reinit)(struct synaptics_rmi4_data *rmi4_data), + void (*func_remove)(struct synaptics_rmi4_data *rmi4_data), + void (*func_attn)(struct synaptics_rmi4_data *rmi4_data, unsigned char intr_mask)) +{ + struct synaptics_rmi4_exp_fn *exp_fhandler; + struct synaptics_rmi4_device_info *rmi = &(rmi4_data->rmi4_mod_info); + + exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL); + + if (!exp_fhandler) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to alloc mem for expansion function\\n", + __func__); + return -ENOMEM; + } + exp_fhandler->fn_type = fn_type; + exp_fhandler->func_init = func_init; + exp_fhandler->func_reinit = func_reinit; + exp_fhandler->func_attn = func_attn; + exp_fhandler->func_remove = func_remove; + list_add_tail(&exp_fhandler->link, &rmi->exp_fn_list); + + return 0; +} + +#ifdef CONFIG_OF +static int synaptics_power_ctrl(void *data, bool on) +{ + struct synaptics_rmi4_data *rmi4_data = (struct synaptics_rmi4_data *)data; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + struct device *dev = &rmi4_data->i2c_client->dev; + struct regulator *regulator_dvdd; + struct regulator *regulator_avdd; + struct pinctrl_state *pinctrl_state; + int retval = 0; + + if (rmi4_data->tsp_pwr_enabled == on) + return retval; + + regulator_dvdd = regulator_get(NULL, pdata->regulator_dvdd); + if (IS_ERR(regulator_dvdd)) { + tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", + __func__, pdata->regulator_dvdd); + return PTR_ERR(regulator_dvdd); + } + + regulator_avdd = regulator_get(NULL, pdata->regulator_avdd); + if (IS_ERR(regulator_avdd)) { + tsp_debug_err(true, dev, "%s: Failed to get %s regulator.\n", + __func__, pdata->regulator_avdd); + return PTR_ERR(regulator_avdd); + } + + tsp_debug_info(true, dev, "%s: %s\n", __func__, on ? "on" : "off"); + + if (on) { + retval = regulator_enable(regulator_avdd); + if (retval) { + tsp_debug_err(true, dev, "%s: Failed to enable avdd: %d\n", __func__, retval); + return retval; + } + retval = regulator_enable(regulator_dvdd); + if (retval) { + tsp_debug_err(true, dev, "%s: Failed to enable vdd: %d\n", __func__, retval); + return retval; + } + + pinctrl_state = pinctrl_lookup_state(rmi4_data->pinctrl, "on_state"); + } else { + if (regulator_is_enabled(regulator_dvdd)) + regulator_disable(regulator_dvdd); + if (regulator_is_enabled(regulator_avdd)) + regulator_disable(regulator_avdd); + + pinctrl_state = pinctrl_lookup_state(rmi4_data->pinctrl, "off_state"); + } + + if (IS_ERR(pinctrl_state)) { + tsp_debug_err(true, dev, "%s: Failed to lookup pinctrl.\n", __func__); + } else { + retval = pinctrl_select_state(rmi4_data->pinctrl, pinctrl_state); + if (retval) + tsp_debug_err(true, dev, "%s: Failed to configure pinctrl.\n", __func__); + } + + rmi4_data->tsp_pwr_enabled = on; + regulator_put(regulator_dvdd); + regulator_put(regulator_avdd); + + return retval; +} + +static int synaptics_parse_dt(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct synaptics_rmi4_platform_data *pdata = dev->platform_data; + struct device_node *np = dev->of_node; + u32 coords[2], lines[2]; + int retval = 0; + + pdata->gpio = of_get_named_gpio(np, "synaptics,irq_gpio", 0); + if (gpio_is_valid(pdata->gpio)) { + retval = gpio_request_one(pdata->gpio, GPIOF_DIR_IN, "synaptics,tsp_int"); + if (retval) { + tsp_debug_err(true, dev, "Unable to request tsp_int [%d]\n", pdata->gpio); + return -EINVAL; + } + } else { + tsp_debug_err(true, dev, "Failed to get irq gpio\n"); + return -EINVAL; + } + client->irq = gpio_to_irq(pdata->gpio); + + if (of_property_read_u32(np, "synaptics,irq_type", &pdata->irq_type)) { + tsp_debug_err(true, dev, "Failed to get irq_type property\n"); + return -EINVAL; + } + + if (of_property_read_u32_array(np, "synaptics,max_coords", coords, 2)) { + tsp_debug_err(true, dev, "Failed to get max_coords property\n"); + return -EINVAL; + } + pdata->sensor_max_x = coords[0]; + pdata->sensor_max_y = coords[1]; + + if (of_property_read_u32_array(np, "synaptics,num_lines", lines, 2)) { + tsp_debug_err(true, dev, "Failed to get num_liness property\n"); + return -EINVAL; + } + pdata->num_of_rx = lines[0]; + pdata->num_of_tx = lines[1]; + pdata->max_touch_width = max(pdata->num_of_rx, pdata->num_of_tx); + + pdata->x_flip = of_property_read_bool(np, "synaptics,x_flip"); + pdata->y_flip = of_property_read_bool(np, "synaptics,y_flip"); + pdata->x_y_chnage = of_property_read_bool(np, "synaptics,x_y_chnage"); + + if (of_property_read_u32(np, "synaptics,x_offset", &pdata->x_offset)) { + tsp_debug_info(true, dev, "Failed to get x_offset property\n"); + } + + if (of_property_read_string(np, "synaptics,regulator_dvdd", &pdata->regulator_dvdd)) { + tsp_debug_err(true, dev, "Failed to get regulator_dvdd name property\n"); + return -EINVAL; + } + if (of_property_read_string(np, "synaptics,regulator_avdd", &pdata->regulator_avdd)) { + tsp_debug_err(true, dev, "Failed to get regulator_avdd name property\n"); + return -EINVAL; + } + pdata->power = synaptics_power_ctrl; + + /* Optional parmeters(those values are not mandatory) + * do not return error value even if fail to get the value + */ + of_property_read_string(np, "synaptics,firmware_name", &pdata->firmware_name); + + if (of_property_read_string_index(np, "synaptics,project_name", 0, &pdata->project_name)) + tsp_debug_err(true, dev, "Failed to get project_name property\n"); + if (of_property_read_u32(np, "synaptics,panel_revision", &pdata->panel_revision)) + tsp_debug_err(true, dev, "Failed to get panel_revision property\n"); + if (of_property_read_string_index(np, "synaptics,project_name", 1, &pdata->model_name)) + tsp_debug_err(true, dev, "Failed to get model_name property\n"); + if (of_property_read_u32(np, "synaptics,device_num", &pdata->device_num)) + tsp_debug_err(true, dev, "Failed to get device_num property\n"); + + tsp_debug_info(true, dev, "irq :%d, irq_type: 0x%04x, project/model_name: %s/%s, device_num: %d\n", + pdata->gpio, pdata->irq_type, pdata->project_name, pdata->model_name, pdata->device_num); + + tsp_debug_info(true, dev, "num_of[rx,tx]: [%d,%d], max[x,y]: [%d,%d], max_width: %d, flip[x,y,x_y,x_offset]:[%d,%d,%d %d]", + pdata->num_of_rx, pdata->num_of_tx, pdata->sensor_max_x, pdata->sensor_max_y,pdata->max_touch_width, + pdata->x_flip, pdata->y_flip, pdata->x_y_chnage, pdata->x_offset); + + return retval; +} +#endif + +static int synaptics_rmi4_setup_drv_data(struct i2c_client *client) +{ + int retval = 0; + struct synaptics_rmi4_platform_data *pdata; + struct synaptics_rmi4_data *rmi4_data; + + /* parse dt */ + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct synaptics_rmi4_platform_data), GFP_KERNEL); + + if (!pdata) { + tsp_debug_err(true, &client->dev, "Failed to allocate platform data\n"); + return -ENOMEM; + } + + client->dev.platform_data = pdata; + retval = synaptics_parse_dt(client); + if (retval) { + tsp_debug_err(true, &client->dev, "Failed to parse dt\n"); + return retval; + } + } else { + pdata = client->dev.platform_data; + } + + if (!pdata) { + tsp_debug_err(true, &client->dev, "No platform data found\n"); + return -EINVAL; + } + if (!pdata->power) { + tsp_debug_err(true, &client->dev, "No power contorl found\n"); + return -EINVAL; + } + + rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data), GFP_KERNEL); + if (!rmi4_data) { + tsp_debug_err(true, &client->dev, + "%s: Failed to alloc mem for rmi4_data\n", + __func__); + return -ENOMEM; + } + + rmi4_data->i2c_client = client; + rmi4_data->board = pdata; + rmi4_data->touch_stopped = false; + rmi4_data->sensor_sleep = false; + rmi4_data->irq_enabled = false; + rmi4_data->tsp_probe = false; + rmi4_data->rebootcount = 0; + rmi4_data->panel_revision = rmi4_data->board->panel_revision; + rmi4_data->i2c_read = synaptics_rmi4_i2c_read; + rmi4_data->i2c_write = synaptics_rmi4_i2c_write; + rmi4_data->irq_enable = synaptics_rmi4_irq_enable; + rmi4_data->reset_device = synaptics_rmi4_reset_device; + rmi4_data->stop_device = synaptics_rmi4_stop_device; + rmi4_data->start_device = synaptics_rmi4_start_device; +#ifdef USE_SENSOR_SLEEP + rmi4_data->sleep_device = synaptics_rmi4_sensor_sleep; + rmi4_data->wake_device = synaptics_rmi4_sensor_wake; +#endif + rmi4_data->irq = rmi4_data->i2c_client->irq; + + /* To prevent input device is set up with defective values */ + rmi4_data->sensor_max_x = rmi4_data->board->sensor_max_x; + rmi4_data->sensor_max_y = rmi4_data->board->sensor_max_y; + rmi4_data->num_of_rx = rmi4_data->board->num_of_rx; + rmi4_data->num_of_tx = rmi4_data->board->num_of_tx; + rmi4_data->max_touch_width = max(rmi4_data->num_of_rx, + rmi4_data->num_of_tx); + rmi4_data->num_of_fingers = MAX_NUMBER_OF_FINGERS; + + mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex)); + mutex_init(&(rmi4_data->rmi4_reset_mutex)); + mutex_init(&(rmi4_data->rmi4_reflash_mutex)); + mutex_init(&(rmi4_data->rmi4_device_mutex)); + init_completion(&rmi4_data->init_done); + + i2c_set_clientdata(client, rmi4_data); + + if (pdata->get_ddi_type) { + rmi4_data->ddi_type = pdata->get_ddi_type(); + tsp_debug_info(true, &client->dev, "%s: DDI Type is %s[%d]\n", + __func__, rmi4_data->ddi_type ? "MAGNA" : "SDC", rmi4_data->ddi_type); + } + + return retval; +} + +/** + * synaptics_rmi4_probe() + * + * Called by the kernel when an association with an I2C device of the + * same name is made (after doing i2c_add_driver). + * + * This funtion allocates and initializes the resources for the driver + * as an input driver, turns on the power to the sensor, queries the + * sensor for its supported Functions and characteristics, registers + * the driver to the input subsystem, sets up the interrupt, handles + * the registration of the early_suspend and late_resume functions, + * and creates a work queue for detection of other expansion Function + * modules. + */ +static int synaptics_rmi4_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data = NULL; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + tsp_debug_err(true, &client->dev, + "%s: SMBus byte data not supported\n", + __func__); + return -EIO; + } + + if (lpcharge == 1) { + tsp_debug_err(true, &client->dev, "%s : Do not load driver due to : lpm %d\n", + __func__, lpcharge); + return -ENODEV; + } + + /* Build up driver data */ + retval = synaptics_rmi4_setup_drv_data(client); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to set up driver data\n", __func__); + goto err_setup_drv_data; + } + + rmi4_data = (struct synaptics_rmi4_data *)i2c_get_clientdata(client); + if (!rmi4_data) { + tsp_debug_err(true, &client->dev, "%s: Failed to get driver data\n", __func__); + goto err_get_drv_data; + } + + rmi4_data->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR(rmi4_data->pinctrl)) { + tsp_debug_err(true, &client->dev, "%s: Failed to get pinctrl data\n", __func__); + retval = PTR_ERR(rmi4_data->pinctrl); + goto err_get_pinctrl; + } + +err_tsp_reboot: + rmi4_data->board->power(rmi4_data, true); + msleep(SYNAPTICS_POWER_MARGIN_TIME); + + if (rmi4_data->rebootcount) + synaptics_rmi4_release_support_fn(rmi4_data); + + /* Query device infomations */ + retval = synaptics_rmi4_query_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to query device\n", __func__); + + /* Protection code */ + if ((retval == TSP_NEEDTO_REBOOT) && (rmi4_data->rebootcount < MAX_TSP_REBOOT)) { + rmi4_data->board->power(rmi4_data, false); + msleep(SYNAPTICS_POWER_MARGIN_TIME); + msleep(SYNAPTICS_POWER_MARGIN_TIME); + rmi4_data->rebootcount++; + synaptics_rmi4_release_support_fn(rmi4_data); + + tsp_debug_err(true, &client->dev, "%s: reboot sequence by i2c fail\n", __func__); + goto err_tsp_reboot; + } else { + goto err_query_device; + } + } + + /* Set up input device */ + retval = synaptics_rmi4_set_input_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to set up input device\n", + __func__); + goto err_set_input_device; + } + + /* Set up expanded function list */ + retval = synaptics_rmi4_init_exp_fn(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to initialize expandered functions\n", + __func__); + goto err_init_exp_fn; + } + + /* Enable attn pin */ + retval = synaptics_rmi4_irq_enable(rmi4_data, true); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to enable attention interrupt\n", + __func__); + goto err_enable_irq; + } + + /* Creat sysfs files */ + retval = sysfs_create_group(&rmi4_data->input_dev->dev.kobj, &attr_group); + if (retval < 0) { + tsp_debug_err(true, &client->dev, "%s: Failed to create sysfs attributes\n", + __func__); + goto err_sysfs; + } + + /* Update firmware on probe */ + retval = synaptics_rmi4_fw_update_on_probe(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to firmware update\n", + __func__); + goto err_fw_update; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1; + rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend; + rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume; + register_early_suspend(&rmi4_data->early_suspend); +#endif + +#ifdef SYNAPTICS_RMI_INFORM_CHARGER + rmi4_data->register_cb = synaptics_tsp_register_callback; + + rmi4_data->callbacks.inform_charger = synaptics_ta_cb; + if (rmi4_data->register_cb) { + tsp_debug_err(true, &client->dev, "Register TA Callback\n"); + rmi4_data->register_cb(&rmi4_data->callbacks); + } +#endif + /* for blocking to be excuted open function until probing */ + rmi4_data->tsp_probe = true; + + /* it will be started by input reader */ +// synaptics_rmi4_stop_device(rmi4_data); + + complete_all(&rmi4_data->init_done); + + return retval; + +err_fw_update: +err_sysfs: + sysfs_remove_group(&rmi4_data->input_dev->dev.kobj, &attr_group); + synaptics_rmi4_irq_enable(rmi4_data, false); + +err_enable_irq: + synaptics_rmi4_remove_exp_fn(rmi4_data); + +err_init_exp_fn: + input_unregister_device(rmi4_data->input_dev); + input_free_device(rmi4_data->input_dev); + rmi4_data->input_dev = NULL; + +err_set_input_device: +err_query_device: + synaptics_rmi4_release_support_fn(rmi4_data); + rmi4_data->board->power(rmi4_data, false); + complete_all(&rmi4_data->init_done); + +err_get_pinctrl: +err_get_drv_data: +err_setup_drv_data: + kfree(rmi4_data); + + return retval; +} + +#ifdef USE_SHUTDOWN_CB +static void synaptics_rmi4_shutdown(struct i2c_client *client) +{ + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + + synaptics_rmi4_stop_device(rmi4_data); +} +#endif + +/** + * synaptics_rmi4_remove() + * + * Called by the kernel when the association with an I2C device of the + * same name is broken (when the driver is unloaded). + * + * This funtion terminates the work queue, stops sensor data acquisition, + * frees the interrupt, unregisters the driver from the input subsystem, + * turns off the power to the sensor, and frees other allocated resources. + */ +static int synaptics_rmi4_remove(struct i2c_client *client) +{ + struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client); + struct synaptics_rmi4_device_info *rmi; + + rmi = &(rmi4_data->rmi4_mod_info); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&rmi4_data->early_suspend); +#endif + synaptics_rmi4_irq_enable(rmi4_data, false); + + sysfs_remove_group(&rmi4_data->input_dev->dev.kobj, &attr_group); + + input_unregister_device(rmi4_data->input_dev); + + synaptics_rmi4_remove_exp_fn(rmi4_data); + + rmi4_data->board->power(rmi4_data, false); + rmi4_data->touch_stopped = true; + + synaptics_rmi4_release_support_fn(rmi4_data); + + input_free_device(rmi4_data->input_dev); + + kfree(rmi4_data); + + return 0; +} + +#ifdef USE_SENSOR_SLEEP +/** + * synaptics_rmi4_sensor_sleep() + * + * Called by synaptics_rmi4_early_suspend() and synaptics_rmi4_suspend(). + * + * This function stops finger data acquisition and puts the sensor to sleep. + */ +static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char device_ctrl; + struct pinctrl_state *pinctrl_state; + + mutex_lock(&rmi4_data->rmi4_device_mutex); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s, from %s\n", + __func__, rmi4_data->sensor_sleep ? "Sleep" : "Wake"); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to enter sleep mode\n", + __func__); + rmi4_data->sensor_sleep = false; + goto out; + } + + device_ctrl = (device_ctrl & ~MASK_3BIT); + device_ctrl = (device_ctrl | SENSOR_SLEEP); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to enter sleep mode\n", + __func__); + rmi4_data->sensor_sleep = false; + goto out; + } + + rmi4_data->sensor_sleep = true; + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s : [F01_CTRL] 0x%02X, [F51_CTRL] 0x%02X/0x%02X/0x%02X]\n", + __func__, device_ctrl, rmi4_data->f51->proximity_enables, rmi4_data->f51->general_control, rmi4_data->f51->general_control_2); + + msleep(SYNAPTICS_DEEPSLEEP_TIME); + synpatics_rmi4_release_all_event(rmi4_data, RELEASE_TYPE_ALL); + + pinctrl_state = pinctrl_lookup_state(rmi4_data->pinctrl, "sleep_state"); + + if (IS_ERR(pinctrl_state)) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to lookup pinctrl.\n", __func__); + } else { + retval = pinctrl_select_state(rmi4_data->pinctrl, pinctrl_state); + if (retval) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s: Failed to configure pinctrl.\n", __func__); + } + +out: + mutex_unlock(&rmi4_data->rmi4_device_mutex); + + return; +} + +/** + * synaptics_rmi4_sensor_wake() + * + * Called by synaptics_rmi4_resume() and synaptics_rmi4_late_resume(). + * + * This function wakes the sensor from sleep. + */ +static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data) +{ + int retval; + unsigned char device_ctrl; + + mutex_lock(&rmi4_data->rmi4_device_mutex); + + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s, from %s\n", + __func__, rmi4_data->sensor_sleep ? "sleep" : "wake"); + + retval = synaptics_rmi4_i2c_read(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wake from sleep mode\n", + __func__); + rmi4_data->sensor_sleep = true; + goto out; + } + + device_ctrl = (device_ctrl & ~MASK_3BIT); + device_ctrl = (device_ctrl | NORMAL_OPERATION); + + retval = synaptics_rmi4_i2c_write(rmi4_data, + rmi4_data->f01_ctrl_base_addr, + &device_ctrl, + sizeof(device_ctrl)); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to wake from sleep mode\n", + __func__); + rmi4_data->sensor_sleep = true; + goto out; + } + + rmi4_data->sensor_sleep = false; + tsp_debug_info(true, &rmi4_data->i2c_client->dev, "%s : [F01_CTRL] 0x%02X, [F51_CTRL] 0x%02X/0x%02X/0x%02X]\n", + __func__, device_ctrl, rmi4_data->f51->proximity_enables, rmi4_data->f51->general_control, rmi4_data->f51->general_control_2); +out: + mutex_unlock(&rmi4_data->rmi4_device_mutex); + + return; +} +#endif + +static int synaptics_rmi4_stop_device(struct synaptics_rmi4_data *rmi4_data) +{ + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + mutex_lock(&rmi4_data->rmi4_device_mutex); + + if (rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s already power off\n", + __func__); + goto out; + } + + disable_irq(rmi4_data->i2c_client->irq); + + synpatics_rmi4_release_all_event(rmi4_data, RELEASE_TYPE_ALL); + + rmi4_data->touch_stopped = true; + pdata->power(rmi4_data, false); + + if (pdata->enable_sync) + pdata->enable_sync(false); + + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +out: + mutex_unlock(&rmi4_data->rmi4_device_mutex); + return 0; +} + +static int synaptics_rmi4_start_device(struct synaptics_rmi4_data *rmi4_data) +{ + int retval = 0; + const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board; + + mutex_lock(&rmi4_data->rmi4_device_mutex); + + if (!rmi4_data->touch_stopped) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, "%s already power on\n", + __func__); + goto out; + } + + pdata->power(rmi4_data, true); + rmi4_data->touch_stopped = false; + + if (pdata->enable_sync) + pdata->enable_sync(true); + + msleep(SYNAPTICS_HW_RESET_TIME); + + retval = synaptics_rmi4_reinit_device(rmi4_data); + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to reinit device\n", + __func__); + } + enable_irq(rmi4_data->i2c_client->irq); + + tsp_debug_dbg(true, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +out: + mutex_unlock(&rmi4_data->rmi4_device_mutex); + return retval; +} + +static int synaptics_rmi4_input_open(struct input_dev *dev) +{ + struct synaptics_rmi4_data *rmi4_data = input_get_drvdata(dev); + int retval; + + retval = wait_for_completion_interruptible_timeout(&rmi4_data->init_done, + msecs_to_jiffies(90 * MSEC_PER_SEC)); + + if (retval < 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "error while waiting for device to init (%d)\n", retval); + retval = -ENXIO; + goto err_open; + } + if (retval == 0) { + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "timedout while waiting for device to init\n"); + retval = -ENXIO; + goto err_open; + } + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) { + synaptics_rmi4_sensor_wake(rmi4_data); + } else +#endif + { + retval = synaptics_rmi4_start_device(rmi4_data); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to start device\n", __func__); + } + + return 0; + +err_open: + return retval; +} + +static void synaptics_rmi4_input_close(struct input_dev *dev) +{ + struct synaptics_rmi4_data *rmi4_data = input_get_drvdata(dev); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) + synaptics_rmi4_sensor_sleep(rmi4_data); + else +#endif + synaptics_rmi4_stop_device(rmi4_data); +} + +#ifdef CONFIG_PM +#ifdef CONFIG_HAS_EARLYSUSPEND +#define synaptics_rmi4_suspend NULL +#define synaptics_rmi4_resume NULL + +/** + * synaptics_rmi4_early_suspend() + * + * Called by the kernel during the early suspend phase when the system + * enters suspend. + * + * This function calls synaptics_rmi4_sensor_sleep() to stop finger + * data acquisition and put the sensor to sleep. + */ +static void synaptics_rmi4_early_suspend(struct early_suspend *h) +{ + struct synaptics_rmi4_data *rmi4_data = + container_of(h, struct synaptics_rmi4_data, + early_suspend); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) + synaptics_rmi4_sensor_sleep(rmi4_data); + else +#endif + synaptics_rmi4_stop_device(rmi4_data); + + return; +} + +/** + * synaptics_rmi4_late_resume() + * + * Called by the kernel during the late resume phase when the system + * wakes up from suspend. + * + * This function goes through the sensor wake process if the system wakes + * up from early suspend (without going into suspend). + */ +static void synaptics_rmi4_late_resume(struct early_suspend *h) +{ + int retval = 0; + struct synaptics_rmi4_data *rmi4_data = + container_of(h, struct synaptics_rmi4_data, + early_suspend); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) { + synaptics_rmi4_sensor_wake(rmi4_data); + } else +#endif + { + retval = synaptics_rmi4_start_device(rmi4_data); + if (retval < 0) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to start device\n", __func__); + } + + return; +} +#else + +/** + * synaptics_rmi4_suspend() + * + * Called by the kernel during the suspend phase when the system + * enters suspend. + * + * This function stops finger data acquisition and puts the sensor to + * sleep (if not already done so during the early suspend phase), + * disables the interrupt, and turns off the power to the sensor. + */ +static int synaptics_rmi4_suspend(struct device *dev) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + + mutex_lock(&rmi4_data->input_dev->mutex); + + if (rmi4_data->input_dev->users) { +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) + synaptics_rmi4_sensor_sleep(rmi4_data); + else +#endif + synaptics_rmi4_stop_device(rmi4_data); + } + mutex_unlock(&rmi4_data->input_dev->mutex); + + return 0; +} + +/** + * synaptics_rmi4_resume() + * + * Called by the kernel during the resume phase when the system + * wakes up from suspend. + * + * This function turns on the power to the sensor, wakes the sensor + * from sleep, enables the interrupt, and starts finger data + * acquisition. + */ +static int synaptics_rmi4_resume(struct device *dev) +{ + struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); + + tsp_debug_dbg(false, &rmi4_data->i2c_client->dev, "%s\n", __func__); + + mutex_lock(&rmi4_data->input_dev->mutex); + + if (rmi4_data->input_dev->users) { +#ifdef USE_SENSOR_SLEEP + if (rmi4_data->use_deepsleep) { + synaptics_rmi4_sensor_wake(rmi4_data); + } else +#endif + { + if (synaptics_rmi4_start_device(rmi4_data)) + tsp_debug_err(true, &rmi4_data->i2c_client->dev, + "%s: Failed to start device\n", __func__); + } + } + + mutex_unlock(&rmi4_data->input_dev->mutex); + + return 0; +} +#endif + +static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = { + .suspend = synaptics_rmi4_suspend, + .resume = synaptics_rmi4_resume, +}; +#endif + +static const struct i2c_device_id synaptics_rmi4_id_table[] = { + {DRIVER_NAME, 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); + + +#ifdef CONFIG_OF +static struct of_device_id synaptics_rmi4_dt_ids[] = { + { .compatible = "synaptics,rmi4" }, + { } +}; +#endif + +static struct i2c_driver synaptics_rmi4_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &synaptics_rmi4_dev_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(synaptics_rmi4_dt_ids), +#endif + }, + .probe = synaptics_rmi4_probe, + .remove = synaptics_rmi4_remove, +#ifdef USE_SHUTDOWN_CB + .shutdown = synaptics_rmi4_shutdown, +#endif + .id_table = synaptics_rmi4_id_table, +}; + +/** + * synaptics_rmi4_init() + * + * Called by the kernel during do_initcalls (if built-in) + * or when the driver is loaded (if a module). + * + * This function registers the driver to the I2C subsystem. + * + */ +static int __init synaptics_rmi4_init(void) +{ + return i2c_add_driver(&synaptics_rmi4_driver); +} + +/** + * synaptics_rmi4_exit() + * + * Called by the kernel when the driver is unloaded. + * + * This funtion unregisters the driver from the I2C subsystem. + * + */ +static void __exit synaptics_rmi4_exit(void) +{ + i2c_del_driver(&synaptics_rmi4_driver); +} + +module_init(synaptics_rmi4_init); +module_exit(synaptics_rmi4_exit); + +MODULE_AUTHOR("Synaptics, Inc."); +MODULE_DESCRIPTION("Synaptics RMI4 I2C Touch Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(SYNAPTICS_RMI4_DRIVER_VERSION); diff --git a/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.h b/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.h new file mode 100644 index 000000000000..04408a748a18 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx2/synaptics_i2c_rmi.h @@ -0,0 +1,1546 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _SYNAPTICS_RMI4_H_ +#define _SYNAPTICS_RMI4_H_ + +#define SYNAPTICS_RMI4_DRIVER_VERSION "DS5 1.0" +#include +#include +#include + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +#include +#endif +#ifdef CONFIG_INPUT_BOOSTER +#include +#endif + +/**************************************/ +/* Define related with driver feature */ +#define FACTORY_MODE +#define PROXIMITY_MODE +//#define EDGE_SWIPE +#define USE_SHUTDOWN_CB + +#define CHECK_PR_NUMBER +#define REPORT_2D_W + +#ifdef CONFIG_SEC_FACTORY +#define REPORT_2D_Z /* only for CONFIG_SEC_FACTORY */ +#endif +#ifdef REPORT_2D_Z +#define DSX_PRESSURE_MAX 255 +#endif + +#ifdef CONFIG_INPUT_BOOSTER +#define TSP_BOOSTER +#endif +#if defined(CONFIG_GLOVE_TOUCH) +#define GLOVE_MODE +#endif + +//#define USE_STYLUS +#define USE_ACTIVE_REPORT_RATE + +/* #define SKIP_UPDATE_FW_ON_PROBE */ +/* #define REPORT_ORIENTATION */ +/* #define USE_SENSOR_SLEEP */ +/**************************************/ +/**************************************/ + +/* Show TSP status information for debug */ +#define PRINT_DEBUG_INFO +#ifdef PRINT_DEBUG_INFO +#define F51_HAND_EDGE_DATA_SIZE 9 +#define F51_HAS_DELTA_INFO (1 << 3) +#define F51_HAS_HAND_EDGE (1 << 4) +#define F54_DATA10_ADDR 0x0108 +#define F54_DATA14_ADDR 0X0109 +#define F54_DATA16_ADDR 0x010a +#define F54_DATA17_ADDR 0x010bf +#endif + +#ifdef CONFIG_SEC_DEBUG_TSP_LOG +#define tsp_debug_dbg(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_dbg(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_dbg(dev, fmt, ## __VA_ARGS__); \ +}) + +#define tsp_debug_info(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_info(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_info(dev, fmt, ## __VA_ARGS__); \ +}) + +#define tsp_debug_err(mode, dev, fmt, ...) \ +({ \ + if (mode) { \ + dev_err(dev, fmt, ## __VA_ARGS__); \ + sec_debug_tsp_log(fmt, ## __VA_ARGS__); \ + } \ + else \ + dev_err(dev, fmt, ## __VA_ARGS__); \ +}) +#else +#define tsp_debug_dbg(mode, dev, fmt, ...) dev_dbg(dev, fmt, ## __VA_ARGS__) +#define tsp_debug_info(mode, dev, fmt, ...) dev_info(dev, fmt, ## __VA_ARGS__) +#define tsp_debug_err(mode, dev, fmt, ...) dev_err(dev, fmt, ## __VA_ARGS__) +#endif + +#define SYNAPTICS_DEVICE_NAME "SYNAPTICS" +#define DRIVER_NAME "synaptics_rmi4_i2c" + +#define SYNAPTICS_HW_RESET_TIME 100 +#define SYNAPTICS_REZERO_TIME 100 +#define SYNAPTICS_POWER_MARGIN_TIME 150 +#define SYNAPTICS_DEEPSLEEP_TIME 20 + +#define TSP_FACTEST_RESULT_PASS 2 +#define TSP_FACTEST_RESULT_FAIL 1 +#define TSP_FACTEST_RESULT_NONE 0 + +#define SYNAPTICS_MAX_FW_PATH 64 + +#define SYNAPTICS_DEFAULT_UMS_FW "/sdcard/synaptics.fw" + +#define DEFAULT_DEVICE_NUM 1 + +/* Define for Firmware file image format */ +#define FIRMWARE_IMG_HEADER_MAJOR_VERSION_OFFSET (0x07) +#define NEW_IMG_MAJOR_VERSION (0x10) + + +/* New firmware image format(PR number is loaded defaultly) for v7 */ +#define PR_NUMBER_0TH_BYTE_BIN_OFFSET_V7 (0x84) + +#define PDT_PROPS (0X00EF) +#define PDT_START (0x00E9) +#define PDT_END (0x000A) +#define PDT_ENTRY_SIZE (0x0006) +#define PAGES_TO_SERVICE (10) +#define PAGE_SELECT_LEN (2) + +#define SYNAPTICS_RMI4_F01 (0x01) +#define SYNAPTICS_RMI4_F11 (0x11) +#define SYNAPTICS_RMI4_F12 (0x12) +#define SYNAPTICS_RMI4_F1A (0x1a) +#define SYNAPTICS_RMI4_F34 (0x34) +#define SYNAPTICS_RMI4_F51 (0x51) +#define SYNAPTICS_RMI4_F54 (0x54) +#define SYNAPTICS_RMI4_F55 (0x55) +#define SYNAPTICS_RMI4_F60 (0x60) +#define SYNAPTICS_RMI4_FDB (0xdb) + +#define SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2 +#define SYNAPTICS_RMI4_DATE_CODE_SIZE 3 +#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10 +#define SYNAPTICS_RMI4_BUILD_ID_SIZE 3 +#define SYNAPTICS_RMI4_PRODUCT_ID_LENGTH 10 +#define SYNAPTICS_RMI4_PACKAGE_ID_SIZE 4 + +#define MAX_NUMBER_OF_BUTTONS 4 +#define MAX_INTR_REGISTERS 4 +#define F12_FINGERS_TO_SUPPORT 10 +#define MAX_NUMBER_OF_FINGERS (F12_FINGERS_TO_SUPPORT) + +#define MASK_16BIT 0xFFFF +#define MASK_8BIT 0xFF +#define MASK_7BIT 0x7F +#define MASK_6BIT 0x3F +#define MASK_5BIT 0x1F +#define MASK_4BIT 0x0F +#define MASK_3BIT 0x07 +#define MASK_2BIT 0x03 +#define MASK_1BIT 0x01 + +#define INVALID_X 65535 +#define INVALID_Y 65535 + +/* Define for Object type and status(F12_2D_data(N)/0). + * Each 3-bit finger status field represents the following: + * 000 = finger not present + * 001 = finger present and data accurate + * 010 = stylus pen (passive pen) + * 011 = palm touch + * 100 = not used + * 101 = hover + * 110 = glove touch + */ +#define OBJECT_NOT_PRESENT (0x00) +#define OBJECT_FINGER (0x01) +#define OBJECT_PASSIVE_STYLUS (0x02) +#define OBJECT_PALM (0x03) +#define OBJECT_UNCLASSIFIED (0x04) +#define OBJECT_HOVER (0x05) +#define OBJECT_GLOVE (0x06) + +/* Define for object type report enable Mask(F12_2D_CTRL23) */ +#define OBJ_TYPE_FINGER (1 << 0) +#define OBJ_TYPE_PASSIVE_STYLUS (1 << 1) +#define OBJ_TYPE_PALM (1 << 2) +#define OBJ_TYPE_UNCLASSIFIED (1 << 3) +#define OBJ_TYPE_HOVER (1 << 4) +#define OBJ_TYPE_GLOVE (1 << 5) +#define OBJ_TYPE_NARROW_SWIPE (1 << 6) +#define OBJ_TYPE_HANDEDGE (1 << 7) +#define OBJ_TYPE_DEFAULT (0x85) +/*OBJ_TYPE_FINGER, OBJ_TYPE_UNCLASSIFIED, OBJ_TYPE_HANDEDGE*/ + +/* Define for Data report enable Mask(F12_2D_CTRL28) */ +#define RPT_TYPE (1 << 0) +#define RPT_X_LSB (1 << 1) +#define RPT_X_MSB (1 << 2) +#define RPT_Y_LSB (1 << 3) +#define RPT_Y_MSB (1 << 4) +#define RPT_Z (1 << 5) +#define RPT_WX (1 << 6) +#define RPT_WY (1 << 7) +#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB) + +/* Define for Feature enable(F12_2D_CTRL26) + * bit[0] : represent enable or disable glove mode(high sensitivity mode) + * bit[1] : represent enable or disable cover mode. + * (cover is on lcd, change sensitivity to prevent unintended touch) + * bit[2] : represent enable or disable fast glove mode. + * (change glove mode entering condition to be faster) + */ +#define GLOVE_DETECTION_EN (1 << 0) +#define CLOSED_COVER_EN (1 << 1) +#define FAST_GLOVE_DECTION_EN (1 << 2) + +#define CLEAR_COVER_MODE_EN (CLOSED_COVER_EN | GLOVE_DETECTION_EN) +#define FLIP_COVER_MODE_EN (CLOSED_COVER_EN) + +#ifdef PROXIMITY_MODE +#define F51_FINGER_TIMEOUT 50 /* ms */ +#define HOVER_Z_MAX (255) + +#define F51_PROXIMITY_ENABLES_OFFSET (0) +/* Define for proximity enables(F51_CUSTOM_CTRL00) */ +#define FINGER_HOVER_EN (1 << 0) +#define AIR_SWIPE_EN (1 << 1) +#define LARGE_OBJ_EN (1 << 2) +#define HOVER_PINCH_EN (1 << 3) +#define LARGE_OBJ_WAKEUP_GESTURE_EN (1 << 4) +/* Reserved 5 */ +#define ENABLE_HANDGRIP_RECOG (1 << 6) +#define SLEEP_PROXIMITY (1 << 7) + +#define F51_GENERAL_CONTROL_OFFSET (1) +/* Define for General Control(F51_CUSTOM_CTRL01) */ +#define JIG_TEST_EN (1 << 0) +#define JIG_COMMAND_EN (1 << 1) +#define DEAD_ZONE_EN (1 << 2) +#define EN_GHOST_FINGER_STATUS_REPORT (1 << 3) +//#define RESERVED (1 << 4) +#define EDGE_SWIPE_EN (1 << 5) +//#define RESERVED (1 << 6) +//#define RESERVED (1 << 7) + +#define F51_GENERAL_CONTROL_2_OFFSET (2) +/* Define for General Control(F51_CUSTOM_CTRL02) */ +/* Reserved 0 ~ 7 */ + +/* Define for proximity Controls(F51_CUSTOM_QUERY04) */ +//#define HAS_FINGER_HOVER (1 << 0) +//#define HAS_AIR_SWIPE (1 << 1) +//#define HAS_LARGE_OBJ (1 << 2) +//#define HAS_HOVER_PINCH (1 << 3) +#define HAS_EDGE_SWIPE (1 << 4) +//#define HAS_SINGLE_FINGER (1 << 5) +//#define HAS_GRIP_SUPPRESSION (1 << 6) +//#define HAS_PALM_REJECTION (1 << 7) + +/* Define for proximity Controls 2(F51_CUSTOM_QUERY05) */ +#define HAS_PROFILE_HANDEDNESS (1 << 0) +#define HAS_LOWG (1 << 1) +#define HAS_FACE_DETECTION (1 << 2) +#define HAS_SIDE_BUTTONS (1 << 3) +#define HAS_CAMERA_GRIP_DETECTION (1 << 4) +/* Reserved 5 ~ 7 */ + +/* Define for Detection flag 2(F51_CUSTOM_DATA06) */ +#define HAS_HAND_EDGE_SWIPE_DATA (1 << 0) +#define SIDE_BUTTON_DETECTED (1 << 1) +/* Reserved 2 ~ 7 */ + +#define F51_DATA_RESERVED_SIZE (1) +#define F51_DATA_1_SIZE (4) /* FINGER_HOVER */ +#define F51_DATA_2_SIZE (1) /* HOVER_PINCH */ +#define F51_DATA_3_SIZE (1) /* AIR_SWIPE | LARGE_OBJ */ +#define F51_DATA_4_SIZE (2) /* SIDE_BUTTON */ +#define F51_DATA_5_SIZE (1) /* CAMERA_GRIP_DETECTION */ +#define F51_DATA_6_SIZE (2) /* DETECTION_FLAG2 */ + +#ifdef EDGE_SWIPE +#define EDGE_SWIPE_WIDTH_MAX 255 +#define EDGE_SWIPE_PALM_MAX 1 + +#define EDGE_SWIPE_WITDH_X_OFFSET 5 +#define EDGE_SWIPE_AREA_OFFSET 7 +#endif + +#ifdef SIDE_TOUCH +#define MAX_SIDE_BUTTONS 8 +#define NUM_OF_ACTIVE_SIDE_BUTTONS 6 +#endif +#endif + +#define SYN_I2C_RETRY_TIMES 3 +#define MAX_F11_TOUCH_WIDTH 15 + +#define CHECK_STATUS_TIMEOUT_MS 200 +#define F01_STD_QUERY_LEN 21 +#define F01_BUID_ID_OFFSET 18 +#define F11_STD_QUERY_LEN 9 +#define F11_STD_CTRL_LEN 10 +#define F11_STD_DATA_LEN 12 +#define STATUS_NO_ERROR 0x00 +#define STATUS_RESET_OCCURRED 0x01 +#define STATUS_INVALID_CONFIG 0x02 +#define STATUS_DEVICE_FAILURE 0x03 +#define STATUS_CONFIG_CRC_FAILURE 0x04 +#define STATUS_FIRMWARE_CRC_FAILURE 0x05 +#define STATUS_CRC_IN_PROGRESS 0x06 + +/* Define for Device Control(F01_RMI_CTRL00) */ +#define NORMAL_OPERATION (0 << 0) +#define SENSOR_SLEEP (1 << 0) +#define NO_SLEEP_ON (1 << 2) +/* Reserved 3 ~ 4 */ +#define CHARGER_CONNECTED (1 << 5) +#define REPORT_RATE (1 << 6) +#define CONFIGURED (1 << 7) + +#define TSP_NEEDTO_REBOOT (-ECONNREFUSED) +#define MAX_TSP_REBOOT 3 + +#define SYNAPTICS_BL_ID_0_OFFSET 0 +#define SYNAPTICS_BL_ID_1_OFFSET 1 +#define SYNAPTICS_BL_MINOR_REV_OFFSET 2 +#define SYNAPTICS_BL_MAJOR_REV_OFFSET 3 + +#define SYNAPTICS_BOOTLOADER_ID_SIZE 4 + + +#define SYNAPTICS_BL_PROPERTIES_V7 0 +#define SYNAPTICS_BL_MINOR_REV_OFFSET_V7 1 +#define SYNAPTICS_BL_MAJOR_REV_OFFSET_V7 2 + +#define SYNAPTICS_BOOTLOADER_REVISION 3 + + +/* Below version is represent that it support guest thread functionality. */ +#define BL_MAJOR_VER_OF_GUEST_THREAD 0x36 /* '6' */ +#define BL_MINOR_VER_OF_GUEST_THREAD 0x34 /* '4' */ + +#define SYNAPTICS_ACCESS_READ false +#define SYNAPTICS_ACCESS_WRITE true + +/* Below offsets are defined manually. + * So please keep in your mind when use this. it can be changed based on + * firmware version you can check it debug_address sysfs node + * (sys/class/sec/tsp/cmd). + * If it is possible to replace that getting address from IC, + * I recommend the latter than former. + */ +#ifdef PROXIMITY_MODE +#define MANUAL_DEFINED_OFFSET_GRIP_EDGE_EXCLUSION_RX (32) +#endif +#ifdef SIDE_TOUCH +#define MANUAL_DEFINED_OFFSET_SIDEKEY_THRESHOLD (47) +#endif +#ifdef USE_STYLUS +#define MANUAL_DEFINED_OFFSET_FORCEFINGER_ON_EDGE (61) +#endif +/* Enum for each product id */ +enum synaptics_product_ids { + SYNAPTICS_PRODUCT_ID_NONE = 0, + SYNAPTICS_PRODUCT_ID_S5807, + SYNAPTICS_PRODUCT_ID_S5806, + SYNAPTICS_PRODUCT_ID_S5300, + SYNAPTICS_PRODUCT_ID_MAX +}; + +/* Define for Revision of IC */ +#define SYNAPTICS_IC_REVISION_AA 0xAA + +/* Release event type for manual release.. */ +#define RELEASE_TYPE_FINGER (1 << 0) +#define RELEASE_TYPE_SIDEKEY (1 << 1) + +#define RELEASE_TYPE_ALL (RELEASE_TYPE_FINGER | RELEASE_TYPE_SIDEKEY) + +#ifdef USE_ACTIVE_REPORT_RATE +#define SYNAPTICS_RPT_RATE_30HZ_VAL (0x50) +#define SYNAPTICS_RPT_RATE_60HZ_VAL (0x16) +#define SYNAPTICS_RPT_RATE_90HZ_VAL (0x04) + +enum synaptics_report_rate { + SYNAPTICS_RPT_RATE_START = 0, + SYNAPTICS_RPT_RATE_90HZ = SYNAPTICS_RPT_RATE_START, + SYNAPTICS_RPT_RATE_60HZ, + SYNAPTICS_RPT_RATE_30HZ, + SYNAPTICS_RPT_RATE_END +}; +#endif + +/* load Register map file */ +#include "rmi_register_map.h" + +struct synaptics_rmi4_f1a_handle { + int button_bitmask_size; + unsigned char max_count; + unsigned char valid_button_count; + unsigned char *button_data_buffer; + unsigned char *button_map; + struct synaptics_rmi4_f1a_query button_query; + struct synaptics_rmi4_f1a_control button_control; +}; + +#ifdef PROXIMITY_MODE +#ifdef EDGE_SWIPE +struct synaptics_rmi4_edge_swipe { + int sumsize; + int palm; + int wx; + int wy; +}; +#endif + +struct synaptics_rmi4_f51_handle { +/* CTRL */ + unsigned char proximity_enables; /* F51_CUSTOM_CTRL00 */ + unsigned short proximity_enables_addr; + unsigned char general_control; /* F51_CUSTOM_CTRL01 */ + unsigned short general_control_addr; + unsigned char general_control_2; /* F51_CUSTOM_CTRL02 */ + unsigned short general_control_2_addr; +#ifdef PROXIMITY_MODE + unsigned short grip_edge_exclusion_rx_addr; +#endif +#ifdef SIDE_TOUCH + unsigned short sidebutton_tapthreshold_addr; +#endif +#ifdef USE_STYLUS + unsigned short forcefinger_onedge_addr; +#endif +/* QUERY */ + unsigned char proximity_controls; /* F51_CUSTOM_QUERY04 */ + unsigned char proximity_controls_2; /* F51_CUSTOM_QUERY05 */ +/* DATA */ + unsigned short detection_flag_2_addr; /* F51_CUSTOM_DATA06 */ + unsigned short edge_swipe_data_addr; /* F51_CUSTOM_DATA07 */ +#ifdef EDGE_SWIPE + struct synaptics_rmi4_edge_swipe edge_swipe_data; +#endif + unsigned short side_button_data_addr; /* F51_CUSTOM_DATA04 */ + bool finger_is_hover; /* To print hover log */ +}; +#endif + +/* + * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT + * @query_base_addr: base address for query registers + * @cmd_base_addr: base address for command registers + * @ctrl_base_addr: base address for control registers + * @data_base_addr: base address for data registers + * @intr_src_count: number of interrupt sources + * @fn_number: function number + */ +struct synaptics_rmi4_fn_desc { + unsigned char query_base_addr; + unsigned char cmd_base_addr; + unsigned char ctrl_base_addr; + unsigned char data_base_addr; + unsigned char intr_src_count:3; + unsigned char reserved_1:2; + unsigned char fn_version:2; + unsigned char reserved_2:1; + unsigned char fn_number; +}; + +/* + * synaptics_rmi4_fn_full_addr - full 16-bit base addresses + * @query_base: 16-bit base address for query registers + * @cmd_base: 16-bit base address for data registers + * @ctrl_base: 16-bit base address for command registers + * @data_base: 16-bit base address for control registers + */ +struct synaptics_rmi4_fn_full_addr { + unsigned short query_base; + unsigned short cmd_base; + unsigned short ctrl_base; + unsigned short data_base; +}; + +/* + * struct synaptics_rmi4_fn - function handler data structure + * @fn_number: function number + * @num_of_data_sources: number of data sources + * @num_of_data_points: maximum number of fingers supported + * @size_of_data_register_block: data register block size + * @data1_offset: offset to data1 register from data base address + * @intr_reg_num: index to associated interrupt register + * @intr_mask: interrupt mask + * @full_addr: full 16-bit base addresses of function registers + * @link: linked list for function handlers + * @data_size: size of private data + * @data: pointer to private data + */ +struct synaptics_rmi4_fn { + unsigned char fn_number; + unsigned char num_of_data_sources; + unsigned char num_of_data_points; + unsigned char size_of_data_register_block; + unsigned char intr_reg_num; + unsigned char intr_mask; + struct synaptics_rmi4_fn_full_addr full_addr; + struct list_head link; + int data_size; + void *data; + void *extra; +}; + +/* + * struct synaptics_rmi4_device_info - device information + * @version_major: rmi protocol major version number + * @version_minor: rmi protocol minor version number + * @manufacturer_id: manufacturer id + * @product_props: product properties information + * @product_info: product info array + * @date_code: device manufacture date + * @tester_id: tester id array + * @serial_number: device serial number + * @product_id_string: device product id + * @support_fn_list: linked list for function handlers + * @exp_fn_list: linked list for expanded function handlers + */ +struct synaptics_rmi4_device_info { + unsigned int version_major; + unsigned int version_minor; + unsigned char manufacturer_id; + unsigned char product_props; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; + unsigned char date_code[SYNAPTICS_RMI4_DATE_CODE_SIZE]; + unsigned short tester_id; + unsigned short serial_number; + unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE]; + unsigned int package_id; + unsigned int package_rev; + unsigned int pr_number; + struct list_head support_fn_list; + struct list_head exp_fn_list; +}; + +/** + * struct synaptics_finger - Represents fingers. + * @ state: finger status. + * @ mcount: moving counter for debug. + * @ stylus: represent stylus.. + */ +struct synaptics_finger { + unsigned char state; + unsigned short mcount; +#ifdef USE_STYLUS + bool stylus; +#endif +}; + +struct synaptics_rmi4_f12_handle { +/* CTRL */ + unsigned short ctrl11_addr; /* F12_2D_CTRL11 : for jitter level*/ + unsigned short ctrl15_addr; /* F12_2D_CTRL15 : for finger amplitude threshold */ + unsigned short ctrl23_addr; /* F12_2D_CTRL23 : object report enable */ + unsigned char obj_report_enable; /* F12_2D_CTRL23 */ + unsigned short ctrl26_addr; /* F12_2D_CTRL26 : for glove mode */ + unsigned char feature_enable; /* F12_2D_CTRL26 */ + unsigned short ctrl28_addr; /* F12_2D_CTRL28 : for report data */ + unsigned char report_enable; /* F12_2D_CTRL28 */ +/* QUERY */ + unsigned char glove_mode_feature; /* F12_2D_QUERY_10 */ +}; + +enum bl_version { + V5 = 5, + V6 = 6, + BL_V5 = 5, + BL_V6 = 6, + BL_V7 = 7, +}; + +#define IMAGE_HEADER_VERSION_05 0x05 +#define IMAGE_HEADER_VERSION_06 0x06 +#define IMAGE_HEADER_VERSION_10 0x10 + +#define IMAGE_AREA_OFFSET 0x100 +#define LOCKDOWN_SIZE 0x50 + +enum v7_flash_command2 { + CMD_V7_IDLE = 0x00, + CMD_V7_ENTER_BL, + CMD_V7_READ, + CMD_V7_WRITE, + CMD_V7_ERASE, + CMD_V7_ERASE_AP, + CMD_V7_SENSOR_ID, +}; + +enum v7_flash_command { + v7_CMD_IDLE = 0, + v7_CMD_WRITE_FW, + v7_CMD_WRITE_CONFIG, + v7_CMD_WRITE_LOCKDOWN, + v7_CMD_WRITE_GUEST_CODE, + v7_CMD_READ_CONFIG, + v7_CMD_ERASE_ALL, + v7_CMD_ERASE_UI_FIRMWARE, + v7_CMD_ERASE_UI_CONFIG, + v7_CMD_ERASE_BL_CONFIG, + v7_CMD_ERASE_DISP_CONFIG, + v7_CMD_ERASE_FLASH_CONFIG, + v7_CMD_ERASE_GUEST_CODE, + v7_CMD_ENABLE_FLASH_PROG, +}; + +enum v7_config_area { + v7_UI_CONFIG_AREA = 0, + v7_PM_CONFIG_AREA, + v7_BL_CONFIG_AREA, + v7_DP_CONFIG_AREA, + v7_FLASH_CONFIG_AREA, +}; + +enum v7_partition_id { + BOOTLOADER_PARTITION = 0x01, + DEVICE_CONFIG_PARTITION, + FLASH_CONFIG_PARTITION, + MANUFACTURING_BLOCK_PARTITION, + GUEST_SERIALIZATION_PARTITION, + GLOBAL_PARAMETERS_PARTITION, + CORE_CODE_PARTITION, + CORE_CONFIG_PARTITION, + GUEST_CODE_PARTITION, + DISPLAY_CONFIG_PARTITION, +}; + +struct partition_table { + unsigned char partition_id:5; + unsigned char byte_0_reserved:3; + unsigned char byte_1_reserved; + unsigned char partition_length_7_0; + unsigned char partition_length_15_8; + unsigned char start_physical_address_7_0; + unsigned char start_physical_address_15_8; + unsigned char partition_properties_7_0; + unsigned char partition_properties_15_8; +} __packed; + +struct physical_address { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short guest_code; +}; + +struct block_count { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short fl_config; + unsigned short pm_config; + unsigned short bl_config; + unsigned short lockdown; + unsigned short guest_code; +}; + +struct f34_v7_query_0 { + union { + struct { + unsigned char subpacket_1_size:3; + unsigned char has_config_id:1; + unsigned char f34_query0_b4:1; + unsigned char has_thqa:1; + unsigned char f34_query0_b6__7:2; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_query_1_7 { + union { + struct { + /* query 1 */ + unsigned char bl_minor_revision; + unsigned char bl_major_revision; + + /* query 2 */ + unsigned char bl_fw_id_7_0; + unsigned char bl_fw_id_15_8; + unsigned char bl_fw_id_23_16; + unsigned char bl_fw_id_31_24; + + /* query 3 */ + unsigned char minimum_write_size; + unsigned char block_size_7_0; + unsigned char block_size_15_8; + unsigned char flash_page_size_7_0; + unsigned char flash_page_size_15_8; + + /* query 4 */ + unsigned char adjustable_partition_area_size_7_0; + unsigned char adjustable_partition_area_size_15_8; + + /* query 5 */ + unsigned char flash_config_length_7_0; + unsigned char flash_config_length_15_8; + + /* query 6 */ + unsigned char payload_length_7_0; + unsigned char payload_length_15_8; + + /* query 7 */ + unsigned char f34_query7_b0:1; + unsigned char has_bootloader:1; + unsigned char has_device_config:1; + unsigned char has_flash_config:1; + unsigned char has_manufacturing_block:1; + unsigned char has_guest_serialization:1; + unsigned char has_global_parameters:1; + unsigned char has_core_code:1; + unsigned char has_core_config:1; + unsigned char has_guest_code:1; + unsigned char has_display_config:1; + unsigned char f34_query7_b11__15:5; + unsigned char f34_query7_b16__23; + unsigned char f34_query7_b24__31; + } __packed; + unsigned char data[21]; + }; +}; + +struct f34_v7_data_1_5 { + union { + struct { + unsigned char partition_id:5; + unsigned char f34_data1_b5__7:3; + unsigned char block_offset_7_0; + unsigned char block_offset_15_8; + unsigned char transfer_length_7_0; + unsigned char transfer_length_15_8; + unsigned char command; + unsigned char payload_0; + unsigned char payload_1; + } __packed; + unsigned char data[8]; + }; +}; + +static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size, + const unsigned char *src, unsigned int src_size, + unsigned int count) +{ + if (dest == NULL || src == NULL) + return -EINVAL; + + if (count > dest_size || count > src_size) + return -EINVAL; + + memcpy((void *)dest, (const void *)src, count); + + return 0; +} +struct f01_device_control { + union { + struct { + unsigned char sleep_mode:2; + unsigned char nosleep:1; + unsigned char reserved:2; + unsigned char charger_connected:1; + unsigned char report_rate:1; + unsigned char configured:1; + } __packed; + unsigned char data[1]; + }; +}; + + +enum flash_area { + NONE, + UI_FIRMWARE, + CONFIG_AREA, +}; + +enum update_mode { + UPDATE_MODE_NORMAL = 1, + UPDATE_MODE_FORCE = 2, + UPDATE_MODE_LOCKDOWN = 8, +}; + +enum flash_command { + CMD_IDLE = 0x0, + CMD_WRITE_FW_BLOCK = 0x2, + CMD_ERASE_ALL = 0x3, + CMD_WRITE_LOCKDOWN_BLOCK = 0x4, + CMD_READ_CONFIG_BLOCK = 0x5, + CMD_WRITE_CONFIG_BLOCK = 0x6, + CMD_ERASE_CONFIG = 0x7, + CMD_READ_SENSOR_ID = 0x8, + CMD_ERASE_BL_CONFIG = 0x9, + CMD_ERASE_DISP_CONFIG = 0xA, + CMD_ERASE_GUEST_CODE = 0xB, + CMD_WRITE_GUEST_CODE = 0xC, + CMD_ENABLE_FLASH_PROG = 0xF +}; + +struct img_x0x6_header { + /* 0x00 - 0x0f */ + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char options_firmware_id:1; + unsigned char options_contain_bootloader:1; + unsigned char options_reserved:6; + unsigned char bootloader_version; + unsigned char firmware_size[4]; + unsigned char config_size[4]; + /* 0x10 - 0x1f */ + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE]; + unsigned char package_id[2]; + unsigned char package_id_revision[2]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; + /* 0x20 - 0x2f */ + unsigned char reserved_20_2f[16]; + /* 0x30 - 0x3f */ + unsigned char ds_firmware_info[16]; + /* 0x40 - 0x4f */ + unsigned char ds_info[10]; + unsigned char reserved_4a_4f[6]; + /* 0x50 - 0x53 */ + unsigned char firmware_id[4]; +}; + +enum img_x10_container_id { + ID_TOP_LEVEL_CONTAINER = 0, + ID_UI_CONTAINER, + ID_UI_CONFIGURATION, + ID_BOOTLOADER_CONTAINER, + ID_BOOTLOADER_IMAGE_CONTAINER, + ID_BOOTLOADER_CONFIGURATION_CONTAINER, + ID_BOOTLOADER_LOCKDOWN_INFORMATION_CONTAINER, + ID_PERMANENT_CONFIGURATION_CONTAINER, + ID_GUEST_CODE_CONTAINER, + ID_BOOTLOADER_PROTOCOL_DESCRIPTOR_CONTAINER, + ID_UI_PROTOCOL_DESCRIPTOR_CONTAINER, + ID_RMI_SELF_DISCOVERY_CONTAINER, + ID_RMI_PAGE_CONTENT_CONTAINER, + ID_GENERAL_INFORMATION_CONTAINER, + RESERVERD +}; + +struct block_data { + // for v7 + unsigned char *data; + int size; +}; + +#define PRODUCT_INFO_SIZE 2 +#define PRODUCT_ID_SIZE 10 +#define BUILD_ID_SIZE 3 + +struct image_header_05_06 { + /* 0x00 - 0x0f */ + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char options_firmware_id:1; + unsigned char options_bootloader:1; + unsigned char options_guest_code:1; + unsigned char options_tddi:1; + unsigned char options_reserved:4; + unsigned char header_version; + unsigned char firmware_size[4]; + unsigned char config_size[4]; + /* 0x10 - 0x1f */ + unsigned char product_id[PRODUCT_ID_SIZE]; + unsigned char package_id[2]; + unsigned char package_id_revision[2]; + unsigned char product_info[PRODUCT_INFO_SIZE]; + /* 0x20 - 0x2f */ + unsigned char bootloader_addr[4]; + unsigned char bootloader_size[4]; + unsigned char ui_addr[4]; + unsigned char ui_size[4]; + /* 0x30 - 0x3f */ + unsigned char ds_id[16]; + /* 0x40 - 0x4f */ + union { + struct { + unsigned char cstmr_product_id[PRODUCT_ID_SIZE]; + unsigned char reserved_4a_4f[6]; + }; + struct { + unsigned char dsp_cfg_addr[4]; + unsigned char dsp_cfg_size[4]; + unsigned char reserved_48_4f[8]; + }; + }; + /* 0x50 - 0x53 */ + unsigned char firmware_id[4]; +}; + +struct container_descriptor { + unsigned char content_checksum[4]; + unsigned char container_id[2]; + unsigned char minor_version; + unsigned char major_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char container_option_flags[4]; + unsigned char content_options_length[4]; + unsigned char content_options_address[4]; + unsigned char content_length[4]; + unsigned char content_address[4]; +}; + +enum container_id { + TOP_LEVEL_CONTAINER = 0, + UI_CONTAINER, + UI_CONFIG_CONTAINER, + BL_CONTAINER, + BL_IMAGE_CONTAINER, + BL_CONFIG_CONTAINER, + BL_LOCKDOWN_INFO_CONTAINER, + PERMANENT_CONFIG_CONTAINER, + GUEST_CODE_CONTAINER, + BL_PROTOCOL_DESCRIPTOR_CONTAINER, + UI_PROTOCOL_DESCRIPTOR_CONTAINER, + RMI_SELF_DISCOVERY_CONTAINER, + RMI_PAGE_CONTENT_CONTAINER, + GENERAL_INFORMATION_CONTAINER, + DEVICE_CONFIG_CONTAINER, + FLASH_CONFIG_CONTAINER, + GUEST_SERIALIZATION_CONTAINER, + GLOBAL_PARAMETERS_CONTAINER, + CORE_CODE_CONTAINER, + CORE_CONFIG_CONTAINER, + DISPLAY_CONFIG_CONTAINER, +}; + + +struct image_header_10 { + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char minor_header_version; + unsigned char major_header_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char top_level_container_start_addr[4]; +}; + +struct image_metadata { + bool contains_firmware_id; + bool contains_bootloader; + bool contains_disp_config; + bool contains_guest_code; + bool contains_flash_config; + unsigned int firmware_id; + unsigned int checksum; + unsigned int bootloader_size; + unsigned int disp_config_offset; + unsigned char bl_version; + unsigned char product_id[PRODUCT_ID_SIZE + 1]; + unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; + struct block_data bootloader; + struct block_data ui_firmware; + struct block_data ui_config; + struct block_data dp_config; + struct block_data fl_config; + struct block_data bl_config; + struct block_data guest_code; + struct block_data lockdown; + struct block_count blkcount; + struct physical_address phyaddr; +}; +struct register_offset { + unsigned char properties; + unsigned char properties_2; + unsigned char block_size; + unsigned char block_count; + unsigned char gc_block_count; + unsigned char flash_status; + unsigned char partition_id; + unsigned char block_number; + unsigned char transfer_length; + unsigned char flash_cmd; + unsigned char payload; +}; + +struct img_file_content { + unsigned char *fw_image; + unsigned int image_size; + unsigned char *image_name; + unsigned char imageFileVersion; + struct block_data uiFirmware; + struct block_data uiConfig; + struct block_data guestCode; + struct block_data lockdown; + struct block_data permanent; + struct block_data bootloaderInfo; + unsigned char blMajorVersion; + unsigned char blMinorVersion; + unsigned char *configId; /* len 0x4 */ + unsigned char *firmwareId; /* len 0x4 */ + unsigned char *packageId; /* len 0x4 */ + unsigned char *dsFirmwareInfo; /* len 0x10 */ +}; + +struct img_x10_descriptor { + unsigned char contentChecksum[4]; + unsigned char containerID[2]; + unsigned char minorVersion; + unsigned char majorVersion; + unsigned char reserverd[4]; + unsigned char containerOptionFlags[4]; + unsigned char contentOptionLength[4]; + unsigned char contentOptionAddress[4]; + unsigned char contentLength[4]; + unsigned char contentAddress[4]; +}; + +struct img_x10_bl_container { + unsigned char majorVersion; + unsigned char minorVersion; + unsigned char reserved[2]; + unsigned char *subContainer; +}; + +struct pdt_properties { + union { + struct { + unsigned char reserved_1:6; + unsigned char has_bsr:1; + unsigned char reserved_2:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct synaptics_rmi4_fwu_handle { + enum bl_version bl_version; + bool initialized; + bool program_enabled; + bool has_perm_config; + bool has_bl_config; + bool has_disp_config; + bool has_guest_code; + bool force_update; + bool in_flash_prog_mode; + bool do_lockdown; + bool can_guest_bootloader; + unsigned int data_pos; + unsigned char *ext_data_source; + unsigned char *read_config_buf; + unsigned char intr_mask; + unsigned char command; + unsigned char bootloader_id[4]; + unsigned char bootloader_id_ic[2]; + unsigned char flash_status; + unsigned char productinfo1; + unsigned char productinfo2; + unsigned char properties_off; + unsigned char blk_size_off; + unsigned char blk_count_off; + unsigned char blk_data_off; + unsigned char properties2_off; + unsigned char guest_blk_count_off; + unsigned char flash_cmd_off; + unsigned char flash_status_off; + unsigned short block_size; + unsigned short fw_block_count; + unsigned short config_block_count; + unsigned short perm_config_block_count; + unsigned short bl_config_block_count; + unsigned short disp_config_block_count; + unsigned short guest_code_block_count; + unsigned short config_size; + unsigned short config_area; + char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + + struct synaptics_rmi4_f34_query_01 flash_properties; + struct workqueue_struct *fwu_workqueue; + struct delayed_work fwu_work; + struct synaptics_rmi4_fn_desc f01_fd; + struct synaptics_rmi4_fn_desc f34_fd; + struct synaptics_rmi4_data *rmi4_data; + struct img_file_content img; + bool polling_mode; + struct kobject *attr_dir; + + unsigned short flash_config_length; + unsigned short payload_length; + struct register_offset off; + unsigned char partitions; + unsigned short partition_table_bytes; + unsigned short read_config_buf_size; + struct block_count blkcount; + struct physical_address phyaddr; + struct image_metadata v7_img; + bool new_partition_table; + const unsigned char *config_data; +// const unsigned char *image; + unsigned char *image; + bool in_bl_mode; +}; + +#ifdef FACTORY_MODE +#include + +#define CMD_STR_LEN 32 +#define CMD_PARAM_NUM 8 +#define CMD_RESULT_STR_LEN 768 +#define RPT_DATA_STRNCAT_LENGTH 9 + +#define DEBUG_RESULT_STR_LEN 1024 +#define MAX_VAL_OFFSET_AND_LENGTH 10 +#define DEBUG_STR_LEN (CMD_STR_LEN * 2) + +#define DEBUG_PRNT_SCREEN(_dest, _temp, _length, fmt, ...) \ +({ \ + snprintf(_temp, _length, fmt, ## __VA_ARGS__); \ + strcat(_dest, _temp); \ +}) + +#define FT_CMD(name, func) .cmd_name = name, .cmd_func = func + +enum CMD_STATUS { + CMD_STATUS_WAITING = 0, + CMD_STATUS_RUNNING, + CMD_STATUS_OK, + CMD_STATUS_FAIL, + CMD_STATUS_NOT_APPLICABLE, +}; + +struct ft_cmd { + const char *cmd_name; + void (*cmd_func)(void *dev_data); + struct list_head list; +}; + +struct factory_data { + struct device *fac_dev_ts; + short *rawcap_data; + short *delta_data; + int *abscap_data; + int *absdelta_data; + char *trx_short; + unsigned int abscap_rx_min; + unsigned int abscap_rx_max; + unsigned int abscap_tx_min; + unsigned int abscap_tx_max; + bool cmd_is_running; + unsigned char cmd_state; + char cmd[CMD_STR_LEN]; + int cmd_param[CMD_PARAM_NUM]; + char cmd_buff[CMD_RESULT_STR_LEN]; + char cmd_result[CMD_RESULT_STR_LEN]; + struct mutex cmd_lock; + struct list_head cmd_list_head; +}; +#endif + +enum f54_report_types { + F54_8BIT_IMAGE = 1, + F54_16BIT_IMAGE = 2, + F54_RAW_16BIT_IMAGE = 3, + F54_HIGH_RESISTANCE = 4, + F54_TX_TO_TX_SHORT = 5, + F54_RX_TO_RX1 = 7, + F54_TRUE_BASELINE = 9, + F54_FULL_RAW_CAP_MIN_MAX = 13, + F54_RX_OPENS1 = 14, + F54_TX_OPEN = 15, + F54_TX_TO_GROUND = 16, + F54_RX_TO_RX2 = 17, + F54_RX_OPENS2 = 18, + F54_FULL_RAW_CAP = 19, + F54_FULL_RAW_CAP_RX_COUPLING_COMP = 20, + F54_SENSOR_SPEED = 22, + F54_ADC_RANGE = 23, + F54_TREX_OPENS = 24, + F54_TREX_TO_GND = 25, + F54_TREX_SHORTS = 26, + F54_ABS_CAP = 38, + F54_ABS_DELTA = 40, + F54_ABS_ADC = 42, + INVALID_REPORT_TYPE = -1, +}; + +struct synaptics_rmi4_f54_handle { + bool no_auto_cal; + unsigned char status; + unsigned char intr_mask; + unsigned char intr_reg_num; + unsigned char rx_assigned; + unsigned char tx_assigned; + unsigned char *report_data; + unsigned short query_base_addr; + unsigned short control_base_addr; + unsigned short data_base_addr; + unsigned short command_base_addr; + unsigned short fifoindex; + unsigned int report_size; + unsigned int data_buffer_size; + enum f54_report_types report_type; + struct mutex status_mutex; + struct mutex data_mutex; + struct mutex control_mutex; + struct f54_query query; + struct f54_query_13 query_13; + struct f54_query_15 query_15; + struct f54_query_16 query_16; + struct f54_query_21 query_21; + struct f54_control control; +#ifdef FACTORY_MODE + struct factory_data *factory_data; +#endif + struct kobject *attr_dir; + struct hrtimer watchdog; + struct work_struct timeout_work; + struct delayed_work status_work; + struct workqueue_struct *status_workqueue; + struct synaptics_rmi4_data *rmi4_data; +}; + +struct rmidev_data { + int ref_count; + struct cdev main_dev; + struct class *device_class; + struct mutex file_mutex; +}; + +struct rmidev_handle { + dev_t dev_no; + struct device dev; + struct kobject *attr_dir; + struct rmidev_data dev_data; + bool irq_enabled; + struct synaptics_rmi4_data *rmi4_data; +}; + +#ifdef PRINT_DEBUG_INFO +struct synaptics_rmi4_f51_delta_info { + union { + struct { + unsigned char deltamin_lsb; + unsigned char deltamin_msb; + unsigned char deltamax_lsb; + unsigned char deltamax_msb; + unsigned char deltaavg_lsb; + unsigned char deltaavg_msb; + unsigned char fast_relax; + } __packed; + unsigned char data[7]; + }; +}; +struct synaptics_rmi4_f54_cid_im { + union { + struct { + unsigned char cid_im_low; + unsigned char cid_im_high; + } __packed; + unsigned char data[2]; + }; +}; + +struct synaptics_rmi4_f54_freq_im { + union { + struct { + unsigned char freq_im_low; + unsigned char freq_im_high; + } __packed; + unsigned char data[2]; + }; +}; +#endif + +/* + * struct synaptics_rmi4_data - rmi4 device instance data + * @i2c_client: pointer to associated i2c client + * @input_dev: pointer to associated input device + * @board: constant pointer to platform data + * @rmi4_mod_info: device information + * @regulator: pointer to associated regulator + * @rmi4_io_ctrl_mutex: mutex for i2c i/o control + * @early_suspend: instance to support early suspend power management + * @button_0d_enabled: flag for 0d button support + * @full_pm_cycle: flag for full power management cycle in early suspend stage + * @num_of_intr_regs: number of interrupt registers + * @f01_query_base_addr: query base address for f01 + * @f01_cmd_base_addr: command base address for f01 + * @f01_ctrl_base_addr: control base address for f01 + * @f01_data_base_addr: data base address for f01 + * @irq: attention interrupt + * @sensor_max_x: sensor maximum x value + * @sensor_max_y: sensor maximum y value + * @irq_enabled: flag for indicating interrupt enable status + * @touch_stopped: flag to stop interrupt thread processing + * @fingers_on_2d: flag to indicate presence of fingers in 2d area + * @sensor_sleep: flag to indicate sleep state of sensor + * @wait: wait queue for touch data polling in interrupt thread + * @i2c_read: pointer to i2c read function + * @i2c_write: pointer to i2c write function + * @irq_enable: pointer to irq enable function + */ +struct synaptics_rmi4_data { + struct i2c_client *i2c_client; + struct input_dev *input_dev; + const struct synaptics_rmi4_platform_data *board; + struct synaptics_rmi4_device_info rmi4_mod_info; + struct mutex rmi4_reset_mutex; + struct mutex rmi4_io_ctrl_mutex; + struct mutex rmi4_reflash_mutex; + struct timer_list f51_finger_timer; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + const char *firmware_name; + + struct completion init_done; + struct synaptics_finger finger[MAX_NUMBER_OF_FINGERS]; + + unsigned char button_0d_enabled; + unsigned char full_pm_cycle; + unsigned char num_of_rx; + unsigned char num_of_tx; + unsigned int num_of_node; + unsigned char num_of_fingers; + unsigned char max_touch_width; + unsigned char intr_mask[MAX_INTR_REGISTERS]; + unsigned short num_of_intr_regs; + unsigned char *button_txrx_mapping; + unsigned short f01_query_base_addr; + unsigned short f01_cmd_base_addr; + unsigned short f01_ctrl_base_addr; + unsigned short f01_data_base_addr; + unsigned short f34_ctrl_base_addr; +#ifdef PRINT_DEBUG_INFO + unsigned short f51_query_base; + unsigned short f51_data_base; + unsigned short f51_delta_info_addr; +#endif + int irq; + int sensor_max_x; + int sensor_max_y; + bool flash_prog_mode; + bool irq_enabled; + bool touch_stopped; + bool fingers_on_2d; + bool f51_finger; + bool sensor_sleep; + bool stay_awake; + bool staying_awake; + bool tsp_probe; + bool tsp_pwr_enabled; + unsigned char fingers_already_present; + + enum synaptics_product_ids product_id; /* product id of ic */ + unsigned char product_id_string_of_bin[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + int ic_revision_of_ic; /* revision of reading from IC */ + int fw_version_of_ic; /* firmware version of IC */ + int ic_revision_of_bin; /* revision of reading from binary */ + int fw_version_of_bin; /* firmware version of binary */ + int fw_release_date_of_ic; /* Config release data from IC */ + u32 panel_revision; /* Octa panel revision */ + unsigned char bootloader_id[SYNAPTICS_BOOTLOADER_ID_SIZE]; /* Bootloader ID */ + bool doing_reflash; + int rebootcount; + + int bootloader_version; /* Bootloader Version for v7 */ + unsigned char bootloader_revision[SYNAPTICS_BOOTLOADER_REVISION]; /* Bootloader Revision */ + +#ifdef GLOVE_MODE + bool fast_glove_state; + bool touchkey_glove_mode_status; +#endif + unsigned char ddi_type; + + struct synaptics_rmi4_f12_handle f12; + struct synaptics_rmi4_fwu_handle *fwu; +#ifdef PROXIMITY_MODE + struct synaptics_rmi4_f51_handle *f51; +#endif + struct synaptics_rmi4_f54_handle *f54; + struct rmidev_handle *rmidev; + + struct delayed_work rezero_work; + + struct mutex rmi4_device_mutex; +#ifdef SIDE_TOUCH + unsigned char sidekey_data; +#endif + bool use_stylus; +#ifdef SYNAPTICS_RMI_INFORM_CHARGER + int ta_status; + void (*register_cb)(struct synaptics_rmi_callbacks *); + struct synaptics_rmi_callbacks callbacks; +#endif + bool use_deepsleep; + struct pinctrl *pinctrl; + + int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr, + unsigned char *data, unsigned short length); + int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr, + unsigned char *data, unsigned short length); + int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable); + int (*reset_device)(struct synaptics_rmi4_data *rmi4_data); + int (*stop_device)(struct synaptics_rmi4_data *rmi4_data); + int (*start_device)(struct synaptics_rmi4_data *rmi4_data); + void (*sleep_device)(struct synaptics_rmi4_data *rmi4_data); + void (*wake_device)(struct synaptics_rmi4_data *rmi4_data); +}; + +enum exp_fn { + RMI_DEV = 0, + RMI_F54, + RMI_FW_UPDATER, + RMI_DB, + RMI_GUEST, + RMI_LAST, +}; + +struct synaptics_rmi4_exp_fn { + enum exp_fn fn_type; + bool initialized; + int (*func_init)(struct synaptics_rmi4_data *rmi4_data); + int (*func_reinit)(struct synaptics_rmi4_data *rmi4_data); + void (*func_remove)(struct synaptics_rmi4_data *rmi4_data); + void (*func_attn)(struct synaptics_rmi4_data *rmi4_data, + unsigned char intr_mask); + struct list_head link; +}; + +struct synaptics_rmi4_exp_fn_ptr { + int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, + unsigned char *data, unsigned short length); + int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, + unsigned char *data, unsigned short length); + int (*enable)(struct synaptics_rmi4_data *rmi4_data, bool enable); +}; + +int synaptics_rmi4_new_function(enum exp_fn fn_type, + struct synaptics_rmi4_data *rmi4_data, + int (*func_init)(struct synaptics_rmi4_data *rmi4_data), + int (*func_reinit)(struct synaptics_rmi4_data *rmi4_data), + void (*func_remove)(struct synaptics_rmi4_data *rmi4_data), + void (*func_attn)(struct synaptics_rmi4_data *rmi4_data, + unsigned char intr_mask)); + +int rmidev_module_register(struct synaptics_rmi4_data *rmi4_data); +int rmi4_f54_module_register(struct synaptics_rmi4_data *rmi4_data); +int synaptics_rmi4_f54_set_control(struct synaptics_rmi4_data *rmi4_data); +int rmi4_fw_update_module_register(struct synaptics_rmi4_data *rmi4_data); +int rmidb_module_register(struct synaptics_rmi4_data *rmi4_data); +int rmi_guest_module_register(struct synaptics_rmi4_data *rmi4_data); + +int synaptics_fw_updater(struct synaptics_rmi4_data *rmi4_data, unsigned char *fw_data); +int synaptics_rmi4_fw_update_on_probe(struct synaptics_rmi4_data *rmi4_data); +void fwu_parse_image_header_10_simple(struct synaptics_rmi4_data *rmi4_data, unsigned char *image); + +int synaptics_rmi4_f12_ctrl11_set(struct synaptics_rmi4_data *rmi4_data, unsigned char data); +int synaptics_rmi4_set_tsp_test_result_in_config(struct synaptics_rmi4_data *rmi4_data, int value); +int synaptics_rmi4_read_tsp_test_result(struct synaptics_rmi4_data *rmi4_data); +int synaptics_rmi4_access_register(struct synaptics_rmi4_data *rmi4_data, + bool mode, unsigned short address, int length, unsigned char *value); +void synpatics_rmi4_release_all_event(struct synaptics_rmi4_data *rmi4_data, unsigned char type); + +#ifdef PROXIMITY_MODE +int synaptics_rmi4_proximity_enables(struct synaptics_rmi4_data *rmi4_data, unsigned char enables); +#endif +#ifdef GLOVE_MODE +int synaptics_rmi4_glove_mode_enables(struct synaptics_rmi4_data *rmi4_data); +#endif +#ifdef SYNAPTICS_RMI_INFORM_CHARGER +extern void synaptics_tsp_register_callback(struct synaptics_rmi_callbacks *cb); +#endif + +static inline struct device *rmi_attr_kobj_to_dev(struct kobject *kobj) +{ + return container_of(kobj->parent, struct device, kobj); +} + +static inline void *rmi_attr_kobj_to_drvdata(struct kobject *kobj) +{ + return dev_get_drvdata(rmi_attr_kobj_to_dev(kobj)); +} + +static inline ssize_t synaptics_rmi4_show_error(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct device *dev = rmi_attr_kobj_to_dev(kobj); + + dev_warn(dev, "%s Attempted to read from write-only attribute %s\n", + __func__, attr->attr.name); + return -EPERM; +} + +static inline ssize_t synaptics_rmi4_store_error(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct device *dev = rmi_attr_kobj_to_dev(kobj); + + dev_warn(dev, "%s Attempted to write to read-only attribute %s\n", + __func__, attr->attr.name); + return -EPERM; +} + +static inline void batohs(unsigned short *dest, unsigned char *src) +{ + *dest = src[1] * 0x100 + src[0]; +} + +static inline void hstoba(unsigned char *dest, unsigned short src) +{ + dest[0] = src % 0x100; + dest[1] = src / 0x100; +} + +#define RMI_KOBJ_ATTR(_name, _mode, _show, _store) \ + struct kobj_attribute kobj_attr_##_name = __ATTR(_name, _mode, _show, _store) + +#endif diff --git a/drivers/input/wacom/Kconfig b/drivers/input/wacom/Kconfig new file mode 100644 index 000000000000..225609f6e903 --- /dev/null +++ b/drivers/input/wacom/Kconfig @@ -0,0 +1,110 @@ +# +# Wacom configuration +# + +config INPUT_WACOM + tristate "Wacom penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_GXXX. + +config EPEN_WACOM_G5SP + tristate "Wacom G5SP penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G5SP penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_G5SP. + +config EPEN_WACOM_G9PM + tristate "Wacom G9PM penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G9PM penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_G9PM. + +config EPEN_WACOM_G9PL + tristate "Wacom G9PL penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G9PL penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_G9PL. + +config EPEN_WACOM_G9PLL + tristate "Wacom G9PLL penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G9PLL penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_G9PLL. + +config EPEN_WACOM_G10PM + tristate "Wacom G10PM penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G10PM penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_G10PM. + +config EPEN_WACOM_W9012 + tristate "Wacom W9012 penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G10PM penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_W9012. + +config EPEN_WACOM_W9014 + tristate "Wacom W9014 penabled i2c touchscreen" + depends on I2C + help + Say Y here if you have an Wacom G10PM penabled i2c touchscreen + connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom_W9014. + + +config WACOM_LCD_FREQ_COMPENSATE + bool "Wacom LCD vsync/hsync frequency compensate rotuine" + help + Say Y here if you have an Wacom lcd freq compensate config + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called wacom. diff --git a/drivers/input/wacom/Makefile b/drivers/input/wacom/Makefile new file mode 100644 index 000000000000..8c245c5742db --- /dev/null +++ b/drivers/input/wacom/Makefile @@ -0,0 +1,10 @@ + +obj-$(CONFIG_INPUT_WACOM) += wacom_i2c.o wacom_i2c_firm.o wacom_i2c_func.o + +obj-$(CONFIG_EPEN_WACOM_G5SP) += wacom_i2c_flash.o +obj-$(CONFIG_EPEN_WACOM_G9PM) += wacom_i2c_flash.o +obj-$(CONFIG_EPEN_WACOM_G9PL) += w9002_flash.o +obj-$(CONFIG_EPEN_WACOM_G9PLL) += w9002_flash.o +obj-$(CONFIG_EPEN_WACOM_G10PM) += w9002_flash.o +obj-$(CONFIG_EPEN_WACOM_W9012) += w9012_flash.o +obj-$(CONFIG_EPEN_WACOM_W9014) += w9014_flash.o diff --git a/drivers/input/wacom/w9012_flash.c b/drivers/input/wacom/w9012_flash.c new file mode 100644 index 000000000000..52e775838bc4 --- /dev/null +++ b/drivers/input/wacom/w9012_flash.c @@ -0,0 +1,742 @@ +/* + * w9012_flash.c - Wacom Digitizer Controller Flash Driver + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include "wacom.h" +#include "wacom_i2c_func.h" +#include "wacom_i2c_firm.h" +#include "w9012_flash.h" + +#if 0 +int wacom_i2c_master_send(struct i2c_client *client, const char *buf, int count, + unsigned char addr) +{ + int ret; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + + msg.addr = addr; + msg.flags = client->flags & I2C_M_TEN; + msg.len = count; + msg.buf = (char *)buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; +} + +int wacom_i2c_master_recv(struct i2c_client *client, const char *buf, int count, + unsigned char addr) +{ + int ret; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg; + + msg.addr = addr; + msg.flags = client->flags & I2C_M_TEN; + msg.flags |= I2C_M_RD; + msg.len = count; + msg.buf = (char *)buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; +} +#endif +static int wacom_flash_cmd(struct wacom_i2c *wac_i2c) +{ + u8 command[10]; + int len = 0; + int ret; + + command[len++] = 0x0d; + command[len++] = FLASH_START0; + command[len++] = FLASH_START1; + command[len++] = FLASH_START2; + command[len++] = FLASH_START3; + command[len++] = FLASH_START4; + command[len++] = FLASH_START5; + command[len++] = 0x0d; + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:Sending flash command failed\n"); + return -EXIT_FAIL; + } + + msleep(300); + + return 0; +} + +int flash_query(struct wacom_i2c *wac_i2c) +{ + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ret, ECH; + int len = 0; + + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data-Register-MSB */ + command[len++] = 5; /* Length Field-LSB */ + command[len++] = 0; /* Length Field-MSB */ + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_QUERY; /* Report:Boot Query command */ + command[len++] = ECH = 7; /* Report:echo */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + len = 0; + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x38; /* Command-LSB, ReportType:Feature(11) ReportID:8 */ + command[len++] = CMD_GET_FEATURE; /* Command-MSB, GET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data Register-MSB */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + msleep(10); + + ret = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 5 ret:%d \n", __func__, ret); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if ((response[3] != QUERY_CMD) || (response[4] != ECH)) { + printk(KERN_DEBUG"epen:%s res3:%x res4:%x \n", __func__, response[3], + response[4]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + if (response[5] != QUERY_RSP) { + printk(KERN_DEBUG"epen:%s res5:%x \n", __func__, response[5]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + return 0; +} + +static bool flash_blver(struct wacom_i2c *wac_i2c, int *blver) +{ + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ret, ECH; + int len = 0; + + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data-Register-MSB */ + command[len++] = 5; /* Length Field-LSB */ + command[len++] = 0; /* Length Field-MSB */ + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_BLVER; /* Report:Boot Version command */ + command[len++] = ECH = 7; /* Report:echo */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret); + return false; + } + + len = 0; + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x38; /* Command-LSB, ReportType:Feature(11) ReportID:8 */ + command[len++] = CMD_GET_FEATURE; /* Command-MSB, GET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data Register-MSB */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 4 ret:%d \n", __func__, ret); + return false; + } + + msleep(10); + + ret = + wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 5 ret:%d \n", __func__, ret); + return false; + } + + if ((response[3] != BOOT_CMD) || (response[4] != ECH)) { + printk(KERN_DEBUG"epen:%s res[3]:%x res[4]:%x \n", __func__, response[3], + response[4]); + return false; + } + + *blver = (int)response[5]; + + return true; +} + +static bool flash_mputype(struct wacom_i2c *wac_i2c, int *pMpuType) +{ + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ret, ECH; + int len = 0; + + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data-Register-MSB */ + command[len++] = 5; /* Length Field-LSB */ + command[len++] = 0; /* Length Field-MSB */ + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_MPU; /* Report:Boot Query command */ + command[len++] = ECH = 7; /* Report:echo */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret); + return false; + } + + len = 0; + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x38; /* Command-LSB, ReportType:Feature(11) ReportID:8 */ + command[len++] = CMD_GET_FEATURE; /* Command-MSB, GET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data Register-MSB */ + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 4 ret:%d \n", __func__, ret); + return false; + } + + msleep(10); + + ret = + wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 5 ret:%d \n", __func__, ret); + return false; + } + + if ((response[3] != MPU_CMD) || (response[4] != ECH)) { + printk(KERN_DEBUG"epen:%s res[3]:%x res[4]:%x \n", __func__, response[3], + response[4]); + return false; + } + + *pMpuType = (int)response[5]; + return true; +} + +static bool flash_end(struct wacom_i2c *wac_i2c) +{ + u8 command[CMD_SIZE]; + int ret, ECH; + int len = 0; + + command[len++] = 4; + command[len++] = 0; + command[len++] = 0x37; + command[len++] = CMD_SET_FEATURE; + command[len++] = 5; + command[len++] = 0; + command[len++] = 5; + command[len++] = 0; + command[len++] = BOOT_CMD_REPORT_ID; + command[len++] = BOOT_EXIT; + command[len++] = ECH = 7; + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret); + return false; + } + msleep(200); + + return true; +} + +static bool erase_datamem(struct wacom_i2c *wac_i2c) +{ + u8 command[CMD_SIZE]; + u8 response[BOOT_RSP_SIZE]; + unsigned char sum = 0; + unsigned char cmd_chksum; + int ret, ECH, j; + int len = 0; + + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data-Register-MSB */ + command[len++] = 0x07; /* Length Field-LSB */ + command[len++] = 0; /* Length Field-MSB */ + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_ERASE_DATAMEM; /* Report:erase datamem command */ + command[len++] = ECH = BOOT_ERASE_DATAMEM; /* Report:echo */ + command[len++] = DATAMEM_SECTOR0; /* Report:erased block No. */ + + sum = 0; + for (j = 4; j < 12; j++) + sum += command[j]; + cmd_chksum = ~sum + 1; /* Report:check sum */ + command[len++] = cmd_chksum; + + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 1: %d \n", __func__, ret); + return false; + } + + do { + len = 0; + command[len++] = 4; + command[len++] = 0; + command[len++] = 0x38; + command[len++] = CMD_GET_FEATURE; + command[len++] = 5; + command[len++] = 0; + + ret = + wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 2:%d \n", __func__, ret); + return false; + } + + ret = + wacom_i2c_recv(wac_i2c, response, + BOOT_RSP_SIZE, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 3:%d \n", __func__, ret); + return false; + } + + if ((response[3] != 0x0e || response[4] != ECH) + || (response[5] != 0xff && response[5] != 0x00)) + return false; + + } while (response[3] == 0x0e && response[4] == ECH + && response[5] == 0xff); + + return true; +} + +static bool erase_codemem(struct wacom_i2c *wac_i2c, int *eraseBlock, int num) +{ + u8 command[CMD_SIZE]; + u8 response[BOOT_RSP_SIZE]; + unsigned char sum = 0; + unsigned char cmd_chksum; + int ret, ECH; + int len = 0; + int i, j; + + for (i = 0; i < num; i++) { + len = 0; + + command[len++] = 4; /* Command Register-LSB */ + command[len++] = 0; /* Command Register-MSB */ + command[len++] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[len++] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[len++] = 5; /* Data Register-LSB */ + command[len++] = 0; /* Data-Register-MSB */ + command[len++] = 7; /* Length Field-LSB */ + command[len++] = 0; /* Length Field-MSB */ + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_ERASE_FLASH; /* Report:erase command */ + command[len++] = ECH = i; /* Report:echo */ + command[len++] = *eraseBlock; /* Report:erased block No. */ + eraseBlock++; + + sum = 0; + for (j = 4; j < 12; j++) + sum += command[j]; + cmd_chksum = ~sum + 1; /* Report:check sum */ + command[len++] = cmd_chksum; + + ret = + wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 1:%d \n", __func__, i); + return false; + } + + do { + len = 0; + command[len++] = 4; + command[len++] = 0; + command[len++] = 0x38; + command[len++] = CMD_GET_FEATURE; + command[len++] = 5; + command[len++] = 0; + + ret = + wacom_i2c_send(wac_i2c, command, len, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 2:%d \n", __func__, i); + return false; + } + + ret = + wacom_i2c_recv(wac_i2c, response, + BOOT_RSP_SIZE, WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 3:%d \n", __func__, i); + return false; + } + + if ((response[3] != 0x00 || response[4] != ECH) + || (response[5] != 0xff && response[5] != 0x00)) + return false; + + } while (response[3] == 0x00 && response[4] == ECH + && response[5] == 0xff); + } + + return true; +} + +static bool flash_erase(struct wacom_i2c *wac_i2c, int *eraseBlock, int num) +{ + bool ret; + + printk(KERN_DEBUG"epen:%s erasing the data mem\n", __func__); + ret = erase_datamem(wac_i2c); + if (!ret) { + printk(KERN_DEBUG"epen:%s erasing datamem failed \n", __func__); + return false; + } + + printk(KERN_DEBUG"epen:%s erasing the code mem\n", __func__); + ret = erase_codemem(wac_i2c, eraseBlock, num); + if (!ret) { + printk(KERN_DEBUG"epen:%s erasing codemem failed \n", __func__); + return false; + } + + return true; +} + +static bool flash_write_block(struct wacom_i2c *wac_i2c, char *flash_data, + unsigned long ulAddress, u8 * pcommand_id, + int *ECH) +{ + const int MAX_COM_SIZE = (16 + FLASH_BLOCK_SIZE + 2); //16: num of command[0] to command[15] + //FLASH_BLOCK_SIZE: unit to erase the block + //Num of Last 2 checksums + u8 command[300]; + unsigned char sum = 0; + int ret, i; + + command[0] = 4; /* Command Register-LSB */ + command[1] = 0; /* Command Register-MSB */ + command[2] = 0x37; /* Command-LSB, ReportType:Feature(11) ReportID:7 */ + command[3] = CMD_SET_FEATURE; /* Command-MSB, SET_REPORT */ + command[4] = 5; /* Data Register-LSB */ + command[5] = 0; /* Data-Register-MSB */ + command[6] = 76; /* Length Field-LSB */ + command[7] = 0; /* Length Field-MSB */ + command[8] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[9] = BOOT_WRITE_FLASH; /* Report:program command */ + command[10] = *ECH = ++(*pcommand_id); /* Report:echo */ + command[11] = ulAddress & 0x000000ff; + command[12] = (ulAddress & 0x0000ff00) >> 8; + command[13] = (ulAddress & 0x00ff0000) >> 16; + command[14] = (ulAddress & 0xff000000) >> 24; /* Report:address(4bytes) */ + command[15] = 8; /* Report:size(8*8=64) */ + + sum = 0; + for (i = 4; i < 16; i++) + sum += command[i]; + command[MAX_COM_SIZE - 2] = ~sum + 1; /* Report:command checksum */ + + sum = 0; + for (i = 16; i < (FLASH_BLOCK_SIZE + 16); i++) { + command[i] = flash_data[ulAddress + (i - 16)]; + sum += flash_data[ulAddress + (i - 16)]; + } + + command[MAX_COM_SIZE - 1] = ~sum + 1; /* Report:data checksum */ + + ret = + wacom_i2c_send(wac_i2c, command, (BOOT_CMD_SIZE + 4), + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s 1 ret:%d \n", __func__, ret); + return false; + } + + return true; +} + +static bool flash_write(struct wacom_i2c *wac_i2c, + unsigned char *flash_data, + unsigned long start_address, unsigned long *max_address) +{ + bool bRet = false; + u8 command_id = 0; + u8 command[BOOT_RSP_SIZE]; + u8 response[BOOT_RSP_SIZE]; + int ret, i, j, len, ECH = 0, ECH_len = 0; + int ECH_ARRAY[3]; + unsigned long ulAddress; + + j = 0; + for (ulAddress = start_address; ulAddress < *max_address; + ulAddress += FLASH_BLOCK_SIZE) { + for (i = 0; i < FLASH_BLOCK_SIZE; i++) { + if (flash_data[ulAddress + i] != 0xFF) + break; + } + if (i == (FLASH_BLOCK_SIZE)) + continue; + /* for debug */ + //printk(KERN_DEBUG"epen:write data %#x\n", (unsigned int)ulAddress); + bRet = + flash_write_block(wac_i2c, flash_data, ulAddress, + &command_id, &ECH); + if (!bRet) + return false; + + if (ECH_len == 3) + ECH_len = 0; + + ECH_ARRAY[ECH_len++] = ECH; + + if (ECH_len == 3) { + for (j = 0; j < 3; j++) { + do { + len = 0; + command[len++] = 4; + command[len++] = 0; + command[len++] = 0x38; + command[len++] = CMD_GET_FEATURE; + command[len++] = 5; + command[len++] = 0; + + ret = + wacom_i2c_send(wac_i2c, + command, len, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 2:%d \n", + __func__, i); + return false; + } + + ret = + wacom_i2c_recv(wac_i2c, + response, + BOOT_RSP_SIZE, + WACOM_I2C_MODE_BOOT); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s failing 3:%d \n", + __func__, i); + return false; + } + + if ((response[3] != 0x01 + || response[4] != ECH_ARRAY[j]) + || (response[5] != 0xff + && response[5] != 0x00)) + return false; + //printk(KERN_DEBUG"epen:addr: %x res:%x \n", ulAddress, response[5]); + } while (response[3] == 0x01 + && response[4] == ECH_ARRAY[j] + && response[5] == 0xff); + } + } + } + + return true; +} + +int wacom_i2c_flash_w9012(struct wacom_i2c *wac_i2c, unsigned char *fw_data) +{ + bool bRet = false; + int result, i; + int eraseBlock[200], eraseBlockNum; + int iBLVer, iMpuType; + unsigned long max_address = 0; /* Max.address of Load data */ + unsigned long start_address = 0x2000; /* Start.address of Load data */ + + /*Obtain boot loader version */ + if (!flash_blver(wac_i2c, &iBLVer)) { + printk(KERN_DEBUG"epen:%s failed to get Boot Loader version \n", __func__); + return -EXIT_FAIL_GET_BOOT_LOADER_VERSION; + } + printk(KERN_DEBUG"epen:BL version: %x \n", iBLVer); + + /*Obtain MPU type: this can be manually done in user space */ + if (!flash_mputype(wac_i2c, &iMpuType)) { + printk(KERN_DEBUG"epen:%s failed to get MPU type \n", __func__); + return -EXIT_FAIL_GET_MPU_TYPE; + } + if (iMpuType != MPU_W9012) { + printk(KERN_DEBUG"epen:MPU is not for W9012 : %x \n", iMpuType); + return -EXIT_FAIL_GET_MPU_TYPE; + } + printk(KERN_DEBUG"epen:MPU type: %x \n", iMpuType); + + /*-----------------------------------*/ + /*Flashing operation starts from here */ + + /*Set start and end address and block numbers */ + eraseBlockNum = 0; + start_address = W9012_START_ADDR; + max_address = W9012_END_ADDR; + for (i = BLOCK_NUM; i >= 8; i--) { + eraseBlock[eraseBlockNum] = i; + eraseBlockNum++; + } + + msleep(300); + + /*Erase the old program */ + printk(KERN_DEBUG"epen:%s erasing the current firmware \n", __func__); + bRet = flash_erase(wac_i2c, eraseBlock, eraseBlockNum); + if (!bRet) { + printk(KERN_DEBUG"epen:%s failed to erase the user program \n", __func__); + result = -EXIT_FAIL_ERASE; + goto fail; + } + + /*Write the new program */ + printk(KERN_DEBUG"epen:%s writing new firmware \n", __func__); + bRet = flash_write(wac_i2c, fw_data, start_address, &max_address); + if (!bRet) { + printk(KERN_DEBUG"epen:%s failed to write firmware \n", __func__); + result = -EXIT_FAIL_WRITE_FIRMWARE; + goto fail; + } + + /*Return to the user mode */ + printk(KERN_DEBUG"epen:%s closing the boot mode \n", __func__); + bRet = flash_end(wac_i2c); + if (!bRet) { + printk(KERN_DEBUG"epen:%s closing boot mode failed \n", __func__); + result = -EXIT_FAIL_WRITING_MARK_NOT_SET; + goto fail; + } + + printk(KERN_DEBUG"epen:%s write and verify completed \n", __func__); + result = EXIT_OK; + + fail: + return result; +} + +int wacom_i2c_flash(struct wacom_i2c *wac_i2c) +{ + int ret; + + if (fw_data == NULL) { + printk(KERN_ERR "epen:Data is NULL. Exit.\n"); + return -1; + } + + wac_i2c->pdata->compulsory_flash_mode(true); + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + ret = wacom_flash_cmd(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s cannot send flash command \n", __func__); + } + + ret = flash_query(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s Error: cannot send query \n", __func__); + ret = -EXIT_FAIL; + goto end_wacom_flash; + } + + ret = wacom_i2c_flash_w9012(wac_i2c, fw_data); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s Error: flash failed \n", __func__); + ret = -EXIT_FAIL; + goto end_wacom_flash; + } + + end_wacom_flash: + wac_i2c->pdata->compulsory_flash_mode(false); + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + return ret; +} + +int wacom_i2c_usermode(struct wacom_i2c *wac_i2c) +{ + int ret; + bool bRet = false; + + wac_i2c->pdata->compulsory_flash_mode(true); + + ret = wacom_flash_cmd(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s cannot send flash command at user-mode \n", __func__); + return ret; + } + + /*Return to the user mode */ + printk(KERN_DEBUG"epen:%s closing the boot mode \n", __func__); + bRet = flash_end(wac_i2c); + if (!bRet) { + printk(KERN_DEBUG"epen:%s closing boot mode failed \n", __func__); + ret = -EXIT_FAIL_WRITING_MARK_NOT_SET; + goto end_usermode; + } + + wac_i2c->pdata->compulsory_flash_mode(false); + + printk(KERN_DEBUG"epen:%s making user-mode completed \n", __func__); + ret = EXIT_OK; + + + end_usermode: + return ret; +} diff --git a/drivers/input/wacom/w9012_flash.h b/drivers/input/wacom/w9012_flash.h new file mode 100644 index 000000000000..87588290c92a --- /dev/null +++ b/drivers/input/wacom/w9012_flash.h @@ -0,0 +1,132 @@ +/* + * w9012_flash.h - Wacom Digitizer Controller Flash Driver + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _WACOM_I2C_FLASH_H +#define _WACOM_I2C_FLASH_H + +#define FLASH_START0 'f' +#define FLASH_START1 'l' +#define FLASH_START2 'a' +#define FLASH_START3 's' +#define FLASH_START4 'h' +#define FLASH_START5 '\r' +#define FLASH_ACK 0x06 + +/*Address for boot is 0x09 by default, but it may be different in other models*/ +#define WACOM_FLASH_W9012 0x09 +#define WACOM_QUERY_SIZE 19 +#define pen_QUERY '*' +#define ACK 0 + +#define MPU_W9012 0x2d + +#define FLASH_BLOCK_SIZE 64 +#define DATA_SIZE (65536 * 2) +#define BLOCK_NUM 127 +#define W9012_START_ADDR 0x2000 +#define W9012_END_ADDR 0x1ffff + +#define CMD_GET_FEATURE 2 +#define CMD_SET_FEATURE 3 + +#define BOOT_CMD_SIZE 78 +#define BOOT_RSP_SIZE 6 +#define BOOT_CMD_REPORT_ID 7 +#define BOOT_ERASE_DATAMEM 0x0e +#define BOOT_ERASE_FLASH 0 +#define BOOT_WRITE_FLASH 1 +#define BOOT_EXIT 3 +#define BOOT_BLVER 4 +#define BOOT_MPU 5 +#define BOOT_QUERY 7 + +#define QUERY_CMD 0x07 +#define BOOT_CMD 0x04 +#define MPU_CMD 0x05 +#define ERS_CMD 0x00 + +#define QUERY_RSP 0x06 +#define ERS_RSP 0x00 +#define WRITE_RSP 0x00 + +#define CMD_SIZE (72+6) +#define RSP_SIZE 6 + +/*Sector Nos for erasing datamem*/ +#define WRITE_CMD 0x01 +#define DATAMEM_SECTOR0 0 +#define DATAMEM_SECTOR1 1 +#define DATAMEM_SECTOR2 2 +#define DATAMEM_SECTOR3 3 +#define DATAMEM_SECTOR4 4 +#define DATAMEM_SECTOR5 5 +#define DATAMEM_SECTOR6 6 +#define DATAMEM_SECTOR7 7 + +// +// exit codes +// +#define EXIT_OK (0) +#define EXIT_REBOOT (1) +#define EXIT_FAIL (2) +#define EXIT_USAGE (3) +#define EXIT_NO_SUCH_FILE (4) +#define EXIT_NO_INTEL_HEX (5) +#define EXIT_FAIL_OPEN_COM_PORT (6) +#define EXIT_FAIL_ENTER_FLASH_MODE (7) +#define EXIT_FAIL_FLASH_QUERY (8) +#define EXIT_FAIL_BAUDRATE_CHANGE (9) +#define EXIT_FAIL_WRITE_FIRMWARE (10) +#define EXIT_FAIL_EXIT_FLASH_MODE (11) +#define EXIT_CANCEL_UPDATE (12) +#define EXIT_SUCCESS_UPDATE (13) +#define EXIT_FAIL_HID2SERIAL (14) +#define EXIT_FAIL_VERIFY_FIRMWARE (15) +#define EXIT_FAIL_MAKE_WRITING_MARK (16) +#define EXIT_FAIL_ERASE_WRITING_MARK (17) +#define EXIT_FAIL_READ_WRITING_MARK (18) +#define EXIT_EXIST_MARKING (19) +#define EXIT_FAIL_MISMATCHING (20) +#define EXIT_FAIL_ERASE (21) +#define EXIT_FAIL_GET_BOOT_LOADER_VERSION (22) +#define EXIT_FAIL_GET_MPU_TYPE (23) +#define EXIT_MISMATCH_BOOTLOADER (24) +#define EXIT_MISMATCH_MPUTYPE (25) +#define EXIT_FAIL_ERASE_BOOT (26) +#define EXIT_FAIL_WRITE_BOOTLOADER (27) +#define EXIT_FAIL_SWAP_BOOT (28) +#define EXIT_FAIL_WRITE_DATA (29) +#define EXIT_FAIL_GET_FIRMWARE_VERSION (30) +#define EXIT_FAIL_GET_UNIT_ID (31) +#define EXIT_FAIL_SEND_STOP_COMMAND (32) +#define EXIT_FAIL_SEND_QUERY_COMMAND (33) +#define EXIT_NOT_FILE_FOR_535 (34) +#define EXIT_NOT_FILE_FOR_514 (35) +#define EXIT_NOT_FILE_FOR_503 (36) +#define EXIT_MISMATCH_MPU_TYPE (37) +#define EXIT_NOT_FILE_FOR_515 (38) +#define EXIT_NOT_FILE_FOR_1024 (39) +#define EXIT_FAIL_VERIFY_WRITING_MARK (40) +#define EXIT_DEVICE_NOT_FOUND (41) +#define EXIT_FAIL_WRITING_MARK_NOT_SET (42) +#define EXIT_FAIL_SET_PDCT (43) +#define ERR_SET_PDCT (44) +#define ERR_GET_PDCT (45) + +#endif /*_WACOM_I2C_FLASH_H*/ diff --git a/drivers/input/wacom/w9014_flash.c b/drivers/input/wacom/w9014_flash.c new file mode 100644 index 000000000000..8db982e5f8f1 --- /dev/null +++ b/drivers/input/wacom/w9014_flash.c @@ -0,0 +1,617 @@ +/* + * Wacom Penabled Driver for I2C + * + * Copyright (c) 2011-2014 Tatsunosuke Tobita, Wacom. + * + * + * This program is free software; you can redistribute it + * and/or modify it under the terms of the GNU General + * Public License as published by the Free Software + * Foundation; either version of 2 of the License, + * or (at your option) any later version. + */ +#include "wacom.h" +#include "wacom_i2c_func.h" +#include "wacom_i2c_firm.h" +#include "w9014_flash.h" + +#if 0 +int wacom_i2c_master_send(struct i2c_client *client,const char *buf ,int count, unsigned char addr) +{ + int ret; + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + + msg.addr = addr; + msg.flags = client->flags & I2C_M_TEN; + msg.len = count; + msg.buf = (char *)buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; +} + +int wacom_i2c_master_recv(struct i2c_client *client, const char *buf ,int count, unsigned char addr) +{ + int ret; + struct i2c_adapter *adap=client->adapter; + struct i2c_msg msg; + + msg.addr = addr; + msg.flags = client->flags & I2C_M_TEN; + msg.flags |= I2C_M_RD; + msg.len = count; + msg.buf = (char *)buf; + + ret = i2c_transfer(adap, &msg, 1); + + /* If everything went ok (i.e. 1 msg transmitted), return #bytes + transmitted, else error code. */ + return (ret == 1) ? count : ret; +} +#endif + +bool wacom_i2c_set_feature(struct wacom_i2c *wac_i2c, u8 report_id, unsigned int buf_size, u8 *data, + u16 cmdreg, u16 datareg) +{ + int i, ret = -1; + int total = SFEATURE_SIZE + buf_size; + u8 *sFeature = NULL; + bool bRet = false; + + sFeature = kzalloc(sizeof(u8) * total, GFP_KERNEL); + if (!sFeature) { + printk(KERN_DEBUG"%s cannot preserve memory \n", __func__); + goto out; + } + memset(sFeature, 0, sizeof(u8) * total); + + sFeature[0] = (u8)(cmdreg & 0x00ff); + sFeature[1] = (u8)((cmdreg & 0xff00) >> 8); + sFeature[2] = (RTYPE_FEATURE << 4) | report_id; + sFeature[3] = CMD_SET_FEATURE; + sFeature[4] = (u8)(datareg & 0x00ff); + sFeature[5] = (u8)((datareg & 0xff00) >> 8); + + if ( (buf_size + 2) > 255) { + sFeature[6] = (u8)((buf_size + 2) & 0x00ff); + sFeature[7] = (u8)(( (buf_size + 2) & 0xff00) >> 8); + } else { + sFeature[6] = (u8)(buf_size + 2); + sFeature[7] = (u8)(0x00); + } + + for (i = 0; i < buf_size; i++) + sFeature[i + SFEATURE_SIZE] = *(data + i); + +// ret = wacom_i2c_master_send(client, sFeature, total, WACOM_FLASH_W9014); + ret = wacom_i2c_send(wac_i2c, sFeature, total, WACOM_I2C_MODE_BOOT); + if (ret != total) { + printk(KERN_DEBUG "Sending Set_Feature failed sent bytes: %d \n", ret); + goto err; + } + + usleep_range(60, 61); + bRet = true; + err: + kfree(sFeature); + sFeature = NULL; + + out: + return bRet; +} + +bool wacom_i2c_get_feature(struct wacom_i2c *wac_i2c, u8 report_id, unsigned int buf_size, u8 *data, + u16 cmdreg, u16 datareg, int delay) +{ + int ret = -1; + u8 *recv = NULL; + bool bRet = false; + u8 gFeature[] = { + (u8)(cmdreg & 0x00ff), + (u8)((cmdreg & 0xff00) >> 8), + (RTYPE_FEATURE << 4) | report_id, + CMD_GET_FEATURE, + (u8)(datareg & 0x00ff), + (u8)((datareg & 0xff00) >> 8) + }; + + /*"+ 2", adding 2 more spaces for organizeing again later in the passed data, "data"*/ + recv = kzalloc(sizeof(u8) * (buf_size + 0), GFP_KERNEL); + if (!recv) { + printk(KERN_DEBUG"%s cannot preserve memory \n", __func__); + goto out; + } + + memset(recv, 0, sizeof(u8) * (buf_size + 0)); /*Append 2 bytes for length low and high of the byte*/ + +// ret = wacom_i2c_master_send(client, gFeature, GFEATURE_SIZE, WACOM_FLASH_W9014); + ret = wacom_i2c_send(wac_i2c, gFeature, GFEATURE_SIZE, WACOM_I2C_MODE_BOOT); + if (ret != GFEATURE_SIZE) { + printk(KERN_DEBUG"%s Sending Get_Feature failed; sent bytes: %d \n", __func__, ret); + goto err; + } + + udelay(delay); + +// ret = wacom_i2c_master_recv(client, recv, (buf_size), WACOM_FLASH_W9014); + ret = wacom_i2c_recv(wac_i2c, recv, buf_size,WACOM_I2C_MODE_BOOT); + if (ret != buf_size) { + printk(KERN_DEBUG"%s Receiving data failed; recieved bytes: %d \n", __func__, ret); + goto err; + } + + /*Coppy data pointer, subtracting the first two bytes of the length*/ + memcpy(data, (recv + 0), buf_size); + + bRet = true; + err: + kfree(recv); + recv = NULL; + + out: + return bRet; +} + +static int wacom_flash_cmd(struct wacom_i2c *wac_i2c) +{ + u8 command[10]; + int len = 0; + int ret = -1; + + command[len++] = 0x0d; + command[len++] = FLASH_START0; + command[len++] = FLASH_START1; + command[len++] = FLASH_START2; + command[len++] = FLASH_START3; + command[len++] = FLASH_START4; + command[len++] = FLASH_START5; + command[len++] = 0x0d; + +// ret = i2c_master_send(wac_i2c->client, command, len); + ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT); + if(ret < 0){ + printk("Sending flash command failed\n"); + return -EXIT_FAIL; + } + + msleep(300); + + return 0; +} + +int flash_query_w9014(struct wacom_i2c *wac_i2c) +{ + bool bRet = false; + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ECH, len = 0; + + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_QUERY; /* Report:Boot Query command */ + command[len++] = ECH = 7; /* Report:echo */ + + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, len, command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + bRet = wacom_i2c_get_feature(wac_i2c, REPORT_ID_2, RSP_SIZE, response, COMM_REG, DATA_REG, (10 * 1000)); + if (!bRet) { + printk("%s failed to get feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if ( (response[3] != QUERY_CMD) || + (response[4] != ECH) ) { + printk("%s res3:%x res4:%x \n", __func__, response[3], response[4]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if (response[5] != QUERY_RSP) { + printk("%s res5:%x \n", __func__, response[5]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + printk("QUERY SUCCEEDED \n"); + return 0; +} + +static bool flash_blver_w9014(struct wacom_i2c *wac_i2c, int *blver) +{ + bool bRet = false; + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ECH, len = 0; + + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_BLVER; /* Report:Boot Version command */ + command[len++] = ECH = 7; /* Report:echo */ + + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, len, command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature1\n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + bRet = wacom_i2c_get_feature(wac_i2c, REPORT_ID_2, RSP_SIZE, response, COMM_REG, DATA_REG, (10 * 1000)); + if (!bRet) { + printk("%s 2 failed to set feature\n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if ( (response[3] != BOOT_CMD) || + (response[4] != ECH) ) { + printk("%s res3:%x res4:%x \n", __func__, response[3], response[4]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if (response[5] != QUERY_RSP) { + printk("%s res5:%x \n", __func__, response[5]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + *blver = (int)response[5]; + + return true; +} + +static bool flash_mputype_w9014(struct wacom_i2c *wac_i2c, int* pMpuType) +{ + bool bRet = false; + u8 command[CMD_SIZE]; + u8 response[RSP_SIZE]; + int ECH, len = 0; + + command[len++] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[len++] = BOOT_MPU; /* Report:Boot Query command */ + command[len++] = ECH = 7; /* Report:echo */ + + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, len, command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + bRet = wacom_i2c_get_feature(wac_i2c, REPORT_ID_2, RSP_SIZE, response, COMM_REG, DATA_REG, (10 * 1000)); + if (!bRet) { + printk("%s failed to get feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if ( (response[3] != MPU_CMD) || + (response[4] != ECH) ) { + printk("%s res3:%x res4:%x \n", __func__, response[3], response[4]); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + *pMpuType = (int)response[5]; + return true; +} + +static bool flash_end_w9014(struct wacom_i2c *wac_i2c) +{ + bool bRet = false; + u8 command[CMD_SIZE]; + int ECH, len = 0; + + command[len++] = BOOT_CMD_REPORT_ID; + command[len++] = BOOT_EXIT; + command[len++] = ECH = 7; + + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, len, command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature 1\n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + return true; +} + +static bool flash_erase_all(struct wacom_i2c *wac_i2c) +{ + bool bRet = false; + u8 command[BOOT_CMD_SIZE]; + u8 response[BOOT_RSP_SIZE]; + int i, len = 0; + int ECH, sum = 0; + + command[len++] = 7; + command[len++] = 16; + command[len++] = ECH = 2; + command[len++] = 3; + + /*Preliminarily store the data that cannnot appear here, but in wacom_set_feature()*/ + sum += 0x05; + sum += 0x07; + for (i = 0; i < len; i++) + sum += command[i]; + + command[len++] = ~sum + 1; + + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, len, command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + do { + + + bRet = wacom_i2c_get_feature(wac_i2c, REPORT_ID_2, BOOT_RSP_SIZE, response, COMM_REG, DATA_REG, 0); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + if (!(response[3] & 0x10) || !(response[4] & ECH) || + (!(response[5] & 0xff) && response[5] & 0x00)) { + printk("%s failing 4 resp1: %x resp2: %x resp3: %x \n", + __func__, response[3], response[4], response[5]); + return false; + } + + mdelay(200); + + } while(response[3] == 0x10 && response[4] == ECH && response[5] == 0xff); + + return true; +} + +static bool flash_write_block_w9014(struct wacom_i2c *wac_i2c, char *flash_data, + unsigned long ulAddress, u8 *pcommand_id, int *ECH) +{ + const int MAX_COM_SIZE = (8 + FLASH_BLOCK_SIZE + 2); //8: num of command[0] to command[7] + //FLASH_BLOCK_SIZE: unit to erase the block + //Num of Last 2 checksums + bool bRet = false; + u8 command[300]; + unsigned char sum = 0; + int i; + + command[0] = BOOT_CMD_REPORT_ID; /* Report:ReportID */ + command[1] = BOOT_WRITE_FLASH; /* Report:program command */ + command[2] = *ECH = ++(*pcommand_id); /* Report:echo */ + command[3] = ulAddress & 0x000000ff; + command[4] = (ulAddress & 0x0000ff00) >> 8; + command[5] = (ulAddress & 0x00ff0000) >> 16; + command[6] = (ulAddress & 0xff000000) >> 24; /* Report:address(4bytes) */ + command[7] = 8; /* Report:size(8*8=64) */ + + /*Preliminarily store the data that cannnot appear here, but in wacom_set_feature()*/ + sum = 0; + sum += 0x05; + sum += 0x4c; + for (i = 0; i < 8; i++) + sum += command[i]; + command[MAX_COM_SIZE - 2] = ~sum + 1; /* Report:command checksum */ + + sum = 0; + for (i = 8; i < (FLASH_BLOCK_SIZE + 8); i++){ + command[i] = flash_data[ulAddress+(i - 8)]; + sum += flash_data[ulAddress+(i - 8)]; + } + + command[MAX_COM_SIZE - 1] = ~sum+1; /* Report:data checksum */ + + /*Subtract 8 for the first 8 bytes*/ + bRet = wacom_i2c_set_feature(wac_i2c, REPORT_ID_1, (BOOT_CMD_SIZE + 4 - 8), command, COMM_REG, DATA_REG); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + udelay(50); + + return true; +} + +static bool flash_write_w9014(struct wacom_i2c *wac_i2c, unsigned char *flash_data, + unsigned long start_address, unsigned long *max_address) +{ + bool bRet = false; + u8 command_id = 0; + u8 response[BOOT_RSP_SIZE]; + int i, j, ECH = 0, ECH_len = 0; + int ECH_ARRAY[3]; + unsigned long ulAddress; + + j = 0; + for (ulAddress = start_address; ulAddress < *max_address; ulAddress += FLASH_BLOCK_SIZE) { + for (i = 0; i < FLASH_BLOCK_SIZE; i++) { + if (flash_data[ulAddress+i] != 0xFF) + break; + } + if (i == (FLASH_BLOCK_SIZE)) + continue; + + /* for debug */ + //printk(KERN_DEBUG"epen:write data %#x\n", (unsigned int)ulAddress); + + bRet = flash_write_block_w9014(wac_i2c, flash_data, ulAddress, &command_id, &ECH); + if(!bRet) + return false; + if (ECH_len == 3) + ECH_len = 0; + + ECH_ARRAY[ECH_len++] = ECH; + if (ECH_len == 3) { + for (j = 0; j < 3; j++) { + do { + + bRet = wacom_i2c_get_feature(wac_i2c, REPORT_ID_2, BOOT_RSP_SIZE, response, COMM_REG, DATA_REG, 50); + if (!bRet) { + printk("%s failed to set feature \n", __func__); + return -EXIT_FAIL_SEND_QUERY_COMMAND; + } + + if ((response[3] != 0x01 || response[4] != ECH_ARRAY[j]) || (response[5] != 0xff && response[5] != 0x00)) { + printk("%s mismatched echo array \n", __func__); +// printk("addr: %x res:%x \n", ulAddress, response[5]); + return false; + } + } while (response[3] == 0x01 && response[4] == ECH_ARRAY[j] && response[5] == 0xff); + } + } + } + return true; +} + +int wacom_i2c_flash_w9014(struct wacom_i2c *wac_i2c, unsigned char *fw_data) +{ + bool bRet = false; + int result, i; + int eraseBlock[200], eraseBlockNum; + int iBLVer = 0, iMpuType = 0; + unsigned long max_address = 0; /* Max.address of Load data */ + unsigned long start_address = 0x2000; /* Start.address of Load data */ + + /*Obtain boot loader version*/ + if (!flash_blver_w9014(wac_i2c, &iBLVer)) { + printk("%s failed to get Boot Loader version \n", __func__); + return -EXIT_FAIL_GET_BOOT_LOADER_VERSION; + } + printk("BL version: %x \n", iBLVer); + + /*Obtain MPU type: this can be manually done in user space*/ + if (!flash_mputype_w9014(wac_i2c, &iMpuType)) { + printk("%s failed to get MPU type \n", __func__); + return -EXIT_FAIL_GET_MPU_TYPE; + } + if (iMpuType != MPU_W9014) { + printk("MPU is not for W9014 : %x \n", iMpuType); + return -EXIT_FAIL_GET_MPU_TYPE; + } + printk("MPU type: %x \n", iMpuType); + + /*-----------------------------------*/ + /*Flashing operation starts from here*/ + + /*Set start and end address and block numbers*/ + eraseBlockNum = 0; + start_address = W9014_START_ADDR; + max_address = W9014_END_ADDR; + for (i = BLOCK_NUM; i >= 8; i--) { + eraseBlock[eraseBlockNum] = i; + eraseBlockNum++; + } + + msleep(300); + + /*Erase the old program*/ + printk("%s erasing the current firmware \n", __func__); + bRet = flash_erase_all(wac_i2c); + if (!bRet) { + printk("%s failed to erase the user program \n", __func__); + result = -EXIT_FAIL_ERASE; + goto fail; + } + + /*Write the new program*/ + printk(KERN_DEBUG"epen:%s writing new firmware \n", __func__); + bRet = flash_write_w9014(wac_i2c, fw_data, start_address, &max_address); + if (!bRet) { + printk("%s failed to write firmware \n", __func__); + result = -EXIT_FAIL_WRITE_FIRMWARE; + goto fail; + } + + /*Return to the user mode*/ + printk("%s closing the boot mode \n", __func__); + bRet = flash_end_w9014(wac_i2c); + if (!bRet) { + printk("%s closing boot mode failed \n", __func__); + result = -EXIT_FAIL_WRITING_MARK_NOT_SET; + goto fail; + } + + printk("%s write and verify completed \n", __func__); + result = EXIT_OK; + + fail: + return result; +} + +int wacom_i2c_flash(struct wacom_i2c *wac_i2c) +{ + int ret; + + if (fw_data == NULL) { + printk(KERN_ERR "epen:Data is NULL. Exit.\n"); + return -1; + } + + wac_i2c->pdata->compulsory_flash_mode(true); + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + ret = wacom_flash_cmd(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s cannot send flash command \n", __func__); + } + + printk(KERN_DEBUG"epen:%s pass wacom_flash_cmd \n", __func__); + + ret = flash_query_w9014(wac_i2c); + if(ret < 0) { + printk(KERN_DEBUG"epen:%s Error: cannot send query \n", __func__); + ret = -EXIT_FAIL; + goto end_wacom_flash; + } + + printk(KERN_DEBUG"epen:%s pass flash_query_w9014 \n", __func__); + + ret = wacom_i2c_flash_w9014(wac_i2c, fw_data); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s Error: flash failed \n", __func__); + ret = -EXIT_FAIL; + goto end_wacom_flash; + } + + msleep(200); + end_wacom_flash: + wac_i2c->pdata->compulsory_flash_mode(false); + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + return ret; +} + +int wacom_i2c_usermode(struct wacom_i2c *wac_i2c) +{ + int ret; +#if 0 + bool bRet = false; + + wac_i2c->pdata->compulsory_flash_mode(true); + + ret = wacom_flash_cmd(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:%s cannot send flash command at user-mode \n", __func__); + return ret; + } + + /*Return to the user mode */ + printk(KERN_DEBUG"epen:%s closing the boot mode \n", __func__); + bRet = flash_end(wac_i2c); + if (!bRet) { + printk(KERN_DEBUG"epen:%s closing boot mode failed \n", __func__); + ret = -EXIT_FAIL_WRITING_MARK_NOT_SET; + goto end_usermode; + } + + + wac_i2c->pdata->compulsory_flash_mode(false); + printk(KERN_DEBUG"epen:%s making user-mode completed \n", __func__); + ret = EXIT_OK; + + + end_usermode: +#else + ret = 0; +#endif + return ret; +} diff --git a/drivers/input/wacom/w9014_flash.h b/drivers/input/wacom/w9014_flash.h new file mode 100644 index 000000000000..3ad5db86e929 --- /dev/null +++ b/drivers/input/wacom/w9014_flash.h @@ -0,0 +1,146 @@ +/* + * w9012_flash.h - Wacom Digitizer Controller Flash Driver + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _WACOM_I2C_FLASH_H +#define _WACOM_I2C_FLASH_H + +/*-------------------------------------*/ +#define FLASH_START0 'f' +#define FLASH_START1 'l' +#define FLASH_START2 'a' +#define FLASH_START3 's' +#define FLASH_START4 'h' +#define FLASH_START5 '\r' +#define FLASH_ACK 0x06 + +/*Address for boot is 0x09 by default, but it may be different in other models*/ +#define WACOM_FLASH_W9014 0x09 +#define WACOM_QUERY_SIZE 19 +#define pen_QUERY '*' +#define ACK 0 + +#define MPU_W9014 0x2f + +#define FLASH_BLOCK_SIZE 64 +#define DATA_SIZE (65536 * 2) +#define BLOCK_NUM 127 +#define W9014_START_ADDR 0x2000 +#define W9014_END_ADDR 0x1ffff + +#define CMD_GET_FEATURE 2 +#define CMD_SET_FEATURE 3 + +/*Added for using this prog. in Linux user-space program*/ +#define RTYPE_FEATURE 0x03 /*: Report type -> feature(11b)*/ +#define GET_FEATURE 0x02 +#define SET_FEATURE 0x03 +#define GFEATURE_SIZE 6 +#define SFEATURE_SIZE 8 + +#define COMM_REG 0x04 +#define DATA_REG 0x05 +#define REPORT_ID_1 0x07 +#define REPORT_ID_2 0x08 +#define BOOT_QUERY_SIZE 5 + +#define BOOT_CMD_SIZE 78 +#define BOOT_RSP_SIZE 6 +#define BOOT_CMD_REPORT_ID 7 +#define BOOT_ERASE_DATAMEM 0x0e +#define BOOT_ERASE_FLASH 0 +#define BOOT_WRITE_FLASH 1 +#define BOOT_EXIT 3 +#define BOOT_BLVER 4 +#define BOOT_MPU 5 +#define BOOT_QUERY 7 + +#define QUERY_CMD 0x07 +#define BOOT_CMD 0x04 +#define MPU_CMD 0x05 +#define ERS_CMD 0x00 +#define WRITE_CMD 0x01 + +#define QUERY_RSP 0x06 +#define ERS_RSP 0x00 +#define WRITE_RSP 0x00 + +#define CMD_SIZE (72+6) +#define RSP_SIZE 6 + +/*Sector Nos for erasing datamem*/ +#define DATAMEM_SECTOR0 0 +#define DATAMEM_SECTOR1 1 +#define DATAMEM_SECTOR2 2 +#define DATAMEM_SECTOR3 3 +#define DATAMEM_SECTOR4 4 +#define DATAMEM_SECTOR5 5 +#define DATAMEM_SECTOR6 6 +#define DATAMEM_SECTOR7 7 + +// +// exit codes +// +#define EXIT_OK (0) +#define EXIT_REBOOT (1) +#define EXIT_FAIL (2) +#define EXIT_USAGE (3) +#define EXIT_NO_SUCH_FILE (4) +#define EXIT_NO_INTEL_HEX (5) +#define EXIT_FAIL_OPEN_COM_PORT (6) +#define EXIT_FAIL_ENTER_FLASH_MODE (7) +#define EXIT_FAIL_FLASH_QUERY (8) +#define EXIT_FAIL_BAUDRATE_CHANGE (9) +#define EXIT_FAIL_WRITE_FIRMWARE (10) +#define EXIT_FAIL_EXIT_FLASH_MODE (11) +#define EXIT_CANCEL_UPDATE (12) +#define EXIT_SUCCESS_UPDATE (13) +#define EXIT_FAIL_HID2SERIAL (14) +#define EXIT_FAIL_VERIFY_FIRMWARE (15) +#define EXIT_FAIL_MAKE_WRITING_MARK (16) +#define EXIT_FAIL_ERASE_WRITING_MARK (17) +#define EXIT_FAIL_READ_WRITING_MARK (18) +#define EXIT_EXIST_MARKING (19) +#define EXIT_FAIL_MISMATCHING (20) +#define EXIT_FAIL_ERASE (21) +#define EXIT_FAIL_GET_BOOT_LOADER_VERSION (22) +#define EXIT_FAIL_GET_MPU_TYPE (23) +#define EXIT_MISMATCH_BOOTLOADER (24) +#define EXIT_MISMATCH_MPUTYPE (25) +#define EXIT_FAIL_ERASE_BOOT (26) +#define EXIT_FAIL_WRITE_BOOTLOADER (27) +#define EXIT_FAIL_SWAP_BOOT (28) +#define EXIT_FAIL_WRITE_DATA (29) +#define EXIT_FAIL_GET_FIRMWARE_VERSION (30) +#define EXIT_FAIL_GET_UNIT_ID (31) +#define EXIT_FAIL_SEND_STOP_COMMAND (32) +#define EXIT_FAIL_SEND_QUERY_COMMAND (33) +#define EXIT_NOT_FILE_FOR_535 (34) +#define EXIT_NOT_FILE_FOR_514 (35) +#define EXIT_NOT_FILE_FOR_503 (36) +#define EXIT_MISMATCH_MPU_TYPE (37) +#define EXIT_NOT_FILE_FOR_515 (38) +#define EXIT_NOT_FILE_FOR_1024 (39) +#define EXIT_FAIL_VERIFY_WRITING_MARK (40) +#define EXIT_DEVICE_NOT_FOUND (41) +#define EXIT_FAIL_WRITING_MARK_NOT_SET (42) +#define EXIT_FAIL_SET_PDCT (43) +#define ERR_SET_PDCT (44) +#define ERR_GET_PDCT (45) + +#endif /*_WACOM_I2C_FLASH_H*/ diff --git a/drivers/input/wacom/wacom.h b/drivers/input/wacom/wacom.h new file mode 100644 index 000000000000..2bd2feb58794 --- /dev/null +++ b/drivers/input/wacom/wacom.h @@ -0,0 +1,277 @@ +#ifndef _LINUX_WACOM_H +#define _LINUX_WACOM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif + +#include + +#ifdef CONFIG_INPUT_BOOSTER +#include +#endif + +#ifdef CONFIG_EPEN_WACOM_W9014 +#define WACOM_FW_SIZE 131092 +#elif defined(CONFIG_EPEN_WACOM_W9012) +#define WACOM_FW_SIZE 131072 +#elif defined(CONFIG_EPEN_WACOM_G9PM) +#define WACOM_FW_SIZE 61440 +#elif defined(CONFIG_EPEN_WACOM_G9PLL) \ + || defined(CONFIG_EPEN_WACOM_G10PM) +#define WACOM_FW_SIZE 65535 +#else +#define WACOM_FW_SIZE 32768 +#endif + +/*Wacom Command*/ +#define COM_COORD_NUM 12 +#define COM_RESERVED_NUM 2 +#define COM_QUERY_NUM 14 +#define COM_QUERY_POS (COM_COORD_NUM+COM_RESERVED_NUM) +#define COM_QUERY_BUFFER (COM_QUERY_POS+COM_QUERY_NUM) +#define COM_QUERY_RETRY 3 + +#define COM_SAMPLERATE_STOP 0x30 +#define COM_SAMPLERATE_40 0x33 +#define COM_SAMPLERATE_80 0x32 +#define COM_SAMPLERATE_133 0x31 +#define COM_SURVEYSCAN 0x2B +#define COM_QUERY 0x2A +#define COM_FLASH 0xff +#define COM_CHECKSUM 0x63 + +/* query data format */ +#define EPEN_REG_HEADER 0x00 +#define EPEN_REG_X1 0x01 +#define EPEN_REG_X2 0x02 +#define EPEN_REG_Y1 0x03 +#define EPEN_REG_Y2 0x04 +#define EPEN_REG_PRESSURE1 0x05 +#define EPEN_REG_PRESSURE2 0x06 +#define EPEN_REG_FWVER1 0X07 +#define EPEN_REG_FWVER2 0X08 +#define EPEN_REG_MPUVER 0X09 +#define EPEN_REG_BLVER 0X0A +#define EPEN_REG_TILT_X 0X0B +#define EPEN_REG_TILT_Y 0X0C +#define EPEN_REG_HEIGHT 0X0D + +/*Information for input_dev*/ +#define EMR 0 +#define WACOM_PKGLEN_I2C_EMR 0 + +/*Special keys*/ +#define EPEN_TOOL_PEN 0x220 +#define EPEN_TOOL_RUBBER 0x221 +#define EPEN_STYLUS 0x22b +#define EPEN_STYLUS2 0x22c + +#define WACOM_DELAY_FOR_RST_RISING 200 +/* #define INIT_FIRMWARE_FLASH */ + +#define WACOM_PDCT_WORK_AROUND +#define WACOM_USE_QUERY_DATA + +/*PDCT Signal*/ +#define PDCT_NOSIGNAL 1 +#define PDCT_DETECT_PEN 0 + +#define WACOM_PRESSURE_MAX 1023 + +/*Digitizer Type*/ +#define EPEN_DTYPE_B660 1 +#define EPEN_DTYPE_B713 2 +#define EPEN_DTYPE_B746 3 +#define EPEN_DTYPE_B804 4 +#define EPEN_DTYPE_B878 5 + +#define EPEN_DTYPE_B887 6 +#define EPEN_DTYPE_B911 7 +#define EPEN_DTYPE_B934 8 +#define EPEN_DTYPE_B968 9 + +#define WACOM_I2C_MODE_BOOT 1 +#define WACOM_I2C_MODE_NORMAL 0 + +#define EPEN_RESUME_DELAY 180 +#define EPEN_OFF_TIME_LIMIT 10000 // usec + + +#if 1//defined(CONFIG_HA) +/* softkey block workaround */ +#define WACOM_USE_SOFTKEY_BLOCK +#define SOFTKEY_BLOCK_DURATION (HZ / 10) + +/* LCD freq sync */ +#ifdef CONFIG_WACOM_LCD_FREQ_COMPENSATE +/* NOISE from LDI. read Vsync at wacom firmware. */ +#define LCD_FREQ_SYNC +#endif + +#ifdef LCD_FREQ_SYNC +#define LCD_FREQ_BOTTOM 60100 +#define LCD_FREQ_TOP 60500 +#endif + +#define LCD_FREQ_SUPPORT_HWID 8 + +/*IRQ TRIGGER TYPE*/ +/*#define EPEN_IRQF_TRIGGER_TYPE IRQF_TRIGGER_FALLING*/ + +#define WACOM_USE_PDATA + +#define WACOM_USE_SOFTKEY + +/* For Android origin */ +#define WACOM_POSX_MAX WACOM_MAX_COORD_Y +#define WACOM_POSY_MAX WACOM_MAX_COORD_X + +#define COOR_WORK_AROUND + +//#define WACOM_IMPORT_FW_ALGO +/*#define WACOM_USE_OFFSET_TABLE*/ +#if 0 +#define WACOM_USE_AVERAGING +#define WACOM_USE_AVE_TRANSITION +#define WACOM_USE_BOX_FILTER +#define WACOM_USE_TILT_OFFSET +#endif + +/*Box Filter Parameters*/ +//#define X_INC_S1 1500 +//#define X_INC_E1 (WACOM_MAX_COORD_X - 1500) +//#define Y_INC_S1 1500 +//#define Y_INC_E1 (WACOM_MAX_COORD_Y - 1500) +// +//#define Y_INC_S2 500 +//#define Y_INC_E2 (WACOM_MAX_COORD_Y - 500) +//#define Y_INC_S3 1100 +//#define Y_INC_E3 (WACOM_MAX_COORD_Y - 1100) + + +/*HWID to distinguish Digitizer*/ +//#define WACOM_DTYPE_B934_HWID 4 +//#define WACOM_DTYPE_B968_HWID 6 + +#endif /*End of Model config*/ + +//#define WACOM_USE_I2C_GPIO + +#ifdef WACOM_USE_PDATA +#undef WACOM_USE_QUERY_DATA +#endif + +#define FW_UPDATE_RUNNING 1 +#define FW_UPDATE_PASS 2 +#define FW_UPDATE_FAIL -1 + +/*Parameters for wacom own features*/ +struct wacom_features { + char comstat; + unsigned int fw_version; + int update_status; +}; + +#define WACOM_FW_PATH "epen/W9012_T.bin" + +enum { + FW_NONE = 0, + FW_BUILT_IN, + FW_HEADER, + FW_IN_SDCARD, + FW_EX_SDCARD, +}; + +/* header ver 1 */ +struct fw_image { + u8 hdr_ver; + u8 hdr_len; + u16 fw_ver1; + u16 fw_ver2; + u16 fw_ver3; + u32 fw_len; + u8 checksum[5]; + u8 alignment_dummy[3]; + u8 data[0]; +} __attribute__ ((packed)); + +struct wacom_i2c { + struct i2c_client *client; + struct i2c_client *client_boot; + struct completion init_done; + struct input_dev *input_dev; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct mutex lock; + struct mutex update_lock; + struct mutex irq_lock; + struct wake_lock fw_wakelock; + struct device *dev; + int irq; + int irq_pdct; + int pen_pdct; + int pen_prox; + int pen_pressed; + int side_pressed; + int tool; + struct delayed_work pen_insert_dwork; + bool pen_insert; +#ifdef WACOM_IMPORT_FW_ALGO + bool use_offset_table; + bool use_aveTransition; +#endif + bool checksum_result; + struct wacom_features *wac_feature; + struct wacom_g5_platform_data *pdata; + struct wacom_g5_callbacks callbacks; + struct delayed_work resume_work; + bool connection_check; + bool battery_saving_mode; + bool pwr_flag; + bool power_enable; + bool boot_mode; + bool query_status; +#ifdef LCD_FREQ_SYNC + int lcd_freq; + bool lcd_freq_wait; + bool use_lcd_freq_sync; + struct work_struct lcd_freq_work; + struct delayed_work lcd_freq_done_work; + struct mutex freq_write_lock; +#endif +#ifdef WACOM_USE_SOFTKEY_BLOCK + bool block_softkey; + struct delayed_work softkey_block_work; +#endif + struct work_struct update_work; + const struct firmware *firm_data; + struct workqueue_struct *fw_wq; + u8 fw_path; + struct fw_image *fw_img; + bool do_crc_check; + struct pinctrl *pinctrl_irq; + struct pinctrl_state *pin_state_irq; +#ifdef WACOM_USE_I2C_GPIO + struct pinctrl *pinctrl_i2c; + struct pinctrl_state *pin_state_i2c; + struct pinctrl_state *pin_state_gpio; +#endif +}; + +#endif /* _LINUX_WACOM_H */ diff --git a/drivers/input/wacom/wacom_i2c.c b/drivers/input/wacom/wacom_i2c.c new file mode 100644 index 000000000000..d2282d2d694d --- /dev/null +++ b/drivers/input/wacom/wacom_i2c.c @@ -0,0 +1,2126 @@ +/* + * wacom_i2c.c - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "wacom.h" +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wacom_i2c_func.h" +#include "wacom_i2c_firm.h" +#define WACOM_FW_PATH_SDCARD "/sdcard/firmware/wacom_firm.bin" + +static struct wacom_features wacom_feature_EMR = { + .comstat = COM_QUERY, + .fw_version = 0x0, + .update_status = FW_UPDATE_PASS, +}; + +unsigned char screen_rotate; +unsigned char user_hand = 1; +extern unsigned int system_rev; + +struct i2c_client *g_client_boot; + +extern int wacom_i2c_flash(struct wacom_i2c *wac_i2c); +extern int wacom_i2c_usermode(struct wacom_i2c *wac_i2c); + +#ifdef CONFIG_OF +char *gpios_name[] = { + "irq", + "pdct", + "fwe", + "sense", + "reset", +}; + +enum { + I_IRQ = 0, + I_PDCT, + I_FWE, + I_SENSE, + I_RESET, +}; +#define WACOM_GET_PDATA(drv_data) (drv_data ? drv_data->pdata : NULL) + +struct wacom_i2c *wacom_get_drv_data(void * data) +{ + static void * drv_data = NULL; + if (unlikely(data)) + drv_data = data; + return (struct wacom_i2c *)drv_data; +} + +static int wacom_pinctrl_init(struct wacom_i2c *wac_i2c) +{ +#ifdef WACOM_USE_I2C_GPIO + int ret; +#endif + + wac_i2c->pinctrl_irq = devm_pinctrl_get(&wac_i2c->client->dev); + if (IS_ERR(wac_i2c->pinctrl_irq)) { + printk(KERN_DEBUG"%s: Failed to get pinctrl\n", __func__); + goto err_pinctrl_get; + } + + wac_i2c->pin_state_irq = pinctrl_lookup_state(wac_i2c->pinctrl_irq, "on_irq"); + if (IS_ERR(wac_i2c->pin_state_irq)) { + printk(KERN_DEBUG"%s: Failed to get pinctrl state\n", __func__); + goto err_pinctrl_get_state; + } + +#ifdef WACOM_USE_I2C_GPIO + wac_i2c->pinctrl_i2c = devm_pinctrl_get_select_default(wac_i2c->client->dev.parent->parent); + if (IS_ERR(wac_i2c->pinctrl_i2c)) { + printk(KERN_DEBUG"%s: Failed to get pinctrl\n", __func__); + goto err_pinctrl_get; + } + + wac_i2c->pin_state_i2c = pinctrl_lookup_state(wac_i2c->pinctrl_i2c, "default"); + if (IS_ERR(wac_i2c->pin_state_i2c)) { + printk(KERN_DEBUG"%s: Failed to get pinctrl state\n", __func__); + goto err_pinctrl_get_state; + } + + wac_i2c->pin_state_gpio = pinctrl_lookup_state(wac_i2c->pinctrl_i2c, "epen_gpio"); + if (IS_ERR(wac_i2c->pin_state_gpio)) { + printk(KERN_DEBUG"%s: Failed to get pinctrl state\n", __func__); + goto err_pinctrl_get_state; + } + + ret = pinctrl_select_state(wac_i2c->pinctrl_i2c, wac_i2c->pin_state_gpio); + if (ret < 0) + printk(KERN_DEBUG"%s: Failed to configure gpio mode\n", __func__); + + ret = pinctrl_select_state(wac_i2c->pinctrl_i2c, wac_i2c->pin_state_i2c); + if (ret < 0) + printk(KERN_DEBUG"%s: Failed to configure i2c mode\n", __func__); +#endif + + return 0; + +err_pinctrl_get_state: + devm_pinctrl_put(wac_i2c->pinctrl_irq); +err_pinctrl_get: + return -ENODEV; +} + +int wacom_power(bool on) +{ + struct wacom_i2c *wac_i2c = wacom_get_drv_data(NULL); + struct wacom_g5_platform_data *pdata = wac_i2c->pdata; + static bool wacom_power_enabled = false; + int ret = 0; + struct regulator *regulator_vdd = NULL; + static struct timeval off_time = {0, 0}; + struct timeval cur_time = {0, 0}; + + if (!pdata) { + printk(KERN_ERR"epen:%s, pdata is null\n", __func__); + return -1; + } + + if (wacom_power_enabled == on) { + printk(KERN_DEBUG"epen:pwr already %s\n", on ? "enabled" : "disabled"); + return 0; + } + + if (on) { + long sec, usec; + + do_gettimeofday(&cur_time); + sec = cur_time.tv_sec - off_time.tv_sec; + usec = cur_time.tv_usec - off_time.tv_usec; + if (!sec) { + usec = EPEN_OFF_TIME_LIMIT - usec; + if (usec > 500) { + usleep_range(usec, usec); + printk(KERN_DEBUG"epen:%s, pwr on usleep %d\n", __func__, (int)usec); + } + } + } + + regulator_vdd = regulator_get(NULL, "wacom_3.3v"); + if (IS_ERR_OR_NULL(regulator_vdd)) { + printk(KERN_ERR"epen: %s reg get err\n", __func__); + regulator_vdd = NULL; + return -EINVAL; + } + + if (on) { + ret = regulator_enable(regulator_vdd); + } else { + if (regulator_is_enabled(regulator_vdd)) { + regulator_disable(regulator_vdd); + do_gettimeofday(&off_time); + } + } + regulator_put(regulator_vdd); + + wacom_power_enabled = on; + + return 0; +} + +static int wacom_suspend_hw(void) +{ + struct wacom_g5_platform_data *pdata = WACOM_GET_PDATA(wacom_get_drv_data(NULL)); + if (pdata->gpios[I_RESET]) + gpio_direction_output(pdata->gpios[I_RESET], 0); + wacom_power(0); + return 0; +} + +static int wacom_resume_hw(void) +{ + struct wacom_i2c *wac_i2c = wacom_get_drv_data(NULL); + struct wacom_g5_platform_data *pdata = WACOM_GET_PDATA(wacom_get_drv_data(NULL)); + int ret; + + if (pdata->gpios[I_RESET]) + gpio_direction_output(pdata->gpios[I_RESET], 1); + /*gpio_direction_output(pdata->gpios[I_PDCT], 1);*/ + + wacom_power(1); + ret = pinctrl_select_state(wac_i2c->pinctrl_irq, wac_i2c->pin_state_irq); + if (ret < 0) + printk(KERN_DEBUG"%s: Failed to configure irq pin\n", __func__); + /*msleep(100);*/ + /*gpio_direction_input(pdata->gpios[I_PDCT]);*/ + return 0; +} + +static int wacom_reset_hw(void) +{ + wacom_suspend_hw(); + msleep(20); + wacom_resume_hw(); + + return 0; +} + +static void wacom_compulsory_flash_mode(bool en) +{ + struct wacom_g5_platform_data *pdata = + WACOM_GET_PDATA(wacom_get_drv_data(NULL)); +#ifdef WACOM_USE_I2C_GPIO + struct wacom_i2c *wac_i2c = wacom_get_drv_data(NULL); + int ret; +#endif + if (likely(pdata->boot_on_ldo)) { + static bool is_enabled = false; + struct regulator *reg_fwe = NULL; + int ret = 0; + + if (is_enabled == en) { + printk(KERN_DEBUG"epen:fwe already %s\n", en ? "enabled" : "disabled"); + return ; + } + + reg_fwe = regulator_get(NULL, "wacom_fwe_1.8v"); + if (IS_ERR_OR_NULL(reg_fwe)) { + printk(KERN_ERR"epen: %s reg get err\n", __func__); + reg_fwe = NULL; + return ; + } + + if (en) { + ret = regulator_enable(reg_fwe); + if (ret) + printk(KERN_DEBUG"epen:failed to enable fwe reg(%d)\n", ret); + } else { + if (regulator_is_enabled(reg_fwe)) + regulator_disable(reg_fwe); + } + regulator_put(reg_fwe); + + is_enabled = en; + } else + gpio_direction_output(pdata->gpios[I_FWE], en); + +#ifdef WACOM_USE_I2C_GPIO + if (!en) { + ret = pinctrl_select_state(wac_i2c->pinctrl_i2c, wac_i2c->pin_state_gpio); + if (ret < 0) + printk(KERN_DEBUG"%s: Failed to configure gpio mode\n", __func__); + + ret = pinctrl_select_state(wac_i2c->pinctrl_i2c, wac_i2c->pin_state_i2c); + if (ret < 0) + printk(KERN_DEBUG"%s: Failed to configure i2c mode\n", __func__); + } +#endif +} + +static int wacom_get_irq_state(void) +{ + struct wacom_g5_platform_data *pdata = + WACOM_GET_PDATA(wacom_get_drv_data(NULL)); + + int level = gpio_get_value(pdata->gpios[I_IRQ]); + + if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) + return !level; + + return level; +} +#endif + +static void wacom_enable_irq(struct wacom_i2c *wac_i2c, bool enable) +{ + static int depth; + + mutex_lock(&wac_i2c->irq_lock); + if (enable) { + if (depth) { + --depth; + enable_irq(wac_i2c->irq); +#ifdef WACOM_PDCT_WORK_AROUND + enable_irq(wac_i2c->irq_pdct); +#endif + } + } else { + if (!depth) { + ++depth; + disable_irq(wac_i2c->irq); +#ifdef WACOM_PDCT_WORK_AROUND + disable_irq(wac_i2c->irq_pdct); +#endif + } + } + mutex_unlock(&wac_i2c->irq_lock); + +#ifdef WACOM_IRQ_DEBUG + printk(KERN_DEBUG"epen:Enable %d, depth %d\n", (int)enable, depth); +#endif +} + +static void wacom_i2c_reset_hw(struct wacom_i2c *wac_i2c) +{ + /* Reset IC */ + wac_i2c->pdata->suspend_platform_hw(); + msleep(50); + wac_i2c->pdata->resume_platform_hw(); + msleep(200); +} + +static void wacom_power_on(struct wacom_i2c *wac_i2c) +{ + mutex_lock(&wac_i2c->lock); + + if (wac_i2c->power_enable) { + printk(KERN_DEBUG"epen:pass pwr on\n"); + goto out_power_on; + } + + if (wac_i2c->battery_saving_mode + && wac_i2c->pen_insert) + goto out_power_on; + + if (wake_lock_active(&wac_i2c->fw_wakelock)) { + printk(KERN_DEBUG"epen:wake_lock active. pass pwr on\n"); + goto out_power_on; + } + + /* power on */ + wac_i2c->pdata->resume_platform_hw(); + wac_i2c->power_enable = true; + + wac_i2c->pdata->compulsory_flash_mode(false); /* compensation to protect from flash mode */ + + cancel_delayed_work_sync(&wac_i2c->resume_work); + schedule_delayed_work(&wac_i2c->resume_work, msecs_to_jiffies(EPEN_RESUME_DELAY)); + + printk(KERN_DEBUG"epen:%s\n", __func__); + out_power_on: + mutex_unlock(&wac_i2c->lock); +} + +static void wacom_power_off(struct wacom_i2c *wac_i2c) +{ + mutex_lock(&wac_i2c->lock); + + if (!wac_i2c->power_enable) { + printk(KERN_DEBUG"epen:pass pwr off\n"); + goto out_power_off; + } + +#ifdef CONFIG_INPUT_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_PEN, BOOSTER_MODE_FORCE_OFF); +#endif + wacom_enable_irq(wac_i2c, false); + + /* release pen, if it is pressed */ + if (wac_i2c->pen_pressed || wac_i2c->side_pressed + || wac_i2c->pen_prox) + forced_release(wac_i2c); + + cancel_delayed_work_sync(&wac_i2c->resume_work); + +#ifdef LCD_FREQ_SYNC + cancel_work_sync(&wac_i2c->lcd_freq_work); + cancel_delayed_work_sync(&wac_i2c->lcd_freq_done_work); + wac_i2c->lcd_freq_wait = false; +#endif +#ifdef WACOM_USE_SOFTKEY_BLOCK + cancel_delayed_work_sync(&wac_i2c->softkey_block_work); + wac_i2c->block_softkey = false; +#endif + + if (wake_lock_active(&wac_i2c->fw_wakelock)) { + printk(KERN_DEBUG"epen:wake_lock active. pass pwr off\n"); + goto out_power_off; + } + + /* power off */ + wac_i2c->power_enable = false; + wac_i2c->pdata->suspend_platform_hw(); + + wac_i2c->pdata->compulsory_flash_mode(false); /* compensation to protect from flash mode */ + + printk(KERN_DEBUG"epen:%s\n", __func__); + out_power_off: + mutex_unlock(&wac_i2c->lock); +} + +static irqreturn_t wacom_interrupt(int irq, void *dev_id) +{ + struct wacom_i2c *wac_i2c = dev_id; + wacom_i2c_coord(wac_i2c); + return IRQ_HANDLED; +} + +#if defined(WACOM_PDCT_WORK_AROUND) +static irqreturn_t wacom_interrupt_pdct(int irq, void *dev_id) +{ + struct wacom_i2c *wac_i2c = dev_id; + + if (wac_i2c->query_status == false) + return IRQ_HANDLED; + + wac_i2c->pen_pdct = gpio_get_value(wac_i2c->pdata->gpios[I_PDCT]); +#if defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + printk(KERN_DEBUG "epen:pdct %d(%d)\n", + wac_i2c->pen_pdct, wac_i2c->pen_prox); +#else + printk(KERN_DEBUG "epen:pdct %d(%d) %d\n", + wac_i2c->pen_pdct, wac_i2c->pen_prox, wac_i2c->pdata->get_irq_state()); +#endif +#if 0 + if (wac_i2c->pen_pdct == PDCT_NOSIGNAL) { + /* If rdy is 1, pen is still working*/ + if (wac_i2c->pen_prox == 0) + forced_release(wac_i2c); + } else if (wac_i2c->pen_prox == 0) + forced_hover(wac_i2c); +#endif + return IRQ_HANDLED; +} +#endif + +static void pen_insert_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, pen_insert_dwork.work); + + wac_i2c->pen_insert = !gpio_get_value(wac_i2c->pdata->gpios[I_SENSE]); + + printk(KERN_DEBUG "epen:%s : %d\n", + __func__, wac_i2c->pen_insert); + + input_report_switch(wac_i2c->input_dev, + SW_PEN_INSERT, !wac_i2c->pen_insert); + input_sync(wac_i2c->input_dev); + + /* batter saving mode */ + if (wac_i2c->pen_insert) { + if (wac_i2c->battery_saving_mode) + wacom_power_off(wac_i2c); + } else + wacom_power_on(wac_i2c); +} +static irqreturn_t wacom_pen_detect(int irq, void *dev_id) +{ + struct wacom_i2c *wac_i2c = dev_id; + + cancel_delayed_work_sync(&wac_i2c->pen_insert_dwork); + schedule_delayed_work(&wac_i2c->pen_insert_dwork, HZ / 20); + return IRQ_HANDLED; +} + +static int init_pen_insert(struct wacom_i2c *wac_i2c) +{ + int ret = 0; + int irq = gpio_to_irq(wac_i2c->pdata->gpios[I_SENSE]); + + INIT_DELAYED_WORK(&wac_i2c->pen_insert_dwork, pen_insert_work); + + ret = + request_threaded_irq( + irq, NULL, + wacom_pen_detect, + IRQF_DISABLED | IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "pen_insert", wac_i2c); + if (ret < 0) { + printk(KERN_ERR + "epen:failed to request pen insert irq\n"); + return -1; + } + printk(KERN_DEBUG"epen:init sense irq %d\n", irq); + + enable_irq_wake(irq); + + /* update the current status */ + schedule_delayed_work(&wac_i2c->pen_insert_dwork, HZ / 2); + + return 0; +} + +static int wacom_i2c_input_open(struct input_dev *dev) +{ + struct wacom_i2c *wac_i2c = input_get_drvdata(dev); + int ret = 0; + +#if 0 + ret = wait_for_completion_interruptible_timeout(&wac_i2c->init_done, + msecs_to_jiffies(1 * MSEC_PER_SEC)); + + if (ret < 0) { + dev_err(&wac_i2c->client->dev, + "error while waiting for device to init (%d)\n", ret); + ret = -ENXIO; + goto err_open; + } + if (ret == 0) { + dev_err(&wac_i2c->client->dev, + "timedout while waiting for device to init\n"); + ret = -ENXIO; + goto err_open; + } +#endif + + wacom_power_on(wac_i2c); + + return ret; +} + +static void wacom_i2c_input_close(struct input_dev *dev) +{ + struct wacom_i2c *wac_i2c = input_get_drvdata(dev); + + wacom_power_off(wac_i2c); +} + +static void wacom_i2c_set_input_values(struct i2c_client *client, + struct wacom_i2c *wac_i2c, + struct input_dev *input_dev) +{ + /*Set input values before registering input device */ + + input_dev->name = "sec_e-pen"; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + + input_dev->evbit[0] |= BIT_MASK(EV_SW); + input_set_capability(input_dev, EV_SW, SW_PEN_INSERT); + + input_dev->open = wacom_i2c_input_open; + input_dev->close = wacom_i2c_input_close; + + __set_bit(ABS_X, input_dev->absbit); + __set_bit(ABS_Y, input_dev->absbit); + __set_bit(ABS_PRESSURE, input_dev->absbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(BTN_TOOL_PEN, input_dev->keybit); + __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); + __set_bit(BTN_STYLUS, input_dev->keybit); + __set_bit(KEY_UNKNOWN, input_dev->keybit); + //__set_bit(KEY_PEN_PDCT, input_dev->keybit); + __set_bit(ABS_DISTANCE, input_dev->absbit); + __set_bit(ABS_TILT_X, input_dev->absbit); + __set_bit(ABS_TILT_Y, input_dev->absbit); + + /* __set_bit(BTN_STYLUS2, input_dev->keybit); */ + /* __set_bit(ABS_MISC, input_dev->absbit); */ + + /*softkey*/ + __set_bit(KEY_RECENT, input_dev->keybit); + __set_bit(KEY_BACK, input_dev->keybit); +} + +static int wacom_check_emr_prox(struct wacom_g5_callbacks *cb) +{ + struct wacom_i2c *wac = container_of(cb, struct wacom_i2c, callbacks); + printk(KERN_DEBUG "epen:%s:\n", __func__); + + return wac->pen_prox; +} + +static int wacom_i2c_remove(struct i2c_client *client) +{ + struct wacom_i2c *wac_i2c = i2c_get_clientdata(client); + free_irq(client->irq, wac_i2c); + input_unregister_device(wac_i2c->input_dev); + kfree(wac_i2c); + + return 0; +} +#ifdef CONFIG_HAS_EARLYSUSPEND +static void wacom_i2c_early_suspend(struct early_suspend *h) +{ + struct wacom_i2c *wac_i2c = + container_of(h, struct wacom_i2c, early_suspend); + printk(KERN_DEBUG "epen:%s.\n", __func__); + wacom_power_off(wac_i2c); +} + +static void wacom_i2c_late_resume(struct early_suspend *h) +{ + struct wacom_i2c *wac_i2c = + container_of(h, struct wacom_i2c, early_suspend); + + printk(KERN_DEBUG "epen:%s.\n", __func__); + wacom_power_on(wac_i2c); +} +#endif + +static void wacom_i2c_resume_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, resume_work.work); + u8 irq_state = 0; + int ret = 0; + + irq_state = wac_i2c->pdata->get_irq_state(); + wacom_enable_irq(wac_i2c, true); + + if (unlikely(irq_state)) { + u8 data[COM_COORD_NUM] = {0,}; + printk(KERN_DEBUG"epen:irq was enabled\n"); + ret = wacom_i2c_recv(wac_i2c, data, COM_COORD_NUM, false); + if (ret < 0) { + printk(KERN_ERR "epen:%s failed to read i2c.L%d\n", __func__, + __LINE__); + } + } + + ret = wacom_i2c_modecheck(wac_i2c); + if(ret) wacom_i2c_usermode(wac_i2c); + +#if defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + printk(KERN_DEBUG "epen:%s\n", __func__); +#else + ret = gpio_get_value(wac_i2c->pdata->gpios[I_PDCT]); + printk(KERN_DEBUG "epen:%s %d%d\n", __func__, irq_state, ret); +#endif +} + +#ifdef LCD_FREQ_SYNC +#define SYSFS_WRITE_LCD "/sys/class/lcd/panel/ldi_fps" +static void wacom_i2c_sync_lcd_freq(struct wacom_i2c *wac_i2c) +{ + int ret = 0; + mm_segment_t old_fs; + struct file *write_node; + char freq[12] = {0, }; + int lcd_freq = wac_i2c->lcd_freq; + + mutex_lock(&wac_i2c->freq_write_lock); + + sprintf(freq, "%d", lcd_freq); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + write_node = filp_open(SYSFS_WRITE_LCD, /*O_RDONLY*/O_RDWR | O_SYNC, 0664); + if (IS_ERR(write_node)) { + ret = PTR_ERR(write_node); + dev_err(&wac_i2c->client->dev, + "%s: node file open fail, %d\n", __func__, ret); + goto err_open_node; + } + + ret = write_node->f_op->write(write_node, (char __user *)freq, strlen(freq), &write_node->f_pos); + if (ret != strlen(freq)) { + dev_err(&wac_i2c->client->dev, + "%s: Can't write node data\n", __func__); + } + printk(KERN_DEBUG"epen:%s write freq %s\n", __func__, freq); + + filp_close(write_node, current->files); + +err_open_node: + set_fs(old_fs); +//err_read_framerate: + mutex_unlock(&wac_i2c->freq_write_lock); + + schedule_delayed_work(&wac_i2c->lcd_freq_done_work, HZ * 5); +} + +static void wacom_i2c_finish_lcd_freq_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, lcd_freq_done_work.work); + + wac_i2c->lcd_freq_wait = false; + + printk(KERN_DEBUG"epen:%s\n", __func__); +} + +static void wacom_i2c_lcd_freq_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, lcd_freq_work); + + wacom_i2c_sync_lcd_freq(wac_i2c); +} +#endif + +#ifdef WACOM_USE_SOFTKEY_BLOCK +static void wacom_i2c_block_softkey_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, softkey_block_work.work); + + wac_i2c->block_softkey = false; +} +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#define wacom_i2c_suspend NULL +#define wacom_i2c_resume NULL + +#else +static int wacom_i2c_suspend(struct device *dev) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + + wac_i2c->pwr_flag = false; + if (wac_i2c->input_dev->users) + wacom_power_off(wac_i2c); + + return 0; +} + +static int wacom_i2c_resume(struct device *dev) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + + wac_i2c->pwr_flag = true; + if (wac_i2c->input_dev->users) + wacom_power_on(wac_i2c); + + return 0; +} +static SIMPLE_DEV_PM_OPS(wacom_pm_ops, wacom_i2c_suspend, wacom_i2c_resume); +#endif + +int load_fw_built_in(struct wacom_i2c *wac_i2c) +{ + int retry = 3; + int ret; + + while (retry--) { + ret = + request_firmware(&wac_i2c->firm_data, wac_i2c->pdata->fw_path, + &wac_i2c->client->dev); + if (ret < 0) { + printk(KERN_ERR + "epen:Unable to open firmware. ret %d retry %d\n", + ret, retry); + continue; + } + break; + } + + if (ret < 0) + return ret; + + wac_i2c->fw_img = (struct fw_image *)wac_i2c->firm_data->data; + + return ret; +} + +int load_fw_sdcard(struct wacom_i2c *wac_i2c) +{ + struct file *fp; + mm_segment_t old_fs; + long fsize, nread; + int ret = 0; + unsigned int nSize; + unsigned int nSize2; + u8 *ums_data; + + nSize = WACOM_FW_SIZE; + nSize2 = nSize + sizeof(struct fw_image); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open(WACOM_FW_PATH_SDCARD, O_RDONLY, S_IRUSR); + + if (IS_ERR(fp)) { + printk(KERN_ERR "epen:failed to open %s.\n", WACOM_FW_PATH_SDCARD); + ret = -ENOENT; + set_fs(old_fs); + return ret; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + printk(KERN_DEBUG + "epen:start, file path %s, size %ld Bytes\n", + WACOM_FW_PATH_SDCARD, fsize); + + if ((fsize != nSize) && (fsize != nSize2)) { + printk(KERN_ERR "epen:UMS firmware size is different\n"); + ret = -EFBIG; + goto size_error; + } + + ums_data = kmalloc(fsize, GFP_KERNEL); + if (IS_ERR(ums_data)) { + printk(KERN_ERR + "epen:%s, kmalloc failed\n", __func__); + ret = -EFAULT; + goto malloc_error; + } + + nread = vfs_read(fp, (char __user *)ums_data, + fsize, &fp->f_pos); + printk(KERN_NOTICE "epen:nread %ld Bytes\n", nread); + if (nread != fsize) { + printk(KERN_ERR + "epen:failed to read firmware file, nread %ld Bytes\n", + nread); + ret = -EIO; + kfree(ums_data); + goto read_err; + } + + filp_close(fp, current->files); + set_fs(old_fs); + + wac_i2c->fw_img = (struct fw_image *)ums_data; + + return 0; + +read_err: +malloc_error: +size_error: + filp_close(fp, current->files); + set_fs(old_fs); + return ret; +} + +int wacom_i2c_load_fw(struct wacom_i2c *wac_i2c, u8 fw_path) +{ + int ret = 0; + struct fw_image *fw_img; + + switch (fw_path) { + case FW_BUILT_IN: + ret = load_fw_built_in(wac_i2c); + break; + case FW_IN_SDCARD: + ret = load_fw_sdcard(wac_i2c); + break; + default: + printk(KERN_DEBUG"epen:unknown path(%d)\n", fw_path); + goto err_load_fw; + } + + if (ret < 0) + goto err_load_fw; + + fw_img = wac_i2c->fw_img; + + /* header check */ + if (fw_img->hdr_ver == 1 && fw_img->hdr_len == sizeof(struct fw_image)) { + fw_data = (u8 *)fw_img->data; + if (fw_path == FW_BUILT_IN) { + fw_ver_file = fw_img->fw_ver1; + memcpy(fw_chksum, fw_img->checksum, 5); + } + } else { + printk(KERN_DEBUG"epen:no hdr\n"); + fw_data = (u8 *)fw_img; + } + + return ret; + +err_load_fw: + fw_data = NULL; + return ret; +} + +void wacom_i2c_unload_fw(struct wacom_i2c *wac_i2c) +{ + switch (wac_i2c->fw_path) { + case FW_BUILT_IN: + release_firmware(wac_i2c->firm_data); + break; + case FW_IN_SDCARD: + kfree(wac_i2c->fw_img); + break; + default: + break; + } + + wac_i2c->fw_img = NULL; + wac_i2c->fw_path = FW_NONE; + wac_i2c->firm_data = NULL; + fw_data = NULL; +} + +int wacom_fw_update(struct wacom_i2c *wac_i2c, u8 fw_path, bool bforced) +{ + u32 fw_ver_ic = wac_i2c->wac_feature->fw_version; + int ret; + + if (wake_lock_active(&wac_i2c->fw_wakelock)) { + printk(KERN_DEBUG"epen:update is already running. pass\n"); + return 0; + } + + mutex_lock(&wac_i2c->update_lock); + wacom_enable_irq(wac_i2c, false); + + printk(KERN_DEBUG"epen:%s\n", __func__); + + ret = wacom_i2c_load_fw(wac_i2c, fw_path); + if (ret < 0) { + printk(KERN_DEBUG"epen:failed to load fw data\n"); + wac_i2c->wac_feature->update_status = FW_UPDATE_FAIL; + goto err_update_load_fw; + } + wac_i2c->fw_path = fw_path; + + /* firmware info */ + printk(KERN_NOTICE "epen:wacom fw ver : 0x%x, new fw ver : 0x%x\n", + wac_i2c->wac_feature->fw_version, fw_ver_file); + + if (!bforced) { + if (fw_ver_ic == fw_ver_file) { + printk(KERN_DEBUG"epen:pass fw update\n"); + wac_i2c->do_crc_check = true; + /*goto err_update_fw;*/ + } else if (fw_ver_ic > fw_ver_file) + goto out_update_fw; + + /* ic < file then update */ + } + + queue_work(wac_i2c->fw_wq, &wac_i2c->update_work); + mutex_unlock(&wac_i2c->update_lock); + + return 0; + + out_update_fw: + wacom_i2c_unload_fw(wac_i2c); + err_update_load_fw: + wacom_enable_irq(wac_i2c, true); + mutex_unlock(&wac_i2c->update_lock); + + return 0; +} + +static void wacom_i2c_update_work(struct work_struct *work) +{ + struct wacom_i2c *wac_i2c = + container_of(work, struct wacom_i2c, update_work); + struct wacom_features *feature = wac_i2c->wac_feature; + int ret = 0; +#ifdef WACOM_USE_I2C_GPIO + int retry = 10; +#else + int retry = 3; +#endif + + if (wac_i2c->fw_path == FW_NONE) + goto end_fw_update; + + wake_lock(&wac_i2c->fw_wakelock); + + /* CRC Check */ + if (wac_i2c->do_crc_check) { + wac_i2c->do_crc_check = false; + ret = wacom_checksum(wac_i2c); + if (ret) + goto err_update_fw; + printk(KERN_DEBUG"epen:crc err, do update\n"); + } + + feature->update_status = FW_UPDATE_RUNNING; + + while (retry--) { + ret = wacom_i2c_flash(wac_i2c); + if (ret) { + printk(KERN_DEBUG"epen:failed to flash fw(%d)\n", ret); +#ifdef WACOM_USE_I2C_GPIO + msleep(500); +#endif + continue; + } + break; + } + if (ret) { + feature->update_status = FW_UPDATE_FAIL; + feature->fw_version = 0; + goto err_update_fw; + } + + ret = wacom_i2c_query(wac_i2c); + if (ret < 0) { + printk(KERN_DEBUG"epen:failed to query to IC(%d)\n", ret); + feature->update_status = FW_UPDATE_FAIL; + goto err_update_fw; + } + + feature->update_status = FW_UPDATE_PASS; + + err_update_fw: + wake_unlock(&wac_i2c->fw_wakelock); + end_fw_update: + wacom_i2c_unload_fw(wac_i2c); + wacom_enable_irq(wac_i2c, true); + + return ; +} + +static ssize_t epen_firm_update_status_show(struct device *dev, +struct device_attribute *attr, + char *buf) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int status = wac_i2c->wac_feature->update_status; + + printk(KERN_DEBUG "epen:%s:(%d)\n", __func__, status); + + if (status == FW_UPDATE_PASS) + return sprintf(buf, "PASS\n"); + else if (status == FW_UPDATE_RUNNING) + return sprintf(buf, "DOWNLOADING\n"); + else if (status == FW_UPDATE_FAIL) + return sprintf(buf, "FAIL\n"); + else + return 0; +} + +static ssize_t epen_firm_version_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + printk(KERN_DEBUG "epen:%s: 0x%x|0x%X\n", __func__, + wac_i2c->wac_feature->fw_version, fw_ver_file); + + return sprintf(buf, "%04X\t%04X\n", + wac_i2c->wac_feature->fw_version, + fw_ver_file); +} + +#if defined(WACOM_IMPORT_FW_ALGO) +#if 0 +static ssize_t epen_tuning_version_show(struct device *dev, +struct device_attribute *attr, char *buf) +{ +#ifdef CONFIG_HA + tuning_version = "0000"; + tuning_model = "N900"; +#endif + printk(KERN_DEBUG "epen:%s: %s\n", __func__, + tuning_version); + + return sprintf(buf, "%s_%s\n", + tuning_model, + tuning_version); +} +#endif + +static ssize_t epen_rotation_store(struct device *dev, +struct device_attribute *attr, + const char *buf, size_t count) +{ + static bool factory_test; + static unsigned char last_rotation; + unsigned int val; + + sscanf(buf, "%u", &val); + + /* Fix the rotation value to 0(Portrait) when factory test(15 mode) */ + if (val == 100 && !factory_test) { + factory_test = true; + screen_rotate = 0; + printk(KERN_DEBUG"epen:%s, enter factory test mode\n", + __func__); + } else if (val == 200 && factory_test) { + factory_test = false; + screen_rotate = last_rotation; + printk(KERN_DEBUG"epen:%s, exit factory test mode\n", + __func__); + } + + /* Framework use index 0, 1, 2, 3 for rotation 0, 90, 180, 270 */ + /* Driver use same rotation index */ + if (val >= 0 && val <= 3) { + if (factory_test) + last_rotation = val; + else + screen_rotate = val; + } + + /* 0: Portrait 0, 1: Landscape 90, 2: Portrait 180 3: Landscape 270 */ + printk(KERN_DEBUG"epen:%s: rotate=%d\n", __func__, screen_rotate); + + return count; +} + +static ssize_t epen_hand_store(struct device *dev, +struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned int val; + + sscanf(buf, "%u", &val); + + if (val == 0 || val == 1) + user_hand = (unsigned char)val; + + /* 0:Left hand, 1:Right Hand */ + printk(KERN_DEBUG"epen:%s: hand=%u\n", __func__, user_hand); + + return count; +} +#endif + +static ssize_t epen_firmware_update_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + u8 fw_path = FW_NONE; + + printk(KERN_DEBUG "epen:%s\n", __func__); + + switch (*buf) { + case 'i': + case 'I': + fw_path = FW_IN_SDCARD; + break; + case 'k': + case 'K': + fw_path = FW_BUILT_IN; + break; + default: + printk(KERN_ERR "epen:wrong parameter\n"); + return count; + } + + wacom_fw_update(wac_i2c, fw_path, true); + + return count; +} + +static ssize_t epen_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int val; + + sscanf(buf, "%d", &val); + + if (val == 1) { + wacom_enable_irq(wac_i2c, false); + + /* Reset IC */ + /*wacom_i2c_reset_hw(wac_i2c->pdata);*/ + wacom_i2c_reset_hw(wac_i2c); + /* I2C Test */ + wacom_i2c_query(wac_i2c); + + wacom_enable_irq(wac_i2c, true); + + printk(KERN_DEBUG "epen:%s, result %d\n", __func__, + wac_i2c->query_status); + } + + return count; +} + +static ssize_t epen_reset_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + + if (wac_i2c->query_status) { + printk(KERN_DEBUG "epen:%s, PASS\n", __func__); + return sprintf(buf, "PASS\n"); + } else { + printk(KERN_DEBUG "epen:%s, FAIL\n", __func__); + return sprintf(buf, "FAIL\n"); + } +} + +#ifdef WACOM_USE_AVE_TRANSITION +static ssize_t epen_ave_store(struct device *dev, +struct device_attribute *attr, + const char *buf, size_t count) +{ + int v1, v2, v3, v4, v5; + int height; + + sscanf(buf, "%d%d%d%d%d%d", &height, &v1, &v2, &v3, &v4, &v5); + + if (height < 0 || height > 2) { + printk(KERN_DEBUG"epen:Height err %d\n", height); + return count; + } + + g_aveLevel_C[height] = v1; + g_aveLevel_X[height] = v2; + g_aveLevel_Y[height] = v3; + g_aveLevel_Trs[height] = v4; + g_aveLevel_Cor[height] = v5; + + printk(KERN_DEBUG "epen:%s, v1 %d v2 %d v3 %d v4 %d\n", __func__, + v1, v2, v3, v4); + + return count; +} + +static ssize_t epen_ave_result_show(struct device *dev, +struct device_attribute *attr, + char *buf) +{ + printk(KERN_DEBUG "epen:%s\n%d %d %d %d\n" + "%d %d %d %d\n%d %d %d %d\n", + __func__, + g_aveLevel_C[0], g_aveLevel_X[0], + g_aveLevel_Y[0], g_aveLevel_Trs[0], + g_aveLevel_C[1], g_aveLevel_X[1], + g_aveLevel_Y[1], g_aveLevel_Trs[1], + g_aveLevel_C[2], g_aveLevel_X[2], + g_aveLevel_Y[2], g_aveLevel_Trs[2]); + return sprintf(buf, "%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n", + g_aveLevel_C[0], g_aveLevel_X[0], + g_aveLevel_Y[0], g_aveLevel_Trs[0], + g_aveLevel_C[1], g_aveLevel_X[1], + g_aveLevel_Y[1], g_aveLevel_Trs[1], + g_aveLevel_C[2], g_aveLevel_X[2], + g_aveLevel_Y[2], g_aveLevel_Trs[2]); +} +#endif + +static ssize_t epen_checksum_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int val; + + sscanf(buf, "%d", &val); + + if (val != 1) { + printk(KERN_DEBUG"epen: wrong cmd %d\n", val); + return count; + } + + wacom_enable_irq(wac_i2c, false); + wacom_checksum(wac_i2c); + wacom_enable_irq(wac_i2c, true); + + printk(KERN_DEBUG "epen:%s, result %d\n", + __func__, wac_i2c->checksum_result); + + return count; +} + +static ssize_t epen_checksum_result_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + + if (wac_i2c->checksum_result) { + printk(KERN_DEBUG "epen:checksum, PASS\n"); + return sprintf(buf, "PASS\n"); + } else { + printk(KERN_DEBUG "epen:checksum, FAIL\n"); + return sprintf(buf, "FAIL\n"); + } +} + +static int wacom_open_test(struct wacom_i2c *wac_i2c) +{ + u8 cmd = 0; + u8 buf[2] = {0,}; + int ret = 0, retry = 10; + + cmd = WACOM_I2C_STOP; + ret = wacom_i2c_send(wac_i2c, &cmd, 1, false); + if (ret <= 0) { + printk(KERN_ERR "epen:failed to send stop command\n"); + return -1; + } + + usleep_range(500, 500); + + cmd = WACOM_I2C_GRID_CHECK; + ret = wacom_i2c_send(wac_i2c, &cmd, 1, false); + if (ret <= 0) { + printk(KERN_ERR "epen:failed to send stop command\n"); + return -1; + } + + msleep(150); + + cmd = WACOM_STATUS; + do { + printk(KERN_DEBUG"epen:read status, retry %d\n", retry); + ret = wacom_i2c_send(wac_i2c, &cmd, 1, false); + if (ret != 1) { + printk(KERN_DEBUG"epen:failed to send cmd(ret:%d)\n", ret); + continue; + } + usleep_range(500, 500); + ret = wacom_i2c_recv(wac_i2c, buf, 2, false); + if (ret != 2) { + printk(KERN_DEBUG"epen:failed to recv data(ret:%d)\n", ret); + continue; + } + + /* + * status value + * 0 : data is not ready + * 1 : PASS + * 2 : Fail (coil function error) + * 3 : Fail (All coil function error) + */ + if (buf[0] == 1) { + printk(KERN_DEBUG"epen:Pass\n"); + break; + } + + printk(KERN_DEBUG"epen:buf[0]:%d, buf[1]:%d\n", buf[0], buf[1]); + msleep(50); + } while (retry--); + + if (ret > 0) + wac_i2c->connection_check = (1 == buf[0]); + else { + wac_i2c->connection_check = false; + return -1; + } + + printk(KERN_DEBUG + "epen:epen_connection : %s buf[1]:%d\n", + wac_i2c->connection_check ? "Pass" : "Fail", buf[1]); + + cmd = WACOM_I2C_STOP; + ret = wacom_i2c_send(wac_i2c, &cmd, 1, false); + if (ret <= 0) { + printk(KERN_ERR "epen:failed to send stop cmd for end\n"); + return -2; + } + + cmd = WACOM_I2C_START; + ret = wacom_i2c_send(wac_i2c, &cmd, 1, false); + if (ret <= 0) { + printk(KERN_ERR "epen:failed to send start cmd for end\n"); + return -2; + } + + return 0; +} + +static ssize_t epen_connection_show(struct device *dev, +struct device_attribute *attr, + char *buf) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int retry = 3; + int ret; + + mutex_lock(&wac_i2c->lock); + + printk(KERN_DEBUG"epen:%s\n", __func__); + wacom_enable_irq(wac_i2c, false); + + if (false == wac_i2c->power_enable) { + wac_i2c->pdata->resume_platform_hw(); + printk(KERN_DEBUG"epen:pwr on\n"); + msleep(200); + } + + while (retry--) { + ret = wacom_open_test(wac_i2c); + if (!ret) + break; + + printk(KERN_DEBUG"epen:failed. retry %d\n", retry); + wac_i2c->pdata->reset_platform_hw(); + if (ret == -1) { + msleep(200); + continue; + } else if (ret == -2) { + break; + } + } + wacom_enable_irq(wac_i2c, true); + + if (false == wac_i2c->power_enable) { + wac_i2c->pdata->suspend_platform_hw(); + printk(KERN_DEBUG"epen:pwr off\n"); + } + mutex_unlock(&wac_i2c->lock); + + printk(KERN_DEBUG + "epen:connection_check : %d\n", + wac_i2c->connection_check); + + return sprintf(buf, "%s\n", + wac_i2c->connection_check ? + "OK" : "NG"); +} + +static ssize_t epen_saving_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int val; + + if (sscanf(buf, "%u", &val) == 1) + wac_i2c->battery_saving_mode = !!val; + + printk(KERN_DEBUG"epen:%s, val %d\n", + __func__, wac_i2c->battery_saving_mode); + + if (!wac_i2c->pwr_flag) { + printk(KERN_DEBUG"epen:pass pwr control\n"); + return count; + } + + if (wac_i2c->battery_saving_mode) { + if (wac_i2c->pen_insert) + wacom_power_off(wac_i2c); + } else + wacom_power_on(wac_i2c); + return count; +} + +#if defined(CONFIG_INPUT_BOOSTER) +static ssize_t epen_boost_level(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct wacom_i2c *wac_i2c = dev_get_drvdata(dev); + int level; + + sscanf(buf, "%d", &level); + + if (level < 0 || level >= BOOSTER_LEVEL_MAX) { + dev_err(&wac_i2c->client->dev, "err to set boost_level %d\n", level); + return count; + } + change_booster_level_for_pen(level); + + dev_info(&wac_i2c->client->dev, "%s %d\n", __func__, level); + + return count; + +} +#endif + +/* firmware update */ +static DEVICE_ATTR(epen_firm_update, + S_IWUSR | S_IWGRP, NULL, epen_firmware_update_store); +/* return firmware update status */ +static DEVICE_ATTR(epen_firm_update_status, + S_IRUGO, epen_firm_update_status_show, NULL); +/* return firmware version */ +static DEVICE_ATTR(epen_firm_version, S_IRUGO, epen_firm_version_show, NULL); +#if defined(WACOM_IMPORT_FW_ALGO) +/* return tuning data version */ +#if 0 +static DEVICE_ATTR(epen_tuning_version, S_IRUGO, + epen_tuning_version_show, NULL); +#endif +/* screen rotation */ +static DEVICE_ATTR(epen_rotation, S_IWUSR | S_IWGRP, NULL, epen_rotation_store); +/* hand type */ +static DEVICE_ATTR(epen_hand, S_IWUSR | S_IWGRP, NULL, epen_hand_store); +#endif + +/* For SMD Test */ +static DEVICE_ATTR(epen_reset, S_IWUSR | S_IWGRP, NULL, epen_reset_store); +static DEVICE_ATTR(epen_reset_result, + S_IRUSR | S_IRGRP, epen_reset_result_show, NULL); + +/* For SMD Test. Check checksum */ +static DEVICE_ATTR(epen_checksum, S_IWUSR | S_IWGRP, NULL, epen_checksum_store); +static DEVICE_ATTR(epen_checksum_result, S_IRUSR | S_IRGRP, + epen_checksum_result_show, NULL); +#ifdef CONFIG_INPUT_BOOSTER +static DEVICE_ATTR(boost_level, S_IWUSR | S_IWGRP, NULL, epen_boost_level); +#endif + +#ifdef WACOM_USE_AVE_TRANSITION +static DEVICE_ATTR(epen_ave, S_IWUSR | S_IWGRP, NULL, epen_ave_store); +static DEVICE_ATTR(epen_ave_result, S_IRUSR | S_IRGRP, + epen_ave_result_show, NULL); +#endif + +static DEVICE_ATTR(epen_connection, + S_IRUGO, epen_connection_show, NULL); + +static DEVICE_ATTR(epen_saving_mode, + S_IWUSR | S_IWGRP, NULL, epen_saving_mode_store); + +static struct attribute *epen_attributes[] = { + &dev_attr_epen_firm_update.attr, + &dev_attr_epen_firm_update_status.attr, + &dev_attr_epen_firm_version.attr, +#if defined(WACOM_IMPORT_FW_ALGO) +#if 0 + &dev_attr_epen_tuning_version.attr, +#endif + &dev_attr_epen_rotation.attr, + &dev_attr_epen_hand.attr, +#endif + &dev_attr_epen_reset.attr, + &dev_attr_epen_reset_result.attr, + &dev_attr_epen_checksum.attr, + &dev_attr_epen_checksum_result.attr, +#ifdef WACOM_USE_AVE_TRANSITION + &dev_attr_epen_ave.attr, + &dev_attr_epen_ave_result.attr, +#endif + &dev_attr_epen_connection.attr, + &dev_attr_epen_saving_mode.attr, +#ifdef CONFIG_INPUT_BOOSTER + &dev_attr_boost_level.attr, +#endif + NULL, +}; + +static struct attribute_group epen_attr_group = { + .attrs = epen_attributes, +}; + +static void wacom_init_abs_params(struct wacom_i2c *wac_i2c) +{ + int min_x, min_y; + int max_x, max_y; + int pressure; + + min_x = wac_i2c->pdata->min_x; + max_x = wac_i2c->pdata->max_x; + min_y = wac_i2c->pdata->min_y; + max_y = wac_i2c->pdata->max_y; + pressure = wac_i2c->pdata->max_pressure; + + if (wac_i2c->pdata->xy_switch) { + input_set_abs_params(wac_i2c->input_dev, ABS_X, min_y, + max_y, 4, 0); + input_set_abs_params(wac_i2c->input_dev, ABS_Y, min_x, + max_x, 4, 0); + } else { + input_set_abs_params(wac_i2c->input_dev, ABS_X, min_x, + max_x, 4, 0); + input_set_abs_params(wac_i2c->input_dev, ABS_Y, min_y, + max_y, 4, 0); + } + input_set_abs_params(wac_i2c->input_dev, ABS_PRESSURE, 0, + pressure, 0, 0); + input_set_abs_params(wac_i2c->input_dev, ABS_DISTANCE, 0, + 1024, 0, 0); + input_set_abs_params(wac_i2c->input_dev, ABS_TILT_X, -63, + 63, 0, 0); + input_set_abs_params(wac_i2c->input_dev, ABS_TILT_Y, -63, + 63, 0, 0); +} + +#ifdef WACOM_IMPORT_FW_ALGO +static void wacom_init_fw_algo(struct wacom_i2c *wac_i2c) +{ +#if defined(CONFIG_MACH_T0) + int digitizer_type = 0; + + /*Set data by digitizer type*/ + digitizer_type = wacom_i2c_get_digitizer_type(); + + if (digitizer_type == EPEN_DTYPE_B746) { + printk(KERN_DEBUG"epen:Use Box filter\n"); + wac_i2c->use_aveTransition = true; + } else if (digitizer_type == EPEN_DTYPE_B713) { + printk(KERN_DEBUG"epen:Reset tilt for B713\n"); + + /*Change tuning version for B713*/ + tuning_version = tuning_version_B713; + + memcpy(tilt_offsetX, tilt_offsetX_B713, sizeof(tilt_offsetX)); + memcpy(tilt_offsetY, tilt_offsetY_B713, sizeof(tilt_offsetY)); + } else if (digitizer_type == EPEN_DTYPE_B660) { + printk(KERN_DEBUG"epen:Reset tilt and origin for B660\n"); + + origin_offset[0] = EPEN_B660_ORG_X; + origin_offset[1] = EPEN_B660_ORG_Y; + memset(tilt_offsetX, 0, sizeof(tilt_offsetX)); + memset(tilt_offsetY, 0, sizeof(tilt_offsetY)); + wac_i2c->use_offset_table = false; + } + + /*Set switch type*/ + wac_i2c->invert_pen_insert = wacom_i2c_invert_by_switch_type(); +#endif + +} +#endif + +#ifdef CONFIG_OF +static int wacom_request_gpio(struct i2c_client *client, struct wacom_g5_platform_data *pdata) +{ + int ret; + int i; + char name[16] = {0, }; + + for (i = 0 ; i < WACOM_GPIO_CNT; ++i) { + if (!pdata->gpios[i]) + continue; + if (pdata->boot_on_ldo) { + if (i == I_FWE) + continue; + } + sprintf(name, "wacom_%s", gpios_name[i]); + ret = gpio_request(pdata->gpios[i], name); + if (ret) { + dev_err(&client->dev,"%s: unable to request %s [%d]\n", + __func__, name, pdata->gpios[i]); + return ret; + } + } + + return 0; +} + +static int wacom_parse_dt(struct i2c_client *client, struct wacom_g5_platform_data *pdata) +{ + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; + int ret; + int i; + char name[20] = {0, }; + u32 tmp[5] = {0, }; + + if (!np) + return -ENOENT; + + if (ARRAY_SIZE(gpios_name) != WACOM_GPIO_CNT) + printk(KERN_ERR"epen:array size error, gpios_name\n"); + + for (i = 0 ; i < WACOM_GPIO_CNT; ++i) { + sprintf(name, "wacom,%s-gpio", gpios_name[i]); + + if (of_find_property(np, name, NULL)) { + pdata->gpios[i] = of_get_named_gpio_flags(np, name, + 0, &pdata->flag_gpio[i]); + + /*printk(KERN_DEBUG"epen:%s:%d\n", gpios_name[i], pdata->gpios[i]);*/ + + if (pdata->gpios[i] < 0) { + printk(KERN_DEBUG"epen:failed to get gpio %s, %d\n", name, pdata->gpios[i]); + pdata->gpios[i] = 0; + } + } else { + printk(KERN_DEBUG"epen:theres no prop %s\n", name); + pdata->gpios[i] = 0; + } + } + + /* get features */ + ret = of_property_read_u32(np, "wacom,irq_type", tmp); + if (ret) { + printk(KERN_ERR"epen:failed to read trigger type %d\n", ret); + return -EINVAL; + } + pdata->irq_type = tmp[0]; + + ret = of_property_read_u32_array(np, "wacom,origin", pdata->origin, 2); + if (ret) { + printk(KERN_ERR"epen:failed to read origin %d\n", ret); + return -EINVAL; + } + + ret = of_property_read_u32_array(np, "wacom,max_coords", tmp, 2); + if (ret) { + printk(KERN_ERR"epen:failed to read max coords %d\n", ret); + return -EINVAL; + } + pdata->max_x = tmp[0]; + pdata->max_y = tmp[1]; + + ret = of_property_read_u32(np, "wacom,max_pressure", tmp); + if (ret) { + printk(KERN_ERR"epen:failed to read max pressure %d\n", ret); + return -EINVAL; + } + pdata->max_pressure = tmp[0]; + + ret = of_property_read_u32_array(np, "wacom,invert", tmp, 3); + if (ret) { + printk(KERN_ERR"epen:failed to read inverts %d\n", ret); + return -EINVAL; + } + pdata->x_invert = tmp[0]; + pdata->y_invert = tmp[1]; + pdata->xy_switch = tmp[2]; + + ret = of_property_read_u32(np, "wacom,ic_type", &pdata->ic_type); + if (ret) { + printk(KERN_ERR"epen:failed to read ic_type %d\n", ret); + pdata->ic_type = WACOM_IC_9012; + } + /* temp */ + if (pdata->ic_type == WACOM_IC_9010) + fw_ver_file = 0x0341; + + ret = of_property_read_string(np, "wacom,fw_path", (const char **)&pdata->fw_path); + if (ret) { + printk(KERN_ERR"epen:failed to read fw_path %d\n", ret); + pdata->fw_path = WACOM_FW_PATH; + } + + ret = of_property_read_string_index(np, "wacom,project_name", 0, (const char **)&pdata->project_name); + if (ret) + printk(KERN_ERR"epen:failed to read project name %d\n", ret); + ret = of_property_read_string_index(np, "wacom,project_name", 1, (const char **)&pdata->model_name); + if (ret) + printk(KERN_ERR"epen:failed to read model name %d\n", ret); + + if (of_find_property(np, "wacom,boot_on_ldo", NULL)) { + ret = of_property_read_u32(np, "wacom,boot_on_ldo", &pdata->boot_on_ldo); + if (ret) { + printk(KERN_ERR"epen:failed to read boot_on_ldo %d\n", ret); + pdata->boot_on_ldo = 0; + } + } + + if (of_find_property(np, "wacom,use_query_cmd", NULL)) { + pdata->use_query_cmd = true; + printk(KERN_DEBUG"epen:use query cmd\n"); + } + printk(KERN_DEBUG"epen:int type %d\n", pdata->irq_type); + + return 0; +} +#endif + +static int wacom_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct wacom_g5_platform_data *pdata = client->dev.platform_data; + struct wacom_i2c *wac_i2c; + struct input_dev *input; + int ret = 0; + bool bforced = false; + + /* init platform data */ + if (pdata == NULL) { + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev,"failed to allocate platform data\n"); + return -EINVAL; + } + client->dev.platform_data = pdata; + + ret = wacom_parse_dt(client, pdata); + if (ret) { + printk(KERN_ERR"epen:failed to parse dt\n"); + return -EINVAL; + } + + ret = wacom_request_gpio(client, pdata); + if (ret) { + printk(KERN_DEBUG"epen:failed to request gpio\n"); + return -EINVAL; + } + } + + /*Check I2C functionality */ + ret = i2c_check_functionality(client->adapter, I2C_FUNC_I2C); + if (!ret) { + printk(KERN_ERR "epen:No I2C functionality found\n"); + ret = -ENODEV; + goto err_i2c_fail; + } + + /*Obtain kernel memory space for wacom i2c */ + wac_i2c = kzalloc(sizeof(struct wacom_i2c), GFP_KERNEL); + if (NULL == wac_i2c) { + printk(KERN_ERR "epen:failed to allocate wac_i2c.\n"); + ret = -ENOMEM; + goto err_alloc_mem; + } + + if (!g_client_boot) { + wac_i2c->client_boot = i2c_new_dummy(client->adapter, + WACOM_I2C_BOOT); + if (!wac_i2c->client_boot) { + dev_err(&client->dev, "Fail to register sub client[0x%x]\n", + WACOM_I2C_BOOT); + } + } + else + wac_i2c->client_boot = g_client_boot; + + + input = input_allocate_device(); + if (NULL == input) { + printk(KERN_ERR "epen:failed to allocate input device.\n"); + ret = -ENOMEM; + goto err_alloc_input_dev; + } + + client->irq = gpio_to_irq(pdata->gpios[I_IRQ]); + + wacom_i2c_set_input_values(client, wac_i2c, input); + + wac_i2c->wac_feature = &wacom_feature_EMR; + wac_i2c->pdata = pdata; + wac_i2c->input_dev = input; + wac_i2c->client = client; + wac_i2c->irq = client->irq; + /* init_completion(&wac_i2c->init_done); */ + wac_i2c->irq_pdct = gpio_to_irq(pdata->gpios[I_PDCT]); + wac_i2c->pen_pdct = PDCT_NOSIGNAL; + wac_i2c->fw_img = NULL; + wac_i2c->fw_path = FW_NONE; +#ifdef CONFIG_OF + wacom_get_drv_data(wac_i2c); + + wac_i2c->pdata->compulsory_flash_mode = wacom_compulsory_flash_mode; + wac_i2c->pdata->suspend_platform_hw = wacom_suspend_hw; + wac_i2c->pdata->resume_platform_hw = wacom_resume_hw; + wac_i2c->pdata->reset_platform_hw = wacom_reset_hw; + wac_i2c->pdata->get_irq_state = wacom_get_irq_state; +#endif + /*Register callbacks */ + wac_i2c->callbacks.check_prox = wacom_check_emr_prox; + if (wac_i2c->pdata->register_cb) + wac_i2c->pdata->register_cb(&wac_i2c->callbacks); + + /* Firmware Feature */ + /*wacom_i2c_init_firm_data();*/ + + /* pinctrl */ + ret = wacom_pinctrl_init(wac_i2c); + if (ret < 0) + goto err_init_pinctrl; + /* Power on */ + wac_i2c->pdata->resume_platform_hw(); + if (false == pdata->boot_on_ldo) + msleep(200); + wac_i2c->power_enable = true; + wac_i2c->pwr_flag = true; + + wacom_i2c_query(wac_i2c); + + wacom_init_abs_params(wac_i2c); + input_set_drvdata(input, wac_i2c); + + /*Set client data */ + i2c_set_clientdata(client, wac_i2c); + i2c_set_clientdata(wac_i2c->client_boot, wac_i2c); + + /*Initializing for semaphor */ + mutex_init(&wac_i2c->lock); + mutex_init(&wac_i2c->update_lock); + mutex_init(&wac_i2c->irq_lock); + wake_lock_init(&wac_i2c->fw_wakelock, WAKE_LOCK_SUSPEND, "wacom"); + INIT_DELAYED_WORK(&wac_i2c->resume_work, wacom_i2c_resume_work); +#ifdef LCD_FREQ_SYNC + mutex_init(&wac_i2c->freq_write_lock); + INIT_WORK(&wac_i2c->lcd_freq_work, wacom_i2c_lcd_freq_work); + INIT_DELAYED_WORK(&wac_i2c->lcd_freq_done_work, wacom_i2c_finish_lcd_freq_work); + wac_i2c->use_lcd_freq_sync = true; +#endif +#ifdef WACOM_USE_SOFTKEY_BLOCK + INIT_DELAYED_WORK(&wac_i2c->softkey_block_work, wacom_i2c_block_softkey_work); + wac_i2c->block_softkey = false; +#endif + INIT_WORK(&wac_i2c->update_work, wacom_i2c_update_work); + + /*Before registering input device, data in each input_dev must be set */ + ret = input_register_device(input); + if (ret) { + pr_err("epen:failed to register input device.\n"); + goto err_register_device; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + wac_i2c->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + wac_i2c->early_suspend.suspend = wacom_i2c_early_suspend; + wac_i2c->early_suspend.resume = wacom_i2c_late_resume; + register_early_suspend(&wac_i2c->early_suspend); +#endif + + wac_i2c->dev = sec_device_create(wac_i2c, "sec_epen"); + if (IS_ERR(wac_i2c->dev)) { + printk(KERN_ERR "Failed to create device(wac_i2c->dev)!\n"); + ret = -ENODEV; + goto err_create_device; + } + + dev_set_drvdata(wac_i2c->dev, wac_i2c); + + ret = sysfs_create_group(&wac_i2c->dev->kobj, &epen_attr_group); + if (ret) { + printk(KERN_ERR + "epen:failed to create sysfs group\n"); + goto err_sysfs_create_group; + } + + ret = sysfs_create_link(&wac_i2c->dev->kobj, &input->dev.kobj, "input"); + if (ret) { + printk(KERN_ERR + "epen:failed to create sysfs link\n"); + goto err_create_symlink; + } + + wac_i2c->fw_wq = create_singlethread_workqueue(client->name); + if (!wac_i2c->fw_wq) { + dev_err(&client->dev, "fail to create workqueue for fw_wq\n"); + ret = -ENOMEM; + goto err_create_fw_wq; + } + + /*Request IRQ */ + ret = + request_threaded_irq(wac_i2c->irq, NULL, wacom_interrupt, + IRQF_DISABLED | wac_i2c->pdata->irq_type | + IRQF_ONESHOT, "sec_epen_irq", wac_i2c); + if (ret < 0) { + printk(KERN_ERR + "epen:failed to request irq(%d) - %d\n", + wac_i2c->irq, ret); + goto err_request_irq; + } + printk(KERN_DEBUG"epen:init irq %d\n", wac_i2c->irq); + + ret = + request_threaded_irq(wac_i2c->irq_pdct, NULL, + wacom_interrupt_pdct, + IRQF_DISABLED | IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "sec_epen_pdct", wac_i2c); + if (ret < 0) { + printk(KERN_ERR + "epen:failed to request irq(%d) - %d\n", + wac_i2c->irq_pdct, ret); + goto err_request_pdct_irq; + } + printk(KERN_DEBUG"epen:init pdct %d\n", wac_i2c->irq_pdct); + + init_pen_insert(wac_i2c); + + wacom_fw_update(wac_i2c, FW_BUILT_IN, bforced); + /*complete_all(&wac_i2c->init_done);*/ + + return 0; + + err_request_pdct_irq: + free_irq(wac_i2c->irq, wac_i2c); + err_request_irq: + destroy_workqueue(wac_i2c->fw_wq); + err_create_fw_wq: + sysfs_delete_link(&wac_i2c->dev->kobj, &input->dev.kobj, "input"); + err_create_symlink: + sysfs_remove_group(&wac_i2c->dev->kobj, + &epen_attr_group); + err_sysfs_create_group: + sec_device_destroy(wac_i2c->dev->devt); + err_create_device: + input_unregister_device(input); + input = NULL; + err_register_device: + wake_lock_destroy(&wac_i2c->fw_wakelock); +#ifdef LCD_FREQ_SYNC + mutex_destroy(&wac_i2c->freq_write_lock); +#endif + mutex_destroy(&wac_i2c->irq_lock); + mutex_destroy(&wac_i2c->update_lock); + mutex_destroy(&wac_i2c->lock); + input_free_device(input); + err_init_pinctrl: + err_alloc_input_dev: + kfree(wac_i2c); + wac_i2c = NULL; + err_alloc_mem: + err_i2c_fail: + return ret; +} + +void wacom_i2c_shutdown(struct i2c_client *client) +{ + struct wacom_i2c *wac_i2c = i2c_get_clientdata(client); + + if (!wac_i2c) + return; + + wac_i2c->pdata->suspend_platform_hw(); + + printk(KERN_DEBUG"epen:%s\n", __func__); + + sec_device_destroy(wac_i2c->dev->devt); +} + +static const struct i2c_device_id wacom_i2c_id[] = { + {"wacom_g5sp_i2c", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); + +#ifdef CONFIG_OF +static struct of_device_id wacom_dt_ids[] = { + { .compatible = "wacom,w9010" }, + { } +}; +#endif + +/*Create handler for wacom_i2c_driver*/ +static struct i2c_driver wacom_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "wacom_g5sp_i2c", +#ifdef CONFIG_PM + .pm = &wacom_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(wacom_dt_ids), +#endif + }, + .probe = wacom_i2c_probe, + .remove = wacom_i2c_remove, + .shutdown = &wacom_i2c_shutdown, + .id_table = wacom_i2c_id, +}; + +static int __init wacom_i2c_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&wacom_i2c_driver); + if (ret) + printk(KERN_ERR "epen:fail to i2c_add_driver\n"); + return ret; +} + +static void __exit wacom_i2c_exit(void) +{ + i2c_del_driver(&wacom_i2c_driver); +} + +module_init(wacom_i2c_init); +module_exit(wacom_i2c_exit); + +/* flash driver for i2c-gpio flash */ +static int wacom_flash_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + g_client_boot = client; + printk(KERN_DEBUG"epen:%s\n", __func__); + return 0; +} +void wacom_flash_shutdown(struct i2c_client *client) +{ + printk(KERN_DEBUG"epen:%s\n", __func__); +} + +static int wacom_flash_remove(struct i2c_client *client) +{ + return 0; +} + +static const struct i2c_device_id wacom_flash_id[] = { + {"wacom_g5sp_flash", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, wacom_flash_id); + +#ifdef CONFIG_OF +static struct of_device_id wacom_flash_dt_ids[] = { + { .compatible = "wacom,flash" }, + { } +}; +#endif + +static struct i2c_driver wacom_flash_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "wacom_g5sp_flash", +#ifdef CONFIG_PM + //.pm = &wacom_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(wacom_flash_dt_ids), +#endif + }, + .probe = wacom_flash_probe, + .remove = wacom_flash_remove, + .shutdown = &wacom_flash_shutdown, + .id_table = wacom_flash_id, +}; + +static int __init wacom_flash_init(void) +{ + int ret = 0; + + ret = i2c_add_driver(&wacom_flash_driver); + if (ret) + printk(KERN_ERR "epen:fail to i2c_add_driver\n"); + return ret; +} + +static void __exit wacom_flash_exit(void) +{ + i2c_del_driver(&wacom_flash_driver); +} + +fs_initcall(wacom_flash_init); +module_exit(wacom_flash_exit); + +MODULE_AUTHOR("Samsung"); +MODULE_DESCRIPTION("Driver for Wacom G5SP Digitizer Controller"); + +MODULE_LICENSE("GPL"); diff --git a/drivers/input/wacom/wacom_i2c_firm.c b/drivers/input/wacom/wacom_i2c_firm.c new file mode 100644 index 000000000000..73ae0473950b --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_firm.c @@ -0,0 +1,81 @@ +/* + * wacom_i2c_firm.c - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include "wacom.h" + +unsigned char *fw_data; +bool ums_binary; +extern unsigned int system_rev; + +const unsigned char mpu_type = 0x2C; + +unsigned int fw_ver_file = 0x020F; +char fw_chksum[] = { 0x1F, 0x2d, 0x83, 0xed, 0xec}; + +#if 0 +void wacom_i2c_set_firm_data(struct wacom_i2c *wac_i2c) +{ + if (wac_i2c->fw_path == FW_IN_SDCARD) + fw_data = (unsigned char *)wac_i2c->fw_data; + else + fw_data = (unsigned char *)wac_i2c->firm_data->data; + + ums_binary = true; +} +#endif + +/*Return digitizer type according to board rev*/ +int wacom_i2c_get_digitizer_type(void) +{ +#if defined(CONFIG_V1A) || defined(CONFIG_CHAGALL) + return EPEN_DTYPE_B878; +#elif defined(CONFIG_HA) + //return EPEN_DTYPE_B968; + //if (system_rev >= WACOM_DTYPE_B968_HWID) + // return EPEN_DTYPE_B968; + //else + // return EPEN_DTYPE_B934; +#endif + return 0; +} + +void wacom_i2c_init_firm_data(void) +{ + int type; + type = wacom_i2c_get_digitizer_type(); + +#if defined(CONFIG_V1A) || defined(CONFIG_CHAGALL) + if (type == EPEN_DTYPE_B878) { + printk(KERN_DEBUG + "epen:Digitizer type is B878\n"); + } +#elif defined(CONFIG_HA) + /*if (likely(type == EPEN_DTYPE_B968)) { + printk(KERN_DEBUG + "epen:Digitizer type is B968\n"); + } else if (type == EPEN_DTYPE_B934) { + printk(KERN_DEBUG + "epen:Digitizer type is B934\n"); + fw_name = "epen/W9010_B934.bin"; + fw_ver_file = 0x0076; + memcpy(fw_chksum, B934_chksum, + sizeof(fw_chksum)); + }*/ +#endif +} diff --git a/drivers/input/wacom/wacom_i2c_firm.h b/drivers/input/wacom/wacom_i2c_firm.h new file mode 100644 index 000000000000..836c399dd599 --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_firm.h @@ -0,0 +1,31 @@ +/* + * wacom_i2c_firm.h - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LINUX_WACOM_I2C_FIRM_H +#define _LINUX_WACOM_I2C_FIRM_H + +extern const unsigned char mpu_type; +extern unsigned int fw_ver_file; +extern unsigned char *fw_data; +extern bool ums_binary; +extern char fw_chksum[]; +void wacom_i2c_init_firm_data(void); +int wacom_i2c_get_digitizer_type(void); + +#endif /* _LINUX_WACOM_I2C_FIRM_H */ \ No newline at end of file diff --git a/drivers/input/wacom/wacom_i2c_flash.c b/drivers/input/wacom/wacom_i2c_flash.c new file mode 100644 index 000000000000..c3d3e95fd3af --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_flash.c @@ -0,0 +1,643 @@ +/* + * wacom_i2c_flash.c - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "wacom.h" +#include "wacom_i2c_func.h" +#include "wacom_i2c_firm.h" +#include "wacom_i2c_flash.h" + +#define ERR_HEX 0x056 +#define RETRY_TRANSFER 5 +unsigned char checksum_data[4]; + +int calc_checksum(unsigned char *flash_data) +{ + unsigned long i; + + if (ums_binary) + return 0; + + for (i = 0; i < 4; i++) + checksum_data[i] = 0; + + for (i = 0x0000; i < 0xC000; i += 4) { + checksum_data[0] ^= flash_data[i]; + checksum_data[1] ^= flash_data[i+1]; + checksum_data[2] ^= flash_data[i+2]; + checksum_data[3] ^= flash_data[i+3]; + } + + printk(KERN_DEBUG + "epen:%s : %02x, %02x, %02x, %02x\n", + __func__, checksum_data[0], checksum_data[1], + checksum_data[2], checksum_data[3]); + + for (i = 0; i < 4; i++) { + if (checksum_data[i] != fw_chksum[i+1]) + return -ERR_HEX; + } + + return 0; +} + +int wacom_i2c_flash_chksum(struct wacom_i2c *wac_i2c, unsigned char *flash_data, + unsigned long *max_address) +{ + unsigned long i; + unsigned long chksum = 0; + + for (i = 0x0000; i <= *max_address; i++) + chksum += flash_data[i]; + + chksum &= 0xFFFF; + + return (int)chksum; +} + +int wacom_i2c_flash_cmd(struct wacom_i2c *wac_i2c) +{ + int ret, len, i; + u8 buf[10], flashq; + + buf[0] = 0x0d; + buf[1] = FLASH_START0; + buf[2] = FLASH_START1; + buf[3] = FLASH_START2; + buf[4] = FLASH_START3; + buf[5] = FLASH_START4; + buf[6] = FLASH_START5; + buf[7] = 0x0d; + flashq = 0xE0; + len = 1; + + ret = wacom_i2c_send(wac_i2c, &flashq, len, true); + if (ret >= 0) { + i = 0; + do { + msleep(1); + ret = wacom_i2c_recv(wac_i2c, + &flashq, len, true); + i++; + + if (i > RETRY) + return -1; + } while (flashq == 0xff); + } else { + msleep(1); + len = 8; + ret = wacom_i2c_send(wac_i2c, buf, len, false); + if (ret < 0) { + printk(KERN_ERR + "epen:Sending flash command failed\n"); + return -1; + } + printk(KERN_DEBUG "epen:flash send?:%d\n", ret); + msleep(270); + } + + return 0; +} + +int wacom_i2c_flash_query(struct wacom_i2c *wac_i2c, u8 query, u8 recvdQuery) +{ + int ret, len, i; + u8 flashq; + + flashq = query; + len = 1; + + ret = wacom_i2c_send(wac_i2c, &flashq, len, true); + if (ret < 0) { + printk(KERN_ERR "epen:query unsent:%d\n", ret); + return -1; + } + + /*sleep*/ + msleep(10); + i = 0; + do { + msleep(1); + flashq = query; + ret = wacom_i2c_recv(wac_i2c, + &flashq, len, true); + i++; + + if (i > RETRY) + return -1; + printk(KERN_DEBUG "epen:ret:%d flashq:%x\n", ret, flashq); + } while (recvdQuery == 0xff && flashq != recvdQuery); + printk(KERN_DEBUG "epen:query:%x\n", flashq); + + return flashq; +} + +int wacom_i2c_flash_end(struct wacom_i2c *wac_i2c) +{ + int ret; + + /* 2012/07/04 Evaluation for 0x80 and 0xA0 added by Wacom*/ + do { + ret = wacom_i2c_flash_query(wac_i2c, FLASH_END, FLASH_END); + if (ret == -1) + return ERR_FAILED_EXIT; + } while (ret == 0xA0 || ret != 0x80); + /* 2012/07/04 Evaluation for 0x80 and 0xA0 added by Wacom*/ + + /*2012/07/05 + below added for giving firmware enough time to change to user mode*/ + msleep(1000); + + printk(KERN_DEBUG "epen:Digitizer activated\n"); + wac_i2c->boot_mode = false; + + return 0; +} + +int wacom_i2c_flash_enter(struct wacom_i2c *wac_i2c) +{ + if (wacom_i2c_flash_query(wac_i2c, FLASH_QUERY, FLASH_ACK) == -1) + return ERR_NOT_FLASH; + + wac_i2c->boot_mode = true; + + return 0; +} + +int wacom_i2c_flash_BLVer(struct wacom_i2c *wac_i2c) +{ + int ret = 0; + ret = wacom_i2c_flash_query(wac_i2c, FLASH_BLVER, 0x40); + if (ret == -1) + return ERR_UNSENT; + + return ret; +} + +int wacom_i2c_flash_mcuId(struct wacom_i2c *wac_i2c) +{ + int ret = 0; + + ret = wacom_i2c_flash_query(wac_i2c, FLASH_MPU, 0x26); + if (ret == -1) + return ERR_UNSENT; + + return ret; +} + +int wacom_i2c_flash_erase(struct wacom_i2c *wac_i2c, u8 cmd_erase, + u8 cmd_block, u8 endBlock) +{ + int len, ret, i, j; + u8 buf[3], sum, block, flashq; + unsigned long swtich_slot_time; + + ret = 0; + + for (i = cmd_block; i >= endBlock; i--) { + block = i; + block |= 0x80; + + sum = cmd_erase; + sum += block; + sum = ~sum + 1; + + buf[0] = cmd_erase; + buf[1] = block; + buf[2] = sum; + + len = 3; + ret = wacom_i2c_send(wac_i2c, buf, len, true); + if (ret < 0) { + printk(KERN_ERR "epen:Erase failed\n"); + return -1; + } + + len = 1; + flashq = 0; + j = 0; + + do { + /*sleep */ + msleep(100); + ret = wacom_i2c_recv(wac_i2c, + &flashq, len, true); + j++; + + if (j > RETRY || flashq == 0x84 || flashq == 0x88 + || flashq == 0x8A || flashq == 0x90) { + /* + 0xff:No data + 0x84:Erase failure + 0x88:Erase time parameter error + 0x8A:Write time parameter error + 0x90:Checksum error + */ + printk(KERN_ERR "epen:Error:%x\n", flashq); + return -1; + } + + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + } while (flashq == 0xff || flashq != 0x06); + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + + if (printk_timed_ratelimit(&swtich_slot_time, 5000)) + printk(KERN_DEBUG "epen:Erasing at %d, ", i); + /*sleep */ + msleep(1); + } + printk(KERN_DEBUG "epen:Erasing done\n"); + return ret; +} + +int wacom_i2c_flash_write(struct wacom_i2c *wac_i2c, unsigned long startAddr, + u8 size, unsigned long maxAddr) +{ + unsigned long ulAddr; + int ret, len, i, j, k; + char sum; + u8 buf[WRITE_BUFF], bank; + unsigned long swtich_slot_time; + + ret = len = i = 0; + bank = BANK; + + for (ulAddr = startAddr; ulAddr <= maxAddr; ulAddr += BLOCK_SIZE_W) { + sum = 0; + buf[0] = FLASH_WRITE; + buf[1] = (u8) (ulAddr & 0xff); + buf[2] = (u8) ((ulAddr & 0xff00) >> 8); + buf[3] = size; + buf[4] = bank; +#ifdef CONFIG_EPEN_WACOM_G9PM + /*Pass Garbage*/ + for (i = 0; i < BLOCK_SIZE_W; i++) { + if (fw_data[ulAddr+i] != 0xff) + break; + } + if (i == BLOCK_SIZE_W) { + printk(KERN_DEBUG"epen:Pass ulAddr %u\n", + (unsigned int)ulAddr); + continue; + } +#endif + + for (i = 0; i < 5; i++) + sum += buf[i]; + + sum = ~sum + 1; + buf[5] = sum; + + len = 6; + + /* 2012/07/18 + * if the returned data is not equal to the length of the bytes + * that is supposed to send/receive, return it as fail + */ + for (k = 0; k < RETRY_TRANSFER; k++) { + ret = wacom_i2c_send(wac_i2c, buf, len, true); + if (ret == len) + break; + if (ret < 0 || k == (RETRY_TRANSFER - 1)) { + printk(KERN_ERR "epen:Write process aborted\n"); + return ERR_FAILED_ENTER; + } + } + /*2012/07/18*/ + + msleep(10); + len = 1; + j = 0; + do { + msleep(5); + ret = wacom_i2c_recv(wac_i2c, + buf, len, true); + j++; + + if (j > RETRY || buf[0] == 0x90) { + /*0xff:No data 0x90:Checksum error */ + printk(KERN_ERR "epen:Error: %x , 0x%lx(%d)\n", + buf[0], ulAddr, __LINE__); + return -1; + } + + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + } while (buf[0] == 0xff || buf[0] != 0x06); + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + + msleep(1); + + sum = 0; + for (i = 0; i < BLOCK_SIZE_W; i++) { + buf[i] = fw_data[ulAddr + i]; + sum += fw_data[ulAddr + i]; + } + sum = ~sum + 1; + buf[BLOCK_SIZE_W] = sum; + len = BLOCK_SIZE_W + 1; + + /* 2012/07/18 + * if the returned data is not equal to the length of the bytes + * that is supposed to send/receive, return it as fail + */ + for (k = 0; k < RETRY_TRANSFER; k++) { + ret = wacom_i2c_send(wac_i2c, buf, len, true); + if (ret == len) + break; + if (ret < 0 || k == (RETRY_TRANSFER - 1)) { + printk(KERN_ERR "epen:Write process aborted\n"); + return ERR_FAILED_ENTER; + } + } + /*2012/07/18*/ + + msleep(50); + len = 1; + j = 0; + + do { + msleep(10); + ret = wacom_i2c_recv(wac_i2c, + buf, len, true); + j++; + + if (j > RETRY || buf[0] == 0x82 || buf[0] == 0x90) { + /* + 0xff:No data + 0x82:Write error + 0x90:Checksum error + */ + printk(KERN_ERR "epen:Error: %x , 0x%lx(%d)\n", + buf[0], ulAddr, __LINE__); + return -1; + } + + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + } while (buf[0] == 0xff || buf[0] != 0x06); + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + + if (printk_timed_ratelimit(&swtich_slot_time, 5000)) + printk(KERN_DEBUG "epen:Written on:0x%lx", ulAddr); + msleep(1); + } + printk(KERN_DEBUG "\nWriting done\n"); + + return 0; +} + +int wacom_i2c_flash_verify(struct wacom_i2c *wac_i2c, unsigned long startAddr, + u8 size, unsigned long maxAddr) +{ + unsigned long ulAddr; + int ret, len, i, j, k; + char sum; + u8 buf[WRITE_BUFF], bank; + unsigned long swtich_slot_time; + + ret = len = i = 0; + bank = BANK; + + for (ulAddr = startAddr; ulAddr <= maxAddr; ulAddr += BLOCK_SIZE_W) { + sum = 0; + buf[0] = FLASH_VERIFY; + buf[1] = (u8) (ulAddr & 0xff); + buf[2] = (u8) ((ulAddr & 0xff00) >> 8); + buf[3] = size; + buf[4] = bank; + + for (i = 0; i < 5; i++) + sum += buf[i]; + sum = ~sum + 1; + buf[5] = sum; + + len = 6; + j = 0; + /*sleep */ + + /* 2012/07/18 + * if the returned data is not equal to the length of the bytes + * that is supposed to send/receive, return it as fail + */ + for (k = 0; k < RETRY_TRANSFER; k++) { + ret = wacom_i2c_send(wac_i2c, buf, len, true); + if (ret == len) + break; + if (ret < 0 || k == (RETRY_TRANSFER - 1)) { + printk(KERN_ERR "epen:Write process aborted\n"); + return ERR_FAILED_ENTER; + } + } + /*2012/07/18*/ + + len = 1; + + do { + msleep(1); + ret = wacom_i2c_recv(wac_i2c, + buf, len, true); + j++; + if (j > RETRY || buf[0] == 0x90) { + /*0xff:No data 0x90:Checksum error */ + printk(KERN_ERR "epen:Error: %x , 0x%lx(%d)\n", + buf[0], ulAddr, __LINE__); + return -1; + } + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + } while (buf[0] == 0xff || buf[0] != 0x06); + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + + msleep(1); + sum = 0; + for (i = 0; i < BLOCK_SIZE_W; i++) { + buf[i] = fw_data[ulAddr + i]; + sum += fw_data[ulAddr + i]; + } + sum = ~sum + 1; + buf[BLOCK_SIZE_W] = sum; + len = BLOCK_SIZE_W + 1; + + /* 2012/07/18 + * if the returned data is not equal to the length of the bytes + * that is supposed to send/receive, return it as fail + */ + for (k = 0; k < RETRY_TRANSFER; k++) { + ret = wacom_i2c_send(wac_i2c, buf, len, true); + if (ret == len) + break; + if (ret < 0 || k == (RETRY_TRANSFER - 1)) { + printk(KERN_ERR "epen:Write process aborted\n"); + return ERR_FAILED_ENTER; + } + } + /*2012/07/18*/ + + len = 1; + j = 0; + do { + msleep(2); + ret = wacom_i2c_recv(wac_i2c, + buf, len, true); + j++; + + if (j > RETRY || buf[0] == 0x81 || buf[0] == 0x90) { + /* + 0xff:No data + 0x82:Write error + 0x90:Checksum error + */ + printk(KERN_ERR "epen:Error: %x , 0x%lx(%d)\n", + buf[0], ulAddr, __LINE__); + return -1; + } + + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + } while (buf[0] == 0xff || buf[0] != 0x06); + /* 2012/07/04 Evaluation if 0x06 or not added by Wacom*/ + + if (printk_timed_ratelimit(&swtich_slot_time, 5000)) + printk(KERN_DEBUG "epen:Verified:0x%lx", ulAddr); + msleep(1); + } + + printk("\nepen:Verifying done\n"); + + return 0; +} + +int wacom_i2c_flash(struct wacom_i2c *wac_i2c) +{ + int ret = 0, blver = 0, mcu = 0; + u32 max_addr = 0, cmd_addr = 0; + bool valid_hex = false; + int cnt = 0; + + if (fw_data == NULL) { + printk(KERN_ERR"epen:Data is NULL. Exit.\n"); + return -1; + } + + wac_i2c->pdata->compulsory_flash_mode(true); + /*Reset */ + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + ret = wacom_i2c_flash_cmd(wac_i2c); + if (ret < 0) + goto fw_update_error; + msleep(10); + + ret = wacom_i2c_flash_enter(wac_i2c); + printk(KERN_DEBUG "epen:flashEnter:%d\n", ret); + msleep(10); + + blver = wacom_i2c_flash_BLVer(wac_i2c); + printk(KERN_DEBUG "epen:blver:%d\n", blver); + msleep(10); + + mcu = wacom_i2c_flash_mcuId(wac_i2c); + printk(KERN_DEBUG "epen:mcu:%x\n", mcu); + if (mpu_type != mcu) { + printk(KERN_DEBUG "epen:mcu:%x\n", mcu); + ret = -ENXIO; + goto mcu_type_error; + } + msleep(1); + + switch (mcu) { + case MPUVER_W8501: + printk(KERN_DEBUG "epen:flashing for w8501 started\n"); + max_addr = MAX_ADDR_W8501; + cmd_addr = MAX_BLOCK_W8501; + break; + + case MPUVER_514: + printk(KERN_DEBUG "epen:Flashing for 514 started\n"); + max_addr = MAX_ADDR_514; + cmd_addr = MAX_BLOCK_514; + break; + + case MPUVER_505: + printk(KERN_DEBUG "epen:Flashing for 505 started\n"); + max_addr = MAX_ADDR_505; + cmd_addr = MAX_BLOCK_505; + break; + + default: + printk(KERN_DEBUG "epen:default called\n"); + goto mcu_type_error; + break; + } + + /*2012/07/04: below modified by Wacom*/ + /*If wacom_i2c_flash_verify returns -ERR_HEX, */ + /*please redo whole process of flashing from */ + /*wacom_i2c_flash_erase */ + do { + cnt++; + ret = wacom_i2c_flash_erase(wac_i2c, FLASH_ERASE, + cmd_addr, END_BLOCK); + if (ret < 0) { + printk(KERN_ERR "epen:error - erase\n"); + continue; + } + msleep(20); + + ret = wacom_i2c_flash_write(wac_i2c, START_ADDR, + NUM_BLOCK_2WRITE, max_addr); + if (ret < 0) { + printk(KERN_ERR "epen:error - writing\n"); + continue; + } + msleep(20); + + ret = wacom_i2c_flash_verify(wac_i2c, START_ADDR, + NUM_BLOCK_2WRITE, max_addr); + + if (ret == -ERR_HEX) + printk(KERN_DEBUG "epen:firmware is not valied\n"); + else if (ret < 0) { + printk(KERN_ERR "epen:error - verifying\n"); + continue; + } else + valid_hex = true; + } while ((!valid_hex) && (cnt < 2)); + /*2012/07/04: Wacom*/ + + if (ret < 0) { + printk(KERN_DEBUG"epen:failed to flash fw\n"); + return ret; + } + + printk(KERN_DEBUG "epen:Firmware successfully updated\n"); + msleep(10); + + mcu_type_error: + ret = wacom_i2c_flash_end(wac_i2c); + if (ret < 0) { + printk(KERN_ERR "epen:error - wacom_i2c_flash_end\n"); + return ret; + } + + fw_update_error: + wac_i2c->pdata->compulsory_flash_mode(false); + /*Reset*/ + wac_i2c->pdata->reset_platform_hw(); + msleep(200); + + return ret; +} diff --git a/drivers/input/wacom/wacom_i2c_flash.h b/drivers/input/wacom/wacom_i2c_flash.h new file mode 100644 index 000000000000..b3324b1af1ae --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_flash.h @@ -0,0 +1,80 @@ +/* + * wacom_i2c_flash.h - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LINUX_WACOM_I2C_FLASH_H +#define _LINUX_WACOM_I2C_FLASH_H + +#define FLASH_START0 'f' +#define FLASH_START1 'l' +#define FLASH_START2 'a' +#define FLASH_START3 's' +#define FLASH_START4 'h' +#define FLASH_START5 '\r' +#define FLASH_ACK 0x06 + +#define PANA_QUERY 0x11 + +#define FLASH_END 0x80 +#define FLASH_VERIFY 0x81 +#define FLASH_WRITE 0x82 +#define FLASH_READ 0x83 +#define FLASH_ERASE 0x84 +#define FLASH_SET_INFO 0x85 +#define FLASH_END_TO_BOOT 0x87 +#define FLASH_BAUDRATE 0x88 + +#define FLASH_QUERY 0xE0 +#define FLASH_BLVER 0xE1 +#define FLASH_UNITID 0xE2 +#define FLASH_GET_INFO 0xE3 +#define FLASH_FWVER 0xE4 +#define FLASH_MPU 0xE8 + +#define WRITE_BUFF 300 +#define BLOCK_SIZE_W 128 +#define NUM_BLOCK_2WRITE 16 +#define BANK 0 +#define START_ADDR 0x1000 +#define END_BLOCK 4 + +#define MAX_BLOCK_W8501 31 +#define MPUVER_W8501 0x26 +#define BLVER_W8501 0x41 +#define MAX_ADDR_W8501 0x7FFF + +#define MAX_BLOCK_514 47 +#define MPUVER_514 0x27 +#define BLVER_514 0x50 +#define MAX_ADDR_514 0xBFFF + +#define MPUVER_505 0x28 +#define MAX_BLOCK_505 59 +#define MAX_ADDR_505 0xEFFF +#define BLVER_505 0xFF + +#define RETRY 1 + +#define ERR_FAILED_ENTER -1 +#define ERR_UNSENT -2 +#define ERR_NOT_FLASH -3 +#define ERR_FAILED_EXIT -4 + +#define PEN_QUERY '*' + +#endif /* _LINUX_WACOM_I2C_FLASH_H */ diff --git a/drivers/input/wacom/wacom_i2c_func.c b/drivers/input/wacom/wacom_i2c_func.c new file mode 100644 index 000000000000..2a5564277103 --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_func.c @@ -0,0 +1,849 @@ +/* + * wacom_i2c_func.c - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "wacom.h" +#include "wacom_i2c_func.h" +#include "wacom_i2c_firm.h" + +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +#define CONFIG_SAMSUNG_KERNEL_DEBUG_USER +#endif + +void forced_release(struct wacom_i2c *wac_i2c) +{ +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + printk(KERN_DEBUG "epen:%s\n", __func__); +#endif + input_report_abs(wac_i2c->input_dev, ABS_X, 0); + input_report_abs(wac_i2c->input_dev, ABS_Y, 0); + input_report_abs(wac_i2c->input_dev, ABS_PRESSURE, 0); + input_report_abs(wac_i2c->input_dev, ABS_DISTANCE, 0); + input_report_key(wac_i2c->input_dev, BTN_STYLUS, 0); + input_report_key(wac_i2c->input_dev, BTN_TOUCH, 0); + input_report_key(wac_i2c->input_dev, BTN_TOOL_RUBBER, 0); + input_report_key(wac_i2c->input_dev, BTN_TOOL_PEN, 0); + input_sync(wac_i2c->input_dev); +#ifdef CONFIG_INPUT_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_PEN, BOOSTER_MODE_FORCE_OFF); +#endif + + wac_i2c->pen_prox = 0; + wac_i2c->pen_pressed = 0; + wac_i2c->side_pressed = 0; + /*wac_i2c->pen_pdct = PDCT_NOSIGNAL;*/ +} + +int wacom_i2c_send(struct wacom_i2c *wac_i2c, + const char *buf, int count, bool mode) +{ + struct i2c_client *client = mode ? + wac_i2c->client_boot : wac_i2c->client; + + if (wac_i2c->boot_mode && !mode) { + printk(KERN_ERR + "epen:failed to send\n"); + return 0; + } + + return i2c_master_send(client, buf, count); +} + +int wacom_i2c_recv(struct wacom_i2c *wac_i2c, + char *buf, int count, bool mode) +{ + struct i2c_client *client = mode ? + wac_i2c->client_boot : wac_i2c->client; + + if (wac_i2c->boot_mode && !mode) { + printk(KERN_ERR + "epen:failed to send\n"); + return 0; + } + + return i2c_master_recv(client, buf, count); +} + +int wacom_i2c_test(struct wacom_i2c *wac_i2c) +{ + int ret, i; + char buf, test[10]; + buf = COM_QUERY; + + ret = wacom_i2c_send(wac_i2c, &buf, sizeof(buf), false); + if (ret > 0) + printk(KERN_INFO "epen:buf:%d, sent:%d\n", buf, ret); + else { + printk(KERN_ERR "epen:Digitizer is not active\n"); + return -1; + } + + ret = wacom_i2c_recv(wac_i2c, test, sizeof(test), false); + if (ret >= 0) { + for (i = 0; i < 8; i++) + printk(KERN_INFO "epen:%d\n", test[i]); + } else { + printk(KERN_ERR "epen:Digitizer does not reply\n"); + return -1; + } + + return 0; +} + +int wacom_checksum(struct wacom_i2c *wac_i2c) +{ + int ret = 0, retry = 10; + int i = 0; + u8 buf[5] = {0, }; + + buf[0] = COM_CHECKSUM; + + while (retry--) { + ret = wacom_i2c_send(wac_i2c, &buf[0], 1, false); + if (ret < 0) { + printk(KERN_DEBUG + "epen:i2c fail, retry, %d\n", + __LINE__); + continue; + } + + msleep(200); + ret = wacom_i2c_recv(wac_i2c, buf, 5, false); + if (ret < 0) { + printk(KERN_DEBUG + "epen:i2c fail, retry, %d\n", + __LINE__); + continue; + } else if (buf[0] == 0x1f) + break; + printk(KERN_DEBUG "epen:checksum retry\n"); + } + + if (ret >= 0) { + printk(KERN_DEBUG + "epen:received checksum %x, %x, %x, %x, %x\n", + buf[0], buf[1], buf[2], buf[3], buf[4]); + } + + for (i = 0; i < 5; ++i) { + if (buf[i] != fw_chksum[i]) { + printk(KERN_DEBUG + "epen:checksum fail %dth %x %x\n", i, + buf[i], fw_chksum[i]); + break; + } + } + + wac_i2c->checksum_result = (5 == i); + + return wac_i2c->checksum_result; +} + +int wacom_i2c_query(struct wacom_i2c *wac_i2c) +{ + struct wacom_g5_platform_data *pdata = wac_i2c->pdata; + struct wacom_features *wac_feature = wac_i2c->wac_feature; + u8 data[COM_QUERY_BUFFER] = {0, }; + u8 *query = data + COM_QUERY_POS; + int read_size = COM_QUERY_BUFFER; + u8 buf = COM_QUERY; + int ret; + int i; + int max_x, max_y, pressure; + + for (i = 0; i < COM_QUERY_RETRY; i++) { + if (unlikely(pdata->use_query_cmd)) { + ret = wacom_i2c_send(wac_i2c, &buf, 1, false); + if (ret < 0) { + printk(KERN_ERR"epen:I2C send failed(%d)\n", ret); + msleep(50); + continue; + } + read_size = COM_QUERY_NUM; + query = data; + msleep(50); + } + + ret = wacom_i2c_recv(wac_i2c, data, read_size, false); + if (ret < 0) { + printk(KERN_ERR"epen:I2C recv failed(%d)\n", ret); + continue; + } + + printk(KERN_INFO "epen:%s: %dth ret of wacom query=%d\n", + __func__, i, ret); + + if (read_size != ret) { + printk(KERN_ERR"epen:read size error %d of %d\n", ret, read_size); + continue; + } + + if (0x0f == query[EPEN_REG_HEADER]) { + wac_feature->fw_version = + ((u16) query[EPEN_REG_FWVER1] << 8) + (u16) query[EPEN_REG_FWVER2]; + break; + } + + printk(KERN_ERR + "epen:%X, %X, %X, %X, %X, %X, %X, fw=0x%x\n", + query[0], query[1], query[2], query[3], + query[4], query[5], query[6], + wac_feature->fw_version); + } + + printk(KERN_NOTICE + "epen:%X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X\n", query[0], + query[1], query[2], query[3], query[4], query[5], query[6], + query[7], query[8], query[9], query[10], query[11], query[12], query[13]); + + if (i == COM_QUERY_RETRY || ret < 0) { + printk(KERN_ERR"epen:%s:failed to read query\n", __func__); + wac_feature->fw_version = 0; + wac_i2c->query_status = false; + return ret; + } + wac_i2c->query_status = true; + + max_x = ((u16) query[EPEN_REG_X1] << 8) + (u16) query[EPEN_REG_X2]; + max_y = ((u16) query[EPEN_REG_Y1] << 8) + (u16) query[EPEN_REG_Y2]; + pressure = ((u16) query[EPEN_REG_PRESSURE1] << 8) + (u16) query[EPEN_REG_PRESSURE2]; + + printk(KERN_NOTICE"epen:q max_x=%d max_y=%d, max_pressure=%d\n", + max_x, max_y, pressure); + printk(KERN_NOTICE"epen:p max_x=%d max_y=%d, max_pressure=%d\n", + pdata->max_x, pdata->max_y, pdata->max_pressure); + printk(KERN_NOTICE "epen:fw_version=0x%X (d7:0x%X,d8:0x%X)\n", + wac_feature->fw_version, query[EPEN_REG_FWVER1], query[EPEN_REG_FWVER2]); + printk(KERN_NOTICE "epen:mpu %#x, bl %#x, tx %d, ty %d, h %d\n", + query[EPEN_REG_MPUVER], query[EPEN_REG_BLVER], + query[EPEN_REG_TILT_X], query[EPEN_REG_TILT_Y], + query[EPEN_REG_HEIGHT]); + + return ret; +} + + +int wacom_i2c_modecheck(struct wacom_i2c *wac_i2c) +{ + u8 buf = COM_QUERY; + int ret; + int mode = WACOM_I2C_MODE_NORMAL; + + ret = wacom_i2c_send(wac_i2c, &buf, 1, false); + if (ret < 0) { + mode = WACOM_I2C_MODE_BOOT; + } + else{ + mode = WACOM_I2C_MODE_NORMAL; + } + printk(KERN_DEBUG "epen:I2C send at usermode(%d)\n", ret); + return mode; +} + + +#ifdef WACOM_IMPORT_FW_ALGO +#ifdef WACOM_USE_OFFSET_TABLE +void wacom_i2c_coord_offset(u16 *coordX, u16 *coordY) +{ + u16 ix, iy; + u16 dXx_0, dXy_0, dXx_1, dXy_1; + int D0, D1, D2, D3, D; + + ix = (u16) (((*coordX)) / CAL_PITCH); + iy = (u16) (((*coordY)) / CAL_PITCH); + + dXx_0 = *coordX - (ix * CAL_PITCH); + dXx_1 = CAL_PITCH - dXx_0; + + dXy_0 = *coordY - (iy * CAL_PITCH); + dXy_1 = CAL_PITCH - dXy_0; + + if (*coordX <= WACOM_MAX_COORD_X) { + D0 = tableX[user_hand][screen_rotate][ix + + (iy * LATTICE_SIZE_X)] * + (dXx_1 + dXy_1); + D1 = tableX[user_hand][screen_rotate][ix + 1 + + iy * LATTICE_SIZE_X] * + (dXx_0 + dXy_1); + D2 = tableX[user_hand][screen_rotate][ix + + (iy + + 1) * LATTICE_SIZE_X] * + (dXx_1 + dXy_0); + D3 = tableX[user_hand][screen_rotate][ix + 1 + + (iy + + 1) * LATTICE_SIZE_X] * + (dXx_0 + dXy_0); + D = (D0 + D1 + D2 + D3) / (4 * CAL_PITCH); + + if (((int)*coordX + D) > 0) + *coordX += D; + else + *coordX = 0; + } + + if (*coordY <= WACOM_MAX_COORD_Y) { + D0 = tableY[user_hand][screen_rotate][ix + + (iy * LATTICE_SIZE_X)] * + (dXy_1 + dXx_1); + D1 = tableY[user_hand][screen_rotate][ix + 1 + + iy * LATTICE_SIZE_X] * + (dXy_1 + dXx_0); + D2 = tableY[user_hand][screen_rotate][ix + + (iy + + 1) * LATTICE_SIZE_X] * + (dXy_0 + dXx_1); + D3 = tableY[user_hand][screen_rotate][ix + 1 + + (iy + + 1) * LATTICE_SIZE_X] * + (dXy_0 + dXx_0); + D = (D0 + D1 + D2 + D3) / (4 * CAL_PITCH); + + if (((int)*coordY + D) > 0) + *coordY += D; + else + *coordY = 0; + } +} +#endif + +#ifdef WACOM_USE_AVERAGING +#define STEP 32 +void wacom_i2c_coord_average(short *CoordX, short *CoordY, + int bFirstLscan, int aveStrength) +{ + unsigned char i; + unsigned int work; + unsigned char ave_step = 4, ave_shift = 2; + static int Sum_X, Sum_Y; + static int AveBuffX[STEP], AveBuffY[STEP]; + static unsigned char AvePtr; + static unsigned char bResetted; +#ifdef WACOM_USE_AVE_TRANSITION + static int tmpBuffX[STEP], tmpBuffY[STEP]; + static unsigned char last_step, last_shift; + static bool transition; + static int tras_counter; +#endif + if (bFirstLscan == 0) { + bResetted = 0; +#ifdef WACOM_USE_AVE_TRANSITION + transition = false; + tras_counter = 0; + last_step = 4; + last_shift = 2; +#endif + return ; + } +#ifdef WACOM_USE_AVE_TRANSITION + if (bResetted) { + if (transition) { + ave_step = last_step; + ave_shift = last_shift; + } else { + ave_step = 2 << (aveStrength-1); + ave_shift = aveStrength; + } + + if (!transition && ave_step != 0 && last_step != 0) { + if (ave_step > last_step) { + transition = true; + tras_counter = ave_step; + /*printk(KERN_DEBUG + "epen:Trans %d to %d\n", + last_step, ave_step);*/ + + memcpy(tmpBuffX, AveBuffX, + sizeof(unsigned int) * last_step); + memcpy(tmpBuffY, AveBuffY, + sizeof(unsigned int) * last_step); + for (i = 0 ; i < last_step; ++i) { + AveBuffX[i] = tmpBuffX[AvePtr]; + AveBuffY[i] = tmpBuffY[AvePtr]; + if (++AvePtr >= last_step) + AvePtr = 0; + } + for ( ; i < ave_step; ++i) { + AveBuffX[i] = *CoordX; + AveBuffY[i] = *CoordY; + Sum_X += *CoordX; + Sum_Y += *CoordY; + } + AvePtr = 0; + + *CoordX = Sum_X >> ave_shift; + *CoordY = Sum_Y >> ave_shift; + + bResetted = 1; + + last_step = ave_step; + last_shift = ave_shift; + return ; + } else if (ave_step < last_step) { + transition = true; + tras_counter = ave_step; + /*printk(KERN_DEBUG + "epen:Trans %d to %d\n", + last_step, ave_step);*/ + + memcpy(tmpBuffX, AveBuffX, + sizeof(unsigned int) * last_step); + memcpy(tmpBuffY, AveBuffY, + sizeof(unsigned int) * last_step); + Sum_X = 0; + Sum_Y = 0; + for (i = 1 ; i <= ave_step; ++i) { + if (AvePtr == 0) + AvePtr = last_step - 1; + else + --AvePtr; + AveBuffX[ave_step-i] = tmpBuffX[AvePtr]; + Sum_X = Sum_X + tmpBuffX[AvePtr]; + + AveBuffY[ave_step-i] = tmpBuffY[AvePtr]; + Sum_Y = Sum_Y + tmpBuffY[AvePtr]; + } + AvePtr = 0; + bResetted = 1; + *CoordX = Sum_X >> ave_shift; + *CoordY = Sum_Y >> ave_shift; + + bResetted = 1; + + last_step = ave_step; + last_shift = ave_shift; + return ; + } + } + + if (!transition && (last_step != ave_step)) { + last_step = ave_step; + last_shift = ave_shift; + } + } +#endif + if (bFirstLscan && (bResetted == 0)) { + AvePtr = 0; + ave_step = 4; + ave_shift = 2; +#if defined(WACOM_USE_AVE_TRANSITION) + tras_counter = ave_step; +#endif + for (i = 0; i < ave_step; i++) { + AveBuffX[i] = *CoordX; + AveBuffY[i] = *CoordY; + } + Sum_X = (unsigned int)*CoordX << ave_shift; + Sum_Y = (unsigned int)*CoordY << ave_shift; + bResetted = 1; + } else if (bFirstLscan) { + Sum_X = Sum_X - AveBuffX[AvePtr] + (*CoordX); + AveBuffX[AvePtr] = *CoordX; + work = Sum_X >> ave_shift; + *CoordX = (unsigned int)work; + + Sum_Y = Sum_Y - AveBuffY[AvePtr] + (*CoordY); + AveBuffY[AvePtr] = (*CoordY); + work = Sum_Y >> ave_shift; + *CoordY = (unsigned int)work; + + if (++AvePtr >= ave_step) + AvePtr = 0; + } +#ifdef WACOM_USE_AVE_TRANSITION + if (transition) { + --tras_counter; + if (tras_counter < 0) + transition = false; + } +#endif +} +#endif + +u8 wacom_i2c_coord_level(u16 gain) +{ + if (gain >= 0 && gain <= 14) + return 0; + else if (gain > 14 && gain <= 24) + return 1; + else + return 2; +} + +#ifdef WACOM_USE_BOX_FILTER +void boxfilt(short *CoordX, short *CoordY, + int height, int bFirstLscan) +{ + bool isMoved = false; + static bool bFirst = true; + static short lastX_loc, lastY_loc; + static unsigned char bResetted; + int threshold = 0; + int distance = 0; + static short bounce; + + /*Reset filter*/ + if (bFirstLscan == 0) { + bResetted = 0; + return ; + } + + if (bFirstLscan && (bResetted == 0)) { + lastX_loc = *CoordX; + lastY_loc = *CoordY; + bResetted = 1; + } + + if (bFirst) { + lastX_loc = *CoordX; + lastY_loc = *CoordY; + bFirst = false; + } + + /*Start Filtering*/ + threshold = 30; + + /*X*/ + distance = abs(*CoordX - lastX_loc); + + if (distance >= threshold) + isMoved = true; + + if (isMoved == false) { + distance = abs(*CoordY - lastY_loc); + if (distance >= threshold) + isMoved = true; + } + + /*Update position*/ + if (isMoved) { + lastX_loc = *CoordX; + lastY_loc = *CoordY; + } else { + *CoordX = lastX_loc + bounce; + *CoordY = lastY_loc; + if (bounce) + bounce = 0; + else + bounce += 5; + } +} +#endif + +#if defined(WACOM_USE_AVE_TRANSITION) +int g_aveLevel_C[] = {2, 2, 4, }; +int g_aveLevel_X[] = {3, 3, 4, }; +int g_aveLevel_Y[] = {3, 3, 4, }; +int g_aveLevel_Trs[] = {3, 4, 4, }; +int g_aveLevel_Cor[] = {4, 4, 4, }; + +void ave_level(short CoordX, short CoordY, + int height, int *aveStrength) +{ + bool transition = false; + bool edgeY = false, edgeX = false; + bool cY = false, cX = false; + + if (CoordY > (WACOM_MAX_COORD_Y - 800)) + cY = true; + else if (CoordY < 800) + cY = true; + + if (CoordX > (WACOM_MAX_COORD_X - 800)) + cX = true; + else if (CoordX < 800) + cX = true; + + if (cX && cY) { + *aveStrength = g_aveLevel_Cor[height]; + return ; + } + + /*Start Filtering*/ + if (CoordX > X_INC_E1) + edgeX = true; + else if (CoordX < X_INC_S1) + edgeX = true; + + /*Right*/ + if (CoordY > Y_INC_E1) { + /*Transition*/ + if (CoordY < Y_INC_E3) + transition = true; + else + edgeY = true; + } + /*Left*/ + else if (CoordY < Y_INC_S1) { + /*Transition*/ + if (CoordY > Y_INC_S3) + transition = true; + else + edgeY = true; + } + + if (transition) + *aveStrength = g_aveLevel_Trs[height]; + else if (edgeX) + *aveStrength = g_aveLevel_X[height]; + else if (edgeY) + *aveStrength = g_aveLevel_Y[height]; + else + *aveStrength = g_aveLevel_C[height]; +} +#endif +#endif /*WACOM_IMPORT_FW_ALGO*/ + +static int keycode[] = { + KEY_RECENT, KEY_BACK, +}; +void wacom_i2c_softkey(struct wacom_i2c *wac_i2c, s16 key, s16 pressed) +{ +#ifdef WACOM_USE_SOFTKEY_BLOCK + if (wac_i2c->block_softkey && pressed) { + cancel_delayed_work_sync(&wac_i2c->softkey_block_work); + printk(KERN_DEBUG"epen:block p\n"); + return ; + } else if (wac_i2c->block_softkey && !pressed) { + printk(KERN_DEBUG"epen:block r\n"); + wac_i2c->block_softkey = false; + return ; + } +#endif + input_report_key(wac_i2c->input_dev, + keycode[key], pressed); + input_sync(wac_i2c->input_dev); + +#if !defined(CONFIG_SAMSUNG_PRODUCT_SHIP) + printk(KERN_DEBUG "epen:keycode:%d pressed:%d\n", + keycode[key], pressed); +#else + printk(KERN_DEBUG "epen:pressed:%d\n", + pressed); +#endif +} + +#ifdef LCD_FREQ_SYNC +void wacom_i2c_lcd_freq_check(struct wacom_i2c *wac_i2c, u8 *data) +{ + u32 lcd_freq = 0; + + if (wac_i2c->lcd_freq_wait == false) { + lcd_freq = ((u16) data[10] << 8) + (u16) data[11]; + wac_i2c->lcd_freq = 2000000000 / (lcd_freq + 1); + wac_i2c->lcd_freq_wait = true; + schedule_work(&wac_i2c->lcd_freq_work); + } +} +#endif + +int wacom_i2c_coord(struct wacom_i2c *wac_i2c) +{ + struct wacom_g5_platform_data *pdata = wac_i2c->pdata; + u8 data[COM_COORD_NUM] = {0, }; + bool prox = false; + bool rdy = false; + int ret = 0; + int stylus; + s16 x, y, pressure; + s16 tmp; + u8 gain = 0; + s16 softkey, pressed, keycode; + s8 tilt_x = 0; + s8 tilt_y = 0; + s8 retry = 3; + + while (retry--) { + ret = wacom_i2c_recv(wac_i2c, data, COM_COORD_NUM, false); + if (ret >= 0) + break; + + printk(KERN_ERR "epen:%s failed to read i2c.retry %d.L%d\n", + __func__, retry, __LINE__); + } + if (ret < 0) { + printk(KERN_ERR"epen:i2c err, exit %s\n", __func__); + return -1; + } + +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + /*printk(KERN_DEBUG"epen:%x, %x, %x, %x, %x, %x, %x %x %x %x %x %x\n", + data[0], data[1], data[2], data[3], data[4], data[5], data[6], + data[7], data[8], data[9], data[10], data[11]);*/ +#endif + + rdy = data[0] & 0x80; + +#ifdef LCD_FREQ_SYNC + if (!rdy && !data[1] && !data[2] && !data[3] && !data[4]) { + if (likely(wac_i2c->use_lcd_freq_sync)) { + if (unlikely(!wac_i2c->pen_prox)) { + wacom_i2c_lcd_freq_check(wac_i2c, data); + } + } + } +#endif + + if (rdy) { + /* checking softkey */ + softkey = !!(data[5] & 0x80); + if (unlikely(softkey)) { + if (unlikely(wac_i2c->pen_prox)) + forced_release(wac_i2c); + + pressed = !!(data[5] & 0x40); + keycode = (data[5] & 0x30) >> 4; + + wacom_i2c_softkey(wac_i2c, keycode, pressed); + return 0; + } + + /* prox check */ + if (!wac_i2c->pen_prox) { + /* check pdct */ + if (unlikely(wac_i2c->pen_pdct == PDCT_NOSIGNAL)) { + printk(KERN_DEBUG"epen:pdct is not active\n"); + return 0; + } +#ifdef CONFIG_INPUT_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_PEN, BOOSTER_MODE_ON); +#endif + wac_i2c->pen_prox = 1; + + if (data[0] & 0x40) + wac_i2c->tool = BTN_TOOL_RUBBER; + else + wac_i2c->tool = BTN_TOOL_PEN; +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + printk(KERN_DEBUG"epen:is in(%d)\n", wac_i2c->tool); +#endif + } + + prox = !!(data[0] & 0x10); + stylus = !!(data[0] & 0x20); + x = ((u16) data[1] << 8) + (u16) data[2]; + y = ((u16) data[3] << 8) + (u16) data[4]; + pressure = ((u16) data[5] << 8) + (u16) data[6]; + gain = data[7]; + tilt_x = (s8)data[9]; + tilt_y = -(s8)data[8]; + + /* origin */ + x = x - pdata->origin[0]; + y = y - pdata->origin[1]; + + /* change axis from wacom to lcd */ + if (pdata->x_invert) + x = pdata->max_x - x; + if (pdata->y_invert) + y = pdata->max_y - y; + + if (pdata->xy_switch) { + tmp = x; + x = y; + y = tmp; + } + + /* validation check */ + if (unlikely(x < 0 || y < 0 || x > pdata->max_y || y > pdata->max_x)) { +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + printk(KERN_DEBUG "epen:raw data x=%d, y=%d\n", + x, y); +#endif + return 0; + } + + /* report info */ + input_report_abs(wac_i2c->input_dev, ABS_X, x); + input_report_abs(wac_i2c->input_dev, ABS_Y, y); + input_report_abs(wac_i2c->input_dev, + ABS_PRESSURE, pressure); + input_report_abs(wac_i2c->input_dev, + ABS_DISTANCE, gain); + input_report_abs(wac_i2c->input_dev, + ABS_TILT_X, tilt_x); + input_report_abs(wac_i2c->input_dev, + ABS_TILT_Y, tilt_y); + input_report_key(wac_i2c->input_dev, + BTN_STYLUS, stylus); + input_report_key(wac_i2c->input_dev, BTN_TOUCH, prox); + input_report_key(wac_i2c->input_dev, wac_i2c->tool, 1); + input_sync(wac_i2c->input_dev); + + /* log */ + if (prox && !wac_i2c->pen_pressed) { +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + printk(KERN_DEBUG + "epen:is pressed(%d,%d,%d)(%d)\n", + x, y, pressure, wac_i2c->tool); +#else + printk(KERN_DEBUG "epen:pressed\n"); +#endif + } else if (!prox && wac_i2c->pen_pressed) { +#if defined(CONFIG_SAMSUNG_KERNEL_DEBUG_USER) + printk(KERN_DEBUG + "epen:is released(%d,%d,%d)(%d)\n", + x, y, pressure, wac_i2c->tool); +#else + printk(KERN_DEBUG "epen:released\n"); +#endif + } + wac_i2c->pen_pressed = prox; + + /* check side */ + if (stylus && !wac_i2c->side_pressed) + printk(KERN_DEBUG "epen:side on\n"); + else if (!stylus && wac_i2c->side_pressed) + printk(KERN_DEBUG "epen:side off\n"); + + wac_i2c->side_pressed = stylus; + } else { + if (wac_i2c->pen_prox) { + /* input_report_abs(wac->input_dev, + ABS_X, x); */ + /* input_report_abs(wac->input_dev, + ABS_Y, y); */ + + input_report_abs(wac_i2c->input_dev, ABS_PRESSURE, 0); + input_report_abs(wac_i2c->input_dev, + ABS_DISTANCE, 0); + input_report_key(wac_i2c->input_dev, BTN_STYLUS, 0); + input_report_key(wac_i2c->input_dev, BTN_TOUCH, 0); + input_report_key(wac_i2c->input_dev, + BTN_TOOL_RUBBER, 0); + input_report_key(wac_i2c->input_dev, BTN_TOOL_PEN, 0); + input_sync(wac_i2c->input_dev); +#ifdef CONFIG_INPUT_BOOSTER + input_booster_send_event(BOOSTER_DEVICE_PEN, BOOSTER_MODE_OFF); +#endif +#ifdef WACOM_USE_SOFTKEY_BLOCK + if (wac_i2c->pen_pressed) { + cancel_delayed_work_sync(&wac_i2c->softkey_block_work); + wac_i2c->block_softkey = true; + schedule_delayed_work(&wac_i2c->softkey_block_work, + SOFTKEY_BLOCK_DURATION); + } +#endif + printk(KERN_DEBUG "epen:is out"); + } + wac_i2c->pen_prox = 0; + wac_i2c->pen_pressed = 0; + wac_i2c->side_pressed = 0; + } + + return 0; +} diff --git a/drivers/input/wacom/wacom_i2c_func.h b/drivers/input/wacom/wacom_i2c_func.h new file mode 100644 index 000000000000..7afb2952576f --- /dev/null +++ b/drivers/input/wacom/wacom_i2c_func.h @@ -0,0 +1,48 @@ +/* + * wacom_i2c_func.h - Wacom G5 Digitizer Controller (I2C bus) + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LINUX_WACOM_I2C_FUNC_H +#define _LINUX_WACOM_I2C_FUNC_H + +#define WACOM_I2C_STOP 0x30 +#define WACOM_I2C_START 0x31 +#define WACOM_I2C_GRID_CHECK 0xC9 +#define WACOM_STATUS 0xD8 + +extern int g_aveLevel_C[]; +extern int g_aveLevel_X[]; +extern int g_aveLevel_Y[]; +extern int g_aveLevel_Trs[]; +extern int g_aveLevel_Cor[]; + +extern int wacom_i2c_send(struct wacom_i2c *wac_i2c, + const char *buf, int count, bool mode); +extern int wacom_i2c_recv(struct wacom_i2c *wac_i2c, + char *buf, int count, bool mode); +extern int wacom_i2c_test(struct wacom_i2c *wac_i2c); +extern int wacom_i2c_coord(struct wacom_i2c *wac_i2c); +extern int wacom_i2c_query(struct wacom_i2c *wac_i2c); +extern int wacom_i2c_modecheck(struct wacom_i2c *wac_i2c); +extern int wacom_checksum(struct wacom_i2c *wac_i2c); +extern void forced_release(struct wacom_i2c *wac_i2c); +#ifdef WACOM_PDCT_WORK_AROUND +extern void forced_hover(struct wacom_i2c *wac_i2c); +#endif + +#endif /* _LINUX_WACOM_I2C_FUNC_H */ diff --git a/drivers/iommu/exynos-iommu.h b/drivers/iommu/exynos-iommu.h index 9dff7d6de836..d568cbf3d132 100644 --- a/drivers/iommu/exynos-iommu.h +++ b/drivers/iommu/exynos-iommu.h @@ -68,7 +68,7 @@ #define SECT_PER_DSECT (DSECT_SIZE / SECT_SIZE) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) -#define PGBASE_TO_PHYS(pgent) (phys_addr_t)((pgent) << PG_ENT_SHIFT) +#define PGBASE_TO_PHYS(pgent) ((phys_addr_t)(pgent) << PG_ENT_SHIFT) #define MAX_NUM_PBUF 6 #define MAX_NUM_PLANE 6 @@ -83,13 +83,14 @@ typedef u32 sysmmu_pte_t; #define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t)) -#define spsection_phys(sent) PGBASE_TO_PHYS(*(sent) & SPSECT_ENT_MASK) +#define ENT_TO_PHYS(ent) (phys_addr_t)(*(ent)) +#define spsection_phys(sent) PGBASE_TO_PHYS(ENT_TO_PHYS(sent) & SPSECT_ENT_MASK) #define spsection_offs(iova) ((iova) & (SPSECT_SIZE - 1)) -#define section_phys(sent) PGBASE_TO_PHYS(*(sent) & SECT_ENT_MASK) +#define section_phys(sent) PGBASE_TO_PHYS(ENT_TO_PHYS(sent) & SECT_ENT_MASK) #define section_offs(iova) ((iova) & (SECT_SIZE - 1)) -#define lpage_phys(pent) PGBASE_TO_PHYS(*(pent) & LPAGE_ENT_MASK) +#define lpage_phys(pent) PGBASE_TO_PHYS(ENT_TO_PHYS(pent) & LPAGE_ENT_MASK) #define lpage_offs(iova) ((iova) & (LPAGE_SIZE - 1)) -#define spage_phys(pent) PGBASE_TO_PHYS(*(pent) & SPAGE_ENT_MASK) +#define spage_phys(pent) PGBASE_TO_PHYS(ENT_TO_PHYS(pent) & SPAGE_ENT_MASK) #define spage_offs(iova) ((iova) & (SPAGE_SIZE - 1)) #define lv2table_base(sent) ((phys_addr_t)(*(sent) & ~0x3F) << PG_ENT_SHIFT) diff --git a/drivers/iommu/exynos-iovmm-v6.c b/drivers/iommu/exynos-iovmm-v6.c index 459f08a4b194..6e8c1b8a271c 100644 --- a/drivers/iommu/exynos-iovmm-v6.c +++ b/drivers/iommu/exynos-iovmm-v6.c @@ -257,6 +257,18 @@ void iovmm_deactivate(struct device *dev) iommu_detach_device(vmm->domain, dev); } +struct iommu_domain *get_domain_from_dev(struct device *dev) +{ + struct exynos_iovmm *vmm = exynos_get_iovmm(dev); + + if (!vmm) { + dev_err(dev, "%s: IOVMM not found\n", __func__); + return NULL; + } + + return vmm->domain; +} + /* iovmm_map - allocate and map IO virtual memory for the given device * dev: device that has IO virtual address space managed by IOVMM * sg: list of physically contiguous memory chunks. The preceding chunk needs to diff --git a/drivers/iommu/exynos-iovmm.c b/drivers/iommu/exynos-iovmm.c index 3d7a0d1ffc56..ce732ee63e49 100644 --- a/drivers/iommu/exynos-iovmm.c +++ b/drivers/iommu/exynos-iovmm.c @@ -279,6 +279,18 @@ void iovmm_deactivate(struct device *dev) iommu_detach_device(vmm->domain, dev); } +struct iommu_domain *get_domain_from_dev(struct device *dev) +{ + struct exynos_iovmm *vmm = exynos_get_iovmm(dev); + + if (!vmm) { + dev_err(dev, "%s: IOVMM not found\n", __func__); + return NULL; + } + + return vmm->domain; +} + /* iovmm_map - allocate and map IO virtual memory for the given device * dev: device that has IO virtual address space managed by IOVMM * sg: list of physically contiguous memory chunks. The preceding chunk needs to diff --git a/drivers/ledmatrix/Kconfig b/drivers/ledmatrix/Kconfig new file mode 100644 index 000000000000..55bff587c393 --- /dev/null +++ b/drivers/ledmatrix/Kconfig @@ -0,0 +1,14 @@ +# +# ICE5_FPGA_LED_MATRIX +# +menu "LED MATRIX FPGA" + +config ICE5_FPGA_LED_MATRIX + tristate "ICE5 FPGA chip for LED MATRIX control" + default n + help + Lattice FPGA can support LED MATRIX controller. + The configuration will enable LED MATRIX feature. + To compile this driver as a module, choose M here. + If unsure, say N. +endmenu diff --git a/drivers/ledmatrix/Makefile b/drivers/ledmatrix/Makefile new file mode 100644 index 000000000000..dbaaf85ff97f --- /dev/null +++ b/drivers/ledmatrix/Makefile @@ -0,0 +1,5 @@ +# +# makefile for LED Emulator +# + +obj-$(CONFIG_ICE5_FPGA_LED_MATRIX) += ice5lp_ledmatrix.o diff --git a/drivers/ledmatrix/ice5lp_ledmatrix.c b/drivers/ledmatrix/ice5lp_ledmatrix.c new file mode 100644 index 000000000000..cca7b67e96e6 --- /dev/null +++ b/drivers/ledmatrix/ice5lp_ledmatrix.c @@ -0,0 +1,1007 @@ +/* + * driver/ice5lp_ledmatrix fpga driver + * + * Copyright (C) 2013 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (CONFIG_OF) +#include +#include +#endif /* CONFIG_OF */ + +#include "ice5lp_ledmatrix_fw.h" + +/* to enable mclk */ +#include +#include + +#define IRDA_TEST_CODE_SIZE (52+48) +#define IRDA_TEST_CODE_ADDR 0x00 +#define READ_LENGTH 8 + +#define US_TO_PATTERN 1000000 +#define MIN_FREQ 20000 + +/* K 3G FW has a limitation of data register : 1000 */ +enum { + REG_LIMIT = 990, +}; + +struct ice5_fpga_data { + struct workqueue_struct *firmware_dl; + struct delayed_work fw_dl; + const struct firmware *fw0; + const struct firmware *fw1; + struct i2c_client *client; + struct regulator *regulator; + char *regulator_name; + struct mutex mutex; + struct { + unsigned char addr; + unsigned char data[REG_LIMIT]; + } i2c_block_transfer; + int i2c_len; + +// int ir_freq; +// int ir_sum; +// struct clk *clock; +}; + +enum { + PWR_ALW, + PWR_REG, + PWR_LDO, +}; + +static struct ice5lp_ledmatrix_platform_data *g_pdata; +static int fw_loaded = 0; +static bool send_success = false; +static int power_type = PWR_LDO; + +/* + * Send barcode emulator firmware data through spi communication + * Firmware Update Code + */ + +static int ice5lp_fw_data_send(const u8 *data, int length) +{ + unsigned int i,j, k; + unsigned char spibit; + + i=0; + k=0; + pr_info("ice5: %s : before spi_clk_scl : %d\n", __func__, gpio_get_value(g_pdata->spi_clk_scl)); + pr_info("ice5: %s : before spi_si_sda : %d\n", __func__, gpio_get_value(g_pdata->spi_si_sda)); + while (i < length) { + j=0; + spibit = data[i]; + while (j < 8) { + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_LOW); + + if (spibit & 0x80) { + gpio_set_value(g_pdata->spi_si_sda,GPIO_LEVEL_HIGH); + } else { + gpio_set_value(g_pdata->spi_si_sda,GPIO_LEVEL_LOW); + } + j = j+1; + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_HIGH); + spibit = spibit<<1; + } + i = i+1; + k=k+1; + if((k%4)==0 && k<=120) + pr_info("ice5: %02X%02X%02X%02X\n", data[k-4], data[k-3], data[k-2], data[k-1]); + } + + i = 0; + while (i < 200) { + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_LOW); + i = i+1; + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_HIGH); + } + + pr_info("ice5: %s : after spi_clk_scl : %d\n", __func__, gpio_get_value(g_pdata->spi_clk_scl)); + pr_info("ice5: %s : after spi_si_sda : %d\n", __func__, gpio_get_value(g_pdata->spi_si_sda)); + return 0; +} + +static int ice5lp_fw_update_start(const u8 *data, int length, int creset) +{ + int retry_count = 0; + + pr_info("ice5: %s\n", __func__); +#if 1 + gpio_set_value(creset, GPIO_LEVEL_LOW); + pr_info("ice5: %s : creset LOW : %d\n", __func__, gpio_get_value(creset)); + + usleep_range(30, 40); + + gpio_set_value(creset, GPIO_LEVEL_HIGH); + pr_info("ice5: %s : creset HIGH : %d\n", __func__, gpio_get_value(creset)); + usleep_range(1000, 1100); + +// while(!ice5lp_check_fwdone()) { + usleep_range(10, 20); + ice5lp_fw_data_send(data, length); + usleep_range(50, 60); + +// if (retry_count > 9) { +// pr_info("ice5lp_ledmatrix firmware update is NOT loaded\n"); +// break; +// } else { + retry_count++; +// } +// } + if (ice5lp_check_fwdone()) { +// gpio_set_value(g_pdata->spi_en_rstn, GPIO_LEVEL_HIGH); + pr_info("ice5lp_ledmatrix firmware update success\n"); + fw_loaded = 1; + } else { + pr_info("Finally, fail to update ice5lp_ledmatrix firmware!\n"); + } +#else + ice5lp_fw_data_send(data, length); +#endif + return 0; +} + +void ice5lp_fw_update(struct work_struct *work) +{ + struct ice5_fpga_data *data = + container_of(work, struct ice5_fpga_data, fw_dl.work); + struct i2c_client *client = data->client; + int ret; + + pr_info("ice5: %s\n", __func__); + gpio_free(g_pdata->spi_clk_scl); + gpio_free(g_pdata->spi_si_sda); + + gpio_request_one(g_pdata->creset_0, GPIOF_OUT_INIT_LOW, "creset_0"); + gpio_request_one(g_pdata->creset_1, GPIOF_OUT_INIT_LOW, "creset_1"); + gpio_request_one(g_pdata->fpga_reset, GPIOF_OUT_INIT_LOW, "fpga_reset"); + + ret = gpio_request_one(g_pdata->spi_si_sda, GPIOF_OUT_INIT_HIGH, "spi_si_sda"); + if(ret){ + pr_err("%s: cannot request spi_si_sda(%d)", __func__, ret); + } + + ret = gpio_request_one(g_pdata->spi_clk_scl, GPIOF_OUT_INIT_HIGH, "spi_clk_scl"); + if(ret){ + pr_err("%s: cannot request spi_clk_scl(%d)", __func__, ret); + } + + + + if (request_firmware(&data->fw0, "ice50/EINK0.fw", &client->dev)) + pr_err("%s: Fail to open firmware 0 file\n", __func__); + else + ice5lp_fw_update_start(data->fw0->data, data->fw0->size, g_pdata->creset_0); + + usleep_range(1000, 1100); + + if (request_firmware(&data->fw1, "ice50/EINK1.fw", &client->dev)) + pr_err("%s: Fail to open firmware 1 file\n", __func__); + else + ice5lp_fw_update_start(data->fw1->data, data->fw1->size, g_pdata->creset_1); + + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_LOW); + gpio_set_value(g_pdata->spi_si_sda,GPIO_LEVEL_LOW); + usleep_range(1000, 1100); + gpio_set_value(g_pdata->spi_clk_scl, GPIO_LEVEL_HIGH); + gpio_set_value(g_pdata->spi_si_sda,GPIO_LEVEL_HIGH); + usleep_range(30, 40); + + gpio_free(g_pdata->spi_clk_scl); + gpio_free(g_pdata->spi_si_sda); + + gpio_request(g_pdata->spi_si_sda, "sda"); + gpio_request(g_pdata->spi_clk_scl, "scl"); + +} + +static int ice5lp_ledmatrix_read(struct i2c_client *client, u16 addr, u8 length, u8 *value) +{ + + struct i2c_msg msg[2]; + int ret; + + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 1; + msg[0].buf = (u8 *) &addr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8 *) value; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret == 2) { + return 0; + } else { + pr_info("%s: err1 %d\n", __func__, ret); + return -EIO; + } +} + +#if 0 +/* When IR test does not work, we need to check some gpios' status */ +static void ice5lp_ledmatrix_print_gpio_status(void) +{ +/* to guess the status of CDONE during probe time */ + if (!fw_loaded) + pr_info("%s : firmware is not loaded\n", __func__); + else + pr_info("%s : firmware is loaded\n", __func__); + + pr_info("%s : fpga_reset : %d\n", __func__, gpio_get_value(g_pdata->fpga_reset)); + pr_info("%s : CRESET_0 : %d\n", __func__, gpio_get_value(g_pdata->creset_0)); + pr_info("%s : CRESET_1 : %d\n", __func__, gpio_get_value(g_pdata->creset_1)); +} +#endif + +static int ice5lp_check_fwdone(void) +{ +#if 0 + + if (!g_pdata->cdone) { + pr_info("%s : no cdone pin data\n", __func__); + return 0; + } + + /* Device in Operation when CDONE='1'; Device Failed when CDONE='0'. */ + if (gpio_get_value(g_pdata->cdone) != 1) { + pr_info("%s : CDONE_FAIL %d\n", __func__, + gpio_get_value(g_pdata->cdone)); + return 0; + } +#endif + return 1; +} + + +static int ice5lp_send_data_to_device(struct ice5_fpga_data *ir_data) +{ + struct ice5_fpga_data *data = ir_data; + struct i2c_client *client = data->client; + int buf_size = data->i2c_len; +// int retry_count = 0; + + int ret; + static int count_number; + +#if defined(DEBUG) + u8 *temp; + int i; + + temp = kzalloc(sizeof(u8)*(buf_size+20), GFP_KERNEL); + if (NULL == temp) + pr_err("Failed to data allocate %s\n", __func__); +#endif + + /* count the number of sending */ + if (count_number >= 100) + count_number = 0; + + count_number++; + + pr_info("%s: total buf_size: %d\n", __func__, buf_size); + + mutex_lock(&data->mutex); + ret = i2c_master_send(client, (unsigned char *) &(data->i2c_block_transfer), buf_size); + if (ret < 0) { + dev_err(&client->dev, "%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &(data->i2c_block_transfer), buf_size); + if (ret < 0) { + dev_err(&client->dev, "%s: err2 %d\n", __func__, ret); +// ice5lp_ledmatrix_print_gpio_status(); + } + } + +#if defined(DEBUG) + /* Registers can be read with special firmware */ +// ice5lp_ledmatrix_read(client, IRDA_TEST_CODE_ADDR, buf_size, temp); + + for (i = 0 ; i < buf_size; i++) + pr_info("[%s] %4d data %5x\n", __func__, i, data->i2c_block_transfer.data[i]); + + kfree(temp); +#endif + + mdelay(10); + + mutex_unlock(&data->mutex); + + pr_info("%s done", __func__); + return 0; + +} + +static int ice5lp_ledmatrix_set_data(struct ice5_fpga_data *data, int *arg, int count) +{ + int i; + /* offset means 1 (slave address) + 2 (data size) + 3 (frequency data) */ + int offset = 6; + int irdata_arg_size = count - 1; +#ifdef CONFIG_REPEAT_ENABLE +#if 0 + /* SAMSUNG : upper word of the third byte in frequecy means the number of repeat frame */ + int nr_repeat_frame = (arg[0] >> 20) & 0xF; +#endif + /* PEEL : 1206 */ + int nr_repeat_frame = (arg[1] >> 4) & 0xF; +#else + int nr_repeat_frame = 0; +#endif + /* remove the frequency data from the data length */ + int irdata_size = irdata_arg_size - nr_repeat_frame; + int temp = 0, converting_factor; + + /* calculate total length for i2c transferring */ + data->i2c_len = irdata_arg_size * 2 + offset; + + pr_info("%s : count %d\n", __func__, count); + pr_info("%s : irdata_arg_size %d\n", __func__, irdata_arg_size); + pr_info("%s : irdata_size %d\n", __func__, irdata_size); + pr_info("%s : i2c length %d\n", __func__, data->i2c_len); + + data->i2c_block_transfer.addr = 0x00; + + /* i2c address will be stored separatedly */ + data->i2c_block_transfer.data[0] = ((data->i2c_len - 1) >> 8) & 0xFF; + data->i2c_block_transfer.data[1] = ((data->i2c_len - 1) >> 0) & 0xFF; + + data->i2c_block_transfer.data[2] = (arg[0] >> 16) & 0xFF; + data->i2c_block_transfer.data[3] = (arg[0] >> 8) & 0xFF; + data->i2c_block_transfer.data[4] = (arg[0] >> 0) & 0xFF; + converting_factor = US_TO_PATTERN / arg[0]; + /* i2c address will be stored separatedly */ + offset--; + + /* arg[1]~[end] are the data for i2c transferring */ + for (i = 0 ; i < irdata_arg_size ; i++ ) { +#ifdef DEBUG + pr_info("[%s] %d array value : %x\n", __func__, i, arg[i]); +#endif + arg[i + 1] = (arg[i + 1] / converting_factor); + data->i2c_block_transfer.data[i * 2 + offset] = arg[i+1] >> 8; + data->i2c_block_transfer.data[i * 2 + offset + 1] = arg[i+1] & 0xFF; + } + + /* +1 is for removing frequency data */ +#ifdef CONFIG_REPEAT_ENABLE + for (i = 1 ; i < irdata_arg_size ; i++) + temp = temp + arg[i + 1]; +#else + for (i = 0 ; i < irdata_arg_size ; i++) + temp = temp + arg[i + 1]; +#endif + +// data->ir_sum = temp; +// data->ir_freq = arg[0]; + + return 0; +} + +static void ledmatrix_led_power_control(bool led, struct ice5_fpga_data *data) +{ + int err; + + if (led) { + if (power_type == PWR_REG) { + err = regulator_enable(data->regulator); + if (err) + pr_info("%s: fail to turn on regulator\b", __func__); + } else if (power_type == PWR_LDO) { + gpio_set_value(g_pdata->ledmatrix_en, GPIO_LEVEL_HIGH); + } + } else { + if (power_type == PWR_REG) + regulator_disable(data->regulator); + else if (power_type == PWR_LDO) + gpio_set_value(g_pdata->ledmatrix_en, GPIO_LEVEL_LOW); + } +} + +/* start of sysfs code */ +static ssize_t ledmatrix_send_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct ice5_fpga_data *data = dev_get_drvdata(dev); + int tdata, i, count = 0; + + int *arr_data; + int err; + +/* mclk on */ +// clk_prepare_enable(data->clock); + + pr_info("%s : ir_send called with %d\n", __func__, (int)size); + if (!fw_loaded) { + pr_info("%s : firmware is not loaded\n", __func__); + return 1; + } + + /* arr_data will store the decimal data(int) from sysfs(char) */ + /* every arr_data will be split by 2 (EX, 173(dec) will be 0x00(hex) and 0xAD(hex) */ + arr_data = kmalloc((sizeof(int) * (REG_LIMIT/2)), GFP_KERNEL); + if (!arr_data) { + pr_info("%s: fail to alloc\n", __func__); + return size; + } + + ledmatrix_led_power_control(true, data); + + for (i = 0 ; i < (REG_LIMIT/2) ; i++) { + tdata = simple_strtoul(buf++, NULL, 10); +#ifdef DEBUG /* debugging, it will cause lagging */ + pr_info("[%s] %d sysfs value : %x\n", __func__, i, tdata); +#endif + if (tdata < 0) { + pr_info("%s : error at simple_strtoul\n", __func__); + break; + } else if ((tdata == 0) && (i > 10)) { + pr_info("%s : end of sysfs input(%d)\n", __func__, i); + break; + } + + arr_data[count] = tdata; + count++; + + while (tdata > 0) { + buf++; + tdata = tdata / 10; + } + } + + if (count >= (REG_LIMIT/2)) { + pr_info("[%s] OVERFLOW\n", __func__); + goto err_overflow; + } + + pr_info("[%s] string to array size : %d\n", __func__, count); + + err = ice5lp_ledmatrix_set_data(data, arr_data, count); + if (err != 0) + pr_info("FAIL is possible?\n"); + + err = ice5lp_send_data_to_device(data); + if (err != 0 && arr_data[0] > MIN_FREQ) { + pr_info("%s: IR SEND might fail, retry!\n", __func__); + + err = ice5lp_send_data_to_device(data); + if (err != 0) { + pr_info("%s: IR SEND might fail again\n", __func__); + send_success = false; + } else { + send_success = true; + } + } else { + send_success = true; + } + +err_overflow: +// data->ir_freq = 0; +// data->ir_sum = 0; + + kfree(arr_data); + + ledmatrix_led_power_control(false, data); + +/* mclk off */ +// clk_disable_unprepare(data->clock); + + return size; +} + +static ssize_t ledmatrix_send_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ice5_fpga_data *data = dev_get_drvdata(dev); + int i; + char *bufp = buf; + + for (i = 5; i < REG_LIMIT - 1; i++) { + if (data->i2c_block_transfer.data[i] == 0 + && data->i2c_block_transfer.data[i+1] == 0) + break; + else + bufp += sprintf(bufp, "%u,", + data->i2c_block_transfer.data[i]); + } + return strlen(buf); +} + +static DEVICE_ATTR(ledmatrix_send, 0664, ledmatrix_send_show, ledmatrix_send_store); + +/* sysfs node ir_send_result */ +static ssize_t ledmatrix_send_result_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + if (send_success) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t ledmatrix_send_result_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + return size; +} +static DEVICE_ATTR(ledmatrix_send_result, 0664, ledmatrix_send_result_show, ledmatrix_send_result_store); + +/* sysfs node irda_test */ +static ssize_t ledmatrix_test_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int ret; + static int toggle = 0; + struct ice5_fpga_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct { + unsigned char addr; + unsigned char data[IRDA_TEST_CODE_SIZE]; + } i2c_block_transfer; + + + int i; + unsigned char BSR_data[IRDA_TEST_CODE_SIZE] = { + 0x01, // reg 0x00 + 0x00, // reg 0x01 + 0x00, // reg 0x02 + 0x00, // reg 0x03 + 0x01, 0x00, + 0x03, 0x00, + 0x06, 0x3F, + 0x1C, 0x3F, + 0x78, 0x21, + 0x70, 0x21, + 0x18, 0x21, + 0x0C, 0x21, + 0x06, 0x21, + 0x03, 0x21, + 0x01, 0x21, + 0x00, 0x21, + 0xFF, 0xBF, + 0xFF, 0xBF, + 0x18, 0x00, + 0x00, 0x00, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0xFF, 0xFF, + 0x00,0x00, + 0x10,0x10, + 0x38,0x38, + 0x7c,0x7c, + 0x3e,0x3e, + 0xff,0xff, + 0x3e,0x3e, + 0x7c,0x7c, + 0x38,0x38, + 0x10,0x10, + 0x00,0x00, + 0x00,0x00, + 0x00,0x00, + 0x08,0x08, + 0x1c,0x1c, + 0x3e,0x3e, + 0x7c,0x7c, + 0xff,0xff, + 0x7c,0x7c, + 0x3e,0x3e, + 0x1c,0x1c, + 0x08,0x08, + 0x00,0x00, + 0x00,0x00, + }; + +#if defined(DEBUG) + u8 *temp; + + temp = kzalloc(sizeof(u8)*(IRDA_TEST_CODE_SIZE+20), GFP_KERNEL); + if (NULL == temp) + pr_err("Failed to data allocate %s\n", __func__); +#endif + + +// if (gpio_get_value(g_pdata->cdone) != 1) { +// pr_err("%s: cdone fail !!\n", __func__); +// return 1; +// } + pr_info("%s : IRDA test code start\n",__func__); + if (!fw_loaded) { + pr_info("%s : firmware is not loaded\n", __func__); + return 1; + } + +// ir_led_power_control(true, data); + + /* make data for sending */ + for (i = 0; i < IRDA_TEST_CODE_SIZE; i++) + i2c_block_transfer.data[i] = BSR_data[i]; + + switch(toggle) + { + case 0 : i2c_block_transfer.data[0] = 0x01; break; + case 1 : i2c_block_transfer.data[0] = 0x33; break; + case 2 : i2c_block_transfer.data[0] = 0x00; break; + default : i2c_block_transfer.data[0] = 0x01; break; + } + toggle = (toggle+1)%3; + + + /* sending data by I2C */ + i2c_block_transfer.addr = IRDA_TEST_CODE_ADDR; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, + IRDA_TEST_CODE_SIZE+1); + pr_err("%s: ret %d\n", __func__, ret); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, + (unsigned char *) &i2c_block_transfer, IRDA_TEST_CODE_SIZE); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + +#if defined(DEBUG) + ice5lp_ledmatrix_read(client, IRDA_TEST_CODE_ADDR, IRDA_TEST_CODE_SIZE, temp); + + for (i = 0 ; i < IRDA_TEST_CODE_SIZE; i++) + pr_info("[%s] %4d rd %5x, td %5x\n", __func__, i, i2c_block_transfer.data[i], temp[i]); + + ice5lp_ledmatrix_print_gpio_status(); +#endif + mdelay(200); +// ir_led_power_control(false, data); + + return size; +} + +static ssize_t ledmatrix_test_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return strlen(buf); +} + +static DEVICE_ATTR(ledmatrix_test, 0664, ledmatrix_test_show, ledmatrix_test_store); + +/* sysfs irda_version */ +static ssize_t ledmatrix_ver_check_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ice5_fpga_data *data = dev_get_drvdata(dev); + + u8 fw_ver; + ice5lp_ledmatrix_read(data->client, 0x02, 1, &fw_ver); + fw_ver = (fw_ver >> 2) & 0x3; + + return sprintf(buf, "%d\n", fw_ver); +} + +static DEVICE_ATTR(ledmatrix_ver_check, 0664, ledmatrix_ver_check_show, NULL); + +static struct attribute *sec_ledmatrix_attributes[] = { + &dev_attr_ledmatrix_send.attr, + &dev_attr_ledmatrix_send_result.attr, + &dev_attr_ledmatrix_test.attr, + &dev_attr_ledmatrix_ver_check.attr, + NULL, +}; + +static struct attribute_group sec_ledmatrix_attr_group = { + .attrs = sec_ledmatrix_attributes, +}; +/* end of sysfs code */ + +#if defined(CONFIG_OF) +static int of_ice5lp_ledmatrix_dt(struct device *dev, struct ice5lp_ledmatrix_platform_data *pdata, + struct ice5_fpga_data *data) +{ + struct device_node *np_ice5lp_ledmatrix = dev->of_node; +// const char *temp_str; +// int ret; + + if(!np_ice5lp_ledmatrix) + return -EINVAL; + + pdata->creset_0 = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,creset_0", 0); + pdata->creset_1 = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,creset_1", 0); + pdata->fpga_reset = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,fpga_reset", 0); + pdata->spi_si_sda = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,spi_si_sda", 0); + pdata->spi_clk_scl = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,spi_clk_scl", 0); + + pdata->ledmatrix_en = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,ledmatrix_en", 0); + +#if 0 + ret = of_property_read_string(np_ice5lp_ledmatrix, "clock-names", &temp_str); + if (ret) { + pr_err("%s: cannot get clock name(%d)", __func__, ret); + return ret; + } + pr_info("%s: %s\n", __func__, temp_str); + + data->clock = devm_clk_get(dev, temp_str); + if (IS_ERR(data->clock)) { + pr_err("%s: cannot get clock(%d)", __func__, ret); + return ret; + } + + ret = of_property_read_string(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,power", &temp_str); + if (ret) { + pr_err("%s: cannot get power type(%d)", __func__, ret); + return ret; + } + + if (!strncasecmp(temp_str, "LDO", 3)) { + pr_info("%s: ice5lp_ledmatrix will use %s\n", __func__, temp_str); + power_type = PWR_LDO; + pdata->ir_en = of_get_named_gpio(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,ir_en", 0); + } else if (!strncasecmp(temp_str, "REG", 3)) { + pr_info("%s: ice5lp_ledmatrix will use regulator\n", __func__); + power_type = PWR_REG; + ret = of_property_read_string(np_ice5lp_ledmatrix, "ice5lp_ledmatrix,regulator_name", + &temp_str); + if (ret) { + pr_err("%s: cannot get regulator_name!(%d)\n", + __func__, ret); + return ret; + } + data->regulator_name = (char *)temp_str; + } else if (!strncasecmp(temp_str, "ALW", 3)) { + pr_info("%s: ice5lp_ledmatrix power control(%s)\n", __func__, temp_str); + power_type = PWR_ALW; + } else { + pr_err("%s: unused power type(%s)\n", __func__, temp_str); + return -EINVAL; + } +#endif + return 0; +} +#else +static int of_ice5lp_ledmatrix_dt(struct device *dev, struct ice5lp_ledmatrix_platform_data *pdata) +{ + return -ENODEV; +} +#endif /* CONFIG_OF */ +#if 0 +static int ice5lp_ledmatrix_gpio_setting(void) +{ + int ret = 0; + + ret = gpio_request_one(g_pdata->creset_b, GPIOF_OUT_INIT_HIGH, "FPGA_CRESET_B"); + ret += gpio_request_one(g_pdata->cdone, GPIOF_IN, "FPGA_CDONE"); + ret += gpio_request_one(g_pdata->irda_irq, GPIOF_IN, "FPGA_IRDA_IRQ"); + ret += gpio_request_one(g_pdata->spi_en_rstn, GPIOF_OUT_INIT_LOW, "FPGA_SPI_EN"); + + if (power_type == PWR_LDO) + ret += gpio_request_one(g_pdata->ir_en, GPIOF_OUT_INIT_LOW, "FPGA_IR_EN"); + +/* i2c-gpio drv already request below pins */ + gpio_free(g_pdata->spi_si_sda); + gpio_free(g_pdata->spi_clk_scl); + ret += gpio_request_one(g_pdata->spi_si_sda, GPIOF_OUT_INIT_LOW, "FPGA_SPI_SI_SDA"); + ret += gpio_request_one(g_pdata->spi_clk_scl, GPIOF_OUT_INIT_LOW, "FPGA_SPI_CLK_SCL"); + + return ret; +} +#endif +static int __devinit ice5lp_ledmatrix_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct ice5_fpga_data *data; + struct ice5lp_ledmatrix_platform_data *pdata; + struct device *ice5lp_ledmatrix_dev; + int error = 0; + + pr_info("%s probe!\n", __func__); + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + data = kzalloc(sizeof(struct ice5_fpga_data), GFP_KERNEL); + if (NULL == data) { + pr_err("Failed to data allocate %s\n", __func__); + error = -ENOMEM; + goto alloc_fail; + } + + if (client->dev.of_node) { + pdata = devm_kzalloc(&client->dev, + sizeof(struct ice5lp_ledmatrix_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&client->dev, "Failed to allocate memory\n"); + error = -ENOMEM; + goto platform_data_fail; + } + error = of_ice5lp_ledmatrix_dt(&client->dev, pdata, data); + if (error) + goto platform_data_fail; + } + else + pdata = client->dev.platform_data; + + g_pdata = pdata; + + pr_info("%s : creset_0 : %d\n", __func__, g_pdata->creset_0); + pr_info("%s : creset_1 : %d\n", __func__, g_pdata->creset_1); + pr_info("%s : fpga_reset : %d\n", __func__, g_pdata->fpga_reset); + pr_info("%s : spi_si_sda : %d\n", __func__, g_pdata->spi_si_sda); + pr_info("%s : spi_clk_scl : %d\n", __func__, g_pdata->spi_clk_scl); + pr_info("%s : ledmatrix_en : %d\n", __func__, g_pdata->ledmatrix_en); + + if(gpio_request_one(pdata->ledmatrix_en, GPIOF_OUT_INIT_LOW, "ledmatrix_en")){ + pr_err("%s: cannot request ledmatrix_en", __func__); + }else { + pr_info("%s : power on before ledmatrix_en : %d\n", __func__, gpio_get_value(g_pdata->ledmatrix_en)); + gpio_set_value(g_pdata->ledmatrix_en, GPIO_LEVEL_HIGH); + pr_info("%s : power on ledmatrix_en : %d\n", __func__, gpio_get_value(g_pdata->ledmatrix_en)); + } + +#if 0 + error = ice5lp_ledmatrix_gpio_setting(); + if (error) + goto platform_data_fail; + + if (ice5_check_cdone()) { + fw_loaded = 1; + pr_info("FPGA FW is loaded!\n"); + } else { + fw_loaded = 0; + pr_info("FPGA FW is NOT loaded!\n"); + } +#endif + data->client = client; + mutex_init(&data->mutex); + + i2c_set_clientdata(client, data); + + /* slave address */ + client->addr = 0x50; + + if (power_type == PWR_REG) { + data->regulator = regulator_get(NULL, data->regulator_name); + if (IS_ERR(data->regulator)) { + pr_info("%s Failed to get regulator.\n", __func__); + error = IS_ERR(data->regulator); + goto platform_data_fail; + } + } + + ice5lp_ledmatrix_dev = sec_device_create(data, "sec_ledmatrix"); + if (IS_ERR(ice5lp_ledmatrix_dev)) + pr_err("Failed to create ice5lp_ledmatrix_dev in sec_ir\n"); + + if (sysfs_create_group(&ice5lp_ledmatrix_dev->kobj, &sec_ledmatrix_attr_group) < 0) { + sec_device_destroy(ice5lp_ledmatrix_dev->devt); + pr_err("Failed to create sysfs group for samsung ir!\n"); + } + + /* Create dedicated thread so that the delay of our work does not affect others */ + data->firmware_dl = + create_singlethread_workqueue("ice5lp_ledmatrix_firmware_dl"); + INIT_DELAYED_WORK(&data->fw_dl, ice5lp_fw_update); + + /* min 1ms is needed */ + queue_delayed_work(data->firmware_dl, + &data->fw_dl, msecs_to_jiffies(20)); + + pr_info("%s : %s %s:\n", __func__, + dev_driver_string(&client->dev), dev_name(&client->dev)); + + return 0; + +platform_data_fail: + kfree(data); +alloc_fail: + return error; +} + +static int __devexit ice5lp_ledmatrix_remove(struct i2c_client *client) +{ + struct ice5_fpga_data *data = i2c_get_clientdata(client); + + i2c_set_clientdata(client, NULL); + kfree(data); + return 0; +} + +#ifdef CONFIG_PM +static int ice5lp_ledmatrix_suspend(struct device *dev) +{ + //gpio_set_value(g_pdata->spi_en_rstn, GPIO_LEVEL_LOW); + return 0; +} + +static int ice5lp_ledmatrix_resume(struct device *dev) +{ + //gpio_set_value(g_pdata->spi_en_rstn, GPIO_LEVEL_HIGH); + return 0; +} + +static const struct dev_pm_ops ice5lp_ledmatrix_pm_ops = { + .suspend = ice5lp_ledmatrix_suspend, + .resume = ice5lp_ledmatrix_resume, +}; +#endif + +static const struct i2c_device_id ice5_id[] = { + {"ice5", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ice5_id); + + +#if defined(CONFIG_OF) +static struct of_device_id ice5lp_ledmatrix_match_table[] = { + { .compatible = "lattice,ice5lp_ledmatrix",}, + {}, +}; +#else +#define ice5lp_ledmatrix_match_table NULL +#endif + +static struct i2c_driver ice5_i2c_driver = { + .driver = { + .name = "ice5", + .of_match_table = ice5lp_ledmatrix_match_table, +#ifdef CONFIG_PM + .pm = &ice5lp_ledmatrix_pm_ops, +#endif + }, + .probe = ice5lp_ledmatrix_probe, + .remove = __devexit_p(ice5lp_ledmatrix_remove), + .id_table = ice5_id, +}; + +static int __init ice5lp_ledmatrix_init(void) +{ + return i2c_add_driver(&ice5_i2c_driver); +} +late_initcall(ice5lp_ledmatrix_init); + +static void __exit ice5lp_ledmatrix_exit(void) +{ + i2c_del_driver(&ice5_i2c_driver); +} +module_exit(ice5lp_ledmatrix_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ICE5LP LEDMATRIX FPGA FOR IRDA"); diff --git a/drivers/ledmatrix/ice5lp_ledmatrix_fw.h b/drivers/ledmatrix/ice5lp_ledmatrix_fw.h new file mode 100644 index 000000000000..cc6409a832c3 --- /dev/null +++ b/drivers/ledmatrix/ice5lp_ledmatrix_fw.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* FIRMWARE VERSION : 22 72 */ +/* TARGET NAME : K3G / KQ */ +/* CHIP : 640 */ +#ifndef _ICE5LP_LEDMATRIX_FW_H_ +#define _ICE5LP_LEDMATRIX_FW_H_ + +#define GPIO_LEVEL_LOW 0 +#define GPIO_LEVEL_HIGH 1 +#define GPIO_LEVEL_NONE 2 + +static int ice5lp_check_fwdone(void); + +#define IR_IOCTL_BASE 'I' +#define IR_IOCTL_SET_FREQ _IOW(IR_IOCTL_BASE, 1, int) +#define IR_IOCTL_SET_SIZE _IOW(IR_IOCTL_BASE, 2, int) +#define IR_IOCTL_SET_DATA _IOW(IR_IOCTL_BASE, 3, int*) +#define IR_IOCTL_START _IO(IR_IOCTL_BASE, 4) +#define IR_IOCTL_STOP _IO(IR_IOCTL_BASE, 5) + +#endif /* _ICE5LP_LEDMATRIX_FW_H_ */ diff --git a/drivers/leds/leds-max77833-rgb.c b/drivers/leds/leds-max77833-rgb.c index d8d8531f3d90..ed8d1880ba12 100644 --- a/drivers/leds/leds-max77833-rgb.c +++ b/drivers/leds/leds-max77833-rgb.c @@ -82,9 +82,20 @@ (time < 8000) ? (time-5000)/1000+10 : \ (time < 12000) ? (time-8000)/2000+13 : 15) +extern unsigned int lcdtype; + static u8 led_dynamic_current = 0x14; +static u8 normal_powermode_current = 0x14; +static u8 low_powermode_current = 0x05; + +static unsigned int device_type = 0; +static unsigned int brightness_ratio_r = 100; +static unsigned int brightness_ratio_g = 100; +static unsigned int brightness_ratio_b = 100; static u8 led_lowpower_mode = 0x0; +static unsigned int octa_color = 0x0; + enum max77833_led_color { WHITE, RED, @@ -111,7 +122,6 @@ struct max77833_rgb { }; #if defined(CONFIG_LEDS_USE_ED28) && defined(CONFIG_SEC_FACTORY) -extern unsigned int lcdtype; extern bool jig_status; #endif @@ -163,8 +173,6 @@ static void max77833_rgb_set(struct led_classdev *led_cdev, } } else { /* Set current */ - if (n==BLUE) - brightness = (brightness * 5) / 2; ret = max77833_write_reg(max77833_rgb->i2c, MAX77833_RGBLED_REG_LED0BRT + n, brightness); if (IS_ERR_VALUE(ret)) { @@ -203,8 +211,34 @@ static void max77833_rgb_set_state(struct led_classdev *led_cdev, dev = led_cdev->dev; n = ret; + if(brightness != 0) { + /* apply brightness ratio for optimize each led brightness*/ + switch(n) { + case RED: + brightness = brightness * brightness_ratio_r / 100; + break; + case GREEN: + brightness = brightness * brightness_ratio_g / 100; + break; + case BLUE: + brightness = brightness * brightness_ratio_b / 100; + break; + } + + /* + There is possibility that low_powermode_current is 0. + ex) low_powermode_current is 1 & brightness_ratio_r is 90 + brightness = 1 * 90 / 100 = 0.9 + brightness is inteager, so brightness is 0. + In this case, it is need to assign 1 of value. + */ + if(brightness == 0) + brightness = 1; + } max77833_rgb_set(led_cdev, brightness); + pr_info("leds-max77833-rgb: %s, led_num = %d, brightness = %d\n", __func__, ret, brightness); + ret = max77833_update_reg(max77833_rgb->i2c, MAX77833_RGBLED_REG_LEDEN, led_state << (2*n), 0x3 << 2*n); if (IS_ERR_VALUE(ret)) { @@ -297,16 +331,12 @@ static int max77833_rgb_blink(struct device *dev, pr_info("leds-max77833-rgb: %s\n", __func__); - if( delay_on > 3250 || delay_off > 12000 ) + value = (LEDBLNK_ON(delay_on) << 4) | LEDBLNK_OFF(delay_off); + ret = max77833_write_reg(max77833_rgb->i2c, + MAX77833_RGBLED_REG_LEDBLNK, value); + if (IS_ERR_VALUE(ret)) { + dev_err(dev, "can't write REG_LEDBLNK : %d\n", ret); return -EINVAL; - else { - value = (LEDBLNK_ON(delay_on) << 4) | LEDBLNK_OFF(delay_off); - ret = max77833_write_reg(max77833_rgb->i2c, - MAX77833_RGBLED_REG_LEDBLNK, value); - if (IS_ERR_VALUE(ret)) { - dev_err(dev, "can't write REG_LEDBLNK : %d\n", ret); - return -EINVAL; - } } return ret; @@ -321,6 +351,13 @@ static struct max77833_rgb_platform_data struct device_node *np; int ret; int i; + int temp; + char octa[4] = {0, }; + char br_ratio_r[23] = "br_ratio_r"; + char br_ratio_g[23] = "br_ratio_g"; + char br_ratio_b[23] = "br_ratio_b"; + char normal_po_cur[29] = "normal_powermode_current"; + char low_po_cur[26] = "low_powermode_current"; pr_info("leds-max77833-rgb: %s\n", __func__); @@ -347,6 +384,118 @@ static struct max77833_rgb_platform_data } } + /* get device_type value in dt */ + ret = of_property_read_u32(np, "device_type", &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing device_type in dt\n", __func__); + } + else { + device_type = (u8)temp; + } + pr_info("leds-max77833-rgb: %s, device_type = %x\n", __func__, device_type); + + /* ZERO */ + if(device_type == 0) { + pr_info("here0\n"); + + switch(octa_color) { + case 0: + strcpy(octa, "_bk"); + break; + case 2: + strcpy(octa, "_wh"); + break; + case 3: + strcpy(octa, "_gd"); + break; + case 4: + strcpy(octa, "_gr"); + break; + case 5: + strcpy(octa, "_rd"); + break; + default: + break; + } + } + /* ZEROF */ + else if(device_type == 1) { + pr_info("here1\n"); + + switch(octa_color) { + case 0: + strcpy(octa, "_bk"); + break; + case 1: + strcpy(octa, "_wh"); + break; + case 2: + strcpy(octa, "_gd"); + break; + case 3: + strcpy(octa, "_bl"); + break; + case 4: + strcpy(octa, "_rd"); + break; + default: + break; + } + } + strcat(normal_po_cur, octa); + strcat(low_po_cur, octa); + strcat(br_ratio_r, octa); + strcat(br_ratio_g, octa); + strcat(br_ratio_b, octa); + + /* get normal_powermode_current value in dt */ + ret = of_property_read_u32(np, normal_po_cur, &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing normal_powermode_current in dt\n", __func__); + } + else { + normal_powermode_current = (u8)temp; + } + pr_info("leds-max77833-rgb: %s, normal_powermode_current = %x\n", __func__, normal_powermode_current); + + /* get low_powermode_current value in dt */ + ret = of_property_read_u32(np, low_po_cur, &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing low_powermode_current in dt\n", __func__); + } + else + low_powermode_current = (u8)temp; + pr_info("leds-max77833-rgb: %s, low_powermode_current = %x\n", __func__, low_powermode_current); + + /* get led red brightness ratio */ + ret = of_property_read_u32(np, br_ratio_r, &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing brightness_ratio_r in dt\n", __func__); + } + else { + brightness_ratio_r = (int)temp; + } + pr_info("leds-max77833-rgb: %s, brightness_ratio_r = %x\n", __func__, brightness_ratio_r); + + /* get led green brightness ratio */ + ret = of_property_read_u32(np, br_ratio_g, &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing brightness_ratio_g in dt\n", __func__); + } + else { + brightness_ratio_g = (int)temp; + } + pr_info("leds-max77833-rgb: %s, brightness_ratio_g = %x\n", __func__, brightness_ratio_g); + + /* get led blue brightness ratio */ + ret = of_property_read_u32(np, br_ratio_b, &temp); + if (IS_ERR_VALUE(ret)) { + pr_info("leds-max77833-rgb: %s, can't parsing brightness_ratio_b in dt\n", __func__); + } + else { + brightness_ratio_b = (int)temp; + } + pr_info("leds-max77833-rgb: %s, brightness_ratio_b = %x\n", __func__, brightness_ratio_b); return pdata; } #endif @@ -427,9 +576,9 @@ static ssize_t store_max77833_rgb_pattern(struct device *dev, /* Set to low power consumption mode */ if (led_lowpower_mode == 1) - led_dynamic_current = 0x5; + led_dynamic_current = low_powermode_current; else - led_dynamic_current = 0x14; + led_dynamic_current = normal_powermode_current; switch (mode) { @@ -477,6 +626,8 @@ static ssize_t store_max77833_rgb_blink(struct device *dev, u8 led_r_brightness = 0; u8 led_g_brightness = 0; u8 led_b_brightness = 0; + unsigned int led_total_br = 0; + unsigned int led_max_br = 0; int ret; ret = sscanf(buf, "0x%8x %5d %5d", &led_brightness, @@ -486,6 +637,8 @@ static ssize_t store_max77833_rgb_blink(struct device *dev, return count; } + /* Set to low power consumption mode */ + led_dynamic_current = normal_powermode_current; /*Reset led*/ max77833_rgb_reset(dev); @@ -493,11 +646,79 @@ static ssize_t store_max77833_rgb_blink(struct device *dev, led_g_brightness = (led_brightness & LED_G_MASK) >> 8; led_b_brightness = led_brightness & LED_B_MASK; - /* In user case, LED current is restricted to less than 2mA */ - led_r_brightness = (led_r_brightness * led_dynamic_current) / LED_MAX_CURRENT; - led_g_brightness = (led_g_brightness * led_dynamic_current) / LED_MAX_CURRENT; - led_b_brightness = (led_b_brightness * led_dynamic_current) / LED_MAX_CURRENT; + /* In user case, LED current is restricted to less than tuning value */ + if (led_r_brightness != 0) { + led_r_brightness = (led_r_brightness * led_dynamic_current) / LED_MAX_CURRENT; + if (led_r_brightness == 0) + led_r_brightness = 1; + } + if (led_g_brightness != 0) { + led_g_brightness = (led_g_brightness * led_dynamic_current) / LED_MAX_CURRENT; + if (led_g_brightness == 0) + led_g_brightness = 1; + } + if (led_b_brightness != 0) { + led_b_brightness = (led_b_brightness * led_dynamic_current) / LED_MAX_CURRENT; + if (led_b_brightness == 0) + led_b_brightness = 1; + } + + led_total_br += led_r_brightness * brightness_ratio_r / 100; + led_total_br += led_g_brightness * brightness_ratio_g / 100; + led_total_br += led_b_brightness * brightness_ratio_b / 100; + + if (brightness_ratio_r >= brightness_ratio_g && + brightness_ratio_r >= brightness_ratio_b) { + led_max_br = normal_powermode_current * brightness_ratio_r / 100; + } else if (brightness_ratio_g >= brightness_ratio_r && + brightness_ratio_g >= brightness_ratio_b) { + led_max_br = normal_powermode_current * brightness_ratio_g / 100; + } else if (brightness_ratio_b >= brightness_ratio_r && + brightness_ratio_b >= brightness_ratio_g) { + led_max_br = normal_powermode_current * brightness_ratio_b / 100; + } + /* Each color decreases according to the limit at the same rate. */ + if(device_type == 1 && octa_color == 1) { + /* There is current consumption problem. + So, add workaround code in the case of zerof white octa device */ + if (led_total_br > led_max_br) { + if (led_r_brightness != 0) { + led_r_brightness = led_r_brightness * led_max_br / led_total_br * 8 / 10; + if (led_r_brightness == 0) + led_r_brightness = 1; + } + if (led_g_brightness != 0) { + led_g_brightness = led_g_brightness * led_max_br / led_total_br * 8 / 10; + if (led_g_brightness == 0) + led_g_brightness = 1; + } + if (led_b_brightness != 0) { + led_b_brightness = led_b_brightness * led_max_br / led_total_br; + if (led_b_brightness == 0) + led_b_brightness = 1; + } + } + } + else { + if (led_total_br > led_max_br) { + if (led_r_brightness != 0) { + led_r_brightness = led_r_brightness * led_max_br / led_total_br; + if (led_r_brightness == 0) + led_r_brightness = 1; + } + if (led_g_brightness != 0) { + led_g_brightness = led_g_brightness * led_max_br / led_total_br; + if (led_g_brightness == 0) + led_g_brightness = 1; + } + if (led_b_brightness != 0) { + led_b_brightness = led_b_brightness * led_max_br / led_total_br; + if (led_b_brightness == 0) + led_b_brightness = 1; + } + } + } if (led_r_brightness) { max77833_rgb_set_state(&max77833_rgb->led[RED], led_r_brightness, LED_BLINK); } @@ -510,7 +731,7 @@ static ssize_t store_max77833_rgb_blink(struct device *dev, /*Set LED blink mode*/ max77833_rgb_blink(dev, delay_on_time, delay_off_time); - pr_info("leds-max77833-rgb: %s\n", __func__); + pr_info("leds-max77833-rgb: %s, delay_on_time= %x, delay_off_time= %x\n", __func__, delay_on_time, delay_off_time); dev_dbg(dev, "led_blink is called, Color:0x%X Brightness:%i\n", led_brightness, led_dynamic_current); return count; @@ -522,14 +743,9 @@ static ssize_t store_led_r(struct device *dev, { struct max77833_rgb *max77833_rgb = dev_get_drvdata(dev); unsigned int brightness; - char buff[10] = {0,}; - int cnt, ret; - - cnt = count; - cnt = (buf[cnt-1] == '\n') ? cnt-1 : cnt; - memcpy(buff, buf, cnt); - buff[cnt] = '\0'; - ret = kstrtouint(buff, 0, &brightness); + int ret; + + ret = kstrtouint(buf, 0, &brightness); if (ret != 0) { dev_err(dev, "fail to get brightness.\n"); goto out; @@ -549,14 +765,9 @@ static ssize_t store_led_g(struct device *dev, { struct max77833_rgb *max77833_rgb = dev_get_drvdata(dev); unsigned int brightness; - char buff[10] = {0,}; - int cnt, ret; - - cnt = count; - cnt = (buf[cnt-1] == '\n') ? cnt-1 : cnt; - memcpy(buff, buf, cnt); - buff[cnt] = '\0'; - ret = kstrtouint(buff, 0, &brightness); + int ret; + + ret = kstrtouint(buf, 0, &brightness); if (ret != 0) { dev_err(dev, "fail to get brightness.\n"); goto out; @@ -576,14 +787,9 @@ static ssize_t store_led_b(struct device *dev, { struct max77833_rgb *max77833_rgb = dev_get_drvdata(dev); unsigned int brightness; - char buff[10] = {0,}; - int cnt, ret; - - cnt = count; - cnt = (buf[cnt-1] == '\n') ? cnt-1 : cnt; - memcpy(buff, buf, cnt); - buff[cnt] = '\0'; - ret = kstrtouint(buff, 0, &brightness); + int ret; + + ret = kstrtouint(buf, 0, &brightness); if (ret != 0) { dev_err(dev, "fail to get brightness.\n"); goto out; @@ -739,14 +945,19 @@ static int max77833_rgb_probe(struct platform_device *pdev) pr_info("leds-max77833-rgb: %s\n", __func__); + octa_color = (lcdtype >> 16) & 0x0000000f; #ifdef CONFIG_OF pdata = max77833_rgb_parse_dt(dev); if (unlikely(IS_ERR(pdata))) return PTR_ERR(pdata); + + led_dynamic_current = normal_powermode_current; #else pdata = dev_get_platdata(dev); #endif + pr_info("leds-max77833-rgb: %s : lcdtype=%d, octa_color=%x device_type=%x \n", + __func__, lcdtype, octa_color, device_type); max77833_rgb = devm_kzalloc(dev, sizeof(struct max77833_rgb), GFP_KERNEL); if (unlikely(!max77833_rgb)) return -ENOMEM; diff --git a/drivers/leds/leds-s2mpb02.c b/drivers/leds/leds-s2mpb02.c index ae53a8cafb36..9665229d1dee 100644 --- a/drivers/leds/leds-s2mpb02.c +++ b/drivers/leds/leds-s2mpb02.c @@ -26,7 +26,6 @@ extern struct class *camera_class; /*sys/class/camera*/ struct device *s2mpb02_led_dev; struct s2mpb02_led_data *global_led_datas[S2MPB02_LED_MAX]; -bool torch_step_adjust = false; struct s2mpb02_led_data { struct led_classdev led; @@ -88,6 +87,7 @@ static int s2mpb02_led_get_en_value(struct s2mpb02_led_data *led_data, int on) static void s2mpb02_led_set(struct led_classdev *led_cdev, enum led_brightness value) { +#if 0 /* disable LED control by other sysfs */ unsigned long flags; struct s2mpb02_led_data *led_data = container_of(led_cdev, struct s2mpb02_led_data, led); @@ -99,6 +99,7 @@ static void s2mpb02_led_set(struct led_classdev *led_cdev, spin_unlock_irqrestore(&led_data->value_lock, flags); schedule_work(&led_data->work); +#endif } static void led_set(struct s2mpb02_led_data *led_data) @@ -121,19 +122,18 @@ static void led_set(struct s2mpb02_led_data *led_data) if (unlikely(ret)) goto error_set_bits; } else { + /* set current */ + ret = s2mpb02_set_bits(led_data->i2c, S2MPB02_REG_FLED_CUR1, + leds_mask[id], data->brightness << leds_shift[id]); + if (unlikely(ret)) + goto error_set_bits; - /* set current */ - ret = s2mpb02_set_bits(led_data->i2c, S2MPB02_REG_FLED_CUR1, - leds_mask[id], data->brightness << leds_shift[id]); - if (unlikely(ret)) - goto error_set_bits; - - /* Turn on LED by I2C */ - value = s2mpb02_led_get_en_value(led_data, 1); - ret = s2mpb02_set_bits(led_data->i2c, - S2MPB02_REG_FLED_CTRL1, S2MPB02_FLED_ENABLE_MODE_MASK, value); - if (unlikely(ret)) - goto error_set_bits; + /* Turn on LED by I2C */ + value = s2mpb02_led_get_en_value(led_data, 1); + ret = s2mpb02_set_bits(led_data->i2c, + S2MPB02_REG_FLED_CTRL1, S2MPB02_FLED_ENABLE_MODE_MASK, value); + if (unlikely(ret)) + goto error_set_bits; } return; @@ -202,6 +202,30 @@ void s2mpb02_led_get_status(struct led_classdev *led_cdev, bool status, bool ono __func__, status, onoff, value[0], value[1], value[2], value[3], value[4], value[5]); } +#ifdef CONFIG_TORCH_CURRENT_CHANGE_SUPPORT +int s2mpb02_set_torch_current(bool torch_mode) +{ + struct s2mpb02_led_data *led_data = global_led_datas[S2MPB02_TORCH_LED_1]; + struct s2mpb02_led *data = led_data->data; + int ret = 0; + + pr_info("%s: torch_mode %d\n", __func__, torch_mode); + mutex_lock(&led_data->lock); + + data->brightness = torch_mode ? S2MPB02_TORCH_OUT_I_60MA : original_brightness; + + /* set current */ + ret = s2mpb02_set_bits(led_data->i2c, S2MPB02_REG_FLED_CUR1, + leds_mask[data->id], data->brightness << leds_shift[data->id]); + if (unlikely(ret)) { + pr_err("%s: failed to set FLED_CUR1, %d\n", __func__, ret); + } + + mutex_unlock(&led_data->lock); + return ret; +} +#endif + ssize_t s2mpb02_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -218,39 +242,26 @@ ssize_t s2mpb02_store(struct device *dev, } pr_info("[LED]%s , value:%d\n", __func__, value); - - if(torch_step_adjust) { - if (value == 0) { - /* Turn off Torch */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = LED_OFF; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else if (1 <= value && value <= 10) { - /* Turn on Torch Step 20mA ~ 200mA */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = value; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else if (value == 100) { - /* Factory mode Turn on Torch */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = S2MPB02_TORCH_OUT_I_240MA; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else { - pr_info("[LED]%s , Invalid value:%d\n", __func__, value); - } + mutex_lock(&global_led_datas[S2MPB02_TORCH_LED_1]->lock); + + if (value == 0) { + /* Turn off Torch */ + global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = LED_OFF; + led_set(global_led_datas[S2MPB02_TORCH_LED_1]); + } else if (value == 1) { + /* Turn on Torch */ + global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = S2MPB02_TORCH_OUT_I_60MA; + led_set(global_led_datas[S2MPB02_TORCH_LED_1]); + } else if (value == 100) { + /* Factory mode Turn on Torch */ + global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = S2MPB02_TORCH_OUT_I_240MA; + led_set(global_led_datas[S2MPB02_TORCH_LED_1]); + } else if (1001 <= value && value <= 1010) { + /* Turn on Torch Step 20mA ~ 200mA */ + global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = value - 1000; + led_set(global_led_datas[S2MPB02_TORCH_LED_1]); } else { - if (value == 0) { - /* Turn off Torch */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = LED_OFF; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else if (value == 1) { - /* Turn on Torch */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = S2MPB02_TORCH_OUT_I_60MA; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else if (value == 100) { - /* Factory mode Turn on Torch */ - global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = S2MPB02_TORCH_OUT_I_240MA; - led_set(global_led_datas[S2MPB02_TORCH_LED_1]); - } else { - pr_info("[LED]%s , Invalid value:%d\n", __func__, value); - } + pr_info("[LED]%s , Invalid value:%d\n", __func__, value); } if (value <= 0) { @@ -260,6 +271,7 @@ ssize_t s2mpb02_store(struct device *dev, global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = original_brightness; } + mutex_unlock(&global_led_datas[S2MPB02_TORCH_LED_1]->lock); return count; } @@ -302,7 +314,6 @@ static int of_s2mpb02_torch_dt(struct s2mpb02_dev *iodev, } pdata->num_leds = of_get_child_count(np); - torch_step_adjust = of_property_read_bool(np, "torch_step_adjust"); for_each_child_of_node(np, c_np) { ret = of_property_read_u32(c_np, "id", &temp); @@ -503,12 +514,19 @@ static int s2mpb02_led_remove(struct platform_device *pdev) return 0; } +static void s2mpb02_led_shutdown(struct device *dev) +{ + global_led_datas[S2MPB02_TORCH_LED_1]->data->brightness = LED_OFF; + led_set(global_led_datas[S2MPB02_TORCH_LED_1]); +} + static struct platform_driver s2mpb02_led_driver = { .probe = s2mpb02_led_probe, .remove = s2mpb02_led_remove, .driver = { .name = "s2mpb02-led", .owner = THIS_MODULE, + .shutdown = s2mpb02_led_shutdown, }, }; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 2dbe252031d1..bc2862a9e093 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -33,6 +33,10 @@ #define DM_MSG_PREFIX "crypt" #define FMP_KEY_STORAGE_OFFSET 0x0FC0 +#if defined(CONFIG_FIPS_FMP) +extern bool in_fmp_fips_err(void); +#endif + /* * context holding the current state of a multi-part conversion */ @@ -1514,6 +1518,13 @@ static int crypt_ctr_cipher(struct dm_target *ti, ti->error = "Error decoding xts-aes-fmp"; ret = -EINVAL; goto bad; +#endif +#if defined(CONFIG_FIPS_FMP) + if (unlikely(in_fmp_fips_err())) { + ti->error = "Error to work fmp due to fips in error"; + ret = -EPERM; + goto bad; + } #endif cc->hw_fmp = 1; diff --git a/drivers/media/isdbt/fc8180_spi/fc8180_bb.c b/drivers/media/isdbt/fc8180_spi/fc8180_bb.c index c3cf964fdd61..e97bedc2fa97 100644 --- a/drivers/media/isdbt/fc8180_spi/fc8180_bb.c +++ b/drivers/media/isdbt/fc8180_spi/fc8180_bb.c @@ -699,7 +699,7 @@ s32 fc8180_init(HANDLE handle) (BBM_I2C_SPI_POL)); #endif - bbm_write(handle, BBM_INT_AUTO_CLEAR, 0x01); + bbm_write(handle, BBM_INT_AUTO_CLEAR, 0x00); bbm_write(handle, BBM_BUF_ENABLE, 0x01); bbm_write(handle, BBM_BUF_INT, 0x01); bbm_write(handle, BBM_INT_MASK, 0x07); diff --git a/drivers/media/isdbt/fc8180_spi/fc8180_isr.c b/drivers/media/isdbt/fc8180_spi/fc8180_isr.c index 0995c7f746b8..6803bfa75507 100644 --- a/drivers/media/isdbt/fc8180_spi/fc8180_isr.c +++ b/drivers/media/isdbt/fc8180_spi/fc8180_isr.c @@ -25,6 +25,7 @@ #include "fci_types.h" #include "fc8180_regs.h" #include "fci_hal.h" +#include "fci_oal.h" s32 (*fc8180_ac_callback)(ulong userdata, u8 *data, s32 length) = NULL; s32 (*fc8180_ts_callback)(ulong userdata, u8 *data, s32 length) = NULL; @@ -44,6 +45,10 @@ static void fc8180_data(HANDLE handle, u8 buf_int_status) bbm_word_read(handle, BBM_BUF_TS_THR, &size); size += 1; + if (size > (TS_BUF_SIZE / 2)) + print_log(0, "[FC8180] Data Size error [%d]\n", size); + + size = (TS_BUF_SIZE / 2); bbm_data(handle, BBM_TS_DATA, &ts_buf[0], size); if (fc8180_ts_callback) @@ -96,6 +101,7 @@ void fc8180_isr(HANDLE handle) #ifndef BBM_I2C_TSIF u8 buf_int_status = 0; + u8 int_status = 0; bbm_read(handle, BBM_BUF_STATUS, &buf_int_status); if (buf_int_status) { bbm_write(handle, BBM_BUF_STATUS, buf_int_status); @@ -109,6 +115,10 @@ void fc8180_isr(HANDLE handle) bbm_write(handle, BBM_BUF_STATUS, buf_int_status); fc8180_data(handle, buf_int_status); } + + bbm_read(handle, BBM_INT_STATUS, &int_status); + if (int_status) + bbm_write(handle, BBM_INT_STATUS, int_status); #endif #ifdef BBM_AUX_INT diff --git a/drivers/media/isdbt/fc8300_spi/fc8300.c b/drivers/media/isdbt/fc8300_spi/fc8300.c index 904cd8194ebb..ce21e94409d4 100644 --- a/drivers/media/isdbt/fc8300_spi/fc8300.c +++ b/drivers/media/isdbt/fc8300_spi/fc8300.c @@ -1217,7 +1217,7 @@ static struct isdbt_platform_data *isdbt_populate_dt_pdata(struct device *dev) pr_err("%s : isdbt-detect-gpio gpio_int =%d\n", __func__, pdata->gpio_int); } #endif - +#if defined(BBM_I2C_SPI) || defined(BBM_I2C_TSIF) pdata->gpio_i2c_sda = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-i2c_sda", 0); if (pdata->gpio_i2c_sda < 0) of_property_read_u32(dev->of_node, "isdbt,isdb-gpio-i2c_sda", &pdata->gpio_i2c_sda); @@ -1237,7 +1237,7 @@ static struct isdbt_platform_data *isdbt_populate_dt_pdata(struct device *dev) } else { pr_err("%s : isdbt-detect-gpio gpio_i2c_scl=%d\n", __func__, pdata->gpio_i2c_scl); } - +#endif pdata->gpio_spi_do = of_get_named_gpio(dev->of_node, "isdbt,isdb-gpio-spi_do", 0); if (pdata->gpio_spi_do < 0) { pr_err("%s : can not find the isdbt-detect-gpio in the gpio_spi_do dt\n", __func__); diff --git a/drivers/media/isdbt/fc8300_spi/fc8300_spi.c b/drivers/media/isdbt/fc8300_spi/fc8300_spi.c index 1a5d7f58299b..4543eb815dd6 100644 --- a/drivers/media/isdbt/fc8300_spi/fc8300_spi.c +++ b/drivers/media/isdbt/fc8300_spi/fc8300_spi.c @@ -38,10 +38,11 @@ #define SPI_AINC 0x80 #define DRIVER_NAME "fc8300_spi" +#define TX_DATA_SIZE 36 /* header(4)+PID1(2)+PID2(2)+...+PID16(2) */ struct spi_device *fc8300_spi; -static u8 tx_data[10]; +static u8 tx_data[TX_DATA_SIZE]; static u8 wdata_buf[32] __cacheline_aligned; static u8 rdata_buf[65536] __cacheline_aligned; @@ -168,7 +169,7 @@ static s32 spi_bulkwrite(HANDLE handle, u8 devid, tx_data[3] = length & 0xff; for (i = 0; i < length; i++) { - if ((4+i) < 10) + if ((4+i) < TX_DATA_SIZE) tx_data[4+i] = data[i]; else ISDB_PR_ERR("Error spi_bulkwrite tx_data length= %d\n", length); diff --git a/drivers/media/m2m1shot.c b/drivers/media/m2m1shot.c index 61ae32f5d14b..10d655d5e10f 100644 --- a/drivers/media/m2m1shot.c +++ b/drivers/media/m2m1shot.c @@ -588,6 +588,8 @@ static int m2m1shot_process(struct m2m1shot_context *ctx, kref_get(&ctx->kref); + mutex_lock(&ctx->mutex); + ret = m2m1shot_prepare_task(m21dev, ctx, task); if (ret) goto err; @@ -627,6 +629,9 @@ static int m2m1shot_process(struct m2m1shot_context *ctx, m2m1shot_finish_task(m21dev, ctx, task); err: + + mutex_unlock(&ctx->mutex); + kref_put(&ctx->kref, m2m1shot_destroy_context); if (ret) diff --git a/drivers/media/platform/exynos/fimc-is2/Kconfig b/drivers/media/platform/exynos/fimc-is2/Kconfig index 581227f8c8e1..af9ed681fd23 100644 --- a/drivers/media/platform/exynos/fimc-is2/Kconfig +++ b/drivers/media/platform/exynos/fimc-is2/Kconfig @@ -20,6 +20,13 @@ config ENABLE_HAL3_2_META_INTERFACE help Use the unified meta in 3.2 and 1.0 HAL. +config TORCH_CURRENT_CHANGE_SUPPORT + bool "Change torch current in recording mode" + depends on USE_VENDER_FEATURE + default n + help + Change torch current in recording mode. + source "drivers/media/platform/exynos/fimc-is2/sensor/Kconfig" source "drivers/media/platform/exynos/fimc-is2/ischain/Kconfig" source "drivers/media/platform/exynos/fimc-is2/vendor/Kconfig" diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h index 369a731258b4..a90d32650795 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-core.h @@ -86,7 +86,7 @@ #define FIMC_IS_REGION_SIZE (0x00005000) #define FIMC_IS_SETFILE_SIZE (0x00140000) #define FIMC_IS_SHARED_REGION_ADDR (0x019C0000) -#define FIMC_IS_BACKUP_SIZE (0x02000000) +#define FIMC_IS_BACKUP_SIZE (0x0189C000) #define FIMC_IS_FW_BASE_MASK ((1 << 26) - 1) diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-companion.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-companion.c index b573e94dfbb9..c09eda4e2bb5 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-companion.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-companion.c @@ -62,6 +62,7 @@ extern struct pm_qos_request exynos_isp_qos_int; extern struct pm_qos_request exynos_isp_qos_mem; extern struct pm_qos_request exynos_isp_qos_cam; extern struct pm_qos_request exynos_isp_qos_disp; +extern bool force_caldata_dump; int fimc_is_companion_g_module(struct fimc_is_device_companion *device, struct fimc_is_module_enum **module) @@ -945,18 +946,22 @@ int fimc_is_companion_s_input(struct fimc_is_device_companion *device, } if (fimc_is_comp_is_valid(core) == 0) { -#ifdef CONFIG_COMPANION_STANDBY_USE - if (GET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION) == SENSOR_STATE_OFF) { - ret = fimc_is_comp_loadfirm(core); - } else { - ret = fimc_is_comp_retention(core); - if (ret == -EINVAL) { - info("companion restart..\n"); +#if defined(CONFIG_COMPANION_STANDBY_USE) + if (force_caldata_dump == false) { + if (GET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION) == SENSOR_STATE_OFF) { ret = fimc_is_comp_loadfirm(core); + } else { + ret = fimc_is_comp_retention(core); + if (ret == -EINVAL) { + info("companion restart..\n"); + ret = fimc_is_comp_loadfirm(core); + } } + SET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION, SENSOR_STATE_ON); + info("%s: COMPANION STATE %u\n", __func__, GET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION)); + } else { + ret = fimc_is_comp_loadfirm(core); } - SET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION, SENSOR_STATE_ON); - info("%s: COMPANION STATE %u\n", __func__, GET_SENSOR_STATE(pdata->standby_state, SENSOR_STATE_COMPANION)); #else ret = fimc_is_comp_loadfirm(core); #endif diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c index e0a14cc50e03..d109fc8888d9 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-device-ischain.c @@ -659,7 +659,7 @@ void fimc_is_ischain_version(enum fimc_is_bin_type type, const char *load_bin, u FIMC_IS_VERSION_SIZE); version_str[FIMC_IS_VERSION_SIZE] = '\0'; - info("FW version : %s\n", version_str); + info("Phone FW version : %s\n", version_str); } else { memcpy(version_str, &load_bin[size - FIMC_IS_SETFILE_VER_OFFSET], FIMC_IS_SETFILE_VER_SIZE); @@ -695,7 +695,9 @@ static int fimc_is_ischain_loadfirm(struct fimc_is_device_ischain *device) #ifdef CONFIG_USE_VENDER_FEATURE struct fimc_is_from_info *sysfs_finfo; + struct fimc_is_from_info *sysfs_pinfo; fimc_is_sec_get_sysfs_finfo(&sysfs_finfo); + fimc_is_sec_get_sysfs_pinfo(&sysfs_pinfo); #endif mdbgd_ischain("%s\n", device, __func__); @@ -740,6 +742,10 @@ static int fimc_is_ischain_loadfirm(struct fimc_is_device_ischain *device) goto out; } +#ifdef CONFIG_USE_VENDER_FEATURE + strncpy(sysfs_pinfo->header_ver, buf + nread - 11, FIMC_IS_HEADER_VER_SIZE); + fimc_is_sec_set_loaded_fw(sysfs_pinfo->header_ver); +#endif memcpy((void *)device->imemory.kvaddr, (void *)buf, fsize); fimc_is_ischain_cache_flush(device, 0, fsize + 1); fimc_is_ischain_version(FIMC_IS_BIN_FW, buf, fsize); @@ -965,8 +971,10 @@ struct fimc_is_module_enum *active_sensor, int position) u32 start_addr = 0; int cal_size = 0; struct fimc_is_from_info *finfo; + struct fimc_is_from_info *pinfo; struct exynos_platform_fimc_is *core_pdata = NULL; struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev); + char *loaded_fw_ver; core_pdata = dev_get_platdata(fimc_is_dev); if (!core_pdata) { @@ -996,6 +1004,9 @@ struct fimc_is_module_enum *active_sensor, int position) fimc_is_sec_get_cal_buf(&cal_buf); } + fimc_is_sec_get_sysfs_pinfo(&pinfo); + fimc_is_sec_get_loaded_fw(&loaded_fw_ver); + cal_ptr = (char *)(device->imemory.kvaddr + start_addr); info("CAL DATA : MAP ver : %c%c%c%c\n", cal_buf[0x40], cal_buf[0x41], @@ -1003,6 +1014,9 @@ struct fimc_is_module_enum *active_sensor, int position) info("Camera : Front Sensor Version : 0x%x\n", cal_buf[0x5C]); + info("eeprom_fw_version = %s, phone_fw_version = %s, loaded_fw_version = %s\n", + finfo->header_ver, pinfo->header_ver, loaded_fw_ver); + /* CRC check */ if (position == SENSOR_POSITION_FRONT) { if (crc32_check_front == true) { @@ -1052,7 +1066,11 @@ static int fimc_is_ischain_loadcalb(struct fimc_is_device_ischain *device, int ret = 0; #ifdef CONFIG_USE_VENDER_FEATURE char *cal_ptr; + u32 start_addr = 0; + int cal_size = 0; struct fimc_is_from_info *sysfs_finfo; + struct fimc_is_from_info *sysfs_pinfo; + char *loaded_fw_ver; char *cal_buf; struct fimc_is_core *core = (struct fimc_is_core *)platform_get_drvdata(device->pdev); @@ -1070,43 +1088,80 @@ static int fimc_is_ischain_loadcalb(struct fimc_is_device_ischain *device, return 0; } - cal_ptr = (char *)(device->imemory.kvaddr + FIMC_IS_CAL_START_ADDR); + if (position == SENSOR_POSITION_FRONT) { + start_addr = FIMC_IS_CAL_START_ADDR_FRONT; + cal_size = FIMC_IS_MAX_CAL_SIZE_FRONT; + fimc_is_sec_get_sysfs_finfo_front(&sysfs_finfo); + fimc_is_sec_get_front_cal_buf(&cal_buf); + } else { + start_addr = FIMC_IS_CAL_START_ADDR; + cal_size = FIMC_IS_MAX_CAL_SIZE; + fimc_is_sec_get_sysfs_finfo(&sysfs_finfo); + fimc_is_sec_get_cal_buf(&cal_buf); + } - fimc_is_sec_get_sysfs_finfo(&sysfs_finfo); - fimc_is_sec_get_cal_buf(&cal_buf); + fimc_is_sec_get_sysfs_pinfo(&sysfs_pinfo); + fimc_is_sec_get_loaded_fw(&loaded_fw_ver); + + cal_ptr = (char *)(device->imemory.kvaddr + start_addr); info("CAL DATA : MAP ver : %c%c%c%c\n", cal_buf[0x60], cal_buf[0x61], cal_buf[0x62], cal_buf[0x63]); - if ((sysfs_finfo->header_ver[0] == 'A') && (sysfs_finfo->header_ver[1] == '2') && (sysfs_finfo->header_ver[2] == '0')) - info("Camera : Rear Sensor Version : 0x%x\n", cal_buf[0xC0]); + info("from_fw_version = %s, phone_fw_version = %s, loaded_fw_version = %s\n", + sysfs_finfo->header_ver, sysfs_pinfo->header_ver, loaded_fw_ver); /* CRC check */ - if (crc32_check == true) { + if (position == SENSOR_POSITION_FRONT) { + if (crc32_check_front == true) { #ifdef CONFIG_COMPANION_USE - if (fimc_is_sec_check_from_ver(core, position)) { - memcpy((void *)(cal_ptr) ,(void *)cal_buf, FIMC_IS_MAX_CAL_SIZE); + if (fimc_is_sec_check_from_ver(core, position)) { + memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size); + info("Camera : the dumped Cal. data was applied successfully.\n"); + } else { + info("Camera : Did not load dumped Cal. Sensor version is lower than V004.\n"); + } +#else + memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size); info("Camera : the dumped Cal. data was applied successfully.\n"); +#endif } else { - info("Camera : Did not load dumped Cal. Sensor version is lower than V004.\n"); + if (crc32_header_check_front == true) { + err("Camera : CRC32 error but only header section is no problem."); + memset((void *)(cal_ptr + 0x1000), 0xFF, cal_size - 0x1000); + } else { + err("Camera : CRC32 error for all section."); + memset((void *)(cal_ptr), 0xFF, cal_size); + ret = -EIO; + } } + } else { + if (crc32_check == true) { +#ifdef CONFIG_COMPANION_USE + if (fimc_is_sec_check_from_ver(core, position)) { + memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size); + info("Camera : the dumped Cal. data was applied successfully.\n"); + } else { + info("Camera : Did not load dumped Cal. Sensor version is lower than V004.\n"); + } #else - memcpy((void *)(cal_ptr) ,(void *)cal_buf, FIMC_IS_MAX_CAL_SIZE); - info("Camera : the dumped Cal. data was applied successfully.\n"); + memcpy((void *)(cal_ptr) ,(void *)cal_buf, cal_size); + info("Camera : the dumped Cal. data was applied successfully.\n"); #endif - } else { - if (crc32_header_check == true) { - err("Camera : CRC32 error but only header section is no problem."); - memset((void *)(cal_ptr + 0x1000), 0xFF, FIMC_IS_MAX_CAL_SIZE - 0x1000); } else { - err("Camera : CRC32 error for all section."); - memset((void *)(cal_ptr), 0xFF, FIMC_IS_MAX_CAL_SIZE); - ret = -EIO; + if (crc32_header_check == true) { + err("Camera : CRC32 error but only header section is no problem."); + memset((void *)(cal_ptr + 0x1000), 0xFF, cal_size - 0x1000); + } else { + err("Camera : CRC32 error for all section."); + memset((void *)(cal_ptr), 0xFF, cal_size); + ret = -EIO; + } } } - fimc_is_ischain_cache_flush(device, FIMC_IS_CAL_START_ADDR, - FIMC_IS_MAX_CAL_SIZE); + fimc_is_ischain_cache_flush(device, start_addr, cal_size); + if (ret) mwarn("calibration loading is fail", device); else diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-dt.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-dt.c index 9660b5816e2c..53a5d7aab0a6 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-dt.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-dt.c @@ -24,6 +24,7 @@ #include "fimc-is-dt.h" #include "fimc-is-core.h" #include "fimc-is-dvfs.h" +#include "fimc-is-sysfs.h" #ifdef CONFIG_OF static int get_pin_lookup_state(struct pinctrl *pinctrl, @@ -284,6 +285,25 @@ static int parse_dvfs_data(struct exynos_platform_fimc_is *pdata, struct device_ return 0; } +#ifdef CAMERA_SYSFS_V2 +static int parse_sysfs_caminfo(struct exynos_platform_fimc_is *pdata, struct device_node *np, + struct fimc_is_cam_info *cam_infos, int camera_num) +{ + u32 temp; + char *pprop; + + DT_READ_U32(np, "isp", cam_infos[camera_num].isp); + DT_READ_U32(np, "cal_memory", cam_infos[camera_num].cal_memory); + DT_READ_U32(np, "read_version", cam_infos[camera_num].read_version); + DT_READ_U32(np, "core_voltage", cam_infos[camera_num].core_voltage); + DT_READ_U32(np, "upgrade", cam_infos[camera_num].upgrade); + DT_READ_U32(np, "companion", cam_infos[camera_num].companion); + DT_READ_U32(np, "ois", cam_infos[camera_num].ois); + + return 0; +} +#endif + int fimc_is_parse_dt(struct platform_device *pdev) { int ret = 0; @@ -293,6 +313,13 @@ int fimc_is_parse_dt(struct platform_device *pdev) struct device_node *dvfs_table_np = NULL; struct device_node *np; const char *dvfs_table_desc; +#ifdef CAMERA_SYSFS_V2 + struct device_node *camInfo_np; + struct fimc_is_cam_info *camera_infos; + char camInfo_string[15]; + int camera_num; + int total_camera_num; +#endif u32 table_index = 0; BUG_ON(!pdev); @@ -387,6 +414,27 @@ int fimc_is_parse_dt(struct platform_device *pdev) err("parse_dvfs_data is fail(%d)", ret); } +#ifdef CAMERA_SYSFS_V2 + ret = of_property_read_u32(np, "total_camera_num", &total_camera_num); + if (ret) { + err("total_camera_num read is fail(%d)", ret); + total_camera_num = 0; + } + fimc_is_get_cam_info(&camera_infos); + + for (camera_num = 0; camera_num < total_camera_num; camera_num++) { + sprintf(camInfo_string, "%s%d", "camera_info", camera_num); + + camInfo_np = of_find_node_by_name(np, camInfo_string); + if (!camInfo_np) { + printk(KERN_ERR "%s: can't find camInfo_string node\n", __func__); + ret = -ENOENT; + goto p_err; + } + parse_sysfs_caminfo(pdata, camInfo_np, camera_infos, camera_num); + } +#endif + dev->platform_data = pdata; return 0; diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c index 0b0327b1e4e1..a797dbe3c4d9 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-groupmgr.c @@ -565,6 +565,9 @@ extern int lm3560_reg_update_export(u8 reg, u8 mask, u8 data); #ifdef CONFIG_LEDS_SKY81296 extern int sky81296_torch_ctrl(int state); #endif +#if defined(CONFIG_TORCH_CURRENT_CHANGE_SUPPORT) && defined(CONFIG_LEDS_S2MPB02) +extern int s2mpb02_set_torch_current(bool movie); +#endif static void fimc_is_group_set_torch(struct fimc_is_group *group, struct fimc_is_frame *ldr_frame) @@ -581,6 +584,9 @@ static void fimc_is_group_set_torch(struct fimc_is_group *group, lm3560_reg_update_export(0xE0, 0xFF, 0xEF); #elif defined(CONFIG_LEDS_SKY81296) sky81296_torch_ctrl(1); +#endif +#if defined(CONFIG_TORCH_CURRENT_CHANGE_SUPPORT) && defined(CONFIG_LEDS_S2MPB02) + s2mpb02_set_torch_current(true); #endif break; case AA_FLASHMODE_START: /*Pre flash mode*/ @@ -588,6 +594,9 @@ static void fimc_is_group_set_torch(struct fimc_is_group *group, lm3560_reg_update_export(0xE0, 0xFF, 0xEF); #elif defined(CONFIG_LEDS_SKY81296) sky81296_torch_ctrl(1); +#endif +#if defined(CONFIG_TORCH_CURRENT_CHANGE_SUPPORT) && defined(CONFIG_LEDS_S2MPB02) + s2mpb02_set_torch_current(false); #endif break; case AA_FLASHMODE_CAPTURE: /*Main flash mode*/ diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-interface.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-interface.c index ef349289951d..c3b39a75e3f8 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-interface.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-interface.c @@ -3039,7 +3039,11 @@ int fimc_is_hw_enum(struct fimc_is_interface *this) msg.param3 = 0; msg.param4 = 0; - waiting_is_ready(this); + ret = waiting_is_ready(this); + if (ret) { + err("waiting for ready is fail"); + } + com_regs = this->com_regs; writel(msg.command, &com_regs->hicmd); writel(msg.instance, &com_regs->hic_stream); diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-video-3aa.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-video-3aa.c index 25da2f170d15..b5e4b0d0bc9d 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-video-3aa.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-video-3aa.c @@ -512,11 +512,11 @@ static int fimc_is_3aa_video_s_ctrl(struct file *file, void *priv, break; case V4L2_CID_IS_CAMERA_TYPE: switch (ctrl->value) { - case 0: + case IS_COLD_BOOT: /* change value to X when !TWIZ | front */ fimc_is_itf_set_fwboot(device, COLD_BOOT); break; - case 1: + case IS_WARM_BOOT: /* change value to X when TWIZ & back | frist time back camera */ if(!device->interface->first_launch) { fimc_is_itf_set_fwboot(device, FIRST_LAUNCHING); diff --git a/drivers/media/platform/exynos/fimc-is2/fimc-is-video.c b/drivers/media/platform/exynos/fimc-is2/fimc-is-video.c index 46062874db71..a043ce4b8542 100644 --- a/drivers/media/platform/exynos/fimc-is2/fimc-is-video.c +++ b/drivers/media/platform/exynos/fimc-is2/fimc-is-video.c @@ -1382,9 +1382,8 @@ int fimc_is_video_s_ctrl(struct file *file, size = sizeof(struct v4l2_plane) * buf->length; planes = kmalloc(size, GFP_KERNEL); - if (IS_ERR_OR_NULL(planes)) { - if (planes) - mverr("kmalloc is fail(%p)", device, video, planes); + if (!planes) { + mverr("kmalloc is fail(%p)", device, video, planes); kfree(buf); ret = -EINVAL; goto p_err; diff --git a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-config.h b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-config.h index 48f54b92d2e7..eae9fd1f52c6 100644 --- a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-config.h +++ b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-config.h @@ -12,6 +12,11 @@ #ifndef FIMC_IS_CONFIG_H #define FIMC_IS_CONFIG_H +#if defined(CONFIG_CAMERA_ZERO) || defined(CONFIG_CAMERA_MARINE) || defined(CONFIG_CAMERA_VLTE) \ + || defined(CONFIG_CAMERA_NOBLE) || defined(CONFIG_CAMERA_ZENLTE) +#include "../vendor/fimc-is-vendor-config_zero.h" +#endif + /* * ================================================================================================= * CONFIG - GLOBAL OPTIONS @@ -91,7 +96,7 @@ * ================================================================================================= */ -/* #define FW_SUSPEND_RESUME */ +#define FW_SUSPEND_RESUME #define ENABLE_CLOCK_GATE #define HAS_FW_CLOCK_GATE /* #define ENABLE_CACHE */ diff --git a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-metadata.h b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-metadata.h index 0e39a26c17ed..44c4a62d10ea 100644 --- a/drivers/media/platform/exynos/fimc-is2/include/fimc-is-metadata.h +++ b/drivers/media/platform/exynos/fimc-is2/include/fimc-is-metadata.h @@ -723,7 +723,8 @@ enum aa_scene_mode { AA_SCENE_MODE_DUAL_VIDEO, AA_SCENE_MODE_120_PREVIEW, AA_SCENE_MODE_LIGHT_TRACE, - AA_SCENE_MODE_FOOD + AA_SCENE_MODE_FOOD, + AA_SCENE_MODE_AQUA }; enum aa_effect_mode { @@ -1554,7 +1555,8 @@ struct camera2_uctl { /** ispfw specific control(user-defined) of drc. */ struct camera2_drc_uctl drcUd; enum camera_vt_mode vtMode; - uint32_t reserved[10]; + float zoomRatio; + uint32_t reserved[9]; }; struct camera2_udm { diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/Kconfig b/drivers/media/platform/exynos/fimc-is2/sensor/module/Kconfig index c245d5292adc..19726929c869 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/Kconfig +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/Kconfig @@ -118,6 +118,12 @@ config CAMERA_SENSOR_IMX219_OBJ default n help Use to build IMX219 camera sensor. +config CAMERA_SENSOR_IMX228_OBJ + bool "Use IMX228 camera sensor" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + Use to build IMX228 camera sensor. config CAMERA_SENSOR_IMX240_OBJ bool "Use IMX240 camera sensor" depends on VIDEO_EXYNOS_FIMC_IS diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/Makefile b/drivers/media/platform/exynos/fimc-is2/sensor/module/Makefile index 67c11b19b249..cbe7d2acea5e 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_CAMERA_SENSOR_4E5_OBJ) += fimc-is-device-4e5.o obj-$(CONFIG_CAMERA_SENSOR_6A3_OBJ) += fimc-is-device-6a3.o obj-$(CONFIG_CAMERA_SENSOR_IMX175_OBJ) += fimc-is-device-imx175.o obj-$(CONFIG_CAMERA_SENSOR_IMX240_OBJ) += fimc-is-device-imx240.o +obj-$(CONFIG_CAMERA_SENSOR_IMX228_OBJ) += fimc-is-device-imx228.o obj-$(CONFIG_CAMERA_SENSOR_IMX219_OBJ) += fimc-is-device-imx219.o obj-$(CONFIG_CAMERA_SENSOR_4H5_OBJ) += fimc-is-device-4h5.o obj-$(CONFIG_CAMERA_SENSOR_4E6_OBJ) += fimc-is-device-4e6.o diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2p2.c b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2p2.c index 39bb6d423841..73d710a93880 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2p2.c +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2p2.c @@ -122,6 +122,9 @@ static int sensor_2p2_power_setpin(struct platform_device *pdev, if (!gpio_is_valid(gpio_comp_rst)) { dev_err(dev, "failed to get main comp reset gpio\n"); return -EINVAL; + } else { + gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_comp_rst); } gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0); @@ -163,8 +166,10 @@ static int sensor_2p2_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2950000); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1200000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); @@ -193,16 +198,20 @@ static int sensor_2p2_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); +#endif #ifdef CONFIG_COMPANION_STANDBY_USE /* STANDBY DISABLE */ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2950000); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1200000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); @@ -229,9 +238,11 @@ static int sensor_2p2_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); #endif +#endif #ifdef CONFIG_OIS_USE /* OIS_FACTORY - POWER ON */ diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2t2.c b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2t2.c index 494dc15d8b7e..7555506f3f6e 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2t2.c +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-2t2.c @@ -122,6 +122,9 @@ static int sensor_2t2_power_setpin(struct platform_device *pdev, if (!gpio_is_valid(gpio_comp_rst)) { dev_err(dev, "%s: failed to get main comp reset gpio\n", __func__); return -EINVAL; + } else { + gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_comp_rst); } gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0); diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-4e6-c2.c b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-4e6-c2.c index e95fd0a50293..144c2d26d931 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-4e6-c2.c +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-4e6-c2.c @@ -292,6 +292,9 @@ static int sensor_4e6_c2_power_setpin(struct platform_device *pdev, if (!gpio_is_valid(gpio_comp_rst)) { dev_err(dev, "%s: failed to get main comp reset gpio\n", __func__); return -EINVAL; + } else { + gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_comp_rst); } gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0); @@ -335,6 +338,10 @@ static int sensor_4e6_c2_power_setpin(struct platform_device *pdev, SET_PIN_INIT(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF); /* FRONT CAMERA - POWER ON */ +#ifdef CONFIG_OIS_USE + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_standby, "standby_low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_reset, "rst_low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDA_2.9V_VT", PIN_REGULATOR, 1, 0); @@ -368,9 +375,17 @@ static int sensor_4e6_c2_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDA_2.9V_VT", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_VT", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); +#endif #ifdef CONFIG_COMPANION_STANDBY_USE /* STANDBY DISABLE */ +#ifdef CONFIG_OIS_USE + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_standby, "standby_low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_reset, "rst_low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDA_2.9V_VT", PIN_REGULATOR, 1, 0); @@ -402,7 +417,12 @@ static int sensor_4e6_c2_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDA_2.9V_VT", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDIO_1.8V_VT", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); +#endif #endif + /* VISION CAMERA - POWER ON */ SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, gpio_standby, "standby_low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON, gpio_reset, "rst_low", PIN_OUTPUT, 0, 0); diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.c b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.c new file mode 100644 index 000000000000..f96b18ffcf9f --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.c @@ -0,0 +1,434 @@ +/* + * Samsung Exynos5 SoC series Sensor driver + * + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include +#include +#include + +#include "fimc-is-hw.h" +#include "fimc-is-core.h" +#include "fimc-is-device-sensor.h" +#include "fimc-is-resourcemgr.h" +#include "fimc-is-device-imx228.h" +#include "fimc-is-dt.h" + +#define SENSOR_NAME "IMX228" + +static struct fimc_is_sensor_cfg config_imx228[] = { + /* 5968x3368@30fps */ + FIMC_IS_SENSOR_CFG(5968, 3368, 30, 36, 0), + /* 5968x3368@24fps */ + FIMC_IS_SENSOR_CFG(5968, 3368, 24, 29, 1), + /* 4480x3368@30fps */ + FIMC_IS_SENSOR_CFG(4480, 3368, 30, 28, 2), + /* 4480x3368@24fps */ + FIMC_IS_SENSOR_CFG(4480, 3368, 24, 22, 3), + /* 3360x3368@30fps */ + FIMC_IS_SENSOR_CFG(3360, 3368, 30, 44, 4), + /* 3360x3368@24fps */ + FIMC_IS_SENSOR_CFG(3360, 3368, 24, 36, 5), + /* 2984x1680@60fps */ + FIMC_IS_SENSOR_CFG(2984, 1680, 60, 44, 6), + /* 2984x1680@30fps */ + FIMC_IS_SENSOR_CFG(2984, 1680, 30, 25, 7), + /* 1480x832@120fps */ + FIMC_IS_SENSOR_CFG(1480, 832, 120, 25, 8), + /* 1480x832@240fps */ + FIMC_IS_SENSOR_CFG(1480, 832, 240, 24, 9), + /* 924x556@300fps */ + FIMC_IS_SENSOR_CFG(924, 556, 300, 25, 10), + /* 5968x1680@60fps */ + FIMC_IS_SENSOR_CFG(5968, 1680, 60, 38, 11), +}; + +static struct fimc_is_vci vci_imx228[] = { + { + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .config = {{0, HW_FORMAT_RAW10}, {1, HW_FORMAT_UNKNOWN}, {2, HW_FORMAT_USER}, {3, 0}} + }, { + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .config = {{0, HW_FORMAT_RAW10}, {1, HW_FORMAT_UNKNOWN}, {2, HW_FORMAT_USER}, {3, 0}} + }, { + .pixelformat = V4L2_PIX_FMT_SBGGR16, + .config = {{0, HW_FORMAT_RAW10}, {1, HW_FORMAT_UNKNOWN}, {2, HW_FORMAT_USER}, {3, 0}} + } +}; + +static int sensor_imx228_init(struct v4l2_subdev *subdev, u32 val) +{ + int ret = 0; + struct fimc_is_module_enum *module; + + BUG_ON(!subdev); + + module = (struct fimc_is_module_enum *)v4l2_get_subdevdata(subdev); + + pr_info("[MOD:D:%d] %s(%d)\n", module->sensor_id, __func__, val); + + return ret; +} + +static const struct v4l2_subdev_core_ops core_ops = { + .init = sensor_imx228_init +}; + +static const struct v4l2_subdev_ops subdev_ops = { + .core = &core_ops +}; + +#ifdef CONFIG_OF +static int sensor_imx228_power_setpin(struct platform_device *pdev, + struct exynos_platform_fimc_is_module *pdata) +{ + struct device *dev; + struct device_node *dnode; + int gpio_reset = 0; + int gpio_comp_rst = 0; + int gpio_mclk = 0; + int gpio_none = 0; + + BUG_ON(!pdev); + + dev = &pdev->dev; + dnode = dev->of_node; + + dev_info(dev, "%s E v4\n", __func__); + + gpio_comp_rst = of_get_named_gpio(dnode, "gpio_comp_reset", 0); + if (!gpio_is_valid(gpio_comp_rst)) { + dev_err(dev, "failed to get main comp reset gpio\n"); + return -EINVAL; + } else { + gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_comp_rst); + } + + gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0); + if (!gpio_is_valid(gpio_reset)) { + dev_err(dev, "failed to get PIN_RESET\n"); + return -EINVAL; + } else { + gpio_request_one(gpio_reset, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_reset); + } + + gpio_mclk = of_get_named_gpio(dnode, "gpio_mclk", 0); + if (!gpio_is_valid(gpio_mclk)) { + dev_err(dev, "%s: failed to get mclk\n", __func__); + return -EINVAL; + } else { + if (gpio_request_one(gpio_mclk, GPIOF_OUT_INIT_LOW, "CAM_MCLK_OUTPUT_LOW")) { + dev_err(dev, "%s: failed to gpio request mclk\n", __func__); + return -ENODEV; + } + + gpio_free(gpio_mclk); + } + + SET_PIN_INIT(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON); + SET_PIN_INIT(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF); +#ifdef CONFIG_COMPANION_STANDBY_USE + SET_PIN_INIT(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE); + SET_PIN_INIT(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE); +#endif + SET_PIN_INIT(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_ON); + SET_PIN_INIT(pdata, SENSOR_SCENARIO_VISION, GPIO_SCENARIO_OFF); +#ifdef CONFIG_OIS_USE + SET_PIN_INIT(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON); + SET_PIN_INIT(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF); +#endif + + /* Normal on */ + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2800000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1050000); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDIO_1.8V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDA_1.8V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_CORE_1.0V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_NORET_0.9V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_CORE_0.8V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "pin", PIN_FUNCTION, 2, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_comp_rst, "comp_rst high", PIN_OUTPUT, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_reset, "sen_rst high", PIN_OUTPUT, 1, 2000); + + /* Normal off */ + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 0, 1000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "pin", PIN_FUNCTION, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "pin", PIN_FUNCTION, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "pin", PIN_FUNCTION, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_reset, "sen_rst", PIN_OUTPUT, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_comp_rst, "comp_rst low", PIN_OUTPUT, 0, 10); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_CORE_0.8V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_NORET_0.9V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_CORE_1.0V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDA_1.8V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); + +#ifdef CONFIG_COMPANION_STANDBY_USE + /* STANDBY DISABLE */ + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2800000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1050000); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDA_1.8V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_CORE_1.0V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_NORET_0.9V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_CORE_0.8V_COMP", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "pin", PIN_FUNCTION, 2, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_comp_rst, "comp_rst high", PIN_OUTPUT, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_reset, "sen_rst high", PIN_OUTPUT, 1, 2000); + + /* STANDBY ENABLE */ + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 0, 1000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "pin", PIN_FUNCTION, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "pin", PIN_FUNCTION, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "pin", PIN_FUNCTION, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_reset, "sen_rst", PIN_OUTPUT, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_comp_rst, "comp_rst low", PIN_OUTPUT, 0, 10); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_CORE_0.8V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_NORET_0.9V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_CORE_1.0V_COMP", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDA_1.8V_COMP", PIN_REGULATOR, 0, 1000); + SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 700000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); +#endif + +#ifdef CONFIG_OIS_USE + /* OIS_FACTORY - POWER ON */ + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_ON, gpio_reset, "sen_rst high", PIN_OUTPUT, 1, 0); + + /* OIS_FACTORY - POWER OFF */ + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); + SET_PIN(pdata, SENSOR_SCENARIO_OIS_FACTORY, GPIO_SCENARIO_OFF, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 0, 0); +#endif + + dev_info(dev, "%s X v4\n", __func__); + + return 0; +} + +#endif /* CONFIG_OF */ + +int sensor_imx228_probe(struct platform_device *pdev) +{ + int ret = 0; + struct fimc_is_core *core; + struct v4l2_subdev *subdev_module; + struct fimc_is_module_enum *module; + struct fimc_is_device_sensor *device; + struct sensor_open_extended *ext; + struct exynos_platform_fimc_is_module *pdata; + struct device *dev; + + BUG_ON(!fimc_is_dev); + + core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev); + if (!core) { + probe_err("core device is not yet probed"); + return -EPROBE_DEFER; + } + + dev = &pdev->dev; + +#ifdef CONFIG_OF + fimc_is_sensor_module_parse_dt(pdev, sensor_imx228_power_setpin); +#endif + + pdata = dev_get_platdata(dev); + device = &core->sensor[pdata->id]; + + subdev_module = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (!subdev_module) { + probe_err("subdev_module is NULL"); + ret = -ENOMEM; + goto p_err; + } + + module = &device->module_enum[atomic_read(&core->resourcemgr.rsccount_module)]; + atomic_inc(&core->resourcemgr.rsccount_module); + clear_bit(FIMC_IS_MODULE_GPIO_ON, &module->state); + module->pdata = pdata; + module->pdev = pdev; + module->sensor_id = SENSOR_NAME_IMX228; + module->subdev = subdev_module; + module->device = pdata->id; + module->client = NULL; + module->active_width = 5952; + module->active_height = 3358; + module->pixel_width = module->active_width + 16; + module->pixel_height = module->active_height + 10; + module->max_framerate = 300; + module->position = pdata->position; + module->mode = CSI_MODE_DT_ONLY; + module->lanes = CSI_DATA_LANES_4; + module->vcis = ARRAY_SIZE(vci_imx228); + module->vci = vci_imx228; + module->sensor_maker = "SONY"; + module->sensor_name = "IMX228"; + module->setfile_name = "setfile_imx228.bin"; + module->cfgs = ARRAY_SIZE(config_imx228); + module->cfg = config_imx228; + module->ops = NULL; + module->private_data = NULL; + + ext = &module->ext; + ext->mipi_lane_num = module->lanes; + ext->I2CSclk = I2C_L0; + + ext->sensor_con.product_name = SENSOR_NAME_IMX228; + ext->sensor_con.peri_type = SE_I2C; + ext->sensor_con.peri_setting.i2c.channel = pdata->sensor_i2c_ch; + ext->sensor_con.peri_setting.i2c.slave_address = pdata->sensor_i2c_addr; + ext->sensor_con.peri_setting.i2c.speed = 400000; + + if (pdata->af_product_name != ACTUATOR_NAME_NOTHING) { + ext->actuator_con.product_name = pdata->af_product_name; + ext->actuator_con.peri_type = SE_I2C; + ext->actuator_con.peri_setting.i2c.channel = pdata->af_i2c_ch; + ext->actuator_con.peri_setting.i2c.slave_address = pdata->af_i2c_addr; + ext->actuator_con.peri_setting.i2c.speed = 400000; + } + + if (pdata->flash_product_name != FLADRV_NAME_NOTHING) { + ext->flash_con.product_name = pdata->flash_product_name; + ext->flash_con.peri_type = SE_GPIO; + ext->flash_con.peri_setting.gpio.first_gpio_port_no = pdata->flash_first_gpio; + ext->flash_con.peri_setting.gpio.second_gpio_port_no = pdata->flash_second_gpio; + } + + ext->from_con.product_name = FROMDRV_NAME_NOTHING; + + if (pdata->companion_product_name != COMPANION_NAME_NOTHING) { + ext->companion_con.product_name = pdata->companion_product_name; + ext->companion_con.peri_info0.valid = true; + ext->companion_con.peri_info0.peri_type = SE_SPI; + ext->companion_con.peri_info0.peri_setting.spi.channel = pdata->companion_spi_channel; + ext->companion_con.peri_info1.valid = true; + ext->companion_con.peri_info1.peri_type = SE_I2C; + ext->companion_con.peri_info1.peri_setting.i2c.channel = pdata->companion_i2c_ch; + ext->companion_con.peri_info1.peri_setting.i2c.slave_address = pdata->companion_i2c_addr; + ext->companion_con.peri_info1.peri_setting.i2c.speed = 400000; + ext->companion_con.peri_info2.valid = true; + ext->companion_con.peri_info2.peri_type = SE_FIMC_LITE; + ext->companion_con.peri_info2.peri_setting.fimc_lite.channel = FLITE_ID_D; + } else { + ext->companion_con.product_name = pdata->companion_product_name; + } + + if (pdata->ois_product_name != OIS_NAME_NOTHING) { + ext->ois_con.product_name = pdata->ois_product_name; + ext->ois_con.peri_type = SE_I2C; + ext->ois_con.peri_setting.i2c.channel = pdata->ois_i2c_ch; + ext->ois_con.peri_setting.i2c.slave_address = pdata->ois_i2c_addr; + ext->ois_con.peri_setting.i2c.speed = 400000; + } else { + ext->ois_con.product_name = pdata->ois_product_name; + ext->ois_con.peri_type = SE_NULL; + } + + v4l2_subdev_init(subdev_module, &subdev_ops); + + v4l2_set_subdevdata(subdev_module, module); + v4l2_set_subdev_hostdata(subdev_module, device); + snprintf(subdev_module->name, V4L2_SUBDEV_NAME_SIZE, "sensor-subdev.%d", module->sensor_id); + +p_err: + probe_info("%s(%d)\n", __func__, ret); + return ret; +} + +static int sensor_imx228_remove(struct platform_device *pdev) +{ + int ret = 0; + + info("%s\n", __func__); + + return ret; +} + +static const struct of_device_id exynos_fimc_is_sensor_imx228_match[] = { + { + .compatible = "samsung,exynos5-fimc-is-sensor-imx228", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_fimc_is_sensor_imx228_match); + +static struct platform_driver sensor_imx228_driver = { + .probe = sensor_imx228_probe, + .remove = sensor_imx228_remove, + .driver = { + .name = SENSOR_NAME, + .owner = THIS_MODULE, + .of_match_table = exynos_fimc_is_sensor_imx228_match, + } +}; + +static int __init fimc_is_sensor_module_init(void) +{ + int ret = platform_driver_register(&sensor_imx228_driver); + if (ret) + err("platform_driver_register failed: %d\n", ret); + + return ret; +} +late_initcall(fimc_is_sensor_module_init); + +static void __exit fimc_is_sensor_module_exit(void) +{ + platform_driver_unregister(&sensor_imx228_driver); +} +module_exit(fimc_is_sensor_module_exit); + diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.h b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.h new file mode 100644 index 000000000000..a0e0c645c9d7 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx228.h @@ -0,0 +1,20 @@ +/* + * Samsung Exynos5 SoC series Sensor driver + * + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * + * 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 FIMC_IS_DEVICE_IMX228_H +#define FIMC_IS_DEVICE_IMX228_H + +#define SENSOR_IMX228_INSTANCE 0 +#define SENSOR_IMX228_NAME SENSOR_NAME_IMX228 + +int sensor_imx228_probe(struct platform_device *pdev); + +#endif diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx240.c b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx240.c index 1012b7c505a3..6eb6b025bed4 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx240.c +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module/fimc-is-device-imx240.c @@ -120,6 +120,9 @@ static int sensor_imx240_power_setpin(struct platform_device *pdev, if (!gpio_is_valid(gpio_comp_rst)) { dev_err(dev, "failed to get main comp reset gpio\n"); return -EINVAL; + } else { + gpio_request_one(gpio_comp_rst, GPIOF_OUT_INIT_LOW, "CAM_GPIO_OUTPUT_LOW"); + gpio_free(gpio_comp_rst); } gpio_reset = of_get_named_gpio(dnode, "gpio_reset", 0); @@ -161,8 +164,10 @@ static int sensor_imx240_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2800000); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1050000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_ON, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); @@ -191,16 +196,20 @@ static int sensor_imx240_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_OFF, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); +#endif #ifdef CONFIG_COMPANION_STANDBY_USE /* STANDBY DISABLE */ SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_reset, "sen_rst low", PIN_OUTPUT, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDAF_2.8V_CAM", PIN_REGULATOR, 1, 2000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 1, 0, 2800000); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 1, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 1, 2500); +#endif SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 1, 0); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 1, 0, 1050000); SET_PIN_VOLTAGE(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_DISABLE, gpio_none, "VDDD_RET_1.0V_COMP", PIN_REGULATOR, 1, 0, 1000000); @@ -227,9 +236,11 @@ static int sensor_imx240_power_setpin(struct platform_device *pdev, SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDA_2.9V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDD_1.2V_CAM", PIN_REGULATOR, 0, 0); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "VDDIO_1.8V_CAM", PIN_REGULATOR, 0, 0); +#ifdef CONFIG_OIS_USE SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VDD_2.8V", PIN_REGULATOR, 0, 2000); SET_PIN(pdata, SENSOR_SCENARIO_NORMAL, GPIO_SCENARIO_STANDBY_ENABLE, gpio_none, "OIS_VM_2.8V", PIN_REGULATOR, 0, 0); #endif +#endif #ifdef CONFIG_OIS_USE /* OIS_FACTORY - POWER ON */ diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/Kconfig b/drivers/media/platform/exynos/fimc-is2/vendor/Kconfig index 36d92bf61084..916043102ef8 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/Kconfig +++ b/drivers/media/platform/exynos/fimc-is2/vendor/Kconfig @@ -58,4 +58,33 @@ config AF_HOST_CONTROL default n help Enable host af control. - +config CAMERA_ZERO + bool "This camera is zero project" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + This camera is zero project. +config CAMERA_MARINE + bool "This camera is marine project" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + This camera is marine project. +config CAMERA_VLTE + bool "This camera is vlte project" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + This camera is vlte project. +config CAMERA_NOBLE + bool "This camera is noble project" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + This camera is noble project. + config CAMERA_ZENLTE + bool "This camera is zenlte project" + depends on VIDEO_EXYNOS_FIMC_IS + default n + help + This camera is zenlte project. diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/Makefile b/drivers/media/platform/exynos/fimc-is2/vendor/Makefile index b77188ea2adb..5ea144f723b9 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/vendor/Makefile @@ -2,7 +2,8 @@ obj-$(CONFIG_USE_VENDER_FEATURE) := fimc-is-spi.o \ fimc-is-i2c.o \ fimc-is-sec-define.o \ crc32.o \ - fimc-is-sysfs.o + fimc-is-sysfs.o \ + fimc-is-device-from.o obj-$(CONFIG_COMPANION_USE) += fimc-is-companion-dt.o diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/crc32.c b/drivers/media/platform/exynos/fimc-is2/vendor/crc32.c index ca9a277535dc..7b6ed7658b8f 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/crc32.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/crc32.c @@ -14,6 +14,45 @@ /* #define DEBUG_CRC */ +#ifndef DEBUG_CRC +unsigned long table[256]; +#else +unsigned long table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; +#endif + static void makeCRCtable(unsigned long *table, unsigned long id) { unsigned long i, j, k; @@ -39,44 +78,6 @@ unsigned long getCRC(volatile unsigned short *mem, signed long size, long i; signed long count; unsigned long CRC = 0; -#ifndef DEBUG_CRC - unsigned long table[256]; -#else - unsigned long table[256] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; -#endif /* duration : under 1 ms */ makeCRCtable(table, 0xEDB88320); diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-companion_c2.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-companion_c2.c index 5d92516c8a1c..4d1d565eb012 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-companion_c2.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-companion_c2.c @@ -587,6 +587,7 @@ static int fimc_is_comp_load_binary(struct fimc_is_core *core, char *name, int b u16 addr1, addr2; char companion_rev[12] = {0, }; struct fimc_is_from_info *sysfs_finfo; + struct fimc_is_from_info *sysfs_pinfo; struct fimc_is_companion_retention *ret_data; #ifdef USE_ION_ALLOC struct ion_handle *handle = NULL; @@ -602,6 +603,7 @@ static int fimc_is_comp_load_binary(struct fimc_is_core *core, char *name, int b #endif ret_data = &core->companion.retention_data; fimc_is_sec_get_sysfs_finfo(&sysfs_finfo); + fimc_is_sec_get_sysfs_pinfo(&sysfs_pinfo); old_fs = get_fs(); set_fs(KERNEL_DS); @@ -667,6 +669,8 @@ static int fimc_is_comp_load_binary(struct fimc_is_core *core, char *name, int b goto p_err; } if (bin_type == COMPANION_FW) { + strncpy(sysfs_pinfo->concord_header_ver, buf + nread - 16, FIMC_IS_HEADER_VER_SIZE); + fimc_is_sec_set_loaded_c1_fw(sysfs_pinfo->concord_header_ver); strncpy(companion_rev, buf + nread - 16, 11); ret_data->firmware_size = (int)size; memset(ret_data->firmware_crc32, 0, sizeof(ret_data->firmware_crc32)); @@ -1275,7 +1279,7 @@ int fimc_is_comp_is_valid(void *core_data) /* check validation(Read data must be 0x73C2) */ fimc_is_comp_i2c_read(core->client0, 0x0, &companion_id); - info("Companion vaildation: 0x%04x\n", companion_id); + info("Companion validation: 0x%04x\n", companion_id); exit: return ret; @@ -1824,4 +1828,4 @@ int fimc_is_comp_set_voltage(char *volt_name, int uV) regulator_put(regulator); return ret; } -#endif \ No newline at end of file +#endif diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.c index 6853caf6763a..0d0ac19041b7 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.c @@ -44,23 +44,30 @@ static struct remove_af_noise af_sensor_interface = { .af_func = NULL, }; -static void fimc_is_af_i2c_config(struct i2c_client *client, bool onoff) +static int fimc_is_af_i2c_config(struct i2c_client *client, bool onoff) { struct device *i2c_dev = client->dev.parent->parent; struct pinctrl *pinctrl_i2c = NULL; - struct fimc_is_device_af *device = i2c_get_clientdata(client); + struct fimc_is_device_af *device; struct fimc_is_af_gpio *gpio; + if (!client) { + pr_info("%s: client is null\n", __func__); + return -ENODEV; + } + + device = i2c_get_clientdata(client); gpio = &device->gpio; - info("(%s):onoff(%d)\n", __func__, onoff); + info("(%s):onoff(%d) use_i2c_pinctrl(%d)\n", __func__, onoff, gpio->use_i2c_pinctrl); if (onoff) { /* ON */ - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + } pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c"); if (IS_ERR_OR_NULL(pinctrl_i2c)) { printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__); @@ -75,13 +82,15 @@ static void fimc_is_af_i2c_config(struct i2c_client *client, bool onoff) } else { devm_pinctrl_put(pinctrl_i2c); } + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + } + } - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); - } - + return 0; } int fimc_is_af_i2c_read(struct i2c_client *client, u16 addr, u16 *data) @@ -393,29 +402,47 @@ int fimc_is_af_parse_dt(struct i2c_client *client) struct device_node *np = client->dev.of_node; gpio = &device->gpio; + gpio->use_i2c_pinctrl = of_property_read_bool(np, "use_i2c_pinctrl"); - ret = of_property_read_string(np, "fimc_is_af_sda", (const char **) &gpio->sda); - if (ret) { - err("af gpio: fail to read, af_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + if(gpio->use_i2c_pinctrl) { + ret = of_property_read_string(np, "fimc_is_af_sda", (const char **) &gpio->sda); + if (ret) { + err("af gpio: fail to read, af_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - ret = of_property_read_string(np, "fimc_is_af_scl",(const char **) &gpio->scl); - if (ret) { - err("af gpio: fail to read, af_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + ret = of_property_read_string(np, "fimc_is_af_scl", (const char **) &gpio->scl); + if (ret) { + err("af gpio: fail to read, af_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - ret = of_property_read_string(np, "fimc_is_af_pinname",(const char **) &gpio->pinname); - if (ret) { - err("af gpio: fail to read, af_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + ret = of_property_read_string(np, "fimc_is_af_pinname", (const char **) &gpio->pinname); + if (ret) { + err("af gpio: fail to read, af_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - info("[AF] sda = %s, scl = %s, pinname = %s\n", gpio->sda, gpio->scl, gpio->pinname); + ret = of_property_read_u32(np, "pinfunc_on", &gpio->pinfunc_on); + if (ret) { + err("af gpio: fail to read, af_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_off", &gpio->pinfunc_off); + if (ret) { + err("af gpio: fail to read, af_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } + + info("[AF] sda = %s, scl = %s, pinname = %s, pinfunc_on = %d, pinfunc_off = %d\n", + gpio->sda, gpio->scl, gpio->pinname, gpio->pinfunc_on, gpio->pinfunc_off); + } p_err: return ret; diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.h index dca011706a29..851ef51e380c 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.h +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-af.h @@ -11,9 +11,12 @@ */ struct fimc_is_af_gpio { + bool use_i2c_pinctrl; char *sda; char *scl; char *pinname; + int pinfunc_on; + int pinfunc_off; }; struct fimc_is_device_af { diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.c index 507dd8e6a689..a6a46278987d 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.c @@ -54,46 +54,86 @@ int fimc_is_eeprom_parse_dt(struct i2c_client *client) gpio = &device->gpio; if (device->driver_data == REAR_DATA) { - ret = of_property_read_string(np, "fimc_is_rear_eeprom_sda", (const char **) &gpio->sda); - if (ret) { - err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_sda\n"); - ret = -ENODEV; - goto p_err; - } - - ret = of_property_read_string(np, "fimc_is_rear_eeprom_scl",(const char **) &gpio->scl); - if (ret) { - err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_scl\n"); - ret = -ENODEV; - goto p_err; - } - - ret = of_property_read_string(np, "fimc_is_rear_eeprom_pinname",(const char **) &gpio->pinname); - if (ret) { - err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_pinname\n"); - ret = -ENODEV; - goto p_err; + gpio->use_i2c_pinctrl = of_property_read_bool(np, "use_i2c_pinctrl"); + if(gpio->use_i2c_pinctrl) { + ret = of_property_read_string(np, "fimc_is_rear_eeprom_sda", (const char **) &gpio->sda); + if (ret) { + err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_sda\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_string(np, "fimc_is_rear_eeprom_scl",(const char **) &gpio->scl); + if (ret) { + err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_scl\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_string(np, "fimc_is_rear_eeprom_pinname",(const char **) &gpio->pinname); + if (ret) { + err("rear eeprom gpio: fail to read, fimc_is_rear_eeprom_pinname\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_on", &gpio->pinfunc_on); + if (ret) { + err("rear eeprom gpio: fail to read, pinfunc_on\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_off", &gpio->pinfunc_off); + if (ret) { + err("rear eeprom gpio: fail to read, pinfunc_off\n"); + ret = -ENODEV; + goto p_err; + } + + info("[%s eeprom] sda = %s, scl = %s, pinname = %s, pinfunc_on = %d, pinfunc_off = %d\n", + "rear", gpio->sda, gpio->scl, gpio->pinname, gpio->pinfunc_on, gpio->pinfunc_off); } } else if (device->driver_data == FRONT_DATA) { - ret = of_property_read_string(np, "fimc_is_front_eeprom_sda", (const char **) &gpio->sda); - if (ret) { - err("front eeprom gpio: fail to read, fimc_is_front_eeprom_sda\n"); - ret = -ENODEV; - goto p_err; - } - - ret = of_property_read_string(np, "fimc_is_front_eeprom_scl",(const char **) &gpio->scl); - if (ret) { - err("front eeprom gpio: fail to read, fimc_is_front_eeprom_scl\n"); - ret = -ENODEV; - goto p_err; - } - - ret = of_property_read_string(np, "fimc_is_front_eeprom_pinname",(const char **) &gpio->pinname); - if (ret) { - err("front eeprom gpio: fail to read, fimc_is_front_eeprom_pinname\n"); - ret = -ENODEV; - goto p_err; + gpio->use_i2c_pinctrl = of_property_read_bool(np, "use_i2c_pinctrl"); + if(gpio->use_i2c_pinctrl) { + ret = of_property_read_string(np, "fimc_is_front_eeprom_sda", (const char **) &gpio->sda); + if (ret) { + err("front eeprom gpio: fail to read, fimc_is_front_eeprom_sda\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_string(np, "fimc_is_front_eeprom_scl",(const char **) &gpio->scl); + if (ret) { + err("front eeprom gpio: fail to read, fimc_is_front_eeprom_scl\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_string(np, "fimc_is_front_eeprom_pinname",(const char **) &gpio->pinname); + if (ret) { + err("front eeprom gpio: fail to read, fimc_is_front_eeprom_pinname\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_on", &gpio->pinfunc_on); + if (ret) { + err("rear eeprom gpio: fail to read, pinfunc_on\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_off", &gpio->pinfunc_off); + if (ret) { + err("rear eeprom gpio: fail to read, pinfunc_off\n"); + ret = -ENODEV; + goto p_err; + } + + info("[%s eeprom] sda = %s, scl = %s, pinname = %s, pinfunc_on = %d, pinfunc_off = %d\n", "front", + gpio->sda, gpio->scl, gpio->pinname, gpio->pinfunc_on, gpio->pinfunc_off); } } else { err("no eeprom driver"); @@ -101,8 +141,6 @@ int fimc_is_eeprom_parse_dt(struct i2c_client *client) goto p_err; } - info("[%s eeprom] sda = %s, scl = %s, pinname = %s\n", device->driver_data == REAR_DATA?"rear":"front", gpio->sda, gpio->scl, gpio->pinname); - p_err: return ret; } diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.h index e90e02c666c5..8198016c3ac0 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.h +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-eeprom.h @@ -11,9 +11,12 @@ */ struct fimc_is_eeprom_gpio { + bool use_i2c_pinctrl; char *sda; char *scl; char *pinname; + int pinfunc_on; + int pinfunc_off; }; struct fimc_is_device_eeprom { diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.c new file mode 100644 index 000000000000..5716aa63f5e5 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.c @@ -0,0 +1,183 @@ +/* + * driver for FIMC-IS FROM SPI + * + * Copyright (c) 2011, Samsung Electronics. All rights reserved + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include + +#include "fimc-is-core.h" +#include "fimc-is-regs.h" + +int fimc_is_spi_write(struct fimc_is_spi *spi, u32 addr, u8 *data, size_t size) +{ + int ret = 0; + u8 tx_buf[512]; + int i = 0; + + tx_buf[0] = 0x02; /* write cmd */ + tx_buf[1] = (addr & 0xFF0000) >> 16; /* address */ + tx_buf[2] = (addr & 0xFF00) >> 8; /* address */ + tx_buf[3] = (addr & 0xFF); /* address */ + + for (i = 0; i < size; i++) { + tx_buf[i + 4] = *(data+ i); + } + + ret = spi_write(spi->device, &tx_buf[0], i + 4); + if (ret) + err("spi sync error - can't read data"); + + return ret; +} + +int fimc_is_spi_write_enable(struct fimc_is_spi *spi) +{ + int ret = 0; + u8 tx_buf; + + tx_buf = 0x06; /* write enable cmd */ + + ret = spi_write(spi->device, &tx_buf, 1); + if (ret) + err("spi sync error - can't read data"); + + return ret; +} + +int fimc_is_spi_write_disable(struct fimc_is_spi *spi) +{ + int ret = 0; + u8 tx_buf; + + tx_buf = 0x04; /* write disable cmd */ + + ret = spi_write(spi->device, &tx_buf, 1); + if (ret) + err("spi sync error - can't read data"); + + return ret; +} + +int fimc_is_spi_read_status_bit(struct fimc_is_spi *spi, u8 *buf) +{ + unsigned char req_data; + int ret; + + struct spi_transfer t_c; + struct spi_transfer t_r; + struct spi_message m; + + memset(&t_c, 0x00, sizeof(t_c)); + memset(&t_r, 0x00, sizeof(t_r)); + + req_data = 0x05; /* read status cmd */ + + t_c.tx_buf = &req_data; + t_c.len = 1; + t_c.cs_change = 1; + t_c.bits_per_word = 8; + + t_r.rx_buf = buf; + t_r.len = 1; + t_r.cs_change = 0; + t_r.bits_per_word = 8; + + spi_message_init(&m); + spi_message_add_tail(&t_c, &m); + spi_message_add_tail(&t_r, &m); + + ret = spi_sync(spi->device, &m); + if (ret) { + err("spi sync error - can't read data"); + return -EIO; + } else { + return 0; + } +} + +int fimc_is_spi_erase_block(struct fimc_is_spi *spi, u32 addr) +{ + int ret = 0; + u8 tx_buf[4]; + + tx_buf[0] = 0xD8; /* erase cmd */ + tx_buf[1] = (addr & 0xFF0000) >> 16; /* address */ + tx_buf[2] = (addr & 0xFF00) >> 8; /* address */ + tx_buf[3] = (addr & 0xFF); /* address */ + + ret = spi_write(spi->device, &tx_buf[0], 4); + if (ret) + err("spi sync error - can't read data"); + + return ret; +} + +int fimc_is_spi_erase_sector(struct fimc_is_spi *spi, u32 addr) +{ + int ret = 0; + u8 tx_buf[4]; + + tx_buf[0] = 0x20; /* erase cmd */ + tx_buf[1] = (addr & 0xFF0000) >> 16; /* address */ + tx_buf[2] = (addr & 0xFF00) >> 8; /* address */ + tx_buf[3] = (addr & 0xFF); /* address */ + + ret = spi_write(spi->device, &tx_buf[0], 4); + if (ret) + err("spi sync error - can't read data"); + + return ret; +} + +int fimc_is_spi_read_module_id(struct fimc_is_spi *spi, void *buf, u16 addr, size_t size) +{ + unsigned char req_data[4] = { 0x90, }; + int ret; + + struct spi_transfer t_c; + struct spi_transfer t_r; + + struct spi_message m; + + memset(&t_c, 0x00, sizeof(t_c)); + memset(&t_r, 0x00, sizeof(t_r)); + + req_data[1] = (addr & 0xFF00) >> 8; + req_data[2] = (addr & 0xFF); + + t_c.tx_buf = req_data; + t_c.len = 4; + t_c.cs_change = 1; + t_c.bits_per_word = 32; + + t_r.rx_buf = buf; + t_r.len = (u32)size; + + spi_message_init(&m); + spi_message_add_tail(&t_c, &m); + spi_message_add_tail(&t_r, &m); + + spi->device->max_speed_hz = 48000000; + ret = spi_sync(spi->device, &m); + if (ret) { + err("spi sync error - can't read data"); + return -EIO; + } else { + return 0; + } +} + +MODULE_DESCRIPTION("FIMC-IS FROM SPI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.h new file mode 100644 index 000000000000..c103d439faad --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-from.h @@ -0,0 +1,22 @@ +/* + * Samsung Exynos5 SoC series FIMC-IS-FROM driver + * + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd + * + * 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 FIMC_IS_FROM_H +#define FIMC_IS_FROM_H + +int fimc_is_spi_write(struct fimc_is_spi *spi, u32 addr, u8 *data, size_t size); +int fimc_is_spi_write_enable(struct fimc_is_spi *spi); +int fimc_is_spi_write_disable(struct fimc_is_spi *spi); +int fimc_is_spi_erase_sector(struct fimc_is_spi *spi, u32 addr); +int fimc_is_spi_erase_block(struct fimc_is_spi *spi, u32 addr); +int fimc_is_spi_read_status_bit(struct fimc_is_spi *spi, u8 *buf); +int fimc_is_spi_read_module_id(struct fimc_is_spi *spi, void *buf, u16 addr, size_t size); +#endif diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.c index c758afac764a..a791d47f8e12 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.c @@ -73,25 +73,31 @@ static bool not_crc_bin; static struct task_struct *ois_ts; #endif -static void fimc_is_ois_i2c_config(struct i2c_client *client, bool onoff) +static int fimc_is_ois_i2c_config(struct i2c_client *client, bool onoff) { struct pinctrl *pinctrl_i2c = NULL; struct device *i2c_dev = client->dev.parent->parent; - struct fimc_is_device_ois *ois_device = i2c_get_clientdata(client); + struct fimc_is_device_ois *ois_device; struct fimc_is_ois_gpio *gpio; + if (!client) { + pr_info("%s: client is null\n", __func__); + return -ENODEV; + } + + ois_device = i2c_get_clientdata(client); gpio = &ois_device->gpio; if (ois_device->ois_hsi2c_status != onoff) { - info("%s : ois_hsi2c_stauts(%d),onoff(%d)\n",__func__, - ois_device->ois_hsi2c_status, onoff); - + info("%s : ois_hsi2c_stauts(%d),onoff(%d), use_i2c_pinctrl(%d)\n", + __func__, ois_device->ois_hsi2c_status, onoff, gpio->use_i2c_pinctrl); if (onoff) { - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + } pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c"); if (IS_ERR_OR_NULL(pinctrl_i2c)) { printk(KERN_ERR "%s: Failed to configure i2c pin\n", __func__); @@ -105,15 +111,17 @@ static void fimc_is_ois_i2c_config(struct i2c_client *client, bool onoff) } else { devm_pinctrl_put(pinctrl_i2c); } - - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + } } ois_device->ois_hsi2c_status = onoff; } + return 0; } int fimc_is_ois_i2c_read(struct i2c_client *client, u16 addr, u8 *data) @@ -1030,6 +1038,8 @@ bool fimc_is_ois_fw_version(struct fimc_is_core *core) memcpy(ois_minfo.header_ver, version, 6); core->ois_ver_read = true; + fimc_is_ois_fw_status(core); + return true; exit: @@ -1393,10 +1403,10 @@ u8 fimc_is_ois_read_cal_checksum(struct fimc_is_core *core) return status; } -void fimc_is_ois_fw_status(struct fimc_is_core *core, u8 *checksum, u8 *caldata) +void fimc_is_ois_fw_status(struct fimc_is_core *core) { - *checksum = fimc_is_ois_read_status(core); - *caldata = fimc_is_ois_read_cal_checksum(core); + ois_minfo.checksum = fimc_is_ois_read_status(core); + ois_minfo.caldata = fimc_is_ois_read_cal_checksum(core); return; } @@ -1735,29 +1745,47 @@ int fimc_is_ois_parse_dt(struct i2c_client *client) struct device_node *np = client->dev.of_node; gpio = &device->gpio; + gpio->use_i2c_pinctrl = of_property_read_bool(np, "use_i2c_pinctrl"); - ret = of_property_read_string(np, "fimc_is_ois_sda", (const char **) &gpio->sda); - if (ret) { - err("ois gpio: fail to read, ois_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + if(gpio->use_i2c_pinctrl) { + ret = of_property_read_string(np, "fimc_is_ois_sda", (const char **) &gpio->sda); + if (ret) { + err("ois gpio: fail to read, ois_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - ret = of_property_read_string(np, "fimc_is_ois_scl",(const char **) &gpio->scl); - if (ret) { - err("ois gpio: fail to read, ois_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + ret = of_property_read_string(np, "fimc_is_ois_scl",(const char **) &gpio->scl); + if (ret) { + err("ois gpio: fail to read, ois_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - ret = of_property_read_string(np, "fimc_is_ois_pinname",(const char **) &gpio->pinname); - if (ret) { - err("ois gpio: fail to read, ois_parse_dt\n"); - ret = -ENODEV; - goto p_err; - } + ret = of_property_read_string(np, "fimc_is_ois_pinname",(const char **) &gpio->pinname); + if (ret) { + err("ois gpio: fail to read, ois_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } - info("[OIS] sda = %s, scl = %s, pinname = %s\n", gpio->sda, gpio->scl, gpio->pinname); + ret = of_property_read_u32(np, "pinfunc_on", &gpio->pinfunc_on); + if (ret) { + err("af gpio: fail to read, ois_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } + + ret = of_property_read_u32(np, "pinfunc_off", &gpio->pinfunc_off); + if (ret) { + err("af gpio: fail to read, ois_parse_dt\n"); + ret = -ENODEV; + goto p_err; + } + + info("[OIS] sda = %s, scl = %s, pinname = %s, pinfunc_on = %d, pinfunc_off = %d\n", + gpio->sda, gpio->scl, gpio->pinname, gpio->pinfunc_on, gpio->pinfunc_off); + } p_err: return ret; @@ -1819,14 +1847,17 @@ static int fimc_is_ois_probe(struct i2c_client *client, } gpio = &device->gpio; - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_PUD, 0)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_PUD, 0)); + + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_PUD, 0)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_PUD, 0)); + } return 0; } diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.h index 9761c9ffb614..219e3855e39b 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.h +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-device-ois.h @@ -11,9 +11,12 @@ */ struct fimc_is_ois_gpio { + bool use_i2c_pinctrl; char *sda; char *scl; char *pinname; + int pinfunc_on; + int pinfunc_off; }; struct fimc_is_device_ois { @@ -35,6 +38,8 @@ struct fimc_is_ois_exif { struct fimc_is_ois_info { char header_ver[7]; char load_fw_name[50]; + u8 checksum; + u8 caldata; }; int fimc_is_ois_i2c_read(struct i2c_client *client, u16 addr, u8 *data); @@ -59,4 +64,4 @@ void fimc_is_ois_init_thread(struct fimc_is_core *core); bool fimc_is_ois_read_userdata(struct fimc_is_core *core); void fimc_is_ois_exif_data(struct fimc_is_core *core); int fimc_is_ois_get_exif_data(struct fimc_is_ois_exif **exif_info); -void fimc_is_ois_fw_status(struct fimc_is_core *core, u8 *checksum, u8 *caldata); +void fimc_is_ois_fw_status(struct fimc_is_core *core); diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-front-c2-4e6_v003.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-front-c2-4e6_v003.h new file mode 100644 index 000000000000..1687ea01f9e3 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-front-c2-4e6_v003.h @@ -0,0 +1,57 @@ +#ifndef FIMC_IS_EEPROM_FRONT_C2_4E6_V003_H +#define FIMC_IS_EEPROM_FRONT_C2_4E6_V003_H + +/* Header referenced section */ +#define EEP_HEADER_VERSION_START_ADDR_FRONT 0x30 +#define EEP_HEADER_CAL_MAP_VER_START_ADDR_FRONT 0x40 +#define EEP_HEADER_OEM_START_ADDR_FRONT 0x0 +#define EEP_HEADER_OEM_END_ADDR_FRONT 0x4 +#define EEP_HEADER_AWB_START_ADDR_FRONT 0x8 +#define EEP_HEADER_AWB_END_ADDR_FRONT 0xC +#define EEP_HEADER_AP_SHADING_START_ADDR_FRONT 0x18 +#define EEP_HEADER_AP_SHADING_END_ADDR_FRONT 0x1C +#define EEP_HEADER_C2_SHADING_START_ADDR_FRONT 0x10 +#define EEP_HEADER_C2_SHADING_END_ADDR_FRONT 0x14 +#define EEP_HEADER_PROJECT_NAME_START_ADDR_FRONT 0x4C + +/* C2 Shading referenced section */ +#define EEP_C2_SHADING_VER_START_ADDR_FRONT 0x1D00 +#define EEP_C2_SHADING_LSC_I0_GAIN_ADDR_FRONT 0x1A02 +#define EEP_C2_SHADING_LSC_J0_GAIN_ADDR_FRONT 0x1A0A +#define EEP_C2_SHADING_LSC_A_GAIN_ADDR_FRONT 0x1A12 +#define EEP_C2_SHADING_LSC_K4_GAIN_ADDR_FRONT 0x1A22 +#define EEP_C2_SHADING_LSC_SCALE_GAIN_ADDR_FRONT 0x1A32 +#define EEP_C2_SHADING_GRASTUNING_AWB_ASH_CORD_ADDR_FRONT 0x1A3A +#define EEP_C2_SHADING_GRASTUNING_AWB_ASH_CORD_INDEX_ADDR_FRONT 0x1A48 +#define EEP_C2_SHADING_GRASTUNING_GAS_ALPHA_ADDR_FRONT 0x1A56 +#define EEP_C2_SHADING_GRASTUNING_GAS_BETA_ADDR_FRONT 0x1A8E +#define EEP_C2_SHADING_GRASTUNING_GAS_OUTDOOR_ALPHA_ADDR_FRONT 0x1AC6 +#define EEP_C2_SHADING_GRASTUNING_GAS_OUTDOOR_BETA_ADDR_FRONT 0x1ACE +#define EEP_C2_SHADING_GRASTUNING_GAS_INDOOR_ALPHA_ADDR_FRONT 0x1AD6 +#define EEP_C2_SHADING_GRASTUNING_GAS_INDOOR_BETA_ADDR_FRONT 0x1ADE +#define EEP_C2_SHADING_LSC_GAIN_START_ADDR_FRONT 0x0306 +#define EEP_C2_SHADING_LSC_GAIN_END_ADDR_FRONT 0x19FD +#define EEP_C2_SHADING_LSC_GAIN_CRC_ADDR_FRONT 0x19FE +#define EEP_C2_SHADING_LSC_PARAMETER_CRC_ARRD_FRONT 0x1AE6 + +/* OEM referenced section */ +#define EEP_OEM_VER_START_ADDR_FRONT 0x150 + +/* AWB referenced section */ +#define EEP_AWB_VER_START_ADDR_FRONT 0x220 + +/* AP Shading referenced section */ +#define EEP_AP_SHADING_VER_START_ADDR_FRONT 0X3B00 + +/* Checksum referenced section */ +#define EEP_CHECKSUM_HEADER_ADDR_FRONT 0xFC +#define EEP_CHECKSUM_OEM_ADDR_FRONT 0x1FC +#define EEP_CHECKSUM_AWB_ADDR_FRONT 0x2FC +#define EEP_CHECKSUM_AP_SHADING_ADDR_FRONT 0x3BFC +#define EEP_CHECKSUM_C2_SHADING_ADDR_FRONT 0x1FFC + +/* etc section */ +#define FIMC_IS_MAX_CAL_SIZE_FRONT (16 * 1024) +#define HEADER_CRC32_LEN_FRONT (0x70) + +#endif /* FIMC_IS_EEPROM_FRONT_C2_4E6_V003_H */ diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-rear-4h5_v002.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-rear-4h5_v002.h new file mode 100644 index 000000000000..c2f6d2af8bcd --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-eeprom-rear-4h5_v002.h @@ -0,0 +1,37 @@ +#ifndef FIMC_IS_EEPROM_REAR_4H5_V002_H +#define FIMC_IS_EEPROM_REAR_4H5_V002_H + +/* Header referenced section */ +#define EEP_HEADER_VERSION_START_ADDR 0x20 +#define EEP_HEADER_CAL_MAP_VER_START_ADDR 0x30 +#define EEP_HEADER_OEM_START_ADDR 0x0 +#define EEP_HEADER_OEM_END_ADDR 0x4 +#define EEP_HEADER_AWB_START_ADDR 0x8 +#define EEP_HEADER_AWB_END_ADDR 0xC +#define EEP_HEADER_AP_SHADING_START_ADDR 0x10 +#define EEP_HEADER_AP_SHADING_END_ADDR 0x14 +#define EEP_HEADER_PROJECT_NAME_START_ADDR 0x38 + +/* OEM referenced section */ +#define EEP_OEM_VER_START_ADDR 0x150 + +/* AWB referenced section */ +#define EEP_AWB_VER_START_ADDR 0x220 + +/* AP Shading referenced section */ +#define EEP_AP_SHADING_VER_START_ADDR 0X1D00 + +/* Checksum referenced section */ +#define EEP_CHECKSUM_HEADER_ADDR 0xFC +#define EEP_CHECKSUM_OEM_ADDR 0x1FC +#define EEP_CHECKSUM_AWB_ADDR 0x2FC +#define EEP_CHECKSUM_AP_SHADING_ADDR 0x3BFC +#define EEP_CHECKSUM_C2_SHADING_ADDR 0x1FFC + +/* etc section */ +#define FIMC_IS_MAX_CAL_SIZE (8 * 1024) +#define FIMC_IS_MAX_FW_SIZE (8 * 1024) +#define FIMC_IS_MAX_SETFILE_SIZE (1120 * 1024) +#define HEADER_CRC32_LEN (80) + +#endif /* FIMC_IS_EEPROM_REAR_4H5_V002_H */ diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c1-2p2_v005.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c1-2p2_v005.h new file mode 100644 index 000000000000..f0cffd92db0a --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c1-2p2_v005.h @@ -0,0 +1,98 @@ +#ifndef FIMC_IS_FROM_REAR_C1_2P2_V005_H +#define FIMC_IS_FROM_REAR_C1_2P2_V005_H + +/* Header referenced section */ +#define FROM_HEADER_VERSION_START_ADDR 0x40 +#define FROM_HEADER_MODULE_ID_START_ADDR 0x0 +#define FROM_HEADER_MODULE_ID_SIZE 0x2 +#define FROM_HEADER_CAL_MAP_VER_START_ADDR 0x60 +#define FROM_HEADER_ISP_SETFILE_VER_START_ADDR 0x64 +#define FROM_HEADER_PROJECT_NAME_START_ADDR 0x6E +#define FROM_HEADER_CONCORD_HEADER_VER_START_ADDR 0x50 +#define FROM_HEADER_ISP_BINARY_START_ADDR 0x0 +#define FROM_HEADER_ISP_BINARY_END_ADDR 0x4 +#define FROM_HEADER_OEM_START_ADDR 0x8 +#define FROM_HEADER_OEM_END_ADDR 0xC +#define FROM_HEADER_AWB_START_ADDR 0x10 +#define FROM_HEADER_AWB_END_ADDR 0x14 +#define FROM_HEADER_SHADING_START_ADDR 0x18 +#define FROM_HEADER_SHADING_END_ADDR 0x1C +#define FROM_HEADER_ISP_SETFILE_START_ADDR 0x20 +#define FROM_HEADER_ISP_SETFILE_END_ADDR 0x24 +#define FROM_HEADER_CONCORD_CAL_START_ADDR 0x28 +#define FROM_HEADER_CONCORD_CAL_END_ADDR 0x2C +#define FROM_HEADER_CONCORD_BINARY_START_ADDR 0x30 +#define FROM_HEADER_CONCORD_BINARY_END_ADDR 0x34 +#define FROM_HEADER_CONCORD_MASTER_SETFILE_START_ADDR 0xA8 +#define FROM_HEADER_CONCORD_MASTER_SETFILE_END_ADDR 0xAC +#define FROM_HEADER_CONCORD_MODE_SETFILE_START_ADDR 0xA8 +#define FROM_HEADER_CONCORD_MODE_SETFILE_END_ADDR 0xAC +#define FROM_HEADER_PDAF_CAL_START_ADDR 0xB0 +#define FROM_HEADER_PDAF_CAL_END_ADDR 0xB4 + +/* Shading referenced section */ +#define FROM_SHADING_LSC_I0_GAIN_ADDR 0x3006 +#define FROM_SHADING_LSC_J0_GAIN_ADDR 0x3008 +#define FROM_SHADING_LSC_A_GAIN_ADDR 0x300A +#define FROM_SHADING_LSC_K4_GAIN_ADDR 0x300E +#define FROM_SHADING_LSC_SCALE_GAIN_ADDR 0x3012 +#define FROM_SHADING_LSC_GAIN_START_ADDR 0x3014 +#define FROM_SHADING_LSC_GAIN_END_ADDR 0x49DB +#define FROM_SHADING_VER_START_ADDR 0x4FE0 + +/* Concord cal referenced section */ +#define FROM_CONCORD_CAL_PDAF_START_ADDR 0x9000 +#define FROM_CONCORD_CAL_PDAF_END_ADDR 0x91FF +#define FROM_CONCORD_XTALK_10_START_ADDR 0x9210 +#define FROM_CONCORD_XTALK_10_END_ADDR 0xA1CF +#define FROM_CONCORD_XTALK_20_START_ADDR 0xA210 +#define FROM_CONCORD_XTALK_20_END_ADDR 0xB1CF +#define FROM_CONCORD_XTALK_30_START_ADDR 0xB210 +#define FROM_CONCORD_XTALK_30_END_ADDR 0xC1CF +#define FROM_CONCORD_XTALK_40_START_ADDR 0xC210 +#define FROM_CONCORD_XTALK_40_END_ADDR 0xD1CF +#define FROM_CONCORD_XTALK_50_START_ADDR 0xD210 +#define FROM_CONCORD_XTALK_50_END_ADDR 0xE1CF +#define FROM_CONCORD_XTALK_60_START_ADDR 0xE210 +#define FROM_CONCORD_XTALK_60_END_ADDR 0xE20F +#define FROM_CONCORD_WCOEF_ADDR 0xF210 + +/* OEM referenced section */ +#define FROM_OEM_AF_INF_ADDR 0x1000 +#define FROM_OEM_AF_INF_ADDR 0x1008 +#define FROM_OEM_VER_START_ADDR 0x1FE0 + +/* AWB referenced section */ +#define FROM_AWB_VER_START_ADDR 0x2FE0 + +/* Companion Checksum referenced section */ +#define FROM_CONCORD_XTALK_10_CHECKSUM_ADDR 0xF21A +#define FROM_CONCORD_XTALK_20_CHECKSUM_ADDR 0xF21E +#define FROM_CONCORD_XTALK_30_CHECKSUM_ADDR 0xF222 +#define FROM_CONCORD_XTALK_40_CHECKSUM_ADDR 0xF226 +#define FROM_CONCORD_XTALK_50_CHECKSUM_ADDR 0xF22A +#define FROM_CONCORD_XTALK_60_CHECKSUM_ADDR 0xF22E +#define FROM_SHADING_LSC_GAIN_CRC_ADDR 0x49DC +#define FROM_CONCORD_PDAF_CRC_ADDR 0x9200 + +/* ISP binary referenced section */ +#define FROM_ISP_BINARY_SETFILE_START_ADDR 0x8000 +#define FROM_ISP_BINARY_SETFILE_END_ADDR 0x3FFFFF + +/* Checksum referenced section */ +#define FROM_CHECKSUM_HEADER_ADDR 0xFFC +#define FROM_CHECKSUM_OEM_ADDR 0x1FFC +#define FROM_CHECKSUM_AWB_ADDR 0x2FFC +#define FROM_CHECKSUM_SHADING_ADDR 0x4FFC +#define FROM_CHECKSUM_PAF_CAL_ADDR 0x8FFC +#define FROM_CHECKSUM_CONCORD_CAL_ADDR 0xFFFC + +/* etc section */ +#define FIMC_IS_MAX_CAL_SIZE (64 * 1024) +#define FIMC_IS_MAX_COMPANION_FW_SIZE (200 * 1024) +#define FIMC_IS_FROM_ERASE_SIZE (64 * 1024) +#define FIMC_IS_MAX_FW_SIZE (2750 * 1024) +#define FIMC_IS_MAX_SETFILE_SIZE (1120 * 1024) +#define HEADER_CRC32_LEN (224) + +#endif /* FIMC_IS_FROM_REAR_C1_2P2_V005_H */ \ No newline at end of file diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c2-imx240_v003.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c2-imx240_v003.h new file mode 100644 index 000000000000..3b41ea3edf70 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-from-rear-c2-imx240_v003.h @@ -0,0 +1,94 @@ +#ifndef FIMC_IS_FROM_REAR_C2_IMX240_V003_H +#define FIMC_IS_FROM_REAR_C2_IMX240_V003_H + +/* Header referenced section */ +#define FROM_HEADER_VERSION_START_ADDR 0x40 +#define FROM_HEADER_MODULE_ID_START_ADDR 0x0 +#define FROM_HEADER_MODULE_ID_SIZE 0x2 +#define FROM_HEADER_CAL_MAP_VER_START_ADDR 0x60 +#define FROM_HEADER_ISP_SETFILE_VER_START_ADDR 0x64 +#define FROM_HEADER_PROJECT_NAME_START_ADDR 0x6E +#define FROM_HEADER_CONCORD_HEADER_VER_START_ADDR 0x50 +#define FROM_HEADER_ISP_BINARY_START_ADDR 0x0 +#define FROM_HEADER_ISP_BINARY_END_ADDR 0x4 +#define FROM_HEADER_OEM_START_ADDR 0x8 +#define FROM_HEADER_OEM_END_ADDR 0xC +#define FROM_HEADER_AWB_START_ADDR 0x10 +#define FROM_HEADER_AWB_END_ADDR 0x14 +#define FROM_HEADER_SHADING_START_ADDR 0x18 +#define FROM_HEADER_SHADING_END_ADDR 0x1C +#define FROM_HEADER_ISP_SETFILE_START_ADDR 0x20 +#define FROM_HEADER_ISP_SETFILE_END_ADDR 0x24 +#define FROM_HEADER_CONCORD_CAL_START_ADDR 0x28 +#define FROM_HEADER_CONCORD_CAL_END_ADDR 0x2C +#define FROM_HEADER_CONCORD_BINARY_START_ADDR 0x30 +#define FROM_HEADER_CONCORD_BINARY_END_ADDR 0x34 +#define FROM_HEADER_CONCORD_MASTER_SETFILE_START_ADDR 0xA8 +#define FROM_HEADER_CONCORD_MASTER_SETFILE_END_ADDR 0xAC +#define FROM_HEADER_CONCORD_MODE_SETFILE_START_ADDR 0xA8 +#define FROM_HEADER_CONCORD_MODE_SETFILE_END_ADDR 0xAC +#define FROM_HEADER_PDAF_CAL_START_ADDR 0xB0 +#define FROM_HEADER_PDAF_CAL_END_ADDR 0xB4 + +/* Shading referenced section */ +#define FROM_SHADING_LSC_I0_GAIN_ADDR 0x4702 +#define FROM_SHADING_LSC_J0_GAIN_ADDR 0x470A +#define FROM_SHADING_LSC_A_GAIN_ADDR 0x4712 +#define FROM_SHADING_LSC_K4_GAIN_ADDR 0x4722 +#define FROM_SHADING_LSC_SCALE_GAIN_ADDR 0x4732 +#define FROM_SHADING_GRASTUNING_AWB_ASH_CORD_ADDR 0x473A +#define FROM_SHADING_GRASTUNING_AWB_ASH_CORD_INDEX_ADDR 0x4748 +#define FROM_SHADING_GRASTUNING_GAS_ALPHA_ADDR 0x4756 +#define FROM_SHADING_GRASTUNING_GAS_BETA_ADDR 0x478E +#define FROM_SHADING_GRASTUNING_GAS_OUTDOOR_ALPHA_ADDR 0x47C6 +#define FROM_SHADING_GRASTUNING_GAS_OUTDOOR_BETA_ADDR 0x47CE +#define FROM_SHADING_GRASTUNING_GAS_INDOOR_ALPHA_ADDR 0x47D6 +#define FROM_SHADING_GRASTUNING_GAS_INDOOR_BETA_ADDR 0x47DE +#define FROM_SHADING_LSC_GAIN_START_ADDR 0x3006 +#define FROM_SHADING_LSC_GAIN_END_ADDR 0x46FD +#define FROM_SHADING_VER_START_ADDR 0x4FE0 + +/* Concord cal referenced section */ +#define FROM_CONCORD_CAL_PDAF_START_ADDR 0x9000 +#define FROM_CONCORD_CAL_PDAF_END_ADDR 0x91FF +#define FROM_CONCORD_CAL_PDAF_SHADING_START_ADDR 0x9204 +#define FROM_CONCORD_CAL_PDAF_SHADING_END_ADDR 0x9623 +#define FROM_CONCORD_XTALK_COEF_ADDR 0x9640 +#define FROM_CONCORD_COEF_OFFSET_R_ADDR 0xEA40 +#define FROM_CONCORD_COEF_OFFSET_G_ADDR 0xEA42 +#define FROM_CONCORD_COEF_OFFSET_B_ADDR 0xEA44 + +/* OEM referenced section */ +#define FROM_OEM_VER_START_ADDR 0x1FE0 + +/* AWB referenced section */ +#define FROM_AWB_VER_START_ADDR 0x2FE0 + +/* Companion Checksum referenced section */ +#define FROM_SHADING_LSC_GAIN_CRC_ADDR 0x46FE +#define FROM_CONCORD_PDAF_CRC_ADDR 0x9200 +#define FROM_CONCORD_PDAF_SHAD_CRC_ADDR 0x9624 +#define FROM_CONCORD_XTALK_COEF_CRC_ADDR 0xEA46 +#define FROM_SHADING_LSC_PARAMETER_CRC_ARRD 0x47EA + +/* ISP binary referenced section */ +#define FROM_ISP_BINARY_SETFILE_START_ADDR 0x8000 +#define FROM_ISP_BINARY_SETFILE_END_ADDR 0x3FFFFF + +/* Checksum referenced section */ +#define FROM_CHECKSUM_HEADER_ADDR 0xFFC +#define FROM_CHECKSUM_OEM_ADDR 0x1FFC +#define FROM_CHECKSUM_AWB_ADDR 0x2FFC +#define FROM_CHECKSUM_SHADING_ADDR 0x4FFC +#define FROM_CHECKSUM_PAF_CAL_ADDR 0x8FFC +#define FROM_CHECKSUM_CONCORD_CAL_ADDR 0xFFFC + +/* etc section */ +#define FIMC_IS_MAX_CAL_SIZE (64 * 1024) +#define FIMC_IS_MAX_COMPANION_FW_SIZE (200 * 1024) +#define FIMC_IS_FROM_ERASE_SIZE (64 * 1024) +#define FIMC_IS_MAX_FW_SIZE (2750 * 1024) +#define FIMC_IS_MAX_SETFILE_SIZE (1120 * 1024) +#define HEADER_CRC32_LEN (224) + +#endif /* FIMC_IS_FROM_REAR_C2_IMX240_V003_H */ \ No newline at end of file diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-i2c.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-i2c.c index 1fa3ae3ca584..0acd457b4f53 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-i2c.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-i2c.c @@ -35,7 +35,9 @@ static int fimc_is_i2c0_probe(struct i2c_client *client, if (!core) panic("core is NULL"); +#if defined(CONFIG_COMPANION_USE) core->client0 = client; +#endif pr_info("%s %s: fimc_is_i2c0 driver probed!\n", dev_driver_string(&client->dev), dev_name(&client->dev)); diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.c index ee84859e001c..3a22470b61e6 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.c @@ -53,7 +53,8 @@ bool companion_front_lsc_isvalid = false; //static bool is_caldata_read = false; //static bool is_c1_caldata_read = false; -static bool force_caldata_dump = false; +bool force_caldata_dump = false; + static int cam_id = CAMERA_SINGLE_REAR; bool is_dumped_fw_loading_needed = false; bool is_dumped_c1_fw_loading_needed = false; @@ -72,8 +73,10 @@ static char cal_buf_front[FIMC_IS_MAX_CAL_SIZE_FRONT]; #endif static char cal_buf[FIMC_IS_MAX_CAL_SIZE]; +#ifdef CAMERA_MODULE_DUALIZE static char fw_buf[FIMC_IS_MAX_FW_SIZE]; -char loaded_fw[12] = {0, }; +#endif +char loaded_fw[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; char loaded_companion_fw[30] = {0, }; bool fimc_is_sec_get_force_caldata_dump(void) @@ -133,12 +136,24 @@ int fimc_is_sec_get_loaded_fw(char **buf) return 0; } +int fimc_is_sec_set_loaded_fw(char *buf) +{ + strncpy(loaded_fw, buf, FIMC_IS_HEADER_VER_SIZE); + return 0; +} + int fimc_is_sec_get_loaded_c1_fw(char **buf) { *buf = &loaded_companion_fw[0]; return 0; } +int fimc_is_sec_set_loaded_c1_fw(char *buf) +{ + strncpy(loaded_companion_fw, buf, FIMC_IS_HEADER_VER_SIZE); + return 0; +} + int fimc_is_sec_set_camid(int id) { cam_id = id; @@ -287,6 +302,7 @@ bool fimc_is_sec_check_from_ver(struct fimc_is_core *core, int position) return true; } } + bool fimc_is_sec_check_cal_crc32(char *buf, int id) { u32 *buf32 = NULL; @@ -294,6 +310,7 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) u32 check_base; u32 check_length; u32 checksum_base; + u32 address_boundary; bool crc32_temp, crc32_header_temp; struct fimc_is_from_info *finfo = NULL; struct fimc_is_companion_retention *ret_data; @@ -306,8 +323,18 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) crc32_temp = true; #ifdef CONFIG_COMPANION_USE - crc32_c1_check = true; + if (id == SENSOR_POSITION_REAR) + crc32_c1_check = false; +#endif + +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) + if (id == SENSOR_POSITION_FRONT) { + address_boundary = FIMC_IS_MAX_CAL_SIZE_FRONT; + } else #endif + { + address_boundary = FIMC_IS_MAX_CAL_SIZE; + } /* Header data */ check_base = 0; @@ -315,32 +342,31 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (id == SENSOR_POSITION_FRONT) { finfo = &sysfs_finfo_front; - checksum_base = ((check_base & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_HEADER_ADDR_FRONT / 4; check_length = HEADER_CRC32_LEN_FRONT; } else #endif { finfo = &sysfs_finfo; #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) - checksum_base = ((check_base & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_HEADER_ADDR / 4; #else - checksum_base = ((check_base & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_HEADER_ADDR / 4; #endif check_length = HEADER_CRC32_LEN; } checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the header (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the header (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; crc32_header_temp = false; - } else if (checksum_base > 0x80000) { - err("Camera: Header checksum address has error(0x%08X)", checksum_base * 4); + goto out; } else { crc32_header_temp = true; } +#if defined(EEP_HEADER_OEM_START_ADDR_FRONT) /* OEM */ check_base = finfo->oem_start_addr / 4; checksum = 0; @@ -348,26 +374,31 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (id == SENSOR_POSITION_FRONT) { - checksum_base = ((finfo->oem_end_addr & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_OEM_ADDR_FRONT / 4; } else #endif { #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) - checksum_base = ((finfo->oem_end_addr & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_OEM_ADDR / 4; #else - checksum_base = ((finfo->oem_end_addr & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_OEM_ADDR / 4; #endif } - checksum = (u32)getCRC((u16 *)&buf32[check_base], - check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the OEM (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: OEM address has error: start(0x%08X), end(0x%08X)", + finfo->oem_start_addr, finfo->oem_end_addr); + crc32_temp = false; + goto out; + } + + checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the OEM (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: OEM checksum address has error(0x%08X)", checksum_base * 4); + goto out; } +#endif /* AWB */ check_base = finfo->awb_start_addr / 4; @@ -376,25 +407,29 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (id == SENSOR_POSITION_FRONT) { - checksum_base = ((finfo->awb_end_addr & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_AWB_ADDR_FRONT / 4; } else #endif { #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) - checksum_base = ((finfo->awb_end_addr & 0xffffff00) + 0xfc) / 4; + checksum_base = EEP_CHECKSUM_AWB_ADDR / 4; #else - checksum_base = ((finfo->awb_end_addr & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_AWB_ADDR / 4; #endif } - checksum = (u32)getCRC((u16 *)&buf32[check_base], - check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the AWB (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: AWB address has error: start(0x%08X), end(0x%08X)", + finfo->awb_start_addr, finfo->awb_end_addr); + crc32_temp = false; + goto out; + } + + checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the AWB (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: AWB checksum address has error(0x%08X)", checksum_base * 4); + goto out; } /* Shading */ @@ -404,25 +439,29 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (id == SENSOR_POSITION_FRONT) { - checksum_base = 0x3BFC / 4; + checksum_base = EEP_CHECKSUM_AP_SHADING_ADDR_FRONT / 4; } else #endif { #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) - checksum_base = 0x1ffc / 4; + checksum_base = EEP_CHECKSUM_AP_SHADING_ADDR / 4; #else - checksum_base = ((0x4FFC & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_SHADING_ADDR / 4; #endif } - checksum = (u32)getCRC((u16 *)&buf32[check_base], - check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the Shading (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: Shading address has error: start(0x%08X), end(0x%08X)", + finfo->shading_start_addr, finfo->shading_end_addr); + crc32_temp = false; + goto out; + } + + checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the Shading (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: Shading checksum address has error(0x%08X)", checksum_base * 4); + goto out; } #ifdef CONFIG_COMPANION_C2_USE @@ -432,14 +471,20 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) checksum = 0; check_length = (finfo->c2_shading_end_addr - finfo->c2_shading_start_addr + 1); - checksum_base = 0x1FFC / 4; + checksum_base = EEP_CHECKSUM_C2_SHADING_ADDR_FRONT / 4; + + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: C2 Shading address has error: start(0x%08X), end(0x%08X)", + finfo->c2_shading_start_addr, finfo->c2_shading_end_addr); + crc32_temp = false; + goto out; + } checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { + if (checksum != buf32[checksum_base]) { err("Camera: CRC32 error at the C2 Shading (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: C2 Shading checksum address has error(0x%08X)", checksum_base * 4); + goto out; } } #endif @@ -450,36 +495,45 @@ bool fimc_is_sec_check_cal_crc32(char *buf, int id) check_base = finfo->pdaf_cal_start_addr / 4; checksum = 0; check_length = (finfo->pdaf_cal_end_addr - finfo->pdaf_cal_start_addr + 1); - checksum_base = ((0x8FFF & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_PAF_CAL_ADDR / 4; + + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: pdaf address has error: start(0x%08X), end(0x%08X)", + finfo->pdaf_start_addr, finfo->pdaf_end_addr); + crc32_temp = false; + goto out; + } - checksum = (u32)getCRC((u16 *)&buf32[check_base], - check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the pdaf cal (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); + checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the pdaf cal (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_temp = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: pdaf cal checksum address has error(0x%08X)", checksum_base * 4); + goto out; } /* concord cal */ check_base = finfo->concord_cal_start_addr / 4; checksum = 0; check_length = (finfo->concord_cal_end_addr - finfo->concord_cal_start_addr + 1); - checksum_base = ((0xFFFC & 0xfffff000) + 0xffc) / 4; + checksum_base = FROM_CHECKSUM_CONCORD_CAL_ADDR / 4; + + if (check_base > address_boundary || checksum_base > address_boundary || check_length <= 0) { + err("Camera: concord cal address has error: start(0x%08X), end(0x%08X)", + finfo->concord_cal_start_addr, finfo->concord_cal_end_addr); + goto out; + } - checksum = (u32)getCRC((u16 *)&buf32[check_base], - check_length, NULL, NULL); - if (checksum_base < 0x80000 && checksum_base > 0 && checksum != buf32[checksum_base]) { - err("Camera: CRC32 error at the concord cal (0x%08X != 0x%08X)", - checksum, buf32[checksum_base]); - crc32_c1_check = false; - } else if (checksum_base > 0x80000 || checksum_base < 0) { - err("Camera: concord cal checksum address has error(0x%08X)", checksum_base * 4); + checksum = (u32)getCRC((u16 *)&buf32[check_base], check_length, NULL, NULL); + if (checksum != buf32[checksum_base]) { + err("Camera: CRC32 error at the concord cal (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); + goto out; + } else { + crc32_c1_check = true; } } #endif +out: #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (id == SENSOR_POSITION_FRONT) { crc32_check_front = crc32_temp; @@ -508,14 +562,14 @@ bool fimc_is_sec_check_fw_crc32(char *buf) info("Camera: Start checking CRC32 FW\n"); - crc32_fw_check = true; - - checksum = (u32)getCRC((u16 *)&buf32[0], (sysfs_finfo.bin_end_addr - sysfs_finfo.bin_start_addr + 1), NULL, NULL); + checksum = (u32)getCRC((u16 *)&buf32[0], sysfs_finfo.fw_size, NULL, NULL); checksum_base = (0x2A8FFC & 0xffffffff) / 4; if (checksum != buf32[checksum_base]) { err("Camera: CRC32 error at the binary section (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_fw_check = false; + } else { + crc32_fw_check = true; } info("Camera: End checking CRC32 FW\n"); @@ -523,6 +577,36 @@ bool fimc_is_sec_check_fw_crc32(char *buf) return crc32_fw_check; } +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_FRONT) +bool fimc_is_sec_check_front_otp_crc32(char *buf) +{ + u32 *buf32 = NULL; + u32 checksum; + bool crc32_temp, crc32_header_temp; + u32 checksumFromOTP; + + buf32 = (u32 *)buf; + checksumFromOTP = buf[41] +( buf[42] << 8) +( buf[43] << 16) + (buf[44] << 24); + + /* Header data */ + checksum = (u32)getCRC((u16 *)&buf32[0], 41, NULL, NULL); + + if(checksum != checksumFromOTP) { + crc32_temp = crc32_header_temp = false; + err("Camera: CRC32 error at the header data section (0x%08X != 0x%08X)", + checksum, checksumFromOTP); + } else { + crc32_temp = crc32_header_temp = true; + pr_info("Camera: End checking CRC32 (0x%08X = 0x%08X)", + checksum, checksumFromOTP); + } + + crc32_check_front = crc32_temp; + crc32_header_check_front = crc32_header_temp; + return crc32_check_front; +} +#endif + bool fimc_is_sec_check_setfile_crc32(char *buf) { u32 *buf32 = NULL; @@ -533,15 +617,14 @@ bool fimc_is_sec_check_setfile_crc32(char *buf) info("Camera: Start checking CRC32 Setfile\n"); - crc32_setfile_check = true; - - checksum = (u32)getCRC((u16 *)&buf32[0], - (sysfs_finfo.setfile_end_addr - sysfs_finfo.setfile_start_addr + 1), NULL, NULL); + checksum = (u32)getCRC((u16 *)&buf32[0], sysfs_finfo.setfile_size, NULL, NULL); checksum_base = (0x1167FC & 0xffffffff) / 4; if (checksum != buf32[checksum_base]) { err("Camera: CRC32 error at the binary section (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_setfile_check = false; + } else { + crc32_setfile_check = true; } info("Camera: End checking CRC32 Setfile\n"); @@ -560,14 +643,14 @@ bool fimc_is_sec_check_companion_fw_crc32(char *buf) info("Camera: Start checking CRC32 Companion FW\n"); - crc32_c1_fw_check = true; - - checksum = (u32)getCRC((u16 *)&buf32[0], (sysfs_finfo.concord_bin_end_addr - sysfs_finfo.concord_bin_start_addr + 1), NULL, NULL); + checksum = (u32)getCRC((u16 *)&buf32[0], sysfs_finfo.comp_fw_size, NULL, NULL); checksum_base = ((0x307FC & 0xffffffff)) / 4; if (checksum != buf32[checksum_base]) { err("Camera: CRC32 error at the binary section (0x%08X != 0x%08X)", checksum, buf32[checksum_base]); crc32_c1_fw_check = false; + } else { + crc32_c1_fw_check = true; } info("Camera: End checking CRC32 Companion FW\n"); @@ -588,7 +671,12 @@ ssize_t write_data_to_file(char *name, char *buf, size_t count, loff_t *pos) old_mask = sys_umask(0); - fd = sys_open(name, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0664); + if (force_caldata_dump) { + sys_rmdir(name); + fd = sys_open(name, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0666); + } else { + fd = sys_open(name, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, 0664); + } if (fd < 0) { err("open file error: %s", name); sys_umask(old_mask); @@ -1019,27 +1107,64 @@ int fimc_is_i2c_read(struct i2c_client *client, void *buf, u32 addr, size_t size return 0; } -int fimc_is_i2c_write(struct i2c_client *client, void *buf, u32 addr, size_t size) +int fimc_is_i2c_write(struct i2c_client *client, u16 addr, u8 data) { - info("%s: do nothing\n", __func__); + const u32 write_buf_size = 3, max_retry = 5; + u8 write_buf[write_buf_size]; + int retries = max_retry; + int ret = 0; + + if (!client) { + pr_info("%s: client is null\n", __func__); + return -ENODEV; + } + + /* Send addr+data */ + write_buf[0] = ((u16)addr) >> 8; + write_buf[1] = (u8)addr; + write_buf[2] = data; + + + for (retries = max_retry; retries > 0; retries--) { + ret = i2c_master_send(client, write_buf, write_buf_size); + if (likely(write_buf_size == ret)) + break; + + pr_info("%s: i2c_master_send failed(%d), try %d\n", __func__, ret, retries); + usleep_range(1000, 1000); + } + + if (unlikely(ret <= 0)) { + pr_err("%s: error %d, fail to write 0x%04X\n", __func__, ret, addr); + return ret ? ret : -ETIMEDOUT; + } + return 0; } -static void fimc_is_i2c_config(struct i2c_client *client, bool onoff) +static int fimc_is_i2c_config(struct i2c_client *client, bool onoff) { struct device *i2c_dev = client->dev.parent->parent; struct pinctrl *pinctrl_i2c = NULL; - struct fimc_is_device_eeprom *eeprom_device = i2c_get_clientdata(client); + struct fimc_is_device_eeprom *eeprom_device; struct fimc_is_eeprom_gpio *gpio; + if (!client) { + pr_info("%s: client is null\n", __func__); + return -ENODEV; + } + + eeprom_device = i2c_get_clientdata(client); gpio = &eeprom_device->gpio; - info("(%s):onoff(%d)\n", __func__, onoff); + info("(%s):onoff(%d) use_i2c_pinctrl(%d)\n", __func__, onoff, gpio->use_i2c_pinctrl); if (onoff) { - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 0)); + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_on)); + } /* ON */ pinctrl_i2c = devm_pinctrl_get_select(i2c_dev, "on_i2c"); if (IS_ERR_OR_NULL(pinctrl_i2c)) { @@ -1055,44 +1180,68 @@ static void fimc_is_i2c_config(struct i2c_client *client, bool onoff) } else { devm_pinctrl_put(pinctrl_i2c); } - pin_config_set(gpio->pinname, gpio->sda, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); - pin_config_set(gpio->pinname, gpio->scl, - PINCFG_PACK(PINCFG_TYPE_FUNC, 2)); + if(gpio->use_i2c_pinctrl) { + pin_config_set(gpio->pinname, gpio->sda, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + pin_config_set(gpio->pinname, gpio->scl, + PINCFG_PACK(PINCFG_TYPE_FUNC, gpio->pinfunc_off)); + } } + + return 0; } -int fimc_is_sec_read_eeprom_header(struct device *dev) +int fimc_is_sec_read_eeprom_header(struct device *dev, int position) { int ret = 0; struct fimc_is_core *core = dev_get_drvdata(fimc_is_dev); struct exynos_platform_fimc_is *core_pdata = NULL; - u8 header_version[12] = {0, }; + u8 header_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; struct i2c_client *client; client = core->eeprom_client0; core_pdata = dev_get_platdata(fimc_is_dev); #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, true); + } + } else +#endif + { fimc_is_i2c_config(client, true); } -#endif - ret = fimc_is_i2c_read(client, header_version, 0x20, 0x0B); + if(position == SENSOR_POSITION_FRONT) { +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) + ret = fimc_is_i2c_read(client, header_version, + EEP_HEADER_VERSION_START_ADDR_FRONT, FIMC_IS_HEADER_VER_SIZE); +#endif + } else { +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) + ret = fimc_is_i2c_read(client, header_version, + EEP_HEADER_VERSION_START_ADDR, FIMC_IS_HEADER_VER_SIZE); +#endif + } #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, false); + } + } else +#endif + { fimc_is_i2c_config(client, false); } -#endif if (unlikely(ret)) { err("failed to fimc_is_i2c_read for header version (%d)\n", ret); ret = -EINVAL; } - memcpy(sysfs_finfo.header_ver, header_version, 11); - sysfs_finfo.header_ver[11] = '\0'; + memcpy(sysfs_finfo.header_ver, header_version, FIMC_IS_HEADER_VER_SIZE); + sysfs_finfo.header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; return ret; } @@ -1125,35 +1274,54 @@ int fimc_is_sec_readcal_eeprom(struct device *dev, int position) } #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, true); + } + } else +#endif + { fimc_is_i2c_config(client, true); } -#endif - if (position == SENSOR_POSITION_FRONT) { - ret = fimc_is_i2c_read(client, finfo->cal_map_ver, CAL_MAP_VER_ADDR_FRONT, 4); - } else { - ret = fimc_is_i2c_read(client, finfo->cal_map_ver, CAL_MAP_VER_ADDR, 4); - } if (position == SENSOR_POSITION_FRONT) { - ret = fimc_is_i2c_read(client, finfo->header_ver, CAL_HEADER_VER_ADDR_FRONT, 11); +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) + ret = fimc_is_i2c_read(client, finfo->cal_map_ver, + EEP_HEADER_CAL_MAP_VER_START_ADDR_FRONT, + FIMC_IS_CAL_MAP_VER_SIZE); + ret = fimc_is_i2c_read(client, finfo->header_ver, + EEP_HEADER_VERSION_START_ADDR_FRONT, + FIMC_IS_HEADER_VER_SIZE); +#endif } else { - ret = fimc_is_i2c_read(client, finfo->header_ver, CAL_HEADER_VER_ADDR, 11); +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) + ret = fimc_is_i2c_read(client, finfo->cal_map_ver, + EEP_HEADER_CAL_MAP_VER_START_ADDR, + FIMC_IS_CAL_MAP_VER_SIZE); + ret = fimc_is_i2c_read(client, finfo->header_ver, + EEP_HEADER_VERSION_START_ADDR, + FIMC_IS_HEADER_VER_SIZE); +#endif } #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, false); + } + } else +#endif + { fimc_is_i2c_config(client, false); } -#endif if (unlikely(ret)) { err("failed to fimc_is_i2c_read (%d)\n", ret); ret = -EINVAL; goto exit; } - printk(KERN_INFO "Camera: Cal map_version = %c%c%c%c\n", finfo->cal_map_ver[0], + printk(KERN_INFO "Camera: EEPROM Cal map_version = %c%c%c%c\n", finfo->cal_map_ver[0], finfo->cal_map_ver[1], finfo->cal_map_ver[2], finfo->cal_map_ver[3]); if (!fimc_is_sec_check_from_ver(core, position)) { @@ -1166,31 +1334,44 @@ int fimc_is_sec_readcal_eeprom(struct device *dev, int position) /* read cal data */ info("Camera: I2C read cal data\n"); #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, true); + } + } else +#endif + { fimc_is_i2c_config(client, true); } -#endif fimc_is_i2c_read(client, buf, 0x0, cal_size); #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_ois_hsi2c) { + if(position == SENSOR_POSITION_FRONT) { + if (core_pdata->use_ois_hsi2c) { + fimc_is_i2c_config(client, false); + } + } else +#endif + { fimc_is_i2c_config(client, false); } -#endif if (position == SENSOR_POSITION_FRONT) { +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) info("FRONT EEPROM header version = %s\n", finfo->header_ver); - finfo->oem_start_addr = *((u32 *)&buf[OEM_START_ADDR_FRONT]); - finfo->oem_end_addr = *((u32 *)&buf[OEM_END_ADDR_FRONT]); +#if defined(EEP_HEADER_OEM_START_ADDR_FRONT) + finfo->oem_start_addr = *((u32 *)&buf[EEP_HEADER_OEM_START_ADDR_FRONT]); + finfo->oem_end_addr = *((u32 *)&buf[EEP_HEADER_OEM_END_ADDR_FRONT]); info("OEM start = 0x%08x, end = 0x%08x\n", (finfo->oem_start_addr), (finfo->oem_end_addr)); - finfo->awb_start_addr = *((u32 *)&buf[AWB_START_ADDR_FRONT]); - finfo->awb_end_addr = *((u32 *)&buf[AWB_END_ADDR_FRONT]); +#endif + finfo->awb_start_addr = *((u32 *)&buf[EEP_HEADER_AWB_START_ADDR_FRONT]); + finfo->awb_end_addr = *((u32 *)&buf[EEP_HEADER_AWB_END_ADDR_FRONT]); info("AWB start = 0x%08x, end = 0x%08x\n", (finfo->awb_start_addr), (finfo->awb_end_addr)); - finfo->shading_start_addr = *((u32 *)&buf[SHADING_START_ADDR_FRONT]); - finfo->shading_end_addr = *((u32 *)&buf[SHADING_END_ADDR_FRONT]); + finfo->shading_start_addr = *((u32 *)&buf[EEP_HEADER_AP_SHADING_START_ADDR_FRONT]); + finfo->shading_end_addr = *((u32 *)&buf[EEP_HEADER_AP_SHADING_END_ADDR_FRONT]); info("Shading start = 0x%08x, end = 0x%08x\n", (finfo->shading_start_addr), (finfo->shading_end_addr)); if (finfo->shading_end_addr > 0x3AFF) { @@ -1198,8 +1379,8 @@ int fimc_is_sec_readcal_eeprom(struct device *dev, int position) finfo->shading_end_addr = 0x3AFF; } #ifdef CONFIG_COMPANION_C2_USE - finfo->c2_shading_start_addr = *((u32 *)&buf[C2_SHADING_START_ADDR_FRONT]); - finfo->c2_shading_end_addr = *((u32 *)&buf[C2_SHADING_END_ADDR_FRONT]); + finfo->c2_shading_start_addr = *((u32 *)&buf[EEP_HEADER_C2_SHADING_START_ADDR_FRONT]); + finfo->c2_shading_end_addr = *((u32 *)&buf[EEP_HEADER_C2_SHADING_END_ADDR_FRONT]); info("c2_shading start = 0x%08x, end = 0x%08x\n", (finfo->c2_shading_start_addr), (finfo->c2_shading_end_addr)); if (finfo->c2_shading_end_addr > 0x1CFF) { @@ -1208,78 +1389,82 @@ int fimc_is_sec_readcal_eeprom(struct device *dev, int position) } /* C2 SHADING Data : Module/Manufacturer Information */ - memcpy(finfo->c2_shading_ver, &buf[C2_SHADING_VER_ADDR_FRONT], 11); - finfo->shading_ver[11] = '\0'; + memcpy(finfo->c2_shading_ver, &buf[EEP_C2_SHADING_VER_START_ADDR_FRONT], FIMC_IS_SHADING_VER_SIZE); + finfo->shading_ver[FIMC_IS_SHADING_VER_SIZE] = '\0'; - finfo->lsc_i0_gain_addr = 0x1A02; + finfo->lsc_i0_gain_addr = EEP_C2_SHADING_LSC_I0_GAIN_ADDR_FRONT; info("Shading lsc_i0 start = 0x%08x\n", finfo->lsc_i0_gain_addr); - finfo->lsc_j0_gain_addr = finfo->lsc_i0_gain_addr + 8; + finfo->lsc_j0_gain_addr = EEP_C2_SHADING_LSC_J0_GAIN_ADDR_FRONT; info("Shading lsc_j0 start = 0x%08x\n", finfo->lsc_j0_gain_addr); - finfo->lsc_a_gain_addr = finfo->lsc_j0_gain_addr + 8; + finfo->lsc_a_gain_addr = EEP_C2_SHADING_LSC_A_GAIN_ADDR_FRONT; info("Shading lsc_a start = 0x%08x\n", finfo->lsc_a_gain_addr); - finfo->lsc_k4_gain_addr = finfo->lsc_a_gain_addr + 16; + finfo->lsc_k4_gain_addr = EEP_C2_SHADING_LSC_K4_GAIN_ADDR_FRONT; info("Shading lsc_k4 start = 0x%08x\n", finfo->lsc_k4_gain_addr); - finfo->lsc_scale_gain_addr = finfo->lsc_k4_gain_addr + 16; + finfo->lsc_scale_gain_addr = EEP_C2_SHADING_LSC_SCALE_GAIN_ADDR_FRONT; info("Shading lsc_scale start = 0x%08x\n", finfo->lsc_scale_gain_addr); - finfo->grasTuning_AwbAshCord_N_addr = finfo->lsc_scale_gain_addr + 8; + finfo->grasTuning_AwbAshCord_N_addr = EEP_C2_SHADING_GRASTUNING_AWB_ASH_CORD_ADDR_FRONT; info("Shading grasTuning_AwbAshCord_N start = 0x%08x\n", finfo->grasTuning_AwbAshCord_N_addr); - finfo->grasTuning_awbAshCordIndexes_N_addr = finfo->grasTuning_AwbAshCord_N_addr + 14; + finfo->grasTuning_awbAshCordIndexes_N_addr = EEP_C2_SHADING_GRASTUNING_AWB_ASH_CORD_INDEX_ADDR_FRONT; info("Shading grasTuning_awbAshCordIndexes_N start = 0x%08x\n", finfo->grasTuning_awbAshCordIndexes_N_addr); - finfo->grasTuning_GASAlpha_M__N_addr = finfo->grasTuning_awbAshCordIndexes_N_addr + 14; + finfo->grasTuning_GASAlpha_M__N_addr = EEP_C2_SHADING_GRASTUNING_GAS_ALPHA_ADDR_FRONT; info("Shading grasTuning_GASAlpha_M__N_addr start = 0x%08x\n", finfo->grasTuning_GASAlpha_M__N_addr); - finfo->grasTuning_GASBeta_M__N_addr = finfo->grasTuning_GASAlpha_M__N_addr + 56; + finfo->grasTuning_GASBeta_M__N_addr = EEP_C2_SHADING_GRASTUNING_GAS_BETA_ADDR_FRONT; info("Shading grasTuning_GASBeta_M__N start = 0x%08x\n", finfo->grasTuning_GASBeta_M__N_addr); - finfo->grasTuning_GASOutdoorAlpha_N_addr = finfo->grasTuning_GASBeta_M__N_addr + 56; + finfo->grasTuning_GASOutdoorAlpha_N_addr = EEP_C2_SHADING_GRASTUNING_GAS_OUTDOOR_ALPHA_ADDR_FRONT; info("Shading grasTuning_GASOutdoorAlpha_N start = 0x%08x\n", finfo->grasTuning_GASOutdoorAlpha_N_addr); - finfo->grasTuning_GASOutdoorBeta_N_addr = finfo->grasTuning_GASOutdoorAlpha_N_addr + 8; + finfo->grasTuning_GASOutdoorBeta_N_addr = EEP_C2_SHADING_GRASTUNING_GAS_OUTDOOR_BETA_ADDR_FRONT; info("Shading grasTuning_GASOutdoorBeta_N start = 0x%08x\n", finfo->grasTuning_GASOutdoorBeta_N_addr); - finfo->grasTuning_GASIndoorAlpha_N_addr = finfo->grasTuning_GASOutdoorBeta_N_addr + 8; + finfo->grasTuning_GASIndoorAlpha_N_addr = EEP_C2_SHADING_GRASTUNING_GAS_INDOOR_ALPHA_ADDR_FRONT; info("Shading grasTuning_GASIndoorAlpha_N start = 0x%08x\n", finfo->grasTuning_GASIndoorAlpha_N_addr); - finfo->grasTuning_GASIndoorBeta_N_addr = finfo->grasTuning_GASIndoorAlpha_N_addr + 8; + finfo->grasTuning_GASIndoorBeta_N_addr = EEP_C2_SHADING_GRASTUNING_GAS_INDOOR_BETA_ADDR_FRONT; info("Shading grasTuning_GASIndoorBeta_N start = 0x%08x\n", finfo->grasTuning_GASIndoorBeta_N_addr); - finfo->lsc_gain_start_addr = finfo->c2_shading_start_addr + 6; - finfo->lsc_gain_end_addr = finfo->lsc_gain_start_addr + 5880 -1; + finfo->lsc_gain_start_addr = EEP_C2_SHADING_LSC_GAIN_START_ADDR_FRONT; + finfo->lsc_gain_end_addr = EEP_C2_SHADING_LSC_GAIN_END_ADDR_FRONT; info("LSC start = 0x%04x, end = 0x%04x\n", finfo->lsc_gain_start_addr, finfo->lsc_gain_end_addr); - finfo->lsc_gain_crc_addr = 0x19FE; + finfo->lsc_gain_crc_addr = EEP_C2_SHADING_LSC_GAIN_CRC_ADDR_FRONT; info("lsc_gain_crc_addr = 0x%04x,\n", finfo->lsc_gain_crc_addr); - finfo->lsc_parameter_crc_addr = 0x1AE6; + finfo->lsc_parameter_crc_addr = EEP_C2_SHADING_LSC_PARAMETER_CRC_ARRD_FRONT; info("lsc_parameter_crc_addr = 0x%04x,\n", finfo->lsc_parameter_crc_addr); info(" Module ver : %c\n", finfo->header_ver[FW_VERSION_INFO]); #endif /* HEARDER Data : Module/Manufacturer Information */ - memcpy(finfo->header_ver, &buf[CAL_HEADER_VER_ADDR_FRONT], 11); - finfo->header_ver[11] = '\0'; + memcpy(finfo->header_ver, &buf[EEP_HEADER_VERSION_START_ADDR_FRONT], FIMC_IS_HEADER_VER_SIZE); + finfo->header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; /* HEARDER Data : Cal Map Version */ - memcpy(finfo->cal_map_ver, &buf[CAL_MAP_VER_ADDR_FRONT], 4); - - memcpy(finfo->project_name, &buf[PROJECT_NAME_ADDR_FRONT], 8); - finfo->project_name[8] = '\0'; + memcpy(finfo->cal_map_ver, + &buf[EEP_HEADER_CAL_MAP_VER_START_ADDR_FRONT], FIMC_IS_CAL_MAP_VER_SIZE); + memcpy(finfo->project_name, + &buf[EEP_HEADER_PROJECT_NAME_START_ADDR_FRONT], FIMC_IS_PROJECT_NAME_SIZE); + finfo->project_name[FIMC_IS_PROJECT_NAME_SIZE] = '\0'; +#if defined(EEP_HEADER_OEM_START_ADDR_FRONT) /* OEM Data : Module/Manufacturer Information */ - memcpy(finfo->oem_ver, &buf[OEM_VER_ADDR_FRONT], 11); - finfo->oem_ver[11] = '\0'; - + memcpy(finfo->oem_ver, &buf[EEP_OEM_VER_START_ADDR_FRONT], FIMC_IS_OEM_VER_SIZE); + finfo->oem_ver[FIMC_IS_OEM_VER_SIZE] = '\0'; +#endif /* AWB Data : Module/Manufacturer Information */ - memcpy(finfo->awb_ver, &buf[AWB_VER_ADDR_FRONT], 11); - finfo->awb_ver[11] = '\0'; + memcpy(finfo->awb_ver, &buf[EEP_AWB_VER_START_ADDR_FRONT], FIMC_IS_AWB_VER_SIZE); + finfo->awb_ver[FIMC_IS_AWB_VER_SIZE] = '\0'; /* SHADING Data : Module/Manufacturer Information */ - memcpy(finfo->shading_ver, &buf[SHADING_VER_ADDR_FRONT], 11); - finfo->shading_ver[11] = '\0'; + memcpy(finfo->shading_ver, &buf[EEP_AP_SHADING_VER_START_ADDR_FRONT], FIMC_IS_SHADING_VER_SIZE); + finfo->shading_ver[FIMC_IS_SHADING_VER_SIZE] = '\0'; +#endif } else { - finfo->oem_start_addr = *((u32 *)&buf[OEM_START_ADDR]); - finfo->oem_end_addr = *((u32 *)&buf[OEM_END_ADDR]); +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) + finfo->oem_start_addr = *((u32 *)&buf[EEP_HEADER_OEM_START_ADDR]); + finfo->oem_end_addr = *((u32 *)&buf[EEP_HEADER_OEM_END_ADDR]); info("OEM start = 0x%08x, end = 0x%08x\n", (finfo->oem_start_addr), (finfo->oem_end_addr)); - finfo->awb_start_addr = *((u32 *)&buf[AWB_START_ADDR]); - finfo->awb_end_addr = *((u32 *)&buf[AWB_END_ADDR]); + finfo->awb_start_addr = *((u32 *)&buf[EEP_HEADER_AWB_START_ADDR]); + finfo->awb_end_addr = *((u32 *)&buf[EEP_HEADER_AWB_END_ADDR]); info("AWB start = 0x%08x, end = 0x%08x\n", (finfo->awb_start_addr), (finfo->awb_end_addr)); - finfo->shading_start_addr = *((u32 *)&buf[SHADING_START_ADDR]); - finfo->shading_end_addr = *((u32 *)&buf[SHADING_END_ADDR]); + finfo->shading_start_addr = *((u32 *)&buf[EEP_HEADER_AP_SHADING_START_ADDR]); + finfo->shading_end_addr = *((u32 *)&buf[EEP_HEADER_AP_SHADING_END_ADDR]); if (finfo->shading_end_addr > 0x1fff) { err("Shading end_addr has error!! 0x%08x", finfo->shading_end_addr); finfo->setfile_end_addr = 0x1fff; @@ -1288,127 +1473,832 @@ int fimc_is_sec_readcal_eeprom(struct device *dev, int position) (finfo->shading_start_addr), (finfo->shading_end_addr)); /* HEARDER Data : Module/Manufacturer Information */ - memcpy(finfo->header_ver, &buf[CAL_HEADER_VER_ADDR], 11); - finfo->header_ver[11] = '\0'; + memcpy(finfo->header_ver, &buf[EEP_HEADER_VERSION_START_ADDR], FIMC_IS_HEADER_VER_SIZE); + finfo->header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; /* HEARDER Data : Cal Map Version */ - memcpy(finfo->cal_map_ver, &buf[CAL_MAP_VER_ADDR], 4); + memcpy(finfo->cal_map_ver, &buf[EEP_HEADER_CAL_MAP_VER_START_ADDR], FIMC_IS_CAL_MAP_VER_SIZE); + + memcpy(finfo->project_name, &buf[EEP_HEADER_PROJECT_NAME_START_ADDR], FIMC_IS_PROJECT_NAME_SIZE); + finfo->project_name[FIMC_IS_PROJECT_NAME_SIZE] = '\0'; + + /* OEM Data : Module/Manufacturer Information */ + memcpy(finfo->oem_ver, &buf[EEP_OEM_VER_START_ADDR], FIMC_IS_OEM_VER_SIZE); + finfo->oem_ver[FIMC_IS_OEM_VER_SIZE] = '\0'; + + /* AWB Data : Module/Manufacturer Information */ + memcpy(finfo->awb_ver, &buf[EEP_AWB_VER_START_ADDR], FIMC_IS_AWB_VER_SIZE); + finfo->awb_ver[FIMC_IS_AWB_VER_SIZE] = '\0'; + + /* SHADING Data : Module/Manufacturer Information */ + memcpy(finfo->shading_ver, &buf[EEP_AP_SHADING_VER_START_ADDR], FIMC_IS_SHADING_VER_SIZE); + finfo->shading_ver[FIMC_IS_SHADING_VER_SIZE] = '\0'; +#endif + } + + /* debug info dump */ +#if defined(EEPROM_DEBUG) + info("++++ EEPROM data info\n"); + info("1. Header info\n"); + info("Module info : %s\n", finfo->header_ver); + info(" ID : %c\n", finfo->header_ver[FW_CORE_VER]); + info(" Pixel num : %c%c\n", finfo->header_ver[FW_PIXEL_SIZE], + finfo->header_ver[FW_PIXEL_SIZE+1]); + info(" ISP ID : %c\n", finfo->header_ver[FW_ISP_COMPANY]); + info(" Sensor Maker : %c\n", finfo->header_ver[FW_SENSOR_MAKER]); + info(" Year : %c\n", finfo->header_ver[FW_PUB_YEAR]); + info(" Month : %c\n", finfo->header_ver[FW_PUB_MON]); + info(" Release num : %c%c\n", finfo->header_ver[FW_PUB_NUM], + finfo->header_ver[FW_PUB_NUM+1]); + info(" Manufacturer ID : %c\n", finfo->header_ver[FW_MODULE_COMPANY]); + info(" Module ver : %c\n", finfo->header_ver[FW_VERSION_INFO]); + info("project_name : %s\n", finfo->project_name); + info("Cal data map ver : %s\n", finfo->cal_map_ver); + info("2. OEM info\n"); + info("Module info : %s\n", finfo->oem_ver); + info("3. AWB info\n"); + info("Module info : %s\n", finfo->awb_ver); + info("4. Shading info\n"); + info("Module info : %s\n", finfo->shading_ver); + info("---- EEPROM data info\n"); +#endif + + /* CRC check */ + if (!fimc_is_sec_check_cal_crc32(buf, position) && (retry > 0)) { + retry--; + goto crc_retry; + } + + if (position == SENSOR_POSITION_FRONT) { + if (finfo->header_ver[3] == 'L') { + crc32_check_factory_front = crc32_check_front; + } else { + crc32_check_factory_front = false; + } + } else { + if (finfo->header_ver[3] == 'L') { + crc32_check_factory = crc32_check; + } else { + crc32_check_factory = false; + } + } + +#ifdef CONFIG_COMPANION_C2_USE + if (fimc_is_sec_check_from_ver(core, position)) { + /* If FROM LSC value is not valid, loading default lsc data */ + if (*((u32 *)&cal_buf_front[sysfs_finfo_front.lsc_gain_start_addr]) == 0x00000000) { + companion_front_lsc_isvalid = false; + } else { + companion_front_lsc_isvalid = true; + } + } +#endif + +#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) + if (core_pdata->use_module_check) { + if (finfo->header_ver[10] == FIMC_IS_LATEST_FROM_VERSION_M) { + is_final_cam_module_front = true; + } else { + is_final_cam_module_front = false; + } + } else { + is_final_cam_module_front = true; + } +#endif + +exit: + return ret; +} + +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_OTPROM_SUPPORT_FRONT) +int fimc_is_sec_readcal_otprom(struct device *dev, int position) +{ + int ret = 0; + char *buf = NULL; + int retry = FIMC_IS_CAL_RETRY_CNT; + struct fimc_is_core *core = dev_get_drvdata(dev); + struct fimc_is_from_info *finfo = NULL; + int cal_size = 0; + struct i2c_client *client = NULL; + struct file *key_fp = NULL; + struct file *dump_fp = NULL; + mm_segment_t old_fs; + loff_t pos = 0; + char selected_page[2] = {0,}; + + if (position == SENSOR_POSITION_FRONT) { +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_FRONT) + finfo = &sysfs_finfo_front; + fimc_is_sec_get_front_cal_buf(&buf); + cal_size = FIMC_IS_MAX_CAL_SIZE_FRONT; + client = core->eeprom_client1; +#endif + } else { +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_REAR) + finfo = &sysfs_finfo; + fimc_is_sec_get_cal_buf(&buf); + cal_size = FIMC_IS_MAX_CAL_SIZE; + client = core->eeprom_client0; +#endif + } + + + fimc_is_i2c_config(client, true); + msleep(10); + + ret = fimc_is_i2c_write(client, 0xA00, 0x04); + if (unlikely(ret)) { + err("failed to fimc_is_i2c_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + fimc_is_i2c_write(client, 0xA02, 0x02); + fimc_is_i2c_write(client, 0xA00, 0x01); + + ret = fimc_is_i2c_read(client, selected_page, 0xA12, 0x1); + if (unlikely(ret)) { + err("failed to fimc_is_i2c_read (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + printk(KERN_INFO "Camera: otp_bank = %d\n", selected_page[0]); + if (selected_page[0] == 0x3) { + printk(KERN_INFO "Camera: OTP 3 page selected\n"); + fimc_is_i2c_write(client, 0xA00, 0x04); + fimc_is_i2c_write(client, 0xA00, 0x00); + + msleep(1); + + fimc_is_i2c_write(client, 0xA00, 0x04); + fimc_is_i2c_write(client, 0xA02, 0x03); + fimc_is_i2c_write(client, 0xA00, 0x01); + } + fimc_is_i2c_read(client, cal_map_version, 0xA22, 0x4); + + fimc_is_i2c_write(client, 0xA00, 0x04); + fimc_is_i2c_write(client, 0xA00, 0x00); + + if(finfo->cal_map_ver[0] != 'V') { + printk(KERN_INFO "Camera: Cal Map version read fail or there's no available data.\n"); + crc32_check_factory_front = false; + goto exit; + } + + printk(KERN_INFO "Camera: OTPROM Cal map_version = %c%c%c%c\n", finfo->cal_map_ver[0], + finfo->cal_map_ver[1], finfo->cal_map_ver[2], finfo->cal_map_ver[3]); + +crc_retry: + cal_size = 50; + fimc_is_i2c_write(client, 0xA00, 0x04); + if(selected_page[0] == 1) + fimc_is_i2c_write(client, 0xA02, 0x02); + else + fimc_is_i2c_write(client, 0xA02, 0x03); + fimc_is_i2c_write(client, 0xA00, 0x01); + + /* read cal data */ + pr_info("Camera: I2C read cal data\n\n"); + fimc_is_i2c_read(client, buf, 0xA15, cal_size); + + fimc_is_i2c_write(client, 0xA00, 0x04); + fimc_is_i2c_write(client, 0xA00, 0x00); + + if (position == SENSOR_POSITION_FRONT) { +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_FRONT) + /* HEARDER Data : Module/Manufacturer Information */ + memcpy(finfo->header_ver, &buf[OPT_HEADER_VERSION_START_ADDR_FRONT], FIMC_IS_HEADER_VER_SIZE); + finfo->header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; + /* HEARDER Data : Cal Map Version */ + memcpy(finfo->cal_map_ver, &buf[OPT_HEADER_CAL_MAP_VER_START_ADDR_FRONT], FIMC_IS_CAL_MAP_VER_SIZE); +#endif + } else { +#if defined(CONFIG_CAMERA_OTPROM_SUPPORT_REAR) + /* HEARDER Data : Module/Manufacturer Information */ + memcpy(finfo->header_ver, &buf[OPT_HEADER_VERSION_START_ADDR], FIMC_IS_HEADER_VER_SIZE); + finfo->header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; + /* HEARDER Data : Cal Map Version */ + memcpy(finfo->cal_map_ver, &buf[OPT_HEADER_CAL_MAP_VER_START_ADDR], FIMC_IS_CAL_MAP_VER_SIZE); +#endif + } + + /* debug info dump */ + pr_info("++++ OTPROM data info\n"); + pr_info("1. Header info\n"); + pr_info("Module info : %s\n", finfo->header_ver); + pr_info(" ID : %c\n", finfo->header_ver[FW_CORE_VER]); + pr_info(" Pixel num : %c%c\n", finfo->header_ver[FW_PIXEL_SIZE], + finfo->header_ver[FW_PIXEL_SIZE+1]); + pr_info(" ISP ID : %c\n", finfo->header_ver[FW_ISP_COMPANY]); + pr_info(" Sensor Maker : %c\n", finfo->header_ver[FW_SENSOR_MAKER]); + pr_info(" Year : %c\n", finfo->header_ver[FW_PUB_YEAR]); + pr_info(" Month : %c\n", finfo->header_ver[FW_PUB_MON]); + pr_info(" Release num : %c%c\n", finfo->header_ver[FW_PUB_NUM], + finfo->header_ver[FW_PUB_NUM+1]); + pr_info(" Manufacturer ID : %c\n", finfo->header_ver[FW_MODULE_COMPANY]); + pr_info(" Module ver : %c\n", finfo->header_ver[FW_VERSION_INFO]); + pr_info("---- OTPROM data info\n"); + + /* CRC check */ + ret = fimc_is_sec_check_front_otp_crc32(buf); + + if (!ret && (retry > 0)) { + retry--; + goto crc_retry; + } + + if (position == SENSOR_POSITION_FRONT) { + if (finfo->header_ver[3] == 'L') { + crc32_check_factory_front = crc32_check_front; + } else { + crc32_check_factory_front = false; + } + if (core->use_module_check) { + if (finfo->header_ver[10] == FIMC_IS_LATEST_FROM_VERSION_M) { + is_final_cam_module_front = true; + } else { + is_final_cam_module_front = false; + } + } else { + is_final_cam_module_front = true; + } + } else { + if (finfo->header_ver[3] == 'L') { + crc32_check_factory = crc32_check; + } else { + crc32_check_factory = false; + } + + + if (!core->use_module_check) { + is_latest_cam_module = true; + } else { + if (sysfs_finfo.header_ver[10] >= CAMERA_MODULE_ES_VERSION) { + is_latest_cam_module = true; + } else { + is_latest_cam_module = false; + } + } + + if (!core->use_module_check) { + is_final_cam_module = true; + } else { + if (sysfs_finfo.header_ver[10] == FIMC_IS_LATEST_FROM_VERSION_M) { + is_final_cam_module = true; + } else { + is_final_cam_module = false; + } + } + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + key_fp = filp_open("/data/media/0/1q2w3e4r.key", O_RDONLY, 0); + if (IS_ERR(key_fp)) { + pr_info("KEY does not exist.\n"); + key_fp = NULL; + goto key_err; + } else { + dump_fp = filp_open("/data/media/0/dump", O_RDONLY, 0); + if (IS_ERR(dump_fp)) { + pr_info("dump folder does not exist.\n"); + dump_fp = NULL; + goto key_err; + } else { + pr_info("dump folder exist, Dump OTPROM cal data.\n"); + if (position == SENSOR_POSITION_FRONT) { + if (write_data_to_file(FIMC_IS_CAL_DUMP_FRONT, buf, FIMC_IS_DUMP_CAL_SIZE, &pos) < 0) { + pr_info("Failed to dump cal data.\n"); + goto dump_err; + } + } else { + if (write_data_to_file(FIMC_IS_CAL_DUMP, buf, FIMC_IS_DUMP_CAL_SIZE, &pos) < 0) { + pr_info("Failed to dump cal data.\n"); + goto dump_err; + } + } + } + } + +dump_err: + if (dump_fp) + filp_close(dump_fp, current->files); +key_err: + if (key_fp) + filp_close(key_fp, current->files); + set_fs(old_fs); +exit: + fimc_is_i2c_config(client, false); + + return ret; +} +#endif +#endif + +#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) +int fimc_is_sec_read_from_header(struct device *dev) +{ + int ret = 0; + struct fimc_is_core *core = dev_get_drvdata(fimc_is_dev); + u8 header_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; + + ret = fimc_is_spi_read(&core->spi0, header_version, FROM_HEADER_VERSION_START_ADDR, FIMC_IS_HEADER_VER_SIZE); + if (ret < 0) { + printk(KERN_ERR "failed to fimc_is_spi_read for header version (%d)\n", ret); + ret = -EINVAL; + } + + memcpy(sysfs_finfo.header_ver, header_version, FIMC_IS_HEADER_VER_SIZE); + sysfs_finfo.header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; + + return ret; +} + +int fimc_is_sec_check_status(struct fimc_is_core *core) +{ + int retry_read = 50; + u8 temp[5] = {0x0, }; + int ret = 0; + + do { + memset(temp, 0x0, sizeof(temp)); + fimc_is_spi_read_status_bit(&core->spi0, &temp[0]); + if (retry_read < 0) { + ret = -EINVAL; + err("check status failed."); + break; + } + retry_read--; + msleep(3); + } while (temp[0]); + + return ret; +} + +#ifdef CAMERA_MODULE_DUALIZE +int fimc_is_sec_read_fw_from_sdcard(char *name, unsigned long *size) +{ + struct file *fw_fp = NULL; + mm_segment_t old_fs; + loff_t pos = 0; + char data_path[100]; + int ret = 0; + unsigned long fsize; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + snprintf(data_path, sizeof(data_path), "%s", name); + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + + fw_fp = filp_open(data_path, O_RDONLY, 0); + if (IS_ERR_OR_NULL(fw_fp)) { + info("%s does not exist.\n", data_path); + fw_fp = NULL; + ret = -EIO; + goto fw_err; + } else { + info("%s exist, Dump from sdcard.\n", name); + fsize = fw_fp->f_path.dentry->d_inode->i_size; + read_data_from_file(name, fw_buf, fsize, &pos); + *size = fsize; + } + +fw_err: + if (fw_fp) + filp_close(fw_fp, current->files); + set_fs(old_fs); + + return ret; +} + +u32 fimc_is_sec_get_fw_crc32(char *buf, size_t size) +{ + u32 *buf32 = NULL; + u32 checksum; + + buf32 = (u32 *)buf; + checksum = (u32)getCRC((u16 *)&buf32[0], size, NULL, NULL); + + return checksum; +} + +int fimc_is_sec_change_from_header(struct fimc_is_core *core) +{ + int ret = 0; + u8 crc_value[4]; + u32 crc_result = 0; + + /* read header data */ + info("Camera: Start SPI read header data\n"); + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + + ret = fimc_is_spi_read(&core->spi0, fw_buf, 0x0, HEADER_CRC32_LEN); + if (ret) { + err("failed to fimc_is_spi_read (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + fw_buf[0x7] = (sysfs_finfo.bin_end_addr & 0xFF000000) >> 24; + fw_buf[0x6] = (sysfs_finfo.bin_end_addr & 0xFF0000) >> 16; + fw_buf[0x5] = (sysfs_finfo.bin_end_addr & 0xFF00) >> 8; + fw_buf[0x4] = (sysfs_finfo.bin_end_addr & 0xFF); + fw_buf[0x27] = (sysfs_finfo.setfile_end_addr & 0xFF000000) >> 24; + fw_buf[0x26] = (sysfs_finfo.setfile_end_addr & 0xFF0000) >> 16; + fw_buf[0x25] = (sysfs_finfo.setfile_end_addr & 0xFF00) >> 8; + fw_buf[0x24] = (sysfs_finfo.setfile_end_addr & 0xFF); + fw_buf[0x37] = (sysfs_finfo.concord_bin_end_addr & 0xFF000000) >> 24; + fw_buf[0x36] = (sysfs_finfo.concord_bin_end_addr & 0xFF0000) >> 16; + fw_buf[0x35] = (sysfs_finfo.concord_bin_end_addr & 0xFF00) >> 8; + fw_buf[0x34] = (sysfs_finfo.concord_bin_end_addr & 0xFF); + + strncpy(&fw_buf[0x40], sysfs_finfo.header_ver, 9); + strncpy(&fw_buf[0x50], sysfs_finfo.concord_header_ver, FIMC_IS_HEADER_VER_SIZE); + strncpy(&fw_buf[0x64], sysfs_finfo.setfile_ver, FIMC_IS_ISP_SETFILE_VER_SIZE); + + fimc_is_spi_write_enable(&core->spi0); + ret = fimc_is_spi_erase_sector(&core->spi0, 0x0); + if (ret) { + err("failed to fimc_is_spi_erase_sector (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + ret = fimc_is_spi_write_enable(&core->spi0); + ret = fimc_is_spi_write(&core->spi0, 0x0, fw_buf, HEADER_CRC32_LEN); + if (ret) { + err("failed to fimc_is_spi_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + crc_result = fimc_is_sec_get_fw_crc32(fw_buf, HEADER_CRC32_LEN); + crc_value[3] = (crc_result & 0xFF000000) >> 24; + crc_value[2] = (crc_result & 0xFF0000) >> 16; + crc_value[1] = (crc_result & 0xFF00) >> 8; + crc_value[0] = (crc_result & 0xFF); + + ret = fimc_is_spi_write_enable(&core->spi0); + ret = fimc_is_spi_write(&core->spi0, 0x0FFC, crc_value, 0x4); + if (ret) { + err("failed to fimc_is_spi_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + info("Camera: End SPI read header data\n"); + +exit: + return ret; +} + +int fimc_is_sec_write_fw_to_from(struct fimc_is_core *core, char *name, bool first_section) +{ + int ret = 0; + unsigned long i = 0; + unsigned long size = 0; + u32 start_addr = 0, erase_addr = 0, end_addr = 0; + u32 checksum_addr = 0, crc_result = 0, erase_end_addr = 0; + u8 crc_value[4]; + + if (!strcmp(name, FIMC_IS_FW_FROM_SDCARD)) { + ret = fimc_is_sec_read_fw_from_sdcard(FIMC_IS_FW_FROM_SDCARD, &size); + start_addr = sysfs_finfo.bin_start_addr; + end_addr = size + start_addr - 1; + sysfs_finfo.bin_end_addr = end_addr; + checksum_addr = 0x3FFFFF; + sysfs_finfo.fw_size = size; + strncpy(sysfs_finfo.header_ver, &fw_buf[size - 11], 9); + } else if (!strcmp(name, FIMC_IS_SETFILE_FROM_SDCARD)) { + ret = fimc_is_sec_read_fw_from_sdcard(FIMC_IS_SETFILE_FROM_SDCARD, &size); + start_addr = sysfs_finfo.setfile_start_addr; + end_addr = size + start_addr - 1; + sysfs_finfo.setfile_end_addr = end_addr; + checksum_addr = 0x156FFF; + sysfs_finfo.setfile_size = size; + strncpy(sysfs_finfo.setfile_ver, &fw_buf[size - 64], 6); + } else if (!strcmp(name, FIMC_IS_COMPANION_FROM_SDCARD)) { + ret = fimc_is_sec_read_fw_from_sdcard(FIMC_IS_COMPANION_FROM_SDCARD, &size); + start_addr = sysfs_finfo.concord_bin_start_addr; + end_addr = size + start_addr - 1; + sysfs_finfo.concord_bin_end_addr = end_addr; + checksum_addr = 0x407FF; + erase_end_addr = 0x3FFFFF; + sysfs_finfo.comp_fw_size = size; + strncpy(sysfs_finfo.concord_header_ver, &fw_buf[size - 16], FIMC_IS_HEADER_VER_SIZE); + } else { + err("Not supported binary type."); + return -EIO; + } + + if (ret < 0) { + err("FW is not exist in sdcard."); + return -EIO; + } + + info("Start %s write to FROM.\n", name); + + if (first_section) { + for (erase_addr = start_addr; erase_addr < erase_end_addr; erase_addr += FIMC_IS_FROM_ERASE_SIZE) { + ret = fimc_is_spi_write_enable(&core->spi0); + ret |= fimc_is_spi_erase_block(&core->spi0, erase_addr); + if (ret) { + err("failed to fimc_is_spi_erase_block (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + } + } + + for (i = 0; i < size; i += 256) { + ret = fimc_is_spi_write_enable(&core->spi0); + if (size - i >= 256) { + ret = fimc_is_spi_write(&core->spi0, start_addr + i, fw_buf + i, 256); + if (ret) { + err("failed to fimc_is_spi_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + } else { + ret = fimc_is_spi_write(&core->spi0, start_addr + i, fw_buf + i, size - i); + if (ret) { + err("failed to fimc_is_spi_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + } + + crc_result = fimc_is_sec_get_fw_crc32(fw_buf, size); + crc_value[3] = (crc_result & 0xFF000000) >> 24; + crc_value[2] = (crc_result & 0xFF0000) >> 16; + crc_value[1] = (crc_result & 0xFF00) >> 8; + crc_value[0] = (crc_result & 0xFF); + + ret = fimc_is_spi_write_enable(&core->spi0); + if (ret) { + err("failed to fimc_is_spi_write_enable (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + ret = fimc_is_spi_write(&core->spi0, checksum_addr -4 + 1, crc_value, 0x4); + if (ret) { + err("failed to fimc_is_spi_write (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + ret = fimc_is_sec_check_status(core); + if (ret) { + err("failed to fimc_is_sec_check_status (%d)\n", ret); + ret = -EINVAL; + goto exit; + } + + info("End %s write to FROM.\n", name); + +exit: + return ret; +} + +int fimc_is_sec_write_fw(struct fimc_is_core *core, struct device *dev) +{ + int ret = 0; +#ifdef CONFIG_COMPANION_USE + struct fimc_is_spi_gpio *spi_gpio = &core->spi0.gpio; +#endif + struct file *key_fp = NULL; + struct file *comp_fw_fp = NULL; + struct file *setfile_fp = NULL; + struct file *isp_fw_fp = NULL; + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + key_fp = filp_open(FIMC_IS_KEY_FROM_SDCARD, O_RDONLY, 0); + if (IS_ERR_OR_NULL(key_fp)) { + info("KEY does not exist.\n"); + key_fp = NULL; + ret = -EIO; + goto key_err; + } else { + comp_fw_fp = filp_open(FIMC_IS_COMPANION_FROM_SDCARD, O_RDONLY, 0); + if (IS_ERR_OR_NULL(comp_fw_fp)) { + info("Companion FW does not exist.\n"); + comp_fw_fp = NULL; + ret = -EIO; + goto comp_fw_err; + } + + setfile_fp = filp_open(FIMC_IS_SETFILE_FROM_SDCARD, O_RDONLY, 0); + if (IS_ERR_OR_NULL(setfile_fp)) { + info("setfile does not exist.\n"); + setfile_fp = NULL; + ret = -EIO; + goto setfile_err; + } + + isp_fw_fp = filp_open(FIMC_IS_FW_FROM_SDCARD, O_RDONLY, 0); + if (IS_ERR_OR_NULL(isp_fw_fp)) { + info("ISP FW does not exist.\n"); + isp_fw_fp = NULL; + ret = -EIO; + goto isp_fw_err; + } + } - memcpy(finfo->project_name, &buf[PROJECT_NAME_ADDR], 8); - finfo->project_name[8] = '\0'; + info("FW file exist, Write Firmware to FROM .\n"); - /* OEM Data : Module/Manufacturer Information */ - memcpy(finfo->oem_ver, &buf[OEM_VER_ADDR], 11); - finfo->oem_ver[11] = '\0'; + if (!fimc_is_sec_ldo_enabled(dev, "VDDIO_1.8V_CAM")) { + info("enable %s in the %s\n", "VDDIO_1.8V_CAM", __func__); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", true); + if (ret) { + err("error, failed to ois_vdd(on)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", true); + if (ret) { + err("error, failed to ois_vm(on)"); + } +#endif + ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", true); + if (ret) { + err("error, failed to cam_io(on)"); + ret = -EIO; + goto isp_fw_err; + } - /* AWB Data : Module/Manufacturer Information */ - memcpy(finfo->awb_ver, &buf[AWB_VER_ADDR], 11); - finfo->awb_ver[11] = '\0'; + } +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, false); +#endif + ret = fimc_is_sec_write_fw_to_from(core, FIMC_IS_COMPANION_FROM_SDCARD, true); + if (ret) { + err("fimc_is_sec_write_fw_to_from failed."); + ret = -EIO; + goto isp_fw_err; + } - /* SHADING Data : Module/Manufacturer Information */ - memcpy(finfo->shading_ver, &buf[SHADING_VER_ADDR], 11); - finfo->shading_ver[11] = '\0'; + ret = fimc_is_sec_write_fw_to_from(core, FIMC_IS_SETFILE_FROM_SDCARD, false); + if (ret) { + err("fimc_is_sec_write_fw_to_from failed."); + ret = -EIO; + goto isp_fw_err; } - /* debug info dump */ -#if defined(EEPROM_DEBUG) - info("++++ EEPROM data info\n"); - info("1. Header info\n"); - info("Module info : %s\n", finfo->header_ver); - info(" ID : %c\n", finfo->header_ver[FW_CORE_VER]); - info(" Pixel num : %c%c\n", finfo->header_ver[FW_PIXEL_SIZE], - finfo->header_ver[FW_PIXEL_SIZE+1]); - info(" ISP ID : %c\n", finfo->header_ver[FW_ISP_COMPANY]); - info(" Sensor Maker : %c\n", finfo->header_ver[FW_SENSOR_MAKER]); - info(" Year : %c\n", finfo->header_ver[FW_PUB_YEAR]); - info(" Month : %c\n", finfo->header_ver[FW_PUB_MON]); - info(" Release num : %c%c\n", finfo->header_ver[FW_PUB_NUM], - finfo->header_ver[FW_PUB_NUM+1]); - info(" Manufacturer ID : %c\n", finfo->header_ver[FW_MODULE_COMPANY]); - info(" Module ver : %c\n", finfo->header_ver[FW_VERSION_INFO]); - info("project_name : %s\n", finfo->project_name); - info("Cal data map ver : %s\n", finfo->cal_map_ver); - info("2. OEM info\n"); - info("Module info : %s\n", finfo->oem_ver); - info("3. AWB info\n"); - info("Module info : %s\n", finfo->awb_ver); - info("4. Shading info\n"); - info("Module info : %s\n", finfo->shading_ver); - info("---- EEPROM data info\n"); + ret = fimc_is_sec_write_fw_to_from(core, FIMC_IS_FW_FROM_SDCARD, false); + if (ret) { + err("fimc_is_sec_write_fw_to_from failed."); + ret = -EIO; + goto isp_fw_err; + } +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_OUTPUT, true); #endif - /* CRC check */ - if (position == SENSOR_POSITION_FRONT) { - ret = fimc_is_sec_check_cal_crc32(buf, SENSOR_POSITION_FRONT); - } else { - ret = fimc_is_sec_check_cal_crc32(buf, SENSOR_POSITION_REAR); - } - if (!ret && (retry > 0)) { - retry--; - goto crc_retry; + /* Off to reset FROM operation. Without this routine, spi read does not work. */ + if (!core->running_rear_camera) { + info("disable %s in the %s\n", "VDDIO_1.8V_CAM", __func__); + ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", false); + if (ret) { + err("error, failed to cam_io(off)"); + ret = -EIO; + } +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", false); + if (ret) { + err("error, failed to ois_vdd(off)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", false); + if (ret) { + err("error, failed to ois_vm(off)"); + } +#endif } -#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (position == SENSOR_POSITION_FRONT) { - if (finfo->header_ver[3] == 'L') { - crc32_check_factory_front = crc32_check_front; - } else { - crc32_check_factory_front = false; + if (!fimc_is_sec_ldo_enabled(dev, "VDDIO_1.8V_CAM")) { + info("enable %s in the %s\n", "VDDIO_1.8V_CAM", __func__); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", true); + if (ret) { + err("error, failed to ois_vdd(on)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", true); + if (ret) { + err("error, failed to ois_vm(on)"); } - } else #endif - { - if (finfo->header_ver[3] == 'L') { - crc32_check_factory = crc32_check; - } else { - crc32_check_factory = false; + ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", true); + if (ret) { + err("error, failed to cam_io(on)"); + ret = -EIO; + goto isp_fw_err; } } -#ifdef CONFIG_COMPANION_C2_USE - if (fimc_is_sec_check_from_ver(core, position)) { - /* If FROM LSC value is not valid, loading default lsc data */ - if (*((u32 *)&cal_buf_front[sysfs_finfo_front.lsc_gain_start_addr]) == 0x00000000) { - companion_front_lsc_isvalid = false; - } else { - companion_front_lsc_isvalid = true; - } +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, false); +#endif + ret = fimc_is_sec_change_from_header(core); + if (ret) { + err("fimc_is_sec_change_from_header failed."); + ret = -EIO; + goto isp_fw_err; } +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_OUTPUT, true); #endif -#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) - if (core_pdata->use_module_check) { - if (finfo->header_ver[10] == FIMC_IS_LATEST_FROM_VERSION_M) { - is_final_cam_module_front = true; - } else { - is_final_cam_module_front = false; + if (!core->running_rear_camera) { + info("disable %s in the %s\n", "VDDIO_1.8V_CAM", __func__); + ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", false); + if (ret) { + err("error, failed to cam_io(off)"); + ret = -EIO; + } +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", false); + if (ret) { + err("error, failed to ois_vdd(off)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", false); + if (ret) { + err("error, failed to ois_vm(off)"); } - } else { - is_final_cam_module_front = true; - } #endif + } + +isp_fw_err: + if (isp_fw_fp) + filp_close(isp_fw_fp, current->files); + +setfile_err: + if (setfile_fp) + filp_close(setfile_fp, current->files); + +comp_fw_err: + if (comp_fw_fp) + filp_close(comp_fw_fp, current->files); + +key_err: + if (key_fp) + filp_close(key_fp, current->files); + set_fs(old_fs); -exit: return ret; } #endif -#if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) -int fimc_is_sec_read_from_header(struct device *dev) +int fimc_is_sec_check_reload(void) { - int ret = 0; - struct fimc_is_core *core = dev_get_drvdata(fimc_is_dev); - u8 header_version[12] = {0, }; + struct file *reload_key_fp = NULL; + mm_segment_t old_fs; - ret = fimc_is_spi_read(&core->spi0, header_version, 0x40, 0x0B); - if (ret < 0) { - printk(KERN_ERR "failed to fimc_is_spi_read for header version (%d)\n", ret); - ret = -EINVAL; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + reload_key_fp = filp_open("/data/media/0/reload/r1e2l3o4a5d.key", O_RDONLY, 0); + if (IS_ERR(reload_key_fp)) { + info("Reload KEY does not exist.\n"); + reload_key_fp = NULL; + } else { + info("Reload KEY exist, reload cal data.\n"); + force_caldata_dump = true; } - memcpy(sysfs_finfo.header_ver, header_version, 11); - sysfs_finfo.header_ver[11] = '\0'; + if (reload_key_fp) + filp_close(reload_key_fp, current->files); + set_fs(old_fs); - return ret; + return 0; } int fimc_is_sec_readcal(struct fimc_is_core *core) @@ -1441,7 +2331,7 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) goto exit; } - ret = fimc_is_spi_read_module_id(&core->spi0, &id, 0x0, 0x2); + ret = fimc_is_spi_read_module_id(&core->spi0, &id, FROM_HEADER_MODULE_ID_START_ADDR, FROM_HEADER_MODULE_ID_SIZE); if (ret) { printk(KERN_ERR "fimc_is_spi_read_module_id (%d)\n", ret); ret = -EINVAL; @@ -1449,13 +2339,14 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) } info("Camera: FROM Module ID = 0x%04x\n", id); - ret = fimc_is_spi_read(&core->spi0, sysfs_finfo.cal_map_ver, 0x60, 0x4); + ret = fimc_is_spi_read(&core->spi0, sysfs_finfo.cal_map_ver, + FROM_HEADER_CAL_MAP_VER_START_ADDR, FIMC_IS_CAL_MAP_VER_SIZE); if (ret) { printk(KERN_ERR "failed to fimc_is_spi_read (%d)\n", ret); ret = -EINVAL; goto exit; } - info("Camera: Cal map_version = %c%c%c%c\n", sysfs_finfo.cal_map_ver[0], + info("Camera: FROM Cal map_version = %c%c%c%c\n", sysfs_finfo.cal_map_ver[0], sysfs_finfo.cal_map_ver[1], sysfs_finfo.cal_map_ver[2], sysfs_finfo.cal_map_ver[3]); crc_retry: @@ -1468,91 +2359,85 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) goto exit; } - sysfs_finfo.bin_start_addr = *((u32 *)&cal_buf[0x0]); - sysfs_finfo.bin_end_addr = *((u32 *)&cal_buf[0x4]); + sysfs_finfo.bin_start_addr = *((u32 *)&cal_buf[FROM_HEADER_ISP_BINARY_START_ADDR]); + sysfs_finfo.bin_end_addr = *((u32 *)&cal_buf[FROM_HEADER_ISP_BINARY_END_ADDR]); info("Binary start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.bin_start_addr), (sysfs_finfo.bin_end_addr)); - sysfs_finfo.oem_start_addr = *((u32 *)&cal_buf[0x8]); - sysfs_finfo.oem_end_addr = *((u32 *)&cal_buf[0xC]); + sysfs_finfo.oem_start_addr = *((u32 *)&cal_buf[FROM_HEADER_OEM_START_ADDR]); + sysfs_finfo.oem_end_addr = *((u32 *)&cal_buf[FROM_HEADER_OEM_END_ADDR]); info("OEM start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.oem_start_addr), (sysfs_finfo.oem_end_addr)); - sysfs_finfo.awb_start_addr = *((u32 *)&cal_buf[0x10]); - sysfs_finfo.awb_end_addr = *((u32 *)&cal_buf[0x14]); + sysfs_finfo.awb_start_addr = *((u32 *)&cal_buf[FROM_HEADER_AWB_START_ADDR]); + sysfs_finfo.awb_end_addr = *((u32 *)&cal_buf[FROM_HEADER_AWB_END_ADDR]); info("AWB start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.awb_start_addr), (sysfs_finfo.awb_end_addr)); - sysfs_finfo.shading_start_addr = *((u32 *)&cal_buf[0x18]); - sysfs_finfo.shading_end_addr = *((u32 *)&cal_buf[0x1C]); + sysfs_finfo.shading_start_addr = *((u32 *)&cal_buf[FROM_HEADER_SHADING_START_ADDR]); + sysfs_finfo.shading_end_addr = *((u32 *)&cal_buf[FROM_HEADER_SHADING_END_ADDR]); info("Shading start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.shading_start_addr), (sysfs_finfo.shading_end_addr)); - sysfs_finfo.setfile_start_addr = *((u32 *)&cal_buf[0x20]); - sysfs_finfo.setfile_end_addr = *((u32 *)&cal_buf[0x24]); + sysfs_finfo.setfile_start_addr = *((u32 *)&cal_buf[FROM_HEADER_ISP_SETFILE_START_ADDR]); + sysfs_finfo.setfile_end_addr = *((u32 *)&cal_buf[FROM_HEADER_ISP_SETFILE_END_ADDR]); info("Setfile start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.setfile_start_addr), (sysfs_finfo.setfile_end_addr)); #ifdef CONFIG_COMPANION_USE - sysfs_finfo.concord_cal_start_addr = *((u32 *)&cal_buf[0x28]); - sysfs_finfo.concord_cal_end_addr = *((u32 *)&cal_buf[0x2C]); + sysfs_finfo.concord_cal_start_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_CAL_START_ADDR]); + sysfs_finfo.concord_cal_end_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_CAL_END_ADDR]); info("concord cal start = 0x%08x, end = 0x%08x\n", sysfs_finfo.concord_cal_start_addr, sysfs_finfo.concord_cal_end_addr); - sysfs_finfo.concord_bin_start_addr = *((u32 *)&cal_buf[0x30]); - sysfs_finfo.concord_bin_end_addr = *((u32 *)&cal_buf[0x34]); + sysfs_finfo.concord_bin_start_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_BINARY_START_ADDR]); + sysfs_finfo.concord_bin_end_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_BINARY_END_ADDR]); info("concord bin start = 0x%08x, end = 0x%08x\n", sysfs_finfo.concord_bin_start_addr, sysfs_finfo.concord_bin_end_addr); - sysfs_finfo.concord_master_setfile_start_addr = *((u32 *)&cal_buf[0xA8]); - sysfs_finfo.concord_master_setfile_end_addr = sysfs_finfo.concord_master_setfile_start_addr + 16064; - sysfs_finfo.concord_mode_setfile_start_addr = sysfs_finfo.concord_master_setfile_end_addr + 1; - sysfs_finfo.concord_mode_setfile_end_addr = *((u32 *)&cal_buf[0xAC]); - sysfs_finfo.pdaf_cal_start_addr = *((u32 *)&cal_buf[0xB0]); - sysfs_finfo.pdaf_cal_end_addr = *((u32 *)&cal_buf[0xB4]); -#ifdef CONFIG_COMPANION_C1_USE - if (fimc_is_sec_check_from_ver(core)) - sysfs_finfo.pdaf_cal_end_addr = 0x540F; - else - sysfs_finfo.pdaf_cal_end_addr = 0x521F; -#endif + sysfs_finfo.concord_master_setfile_start_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_MASTER_SETFILE_START_ADDR]); + sysfs_finfo.concord_master_setfile_end_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_MASTER_SETFILE_START_ADDR]); + sysfs_finfo.concord_mode_setfile_start_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_MODE_SETFILE_START_ADDR]); + sysfs_finfo.concord_mode_setfile_end_addr = *((u32 *)&cal_buf[FROM_HEADER_CONCORD_MODE_SETFILE_END_ADDR]); + sysfs_finfo.pdaf_cal_start_addr = *((u32 *)&cal_buf[FROM_HEADER_PDAF_CAL_START_ADDR]); + sysfs_finfo.pdaf_cal_end_addr = *((u32 *)&cal_buf[FROM_HEADER_PDAF_CAL_END_ADDR]); info("pdaf start = 0x%08x, end = 0x%08x\n", sysfs_finfo.pdaf_cal_start_addr, sysfs_finfo.pdaf_cal_end_addr); - sysfs_finfo.lsc_i0_gain_addr = 0x4702; + sysfs_finfo.lsc_i0_gain_addr = FROM_SHADING_LSC_I0_GAIN_ADDR; info("Shading lsc_i0 start = 0x%08x\n", sysfs_finfo.lsc_i0_gain_addr); - sysfs_finfo.lsc_j0_gain_addr = sysfs_finfo.lsc_i0_gain_addr + 8; + sysfs_finfo.lsc_j0_gain_addr = FROM_SHADING_LSC_J0_GAIN_ADDR; info("Shading lsc_j0 start = 0x%08x\n", sysfs_finfo.lsc_j0_gain_addr); - sysfs_finfo.lsc_a_gain_addr = sysfs_finfo.lsc_j0_gain_addr + 8; + sysfs_finfo.lsc_a_gain_addr = FROM_SHADING_LSC_A_GAIN_ADDR; info("Shading lsc_a start = 0x%08x\n", sysfs_finfo.lsc_a_gain_addr); - sysfs_finfo.lsc_k4_gain_addr = sysfs_finfo.lsc_a_gain_addr + 16; + sysfs_finfo.lsc_k4_gain_addr = FROM_SHADING_LSC_K4_GAIN_ADDR; info("Shading lsc_k4 start = 0x%08x\n", sysfs_finfo.lsc_k4_gain_addr); - sysfs_finfo.lsc_scale_gain_addr = sysfs_finfo.lsc_k4_gain_addr + 16; + sysfs_finfo.lsc_scale_gain_addr = FROM_SHADING_LSC_SCALE_GAIN_ADDR; #ifdef CONFIG_COMPANION_C1_USE - sysfs_finfo.lsc_gain_start_addr = sysfs_finfo.shading_start_addr + 0x14; - sysfs_finfo.lsc_gain_end_addr = sysfs_finfo.lsc_gain_start_addr + 6600 -1; + sysfs_finfo.lsc_gain_start_addr = FROM_SHADING_LSC_GAIN_START_ADDR; + sysfs_finfo.lsc_gain_end_addr = FROM_SHADING_LSC_GAIN_END_ADDR; info("LSC start = 0x%04x, end = 0x%04x\n", sysfs_finfo.lsc_gain_start_addr, sysfs_finfo.lsc_gain_end_addr); #endif #ifdef CONFIG_COMPANION_C2_USE info("Shading lsc_scale start = 0x%08x\n", sysfs_finfo.lsc_scale_gain_addr); - sysfs_finfo.grasTuning_AwbAshCord_N_addr = sysfs_finfo.lsc_scale_gain_addr + 8; + sysfs_finfo.grasTuning_AwbAshCord_N_addr = FROM_SHADING_GRASTUNING_AWB_ASH_CORD_ADDR; info("Shading grasTuning_AwbAshCord_N start = 0x%08x\n", sysfs_finfo.grasTuning_AwbAshCord_N_addr); - sysfs_finfo.grasTuning_awbAshCordIndexes_N_addr = sysfs_finfo.grasTuning_AwbAshCord_N_addr + 14; + sysfs_finfo.grasTuning_awbAshCordIndexes_N_addr = FROM_SHADING_GRASTUNING_AWB_ASH_CORD_INDEX_ADDR; info("Shading grasTuning_awbAshCordIndexes_N start = 0x%08x\n", sysfs_finfo.grasTuning_awbAshCordIndexes_N_addr); - sysfs_finfo.grasTuning_GASAlpha_M__N_addr = sysfs_finfo.grasTuning_awbAshCordIndexes_N_addr + 14; + sysfs_finfo.grasTuning_GASAlpha_M__N_addr = FROM_SHADING_GRASTUNING_GAS_ALPHA_ADDR; info("Shading lsc_scale start = 0x%08x\n", sysfs_finfo.grasTuning_GASAlpha_M__N_addr); - sysfs_finfo.grasTuning_GASBeta_M__N_addr = sysfs_finfo.grasTuning_GASAlpha_M__N_addr + 56; + sysfs_finfo.grasTuning_GASBeta_M__N_addr = FROM_SHADING_GRASTUNING_GAS_BETA_ADDR; info("Shading grasTuning_GASBeta_M__N start = 0x%08x\n", sysfs_finfo.grasTuning_GASBeta_M__N_addr); - sysfs_finfo.grasTuning_GASOutdoorAlpha_N_addr = sysfs_finfo.grasTuning_GASBeta_M__N_addr + 56; + sysfs_finfo.grasTuning_GASOutdoorAlpha_N_addr = FROM_SHADING_GRASTUNING_GAS_OUTDOOR_ALPHA_ADDR; info("Shading grasTuning_GASOutdoorAlpha_N start = 0x%08x\n", sysfs_finfo.grasTuning_GASOutdoorAlpha_N_addr); - sysfs_finfo.grasTuning_GASOutdoorBeta_N_addr = sysfs_finfo.grasTuning_GASOutdoorAlpha_N_addr + 8; + sysfs_finfo.grasTuning_GASOutdoorBeta_N_addr = FROM_SHADING_GRASTUNING_GAS_OUTDOOR_BETA_ADDR; info("Shading grasTuning_GASOutdoorBeta_N start = 0x%08x\n", sysfs_finfo.grasTuning_GASOutdoorBeta_N_addr); - sysfs_finfo.grasTuning_GASIndoorAlpha_N_addr = sysfs_finfo.grasTuning_GASOutdoorBeta_N_addr + 8; + sysfs_finfo.grasTuning_GASIndoorAlpha_N_addr = FROM_SHADING_GRASTUNING_GAS_INDOOR_ALPHA_ADDR; info("Shading grasTuning_GASIndoorAlpha_N start = 0x%08x\n", sysfs_finfo.grasTuning_GASIndoorAlpha_N_addr); - sysfs_finfo.grasTuning_GASIndoorBeta_N_addr = sysfs_finfo.grasTuning_GASIndoorAlpha_N_addr + 8; + sysfs_finfo.grasTuning_GASIndoorBeta_N_addr = FROM_SHADING_GRASTUNING_GAS_INDOOR_BETA_ADDR; info("Shading grasTuning_GASIndoorBeta_N start = 0x%08x\n", sysfs_finfo.grasTuning_GASIndoorBeta_N_addr); - sysfs_finfo.lsc_gain_start_addr = sysfs_finfo.shading_start_addr + 6; - sysfs_finfo.lsc_gain_end_addr = sysfs_finfo.lsc_gain_start_addr + 5880 -1; + sysfs_finfo.lsc_gain_start_addr = FROM_SHADING_LSC_GAIN_START_ADDR; + sysfs_finfo.lsc_gain_end_addr = FROM_SHADING_LSC_GAIN_END_ADDR; info("LSC start = 0x%04x, end = 0x%04x\n", sysfs_finfo.lsc_gain_start_addr, sysfs_finfo.lsc_gain_end_addr); #endif - sysfs_finfo.pdaf_start_addr = sysfs_finfo.concord_cal_start_addr; - sysfs_finfo.pdaf_end_addr = sysfs_finfo.pdaf_start_addr + 512 -1; + sysfs_finfo.pdaf_start_addr = FROM_CONCORD_CAL_PDAF_START_ADDR; + sysfs_finfo.pdaf_end_addr = FROM_CONCORD_CAL_PDAF_END_ADDR; info("pdaf start = 0x%04x, end = 0x%04x\n", sysfs_finfo.pdaf_start_addr, sysfs_finfo.pdaf_end_addr); #ifdef CONFIG_COMPANION_C2_USE - sysfs_finfo.pdaf_shad_start_addr = sysfs_finfo.pdaf_end_addr + 1 + 4; - sysfs_finfo.pdaf_shad_end_addr = sysfs_finfo.pdaf_shad_start_addr + 1056 - 1; + sysfs_finfo.pdaf_shad_start_addr = FROM_CONCORD_CAL_PDAF_SHADING_START_ADDR; + sysfs_finfo.pdaf_shad_end_addr = FROM_CONCORD_CAL_PDAF_SHADING_END_ADDR; info("pdaf_shad start = 0x%04x, end = 0x%04x\n", sysfs_finfo.pdaf_shad_start_addr, sysfs_finfo.pdaf_shad_end_addr); #endif @@ -1561,57 +2446,58 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) sysfs_finfo.coefficient_cal_end_addr = sysfs_finfo.coefficient_cal_start_addr + 24576 -1; info("coefficient_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coefficient_cal_start_addr, sysfs_finfo.coefficient_cal_end_addr);*/ - sysfs_finfo.coef1_start = sysfs_finfo.pdaf_start_addr + 512 + 16; - sysfs_finfo.coef1_end = sysfs_finfo.coef1_start + 4032 -1; + sysfs_finfo.coef1_start = FROM_CONCORD_XTALK_10_START_ADDR; + sysfs_finfo.coef1_end = FROM_CONCORD_XTALK_10_END_ADDR; info("coefficient1_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef1_start, sysfs_finfo.coef1_end); - sysfs_finfo.coef2_start = sysfs_finfo.coef1_end + 64 + 1; - sysfs_finfo.coef2_end = sysfs_finfo.coef2_start + 4032 -1; + sysfs_finfo.coef2_start = FROM_CONCORD_XTALK_20_START_ADDR; + sysfs_finfo.coef2_end = FROM_CONCORD_XTALK_20_END_ADDR; info("coefficient2_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef2_start, sysfs_finfo.coef2_end); - sysfs_finfo.coef3_start = sysfs_finfo.coef2_end + 64 + 1; - sysfs_finfo.coef3_end = sysfs_finfo.coef3_start + 4032 -1; + sysfs_finfo.coef3_start = FROM_CONCORD_XTALK_30_START_ADDR; + sysfs_finfo.coef3_end = FROM_CONCORD_XTALK_30_END_ADDR; info("coefficient3_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef3_start, sysfs_finfo.coef3_end); - sysfs_finfo.coef4_start = sysfs_finfo.coef3_end + 64 + 1; - sysfs_finfo.coef4_end = sysfs_finfo.coef4_start + 4032 -1; + sysfs_finfo.coef4_start = FROM_CONCORD_XTALK_40_START_ADDR; + sysfs_finfo.coef4_end = FROM_CONCORD_XTALK_40_END_ADDR; info("coefficient4_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef4_start, sysfs_finfo.coef4_end); - sysfs_finfo.coef5_start = sysfs_finfo.coef4_end + 64 + 1; - sysfs_finfo.coef5_end = sysfs_finfo.coef5_start + 4032 -1; + sysfs_finfo.coef5_start = FROM_CONCORD_XTALK_50_START_ADDR; + sysfs_finfo.coef5_end = FROM_CONCORD_XTALK_50_END_ADDR; info("coefficient5_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef5_start, sysfs_finfo.coef5_end); - sysfs_finfo.coef6_start = sysfs_finfo.coef5_end + 64 + 1; - sysfs_finfo.coef6_end = sysfs_finfo.coef6_start + 4032 -1; + sysfs_finfo.coef6_start = FROM_CONCORD_XTALK_60_START_ADDR; + sysfs_finfo.coef6_end = FROM_CONCORD_XTALK_60_END_ADDR; info("coefficient6_cal_addr start = 0x%04x, end = 0x%04x\n", sysfs_finfo.coef6_start, sysfs_finfo.coef6_end); - sysfs_finfo.wcoefficient1_addr = 0xF210; + sysfs_finfo.wcoefficient1_addr = FROM_CONCORD_WCOEF_ADDR; info("Shading wcoefficient1 start = 0x%04x\n", sysfs_finfo.wcoefficient1_addr); #endif #ifdef CONFIG_COMPANION_C2_USE - sysfs_finfo.xtalk_coef_start = sysfs_finfo.pdaf_shad_end_addr + 4 + 24 + 1; - sysfs_finfo.coef_offset_R = 0xEA40; - sysfs_finfo.coef_offset_G = sysfs_finfo.coef_offset_R + 2; - sysfs_finfo.coef_offset_B = sysfs_finfo.coef_offset_G + 2; -#endif - memcpy(sysfs_finfo.concord_header_ver, &cal_buf[0x50], 11); - sysfs_finfo.concord_header_ver[11] = '\0'; + sysfs_finfo.xtalk_coef_start = FROM_CONCORD_XTALK_COEF_ADDR; + sysfs_finfo.coef_offset_R = FROM_CONCORD_COEF_OFFSET_R_ADDR; + sysfs_finfo.coef_offset_G = FROM_CONCORD_COEF_OFFSET_G_ADDR; + sysfs_finfo.coef_offset_B = FROM_CONCORD_COEF_OFFSET_B_ADDR; +#endif + memcpy(sysfs_finfo.concord_header_ver, + &cal_buf[FROM_HEADER_CONCORD_HEADER_VER_START_ADDR], FIMC_IS_HEADER_VER_SIZE); + sysfs_finfo.concord_header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; #ifdef CONFIG_COMPANION_C1_USE - sysfs_finfo.af_inf_addr = 0x1000; - sysfs_finfo.af_macro_addr = 0x1008; - sysfs_finfo.coef1_crc_addr= 0xF21A; - sysfs_finfo.coef2_crc_addr = 0xF21E; - sysfs_finfo.coef3_crc_addr = 0xF222; - sysfs_finfo.coef4_crc_addr = 0xF226; - sysfs_finfo.coef5_crc_addr = 0xF22A; - sysfs_finfo.coef6_crc_addr = 0xF22E; -#endif - sysfs_finfo.lsc_gain_crc_addr = 0x46FE; - sysfs_finfo.pdaf_crc_addr = 0x9200; + sysfs_finfo.af_inf_addr = FROM_OEM_AF_INF_ADDR; + sysfs_finfo.af_macro_addr = FROM_OEM_AF_INF_ADDR; + sysfs_finfo.coef1_crc_addr= FROM_CONCORD_XTALK_10_CHECKSUM_ADDR; + sysfs_finfo.coef2_crc_addr = FROM_CONCORD_XTALK_20_CHECKSUM_ADDR; + sysfs_finfo.coef3_crc_addr = FROM_CONCORD_XTALK_30_CHECKSUM_ADDR; + sysfs_finfo.coef4_crc_addr = FROM_CONCORD_XTALK_40_CHECKSUM_ADDR; + sysfs_finfo.coef5_crc_addr = FROM_CONCORD_XTALK_50_CHECKSUM_ADDR; + sysfs_finfo.coef6_crc_addr = FROM_CONCORD_XTALK_60_CHECKSUM_ADDR; +#endif + sysfs_finfo.lsc_gain_crc_addr = FROM_SHADING_LSC_GAIN_CRC_ADDR; + sysfs_finfo.pdaf_crc_addr = FROM_CONCORD_PDAF_CRC_ADDR; #ifdef CONFIG_COMPANION_C2_USE - sysfs_finfo.pdaf_shad_crc_addr = 0x9624; - sysfs_finfo.xtalk_coef_crc_addr = 0xEA46; - sysfs_finfo.lsc_parameter_crc_addr = 0x47E6; + sysfs_finfo.pdaf_shad_crc_addr = FROM_CONCORD_PDAF_SHAD_CRC_ADDR; + sysfs_finfo.xtalk_coef_crc_addr = FROM_CONCORD_XTALK_COEF_CRC_ADDR; + sysfs_finfo.lsc_parameter_crc_addr = FROM_SHADING_LSC_PARAMETER_CRC_ARRD; info("xtalk_coef_start = 0x%04x\n", sysfs_finfo.xtalk_coef_start); info("lsc_gain_crc_addr = 0x%04x\n", sysfs_finfo.lsc_gain_crc_addr); @@ -1622,7 +2508,8 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) #endif #endif - if (sysfs_finfo.setfile_end_addr < 0x8000 || sysfs_finfo.setfile_end_addr > 0x3fffff) { + if (sysfs_finfo.setfile_end_addr < FROM_ISP_BINARY_SETFILE_START_ADDR + || sysfs_finfo.setfile_end_addr > FROM_ISP_BINARY_SETFILE_END_ADDR) { info("setfile end_addr has error!! 0x%08x\n", sysfs_finfo.setfile_end_addr); sysfs_finfo.setfile_end_addr = 0x1fffff; } @@ -1630,41 +2517,47 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) info("Setfile start = 0x%08x, end = 0x%08x\n", (sysfs_finfo.setfile_start_addr), (sysfs_finfo.setfile_end_addr)); - memcpy(sysfs_finfo.header_ver, &cal_buf[0x40], 11); - sysfs_finfo.header_ver[11] = '\0'; - memcpy(sysfs_finfo.cal_map_ver, &cal_buf[0x60], 4); - memcpy(sysfs_finfo.setfile_ver, &cal_buf[0x64], 6); - sysfs_finfo.setfile_ver[6] = '\0'; - memcpy(sysfs_finfo.oem_ver, &cal_buf[0x1FE0], 11); - sysfs_finfo.oem_ver[11] = '\0'; - memcpy(sysfs_finfo.awb_ver, &cal_buf[0x2FE0], 11); - sysfs_finfo.awb_ver[11] = '\0'; - memcpy(sysfs_finfo.shading_ver, &cal_buf[0x4FE0], 11); - sysfs_finfo.shading_ver[11] = '\0'; - memcpy(sysfs_finfo.project_name, &cal_buf[0x6E], 8); - sysfs_finfo.project_name[8] = '\0'; + memcpy(sysfs_finfo.header_ver, &cal_buf[FROM_HEADER_VERSION_START_ADDR], FIMC_IS_HEADER_VER_SIZE); + sysfs_finfo.header_ver[FIMC_IS_HEADER_VER_SIZE] = '\0'; + memcpy(sysfs_finfo.cal_map_ver, &cal_buf[FROM_HEADER_CAL_MAP_VER_START_ADDR], FIMC_IS_CAL_MAP_VER_SIZE); + memcpy(sysfs_finfo.setfile_ver, + &cal_buf[FROM_HEADER_ISP_SETFILE_VER_START_ADDR], FIMC_IS_ISP_SETFILE_VER_SIZE); + sysfs_finfo.setfile_ver[FIMC_IS_ISP_SETFILE_VER_SIZE] = '\0'; + memcpy(sysfs_finfo.oem_ver, &cal_buf[FROM_OEM_VER_START_ADDR], FIMC_IS_OEM_VER_SIZE); + sysfs_finfo.oem_ver[FIMC_IS_OEM_VER_SIZE] = '\0'; + memcpy(sysfs_finfo.awb_ver, &cal_buf[FROM_AWB_VER_START_ADDR], FIMC_IS_AWB_VER_SIZE); + sysfs_finfo.awb_ver[FIMC_IS_AWB_VER_SIZE] = '\0'; + memcpy(sysfs_finfo.shading_ver, &cal_buf[FROM_SHADING_VER_START_ADDR], FIMC_IS_SHADING_VER_SIZE); + sysfs_finfo.shading_ver[FIMC_IS_SHADING_VER_SIZE] = '\0'; + memcpy(sysfs_finfo.project_name, &cal_buf[FROM_HEADER_PROJECT_NAME_START_ADDR], FIMC_IS_PROJECT_NAME_SIZE); + sysfs_finfo.project_name[FIMC_IS_PROJECT_NAME_SIZE] = '\0'; fw_core_version = sysfs_finfo.header_ver[0]; + sysfs_finfo.fw_size = sysfs_finfo.bin_end_addr - sysfs_finfo.bin_start_addr + 1; + sysfs_finfo.setfile_size = sysfs_finfo.setfile_end_addr - sysfs_finfo.setfile_start_addr + 1; + sysfs_finfo.comp_fw_size = sysfs_finfo.concord_bin_end_addr - sysfs_finfo.concord_bin_start_addr + 1; + info("fw_size = %ld\n", sysfs_finfo.fw_size); + info("setfile_size = %ld\n", sysfs_finfo.setfile_size); + info("comp_fw_size = %ld\n", sysfs_finfo.comp_fw_size); + /* debug info dump */ -//#if defined(FROM_DEBUG) -#if 1 info("++++ FROM data info\n"); info("1. Header info\n"); info("Module info : %s\n", sysfs_finfo.header_ver); #ifdef CONFIG_COMPANION_USE info("Companion version info : %s\n", sysfs_finfo.concord_header_ver); #endif - info(" ID : %c\n", sysfs_finfo.header_ver[0]); - info(" Pixel num : %c%c\n", sysfs_finfo.header_ver[1], - sysfs_finfo.header_ver[2]); - info(" ISP ID : %c\n", sysfs_finfo.header_ver[3]); - info(" Sensor Maker : %c\n", sysfs_finfo.header_ver[4]); - info(" Year : %c\n", sysfs_finfo.header_ver[5]); - info(" Month : %c\n", sysfs_finfo.header_ver[6]); - info(" Release num : %c%c\n", sysfs_finfo.header_ver[7], - sysfs_finfo.header_ver[8]); - info(" Manufacturer ID : %c\n", sysfs_finfo.header_ver[9]); - info(" Module ver : %c\n", sysfs_finfo.header_ver[10]); + info(" ID : %c\n", sysfs_finfo.header_ver[FW_CORE_VER]); + info(" Pixel num : %c%c\n", sysfs_finfo.header_ver[FW_PIXEL_SIZE], + sysfs_finfo.header_ver[FW_PIXEL_SIZE + 1]); + info(" ISP ID : %c\n", sysfs_finfo.header_ver[FW_ISP_COMPANY]); + info(" Sensor Maker : %c\n", sysfs_finfo.header_ver[FW_SENSOR_MAKER]); + info(" Year : %c\n", sysfs_finfo.header_ver[FW_PUB_YEAR]); + info(" Month : %c\n", sysfs_finfo.header_ver[FW_PUB_MON]); + info(" Release num : %c%c\n", sysfs_finfo.header_ver[FW_PUB_NUM], + sysfs_finfo.header_ver[FW_PUB_NUM + 1]); + info(" Manufacturer ID : %c\n", sysfs_finfo.header_ver[FW_MODULE_COMPANY]); + info(" Module ver : %c\n", sysfs_finfo.header_ver[FW_VERSION_INFO]); info("Cal data map ver : %s\n", sysfs_finfo.cal_map_ver); info("Setfile ver : %s\n", sysfs_finfo.setfile_ver); info("Project name : %s\n", sysfs_finfo.project_name); @@ -1675,7 +2568,6 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) info("4. Shading info\n"); info("Module info : %s\n", sysfs_finfo.shading_ver); info("---- FROM data info\n"); -#endif /* CRC check */ #ifdef CONFIG_COMPANION_USE @@ -1791,15 +2683,15 @@ int fimc_is_sec_readcal(struct fimc_is_core *core) return ret; } +#ifdef CAMERA_MODULE_DUALIZE int fimc_is_sec_readfw(struct fimc_is_core *core) { int ret = 0; loff_t pos = 0; char fw_path[100]; - char setfile_path[100]; int retry = FIMC_IS_FW_RETRY_CNT; - info("Camera: FW, Setfile need to be dumped\n"); + info("Camera: FW need to be dumped\n"); crc_retry: /* read fw data */ @@ -1824,14 +2716,26 @@ int fimc_is_sec_readfw(struct fimc_is_core *core) snprintf(fw_path, sizeof(fw_path), "%s%s", FIMC_IS_FW_DUMP_PATH, sysfs_finfo.load_fw_name); - if (write_data_to_file(fw_path, fw_buf, - sysfs_finfo.bin_end_addr - sysfs_finfo.bin_start_addr + 1, &pos) < 0) { + if (write_data_to_file(fw_path, fw_buf, sysfs_finfo.fw_size, &pos) < 0) { ret = -EIO; goto exit; } info("Camera: FW Data has dumped successfully\n"); +exit: + return ret; +} + +int fimc_is_sec_read_setfile(struct fimc_is_core *core) +{ + int ret = 0; + loff_t pos = 0; + char setfile_path[100]; + int retry = FIMC_IS_FW_RETRY_CNT; + + info("Camera: Setfile need to be dumped\n"); + setfile_crc_retry: /* read setfile data */ info("Camera: Start SPI read setfile data\n"); @@ -1842,7 +2746,7 @@ int fimc_is_sec_readfw(struct fimc_is_core *core) ret = -EINVAL; goto exit; } - info("Camera: End SPI read fw data\n"); + info("Camera: End SPI read setfile data\n"); /* CRC check */ if (!fimc_is_sec_check_setfile_crc32(fw_buf) && (retry > 0)) { @@ -1856,20 +2760,20 @@ int fimc_is_sec_readfw(struct fimc_is_core *core) snprintf(setfile_path, sizeof(setfile_path), "%s%s", FIMC_IS_FW_DUMP_PATH, sysfs_finfo.load_setfile_name); pos = 0; - if (write_data_to_file(setfile_path, fw_buf, - sysfs_finfo.setfile_end_addr - sysfs_finfo.setfile_start_addr + 1, &pos) < 0) { + if (write_data_to_file(setfile_path, fw_buf, sysfs_finfo.setfile_size, &pos) < 0) { ret = -EIO; goto exit; } info("Camera: Setfile has dumped successfully\n"); - info("Camera: FW, Setfile were dumped successfully\n"); exit: return ret; } #endif +#endif +#ifdef CAMERA_MODULE_DUALIZE #ifdef CONFIG_COMPANION_USE int fimc_is_sec_read_companion_fw(struct fimc_is_core *core) { @@ -1906,8 +2810,7 @@ int fimc_is_sec_read_companion_fw(struct fimc_is_core *core) snprintf(fw_path, sizeof(fw_path), "%s%s", FIMC_IS_FW_DUMP_PATH, sysfs_finfo.load_c1_fw_name); - if (write_data_to_file(fw_path, fw_buf, - sysfs_finfo.concord_bin_end_addr - sysfs_finfo.concord_bin_start_addr + 1, &pos) < 0) { + if (write_data_to_file(fw_path, fw_buf, sysfs_finfo.comp_fw_size, &pos) < 0) { ret = -EIO; goto exit; } @@ -1939,6 +2842,7 @@ int fimc_is_sec_read_companion_fw(struct fimc_is_core *core) return ret; } #endif +#endif #if 0 int fimc_is_sec_gpio_enable(struct exynos_platform_fimc_is *pdata, char *name, bool on) @@ -2063,7 +2967,7 @@ int fimc_is_sec_core_voltage_select(struct device *dev, char *header_ver) * * @ return: true, false or error value */ -static int fimc_is_sec_ldo_enabled(struct device *dev, char *name) { +int fimc_is_sec_ldo_enabled(struct device *dev, char *name) { struct regulator *regulator = NULL; int enabled = 0; @@ -2154,6 +3058,10 @@ int fimc_is_sec_fw_find(struct fimc_is_core *core) snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_IMX240), "%s", FIMC_IS_FW_IMX240); snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_IMX240_SETF), "%s", FIMC_IS_IMX240_SETF); core_pdata->rear_sensor_id = SENSOR_NAME_IMX240; + } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_IMX228)) { + snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_IMX228), "%s", FIMC_IS_FW_IMX228); + snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_IMX228_SETF), "%s", FIMC_IS_IMX228_SETF); + core_pdata->rear_sensor_id = SENSOR_NAME_IMX228; } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, FW_2T2)) { snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_2T2_EVT1), "%s", FIMC_IS_FW_2T2_EVT1); snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_2T2_SETF), "%s", FIMC_IS_2T2_SETF); @@ -2165,6 +3073,10 @@ int fimc_is_sec_fw_find(struct fimc_is_core *core) /* IMX240 */ snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_IMX240), "%s", FIMC_IS_FW_IMX240); snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_IMX240_SETF), "%s", FIMC_IS_IMX240_SETF); + } else if (sensor_id == SENSOR_NAME_IMX228) { + /* IMX228 */ + snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_IMX228), "%s", FIMC_IS_FW_IMX228); + snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_IMX228_SETF), "%s", FIMC_IS_IMX228_SETF); } else if (sensor_id == SENSOR_NAME_IMX134) { /* IMX134 */ snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_IMX134), "%s", FIMC_IS_FW_IMX134); @@ -2190,8 +3102,8 @@ int fimc_is_sec_fw_find(struct fimc_is_core *core) snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_2T2_EVT1), "%s", FIMC_IS_FW_2T2_EVT1); snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_2T2_SETF), "%s", FIMC_IS_2T2_SETF); } else { - snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW), "%s", FIMC_IS_FW); - snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_IMX135_SETF), "%s", FIMC_IS_IMX135_SETF); + snprintf(sysfs_finfo.load_fw_name, sizeof(FIMC_IS_FW_2P2), "%s", FIMC_IS_FW_2P2); + snprintf(sysfs_finfo.load_setfile_name, sizeof(FIMC_IS_2P2_SETF), "%s", FIMC_IS_2P2_SETF); } } @@ -2210,6 +3122,12 @@ int fimc_is_sec_run_fw_sel(struct device *dev, int position) return -EINVAL; } + /* Check reload cal data enabled */ + if (!sysfs_finfo.is_check_cal_reload) { + fimc_is_sec_check_reload(); + } + sysfs_finfo.is_check_cal_reload = true; + #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) if (position == SENSOR_POSITION_FRONT) { if (!sysfs_finfo.is_caldata_read || force_caldata_dump) { @@ -2270,7 +3188,6 @@ int fimc_is_sec_run_fw_sel(struct device *dev, int position) } #endif - info("%s:%d\n", __func__, ret); return ret; } @@ -2279,7 +3196,7 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) { int ret = 0; char fw_path[100]; - char phone_fw_version[12] = {0, }; + char phone_fw_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; struct file *fp = NULL; mm_segment_t old_fs; @@ -2311,6 +3228,16 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) } if (!fimc_is_sec_ldo_enabled(dev, "VDDIO_1.8V_CAM")) { +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel_eeprom: error, failed to ois_vdd(on)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel_eeprom: error, failed to ois_vm(on)"); + } +#endif ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", true); if (ret) { err("fimc_is_sec_fw_sel_eeprom: error, failed to VDDIO_1.8V_CAM(on)"); @@ -2320,8 +3247,7 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) } info("Camera: read cal data from Front EEPROM\n"); - if ((fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_FRONT) != -EIO) && - crc32_header_check_front) { + if (!fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_FRONT)) { sysfs_finfo_front.is_caldata_read = true; } } @@ -2335,6 +3261,16 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) info("forced caldata dump!!\n"); if (!fimc_is_sec_ldo_enabled(dev, "VDDIO_1.8V_CAM")) { +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel_eeprom: error, failed to ois_vdd(on)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel_eeprom: error, failed to ois_vm(on)"); + } +#endif ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", true); if (ret) { err("fimc_is_sec_fw_sel_eeprom: error, failed to VDDIO_1.8V_CAM(on)"); @@ -2346,11 +3282,10 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) info("Camera: read cal data from Rear EEPROM\n"); if (headerOnly) { #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) - fimc_is_sec_read_eeprom_header(dev); + fimc_is_sec_read_eeprom_header(dev, SENSOR_POSITION_REAR); #endif } else { - if ((fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_REAR) != -EIO) && - crc32_header_check) { + if (!fimc_is_sec_readcal_eeprom(dev, SENSOR_POSITION_REAR)) { sysfs_finfo.is_caldata_read = true; } } @@ -2378,7 +3313,14 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) fsize = fp->f_path.dentry->d_inode->i_size; info("start, file path %s, size %ld Bytes\n", fw_path, fsize); - if (fsize > FIMC_IS_MAX_FW_SIZE) { + +#ifdef CAMERA_MODULE_DUALIZE + if (FIMC_IS_MAX_FW_SIZE >= fsize) { + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + temp_buf = fw_buf; + } else +#endif + { info("Phone FW size is larger than FW buffer. Use vmalloc.\n"); read_buf = vmalloc(fsize); if (!read_buf) { @@ -2387,9 +3329,6 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) goto read_phone_fw_exit; } temp_buf = read_buf; - } else { - memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); - temp_buf = fw_buf; } nread = vfs_read(fp, (char __user *)temp_buf, fsize, &fp->f_pos); if (nread != fsize) { @@ -2398,8 +3337,8 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) goto read_phone_fw_exit; } - strncpy(phone_fw_version, temp_buf + nread - 11, 11); - strncpy(sysfs_pinfo.header_ver, temp_buf + nread - 11, 11); + strncpy(phone_fw_version, temp_buf + nread - 11, FIMC_IS_HEADER_VER_SIZE); + strncpy(sysfs_pinfo.header_ver, temp_buf + nread - 11, FIMC_IS_HEADER_VER_SIZE); info("Camera: phone fw version: %s\n", phone_fw_version); read_phone_fw_exit: @@ -2428,6 +3367,14 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", false); if (ret) err("fimc_is_sec_fw_sel_eeprom: error, failed to VDDIO_1.8V_CAM(off)"); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel_eeprom: error, failed to OIS_VDD_2.8V(off)"); + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel_eeprom: error, failed to OIS_VM_2.8V(off)"); +#endif } } else #endif @@ -2436,6 +3383,14 @@ int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly) ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", false); if (ret) err("fimc_is_sec_fw_sel_eeprom: error, failed to VDDIO_1.8V_CAM(off)"); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel_eeprom: error, failed to OIS_VDD_2.8V(off)"); + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel_eeprom: error, failed to OIS_VM_2.8V(off)"); +#endif } } @@ -2451,19 +3406,23 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade int ret = 0; char fw_path[100]; char dump_fw_path[100]; - char dump_fw_version[12] = {0, }; - char phone_fw_version[12] = {0, }; + char dump_fw_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; + char phone_fw_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; +#ifdef CAMERA_MODULE_DUALIZE int from_fw_revision = 0; int dump_fw_revision = 0; int phone_fw_revision = 0; - + bool dump_flag = false; + struct file *setfile_fp = NULL; + char setfile_path[100]; +#endif struct file *fp = NULL; mm_segment_t old_fs; long fsize, nread; u8 *read_buf = NULL; u8 *temp_buf = NULL; bool is_dump_existed = false; - bool is_dump_needed = true; + bool is_dump_needed = false; #ifdef CONFIG_COMPANION_USE struct fimc_is_spi_gpio *spi_gpio = &core->spi0.gpio; #endif @@ -2485,6 +3444,16 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade if (!fimc_is_sec_ldo_enabled(dev, "VDDIO_1.8V_CAM")) { info("enable %s in the %s\n", "VDDIO_1.8V_CAM", __func__); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel: error, failed to ois_vdd(on)"); + } + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", true); + if (ret) { + err("fimc_is_sec_fw_sel: error, failed to ois_vm(on)"); + } +#endif ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", true); if (ret) { err("fimc_is_sec_fw_sel: error, failed to cam_io(on)"); @@ -2501,8 +3470,7 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade if (headerOnly) { fimc_is_sec_read_from_header(dev); } else { - if ((fimc_is_sec_readcal(core) != -EIO) && - crc32_header_check) { + if (!fimc_is_sec_readcal(core)) { sysfs_finfo.is_caldata_read = true; } } @@ -2539,7 +3507,14 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade fsize = fp->f_path.dentry->d_inode->i_size; info("start, file path %s, size %ld Bytes\n", dump_fw_path, fsize); - if (fsize > FIMC_IS_MAX_FW_SIZE) { + +#ifdef CAMERA_MODULE_DUALIZE + if (FIMC_IS_MAX_FW_SIZE >= fsize) { + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + temp_buf = fw_buf; + } else +#endif + { info("Dumped FW size is larger than FW buffer. Use vmalloc.\n"); read_buf = vmalloc(fsize); if (!read_buf) { @@ -2548,9 +3523,6 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade goto read_phone_fw; } temp_buf = read_buf; - } else { - memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); - temp_buf = fw_buf; } nread = vfs_read(fp, (char __user *)temp_buf, fsize, &fp->f_pos); if (nread != fsize) { @@ -2559,7 +3531,7 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade goto read_phone_fw; } - strncpy(dump_fw_version, temp_buf + nread-11, 11); + strncpy(dump_fw_version, temp_buf + nread-11, FIMC_IS_HEADER_VER_SIZE); info("Camera: dumped fw version: %s\n", dump_fw_version); read_phone_fw: @@ -2591,7 +3563,14 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade fsize = fp->f_path.dentry->d_inode->i_size; info("start, file path %s, size %ld Bytes\n", fw_path, fsize); - if (fsize > FIMC_IS_MAX_FW_SIZE) { + +#ifdef CAMERA_MODULE_DUALIZE + if (FIMC_IS_MAX_FW_SIZE >= fsize) { + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + temp_buf = fw_buf; + } else +#endif + { info("Phone FW size is larger than FW buffer. Use vmalloc.\n"); read_buf = vmalloc(fsize); if (!read_buf) { @@ -2600,9 +3579,6 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade goto read_phone_fw_exit; } temp_buf = read_buf; - } else { - memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); - temp_buf = fw_buf; } nread = vfs_read(fp, (char __user *)temp_buf, fsize, &fp->f_pos); if (nread != fsize) { @@ -2611,8 +3587,8 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade goto read_phone_fw_exit; } - strncpy(phone_fw_version, temp_buf + nread - 11, 11); - strncpy(sysfs_pinfo.header_ver, temp_buf + nread - 11, 11); + strncpy(phone_fw_version, temp_buf + nread - 11, FIMC_IS_HEADER_VER_SIZE); + strncpy(sysfs_pinfo.header_ver, temp_buf + nread - 11, FIMC_IS_HEADER_VER_SIZE); info("Camera: phone fw version: %s\n", phone_fw_version); read_phone_fw_exit: @@ -2632,6 +3608,7 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade if (ret < 0) goto exit; +#ifdef CAMERA_MODULE_DUALIZE from_fw_revision = fimc_is_sec_fw_revision(sysfs_finfo.header_ver); phone_fw_revision = fimc_is_sec_fw_revision(phone_fw_version); if (is_dump_existed) { @@ -2672,14 +3649,28 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade } } - if (is_dump_needed) { + if (force_caldata_dump) { + if ((!fimc_is_sec_fw_module_compare(sysfs_finfo.header_ver, phone_fw_version)) + || (from_fw_revision > phone_fw_revision)) + dump_flag = true; + } else { + if (is_dump_needed) { + dump_flag = true; + crc32_fw_check = false; + crc32_setfile_check = false; + } + } + + if (dump_flag) { info("Dump ISP Firmware.\n"); #ifdef CONFIG_COMPANION_USE fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, false); #endif ret = fimc_is_sec_readfw(core); + msleep(20); + ret |= fimc_is_sec_read_setfile(core); #ifdef CONFIG_COMPANION_USE - fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, true); + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_OUTPUT, true); #endif if (ret < 0) { if (!crc32_fw_check || !crc32_setfile_check) { @@ -2693,12 +3684,38 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade strcpy(sysfs_pinfo.header_ver, "NULL"); } + if (is_dumped_fw_loading_needed) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + snprintf(setfile_path, sizeof(setfile_path), "%s%s", + FIMC_IS_FW_DUMP_PATH, sysfs_finfo.load_setfile_name); + setfile_fp = filp_open(setfile_path, O_RDONLY, 0); + if (IS_ERR_OR_NULL(setfile_fp)) { + set_fs(old_fs); + crc32_setfile_check = false; + info("setfile does not exist. Retry setfile dump.\n"); +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, false); +#endif + fimc_is_sec_read_setfile(core); +#ifdef CONFIG_COMPANION_USE + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_OUTPUT, true); +#endif + setfile_fp = NULL; + } else { + if (setfile_fp) + filp_close(setfile_fp, current->files); + set_fs(old_fs); + } + } +#endif + if (is_dump_needed && is_dumped_fw_loading_needed) { - strncpy(loaded_fw, sysfs_finfo.header_ver, 11); + strncpy(loaded_fw, sysfs_finfo.header_ver, FIMC_IS_HEADER_VER_SIZE); } else if (!is_dump_needed && is_dumped_fw_loading_needed) { - strncpy(loaded_fw, dump_fw_version, 11); + strncpy(loaded_fw, dump_fw_version, FIMC_IS_HEADER_VER_SIZE); } else { - strncpy(loaded_fw, phone_fw_version, 11); + strncpy(loaded_fw, phone_fw_version, FIMC_IS_HEADER_VER_SIZE); } } else { @@ -2715,6 +3732,14 @@ int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool heade ret = fimc_is_sec_ldo_enable(dev, "VDDIO_1.8V_CAM", false); if (ret) err("fimc_is_sec_fw_sel: error, failed to cam_io(off)"); +#ifdef CONFIG_OIS_USE + ret = fimc_is_sec_ldo_enable(dev, "OIS_VDD_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel: error, failed to OIS_VDD_2.8V(off)"); + ret = fimc_is_sec_ldo_enable(dev, "OIS_VM_2.8V", false); + if (ret) + err("fimc_is_sec_fw_sel: error, failed to OIS_VM_2.8V(off)"); +#endif } mutex_unlock(&core->spi_lock); @@ -2729,21 +3754,22 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) int ret = 0; char c1_fw_path[100]; char dump_c1_fw_path[100]; - char dump_c1_fw_version[12] = {0, }; - char phone_c1_fw_version[12] = {0, }; + char dump_c1_fw_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; + char phone_c1_fw_version[FIMC_IS_HEADER_VER_SIZE + 1] = {0, }; +#ifdef CAMERA_MODULE_DUALIZE int from_c1_fw_revision = 0; int dump_c1_fw_revision = 0; int phone_c1_fw_revision = 0; - + struct fimc_is_spi_gpio *spi_gpio = &core->spi0.gpio; +#endif struct file *fp = NULL; mm_segment_t old_fs; long fsize, nread; u8 *read_buf = NULL; u8 *temp_buf = NULL; bool is_dump_existed = false; - bool is_dump_needed = true; + bool is_dump_needed = false; int sensor_id = 0; - struct fimc_is_spi_gpio *spi_gpio = &core->spi0.gpio; if ((!sysfs_finfo.is_c1_caldata_read && (cam_id == CAMERA_SINGLE_REAR /* || cam_id == CAMERA_DUAL_FRONT*/)) || @@ -2752,8 +3778,7 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) if (force_caldata_dump) info("forced caldata dump!!\n"); - info("Load companion fw from FROM, fw header version = %s\n", sysfs_finfo.concord_header_ver); - sysfs_finfo.is_c1_caldata_read = true; + sysfs_finfo.is_c1_caldata_read = true; if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_2P2_F) || fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_2P2_I) || @@ -2764,6 +3789,13 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) sysfs_finfo.sensor_id = COMPANION_SENSOR_2P2; snprintf(sysfs_finfo.load_c1_mastersetf_name, sizeof(FIMC_IS_COMPANION_2P2_MASTER_SETF), "%s", FIMC_IS_COMPANION_2P2_MASTER_SETF); snprintf(sysfs_finfo.load_c1_modesetf_name, sizeof(FIMC_IS_COMPANION_2P2_MODE_SETF), "%s", FIMC_IS_COMPANION_2P2_MODE_SETF); + } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_IMX228)) { + snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s", + FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_IMX228_EVT1); + snprintf(sysfs_finfo.load_c1_fw_name, sizeof(FIMC_IS_FW_COMPANION_IMX228_EVT1), "%s", FIMC_IS_FW_COMPANION_IMX228_EVT1); + sysfs_finfo.sensor_id = COMPANION_SENSOR_IMX240; + snprintf(sysfs_finfo.load_c1_mastersetf_name, sizeof(FIMC_IS_COMPANION_IMX228_MASTER_SETF), "%s", FIMC_IS_COMPANION_IMX228_MASTER_SETF); + snprintf(sysfs_finfo.load_c1_modesetf_name, sizeof(FIMC_IS_COMPANION_IMX228_MODE_SETF), "%s", FIMC_IS_COMPANION_IMX228_MODE_SETF); } else if (fimc_is_sec_fw_module_compare(sysfs_finfo.concord_header_ver, FW_IMX240)) { snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s", FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_IMX240_EVT1); @@ -2795,6 +3827,13 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) sysfs_finfo.sensor_id = COMPANION_SENSOR_IMX240; snprintf(sysfs_finfo.load_c1_mastersetf_name, sizeof(FIMC_IS_COMPANION_IMX240_MASTER_SETF), "%s", FIMC_IS_COMPANION_IMX240_MASTER_SETF); snprintf(sysfs_finfo.load_c1_modesetf_name, sizeof(FIMC_IS_COMPANION_IMX240_MODE_SETF), "%s", FIMC_IS_COMPANION_IMX240_MODE_SETF); + } else if (sensor_id == SENSOR_NAME_IMX228) { + snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s", + FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_IMX228_EVT1); + snprintf(sysfs_finfo.load_c1_fw_name, sizeof(FIMC_IS_FW_COMPANION_IMX228_EVT1), "%s", FIMC_IS_FW_COMPANION_IMX228_EVT1); + sysfs_finfo.sensor_id = COMPANION_SENSOR_IMX240; /* for bringup */ + snprintf(sysfs_finfo.load_c1_mastersetf_name, sizeof(FIMC_IS_COMPANION_IMX228_MASTER_SETF), "%s", FIMC_IS_COMPANION_IMX228_MASTER_SETF); + snprintf(sysfs_finfo.load_c1_modesetf_name, sizeof(FIMC_IS_COMPANION_IMX228_MODE_SETF), "%s", FIMC_IS_COMPANION_IMX228_MODE_SETF); } else if (sensor_id == SENSOR_NAME_S5K2P2_12M) { snprintf(c1_fw_path, sizeof(c1_fw_path), "%s%s", FIMC_IS_FW_PATH, FIMC_IS_FW_COMPANION_2P2_12M_EVT1); @@ -2845,7 +3884,14 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) fsize = fp->f_path.dentry->d_inode->i_size; info("start, file path %s, size %ld Bytes\n", dump_c1_fw_path, fsize); - if (fsize > FIMC_IS_MAX_FW_SIZE) { + +#ifdef CAMERA_MODULE_DUALIZE + if (FIMC_IS_MAX_FW_SIZE >= fsize) { + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + temp_buf = fw_buf; + } else +#endif + { info("Dumped Companion FW size is larger than FW buffer. Use vmalloc.\n"); read_buf = vmalloc(fsize); if (!read_buf) { @@ -2854,9 +3900,6 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) goto read_phone_fw; } temp_buf = read_buf; - } else { - memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); - temp_buf = fw_buf; } nread = vfs_read(fp, (char __user *)temp_buf, fsize, &fp->f_pos); if (nread != fsize) { @@ -2865,7 +3908,7 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) goto read_phone_fw; } - strncpy(dump_c1_fw_version, temp_buf + nread - 16, 11); + strncpy(dump_c1_fw_version, temp_buf + nread - 16, FIMC_IS_HEADER_VER_SIZE); info("Camera: dumped companion fw version: %s\n", dump_c1_fw_version); read_phone_fw: @@ -2897,7 +3940,14 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) fsize = fp->f_path.dentry->d_inode->i_size; info("start, file path %s, size %ld Bytes\n", c1_fw_path, fsize); - if (fsize > FIMC_IS_MAX_FW_SIZE) { + +#ifdef CAMERA_MODULE_DUALIZE + if (FIMC_IS_MAX_FW_SIZE >= fsize) { + memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); + temp_buf = fw_buf; + } else +#endif + { info("Phone Companion FW size is larger than FW buffer. Use vmalloc.\n"); read_buf = vmalloc(fsize); if (!read_buf) { @@ -2906,9 +3956,6 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) goto read_phone_fw_exit; } temp_buf = read_buf; - } else { - memset(fw_buf, 0x0, FIMC_IS_MAX_FW_SIZE); - temp_buf = fw_buf; } nread = vfs_read(fp, (char __user *)temp_buf, fsize, &fp->f_pos); if (nread != fsize) { @@ -2917,8 +3964,8 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) goto read_phone_fw_exit; } - strncpy(phone_c1_fw_version, temp_buf + nread - 16, 11); - strncpy(sysfs_pinfo.concord_header_ver, temp_buf + nread - 16, 11); + strncpy(phone_c1_fw_version, temp_buf + nread - 16, FIMC_IS_HEADER_VER_SIZE); + strncpy(sysfs_pinfo.concord_header_ver, temp_buf + nread - 16, FIMC_IS_HEADER_VER_SIZE); info("Camera: phone companion fw version: %s\n", phone_c1_fw_version); read_phone_fw_exit: @@ -2938,6 +3985,7 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) if (ret < 0) goto exit; +#ifdef CAMERA_MODULE_DUALIZE from_c1_fw_revision = fimc_is_sec_fw_revision(sysfs_finfo.concord_header_ver); phone_c1_fw_revision = fimc_is_sec_fw_revision(phone_c1_fw_version); if (is_dump_existed) { @@ -2980,9 +4028,10 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) if (is_dump_needed) { info("Dump companion Firmware.\n"); + crc32_c1_fw_check = false; fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, false); ret = fimc_is_sec_read_companion_fw(core); - fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_FUNC, true); + fimc_is_spi_s_port(spi_gpio, FIMC_IS_SPI_OUTPUT, true); if (ret < 0) { if (!crc32_c1_fw_check) { is_dumped_c1_fw_loading_needed = false; @@ -2994,13 +4043,14 @@ int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev) if (phone_c1_fw_version[0] == 0) { strcpy(sysfs_pinfo.concord_header_ver, "NULL"); } +#endif if (is_dump_needed && is_dumped_c1_fw_loading_needed) { - strncpy(loaded_companion_fw, sysfs_finfo.concord_header_ver, 11); + strncpy(loaded_companion_fw, sysfs_finfo.concord_header_ver, FIMC_IS_HEADER_VER_SIZE); } else if (!is_dump_needed && is_dumped_c1_fw_loading_needed) { - strncpy(loaded_companion_fw, dump_c1_fw_version, 11); + strncpy(loaded_companion_fw, dump_c1_fw_version, FIMC_IS_HEADER_VER_SIZE); } else { - strncpy(loaded_companion_fw, phone_c1_fw_version, 11); + strncpy(loaded_companion_fw, phone_c1_fw_version, FIMC_IS_HEADER_VER_SIZE); } } else { info("already loaded the firmware, Phone_Comp version=%s, F-ROM_Comp version=%s\n", diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.h index ae0d77946489..1bf4004420aa 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.h +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sec-define.h @@ -51,6 +51,7 @@ #include "fimc-is-device-ischain.h" #include "crc32.h" #include "fimc-is-companion.h" +#include "fimc-is-device-from.h" #define FW_CORE_VER 0 #define FW_PIXEL_SIZE 1 @@ -96,6 +97,7 @@ #define FW_3L2 "C13LL" #define FW_IMX135 "C13LS" #define FW_IMX134 "D08LS" +#define FW_IMX228 "A20LS" #define FW_IMX240 "A16LS" #define FW_IMX240_Q "H16US" #define FW_IMX240_Q_C1 "H16UL" @@ -111,6 +113,7 @@ #define FIMC_IS_FW_3L2 "fimc_is_fw2_3l2.bin" #define FIMC_IS_FW_4H5 "fimc_is_fw2_4h5.bin" #define FIMC_IS_FW_IMX134 "fimc_is_fw2_imx134.bin" +#define FIMC_IS_FW_IMX228 "fimc_is_fw2_imx228.bin" #define FIMC_IS_FW_IMX240 "fimc_is_fw2_imx240.bin" #define FIMC_IS_FW_2T2_EVT0 "fimc_is_fw2_2t2_evt0.bin" #define FIMC_IS_FW_2T2_EVT1 "fimc_is_fw2_2t2_evt1.bin" @@ -120,8 +123,10 @@ #define FIMC_IS_FW_COMPANION_2T2_EVT1 "companion_fw_2t2_evt1.bin" #define FIMC_IS_FW_COMPANION_2P2_12M_EVT1 "companion_fw_2p2_12m_evt1.bin" #define FIMC_IS_FW_COMPANION_IMX240_EVT1 "companion_fw_imx240_evt1.bin" +#define FIMC_IS_FW_COMPANION_IMX228_EVT1 "companion_fw_imx228_evt1.bin" #define FIMC_IS_FW_SDCARD "/data/media/0/fimc_is_fw.bin" #define FIMC_IS_IMX240_SETF "setfile_imx240.bin" +#define FIMC_IS_IMX228_SETF "setfile_imx228.bin" #define FIMC_IS_IMX135_SETF "setfile_imx135.bin" #define FIMC_IS_IMX134_SETF "setfile_imx134.bin" #define FIMC_IS_4H5_SETF "setfile_4h5.bin" @@ -139,68 +144,18 @@ #define FIMC_IS_COMPANION_2P2_MODE_SETF "companion_2p2_mode_setfile.bin" #define FIMC_IS_COMPANION_IMX240_MASTER_SETF "companion_imx240_master_setfile.bin" #define FIMC_IS_COMPANION_IMX240_MODE_SETF "companion_imx240_mode_setfile.bin" +#define FIMC_IS_COMPANION_IMX228_MASTER_SETF "companion_imx228_master_setfile.bin" +#define FIMC_IS_COMPANION_IMX228_MODE_SETF "companion_imx228_mode_setfile.bin" #define FIMC_IS_COMPANION_2P2_12M_MASTER_SETF "companion_2p2_12m_master_setfile.bin" #define FIMC_IS_COMPANION_2P2_12M_MODE_SETF "companion_2p2_12m_mode_setfile.bin" #define FIMC_IS_COMPANION_2T2_MASTER_SETF "companion_2t2_master_setfile.bin" #define FIMC_IS_COMPANION_2T2_MODE_SETF "companion_2t2_mode_setfile.bin" #define FIMC_IS_CAL_SDCARD_FRONT "/data/cal_data_front.bin" - -#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) -#define FIMC_IS_MAX_CAL_SIZE (8 * 1024) -#else -#define FIMC_IS_MAX_CAL_SIZE (64 * 1024) -#endif -#define FIMC_IS_MAX_CAL_SIZE_FRONT (16 * 1024) -#define FIMC_IS_MAX_COMPANION_FW_SIZE (200 * 1024) - -#if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) -#define FIMC_IS_MAX_FW_SIZE (8 * 1024) -#define FIMC_IS_MAX_SETFILE_SIZE (1120 * 1024) -#define HEADER_CRC32_LEN (80) -#define OEM_CRC32_LEN (64) -#define AWB_CRC32_LEN (32) -#define SHADING_CRC32_LEN (6623) -#else -#define FIMC_IS_MAX_FW_SIZE (2750 * 1024) -#define FIMC_IS_MAX_SETFILE_SIZE (1120 * 1024) -#define HEADER_CRC32_LEN (224) -#define OEM_CRC32_LEN (192) -#define AWB_CRC32_LEN (32) -#define SHADING_CRC32_LEN (2336) -#endif - -#define HEADER_CRC32_LEN_FRONT (0x70) -#define OEM_START_ADDR_FRONT (0x0) -#define OEM_END_ADDR_FRONT (0x04) -#define AWB_START_ADDR_FRONT (0x08) -#define AWB_END_ADDR_FRONT (0x0C) -#define SHADING_START_ADDR_FRONT (0x18) -#define SHADING_END_ADDR_FRONT (0x1C) -#define C2_SHADING_START_ADDR_FRONT (0x10) -#define C2_SHADING_END_ADDR_FRONT (0x14) -#define CAL_HEADER_VER_ADDR_FRONT (0x30) -#define CAL_MAP_VER_ADDR_FRONT (0x40) -#define PROJECT_NAME_ADDR_FRONT (0x4C) -#define OEM_VER_ADDR_FRONT (0x150) -#define AWB_VER_ADDR_FRONT (0x220) -#define SHADING_VER_ADDR_FRONT (0x3B00) -#define C2_SHADING_VER_ADDR_FRONT (0x1D00) -#define CAL_MAP_VER_ADDR_FRONT (0x40) - -#define OEM_START_ADDR (0x0) -#define OEM_END_ADDR (0x04) -#define AWB_START_ADDR (0x08) -#define AWB_END_ADDR (0x0C) -#define SHADING_START_ADDR (0x10) -#define SHADING_END_ADDR (0x14) -#define CAL_HEADER_VER_ADDR (0x20) -#define CAL_MAP_VER_ADDR (0x30) -#define PROJECT_NAME_ADDR (0x38) -#define OEM_VER_ADDR (0x150) -#define AWB_VER_ADDR (0x220) -#define SHADING_VER_ADDR (0x1CE0) -#define CAL_MAP_VER_ADDR (0x30) +#define FIMC_IS_FW_FROM_SDCARD "/data/media/0/FW/CamFW_Main.bin" +#define FIMC_IS_SETFILE_FROM_SDCARD "/data/media/0/FW/CamSetfile_Main.bin" +#define FIMC_IS_COMPANION_FROM_SDCARD "/data/media/0/FW/CamFW_Companion.bin" +#define FIMC_IS_KEY_FROM_SDCARD "/data/media/0/FW/1q2w3e4r.key" #define SETFILE_SIZE 0x6000 #define READ_SIZE 0x100 @@ -210,6 +165,14 @@ #define FROM_VERSION_V004 '4' #define FROM_VERSION_V005 '5' +#define FIMC_IS_HEADER_VER_SIZE 11 +#define FIMC_IS_OEM_VER_SIZE 11 +#define FIMC_IS_AWB_VER_SIZE 11 +#define FIMC_IS_SHADING_VER_SIZE 11 +#define FIMC_IS_CAL_MAP_VER_SIZE 4 +#define FIMC_IS_PROJECT_NAME_SIZE 8 +#define FIMC_IS_ISP_SETFILE_VER_SIZE 6 + enum { CC_BIN1 = 0, CC_BIN2, @@ -240,16 +203,17 @@ struct fimc_is_from_info { u32 shading_end_addr; u32 setfile_start_addr; u32 setfile_end_addr; - char header_ver[12]; - char cal_map_ver[5]; - char setfile_ver[7]; - char oem_ver[12]; - char awb_ver[12]; - char shading_ver[12]; + char header_ver[FIMC_IS_HEADER_VER_SIZE + 1]; + char cal_map_ver[FIMC_IS_CAL_MAP_VER_SIZE + 1]; + char setfile_ver[FIMC_IS_SETFILE_VER_SIZE + 1]; + char oem_ver[FIMC_IS_OEM_VER_SIZE + 1]; + char awb_ver[FIMC_IS_AWB_VER_SIZE + 1]; + char shading_ver[FIMC_IS_SHADING_VER_SIZE + 1]; char load_fw_name[50]; char load_setfile_name[50]; - char project_name[9]; + char project_name[FIMC_IS_PROJECT_NAME_SIZE + 1]; bool is_caldata_read; + bool is_check_cal_reload; #ifdef CONFIG_COMPANION_USE u32 concord_master_setfile_start_addr; u32 concord_master_setfile_end_addr; @@ -318,13 +282,16 @@ struct fimc_is_from_info { u32 lsc_parameter_crc_addr; u32 c2_shading_start_addr; u32 c2_shading_end_addr; - char c2_shading_ver[12]; + char c2_shading_ver[FIMC_IS_SHADING_VER_SIZE + 1]; #endif - char concord_header_ver[12]; + char concord_header_ver[FIMC_IS_HEADER_VER_SIZE + 1]; char load_c1_fw_name[50]; char load_c1_mastersetf_name[50]; char load_c1_modesetf_name[50]; bool is_c1_caldata_read; + unsigned long fw_size; + unsigned long setfile_size; + unsigned long comp_fw_size; #endif }; @@ -345,7 +312,9 @@ int fimc_is_sec_get_front_cal_buf(char **buf); int fimc_is_sec_get_cal_buf(char **buf); int fimc_is_sec_get_loaded_fw(char **buf); +int fimc_is_sec_set_loaded_fw(char *buf); int fimc_is_sec_get_loaded_c1_fw(char **buf); +int fimc_is_sec_set_loaded_c1_fw(char *buf); int fimc_is_sec_get_camid_from_hal(char *fw_name, char *setf_name); int fimc_is_sec_get_camid(void); @@ -355,14 +324,17 @@ int fimc_is_sec_fw_find(struct fimc_is_core *core); int fimc_is_sec_run_fw_sel(struct device *dev, int position); int fimc_is_sec_readfw(struct fimc_is_core *core); +int fimc_is_sec_read_setfile(struct fimc_is_core *core); #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) || defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) int fimc_is_sec_fw_sel_eeprom(struct device *dev, int id, bool headerOnly); #endif +int fimc_is_sec_write_fw(struct fimc_is_core *core, struct device *dev); #if !defined(CONFIG_CAMERA_EEPROM_SUPPORT_REAR) int fimc_is_sec_readcal(struct fimc_is_core *core); int fimc_is_sec_fw_sel(struct fimc_is_core *core, struct device *dev, bool headerOnly); #endif #ifdef CONFIG_COMPANION_USE +int fimc_is_sec_read_companion_fw(struct fimc_is_core *core); int fimc_is_sec_concord_fw_sel(struct fimc_is_core *core, struct device *dev); #endif int fimc_is_sec_fw_revision(char *fw_ver); @@ -378,4 +350,5 @@ void fimc_is_sec_make_crc32_table(u32 *table, u32 id); int fimc_is_sec_gpio_enable(struct exynos_platform_fimc_is *pdata, char *name, bool on); int fimc_is_sec_core_voltage_select(struct device *dev, char *header_ver); int fimc_is_sec_ldo_enable(struct device *dev, char *name, bool on); +int fimc_is_sec_ldo_enabled(struct device *dev, char *name); #endif /* FIMC_IS_SEC_DEFINE_H */ diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.c index 46b504f957c3..f3e460927065 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.c @@ -149,44 +149,6 @@ int fimc_is_spi_read(struct fimc_is_spi *spi, void *buf, u32 addr, size_t size) return ret; } -int fimc_is_spi_read_module_id(struct fimc_is_spi *spi, void *buf, u16 addr, size_t size) -{ - unsigned char req_data[4] = { 0x90, }; - int ret; - - struct spi_transfer t_c; - struct spi_transfer t_r; - - struct spi_message m; - - memset(&t_c, 0x00, sizeof(t_c)); - memset(&t_r, 0x00, sizeof(t_r)); - - req_data[1] = (addr & 0xFF00) >> 8; - req_data[2] = (addr & 0xFF); - - t_c.tx_buf = req_data; - t_c.len = 4; - t_c.cs_change = 1; - t_c.bits_per_word = 32; - - t_r.rx_buf = buf; - t_r.len = (u32)size; - - spi_message_init(&m); - spi_message_add_tail(&t_c, &m); - spi_message_add_tail(&t_r, &m); - - spi->device->max_speed_hz = 48000000; - ret = spi_sync(spi->device, &m); - if (ret) { - err("spi sync error - can't read data"); - return -EIO; - } else { - return 0; - } -} - static int fimc_is_spi_probe(struct spi_device *device) { int ret = 0; diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.h index d85f153c9a03..3a0da9761c0f 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.h +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-spi.h @@ -34,5 +34,4 @@ int fimc_is_spi_s_pin(struct fimc_is_spi_gpio *spi_gpio, int pincfg_type, int va void fimc_is_spi_s_port(struct fimc_is_spi_gpio *spi_gpio, int func, bool ssn); int fimc_is_spi_reset(struct fimc_is_spi *spi); int fimc_is_spi_read(struct fimc_is_spi *spi, void *buf, u32 addr, size_t size); -int fimc_is_spi_read_module_id(struct fimc_is_spi *spi, void *buf, u16 addr, size_t size); #endif diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.c b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.c index 0c0bb9d439b5..e68bc0a49980 100644 --- a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.c +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.c @@ -12,6 +12,7 @@ #include +#include "fimc-is-sysfs.h" #include "fimc-is-core.h" #include "fimc-is-err.h" #include "fimc-is-sec-define.h" @@ -33,6 +34,7 @@ struct device *camera_ois_dev; static struct fimc_is_core *sysfs_core; extern bool crc32_fw_check; +extern bool crc32_setfile_check; extern bool crc32_check; extern bool crc32_check_factory; extern bool fw_version_crc_check; @@ -53,6 +55,20 @@ extern bool is_final_cam_module_front; static struct fimc_is_from_info *front_finfo = NULL; #endif +#ifdef CAMERA_SYSFS_V2 +static struct fimc_is_cam_info cam_infos[2]; +#endif + +extern bool force_caldata_dump; + +#ifdef CAMERA_SYSFS_V2 +int fimc_is_get_cam_info(struct fimc_is_cam_info **caminfo) +{ + *caminfo = cam_infos; + return 0; +} +#endif + static int read_from_firmware_version(int position) { struct device *is_dev = &sysfs_core->ischain[0].pdev->dev; @@ -83,6 +99,26 @@ static int read_from_firmware_version(int position) return 0; } +#ifdef CONFIG_OIS_USE +static bool read_ois_version(void) +{ + bool ret = true; + + if (!sysfs_core->running_rear_camera) { + if (!sysfs_core->ois_ver_read) { + fimc_is_ois_gpio_on(sysfs_core); + msleep(150); + + ret = fimc_is_ois_check_fw(sysfs_core); + if (!sysfs_core->running_rear_camera) { + fimc_is_ois_gpio_off(sysfs_core); + } + } + } + return ret; +} +#endif + static ssize_t camera_front_sensorid_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -106,9 +142,11 @@ static ssize_t camera_rear_sensorid_show(struct device *dev, int ret = 0; struct device *is_dev = &sysfs_core->ischain[0].pdev->dev; - ret = fimc_is_sec_run_fw_sel(is_dev, SENSOR_POSITION_REAR); - if (ret) { - err("fimc_is_sec_run_fw_sel is fail(%d)", ret); + if (force_caldata_dump == false) { + ret = fimc_is_sec_run_fw_sel(is_dev, SENSOR_POSITION_REAR); + if (ret) { + err("fimc_is_sec_run_fw_sel is fail(%d)", ret); + } } core_pdata = dev_get_platdata(fimc_is_dev); @@ -267,6 +305,8 @@ static ssize_t camera_front_camfw_full_show(struct device *dev, static ssize_t camera_front_checkfw_factory_show(struct device *dev, struct device_attribute *attr, char *buf) { + char command_ack[10] = {0, }; + read_from_firmware_version(SENSOR_POSITION_FRONT); if (!fimc_is_sec_check_from_ver(sysfs_core, SENSOR_POSITION_FRONT)) { @@ -277,25 +317,168 @@ static ssize_t camera_front_checkfw_factory_show(struct device *dev, if (crc32_check_factory_front) { if (!is_final_cam_module_front) { err(" NG, not final cam module"); - return sprintf(buf, "%s\n", "NG"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_VER\n"); +#else + strcpy(command_ack, "NG\n"); +#endif } else { - return sprintf(buf, "%s\n", "OK"); + strcpy(command_ack, "OK\n"); } } else { err(" NG, crc check fail"); - return sprintf(buf, "%s\n", "NG"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_CRC\n"); +#else + strcpy(command_ack, "NG\n"); +#endif + } + return sprintf(buf, "%s", command_ack); +} +#endif + +#ifdef CAMERA_SYSFS_V2 +static ssize_t camera_front_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char camera_info[100] = {0, }; +#ifdef CONFIG_OF + struct fimc_is_cam_info *front_cam_info = &(cam_infos[1]); + strcpy(camera_info, "ISP="); + switch(front_cam_info->isp) { + case CAM_INFO_ISP_TYPE_INTERNAL : + strcat(camera_info, "INT;"); + break; + case CAM_INFO_ISP_TYPE_EXTERNAL : + strcat(camera_info, "EXT;"); + break; + case CAM_INFO_ISP_TYPE_SOC : + strcat(camera_info, "SOC;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "CALMEM="); + switch(front_cam_info->cal_memory) { + case CAM_INFO_CAL_MEM_TYPE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CAL_MEM_TYPE_FROM : + case CAM_INFO_CAL_MEM_TYPE_EEPROM : + case CAM_INFO_CAL_MEM_TYPE_OTP : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "READVER="); + switch(front_cam_info->read_version) { + case CAM_INFO_READ_VER_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_READ_VER_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "COREVOLT="); + switch(front_cam_info->core_voltage) { + case CAM_INFO_CORE_VOLT_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CORE_VOLT_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "UPGRADE="); + switch(front_cam_info->upgrade) { + case CAM_INFO_FW_UPGRADE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_FW_UPGRADE_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_FW_UPGRADE_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "CC="); + switch(front_cam_info->companion) { + case CAM_INFO_COMPANION_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_COMPANION_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "OIS="); + switch(front_cam_info->ois) { + case CAM_INFO_OIS_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_OIS_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; } + + return sprintf(buf, "%s\n", camera_info); +#endif + strcpy(camera_info, "ISP=NULL;CALMEM=NULL;READVER=NULL;COREVOLT=NULL;UPGRADE=NULL;FW_CC=NULL;OIS=NULL"); + + return sprintf(buf, "%s\n", camera_info); } #endif static DEVICE_ATTR(front_camtype, S_IRUGO, camera_front_camtype_show, NULL); +#ifdef CAMERA_SYSFS_V2 +static DEVICE_ATTR(front_caminfo, S_IRUGO, + camera_front_info_show, NULL); +#endif static DEVICE_ATTR(front_camfw, S_IRUGO, camera_front_camfw_show, NULL); #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) static DEVICE_ATTR(front_camfw_full, S_IRUGO, camera_front_camfw_full_show, NULL); static DEVICE_ATTR(front_checkfw_factory, S_IRUGO, camera_front_checkfw_factory_show, NULL); #endif +#ifdef CAMERA_MODULE_DUALIZE +static ssize_t camera_rear_writefw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct device *is_dev = &sysfs_core->ischain[0].pdev->dev; + int ret = 0; + + ret = fimc_is_sec_write_fw(sysfs_core, is_dev); + + if (ret) + return sprintf(buf, "NG\n"); + else + return sprintf(buf, "OK\n"); +} +#endif + static ssize_t camera_rear_camtype_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -335,7 +518,7 @@ static ssize_t camera_rear_camfw_show(struct device *dev, #endif if(fw_version_crc_check) { - if (crc32_fw_check && crc32_check_factory + if (crc32_fw_check && crc32_check_factory && crc32_setfile_check #ifdef CONFIG_COMPANION_USE && crc32_c1_fw_check && crc32_c1_check_factory #endif @@ -348,6 +531,8 @@ static ssize_t camera_rear_camfw_show(struct device *dev, strcat(command_ack, "FW"); if (!crc32_check_factory) strcat(command_ack, "CD"); + if (!crc32_setfile_check) + strcat(command_ack, "SET"); #ifdef CONFIG_COMPANION_USE if (!crc32_c1_fw_check) strcat(command_ack, "FW1"); @@ -394,7 +579,7 @@ static ssize_t camera_rear_camfw_full_show(struct device *dev, #endif if(fw_version_crc_check) { - if (crc32_fw_check && crc32_check_factory + if (crc32_fw_check && crc32_check_factory && crc32_setfile_check #ifdef CONFIG_COMPANION_USE && crc32_c1_fw_check && crc32_c1_check_factory #endif @@ -407,6 +592,8 @@ static ssize_t camera_rear_camfw_full_show(struct device *dev, strcat(command_ack, "FW"); if (!crc32_check_factory) strcat(command_ack, "CD"); + if (!crc32_setfile_check) + strcat(command_ack, "SET"); #ifdef CONFIG_COMPANION_USE if (!crc32_c1_fw_check) strcat(command_ack, "FW1"); @@ -477,6 +664,15 @@ static ssize_t camera_rear_checkfw_user_show(struct device *dev, static ssize_t camera_rear_checkfw_factory_show(struct device *dev, struct device_attribute *attr, char *buf) { + char command_ack[10] = {0, }; +#ifdef CONFIG_OIS_USE + struct fimc_is_ois_info *ois_minfo = NULL; + bool ois_ret = false; + + ois_ret = read_ois_version(); + fimc_is_ois_get_module_version(&ois_minfo); +#endif + read_from_firmware_version(SENSOR_POSITION_REAR); if (!fimc_is_sec_check_from_ver(sysfs_core, SENSOR_POSITION_REAR)) { @@ -485,26 +681,167 @@ static ssize_t camera_rear_checkfw_factory_show(struct device *dev, } if(fw_version_crc_check) { - if (crc32_fw_check && crc32_check_factory + if (crc32_fw_check && crc32_check_factory && crc32_setfile_check #ifdef CONFIG_COMPANION_USE && crc32_c1_fw_check && crc32_c1_check_factory #endif ) { if (!is_final_cam_module) { err(" NG, not final cam module"); - return sprintf(buf, "%s\n", "NG"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_VER\n"); +#else + strcpy(command_ack, "NG\n"); +#endif } else { - return sprintf(buf, "%s\n", "OK"); +#ifdef CONFIG_OIS_USE + if (ois_minfo->checksum != 0x00 || ois_minfo->caldata != 0x00 || !ois_ret) { + err(" NG, OIS crc check fail"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_CRC\n"); +#else + strcpy(command_ack, "NG\n"); +#endif + } else { + strcpy(command_ack, "OK\n"); + } +#else + strcpy(command_ack, "OK\n"); +#endif } } else { err(" NG, crc check fail"); - return sprintf(buf, "%s\n", "NG"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_CRC\n"); +#else + strcpy(command_ack, "NG\n"); +#endif } } else { err(" NG, fw ver crc check fail"); - return sprintf(buf, "%s\n", "NG"); +#ifdef CAMERA_SYSFS_V2 + strcpy(command_ack, "NG_VER\n"); +#else + strcpy(command_ack, "NG\n"); +#endif + } + + return sprintf(buf, "%s", command_ack); +} +#ifdef CAMERA_SYSFS_V2 +static ssize_t camera_rear_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char camera_info[100] = {0, }; +#ifdef CONFIG_OF + struct fimc_is_cam_info *rear_cam_info = &(cam_infos[0]); + + strcpy(camera_info, "ISP="); + switch(rear_cam_info->isp) { + case CAM_INFO_ISP_TYPE_INTERNAL : + strcat(camera_info, "INT;"); + break; + case CAM_INFO_ISP_TYPE_EXTERNAL : + strcat(camera_info, "EXT;"); + break; + case CAM_INFO_ISP_TYPE_SOC : + strcat(camera_info, "SOC;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "CALMEM="); + switch(rear_cam_info->cal_memory) { + case CAM_INFO_CAL_MEM_TYPE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CAL_MEM_TYPE_FROM : + case CAM_INFO_CAL_MEM_TYPE_EEPROM : + case CAM_INFO_CAL_MEM_TYPE_OTP : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "READVER="); + switch(rear_cam_info->read_version) { + case CAM_INFO_READ_VER_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_READ_VER_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "COREVOLT="); + switch(rear_cam_info->core_voltage) { + case CAM_INFO_CORE_VOLT_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_CORE_VOLT_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "UPGRADE="); + switch(rear_cam_info->upgrade) { + case CAM_INFO_FW_UPGRADE_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_FW_UPGRADE_SYSFS : + strcat(camera_info, "SYSFS;"); + break; + case CAM_INFO_FW_UPGRADE_CAMON : + strcat(camera_info, "CAMON;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + strcat(camera_info, "CC="); + switch(rear_cam_info->companion) { + case CAM_INFO_COMPANION_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_COMPANION_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; } + + strcat(camera_info, "OIS="); + switch(rear_cam_info->ois) { + case CAM_INFO_OIS_NONE : + strcat(camera_info, "N;"); + break; + case CAM_INFO_OIS_USE : + strcat(camera_info, "Y;"); + break; + default : + strcat(camera_info, "NULL;"); + break; + } + + return sprintf(buf, "%s\n", camera_info); +#endif + strcpy(camera_info, "ISP=NULL;CALMEM=NULL;READVER=NULL;COREVOLT=NULL;UPGRADE=NULL;FW_CC=NULL;OIS=NULL"); + + return sprintf(buf, "%s\n", camera_info); } +#endif static ssize_t camera_rear_sensor_standby(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -732,35 +1069,15 @@ static ssize_t camera_ois_version_show(struct device *dev, { struct fimc_is_ois_info *ois_minfo = NULL; struct fimc_is_ois_info *ois_pinfo = NULL; - u8 checksum = 0, caldata = 0; bool ret = false; - if (!sysfs_core->running_rear_camera) { - fimc_is_ois_gpio_on(sysfs_core); - msleep(150); - if (!sysfs_core->ois_ver_read) { - ret = fimc_is_ois_check_fw(sysfs_core); - if (!ret) { - if (!sysfs_core->running_rear_camera) { - fimc_is_ois_gpio_off(sysfs_core); - } - return sprintf(buf, "%s %s\n", "NG_FW2", "NULL"); - } - } - - fimc_is_ois_fw_status(sysfs_core, &checksum, &caldata); - - if (!sysfs_core->running_rear_camera) { - fimc_is_ois_gpio_off(sysfs_core); - } - } - + ret = read_ois_version(); fimc_is_ois_get_module_version(&ois_minfo); fimc_is_ois_get_phone_version(&ois_pinfo); - if (checksum != 0x00) { + if (ois_minfo->checksum != 0x00 || !ret) { return sprintf(buf, "%s %s\n", "NG_FW2", "NULL"); - } else if (caldata != 0x00) { + } else if (ois_minfo->caldata != 0x00) { return sprintf(buf, "%s %s\n", "NG_CD2", ois_pinfo->header_ver); } else { return sprintf(buf, "%s %s\n", ois_minfo->header_ver, ois_pinfo->header_ver); @@ -819,6 +1136,10 @@ static ssize_t camera_ois_exif_show(struct device *dev, } #endif +#ifdef CAMERA_MODULE_DUALIZE +static DEVICE_ATTR(from_write, S_IRUGO, + camera_rear_writefw_show, NULL); +#endif static DEVICE_ATTR(rear_camtype, S_IRUGO, camera_rear_camtype_show, NULL); static DEVICE_ATTR(rear_camfw, S_IRUGO, @@ -839,6 +1160,10 @@ static DEVICE_ATTR(rear_checkfw_factory, S_IRUGO, camera_rear_checkfw_factory_show, NULL); static DEVICE_ATTR(rear_sensor_standby, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH, camera_rear_sensor_standby_show, camera_rear_sensor_standby); +#ifdef CAMERA_SYSFS_V2 +static DEVICE_ATTR(rear_caminfo, S_IRUGO, + camera_rear_info_show, NULL); +#endif #ifdef CONFIG_COMPANION_USE static DEVICE_ATTR(isp_core, S_IRUGO, camera_isp_core_show, NULL); @@ -923,91 +1248,88 @@ int fimc_is_create_sysfs(struct fimc_is_core *core) } #endif } +#ifdef CAMERA_SYSFS_V2 + if (device_create_file(camera_front_dev, + &dev_attr_front_caminfo) < 0) { + printk(KERN_ERR + "failed to create front device file, %s\n", + dev_attr_front_caminfo.attr.name); + } +#endif camera_rear_dev = device_create(camera_class, NULL, 1, NULL, "rear"); if (IS_ERR(camera_rear_dev)) { printk(KERN_ERR "failed to create rear device!\n"); } else { - if (device_create_file(camera_rear_dev, - &dev_attr_rear_sensorid) < 0) { + if (device_create_file(camera_rear_dev, &dev_attr_rear_sensorid) < 0) { printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_sensorid.attr.name); } - - if (device_create_file(camera_rear_dev, &dev_attr_rear_camtype) - < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", +#ifdef CAMERA_MODULE_DUALIZE + if (device_create_file(camera_rear_dev, &dev_attr_from_write) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", + dev_attr_from_write.attr.name); + } +#endif + if (device_create_file(camera_rear_dev, &dev_attr_rear_camtype) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_camtype.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_camfw) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_camfw) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_camfw.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_camfw_full) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_camfw_full) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_camfw_full.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_checkfw_user) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_checkfw_user) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_checkfw_user.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_checkfw_factory) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_checkfw_factory) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_checkfw_factory.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_sensor_standby) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_sensor_standby) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_sensor_standby.attr.name); } -#ifdef CONFIG_COMPANION_USE +#ifdef CAMERA_SYSFS_V2 if (device_create_file(camera_rear_dev, - &dev_attr_rear_companionfw) < 0) { + &dev_attr_rear_caminfo) < 0) { printk(KERN_ERR "failed to create rear device file, %s\n", + dev_attr_rear_caminfo.attr.name); + } +#endif +#ifdef CONFIG_COMPANION_USE + if (device_create_file(camera_rear_dev, &dev_attr_rear_companionfw) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_companionfw.attr.name); } - if (device_create_file(camera_rear_dev, - &dev_attr_rear_companionfw_full) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_companionfw_full) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_companionfw_full.attr.name); } #endif - if (device_create_file(camera_rear_dev, - &dev_attr_rear_calcheck) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_rear_calcheck) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_calcheck.attr.name); } #ifdef CONFIG_COMPANION_USE - if (device_create_file(camera_rear_dev, - &dev_attr_isp_core) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_isp_core) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_isp_core.attr.name); } #endif #ifdef CONFIG_OIS_USE - if (device_create_file(camera_rear_dev, - &dev_attr_fw_update) < 0) { - printk(KERN_ERR - "failed to create rear device file, %s\n", + if (device_create_file(camera_rear_dev, &dev_attr_fw_update) < 0) { + printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_fw_update.attr.name); } #endif #ifdef FORCE_CAL_LOAD - if (device_create_file(camera_rear_dev, - &dev_attr_rear_force_cal_load) < 0) { + if (device_create_file(camera_rear_dev, &dev_attr_rear_force_cal_load) < 0) { printk(KERN_ERR "failed to create rear device file, %s\n", dev_attr_rear_force_cal_load.attr.name); } @@ -1019,40 +1341,28 @@ int fimc_is_create_sysfs(struct fimc_is_core *core) if (IS_ERR(camera_ois_dev)) { printk(KERN_ERR "failed to create ois device!\n"); } else { - if (device_create_file(camera_ois_dev, - &dev_attr_selftest) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_selftest) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_selftest.attr.name); } - if (device_create_file(camera_ois_dev, - &dev_attr_ois_power) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_ois_power) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_ois_power.attr.name); } - if (device_create_file(camera_ois_dev, - &dev_attr_ois_rawdata) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_ois_rawdata) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_ois_rawdata.attr.name); } - if (device_create_file(camera_ois_dev, - &dev_attr_oisfw) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_oisfw) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_oisfw.attr.name); } - if (device_create_file(camera_ois_dev, - &dev_attr_ois_diff) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_ois_diff) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_ois_diff.attr.name); } - if (device_create_file(camera_ois_dev, - &dev_attr_ois_exif) < 0) { - printk(KERN_ERR - "failed to create ois device file, %s\n", + if (device_create_file(camera_ois_dev, &dev_attr_ois_exif) < 0) { + printk(KERN_ERR "failed to create ois device file, %s\n", dev_attr_ois_exif.attr.name); } } @@ -1072,11 +1382,17 @@ int fimc_is_destroy_sysfs(struct fimc_is_core *core) #if defined(CONFIG_CAMERA_EEPROM_SUPPORT_FRONT) device_remove_file(camera_front_dev, &dev_attr_front_camfw_full); device_remove_file(camera_front_dev, &dev_attr_front_checkfw_factory); +#endif +#ifdef CAMERA_SYSFS_V2 + device_remove_file(camera_front_dev, &dev_attr_front_caminfo); #endif } if (camera_rear_dev) { device_remove_file(camera_rear_dev, &dev_attr_rear_sensorid); +#ifdef CAMERA_MODULE_DUALIZE + device_remove_file(camera_rear_dev, &dev_attr_from_write); +#endif device_remove_file(camera_rear_dev, &dev_attr_rear_camtype); device_remove_file(camera_rear_dev, &dev_attr_rear_camfw); device_remove_file(camera_rear_dev, &dev_attr_rear_camfw_full); @@ -1088,6 +1404,9 @@ int fimc_is_destroy_sysfs(struct fimc_is_core *core) device_remove_file(camera_rear_dev, &dev_attr_rear_companionfw_full); #endif device_remove_file(camera_rear_dev, &dev_attr_rear_calcheck); +#ifdef CAMERA_SYSFS_V2 + device_remove_file(camera_rear_dev, &dev_attr_rear_caminfo); +#endif #ifdef CONFIG_COMPANION_USE device_remove_file(camera_rear_dev, &dev_attr_isp_core); #endif diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.h new file mode 100644 index 000000000000..f06fee760f3b --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-sysfs.h @@ -0,0 +1,68 @@ +/* linux/arch/arm/mach-exynos/include/mach/fimc-is-sysfs.h + * + * Copyright (C) 2011 Samsung Electronics, Co. Ltd + * + * 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 _FIMC_IS_SYSFS_H_ +#define _FIMC_IS_SYSFS_H_ + +#include "fimc-is-core.h" + +#ifdef CAMERA_SYSFS_V2 +enum fimc_is_cam_info_isp { + CAM_INFO_ISP_TYPE_INTERNAL = 0, + CAM_INFO_ISP_TYPE_EXTERNAL, + CAM_INFO_ISP_TYPE_SOC, +}; + +enum fimc_is_cam_info_cal_mem { + CAM_INFO_CAL_MEM_TYPE_NONE = 0, + CAM_INFO_CAL_MEM_TYPE_FROM, + CAM_INFO_CAL_MEM_TYPE_EEPROM, + CAM_INFO_CAL_MEM_TYPE_OTP, +}; + +enum fimc_is_cam_info_read_ver { + CAM_INFO_READ_VER_SYSFS = 0, + CAM_INFO_READ_VER_CAMON, +}; + +enum fimc_is_cam_info_core_voltage { + CAM_INFO_CORE_VOLT_NONE = 0, + CAM_INFO_CORE_VOLT_USE, +}; + +enum fimc_is_cam_info_upgrade { + CAM_INFO_FW_UPGRADE_NONE = 0, + CAM_INFO_FW_UPGRADE_SYSFS, + CAM_INFO_FW_UPGRADE_CAMON, +}; + +enum fimc_is_cam_info_companion { + CAM_INFO_COMPANION_NONE = 0, + CAM_INFO_COMPANION_USE, +}; + +enum fimc_is_cam_info_ois { + CAM_INFO_OIS_NONE = 0, + CAM_INFO_OIS_USE, +}; + +struct fimc_is_cam_info { + unsigned int isp; + unsigned int cal_memory; + unsigned int read_version; + unsigned int core_voltage; + unsigned int upgrade; + unsigned int companion; + unsigned int ois; +}; + +int fimc_is_get_cam_info(struct fimc_is_cam_info **caminfo); + +#endif +#endif /* _FIMC_IS_SYSFS_H_ */ diff --git a/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-vendor-config_zero.h b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-vendor-config_zero.h new file mode 100644 index 000000000000..4d251c4aa335 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/vendor/fimc-is-vendor-config_zero.h @@ -0,0 +1,9 @@ +#ifndef FIMC_IS_VENDOR_CONFIG_ZERO_H +#define FIMC_IS_VENDOR_CONFIG_ZERO_H + +#include "fimc-is-from-rear-c2-imx240_v003.h" +#include "fimc-is-eeprom-front-c2-4e6_v003.h" + +#define CAMERA_SYSFS_V2 +#define CAMERA_MODULE_DUALIZE +#endif /* FIMC_IS_VENDOR_CONFIG_ZERO_H */ diff --git a/drivers/media/platform/exynos/mfc/regs-mfc-v6.h b/drivers/media/platform/exynos/mfc/regs-mfc-v6.h index ffcf6ed5fe47..9e7af6b40433 100644 --- a/drivers/media/platform/exynos/mfc/regs-mfc-v6.h +++ b/drivers/media/platform/exynos/mfc/regs-mfc-v6.h @@ -140,6 +140,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_RET_INSTANCE_ID 0xF070 #define S5P_FIMV_ERROR_CODE 0xF074 +#define S5P_FIMV_ERR_HEADER_NOT_FOUND 102 #define S5P_FIMV_ERR_WARNINGS_START 160 #define S5P_FIMV_ERR_WARNINGS_END 222 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -227,6 +228,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) +#define S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT 3 #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) @@ -240,6 +242,8 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_D_DISPLAY_FRAME_TYPE 0xF514 #define S5P_FIMV_DISPLAY_FRAME_MASK 7 +#define S5P_FIMV_DISPLAY_TEMP_INFO_MASK 0x1 +#define S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT 7 #define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0 #define S5P_FIMV_DISPLAY_FRAME_I 1 #define S5P_FIMV_DISPLAY_FRAME_P 2 diff --git a/drivers/media/platform/exynos/mfc/regs-mfc-v8.h b/drivers/media/platform/exynos/mfc/regs-mfc-v8.h index 79546714edec..5dcc789bc756 100644 --- a/drivers/media/platform/exynos/mfc/regs-mfc-v8.h +++ b/drivers/media/platform/exynos/mfc/regs-mfc-v8.h @@ -144,6 +144,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_RET_INSTANCE_ID 0xF070 #define S5P_FIMV_ERROR_CODE 0xF074 +#define S5P_FIMV_ERR_HEADER_NOT_FOUND 102 #define S5P_FIMV_ERR_WARNINGS_START 160 #define S5P_FIMV_ERR_WARNINGS_END 222 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -313,6 +314,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) +#define S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT 3 #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) @@ -325,6 +327,8 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_D_DISPLAY_CHROMA_ADDR 0xF610 #define S5P_FIMV_DISPLAY_FRAME_MASK 7 +#define S5P_FIMV_DISPLAY_TEMP_INFO_MASK 0x1 +#define S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT 7 #define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0 #define S5P_FIMV_DISPLAY_FRAME_I 1 #define S5P_FIMV_DISPLAY_FRAME_P 2 diff --git a/drivers/media/platform/exynos/mfc/regs-mfc-v9.h b/drivers/media/platform/exynos/mfc/regs-mfc-v9.h index 06bf8ef5d37d..61d76ef30af9 100644 --- a/drivers/media/platform/exynos/mfc/regs-mfc-v9.h +++ b/drivers/media/platform/exynos/mfc/regs-mfc-v9.h @@ -15,6 +15,10 @@ #define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) #define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5p_FIMV_START_ADDR) / 4) +/* This value guarantees 375msec ~ 2sec according to MFC clock (533MHz ~ 100MHz) + * releated with S5P_FIMV_DEC_TIMEOUT_VALUE */ +#define MFC_TIMEOUT_VALUE 200000000 + /* Number of bits that the buffer address should be shifted for particular * MFC buffers. */ #define S5P_FIMV_MEM_OFFSET 0 @@ -146,6 +150,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_RET_INSTANCE_ID 0xF070 #define S5P_FIMV_ERROR_CODE 0xF074 +#define S5P_FIMV_ERR_HEADER_NOT_FOUND 102 #define S5P_FIMV_ERR_WARNINGS_START 160 #define S5P_FIMV_ERR_WARNINGS_END 222 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -304,6 +309,7 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) #define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) +#define S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT 3 #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) @@ -316,6 +322,8 @@ static inline unsigned int r2h_bits(int cmd) #define S5P_FIMV_D_DISPLAY_CHROMA_ADDR 0xF610 #define S5P_FIMV_DISPLAY_FRAME_MASK 7 +#define S5P_FIMV_DISPLAY_TEMP_INFO_MASK 0x1 +#define S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT 7 #define S5P_FIMV_DISPLAY_FRAME_NOT_CODED 0 #define S5P_FIMV_DISPLAY_FRAME_I 1 #define S5P_FIMV_DISPLAY_FRAME_P 2 diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc.c b/drivers/media/platform/exynos/mfc/s5p_mfc.c index da55ea2f4503..9af63c8a210d 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc.c @@ -720,15 +720,27 @@ static inline enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file) static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dec *dec; + struct s5p_mfc_dev *dev; struct s5p_mfc_buf *dst_buf; int index, is_first = 1; + unsigned int interlace_type = 0, is_interlace = 0; if (!ctx) { mfc_err("no mfc context to run\n"); return; } + dev = ctx->dev; + if (!dev) { + mfc_err("no mfc device to run\n"); + return; + } + dec = ctx->dec_priv; + if (!dec) { + mfc_err("no mfc decoder to run\n"); + return; + } mfc_debug(2, "Decided to finish\n"); ctx->sequence++; @@ -737,18 +749,22 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) struct s5p_mfc_buf, list); mfc_debug(2, "Cleaning up buffer: %d\n", dst_buf->vb.v4l2_buf.index); + if (interlaced_cond(ctx)) + is_interlace = s5p_mfc_is_interlace_picture(); vb2_set_plane_payload(&dst_buf->vb, 0, 0); vb2_set_plane_payload(&dst_buf->vb, 1, 0); list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->vb.v4l2_buf.sequence = (ctx->sequence++); - - if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info(ctx, PIC_TIME_BOT)) - dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + if (is_interlace) { + interlace_type = s5p_mfc_get_interlace_type(); + if (interlace_type) + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED_TB; + else + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED_BT; + } else - dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; - + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; clear_bit(dst_buf->vb.v4l2_buf.index, &dec->dpb_status); index = dst_buf->vb.v4l2_buf.index; @@ -879,8 +895,6 @@ static void s5p_mfc_handle_frame_copy_timestamp(struct s5p_mfc_ctx *ctx) } } -#define on_res_change(ctx) ((ctx)->state >= MFCINST_RES_CHANGE_INIT && \ - (ctx)->state <= MFCINST_RES_CHANGE_END) static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) { struct s5p_mfc_dec *dec; @@ -890,6 +904,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) dma_addr_t dspl_y_addr; unsigned int index; unsigned int frame_type; + unsigned int interlace_type = 0, is_interlace = 0; int mvc_view_id; unsigned int dst_frame_status, last_frame_status; struct list_head *dst_queue_addr; @@ -950,7 +965,8 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) if (!(not_coded_cond(ctx) && FW_HAS_NOT_CODED(dev))) return; } - + if (interlaced_cond(ctx)) + is_interlace = s5p_mfc_is_interlace_picture(); if (dec->is_dynamic_dpb) { prev_flag = dec->dynamic_used; dec->dynamic_used = mfc_get_dec_used_flag(); @@ -985,11 +1001,17 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) dst_buf->vb.v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_info(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info(ctx, PIC_TIME_BOT)) - dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + if (is_interlace) { + interlace_type = s5p_mfc_get_interlace_type(); + if (interlace_type) + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED_TB; + else + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED_BT; + } else - dst_buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + dst_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + mfc_debug(2, "is_interlace : %d interlace_type : %d\n", + is_interlace, interlace_type); for (i = 0; i < raw->num_planes; i++) vb2_set_plane_payload(&dst_buf->vb, i, @@ -1000,7 +1022,8 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) dst_buf->vb.v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME); + V4L2_BUF_FLAG_BFRAME | + V4L2_BUF_FLAG_ERROR); switch (frame_type) { case S5P_FIMV_DISPLAY_FRAME_I: @@ -1019,9 +1042,12 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) break; } - if (s5p_mfc_err_dspl(err)) + if (s5p_mfc_err_dspl(err)) { mfc_err_ctx("Warning for displayed frame: %d\n", s5p_mfc_err_dspl(err)); + dst_buf->vb.v4l2_buf.flags |= + V4L2_BUF_FLAG_ERROR; + } if (call_cop(ctx, get_buf_ctrls_val, ctx, &ctx->dst_ctrls[index]) < 0) mfc_err_ctx("failed in get_buf_ctrls_val\n"); @@ -1535,12 +1561,29 @@ static inline void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, if (err == S5P_FIMV_VPS_ONLY_ERROR) { ctx->state = MFCINST_VPS_PARSED_ONLY; if (!list_empty(&ctx->src_queue)) { - src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); list_del(&src_buf->list); ctx->src_queue_cnt--; vb2_buffer_done(&src_buf->vb, VB2_BUF_STATE_DONE); } + } else if (err == S5P_FIMV_ERR_HEADER_NOT_FOUND && !ctx->is_drm) { + unsigned char *stream_vir = NULL; + unsigned int strm_size = 0; + spin_lock_irqsave(&dev->irqlock, flags); + if (!list_empty(&ctx->src_queue)) { + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + stream_vir = src_buf->vir_addr; + strm_size = src_buf->vb.v4l2_planes[0].bytesused; + if (strm_size > 32) + strm_size = 32; + } + spin_unlock_irqrestore(&dev->irqlock, flags); + if (stream_vir && strm_size) + print_hex_dump(KERN_ERR, "No header: ", + DUMP_PREFIX_ADDRESS, strm_size, 4, + stream_vir, strm_size, false); } case MFCINST_RES_CHANGE_END: /* This error had to happen while parsing the header */ @@ -1729,7 +1772,8 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) s5p_mfc_is_interlace_picture(); if ((ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC) && + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) && !list_empty(&ctx->src_queue)) { struct s5p_mfc_buf *src_buf; src_buf = list_entry(ctx->src_queue.next, diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_common.h b/drivers/media/platform/exynos/mfc/s5p_mfc_common.h index 0d9794810daa..4e67b5fae6f8 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_common.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_common.h @@ -237,6 +237,7 @@ struct s5p_mfc_buf { int used; int already; int consumed; + unsigned char *vir_addr; }; #define vb_to_mfc_buf(x) \ @@ -1088,6 +1089,7 @@ static inline unsigned int mfc_version(struct s5p_mfc_dev *dev) #endif #define FW_HAS_GOP2(dev) (IS_MFCv9X(dev) && \ (dev->fw.date >= 0x150316)) +#define FW_HAS_E_MIN_SCRATCH_BUF(dev) IS_MFCv9X(dev) #define HW_LOCK_CLEAR_MASK (0xFFFFFFFF) @@ -1096,11 +1098,15 @@ static inline unsigned int mfc_version(struct s5p_mfc_dev *dev) #define is_mpeg4vc1(ctx) ((ctx->codec_mode == S5P_FIMV_CODEC_VC1RCV_DEC) ||\ (ctx->codec_mode == S5P_FIMV_CODEC_VC1_DEC) ||\ (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC)) +#define is_mpeg2(ctx) (ctx->codec_mode == S5P_FIMV_CODEC_MPEG2_DEC) #define MFC_UHD_RES (3840*2160) #define MFC_HD_RES (1280*720) #define is_UHD(ctx) (((ctx)->img_width * (ctx)->img_height) == MFC_UHD_RES) #define under_HD(ctx) (((ctx)->img_width * (ctx)->img_height) <= MFC_HD_RES) #define not_coded_cond(ctx) is_mpeg4vc1(ctx) +#define interlaced_cond(ctx) is_mpeg4vc1(ctx) || is_mpeg2(ctx) || is_h264(ctx) +#define on_res_change(ctx) ((ctx)->state >= MFCINST_RES_CHANGE_INIT && \ + (ctx)->state <= MFCINST_RES_CHANGE_END) /* Extra information for Decoder */ #define DEC_SET_DUAL_DPB (1 << 0) diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c b/drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c index d3c345c85a84..ad26757cf6d1 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_ctrl.c @@ -512,6 +512,7 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int ret; + int old_state; mfc_debug_enter(); @@ -525,7 +526,8 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_err("no mfc context to run\n"); return -EINVAL; } - + old_state = ctx->state; + ctx->state = MFCINST_ABORT; ret = wait_event_interruptible_timeout(ctx->queue, (test_bit(ctx->num, &dev->hw_lock) == 0), msecs_to_jiffies(MFC_INT_TIMEOUT)); @@ -536,9 +538,11 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) } spin_lock_irq(&dev->condlock); + mfc_info_dev("curr_ctx_drm:%d, hw_lock:%lu\n", dev->curr_ctx_drm, dev->hw_lock); set_bit(ctx->num, &dev->hw_lock); spin_unlock_irq(&dev->condlock); + ctx->state = old_state; s5p_mfc_clock_on(dev); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_sleep_cmd(dev); @@ -571,6 +575,7 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) { + enum mfc_buf_usage_type buf_type; int ret; mfc_debug_enter(); @@ -579,6 +584,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) mfc_err("no mfc device to run\n"); return -EINVAL; } + mfc_info_dev("curr_ctx_drm:%d\n", dev->curr_ctx_drm); dev->wakeup_status = 1; /* Set clock source again after wake up */ s5p_mfc_set_clock_parent(dev); @@ -589,15 +595,27 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clock_on(dev); dev->wakeup_status = 0; + /* SYSMMU default block mode (not enalble/disable) */ + if (dev->curr_ctx_drm) { + ret = s5p_mfc_mem_resume(dev->alloc_ctx[0]); + if (ret < 0) + mfc_err_dev("Failed to attach iommu\n"); + s5p_mfc_mem_suspend(dev->alloc_ctx[0]); + } + ret = s5p_mfc_reset(dev); if (ret) { mfc_err_dev("Failed to reset MFC - timeout.\n"); goto err_mfc_wakeup; } mfc_debug(2, "Done MFC reset...\n"); + if (dev->curr_ctx_drm) + buf_type = MFCBUF_DRM; + else + buf_type = MFCBUF_NORMAL; /* 1. Set DRAM base Addr */ - s5p_mfc_init_memctrl(dev, MFCBUF_NORMAL); + s5p_mfc_init_memctrl(dev, buf_type); /* 2. Initialize registers of channel I/F */ s5p_mfc_clear_cmds(dev); diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_dec.c b/drivers/media/platform/exynos/mfc/s5p_mfc_dec.c index e699cc53e367..b82dfb1d4ad3 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_dec.c @@ -2759,9 +2759,11 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state = MFCINST_ABORT; if (s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET)) - s5p_mfc_cleanup_timeout(ctx); - - aborted = 1; + s5p_mfc_cleanup_timeout(ctx); + if (on_res_change(ctx)) + mfc_debug(2, "stop on res change(state:%d)\n", ctx->state); + else + aborted = 1; } spin_lock_irqsave(&dev->irqlock, flags); @@ -2866,6 +2868,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) int remove_flag = 0; int index; int skip_add = 0; + unsigned char *stream_vir = NULL; mfc_debug_enter(); if (!ctx) { @@ -2890,9 +2893,14 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) mfc_debug(2, "Adding to src: %p (0x%08lx, 0x%08lx)\n", vb, (unsigned long)s5p_mfc_mem_plane_addr(ctx, vb, 0), (unsigned long)buf->planes.stream); + if (ctx->state < MFCINST_HEAD_PARSED && !ctx->is_drm) { + stream_vir = vb2_plane_vaddr(vb, 0); + s5p_mfc_mem_inv_vb(vb, 1); + } spin_lock_irqsave(&dev->irqlock, flags); list_add_tail(&buf->list, &ctx->src_queue); ctx->src_queue_cnt++; + buf->vir_addr = stream_vir; spin_unlock_irqrestore(&dev->irqlock, flags); } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { buf->used = 0; diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c b/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c index 8ebc4fe26d3b..72172a419903 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c @@ -2539,6 +2539,8 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) } if (IS_MFCV6(dev)) ctx->dpb_count = s5p_mfc_get_enc_dpb_count(); + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) + ctx->scratch_buf_size = s5p_mfc_get_enc_scratch_size(); return 0; } diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.c index 6c8ac886b996..d9671cee7988 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.c @@ -323,8 +323,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) ctx->scratch_buf_size = ENC_V80_H264_SCRATCH_SIZE(mb_width, mb_height); else if (IS_MFCv9X(dev)) - ctx->scratch_buf_size = - ENC_V90_H264_SCRATCH_SIZE(mb_width, mb_height); + mfc_debug(2, "Use min scratch buffer size \n"); else ctx->scratch_buf_size = ENC_V65_H264_SCRATCH_SIZE(mb_width, mb_height); @@ -340,6 +339,8 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) if (mfc_version(dev) == 0x61) ctx->scratch_buf_size = ENC_V61_MPEG4_SCRATCH_SIZE(mb_width, mb_height); + else if (IS_MFCv9X(dev)) + mfc_debug(2, "Use min scratch buffer size \n"); else ctx->scratch_buf_size = ENC_V65_MPEG4_SCRATCH_SIZE(mb_width, mb_height); @@ -355,8 +356,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) ctx->scratch_buf_size = ENC_V80_VP8_SCRATCH_SIZE(mb_width, mb_height); else if (IS_MFCv9X(dev)) - ctx->scratch_buf_size = - ENC_V90_VP8_SCRATCH_SIZE(mb_width, mb_height); + mfc_debug(2, "Use min scratch buffer size \n"); else ctx->scratch_buf_size = ENC_V70_VP8_SCRATCH_SIZE(mb_width, mb_height); @@ -369,8 +369,11 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) ctx->port_b_size = 0; break; case S5P_FIMV_CODEC_HEVC_ENC: - ctx->scratch_buf_size = - ENC_V90_HEVC_SCRATCH_SIZE(mb_width, lcu_width); + if (IS_MFCv9X(dev)) + mfc_debug(2, "Use min scratch buffer size \n"); + else + mfc_err_ctx("MFC 0x%x is not supported codec type(%d)\n", + mfc_version(dev), ctx->codec_mode); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); ctx->port_a_size = ctx->scratch_buf_size + enc->tmv_buffer_size + @@ -1609,6 +1612,10 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE); WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE); + /* Disable all macroblock adaptive scaling features */ + reg = 0xF; + WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG); + WRITEL(0x0, S5P_FIMV_E_VBV_INIT_DELAY); /* SEQ_start Only */ /* initialize for '0' only setting */ @@ -1776,7 +1783,6 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND); /* macroblock adaptive scaling features */ - WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG); if (p->rc_mb) { reg = 0; /** dark region */ @@ -1916,7 +1922,8 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) for (i = 0; i < (p_264->hier_qp_layer & 0x7); i++) WRITEL(p_264->hier_qp_layer_qp[i], S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0 + i * 4); - } else { + } + if (p->rc_frame) { for (i = 0; i < (p_264->hier_qp_layer & 0x7); i++) WRITEL(p_264->hier_qp_layer_bit[i], S5P_FIMV_E_H264_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4); @@ -2184,7 +2191,8 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) for (i = 0; i < (p_vp8->num_temporal_layer & 0x3); i++) WRITEL(p_vp8->hier_qp_layer_qp[i], S5P_FIMV_E_VP8_HIERARCHICAL_QP_LAYER0 + i * 4); - } else { + } + if (p->rc_frame) { for (i = 0; i < (p_vp8->num_temporal_layer & 0x3); i++) WRITEL(p_vp8->hier_qp_layer_bit[i], S5P_FIMV_E_H264_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4); @@ -2242,10 +2250,6 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) reg |= p_vp8->rc_min_qp; WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND); - /* Disable all macroblock adaptive scaling features */ - reg = 0xF; - WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG); - mfc_debug_leave(); return 0; @@ -2336,17 +2340,21 @@ static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) WRITEL(reg, S5P_FIMV_E_HEVC_NAL_CONTROL); } /* hier qp enable */ - if (p_hevc->hier_qp && p_hevc->hier_qp_layer) { + if (p_hevc->hier_qp_layer) { reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; reg |= p_hevc->hier_qp_layer & 0x7; - /* number of coding layer should be zero when hierarchical is disable */ WRITEL(reg, S5P_FIMV_E_NUM_T_LAYER); /* QP value for each layer */ - for (i = 0; i < (p_hevc->hier_qp_layer & 0x7); i++) - WRITEL(p_hevc->hier_qp_layer_qp, - S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4); - WRITEL(p_hevc->hier_qp_layer_bit, - S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4); + if (p_hevc->hier_qp) { + for (i = 0; i < (p_hevc->hier_qp_layer & 0x7); i++) + WRITEL(p_hevc->hier_qp_layer_qp, + S5P_FIMV_E_HIERARCHICAL_QP_LAYER0 + i * 4); + } + if (p->rc_frame) { + for (i = 0; i < (p_hevc->hier_qp_layer & 0x7); i++) + WRITEL(p_hevc->hier_qp_layer_bit, + S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0 + i * 4); + } } /* rate control config. */ reg = READL(S5P_FIMV_E_RC_CONFIG); @@ -2382,7 +2390,6 @@ static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND); /* macroblock adaptive scaling features */ - WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG); if (p->rc_mb) { reg = 0; /** dark region */ @@ -2569,6 +2576,8 @@ int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, int last_frame) WRITEL(dec->dpb_status, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER); WRITEL(0x0, S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER); WRITEL(dec->slice_enable, S5P_FIMV_D_SLICE_IF_ENABLE); + if (IS_MFCv9X(dev)) + WRITEL(MFC_TIMEOUT_VALUE, S5P_FIMV_DEC_TIMEOUT_VALUE); WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID); /* Issue different commands to instance basing on whether it @@ -3284,6 +3293,9 @@ static inline int s5p_mfc_dec_dpb_flush(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; + if (on_res_change(ctx)) + mfc_err("dpb flush on res change(state:%d)\n", ctx->state); + dev->curr_ctx = ctx->num; s5p_mfc_clean_ctx_int_flags(ctx); diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.h index 3482377112d9..b20f72fe2647 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v6.h @@ -64,6 +64,10 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); #define s5p_mfc_get_disp_frame_type() (readl(ctx->dev->regs_base + \ S5P_FIMV_D_DISPLAY_FRAME_TYPE) \ & S5P_FIMV_DISPLAY_FRAME_MASK) +#define s5p_mfc_get_interlace_type() ((readl(dev->regs_base + \ + S5P_FIMV_D_DISPLAY_FRAME_TYPE) \ + >> S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT) \ + & S5P_FIMV_DISPLAY_TEMP_INFO_MASK) #define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ S5P_FIMV_D_DECODED_NAL_SIZE) #define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ @@ -90,6 +94,7 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); S5P_FIMV_RET_INSTANCE_ID) #define s5p_mfc_get_enc_dpb_count() readl(dev->regs_base + \ S5P_FIMV_E_NUM_DPB) +#define s5p_mfc_get_enc_scratch_size() 0 #define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ S5P_FIMV_E_STREAM_SIZE) #define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ @@ -107,9 +112,9 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); S5P_FIMV_D_USED_DPB_FLAG_LOWER) #define s5p_mfc_is_interlace_picture() ((readl(dev->regs_base + \ - S5P_FIMV_D_DECODED_STATUS) & \ - S5P_FIMV_DEC_STATUS_INTERLACE_MASK) == \ - S5P_FIMV_DEC_STATUS_INTERLACE) + S5P_FIMV_D_DISPLAY_STATUS) & \ + S5P_FIMV_DEC_STATUS_INTERLACE_MASK)) >> \ + S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT #define s5p_mfc_get_dec_status() (readl(dev->regs_base + \ S5P_FIMV_D_DECODED_STATUS) \ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v8.h b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v8.h index bd80042c5693..ac0ac5b78663 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v8.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v8.h @@ -90,6 +90,7 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); S5P_FIMV_RET_INSTANCE_ID) #define s5p_mfc_get_enc_dpb_count() readl(dev->regs_base + \ S5P_FIMV_E_NUM_DPB) +#define s5p_mfc_get_enc_scratch_size() 0 #define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ S5P_FIMV_E_STREAM_SIZE) #define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ @@ -106,9 +107,14 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); & S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK) #define s5p_mfc_is_interlace_picture() ((readl(dev->regs_base + \ - S5P_FIMV_D_DECODED_STATUS) & \ - S5P_FIMV_DEC_STATUS_INTERLACE_MASK) == \ - S5P_FIMV_DEC_STATUS_INTERLACE) + S5P_FIMV_D_DISPLAY_STATUS) & \ + S5P_FIMV_DEC_STATUS_INTERLACE_MASK)) >> \ + S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT + +#define s5p_mfc_get_interlace_type() ((readl(dev->regs_base + \ + S5P_FIMV_D_DISPLAY_FRAME_TYPE) \ + >> S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT) \ + & S5P_FIMV_DISPLAY_TEMP_INFO_MASK) #define s5p_mfc_get_dec_status() (readl(dev->regs_base + \ S5P_FIMV_D_DECODED_STATUS) \ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v9.h b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v9.h index 6fc967100745..7644451748d1 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v9.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_opr_v9.h @@ -64,6 +64,10 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); #define s5p_mfc_get_disp_frame_type() (readl(ctx->dev->regs_base + \ S5P_FIMV_D_DISPLAY_FRAME_TYPE) \ & S5P_FIMV_DISPLAY_FRAME_MASK) +#define s5p_mfc_get_interlace_type() ((readl(dev->regs_base + \ + S5P_FIMV_D_DISPLAY_FRAME_TYPE) \ + >> S5P_FIMV_DISPLAY_TEMP_INFO_SHIFT) \ + & S5P_FIMV_DISPLAY_TEMP_INFO_MASK) #define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ S5P_FIMV_D_DECODED_NAL_SIZE) #define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ @@ -90,6 +94,8 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); S5P_FIMV_RET_INSTANCE_ID) #define s5p_mfc_get_enc_dpb_count() readl(dev->regs_base + \ S5P_FIMV_E_NUM_DPB) +#define s5p_mfc_get_enc_scratch_size() readl(dev->regs_base + \ + S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE) #define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ S5P_FIMV_E_STREAM_SIZE) #define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ @@ -106,9 +112,9 @@ void s5p_mfc_enc_calc_src_size(struct s5p_mfc_ctx *ctx); & S5P_FIMV_D_MVC_VIEW_ID_DISP_MASK) #define s5p_mfc_is_interlace_picture() ((readl(dev->regs_base + \ - S5P_FIMV_D_DECODED_STATUS) & \ - S5P_FIMV_DEC_STATUS_INTERLACE_MASK) == \ - S5P_FIMV_DEC_STATUS_INTERLACE) + S5P_FIMV_D_DISPLAY_STATUS) & \ + S5P_FIMV_DEC_STATUS_INTERLACE_MASK)) >> \ + S5P_FIMV_DEC_STATUS_INTERLACE_SHIFT #define s5p_mfc_get_dec_status() (readl(dev->regs_base + \ S5P_FIMV_D_DECODED_STATUS) \ diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index d529ba788f41..6c8bbef94cbf 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -35,6 +35,12 @@ config RADIO_SI476X To compile this driver as a module, choose M here: the module will be called radio-si476x. +config RADIO_RTC6213N + bool "RTC6213N FM Radio Receiver support" + depends on I2C && VIDEO_V4L2 + +source "drivers/media/radio/rtc6213n/Kconfig" + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 0dcdb320cfc7..854220f4f74d 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ +obj-$(CONFIG_RADIO_RTC6213N) += rtc6213n/ obj-$(CONFIG_USB_MR800) += radio-mr800.o obj-$(CONFIG_USB_KEENE) += radio-keene.o obj-$(CONFIG_USB_MA901) += radio-ma901.o diff --git a/drivers/media/radio/rtc6213n/Kconfig b/drivers/media/radio/rtc6213n/Kconfig new file mode 100644 index 000000000000..371ef55a8a5d --- /dev/null +++ b/drivers/media/radio/rtc6213n/Kconfig @@ -0,0 +1,37 @@ +config USB_RTC6213N + tristate "Richwave RTC6213N FM Tuner support with USB" + depends on USB && RADIO_RTC6213N + ---help--- + This is a driver for USB devices with the Richwave RTC6213N chip. + Currently these devices are known to work: + - 10c4:818a: Richwave USB FM Radio Reference Design + - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) + - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700) + - 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear) + + Sound is provided by the ALSA USB Audio/MIDI driver. Therefore + if you don't want to use the device solely for RDS receiving, + it is recommended to also select SND_USB_AUDIO. + + Please have a look at the documentation, especially on how + to redirect the audio stream from the radio to your sound device: + Documentation/video4linux/RTC6213N.txt + + Say Y here if you want to connect this type of radio to your + computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called radio-usb-RTC6213N. + +config I2C_RTC6213N + tristate "Richwave RTC6213N FM Radio Receiver support with I2C" + depends on I2C && RADIO_RTC6213N && !USB_RTC6213N + ---help--- + This is a driver for I2C devices with the Richwave RTC6213N + chip. + + Say Y here if you want to connect this type of radio to your + computer's I2C port. + + To compile this driver as a module, choose M here: the + module will be called radio-i2c-RTC6213N. diff --git a/drivers/media/radio/rtc6213n/Makefile b/drivers/media/radio/rtc6213n/Makefile new file mode 100644 index 000000000000..20d3346c44ef --- /dev/null +++ b/drivers/media/radio/rtc6213n/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for radios with Richwave RTC6213N FM Tuner +# + +radio-usb-rtc6213n-objs := radio-rtc6213n-usb.o radio-rtc6213n-common.o +radio-i2c-rtc6213n-objs := radio-rtc6213n-i2c.o radio-rtc6213n-common.o + +obj-$(CONFIG_USB_RTC6213N) += radio-usb-rtc6213n.o +obj-$(CONFIG_I2C_RTC6213N) += radio-i2c-rtc6213n.o diff --git a/drivers/media/radio/rtc6213n/radio-rtc6213n-common.c b/drivers/media/radio/rtc6213n/radio-rtc6213n-common.c new file mode 100644 index 000000000000..1fc32130c0aa --- /dev/null +++ b/drivers/media/radio/rtc6213n/radio-rtc6213n-common.c @@ -0,0 +1,1180 @@ +/* + * drivers/media/radio/rtc6213n/radio-rtc6213n-common.c + * + * Driver for Richwave RTC6213N FM Tuner + * + * Copyright (c) 2013 Richwave Technology Co.Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * History: + * 2013-05-12 TianTsai Chang + * Version 1.0.0 + * - First working version + */ + +/* kernel includes */ +#include +#include +#include "radio-rtc6213n.h" + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Spacing (kHz) */ +/* 0: 200 kHz (USA, Australia) */ +/* 1: 100 kHz (Europe, Japan) */ +/* 2: 50 kHz */ +static unsigned short space = 1; +module_param(space, ushort, 0444); +MODULE_PARM_DESC(space, "Spacing: 0=200kHz *1=100kHz* 2=50kHz"); + +/* Bottom of Band (MHz) */ +/* 0: 87.5 - 108 MHz (USA, Europe)*/ +/* 1: 76 - 108 MHz (Japan wide band) */ +/* 2: 76 - 90 MHz (Japan) */ +static unsigned short band; +module_param(band, ushort, 0444); +MODULE_PARM_DESC(band, "Band: *0=87.5-108MHz* 1=76-108MHz 2=76-91MHz 3=65-76MHz"); + +/* De-emphasis */ +/* 0: 75 us (USA) */ +/* 1: 50 us (Europe, Australia, Japan) */ +static unsigned short de; +module_param(de, ushort, 0444); +MODULE_PARM_DESC(de, "De-emphasis: *0=75us* 1=50us"); + +/* Tune timeout */ +static unsigned int tune_timeout = 3000; +module_param(tune_timeout, uint, 0644); +MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); + +/* Seek timeout */ +static unsigned int seek_timeout = 8000; +module_param(seek_timeout, uint, 0644); +MODULE_PARM_DESC(seek_timeout, "Seek timeout: *8000*"); + +/************************************************************************** + * Generic Functions + **************************************************************************/ + +/* + * rtc6213n_set_chan - set the channel + */ +static int rtc6213n_set_chan(struct rtc6213n_device *radio, unsigned short chan) +{ + int retval; + unsigned long timeout; + bool timed_out = 0; + + dev_info(&radio->videodev->dev, "======== rtc6213n_set_chan ========\n"); + dev_info(&radio->videodev->dev, "RTC6213n tuning process is starting\n"); + dev_info(&radio->videodev->dev, "CHAN=0x%4.4hx SKCFG1=0x%4.4hx STATUS=0x%4.4hx chan=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS], chan); + + /* start tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_CH; + radio->registers[CHANNEL] |= CHANNEL_CSR0_TUNE | chan; + retval = rtc6213n_set_register(radio, CHANNEL); + if (retval < 0) + goto done; + + /* currently I2C driver only uses interrupt way to tune */ + if (radio->stci_enabled) { + INIT_COMPLETION(radio->completion); + + /* wait till tune operation has completed */ + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(tune_timeout)); + if (!retval) { + dev_info(&radio->videodev->dev, "rtc6213n_set_chan : timed_out\n"); + timeout = true; + } + retval = rtc6213n_get_register(radio, STATUS); + if (retval < 0) + goto stop; + } else { + /* wait till tune operation has completed */ + timeout = jiffies + msecs_to_jiffies(tune_timeout); + do { + retval = rtc6213n_get_all_registers(radio); + if (retval < 0) + goto stop; + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUS] & STATUS_STD) == 0) + && (!timed_out)); + } + dev_info(&radio->videodev->dev, "RTC6213n tuning process is done\n"); + dev_info(&radio->videodev->dev, "CHAN=0x%4.4hx SKCFG1=0x%4.4hx STATUS=0x%4.4hx, STD = %d, SF = %d, RSSI = %d\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS], + (radio->registers[STATUS] & STATUS_STD) >> 14, + (radio->registers[STATUS] & STATUS_SF) >> 13, + (radio->registers[RSSI] & RSSI_RSSI)); + + if ((radio->registers[STATUS] & STATUS_STD) == 0) + dev_info(&radio->videodev->dev, "tune does not complete\n"); + if (timed_out) + dev_info(&radio->videodev->dev, "tune timed out after %u ms\n", + tune_timeout); + +stop: + /* stop tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_TUNE; + retval = rtc6213n_set_register(radio, CHANNEL); + if (retval < 0) + goto stop; + + retval = rtc6213n_get_register(radio, STATUS); + if (retval < 0) + goto stop; + +done: + dev_info(&radio->videodev->dev, "rtc6213n_set_chans is done\n"); + dev_info(&radio->videodev->dev, "CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx STATUS=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS]); + dev_info(&radio->videodev->dev, "========= rtc6213n_set_chan End ==========\n"); + + return retval; +} + + +/* + * rtc6213n_get_freq - get the frequency + */ +static int rtc6213n_get_freq(struct rtc6213n_device *radio, unsigned int *freq) +{ + unsigned int spacing, band_bottom; + unsigned short chan; + int retval; + + /* Spacing (kHz) */ + switch ((radio->registers[CHANNEL] & CHANNEL_CSR0_CHSPACE) >> 10) { + /* 0: 200 kHz (USA, Australia) */ + case 0: + spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1: + spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: + spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch ((radio->registers[CHANNEL] & CHANNEL_CSR0_BAND) >> 12) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0: + band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: + band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + band_bottom = 76 * FREQ_MUL; break; + }; + +stop: + /* read channel */ + retval = rtc6213n_get_register(radio, STATUS); + if (retval < 0) + goto stop; + + chan = radio->registers[STATUS] & STATUS_READCH; + + dev_info(&radio->videodev->dev, "rtc6213n_get_freq is done\n"); + dev_info(&radio->videodev->dev, "CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx STATUS=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS]); + + + /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ + *freq = chan * spacing + band_bottom; + dev_info(&radio->videodev->dev, "rtc6213n_get_freq is done1 : band_bottom=%d, spacing=%d, chan=%d, freq=%d\n", + band_bottom, spacing, chan, *freq); + + return retval; +} + + +/* + * rtc6213n_set_freq - set the frequency + */ +int rtc6213n_set_freq(struct rtc6213n_device *radio, unsigned int freq) +{ + unsigned int spacing, band_bottom; + unsigned short chan; + + /* Spacing (kHz) */ + switch ((radio->registers[CHANNEL] & CHANNEL_CSR0_CHSPACE) >> 10) { + /* 0: 200 kHz (USA, Australia) */ + case 0: + spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1: + spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: + spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch ((radio->registers[CHANNEL] & CHANNEL_CSR0_BAND) >> 12) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0: + band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: + band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + band_bottom = 76 * FREQ_MUL; break; + }; + + /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ + chan = (freq - band_bottom) / spacing; + + return rtc6213n_set_chan(radio, chan); +} + + +/* + * rtc6213n_set_seek - set seek + */ +static int rtc6213n_set_seek(struct rtc6213n_device *radio, + unsigned int seek_wrap, unsigned int seek_up) +{ + int retval = 0; + unsigned long timeout; + bool timed_out = 0; + + dev_info(&radio->videodev->dev, "========= rtc6213n_set_seek ==========\n"); + dev_info(&radio->videodev->dev, "RTC6213n seeking process is starting\n"); + dev_info(&radio->videodev->dev, "CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx STATUS=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS]); + + if (seek_wrap) + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SKMODE; + else + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SKMODE; + + if (seek_up) + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SEEKUP; + else + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEKUP; + + retval = rtc6213n_set_register(radio, SEEKCFG1); + if (retval < 0) + goto done; + + /* start seeking */ + radio->registers[SEEKCFG1] |= SEEKCFG1_CSR0_SEEK; + + retval = rtc6213n_set_register(radio, SEEKCFG1); + if (retval < 0) + goto done; + + /* currently I2C driver only uses interrupt way to seek */ + if (radio->stci_enabled) { + INIT_COMPLETION(radio->completion); + + /* wait till seek operation has completed */ + retval = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(seek_timeout)); + if (!retval) { + dev_info(&radio->videodev->dev, "rtc6213n_set_seek : timed_out\n"); + timed_out = true; + } + } else { + /* wait till seek operation has completed */ + timeout = jiffies + msecs_to_jiffies(seek_timeout); + do { + retval = rtc6213n_get_register(radio, STATUS); + if (retval < 0) + goto stop; + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUS] & STATUS_STD) == 0) && + (!timed_out)); + } + dev_info(&radio->videodev->dev, "RTC6213n seeking process is done\n"); + dev_info(&radio->videodev->dev, "CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx STATUS=0x%4.4hx, STD = %d, SF = %d, RSSI = %d\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[STATUS], + (radio->registers[STATUS] & STATUS_STD) >> 14, + (radio->registers[STATUS] & STATUS_SF) >> 13, + (radio->registers[RSSI] & RSSI_RSSI)); + + if ((radio->registers[STATUS] & STATUS_STD) == 0) + dev_info(&radio->videodev->dev, "seek does not complete\n"); + /*if (radio->registers[STATUS] & STATUS_SF) + dev_info(&radio->videodev->dev, + "seek failed / band limit reached\n");*/ + if (timed_out) + dev_info(&radio->videodev->dev, "seek timed out after %u ms\n", + seek_timeout); + +stop: + /* stop seeking : clear STD*/ + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK; + retval = rtc6213n_set_register(radio, SEEKCFG1); + +done: + if (radio->registers[STATUS] & STATUS_SF) { + dev_info(&radio->videodev->dev, "seek failed / band limit reached\n"); + retval = ESPIPE; + } + /* try again, if timed out */ + else if ((retval == 0) && timed_out) + retval = -EAGAIN; + dev_info(&radio->videodev->dev, "========= rtc6213n_set_seek End ==========\n\n"); + + return retval; +} + + +/* + * rtc6213n_start - switch on radio + */ +int rtc6213n_start(struct rtc6213n_device *radio) +{ + int retval; + + u16 swbk1[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0x4000, + 0x1A08, 0x0100, 0x0740, 0x0040, 0x005A, 0x02C0, 0x0000, + 0x1440, 0x0080, 0x0840, 0x0000, 0x4002, 0x805A, 0x0D35, + 0x7367, 0x0000}; + u16 swbk2[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0x8000, + 0x0000, 0x0000, 0x0333, 0x051C, 0x01EB, 0x01EB, 0x0333, + 0xF2AB, 0x7F8A, 0x0780, 0x0000, 0x1400, 0x405A, 0x0000, + 0x3200, 0x0000}; + u16 swbk4[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0x2000, + 0x050F, 0x0E85, 0x5AA6, 0xDC57, 0x8000, 0x00A3, 0x00A3, + 0xC018, 0x7F80, 0x3C08, 0xB6CF, 0x8100, 0x0000, 0x0140, + 0x4700, 0x0000}; + u16 swbk5[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0x6000, + 0x3590, 0x6311, 0x3008, 0x0019, 0x0D79, 0x7D2F, 0x8000, + 0x02A1, 0x771F, 0x3241, 0x2635, 0x2516, 0x3614, 0x0000, + 0x0000, 0x0000}; + u16 swbk7[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0xE000, + 0x11A2, 0x0F92, 0x0000, 0x0000, 0x0000, 0x0000, 0x801D, + 0x0000, 0x0000, 0x0072, 0x00FF, 0x001F, 0x03FF, 0x16D1, + 0x13B7, 0x0000}; + + dev_info(&radio->videodev->dev, "RTC6213n_start0 : DeviceID=0x%4.4hx ChipID=0x%4.4hx Addr=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->client->addr); + + radio->registers[BANKCFG] = 0x0000; + +#if 0 + /* Keep in case of any unpredicted control */ + /* Set 0x16AA */ + radio->registers[DEVICEID] = 0x16AA; + retval = rtc6213n_set_register(radio, DEVICEID); + if (retval < 0) + goto done; + /* should insert delay large than 300ms before writing 0x96AA */ + msleep(50); +#endif + /* Don't read all between writing 0x16AA and 0x96AA */ + radio->registers[DEVICEID] = 0x96AA; + retval = rtc6213n_set_register(radio, DEVICEID); + if (retval < 0) + goto done; + msleep(50); + + /* get device and chip versions */ + /* Have to update shadow buf from all register */ + if (rtc6213n_get_all_registers(radio) < 0) { + retval = -EIO; + goto done; + } + + dev_info(&radio->videodev->dev, "======== before initail process ========\n"); + dev_info(&radio->videodev->dev, "RTC6213n_start2 : DeviceID=0x%4.4hx ChipID=0x%4.4hx Addr=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->client->addr); + + retval = rtc6213n_set_serial_registers(radio, swbk1, 23); + if (retval < 0) + goto done; + + retval = rtc6213n_set_serial_registers(radio, swbk2, 23); + if (retval < 0) + goto done; + + retval = rtc6213n_set_serial_registers(radio, swbk4, 23); + if (retval < 0) + goto done; + + retval = rtc6213n_set_serial_registers(radio, swbk5, 23); + if (retval < 0) + goto done; + + retval = rtc6213n_set_serial_registers(radio, swbk7, 23); + if (retval < 0) + goto done; + + /* get device and chip versions */ + if (rtc6213n_get_all_registers(radio) < 0) { + retval = -EIO; + goto done; + } + +done: + return retval; +} + +/* + * rtc6213n_stop - switch off radio + */ +int rtc6213n_stop(struct rtc6213n_device *radio) +{ + int retval; + + /* sysconfig */ + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + retval = rtc6213n_set_register(radio, SYSCFG); + if (retval < 0) + goto done; + + /* powerconfig */ + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_MUTE; + retval = rtc6213n_set_register(radio, MPXCFG); + + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_CSR0_DISABLE; + radio->registers[POWERCFG] &= ~POWERCFG_CSR0_ENABLE; + retval = rtc6213n_set_register(radio, POWERCFG); + + /* Set 0x16AA */ + radio->registers[DEVICEID] = 0x16AA; + retval = rtc6213n_set_register(radio, DEVICEID); + +done: + return retval; +} + +/* + * rtc6213n_rds_on - switch on rds reception + */ +static int rtc6213n_rds_on(struct rtc6213n_device *radio) +{ + int retval; + + /* sysconfig */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDS_EN; + retval = rtc6213n_set_register(radio, SYSCFG); + + if (retval < 0) + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + + return retval; +} + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * rtc6213n_fops_read - read RDS data + */ +static ssize_t rtc6213n_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + mutex_lock(&radio->lock); + /* if RDS is not on, then turn on RDS */ + if ((radio->registers[SYSCFG] & SYSCFG_CSR0_RDS_EN) == 0) + rtc6213n_rds_on(radio); + + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } + if (wait_event_interruptible(radio->read_queue, + radio->wr_index != radio->rd_index) < 0) { + retval = -EINTR; + goto done; + } + } + + /* calculate block count from byte count */ + count /= 3; + dev_info(&radio->videodev->dev, "rtc6213n_fops_read : count = %zu\n", + count); + + /* copy RDS block out of internal buffer and to user buffer */ + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + /* always transfer rds complete blocks */ + if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + dev_info(&radio->videodev->dev, "rtc6213n_fops_read : block_count = %d, count = %zu\n", + block_count, count); + } + +done: + mutex_unlock(&radio->lock); + return retval; +} + +/* + * rtc6213n_fops_poll - poll RDS data + */ +static unsigned int rtc6213n_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + mutex_lock(&radio->lock); + if ((radio->registers[SYSCFG] & SYSCFG_CSR0_RDS_EN) == 0) + rtc6213n_rds_on(radio); + mutex_unlock(&radio->lock); + + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + +/* + * rtc6213n_fops - file operations interface + */ +static const struct v4l2_file_operations rtc6213n_fops = { + .owner = THIS_MODULE, + .read = rtc6213n_fops_read, + .poll = rtc6213n_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = rtc6213n_fops_open, + .release = rtc6213n_fops_release, +}; + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ +/* + * rtc6213n_vidioc_queryctrl - enumerate control items + */ +static int rtc6213n_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = -EINVAL; + + /* abort if qc->id is below V4L2_CID_BASE */ + if (qc->id < V4L2_CID_BASE) + goto done; + + /* search video control */ + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + } + + /* disable unsupported base controls */ + /* to satisfy kradio and such apps */ + if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { + qc->flags = V4L2_CTRL_FLAG_DISABLED; + retval = 0; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "query controls failed with %d\n", retval); + return retval; +} + + +/* + * rtc6213n_vidioc_g_ctrl - get the value of a control + */ +static int rtc6213n_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + dev_info(&radio->videodev->dev, "========= Get V4L2_CONTROL ==========\n"); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[MPXCFG] & MPXCFG_CSR0_VOLUME; + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[MPXCFG] & + MPXCFG_CSR0_DIS_MUTE) == 0) ? 1 : 0; + break; + case V4L2_CID_PRIVATE_CSR0_DIS_SMUTE: + ctrl->value = ((radio->registers[MPXCFG] & + MPXCFG_CSR0_DIS_SMUTE) == 0) ? 1 : 0; + break; + case V4L2_CID_PRIVATE_CSR0_BAND: + ctrl->value = ((radio->registers[CHANNEL] & + CHANNEL_CSR0_BAND) >> 12); + break; + case V4L2_CID_PRIVATE_CSR0_SEEKRSSITH: + ctrl->value = radio->registers[SEEKCFG1] & + SEEKCFG1_CSR0_SEEKRSSITH; + break; + case V4L2_CID_PRIVATE_RSSI: + rtc6213n_get_all_registers(radio); + ctrl->value = radio->registers[RSSI] & RSSI_RSSI; + dev_info(&radio->videodev->dev, "Get V4L2_CONTROL V4L2_CID_PRIVATE_RSSI: STATUS=0x%4.4hx RSSI = %d\n", + radio->registers[STATUS], + radio->registers[RSSI] & RSSI_RSSI); + dev_info(&radio->videodev->dev, "Get V4L2_CONTROL V4L2_CID_PRIVATE_RSSI: regC=0x%4.4hx RegD=0x%4.4hx\n", + radio->registers[BA_DATA], radio->registers[BB_DATA]); + dev_info(&radio->videodev->dev, "Get V4L2_CONTROL V4L2_CID_PRIVATE_RSSI: regE=0x%4.4hx RegF=0x%4.4hx\n", + radio->registers[BC_DATA], radio->registers[BD_DATA]); + break; + case V4L2_CID_PRIVATE_DEVICEID: + ctrl->value = radio->registers[DEVICEID] & DEVICE_ID; + dev_info(&radio->videodev->dev, "Get V4L2_CONTROL V4L2_CID_PRIVATE_DEVICEID: DEVICEID=0x%4.4hx\n", + radio->registers[DEVICEID]); + break; + default: + retval = -EINVAL; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get control failed with %d\n", retval); + dev_info(&radio->videodev->dev, "========= Get V4L2_CONTROL End ==========\n\n"); + + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_s_ctrl - set the value of a control + */ +static int rtc6213n_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + dev_info(&radio->videodev->dev, "========= Get V4L2_CONTROL ==========\n"); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + dev_info(&radio->videodev->dev, "V4L2_CID_AUDIO_VOLUME : MPXCFG=0x%4.4hx POWERCFG=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[POWERCFG]); + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_VOLUME; + radio->registers[MPXCFG] |= + (ctrl->value > 15) ? 8 : ctrl->value; + + dev_info(&radio->videodev->dev, "V4L2_CID_AUDIO_VOLUME : MPXCFG=0x%4.4hx POWERCFG=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[POWERCFG]); + retval = rtc6213n_set_register(radio, MPXCFG); + break; + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_MUTE; + else + radio->registers[MPXCFG] |= MPXCFG_CSR0_DIS_MUTE; + retval = rtc6213n_set_register(radio, MPXCFG); + break; + /* PRIVATE CID */ + case V4L2_CID_PRIVATE_CSR0_DIS_SMUTE: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_DIS_SMUTE : before V4L2_CID_PRIVATE_CSR0_DIS_SMUTE"); + if (ctrl->value == 1) + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DIS_SMUTE; + else + radio->registers[MPXCFG] |= MPXCFG_CSR0_DIS_SMUTE; + retval = rtc6213n_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_CSR0_DEEM: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_DEEM : before V4L2_CID_PRIVATE_CSR0_DEEM"); + if (ctrl->value == 1) + radio->registers[MPXCFG] |= MPXCFG_CSR0_DEEM; + else + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_DEEM; + retval = rtc6213n_set_register(radio, MPXCFG); + break; + case V4L2_CID_PRIVATE_CSR0_BAND: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_BAND : CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1]); + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_BAND; + radio->registers[CHANNEL] |= (ctrl->value << 12); + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_BAND : CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1]); + retval = rtc6213n_set_register(radio, CHANNEL); + break; + case V4L2_CID_PRIVATE_CSR0_CHSPACE: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_CHSPACE : CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1]); + radio->registers[CHANNEL] &= ~CHANNEL_CSR0_CHSPACE; + radio->registers[CHANNEL] |= (ctrl->value << 10); + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_CHSPACE : CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1]); + retval = rtc6213n_set_register(radio, CHANNEL); + break; + case V4L2_CID_PRIVATE_CSR0_RDS_EN: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_RDS_EN : CHANNEL=0x%4.4hx SYSCFG=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SYSCFG]); + radio->registers[SYSCFG] &= ~SYSCFG_CSR0_RDS_EN; + radio->registers[SYSCFG] |= (ctrl->value << 12); + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_RDS_EN : CHANNEL=0x%4.4hx SYSCFG=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SYSCFG]); + retval = rtc6213n_set_register(radio, SYSCFG); + break; + case V4L2_CID_PRIVATE_SEEK_CANCEL: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_SEEK_CANCEL : MPXCFG=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[SEEKCFG1]); + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEK; + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_SEEK_CANCEL : MPXCFG=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[SEEKCFG1]); + retval = rtc6213n_set_register(radio, SEEKCFG1); + break; + case V4L2_CID_PRIVATE_CSR0_SEEKRSSITH: + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_SEEKRSSITH : MPXCFG=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[SEEKCFG1]); + radio->registers[SEEKCFG1] &= ~SEEKCFG1_CSR0_SEEKRSSITH; + radio->registers[SEEKCFG1] |= ctrl->value; + + dev_info(&radio->videodev->dev, "V4L2_CID_PRIVATE_CSR0_SEEKRSSITH : MPXCFG=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[SEEKCFG1]); + retval = rtc6213n_set_register(radio, SEEKCFG1); + break; + default: + retval = -EINVAL; + } + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set control failed with %d\n", retval); + dev_info(&radio->videodev->dev, "========= Set V4L2_CONTROL End ==========\n\n"); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_g_audio - get audio attributes + */ +static int rtc6213n_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + /* driver constants */ + audio->index = 0; + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + audio->mode = 0; + + return 0; +} + + +/* + * rtc6213n_vidioc_g_tuner - get tuner attributes + */ +static int rtc6213n_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_g_tuner: CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx RSSI=0x%4.4hx FREQ_MUL=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[RSSI], FREQ_MUL); + + if (tuner->index != 0) { + retval = -EINVAL; + goto done; + } + + retval = rtc6213n_get_register(radio, RSSI); + if (retval < 0) + goto done; + + /* driver constants */ + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO; + + /* range limits */ + switch ((radio->registers[CHANNEL] & CHANNEL_CSR0_BAND) >> 12) { + /* 0: 87.5 - 108 MHz (USA, Europe, default) */ + default: + tuner->rangelow = 87.5 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1: + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 2: 76 - 90 MHz (Japan) */ + case 2: + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 90 * FREQ_MUL; + break; + }; + + /* stereo indicator == stereo (instead of mono) */ + if ((radio->registers[STATUS] & STATUS_SI) == 0) + tuner->rxsubchans = V4L2_TUNER_SUB_MONO; + else + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + /* If there is a reliable method of detecting an RDS channel, + then this code should check for that before setting this + RDS subchannel. */ + tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; + + /* mono/stereo selector */ + if ((radio->registers[MPXCFG] & MPXCFG_CSR0_MONO) == 0) + tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; + + /* min is worst, max is best; rssi: 0..0xff */ + tuner->signal = (radio->registers[RSSI] & RSSI_RSSI); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get tuner failed with %d\n", retval); + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_g_tuner: CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx RSSI=0x%4.4hx FREQ_MUL=0x%4.4hx\n", + radio->registers[CHANNEL], radio->registers[SEEKCFG1], + radio->registers[RSSI], FREQ_MUL); + + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_s_tuner - set tuner attributes + */ +static int rtc6213n_vidioc_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *tuner) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + if (tuner->index != 0) + goto done; + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_tuner1: DeviceID=0x%4.4hx ChipID=0x%4.4hx MPXCFG=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->registers[MPXCFG]); + + /* mono/stereo selector */ + switch (tuner->audmode) { + case V4L2_TUNER_MODE_MONO: + radio->registers[MPXCFG] |= MPXCFG_CSR0_MONO; /* force mono */ + break; + case V4L2_TUNER_MODE_STEREO: + radio->registers[MPXCFG] &= ~MPXCFG_CSR0_MONO; /* try stereo */ + break; + default: + goto done; + } + + retval = rtc6213n_set_register(radio, MPXCFG); + + dev_info(&radio->videodev->dev, "RTC6213n Tuner1: DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner2: Reg2=0x%4.4hx Reg3=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[CHANNEL]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner3: Reg4=0x%4.4hx Reg5=0x%4.4hx\n", + radio->registers[SYSCFG], radio->registers[SEEKCFG1]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner4: Reg6=0x%4.4hx Reg7=0x%4.4hx\n", + radio->registers[POWERCFG], radio->registers[PADCFG]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner5: Reg8=0x%4.4hx Reg9=0x%4.4hx\n", + radio->registers[8], radio->registers[9]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner6: regA=0x%4.4hx RegB=0x%4.4hx\n", + radio->registers[10], radio->registers[11]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner7: regC=0x%4.4hx RegD=0x%4.4hx\n", + radio->registers[12], radio->registers[13]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner8: regE=0x%4.4hx RegF=0x%4.4hx\n", + radio->registers[14], radio->registers[15]); + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_tuner2: DeviceID=0x%4.4hx ChipID=0x%4.4hx MPXCFG=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->registers[MPXCFG]); + retval = rtc6213n_get_register(radio, MPXCFG); + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_tuner3: DeviceID=0x%4.4hx ChipID=0x%4.4hx MPXCFG=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID], + radio->registers[MPXCFG]); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set tuner failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_g_frequency - get tuner or modulator radio frequency + */ +static int rtc6213n_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + /* safety checks */ + mutex_lock(&radio->lock); + + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + if (freq->tuner != 0) { + retval = -EINVAL; + goto done; + } + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_g_frequency1 : *freq=%d\n", + freq->frequency); + freq->type = V4L2_TUNER_RADIO; + retval = rtc6213n_get_freq(radio, &freq->frequency); + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_g_frequency2 : *freq=%d, retval=%d\n", + freq->frequency, retval); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "get frequency failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_s_frequency - set tuner or modulator radio frequency + */ +static int rtc6213n_vidioc_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *freq) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + if (freq->tuner != 0) { + retval = -EINVAL; + goto done; + } + + if (retval < 0) + dev_warn(&radio->videodev->dev, "Disable RDS failed with %d\n", + retval); + + dev_warn(&radio->videodev->dev, "rtc6213n_vidioc_s_frequency freq = %d\n", + freq->frequency); + retval = rtc6213n_set_freq(radio, freq->frequency); + +done: + if (retval < 0) + dev_warn(&radio->videodev->dev, + "set frequency failed with %d\n", retval); + + if (retval < 0) + dev_warn(&radio->videodev->dev, "Enable RDS failed with %d\n", + retval); + + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_vidioc_s_hw_freq_seek - set hardware frequency seek + */ +static int rtc6213n_vidioc_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_hw_freq_seek2 : MPXCFG=0x%4.4hx CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[CHANNEL], + radio->registers[SEEKCFG1]); + + /* safety checks */ + retval = rtc6213n_disconnect_check(radio); + if (retval) + goto done; + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_hw_freq_seek : MPXCFG=0x%4.4hx CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx seek_tuner=%d\n", + radio->registers[MPXCFG], radio->registers[CHANNEL], + radio->registers[SEEKCFG1], seek->tuner); + + if (seek->tuner != 0) { + retval = -EINVAL; + goto done; + } + + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_hw_freq_seek : MPXCFG=0x%4.4hx CHANNEL=0x%4.4hx SEEKCFG1=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[CHANNEL], + radio->registers[SEEKCFG1]); + + retval = rtc6213n_set_seek(radio, seek->wrap_around, seek->seek_upward); + +#if 0 +#if 0 + retval = rtc6213n_get_freq(radio, &freqvalue); + seek->reserved[0] = freqvalue; +#else + seek->reserved[0] = radio->registers[STATUS] & STATUS_READCH; +#endif + dev_info(&radio->videodev->dev, "rtc6213n_vidioc_s_hw_freq_seek : seek->reserved[0]=%d\n", + seek->reserved[0]); +#endif + +done: + if (retval < 0) + dev_info(&radio->videodev->dev, + "set hardware frequency seek failed with %d\n", retval); + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_ioctl_ops - video device ioctl operations + */ +static const struct v4l2_ioctl_ops rtc6213n_ioctl_ops = { + .vidioc_querycap = rtc6213n_vidioc_querycap, + .vidioc_queryctrl = rtc6213n_vidioc_queryctrl, + .vidioc_g_ctrl = rtc6213n_vidioc_g_ctrl, + .vidioc_s_ctrl = rtc6213n_vidioc_s_ctrl, + .vidioc_g_audio = rtc6213n_vidioc_g_audio, + .vidioc_g_tuner = rtc6213n_vidioc_g_tuner, + .vidioc_s_tuner = rtc6213n_vidioc_s_tuner, + .vidioc_g_frequency = rtc6213n_vidioc_g_frequency, + .vidioc_s_frequency = rtc6213n_vidioc_s_frequency, + .vidioc_s_hw_freq_seek = rtc6213n_vidioc_s_hw_freq_seek, +}; + + +/* + * rtc6213n_viddev_template - video device interface + */ +struct video_device rtc6213n_viddev_template = { + .fops = &rtc6213n_fops, + .name = DRIVER_NAME, + .release = video_device_release, + .ioctl_ops = &rtc6213n_ioctl_ops, +}; + +/************************************************************************** + * Module Interface + **************************************************************************/ + +/* + * rtc6213n_i2c_init - module init + */ +static __init int rtc6213n_init(void) +{ + pr_info(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return rtc6213n_i2c_init(); +} + +/* + * rtc6213n_i2c_exit - module exit + */ +static void __exit rtc6213n_exit(void) +{ + i2c_del_driver(&rtc6213n_i2c_driver); +} + +module_init(rtc6213n_init); +module_exit(rtc6213n_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/media/radio/rtc6213n/radio-rtc6213n-i2c.c b/drivers/media/radio/rtc6213n/radio-rtc6213n-i2c.c new file mode 100644 index 000000000000..6334d35bffda --- /dev/null +++ b/drivers/media/radio/rtc6213n/radio-rtc6213n-i2c.c @@ -0,0 +1,646 @@ +/* + * drivers/media/radio/rtc6213n/radio-rtc6213n-i2c.c + * + * I2C driver for Richwave RTC6213N FM Tuner + * + * Copyright (c) 2013 Richwave Technology Co.Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* kernel includes */ +#include +#include +#include +#include +#include "radio-rtc6213n.h" + +static struct of_device_id rtc6213n_i2c_dt_ids[] = { + {.compatible = "rtc6213n"}, + {} +}; + +/* I2C Device ID List */ +static const struct i2c_device_id rtc6213n_i2c_id[] = { + /* Generic Entry */ + { "rtc6213n", 0 }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(i2c, rtc6213n_i2c_id); + +static unsigned short space = 1; +static unsigned short band; +static unsigned short de; + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Radio Nr */ +static int radio_nr = -1; +module_param(radio_nr, int, 0444); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static unsigned short max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, ushort, 0644); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + + + +/************************************************************************** + * I2C Definitions + **************************************************************************/ +/* Write starts with the upper byte of register 0x02 */ +#define WRITE_REG_NUM RADIO_REGISTER_NUM +#define WRITE_INDEX(i) ((i + 0x02)%16) + +/* Read starts with the upper byte of register 0x0a */ +#define READ_REG_NUM RADIO_REGISTER_NUM +#define READ_INDEX(i) ((i + RADIO_REGISTER_NUM - 0x0a) % READ_REG_NUM) + +/*static*/ +struct tasklet_struct my_tasklet; +/************************************************************************** + * General Driver Functions - REGISTERs + **************************************************************************/ + +/* + * rtc6213n_get_register - read register + */ +int rtc6213n_get_register(struct rtc6213n_device *radio, int regnr) +{ + u16 buf[READ_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, + (void *)buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + radio->registers[regnr] = __be16_to_cpu(buf[READ_INDEX(regnr)]); + + return 0; +} + + +/* + * rtc6213n_set_register - write register + */ +int rtc6213n_set_register(struct rtc6213n_device *radio, int regnr) +{ + int i; + u16 buf[WRITE_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, 0, sizeof(u16) * WRITE_REG_NUM, + (void *)buf }, + }; + + for (i = 0; i < WRITE_REG_NUM; i++) + buf[i] = __cpu_to_be16(radio->registers[WRITE_INDEX(i)]); + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + return 0; +} + +/* + * rtc6213n_set_register - write register + */ +int rtc6213n_set_serial_registers(struct rtc6213n_device *radio, + u16 *data, int bytes) +{ + int i; + u16 buf[46]; + struct i2c_msg msgs[1] = { + { radio->client->addr, 0, sizeof(u16) * bytes, + (void *)buf }, + }; + + for (i = 0; i < bytes; i++) + buf[i] = __cpu_to_be16(data[i]); + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + return 0; +} + +/************************************************************************** + * General Driver Functions - ENTIRE REGISTERS + **************************************************************************/ +/* + * rtc6213n_get_all_registers - read entire registers + */ +/* changed from static */ +int rtc6213n_get_all_registers(struct rtc6213n_device *radio) +{ + int i; + u16 buf[READ_REG_NUM]; + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, + (void *)buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + for (i = 0; i < READ_REG_NUM; i++) + radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]); + + return 0; +} + +/* + * rtc6213n_get_allbanks_registers - read entire registers of each bank + */ +#if 0 +int rtc6213n_get_allbanks_registers(struct rtc6213n_device *radio) +{ + int i; + u16 buf[READ_REG_NUM]; + + radio->registers[BANKCFG] = 0x4000; + retval = rtc6213n_set_register(radio, BANKCFG); + if (retval < 0) + goto done; + + struct i2c_msg msgs[1] = { + { radio->client->addr, I2C_M_RD, sizeof(u16) * READ_REG_NUM, + (void *)buf }, + }; + + if (i2c_transfer(radio->client->adapter, msgs, 1) != 1) + return -EIO; + + for (i = 0; i < READ_REG_NUM; i++) + radio->registers[i] = __be16_to_cpu(buf[READ_INDEX(i)]); + + return 0; +} +#endif + +int rtc6213n_disconnect_check(struct rtc6213n_device *radio) +{ + return 0; +} + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * rtc6213n_fops_open - file open + */ +int rtc6213n_fops_open(struct file *file) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + mutex_lock(&radio->lock); + radio->users++; + + dev_info(&radio->videodev->dev, "rtc6213n_fops_open : user num = %d\n", + radio->users); + + if (radio->users == 1) { + /* start radio */ + retval = rtc6213n_start(radio); + if (retval < 0) + goto done; + dev_info(&radio->videodev->dev, "rtc6213n_fops_open : after initialization\n"); + + /* mpxconfig */ + /* Disable Softmute / Disable Mute / De-emphasis / Volume 8 */ + radio->registers[MPXCFG] = 0x0000 | + MPXCFG_CSR0_DIS_SMUTE | MPXCFG_CSR0_DIS_MUTE | + ((de << 12) & MPXCFG_CSR0_DEEM) | 0x0008; + retval = rtc6213n_set_register(radio, MPXCFG); + if (retval < 0) + goto done; + + /* channel */ + /* Band / Space / Default channel 90.1Mhz */ + radio->registers[CHANNEL] = + ((band << 12) & CHANNEL_CSR0_BAND) | + ((space << 10) & CHANNEL_CSR0_CHSPACE) | 0x1a; + retval = rtc6213n_set_register(radio, CHANNEL); + if (retval < 0) + goto done; + + /* seekconfig2 */ + /* Seeking TH */ + radio->registers[SEEKCFG2] = 0x4050; + retval = rtc6213n_set_register(radio, SEEKCFG2); + if (retval < 0) + goto done; + + /* enable RDS / STC interrupt */ + radio->registers[SYSCFG] |= SYSCFG_CSR0_RDSIRQEN; + radio->registers[SYSCFG] |= SYSCFG_CSR0_STDIRQEN; + /*radio->registers[SYSCFG] |= SYSCFG_CSR0_RDS_EN;*/ + retval = rtc6213n_set_register(radio, SYSCFG); + if (retval < 0) + goto done; + + radio->registers[PADCFG] &= ~PADCFG_CSR0_GPIO; + radio->registers[PADCFG] |= 0x1 << 2; + retval = rtc6213n_set_register(radio, PADCFG); + if (retval < 0) + goto done; + + /* powerconfig */ + /* Enable FM */ + radio->registers[POWERCFG] = POWERCFG_CSR0_ENABLE; + retval = rtc6213n_set_register(radio, POWERCFG); + if (retval < 0) + goto done; + +#if 1 + dev_info(&radio->videodev->dev, "RTC6213n Tuner1: DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner2: Reg2=0x%4.4hx Reg3=0x%4.4hx\n", + radio->registers[MPXCFG], radio->registers[CHANNEL]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner3: Reg4=0x%4.4hx Reg5=0x%4.4hx\n", + radio->registers[SYSCFG], radio->registers[SEEKCFG1]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner4: Reg6=0x%4.4hx Reg7=0x%4.4hx\n", + radio->registers[POWERCFG], radio->registers[PADCFG]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner5: Reg8=0x%4.4hx Reg9=0x%4.4hx\n", + radio->registers[8], radio->registers[9]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner6: regA=0x%4.4hx RegB=0x%4.4hx\n", + radio->registers[10], radio->registers[11]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner7: regC=0x%4.4hx RegD=0x%4.4hx\n", + radio->registers[12], radio->registers[13]); + dev_info(&radio->videodev->dev, "RTC6213n Tuner8: regE=0x%4.4hx RegF=0x%4.4hx\n", + radio->registers[14], radio->registers[15]); +#endif + } + dev_info(&radio->videodev->dev, "rtc6213n_fops_open : Exit\n"); + +done: + mutex_unlock(&radio->lock); + return retval; +} + + +/* + * rtc6213n_fops_release - file release + */ +int rtc6213n_fops_release(struct file *file) +{ + struct rtc6213n_device *radio = video_drvdata(file); + int retval = 0; + + /* safety check */ + if (!radio) + return -ENODEV; + + mutex_lock(&radio->lock); + radio->users--; + if (radio->users == 0) { + /* stop radio */ + retval = rtc6213n_stop(radio); + tasklet_kill(&my_tasklet); + } + mutex_unlock(&radio->lock); + dev_info(&radio->videodev->dev, "rtc6213n_fops_release : Exit\n"); + + return retval; +} + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * rtc6213n_vidioc_querycap - query device capabilities + */ +int rtc6213n_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + capability->version = DRIVER_KERNEL_VERSION; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | + V4L2_CAP_TUNER | V4L2_CAP_RADIO; + + return 0; +} + + + +/************************************************************************** + * I2C Interface + **************************************************************************/ + +/* + * rtc6213n_i2c_interrupt - interrupt handler + */ +static irqreturn_t rtc6213n_i2c_interrupt(int irq, void *dev_id) +{ + struct rtc6213n_device *radio = dev_id; + unsigned char regnr; + unsigned char blocknum; + unsigned short bler; /* rds block errors */ + unsigned short rds; + unsigned char tmpbuf[3]; + int retval = 0; + +#if 1 + /* check Seek/Tune Complete */ + retval = rtc6213n_get_register(radio, STATUS); + if (retval < 0) + goto end; +#endif + + if (radio->registers[STATUS] & STATUS_STD) { + complete(&radio->completion); + dev_info(&radio->videodev->dev, "rtc6213n_i2c_interrupt Seek/Tune Done\n"); + dev_info(&radio->videodev->dev, "STATUS=0x%4.4hx, STD = %d, SF = %d, RSSI = %d\n", + radio->registers[STATUS], + (radio->registers[STATUS] & STATUS_STD) >> 14, + (radio->registers[STATUS] & STATUS_SF) >> 13, + (radio->registers[RSSI] & RSSI_RSSI)); + goto end; + } + +#if 1 + /* Update RDS registers */ + for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) { + retval = rtc6213n_get_register(radio, STATUS + regnr); + if (retval < 0) + goto end; + } + + /* get rds blocks */ + if ((radio->registers[STATUS] & STATUS_RDS_RDY) == 0) + /* No RDS group ready, better luck next time */ + goto end; + dev_info(&radio->videodev->dev, "interrupt : STATUS=0x%4.4hx, RSSI=%d\n", + radio->registers[STATUS], radio->registers[RSSI] & RSSI_RSSI); + dev_info(&radio->videodev->dev, "BAErr %d, BBErr %d, BCErr %d, BDErr %d\n", + (radio->registers[RSSI] & RSSI_RDS_BA_ERRS) >> 14, + (radio->registers[RSSI] & RSSI_RDS_BB_ERRS) >> 12, + (radio->registers[RSSI] & RSSI_RDS_BC_ERRS) >> 10, + (radio->registers[RSSI] & RSSI_RDS_BD_ERRS) >> 8); + dev_info(&radio->videodev->dev, "RDS_RDY=%d, RDS_SYNC=%d\n", + (radio->registers[STATUS] & STATUS_RDS_RDY) >> 15, + (radio->registers[STATUS] & STATUS_RDS_SYNC) >> 11); +#endif + + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[RSSI] & + RSSI_RDS_BA_ERRS) >> 14; + rds = radio->registers[BA_DATA]; + break; + case 1: + bler = (radio->registers[RSSI] & + RSSI_RDS_BB_ERRS) >> 12; + rds = radio->registers[BB_DATA]; + break; + case 2: + bler = (radio->registers[RSSI] & + RSSI_RDS_BC_ERRS) >> 10; + rds = radio->registers[BC_DATA]; + break; + case 3: + bler = (radio->registers[RSSI] & + RSSI_RDS_BD_ERRS) >> 8; + rds = radio->registers[BD_DATA]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + put_unaligned_le16(rds, &tmpbuf); + tmpbuf[2] = blocknum; /* offset name */ + + tmpbuf[2] |= blocknum << 3; /* received offset */ + tmpbuf[2] |= bler << 6; + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } + } + + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); + +end: + + return IRQ_HANDLED; +} + +/* + * rtc6213n_i2c_probe - probe for the device + */ +static int rtc6213n_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtc6213n_device *radio; + int retval = 0; + + /* private data allocation and initialization */ + radio = kzalloc(sizeof(struct rtc6213n_device), GFP_KERNEL); + if (!radio) { + retval = -ENOMEM; + goto err_initial; + } + + radio->users = 0; + radio->client = client; + mutex_init(&radio->lock); + + /* video device allocation and initialization */ + radio->videodev = video_device_alloc(); + if (!radio->videodev) { + retval = -ENOMEM; + goto err_radio; + } + memcpy(radio->videodev, &rtc6213n_viddev_template, + sizeof(rtc6213n_viddev_template)); + video_set_drvdata(radio->videodev, radio); + + /* get device and chip versions */ + if (rtc6213n_get_all_registers(radio) < 0) { + retval = -EIO; + goto err_video; + } + + dev_info(&client->dev, "rtc6213n_i2c_probe DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + + /* rds buffer allocation */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + retval = -EIO; + goto err_video; + } + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->read_queue); + + /* mark Seek/Tune Complete Interrupt enabled */ + radio->stci_enabled = true; + init_completion(&radio->completion); + + dev_info(&client->dev, "rtc6213n_i2c_probe DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + + retval = request_threaded_irq(client->irq, NULL, rtc6213n_i2c_interrupt, + IRQF_TRIGGER_FALLING|IRQF_ONESHOT, DRIVER_NAME, radio); + if (retval) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_rds; + } + + /* register video device */ + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, + radio_nr); + if (retval) { + dev_warn(&client->dev, "Could not register video device\n"); + goto err_all; + } + i2c_set_clientdata(client, radio); + + return 0; +err_all: + free_irq(client->irq, radio); +err_rds: + kfree(radio->buffer); +err_video: + video_device_release(radio->videodev); +err_radio: + kfree(radio); +err_initial: + return retval; +} + + +/* + * rtc6213n_i2c_remove - remove the device + */ +static int rtc6213n_i2c_remove(struct i2c_client *client) +{ + struct rtc6213n_device *radio = i2c_get_clientdata(client); + + free_irq(client->irq, radio); + video_unregister_device(radio->videodev); + kfree(radio); + + return 0; +} + + +#ifdef CONFIG_PM +/* + * rtc6213n_i2c_suspend - suspend the device + */ +static int rtc6213n_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc6213n_device *radio = i2c_get_clientdata(client); + + /* power down */ + radio->registers[POWERCFG] |= POWERCFG_CSR0_DISABLE; + if (rtc6213n_set_register(radio, POWERCFG) < 0) + return -EIO; + + return 0; +} + + +/* + * rtc6213n_i2c_resume - resume the device + */ +static int rtc6213n_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rtc6213n_device *radio = i2c_get_clientdata(client); + + /* power up : need 110ms */ + radio->registers[POWERCFG] |= POWERCFG_CSR0_ENABLE; + if (rtc6213n_set_register(radio, POWERCFG) < 0) + return -EIO; + msleep(110); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rtc6213n_i2c_pm, rtc6213n_i2c_suspend, + rtc6213n_i2c_resume); +#endif + + +/* + * rtc6213n_i2c_driver - i2c driver interface + */ +struct i2c_driver rtc6213n_i2c_driver = { + .driver = { + .name = "rtc6213n", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rtc6213n_i2c_dt_ids), +#ifdef CONFIG_PM + .pm = &rtc6213n_i2c_pm, +#endif + }, + .probe = rtc6213n_i2c_probe, + .remove = rtc6213n_i2c_remove, + .id_table = rtc6213n_i2c_id, +}; + +/* + * rtc6213n_i2c_init + */ +int rtc6213n_i2c_init(void) +{ + pr_info(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); + return i2c_add_driver(&rtc6213n_i2c_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/media/radio/rtc6213n/radio-rtc6213n.h b/drivers/media/radio/rtc6213n/radio-rtc6213n.h new file mode 100644 index 000000000000..472a8c99a1c9 --- /dev/null +++ b/drivers/media/radio/rtc6213n/radio-rtc6213n.h @@ -0,0 +1,227 @@ +/* + * drivers/media/radio/rtc6213n/radio-rtc6213n.h + * + * Driver for Richwave RTC6213N FM Tuner + * + * Copyright (c) 2013 Richwave Technology Co.Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* driver definitions */ +#define DRIVER_NAME "rtc6213n-fmtuner" + +/* kernel includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* driver definitions */ +#define DRIVER_AUTHOR "TianTsai Chang " +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) +#define DRIVER_CARD "Richwave rtc6213n FM Tuner" +#define DRIVER_DESC "I2C radio driver for rtc6213n FM Tuner" +#define DRIVER_VERSION "1.0.1" + +/************************************************************************** + * Register Definitions + **************************************************************************/ +#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define RADIO_REGISTER_NUM 16 /* DEVICEID */ +#define RDS_REGISTER_NUM 6 /* STATUSRSSI */ + +#define DEVICEID 0 /* Device ID Code */ +#define DEVICE_ID 0xffff /* [15:00] Device ID */ +#define DEVICEID_PN 0xf000 /* [15:12] Part Number */ +#define DEVICEID_MFGID 0x0fff /* [11:00] Manufacturer ID */ + +#define CHIPID 1 /* Chip ID Code */ +#define CHIPID_REVISION_NO 0xfc00 /* [15:10] Chip Reversion */ + +#define MPXCFG 2 /* Power Configuration */ +#define MPXCFG_CSR0_DIS_SMUTE 0x8000 /* [15:15] Disable Softmute */ +#define MPXCFG_CSR0_DIS_MUTE 0x4000 /* [14:14] Disable Mute */ +#define MPXCFG_CSR0_MONO 0x2000 /* [13:13] Mono or Auto Detect */ +#define MPXCFG_CSR0_DEEM 0x1000 /* [12:12] DE-emphasis */ +#define MPXCFG_CSR0_BLNDADJUST 0x0300 /* [09:08] Blending Adjust */ +#define MPXCFG_CSR0_SMUTERATE 0x00c0 /* [07:06] Softmute Rate */ +#define MPXCFG_CSR0_SMUTEATT 0x0030 /* [05:04] Softmute Attenuation */ +#define MPXCFG_CSR0_VOLUME 0x000f /* [03:00] Volume */ + +#define CHANNEL 3 /* Tuning Channel Setting */ +#define CHANNEL_CSR0_TUNE 0x8000 /* [15:15] Tune */ +#define CHANNEL_CSR0_BAND 0x3000 /* [13:12] Band Select */ +#define CHANNEL_CSR0_CHSPACE 0x0c00 /* [11:10] Channel Sapcing */ +#define CHANNEL_CSR0_CH 0x03ff /* [09:00] Tuning Channel */ + +#define SYSCFG 4 /* System Configuration 1 */ +#define SYSCFG_CSR0_RDSIRQEN 0x8000 /* [15:15] RDS Interrupt Enable */ +#define SYSCFG_CSR0_STDIRQEN 0x4000 /* [14:14] STD Interrupt Enable */ +#define SYSCFG_CSR0_DIS_AGC 0x2000 /* [13:13] Disable AGC */ +#define SYSCFG_CSR0_RDS_EN 0x1000 /* [12:12] RDS Enable */ +#define SYSCFG_CSR0_RBDS_M 0x0300 /* [09:08] MMBS setting */ + +#define SEEKCFG1 5 /* Seek Configuration 1 */ +#define SEEKCFG1_CSR0_SEEK 0x8000 /* [15:15] Enable Seek Function */ +#define SEEKCFG1_CSR0_SEEKUP 0x4000 /* [14:14] Seek Direction */ +#define SEEKCFG1_CSR0_SKMODE 0x2000 /* [13:13] Seek Mode */ +#define SEEKCFG1_CSR0_SEEKRSSITH 0x00ff /* [07:00] RSSI Seek Threshold */ + +#define POWERCFG 6 /* Power Configuration */ +#define POWERCFG_CSR0_ENABLE 0x8000 /* [15:15] Power-up Enable */ +#define POWERCFG_CSR0_DISABLE 0x4000 /* [14:14] Power-up Disable */ +#define POWERCFG_CSR0_BLNDOFS 0x0f00 /* [11:08] Blending Offset Value */ + +#define PADCFG 7 /* PAD Configuration */ +#define PADCFG_CSR0_RC_EN 0xf000 /* Internal crystal RC enable*/ +#define PADCFG_CSR0_GPIO 0x0004 /* [03:02] General purpose I/O */ + +#define BANKCFG 8 /* Bank Serlection */ +/* contains reserved */ + +#define SEEKCFG2 9 /* Seek Configuration 2 */ +#define SEEKCFG2_CSR0_OFSTH 0x4000 /* [15:08] DC offset fail TH */ +#define SEEKCFG2_CSR0_QLTTH 0x0010 /* [07:00] Spike fail TH */ + +/* BOOTCONFIG only contains reserved [*/ +#define STATUS 10 /* Status and Work channel */ +#define STATUS_RDS_RDY 0x8000 /* [15:15] RDS Ready */ +#define STATUS_STD 0x4000 /* [14:14] Seek/Tune Done */ +#define STATUS_SF 0x2000 /* [13:13] Seek Fail */ +#define STATUS_RDS_SYNC 0x0800 /* [11:11] RDS synchronization */ +#define STATUS_SI 0x0400 /* [10:10] Stereo Indicator */ +#define STATUS_READCH 0x03ff /* [09:00] Read Channel */ + +#define RSSI 11 /* RSSI and RDS error */ +#define RSSI_RDS_BA_ERRS 0xc000 /* [15:14] RDS Block A Errors */ +#define RSSI_RDS_BB_ERRS 0x3000 /* [15:14] RDS Block B Errors */ +#define RSSI_RDS_BC_ERRS 0x0c00 /* [13:12] RDS Block C Errors */ +#define RSSI_RDS_BD_ERRS 0x0300 /* [11:10] RDS Block D Errors */ +#define RSSI_RSSI 0x00ff /* [09:00] Read Channel */ + +#define BA_DATA 12 /* Block A data */ +#define RDSA_RDSA 0xffff /* [15:00] RDS Block A Data */ + +#define BB_DATA 13 /* Block B data */ +#define RDSB_RDSB 0xffff /* [15:00] RDS Block B Data */ + +#define BC_DATA 14 /* Block C data */ +#define RDSC_RDSC 0xffff /* [15:00] RDS Block C Data */ + +#define BD_DATA 15 /* Block D data */ +#define RDSD_RDSD 0xffff /* [15:00] RDS Block D Data */ + +/* (V4L2_CID_PRIVATE_BASE + ( << 4) + ( << 0)) */ +/* already defined in */ +/* #define V4L2_CID_PRIVATE_BASE 0x08000000 */ + +#define RW_PRIBASE V4L2_CID_PRIVATE_BASE +/*#define RTC6213N_IOC_POWERUP (RW_PRIBASE + (POWERCFG<<4) + 15) +#define RTC6213N_IOC_POWERDOWN (RW_PRIBASE + (POWERCFG<<4) + 14)*/ + +#define V4L2_CID_PRIVATE_DEVICEID (RW_PRIBASE + (DEVICEID<<4) + 0) +#define V4L2_CID_PRIVATE_CSR0_DIS_SMUTE (RW_PRIBASE + (MPXCFG<<4) + 15) +#define V4L2_CID_PRIVATE_CSR0_DEEM (RW_PRIBASE + (MPXCFG<<4) + 12) +#define V4L2_CID_PRIVATE_CSR0_BLNDADJUST (RW_PRIBASE + (MPXCFG<<4) + 8) + +#define V4L2_CID_PRIVATE_CSR0_BAND (RW_PRIBASE + (CHANNEL<<4) + 12) +#define V4L2_CID_PRIVATE_CSR0_CHSPACE (RW_PRIBASE + (CHANNEL<<4) + 10) + +#define V4L2_CID_PRIVATE_CSR0_DIS_AGC (RW_PRIBASE + (SYSCFG<<4) + 13) +#define V4L2_CID_PRIVATE_CSR0_RDS_EN (RW_PRIBASE + (SYSCFG<<4) + 12) + +#define V4L2_CID_PRIVATE_SEEK_CANCEL (RW_PRIBASE + (SEEKCFG1<<4) + 10) +#define V4L2_CID_PRIVATE_CSR0_SEEKRSSITH (RW_PRIBASE + (SEEKCFG1<<4) + 0) + +#define V4L2_CID_PRIVATE_RDS_RDY (RW_PRIBASE + (STATUS<<4) + 15) +#define V4L2_CID_PRIVATE_STD (RW_PRIBASE + (STATUS<<4) + 14) +#define V4L2_CID_PRIVATE_SF (RW_PRIBASE + (STATUS<<4) + 13) +#define V4L2_CID_PRIVATE_RDS_SYNC (RW_PRIBASE + (STATUS<<4) + 11) +#define V4L2_CID_PRIVATE_SI (RW_PRIBASE + (STATUS<<4) + 10) + +#define V4L2_CID_PRIVATE_RSSI (RW_PRIBASE + (RSSI<<4) + 0) +/************************************************************************** + * General Driver Definitions + **************************************************************************/ + +/* + * rtc6213n_device - private data + */ +struct rtc6213n_device { + struct video_device *videodev; + + /* driver management */ + unsigned int users; + + /* Richwave internal registers (0..15) */ + unsigned short registers[RADIO_REGISTER_NUM]; + + /* RDS receive buffer */ + wait_queue_head_t read_queue; + struct mutex lock; /* buffer locking */ + unsigned char *buffer; /* size is always multiple of three */ + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; + + struct completion completion; + bool stci_enabled; /* Seek/Tune Complete Interrupt */ + + struct i2c_client *client; +}; + +/************************************************************************** + * Firmware Versions + **************************************************************************/ +#define RADIO_FW_VERSION 15 + +/************************************************************************** + * Frequency Multiplicator + **************************************************************************/ +#define FREQ_MUL 1000 +#define CONFIG_RDS + +/************************************************************************** + * Common Functions + **************************************************************************/ +extern struct i2c_driver rtc6213n_i2c_driver; +extern struct video_device rtc6213n_viddev_template; +extern struct tasklet_struct my_tasklet; +extern int rtc6213n_get_all_registers(struct rtc6213n_device *radio); +extern int rtc6213n_get_register(struct rtc6213n_device *radio, int regnr); +extern int rtc6213n_set_register(struct rtc6213n_device *radio, int regnr); +extern int rtc6213n_set_serial_registers(struct rtc6213n_device *radio, + u16 *data, int bytes); +int rtc6213n_i2c_init(void); +int rtc6213n_disconnect_check(struct rtc6213n_device *radio); +int rtc6213n_set_freq(struct rtc6213n_device *radio, unsigned int freq); +int rtc6213n_start(struct rtc6213n_device *radio); +int rtc6213n_stop(struct rtc6213n_device *radio); +int rtc6213n_fops_open(struct file *file); +int rtc6213n_fops_release(struct file *file); +int rtc6213n_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability); diff --git a/drivers/media/tdmb/Makefile b/drivers/media/tdmb/Makefile index 24c0a7254d5d..aa2b7ec7c0be 100644 --- a/drivers/media/tdmb/Makefile +++ b/drivers/media/tdmb/Makefile @@ -11,6 +11,10 @@ obj-$(CONFIG_TDMB) += tdmb.o tdmb_data.o ccflags-$(CONFIG_TDMB_FC8080) += -Idrivers/media/tdmb/fc8080 obj-$(CONFIG_TDMB_FC8080) += tdmb_port_fc8080.o obj-$(CONFIG_TDMB_FC8080) += fc8080/ +# MTV319 +ccflags-$(CONFIG_TDMB_MTV319) += -Idrivers/media/tdmb/mtv319 +obj-$(CONFIG_TDMB_MTV319) += tdmb_port_mtv319.o +obj-$(CONFIG_TDMB_MTV319) += mtv319/ # i/f obj-$(CONFIG_TDMB_SPI) += tdmb_spi.o obj-$(CONFIG_TDMB_EBI) += tdmb_ebi.o diff --git a/drivers/media/tdmb/mtv319/Makefile b/drivers/media/tdmb/mtv319/Makefile new file mode 100644 index 000000000000..21d202ae71a3 --- /dev/null +++ b/drivers/media/tdmb/mtv319/Makefile @@ -0,0 +1,8 @@ +obj-y += mtv319.o +obj-y += mtv319_port.o +obj-y += mtv319_rf.o +obj-y += mtv319_ficdec.o +obj-y += mtv319_tdmb.o +obj-y += mtv319_cifdec.o + +ccflags-y += -Idrivers/media/tdmb diff --git a/drivers/media/tdmb/mtv319/mtv319.c b/drivers/media/tdmb/mtv319/mtv319.c new file mode 100644 index 000000000000..cd5ad6be370f --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319.c @@ -0,0 +1,88 @@ +/* +* +* File name: mtv319.c +* +* Description : MTV319 T-DMB services source file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "mtv319_rf.h" +#include "mtv319_internal.h" + +U8 g_bRtvIntrMaskReg; +U8 g_bRtvPage; + + +int REV_ID; + +INT rtv_InitSystem(void) +{ + int i; + U8 read0, read1; + + g_bRtvIntrMaskReg = 0xFF; + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #ifdef RTV_IF_SPI + #define WR27_VAL 0x10 + #else + #define WR27_VAL 0x12 + #endif + + #define WR29_VAL 0x31 + + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + for (i = 0; i < 100; i++) { + RTV_REG_SET(0x29, WR29_VAL); /* BUFSEL first! */ + RTV_REG_SET(0x27, WR27_VAL); + + read0 = RTV_REG_GET(0x27); + read1 = RTV_REG_GET(0x29); + RTV_DBGMSG2("read0(0x%02X), read1(0x%02X)\n", read0, read1); + + if ((read0 == WR27_VAL) && (read1 == WR29_VAL)) + goto RTV_POWER_ON_SUCCESS; + + RTV_DBGMSG1("[rtv_InitSystem] Power On wait: %d\n", i); + RTV_DELAY_MS(5); + } +#else + RTV_REG_MAP_SEL(HOST_PAGE); + for (i = 0; i < 100; i++) { + RTV_REG_SET(0x05, 0x00); + RTV_REG_SET(0x08, 0x10); + + read0 = RTV_REG_GET(0x05); + read1 = RTV_REG_GET(0x08); + RTV_DBGMSG2("read0(0x%02X), read1(0x%02X)\n", read0, read1); + + if ((read0 == 0x00) && (read1 == 0x10)) + goto RTV_POWER_ON_SUCCESS; + + RTV_REG_SET(0x07, 0x00); + + RTV_DBGMSG1("[rtv_InitSystem] Power On wait: %d\n", i); + RTV_DELAY_MS(5); + } +#endif + + RTV_DBGMSG1("rtv_InitSystem: Power On Check error: %d\n", i); + return RTV_POWER_ON_CHECK_ERROR; + +RTV_POWER_ON_SUCCESS: + + return RTV_SUCCESS; +} + + diff --git a/drivers/media/tdmb/mtv319/mtv319.h b/drivers/media/tdmb/mtv319/mtv319.h new file mode 100644 index 000000000000..fdf08aa152d5 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319.h @@ -0,0 +1,161 @@ +/* +* +* File name: mtv319.h +* +* Description : MTV319 device driver API header file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __MTV319_H__ +#define __MTV319_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "mtv319_port.h" + +/*============================================================================= +* +* Common definitions and types. +* +*===========================================================================*/ +#define MTV319_CHIP_ID 0xC6 +#define MTV319_FIC_BUF_SIZE (3 * 188) +#define MTV319_SPI_CMD_SIZE 3 + +#ifndef NULL + #define NULL 0 +#endif + +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef TRUE + #define TRUE 1 +#endif + +#ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef ABS + #define ABS(x) (((x) < 0) ? -(x) : (x)) +#endif + + +/* Error codes. */ +#define RTV_SUCCESS 0 +#define RTV_POWER_ON_CHECK_ERROR -1 +#define RTV_ADC_CLK_UNLOCKED -2 +#define RTV_PLL_UNLOCKED -3 +#define RTV_CHANNEL_NOT_DETECTED -4 +#define RTV_NOT_OPENED_FIC -5 +#define RTV_INVAILD_SUBCHANNEL_ID -6 +#define RTV_NO_MORE_SUBCHANNEL -7 +#define RTV_ALREADY_OPENED_SUBCHANNEL_ID -8 +#define RTV_INVAILD_THRESHOLD_SIZE -9 +#define RTV_OPENING_SERVICE_FULL -10 +#define RTV_INVAILD_SERVICE_TYPE -11 +#define RTV_FIC_READ_TIMEOUT -12 +#define RTV_SHOULD_CLOSE_SUBCHANNELS -13 +#define RTV_SHOULD_CLOSE_FIC -14 +#define RTV_INVALID_FIC_OPEN_STATE -15 + +/* Do not modify the value! */ +enum E_RTV_SERVICE_TYPE { + RTV_SERVICE_DMB = 0, /* DMB Video */ + RTV_SERVICE_DAB = 1, /* DAB */ + RTV_SERVICE_DABPLUS = 2 /* DAB+ */ +}; + +/* Cont flag of multi channel header */ +enum RTV_MCH_HDR_CONT_FLAG_T { + RTV_MCH_HDR_CONT_MED = 0, + RTV_MCH_HDR_CONT_LAST = 1, + RTV_MCH_HDR_CONT_FIRST = 2, + RTV_MCH_HDR_CONT_ALONE = 3 +}; + +/* ID flag of multi channel header */ +enum RTV_MCH_HDR_ID_FLAG_T { + RTV_MCH_HDR_ID_DAB = 0, + RTV_MCH_HDR_ID_DMB = 1, + RTV_MCH_HDR_ID_FIDC = 2, + RTV_MCH_HDR_ID_FIC = 3, + MAX_NUM_MCH_HDR_ID_TYPE +}; + +#define RTV_MCH_HDR_SIZE 4 /* Size, in bytes, of MCH header */ +#define MAX_MCH_PAYLOAD_SIZE (RTV_TSP_XFER_SIZE - RTV_MCH_HDR_SIZE) + +/*============================================================================= +* +* TDMB definitions, types and APIs. +* +*===========================================================================*/ +#define RTV_TDMB_AGC_LOCK_MASK 0x1 +#define RTV_TDMB_OFDM_LOCK_MASK 0x2 +#define RTV_TDMB_FEC_LOCK_MASK 0x4 + +#define RTV_TDMB_CHANNEL_LOCK_OK \ + (RTV_TDMB_AGC_LOCK_MASK|RTV_TDMB_OFDM_LOCK_MASK|RTV_TDMB_FEC_LOCK_MASK) + +#define RTV_TDMB_BER_DIVIDER 100000 +#define RTV_TDMB_CNR_DIVIDER 1000 +#define RTV_TDMB_RSSI_DIVIDER 1000 + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) +extern UINT g_nRtvInterruptLevelSize; +static INLINE UINT rtvTDMB_GetInterruptLevelSize(void) +{ + return g_nRtvInterruptLevelSize; +} +#endif + +INT rtvTDMB_OpenSubChannelExt(U32 dwChFreqKHz, UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType, UINT nThresholdSize); + +UINT rtvTDMB_GetLockStatus(void); +UINT rtvTDMB_GetAntennaLevel(U32 dwCER); +U32 rtvTDMB_GetFicCER(void); +U32 rtvTDMB_GetCER(void); +U32 rtvTDMB_GetPER(void); +S32 rtvTDMB_GetRSSI(void); +U32 rtvTDMB_GetCNR(void); +U32 rtvTDMB_GetBER(void); +U32 rtvTDMB_GetPreviousFrequency(void); +UINT rtvTDMB_GetOpenedSubChannelCount(void); +void rtvTDMB_CloseAllSubChannels(void); +INT rtvTDMB_CloseSubChannel(UINT nSubChID); +INT rtvTDMB_OpenSubChannel(U32 dwChFreqKHz, UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType, UINT nThresholdSize); +INT rtvTDMB_ReadFIC(U8 *pbBuf); +void rtvTDMB_CloseFIC(void); +INT rtvTDMB_OpenFIC(void); +INT rtvTDMB_ScanFrequency(U32 dwChFreqKHz); +INT rtvTDMB_Initialize(unsigned long interface); +UINT tdmb_GetOfdmLockStatus(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_H__ */ + diff --git a/drivers/media/tdmb/mtv319/mtv319_cifdec.c b/drivers/media/tdmb/mtv319/mtv319_cifdec.c new file mode 100644 index 000000000000..5b69d3292646 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_cifdec.c @@ -0,0 +1,1311 @@ +/* +* +* File name: mtv319_cifdec.c +* +* Description : MTV319 CIF decoder source file for T-DMB and DAB. +* +* Copyright (C) (2014, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/****************************************************************************** +* REVISION HISTORY +* +* DATE NAME REMARKS +* ---------- ------------- ------------------------------------------------ +* 07/12/2012 Ko, Kevin Created. +******************************************************************************/ + +#include "mtv319_cifdec.h" + + +/*============================================================================ +* Defines the number of CIF buffer pool. +*===========================================================================*/ +#define MAX_NUM_INPUT_TSP (16) + +/*============================================================================ +* Select the debug options. +*===========================================================================*/ +#define _DEBUG_MSG_ENABLE +#define _DEBUG_ASSERT_ENABLE +/* #define _DEBUG_CIFDEC_ERR_STATIC */ +#define _DEBUG_HEADER_DECODING + +#define MAX_NUM_SUBCH 64 + +/* Used sub channel ID bits. [0]: 0 ~ 31, [1]: 32 ~ 63 */ +static U32 g_aAddedSubChIdBits[2]; + +#ifdef _DEBUG_MSG_ENABLE + #define CIF_DBGMSG0(fmt) printk(fmt) + #define CIF_DBGMSG1(fmt, arg1) printk(fmt, arg1) + #define CIF_DBGMSG2(fmt, arg1, arg2) printk(fmt, arg1, arg2) + #define CIF_DBGMSG3(fmt, arg1, arg2, arg3) printk(fmt, arg1, arg2, arg3) + #define CIF_DBGMSG4(fmt, arg1, arg2, arg3, arg4)\ + printk(fmt, arg1, arg2, arg3, arg4) +#else + /* To eliminates the debug messages. */ + #define CIF_DBGMSG0(fmt) ((void)0) + #define CIF_DBGMSG1(fmt, arg1) ((void)0) + #define CIF_DBGMSG2(fmt, arg1, arg2) ((void)0) + #define CIF_DBGMSG3(fmt, arg1, arg2, arg3) ((void)0) + #define CIF_DBGMSG4(fmt, arg1, arg2, arg3, arg4) ((void)0) +#endif + +#if defined(__KERNEL__) /* Linux kernel */ + #include + static struct mutex cif_mutex; + #define CIF_MUTEX_INIT mutex_init(&cif_mutex) + #define CIF_MUTEX_LOCK mutex_lock(&cif_mutex) + #define CIF_MUTEX_UNLOCK mutex_unlock(&cif_mutex) + #define CIF_MUTEX_DEINIT ((void)0) + + #ifdef _DEBUG_ASSERT_ENABLE + #define CIF_ASSERT(expr) \ + do { \ + if (!(expr)) { \ + printk(KERN_EMERG "assert failed %s: %d: %s\n",\ + __FILE__, __LINE__, #expr); \ + BUG(); \ + } \ + } while (0) + #else + #define CIF_ASSERT(expr) do {} while (0) + #endif + +#elif !defined(__KERNEL__) && defined(__linux__) /* Linux application */ + #include + static pthread_mutex_t cif_mutex; + #define CIF_MUTEX_INIT pthread_mutex_init(&cif_mutex) + #define CIF_MUTEX_LOCK pthread_mutex_lock(&cif_mutex) + #define CIF_MUTEX_UNLOCK pthread_mutex_unlock(&cif_mutex) + #define CIF_MUTEX_DEINIT ((void)0) + + #ifdef _DEBUG_ASSERT_ENABLE + #include + #define CIF_ASSERT(expr) assert(expr) + #else + #define CIF_ASSERT(expr) do {} while (0) + #endif + +#elif defined(WINCE) || defined(WINDOWS) || defined(WIN32) + static CRITICAL_SECTION cif_mutex; + #define CIF_MUTEX_INIT InitializeCriticalSection(&cif_mutex) + #define CIF_MUTEX_LOCK EnterCriticalSection(&cif_mutex) + #define CIF_MUTEX_UNLOCK LeaveCriticalSection(&cif_mutex) + #define CIF_MUTEX_DEINIT DeleteCriticalSection(&cif_mutex) + + #ifdef _DEBUG_ASSERT_ENABLE + #ifdef WINCE + #include + #define CIF_ASSERT(expr) ASSERT(expr) + #else + #include + #define CIF_ASSERT(expr) _ASSERT(expr) + #endif + #else + #define CIF_ASSERT(expr) do {} while (0) + #endif +#else + #error "Code not present" + /* temp: TODO */ + #define CIF_MUTEX_INIT ((void)0) + #define CIF_MUTEX_LOCK ((void)0) + #define CIF_MUTEX_UNLOCK ((void)0) + #define CIF_MUTEX_DEINIT ((void)0) + + #ifdef _DEBUG_ASSERT_ENABLE + #include + #define CIF_ASSERT(expr) assert(expr) + #else + #define CIF_ASSERT(expr) do {} while (0) + #endif +#endif + +#if defined(__KERNEL__) && defined(RTV_MCHDEC_DIRECT_COPY_USER_SPACE)\ +/* Linux kernel */ + + /* File dump enable */ + #if 0 + #define _MSC_KERNEL_FILE_DUMP_ENABLE + #endif + + #ifdef _MSC_KERNEL_FILE_DUMP_ENABLE + #include + + /* MSC filename: /data/dmb_msc_SUBCH_ID.ts */ + #define MSC_DEC_FNAME_PREFIX "/data/dmb_msc" + + static struct file *g_ptDecMscFilp[MAX_NUM_SUBCH]; + static UINT g_nKfileDecSubchID; + + static void cif_kfile_write(const char __user *buf, size_t len) + { + mm_segment_t oldfs; + struct file *fp_msc; + int ret; + + if (g_nKfileDecSubchID != 0xFFFF) { + fp_msc = g_ptDecMscFilp[g_nKfileDecSubchID]; + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = fp_msc->f_op->write(fp_msc, buf, + len, &fp_msc->f_pos); + set_fs(oldfs); + } + } + + static INLINE void __cif_kfile_close(UINT subch_id) + { + if (g_ptDecMscFilp[subch_id]) { + filp_close(g_ptDecMscFilp[subch_id], NULL); + g_ptDecMscFilp[subch_id] = NULL; + } + } + + static void cif_kfile_all_close(void) + { + unsigned int subch_id; + U32 reged_subch_id_bits; + + subch_id = 0; + reged_subch_id_bits = g_aAddedSubChIdBits[0]; + while (reged_subch_id_bits) { + if (reged_subch_id_bits & 0x01) + __cif_kfile_close(subch_id); + + reged_subch_id_bits >>= 1; + subch_id++; + } + + subch_id = 32; + reged_subch_id_bits = g_aAddedSubChIdBits[1]; + while (reged_subch_id_bits) { + if (reged_subch_id_bits & 0x01) + __cif_kfile_close(subch_id); + + reged_subch_id_bits >>= 1; + subch_id++; + } + } + + static void cif_kfile_close(UINT subch_id) + { + if (subch_id != 0xFFFF) + __cif_kfile_close(subch_id); + else + cif_kfile_all_close(); + } + + static int cif_kfile_open(UINT subch_id) + { + char fname[MAX_NUM_SUBCH]; + struct file *fp_msc; + + if (g_ptDecMscFilp[subch_id] == NULL) { + sprintf(fname, "%s_%u.ts", + MSC_DEC_FNAME_PREFIX, subch_id); + fp_msc = filp_open(fname, O_WRONLY, S_IRUSR); + if (fp_msc == NULL) { + printk(KERN_EMERG "[cif_kfile_open] f_err: %s!\n", + fname); + return -1; + } + + g_ptDecMscFilp[subch_id] = fp_msc; + printk(KERN_INFO "[cif_kfile_open] File opened: %s\n", + fname); + } else + printk(KERN_INFO "[cif_kfile_open] Already opened!\n"); + + return 0; + } + + #define CIF_KFILE_CLOSE(subch_id) cif_kfile_close(subch_id) + #define CIF_KFILE_OPEN(subch_id) cif_kfile_open(subch_id) + #define CIF_KFILE_WRITE(buf, size) cif_kfile_write(buf, size) + #define CIF_MSC_KFILE_WRITE_DIS g_nKfileDecSubchID = 0xFFFF; + #define CIF_MSC_KFILE_WRITE_EN(subch_id)\ + g_nKfileDecSubchID = subch_id; + #else + #define CIF_KFILE_CLOSE(subch_id) ((void)0) + #define CIF_KFILE_OPEN(subch_id) ((void)0) + #define CIF_KFILE_WRITE(buf, size) ((void)0) + #define CIF_MSC_KFILE_WRITE_DIS ((void)0) + #define CIF_MSC_KFILE_WRITE_EN(subch_id) ((void)0) + #endif + + #include + + #define CIF_DATA_COPY(dst_ptr, src_ptr, size) \ + do { \ + CIF_KFILE_WRITE(src_ptr, size);\ + if (copy_to_user(dst_ptr, src_ptr, size)) {\ + WARN(1, KERN_ERR "copy_to_user error!\n"); + } \ + } while (0) +#else + #define CIF_KFILE_CLOSE(subch_id) ((void)0) + #define CIF_KFILE_OPEN(subch_id) ((void)0) + #define CIF_KFILE_WRITE(buf, size) ((void)0) + #define CIF_MSC_KFILE_WRITE_DIS ((void)0) + #define CIF_MSC_KFILE_WRITE_EN(subch_id) ((void)0) + + #define CIF_DATA_COPY(dst_ptr, src_ptr, size) \ + do { memcpy(dst_ptr, src_ptr, size); } while (0) +#endif + + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) +static enum RTV_MCH_HDR_ID_FLAG_T g_eSingleSvcFlagID; +#endif + +#define CIF_DISCARDED_TSP_MARK_0 0x48 +#define CIF_DISCARDED_TSP_MARK_1 0xFF + +#define CIF_INVALID_SUBCH_ID 0xFF + +static UINT g_nOutDecBufIdxBits; /* Decoded out buffer index bits */ + +static enum E_RTV_SERVICE_TYPE g_eaSvcType[MAX_NUM_SUBCH]; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) +static U8 g_abOutDecBufIdx[MAX_NUM_SUBCH]; /* Decoded out buffer index for sub ch */ +#endif + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + static UINT g_nSingleSubchID; +#endif + +static BOOL g_fCifInited = FALSE; + +static volatile BOOL g_fForceDecodeStop; + + +enum CIFDEC_STATUS_TYPE { + CIFDEC_S__OK = 0, + CIFDEC_S__INVALID_SYNC_BYTE = 1, + CIFDEC_S__INVALID_SUBCH_SIZE = 2, + CIFDEC_S__INVALID_SUBCH_ID = 3, + + CIFDEC_S__NOT_EN_FIC_DECODER = 4, + CIFDEC_S__CHANGED_SUBCH_ID = 5, + CIFDEC_S__SMALL_DEC_BUF = 6, + CIFDEC_S__CIFB_ALLOC_ERR = 7, + CIFDEC_S__DISCARDED_TSP = 8, + + CIFDEC_S__NOT_ENOUGH_DECODE_MSC_SIZE = 9, + CIFDEC_S__INVALID_HEADER_BYTE = 10, + CIFDEC_S__INVALID_SVC_TYPE = 11, + CIFDEC_S__MISSING_LAST_DMB_TS = 12, + + CIFDEC_S__TRUNCATED_FIC = 13, + CIFDEC_S__NOT_ENOUGH_DECODE_FIC_SIZE = 14, + +#ifdef _DEBUG_HEADER_DECODING + CIFDEC_S__ZERO_PAYLOAD_SIZE = 15, + CIFDEC_S__SHORT_PAYLOAD_SIZE = 16, + + CIFDEC_S__INVALID_FIC_SIZE = 17, +#endif + MAX_NUM_DEC_ERR_TYPE +}; + + +#ifdef _DEBUG_CIFDEC_ERR_STATIC + /* CIF decoder error statistics */ + static unsigned long g_aErrStat[MAX_NUM_DEC_ERR_TYPE]; + #define CIF_ERR_STAT_INC(err_type) g_aErrStat[err_type]++; + #define CIF_ERR_STAT_RST(err_type) g_aErrStat[err_type] = 0 + #define CIF_ERR_STAT_RST_ALL\ + memset(g_aErrStat, 0, sizeof(g_aErrStat)) + #define CIF_ERR_STAT_SHOW\ + do {\ + INT i, mod = (MAX_NUM_DEC_ERR_TYPE-1) % 2; \ + CIF_DBGMSG0("|----- CIF decoding Statistics -----\n");\ + for (i = 1; i < MAX_NUM_DEC_ERR_TYPE-1; i += 2) {\ + CIF_DBGMSG4("| S_%d(%ld), S_%d(%ld)\n",\ + i, g_aErrStat[i], i+1, g_aErrStat[i+1]);\ + } \ + if (mod) \ + CIF_DBGMSG2("| S_%d(%ld)\n", i, g_aErrStat[i]);\ + CIF_DBGMSG0("|------------------------------------\n");\ + } while (0) +#else + #define CIF_ERR_STAT_INC(err_type) ((void)0) + #define CIF_ERR_STAT_RST(err_type) ((void)0) + #define CIF_ERR_STAT_RST_ALL ((void)0) + #define CIF_ERR_STAT_SHOW ((void)0) +#endif + +/* CIF decoder Buffer */ +struct CIFB_INFO { + struct CIFB_INFO *ptNext; + + U8 id_flag; + U8 subch_id; + U8 cont; + U8 ts_size; /* size of data in the current TSP. */ + + U16 data_len; /* Total data size */ + + U8 header_on; + + const U8 *ts_ptr; /* The pointer to real TS data */ + + BOOL frag_buf_used; +}; + +struct CIFB_HEAD_INFO { + struct CIFB_INFO *ptFirst; + struct CIFB_INFO *ptLast; + UINT cnt; /* Item count in the list */ + UINT tts_len; /* Total ts len in the chain. */ +}; + + +#define NUM_CIF_BUF_POOL\ + (MAX_NUM_INPUT_TSP + 2/*FIC frag*/\ + + (10*RTV_MAX_NUM_USE_SUBCHANNEL)/*for short frag cifb*/) + + +/* FIC TSP Queue */ +static struct CIFB_HEAD_INFO cifdec_fic_tspq; + +/* Buffer for fragment. Up to 2 fragments. */ +static U8 fic_frag_buf[2][188]; + +/* MSC TSP Queue */ +static struct CIFB_HEAD_INFO cifdec_msc_tspq[RTV_MAX_NUM_USE_SUBCHANNEL]; + +/* Buffer for fragment */ +static U8 msc_frag_buf[RTV_MAX_NUM_USE_SUBCHANNEL][188*2]; + +static struct CIFB_INFO cif_buf_pool[NUM_CIF_BUF_POOL]; +static struct CIFB_INFO *g_aCifBufPoolList[NUM_CIF_BUF_POOL]; +static UINT g_nCifBufPoolFreeCnt; + + +static INLINE void cifb_free_buffer(struct CIFB_INFO *cifb) +{ + CIF_ASSERT(g_nCifBufPoolFreeCnt < NUM_CIF_BUF_POOL); + g_aCifBufPoolList[g_nCifBufPoolFreeCnt++] = cifb; +} + +static INLINE struct CIFB_INFO *cifb_alloc_buffer(const U8 *ts_ptr) +{ + if (g_nCifBufPoolFreeCnt) { + struct CIFB_INFO *cifb; + cifb = g_aCifBufPoolList[--g_nCifBufPoolFreeCnt]; + cifb->ts_ptr = ts_ptr; + cifb->ts_size = 0; + return cifb; + } else + return NULL; +} + +static INLINE void cifb_queue_unlink(struct CIFB_HEAD_INFO *q, + struct CIFB_INFO *cifb) +{ + if (q->ptFirst != NULL) { + q->ptFirst = cifb->ptNext; + + if (q->ptFirst == NULL) + q->ptLast = NULL; + + cifb->ptNext = NULL; + } + + q->tts_len -= cifb->ts_size; + q->cnt--; +} + +static INLINE void cifb_queue_free(struct CIFB_HEAD_INFO *q, + struct CIFB_INFO *cifb) +{ + CIF_ASSERT(q->cnt != 0); + cifb_queue_unlink(q, cifb); + cifb_free_buffer(cifb); +} + +static INLINE struct CIFB_INFO *cifb_peek_frist(struct CIFB_HEAD_INFO *q) +{ + return q->ptFirst; +} + +static void cifb_queue_release_all(struct CIFB_HEAD_INFO *q) +{ + struct CIFB_INFO *cifb; + + while ((cifb = cifb_peek_frist(q)) != NULL) + cifb_queue_free(q, cifb); + + CIF_ASSERT(g_nCifBufPoolFreeCnt == NUM_CIF_BUF_POOL); +} + +static INLINE void cifb_enqueue(struct CIFB_HEAD_INFO *q, + struct CIFB_INFO *new) +{ + new->ptNext = NULL; + + if (q->ptLast != NULL) + q->ptLast->ptNext = new; + else + q->ptFirst = new; + + q->ptLast = new; + + q->cnt++; + q->tts_len += new->ts_size; +} + +static INLINE void cifb_queue_init(struct CIFB_HEAD_INFO *q) +{ + q->ptFirst = q->ptLast = NULL; + + q->cnt = 0; + q->tts_len = 0; +} + +/* +* Copy TS from cifb to decoded output buffer. +* return: Copying node in next time or Head. +*/ +static INLINE struct CIFB_INFO *cifb_copydec(U8 *dec_buf, struct CIFB_INFO *cifb, + struct CIFB_HEAD_INFO *head, UINT len) +{ + UINT copied; + struct CIFB_INFO *next; + + CIF_ASSERT(cifb != NULL); + CIF_ASSERT(len && (head->tts_len >= len)); + + while ((cifb = cifb_peek_frist(head)) != NULL) { + copied = MIN(cifb->ts_size, len); + if (copied) + CIF_DATA_COPY(dec_buf, cifb->ts_ptr, copied); + + if (cifb->ts_size == copied) { + next = cifb->ptNext; + cifb_queue_free(head, cifb); + cifb = next; + } else { + cifb->ts_ptr += copied; + cifb->ts_size -= copied; + head->tts_len -= copied; + } + + dec_buf += copied; + len -= copied; + if (len == 0) + break; + } + + return cifb; +} + +/* Copy the Audio/Data MSC into user-buffer with 188-bytes align. */ +static UINT copy_dab_188(struct RTV_CIF_DEC_INFO *dec, UINT idx, + struct CIFB_HEAD_INFO *tspq, enum CIFDEC_STATUS_TYPE *status) +{ + UINT mod, copied; + UINT subch_size = dec->subch_size[idx]; + U8 *subch_ptr = &dec->subch_buf_ptr[idx][subch_size]; + struct CIFB_INFO *cifb = cifb_peek_frist(tspq); /* The first entry */ + + *status = CIFDEC_S__OK; + + if (tspq->tts_len >= 188) { + mod = tspq->tts_len % 188; + copied = tspq->tts_len - mod; + + cifb = cifb_copydec(subch_ptr, cifb, tspq, copied); + dec->subch_size[idx] += copied; + } + + if (tspq->tts_len) { + UINT len; /* Length, in bytes of fragment data */ + struct CIFB_INFO *frist_frag_cifb = cifb; + + if (cifb->frag_buf_used == FALSE) + len = 0; + else { + len = cifb->ts_size; + memmove(msc_frag_buf[idx], cifb->ts_ptr, len); + cifb->ts_size = 0; + } + + do { + /* Copy ts data into fragment-buffer. */ + if (cifb->ts_size) { + memcpy(&msc_frag_buf[idx][len], cifb->ts_ptr, cifb->ts_size); + + len += cifb->ts_size; + cifb->ts_size = 0; /* Reset the size */ + } + + cifb = cifb->ptNext; + } while (cifb); + + /* Adjust ts pointer */ + frist_frag_cifb->ts_ptr = (const U8 *)msc_frag_buf[idx]; + frist_frag_cifb->ts_size = len; + frist_frag_cifb->frag_buf_used = TRUE; + + *status = CIFDEC_S__NOT_ENOUGH_DECODE_MSC_SIZE; + } + + return dec->subch_size[idx] - subch_size; +} + +static void proc_msc_dab(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq) +{ + enum CIFDEC_STATUS_TYPE status = CIFDEC_S__OK; + U8 dec_idx; + UINT i, copy_size; + struct CIFB_INFO *cifb = cifb_peek_frist(tspq); /* The first entry */ + + /* Get the index of output buffer determined when add sub channel. */ +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + dec_idx = 0; +#else + dec_idx = g_abOutDecBufIdx[cifb->subch_id]; +#endif + if (dec->subch_id[dec_idx] == CIF_INVALID_SUBCH_ID) + dec->subch_id[dec_idx] = cifb->subch_id; /* The first */ + + /* Check if subch ID was changed in the same out buf index ? */ + if (dec->subch_id[dec_idx] == cifb->subch_id) { + /*Check if the size is greater than the size of output buffer.*/ + if (tspq->tts_len <= dec->subch_buf_size[dec_idx]) { + CIF_MSC_KFILE_WRITE_EN(cifb->subch_id); + copy_size = copy_dab_188(dec, dec_idx, tspq, &status); + dec->subch_buf_size[dec_idx] -= copy_size; + CIF_MSC_KFILE_WRITE_DIS; + } else + status = CIFDEC_S__SMALL_DEC_BUF; + } else + status = CIFDEC_S__CHANGED_SUBCH_ID; + + if (status != CIFDEC_S__OK) { + if (status == CIFDEC_S__NOT_ENOUGH_DECODE_MSC_SIZE) { + CIF_ERR_STAT_INC(status); + } + else { + for (i = 0; i < tspq->cnt; i++) /* must first */ + CIF_ERR_STAT_INC(status); + + cifb_queue_release_all(tspq); + } + } +} + +/* Copy the Video MSC into user-buffer with 188-bytes align. */ +static UINT copy_dmb_188(struct RTV_CIF_DEC_INFO *dec, UINT idx, + struct CIFB_HEAD_INFO *tspq, enum CIFDEC_STATUS_TYPE *status) +{ + struct CIFB_INFO *cifb; + UINT subch_size = dec->subch_size[idx]; + U8 *subch_ptr = &dec->subch_buf_ptr[idx][subch_size]; + + *status = CIFDEC_S__OK; + + while ((cifb = cifb_peek_frist(tspq)) != NULL) { + if (g_fForceDecodeStop == TRUE) + break; + + if (cifb->header_on == 0) { + CIF_DATA_COPY(subch_ptr, cifb->ts_ptr, 188); + subch_ptr += 188; + dec->subch_size[idx] += 188; + cifb_queue_free(tspq, cifb); + } else { + if (cifb->cont == RTV_MCH_HDR_CONT_FIRST) { + if (cifb->ts_ptr[0] == 0x47) { + if (tspq->cnt > 1) { + if (cifb->ptNext->cont == RTV_MCH_HDR_CONT_LAST) { + cifb_copydec(subch_ptr, + cifb, tspq, 188); + subch_ptr += 188; + dec->subch_size[idx] += 188; + } + else { + CIF_ERR_STAT_INC(CIFDEC_S__MISSING_LAST_DMB_TS); + cifb_queue_free(tspq, cifb); /* Discard TSP */ + } + } else { + /* Copy ts data into buffer. NOT input buffer! */ + memcpy(&msc_frag_buf[idx], cifb->ts_ptr, cifb->ts_size); + + /* Adjust ts pointer */ + cifb->ts_ptr = (const U8 *)&msc_frag_buf[idx]; + cifb->frag_buf_used = TRUE; + + *status = CIFDEC_S__NOT_ENOUGH_DECODE_MSC_SIZE; + goto exit_dmb_copy; + } + } else { + CIF_ERR_STAT_INC(CIFDEC_S__INVALID_SYNC_BYTE); + cifb_queue_free(tspq, cifb); /* Discard TSP */ + } + } else + cifb_queue_free(tspq, cifb); /* Discard the TSP. */ + } + } + +exit_dmb_copy: + return dec->subch_size[idx] - subch_size; +} + +static void proc_msc_dmb_dabp(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq) +{ + enum CIFDEC_STATUS_TYPE status = CIFDEC_S__OK; + U8 dec_idx; + UINT i, copy_size; + struct CIFB_INFO *cifb = cifb_peek_frist(tspq); /* The first entry */ + + /* Get the index of output buffer determined when add sub channel. */ +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + dec_idx = 0; +#else + dec_idx = g_abOutDecBufIdx[cifb->subch_id]; +#endif + if (dec->subch_id[dec_idx] == CIF_INVALID_SUBCH_ID) + dec->subch_id[dec_idx] = cifb->subch_id; /* The 1st time */ + + /* Check if subch ID was changed in the same out buf index ? */ + if (dec->subch_id[dec_idx] == cifb->subch_id) { + /*Check if the size is greater than the size of output buffer.*/ + if (tspq->tts_len <= dec->subch_buf_size[dec_idx]) { + CIF_MSC_KFILE_WRITE_EN(cifb->subch_id); + + if (g_eaSvcType[cifb->subch_id] + == RTV_SERVICE_DMB) + copy_size = copy_dmb_188(dec, dec_idx, tspq, &status); + else + copy_size = copy_dab_188(dec, dec_idx, tspq, &status); + + dec->subch_buf_size[dec_idx] -= copy_size; + CIF_MSC_KFILE_WRITE_DIS; + } else + status = CIFDEC_S__SMALL_DEC_BUF; + } else + status = CIFDEC_S__CHANGED_SUBCH_ID; + + if (status != CIFDEC_S__OK) { + if (status == CIFDEC_S__NOT_ENOUGH_DECODE_MSC_SIZE) { + CIF_ERR_STAT_INC(status); + } + else { + for (i = 0; i < tspq->cnt; i++) /* must first */ + CIF_ERR_STAT_INC(status); + + cifb_queue_release_all(tspq); + } + } + + return; +} + +#if 0 +static void proc_fidc(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq) +{ + struct CIFB_INFO *cifb = cifb_peek_frist(tspq); /* The first entry */ + + CIF_DBGMSG0("[proc_fidc] EWS data. Not yet processed...\n"); + + while ((cifb = cifb_peek_frist(tspq)) != NULL) + cifb = cifb_queue_free(tspq, cifb); +} +#endif + +static struct CIFB_INFO *copy_fic_192(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq, + struct CIFB_INFO *cifb, enum CIFDEC_STATUS_TYPE *status) +{ + UINT copied = 0; /* Copy length */ + + if (tspq->cnt >= 2) { + if (cifb->ptNext->cont == RTV_MCH_HDR_CONT_LAST) { + dec->fic_size = cifb->data_len; /* FINISHED */ + + copied = cifb->ts_size/* First */ + + cifb->ptNext->ts_size/* Last */; + cifb = cifb_copydec(dec->fic_buf_ptr, cifb, tspq, copied); + } else + *status = CIFDEC_S__TRUNCATED_FIC; + } + else + *status = CIFDEC_S__NOT_ENOUGH_DECODE_FIC_SIZE; + + return cifb; +} + +static struct CIFB_INFO *copy_fic_96_128(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq, + struct CIFB_INFO *cifb, enum CIFDEC_STATUS_TYPE *status) +{ + dec->fic_size = cifb->data_len; /* FINISHED */ + cifb = cifb_copydec(dec->fic_buf_ptr, cifb, tspq, cifb->data_len); + + return cifb; +} + +static INLINE struct CIFB_INFO *copy_fic_384(struct RTV_CIF_DEC_INFO *dec, + struct CIFB_HEAD_INFO *tspq, + struct CIFB_INFO *cifb, enum CIFDEC_STATUS_TYPE *status) +{ + UINT copied = 0; /* Copy length */ + + if (tspq->cnt >= 3) { + if ((cifb->ptNext->cont == RTV_MCH_HDR_CONT_MED) + && (cifb->ptNext->ptNext->cont == RTV_MCH_HDR_CONT_LAST)) { + dec->fic_size = cifb->data_len; /* FINISHED */ + + copied = cifb->ts_size/* First */ + + cifb->ptNext->ts_size/* Med */ + + cifb->ptNext->ptNext->ts_size/* Last */; + cifb = cifb_copydec(dec->fic_buf_ptr, cifb, tspq, copied); + } else + *status = CIFDEC_S__TRUNCATED_FIC; + } + else + *status = CIFDEC_S__NOT_ENOUGH_DECODE_FIC_SIZE; + + return cifb; +} + +static void proc_fic(struct RTV_CIF_DEC_INFO *dec, struct CIFB_HEAD_INFO *tspq) +{ + enum CIFDEC_STATUS_TYPE status; + struct CIFB_INFO *cifb; + + while ((cifb = cifb_peek_frist(tspq)) != NULL) { + if (g_fForceDecodeStop == TRUE) + break; + + status = CIFDEC_S__OK; + + if (!dec->fic_size) { /* Decoding was not finished ? */ + if (cifb->cont == RTV_MCH_HDR_CONT_FIRST) { + switch (cifb->data_len) { + case 384: + cifb = copy_fic_384(dec, tspq, cifb, &status); + break; + case 96: + case 128: + cifb = copy_fic_96_128(dec, tspq, cifb, &status); + break; + case 192: + cifb = copy_fic_192(dec, tspq, cifb, &status); + break; + default: + break; + } + + if (status != CIFDEC_S__OK) { + CIF_ERR_STAT_INC(status); + + if (status == CIFDEC_S__NOT_ENOUGH_DECODE_FIC_SIZE) { + UINT cnt = 0; + + do { + /* Copy ts data into buffer. NOT input buffer! */ + memcpy(&fic_frag_buf[cnt], + cifb->ts_ptr, cifb->ts_size); + + /* Adjust ts pointer */ + cifb->ts_ptr = (const U8 *)&fic_frag_buf[cnt]; + cnt++; + + cifb = cifb->ptNext; + } while (cifb); + goto stop_fic_decode; + } + + cifb_queue_free(tspq, cifb); + } + } + else if (cifb->cont == RTV_MCH_HDR_CONT_ALONE) { + dec->fic_size = cifb->data_len; /* FINISHED */ + cifb_copydec(dec->fic_buf_ptr, cifb, + tspq, cifb->data_len); + } + else + cifb_queue_free(tspq, cifb); /* Discard the TSP. */ + } else { /* Already decoded ? */ + /* Discard the TSP. */ + cifb_queue_free(tspq, cifb); + /*CIF_DBGMSG0("[proc_fic] Already decoded.\n");*/ + } + } + +stop_fic_decode: + return; +} + +static INLINE enum CIFDEC_STATUS_TYPE + decode_header(struct CIFB_INFO *cifb, const U8 *tsp) +{ + UINT array_idx, last_size; + U32 bit_val; + + if (tsp[0] == RTV_MCH_HEADER_SYNC_BYTE) { /* sync byte ok? */ + cifb->id_flag = tsp[1] >> 6; + cifb->subch_id = tsp[1] & 0x3F; + cifb->cont = tsp[2] >> 6; + cifb->data_len = ((tsp[2] & 0x3F)<<8) | tsp[3]; + + cifb->header_on = 1; + cifb->frag_buf_used = FALSE; + +#ifdef _DEBUG_HEADER_DECODING + if (cifb->data_len == 0) + return CIFDEC_S__ZERO_PAYLOAD_SIZE; +#endif + + last_size = cifb->data_len % MAX_MCH_PAYLOAD_SIZE; + if (!last_size) + last_size = MAX_MCH_PAYLOAD_SIZE; + + switch (cifb->cont) { + case RTV_MCH_HDR_CONT_FIRST: + case RTV_MCH_HDR_CONT_MED: +#ifdef _DEBUG_HEADER_DECODING + if (cifb->data_len < MAX_MCH_PAYLOAD_SIZE) + return CIFDEC_S__SHORT_PAYLOAD_SIZE; +#endif + cifb->ts_size = MAX_MCH_PAYLOAD_SIZE; + break; + case RTV_MCH_HDR_CONT_LAST: + cifb->ts_size = last_size; + break; + default: /* Alone */ + cifb->ts_size = (U8)cifb->data_len; + break; + } + + switch (cifb->id_flag) { + case RTV_MCH_HDR_ID_DMB: + case RTV_MCH_HDR_ID_DAB: + if (cifb->id_flag == RTV_MCH_HDR_ID_DMB) { + if (cifb->data_len != 188) + return CIFDEC_S__INVALID_SUBCH_SIZE; + } + else { + if (cifb->data_len > 6912/*1 CIF size*/) + return CIFDEC_S__INVALID_SUBCH_SIZE; + } + + array_idx = cifb->subch_id >> 5; /* Divide by 32 */ + bit_val = 1 << (cifb->subch_id & 31); + if (!(g_aAddedSubChIdBits[array_idx] & bit_val)) + /* Closed(or Not opened) or Changed ID */ + return CIFDEC_S__INVALID_SUBCH_ID; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + if (g_eSingleSvcFlagID != cifb->id_flag) + return CIFDEC_S__INVALID_SVC_TYPE; +#endif + break; + + case RTV_MCH_HDR_ID_FIC: +#ifdef _DEBUG_HEADER_DECODING + switch (cifb->data_len) { + case 384: case 96: case 128: case 192: + break; + default: + return CIFDEC_S__INVALID_FIC_SIZE; + } +#endif + break; + + default: /* RTV_MCH_HDR_ID_FIDC */ + break; + } + } else { /* Not sync byte */ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #if !defined(RTV_MSC_HDR_ENABLED) + if (g_eSingleSvcFlagID == RTV_MCH_HDR_ID_DMB) { + if (tsp[0] == 0x47) { + cifb->header_on = 0; + cifb->subch_id = g_nSingleSubchID; + cifb->ts_size = 188; + cifb->id_flag = RTV_MCH_HDR_ID_DMB; + cifb->ts_ptr -= RTV_MCH_HDR_SIZE; + return CIFDEC_S__OK; + } else { + CIF_DBGMSG1("[decode_headers] ERR tsp[%d]\n", tsp[0]); + } + } else + return CIFDEC_S__INVALID_SVC_TYPE; + #endif +#endif + /* tsp[2]: alone tsp && MSB of data_len. */ + if (tsp[2] == CIF_DISCARDED_TSP_MARK_1) + return CIFDEC_S__DISCARDED_TSP; + else + return CIFDEC_S__INVALID_HEADER_BYTE; + } + + return CIFDEC_S__OK; +} + +int rtvCIFDEC_Decode(struct RTV_CIF_DEC_INFO *ptDecInfo, + const U8 *pbTsBuf, UINT nTsLen) +{ + enum CIFDEC_STATUS_TYPE status; + struct CIFB_INFO *cifb; + struct CIFB_HEAD_INFO *tspq; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + ptDecInfo->subch_size[0] = 0; + ptDecInfo->subch_id[0] = CIF_INVALID_SUBCH_ID; /* Default invalid */ +#else + UINT i, q_idx; + for (i = 0; i < RTV_MAX_NUM_USE_SUBCHANNEL; i++) { + ptDecInfo->subch_size[i] = 0; + ptDecInfo->subch_id[i] = CIF_INVALID_SUBCH_ID; /* Default */ + } +#endif + + ptDecInfo->fic_size = 0; + + if (nTsLen == 0) { + CIF_DBGMSG0("[rtvCIFDEC_Decode] Sourct TS size is zero\n"); + return 0 ; + } + +#if 0 /* for debug */ + if (nTsLen % RTV_TSP_XFER_SIZE) { + CIF_DBGMSG1("[rtvCIFDEC_Decode] Not aligned: %u\n", nTsLen); + return; + } +#endif + + if (g_fCifInited == FALSE) { + CIF_DBGMSG0("[rtvCIFDEC_Decode] Not yet init\n"); + return 0; + } + + CIF_MUTEX_LOCK; + + do { + if (g_fForceDecodeStop == TRUE) + break; + +cifb_alloc_retry: + /* Get a current TSP header buffer to be decoded. */ + cifb = cifb_alloc_buffer(pbTsBuf + RTV_MCH_HDR_SIZE); + if (!cifb) { + /* Free the first entry. */ + if (cifdec_msc_tspq[0].cnt) /* Not empty? */ + cifb_queue_free(&cifdec_msc_tspq[0], cifdec_msc_tspq[0].ptFirst); + + CIF_DBGMSG0("No more cif buffer!\n"); + CIF_ERR_STAT_INC(CIFDEC_S__CIFB_ALLOC_ERR); + goto cifb_alloc_retry; + } + + status = decode_header(cifb, pbTsBuf); + if (status == CIFDEC_S__OK) { + switch (cifb->id_flag) { + case RTV_MCH_HDR_ID_DMB: + case RTV_MCH_HDR_ID_DAB: +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + cifb_enqueue(&cifdec_msc_tspq[0], cifb); +#else + q_idx = g_abOutDecBufIdx[cifb->subch_id]; + cifb_enqueue(&cifdec_msc_tspq[q_idx], cifb); +#endif + break; + + case RTV_MCH_HDR_ID_FIC: + cifb_enqueue(&cifdec_fic_tspq, cifb); + break; + + default: /* FIDC */ + CIF_DBGMSG1("Invalid ID flag(%d)\n", cifb->id_flag); + cifb_free_buffer(cifb); + break; + } + } + else { + cifb_free_buffer(cifb); + CIF_ERR_STAT_INC(status); + } + + pbTsBuf += RTV_TSP_XFER_SIZE; + nTsLen -= RTV_TSP_XFER_SIZE; + } while (nTsLen); + + if (cifdec_fic_tspq.cnt) /* Not empty? */ + proc_fic(ptDecInfo, &cifdec_fic_tspq); + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + if (cifdec_msc_tspq[0].cnt) { /* Not empty? */ + tspq = &cifdec_msc_tspq[0]; + cifb = cifb_peek_frist(tspq); + + if (cifb->id_flag == RTV_MCH_HDR_ID_DMB) /* or DAB+ */ + proc_msc_dmb_dabp(ptDecInfo, tspq); + else + proc_msc_dab(ptDecInfo, tspq); + } +#else + for (i = 0; i < RTV_MAX_NUM_USE_SUBCHANNEL; i++) { + if (cifdec_msc_tspq[i].cnt)) { /* Not empty? */ + tspq = &cifdec_msc_tspq[i]; + cifb = cifb_peek_frist(tspq); + if (cifb->id_flag == RTV_MCH_HDR_ID_DMB) + proc_msc_dmb_dabp(ptDecInfo, tspq); + else + proc_msc_dab(ptDecInfo, tspq); + } + } +#endif + + CIF_MUTEX_UNLOCK; + + return 2; +} + +/* nFicMscType: 0(FIC), 1(MSC) */ +UINT rtvCIFDEC_SetDiscardTS(int nFicMscType, U8 *pbTsBuf, UINT nTsLen) +{ + UINT i, nTsCnt; + enum RTV_MCH_HDR_ID_FLAG_T nIdFlag; + UINT nDiscardSize = 0; + + nTsCnt = nTsLen / RTV_TSP_XFER_SIZE; + + for (i = 0; i < nTsCnt; i++, pbTsBuf += RTV_TSP_XFER_SIZE) { + if (pbTsBuf[0] == RTV_MCH_HEADER_SYNC_BYTE) { /* NOT discarded byte */ + nIdFlag = pbTsBuf[1] >> 6; + + if (nFicMscType == 1) { + if ((nIdFlag == RTV_MCH_HDR_ID_DMB) + || (nIdFlag == RTV_MCH_HDR_ID_DAB)) { + /* sync byte => discarded byte */ + pbTsBuf[0] = CIF_DISCARDED_TSP_MARK_0; + pbTsBuf[2] = CIF_DISCARDED_TSP_MARK_1; + nDiscardSize += RTV_TSP_XFER_SIZE; + } + } else { + if (nIdFlag == RTV_MCH_HDR_ID_FIC) { + pbTsBuf[0] = CIF_DISCARDED_TSP_MARK_0; + pbTsBuf[2] = CIF_DISCARDED_TSP_MARK_1; + nDiscardSize += RTV_TSP_XFER_SIZE; + } + } + } + } + + return nDiscardSize; +} + +UINT rtvCIFDEC_GetDecBufIndex(UINT nSubChID) +{ + UINT nDecIdx; + + if (g_fCifInited == FALSE) { + CIF_DBGMSG0("[rtvCIFDEC_GetDecBufIndex] Not yet init\n"); + return RTV_CIFDEC_INVALID_BUF_IDX; + } + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + nDecIdx = 0; +#else + CIF_MUTEX_LOCK; /* To wait for add/delete operation. */ + nDecIdx = g_abOutDecBufIdx[nSubChID]; + CIF_MUTEX_UNLOCK; +#endif + + return nDecIdx; +} + +/* +This function delete a sub channel ID from the CIF decoder. +This function should called after Sub Channel Close. */ +void rtvCIFDEC_DeleteSubChannelID(UINT nSubChID) +{ + U8 nIdx; + UINT nArrayIdx = nSubChID >> 5; /* Divide by 32 */ + U32 dwBitVal = 1 << (nSubChID & 31); /* Modular and Shift */ + + if (g_fCifInited == FALSE) { + CIF_DBGMSG0("[rtvCIFDEC_DeleteSubChannelID] Not yet init\n"); + return; + } + + CIF_MUTEX_LOCK; + + if (g_aAddedSubChIdBits[nArrayIdx] & dwBitVal) { + CIF_KFILE_CLOSE(nSubChID); + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + nIdx = 0; + cifb_queue_release_all(&cifdec_msc_tspq[0]); + g_nSingleSubchID = CIF_INVALID_SUBCH_ID; +#else + nIdx = g_abOutDecBufIdx[nSubChID]; + cifb_queue_release_all(&cifdec_msc_tspq[nIdx]); + g_abOutDecBufIdx[nSubChID] = RTV_CIFDEC_INVALID_BUF_IDX; +#endif + g_nOutDecBufIdxBits &= ~(1 << nIdx); + g_aAddedSubChIdBits[nArrayIdx] &= ~dwBitVal; /* after kfile */ + } + + CIF_MUTEX_UNLOCK; +} + +/* +This function add a sub channel ID to the CIF decoder to verify CIF header. +This function should called before Sub Channel Open. */ +BOOL rtvCIFDEC_AddSubChannelID(UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType) +{ + BOOL fRet = FALSE; + U8 nIdx; + UINT nArrayIdx = nSubChID >> 5; /* Divide by 32 */ + U32 dwBitVal = 1 << (nSubChID & 31); /* Modular and Shift */ + + if (g_fCifInited == FALSE) { + CIF_DBGMSG0("[rtvCIFDEC_AddSubChannelID] Not yet init\n"); + return FALSE; + } + + CIF_MUTEX_LOCK; + + /* Check if already registerd ? */ + if ((g_aAddedSubChIdBits[nArrayIdx] & dwBitVal) == 0) { + g_aAddedSubChIdBits[nArrayIdx] |= dwBitVal; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + nIdx = 0; + g_nSingleSubchID = nSubChID; +#else + for (nIdx = 0; nIdx < RTV_MAX_NUM_USE_SUBCHANNEL; nIdx++) { +#endif + if ((g_nOutDecBufIdxBits & (1<= 2) + break; + #endif + } +#if (RTV_MAX_NUM_USE_SUBCHANNEL != 1) + } +#endif + } + + CIF_MUTEX_UNLOCK; + + return fRet; +} + +/* This function deinitialize the CIF decoder.*/ +void rtvCIFDEC_Deinit(void) +{ + if (g_fCifInited == FALSE) + return; + + g_fCifInited = FALSE; + g_fForceDecodeStop = TRUE; + + CIF_DBGMSG0("[rtvCIFDEC_Deinit] CIF decode Exit\n"); + + CIF_MUTEX_LOCK; + + CIF_ERR_STAT_SHOW; + + CIF_KFILE_CLOSE(0xFFFF); + + CIF_MUTEX_UNLOCK; + + CIF_MUTEX_DEINIT; +} + + +/* This function initialize the CIF decoder. */ +void rtvCIFDEC_Init(void) +{ + UINT i; + + if (g_fCifInited == TRUE) { + CIF_DBGMSG0("[rtvCIFDEC_Init] Already inited!\n"); + return; + } + + g_nCifBufPoolFreeCnt = NUM_CIF_BUF_POOL; + for (i = 0; i < NUM_CIF_BUF_POOL; i++) + g_aCifBufPoolList[i] = &cif_buf_pool[(NUM_CIF_BUF_POOL-1) - i]; + + CIF_ERR_STAT_RST_ALL; + + g_nOutDecBufIdxBits = 0x00; + + g_aAddedSubChIdBits[0] = 0; + g_aAddedSubChIdBits[1] = 0; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + g_nSingleSubchID = CIF_INVALID_SUBCH_ID; +#endif +#ifdef _MSC_KERNEL_FILE_DUMP_ENABLE + memset(g_ptDecMscFilp, 0, sizeof(g_ptDecMscFilp)); + CIF_MSC_KFILE_WRITE_DIS; +#endif + +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + memset(g_abOutDecBufIdx, RTV_CIFDEC_INVALID_BUF_IDX, + sizeof(g_abOutDecBufIdx)); +#endif + + CIF_MUTEX_INIT; + + cifb_queue_init(&cifdec_fic_tspq); + + g_fCifInited = TRUE; + g_fForceDecodeStop = FALSE; +} + + diff --git a/drivers/media/tdmb/mtv319/mtv319_cifdec.h b/drivers/media/tdmb/mtv319/mtv319_cifdec.h new file mode 100644 index 000000000000..810bcfceb124 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_cifdec.h @@ -0,0 +1,74 @@ +/* +* +* File name: mtv319_cifdec.h +* +* Description : MTV319 CIF decoder header file. +* +* Copyright (C) (2014, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +/****************************************************************************** +* REVISION HISTORY +* +* DATE NAME REMARKS +* ---------- ------------- ------------------------------------------------ +* 07/12/2012 Ko, Kevin Created. +******************************************************************************/ + +#ifndef __MTV319_CIFDEC_H__ +#define __MTV319_CIFDEC_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "mtv319.h" + +#define RTV_CIFDEC_INVALID_BUF_IDX 0xFF + +struct RTV_CIF_DEC_INFO { + unsigned int fic_size; /* Result size. */ + + /* Source buffer address to be decoded. (Input/Output) */ + unsigned char *fic_buf_ptr; + + /* Decoded MSC sub channel size (Output) */ + unsigned int subch_size[RTV_MAX_NUM_USE_SUBCHANNEL]; + + /* Decoded MSC sub channel ID.(Output) */ + unsigned int subch_id[RTV_MAX_NUM_USE_SUBCHANNEL]; + + /* Source MSC buffer address to be decoded. (Input/Output) */ + unsigned char *subch_buf_ptr[RTV_MAX_NUM_USE_SUBCHANNEL]; + + /* Source MSC buffer size. (Input) */ + unsigned int subch_buf_size[RTV_MAX_NUM_USE_SUBCHANNEL]; +}; + +int rtvCIFDEC_Decode(struct RTV_CIF_DEC_INFO *ptDecInfo, + const U8 *pbTsBuf, UINT nTsLen); +UINT rtvCIFDEC_SetDiscardTS(int nFicMscType, U8 *pbTsBuf, UINT nTsLen); +UINT rtvCIFDEC_GetDecBufIndex(UINT nSubChID); +void rtvCIFDEC_DeleteSubChannelID(UINT nSubChID); +BOOL rtvCIFDEC_AddSubChannelID(UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType); +void rtvCIFDEC_Deinit(void); +void rtvCIFDEC_Init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_CIFDEC_H__ */ + + diff --git a/drivers/media/tdmb/mtv319/mtv319_ficdec.c b/drivers/media/tdmb/mtv319/mtv319_ficdec.c new file mode 100644 index 000000000000..4cc4a1660613 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_ficdec.c @@ -0,0 +1,2691 @@ +/* +* +* File name: mtv319_ficdec.c +* +* Description : RAONTECH FIC Decoder driver. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include +#include "mtv319_ficdec_internal.h" +#include "mtv319_internal.h" + +/*****************************/ +/* FIC Information Variable */ +/*****************************/ +static struct FIG_DATA fig_data; +static const U8 FIC_BIT_MASK[8] = {0x0, 0x80, 0xC0, 0xE0, 0xFF, + 0xF8, 0xFC, 0xFE}; + +static U8 Ensemble_ECC = 0xFF; + + +/**********************************/ +/* FIC information get function */ +/**********************************/ +static S32 Get_Bytes(U8 cnt, void *Res) +{ + S32 i; + + for (i = 0; i < cnt; i++) { + *((U8 *) Res+i) = *(fig_data.data+fig_data.byte_cnt); + fig_data.byte_cnt++; + } + + return RTV_OK; +} + +static S32 Get_Bits(U8 cnt, void *Res) +{ + *(U8 *)Res = (U8) (*(fig_data.data+fig_data.byte_cnt) & + (FIC_BIT_MASK[cnt] >> fig_data.bit_cnt)); + + *(U8 *)Res = (*(U8 *)Res) >> (8-cnt-fig_data.bit_cnt); + fig_data.bit_cnt += cnt; + if (fig_data.bit_cnt == 8) { + fig_data.byte_cnt++; + fig_data.bit_cnt = 0; + } + return RTV_OK; +} + +void *Get_FIG0_EXT[] = { + (void *) Get_FIG0_EXT0, (void *) Get_FIG0_EXT1, + (void *) Get_FIG0_EXT2, (void *) Get_FIG0_EXT3, + (void *) Get_FIG0_EXT4, (void *) Get_FIG0_EXT5, + (void *) Get_FIG0_EXT6, (void *) Get_FIG0_EXT7, + (void *) Get_FIG0_EXT8, (void *) Get_FIG0_EXT9, + (void *) Get_FIG0_EXT10, (void *) Get_FIG0_EXT11, + (void *) Get_FIG0_EXT12, (void *) Get_FIG0_EXT13, + (void *) Get_FIG0_EXT14, (void *) Get_FIG0_EXT15, + (void *) Get_FIG0_EXT16, (void *) Get_FIG0_EXT17, + (void *) Get_FIG0_EXT18, (void *) Get_FIG0_EXT19, + (void *) Get_FIG0_EXT20, (void *) Get_FIG0_EXT21, + (void *) Get_FIG0_EXT22, (void *) Get_FIG0_EXT23, + (void *) Get_FIG0_EXT24, (void *) Get_FIG0_EXT25, + (void *) Get_FIG0_EXT26, (void *) Get_FIG0_EXT27, + (void *) Get_FIG0_EXT28, (void *) Get_FIG0_EXT29, + (void *) Get_FIG0_EXT30, (void *) Get_FIG0_EXT31, + 0 +}; + +void *Get_FIG1_EXT[] = { + (void *) Get_FIG1_EXT0, (void *) Get_FIG1_EXT1, + (void *) Get_FIG1_EXT2, (void *) Get_FIG1_EXT3, + (void *) Get_FIG1_EXT4, (void *) Get_FIG1_EXT5, + (void *) Get_FIG1_EXT6, (void *) Get_FIG1_EXT7, + 0 +}; + +void *Get_FIG2_EXT[] = { + (void *) Get_FIG2_EXT0, (void *) Get_FIG2_EXT1, + (void *) Get_FIG2_EXT2, (void *) Get_FIG2_EXT3, + (void *) Get_FIG2_EXT4, (void *) Get_FIG2_EXT5, + (void *) Get_FIG2_EXT6, (void *) Get_FIG2_EXT7, + 0 +}; + +void *Get_FIG5_EXT[] = { + (void *) Get_FIG5_EXT0, (void *) Get_FIG5_EXT1, (void *) Get_FIG5_EXT2, + 0 +}; + +void *FIG_PARSER[] = { + (void *) MCI_SI_DEC, + (void *) SI_LABEL_DEC1, + (void *) SI_LABEL_DEC2, + (void *) RESERVED1, + (void *) RESERVED2, + (void *) FIDC_DEC, + (void *) CA_DEC, + (void *) RESERVED3, + 0 +}; + +S32 Get_FIG_Init(U8 *data) +{ + fig_data.data = data; + fig_data.byte_cnt = 0; + fig_data.bit_cnt = 0; + return RTV_OK; +} + +S32 Get_FIG_Header(struct FIG_DATA *fig_data) +{ + + Get_Bytes(1, &(fig_data->length)); + if (fig_data->length == PN_FIB_END_MARKER) + return PN_FIB_END_MARKER; + + fig_data->type = (fig_data->length) >> 5; + fig_data->length = (fig_data->length) & 0x1f; + return RTV_OK; +} + +S32 FIB_INIT_DEC(U8 *fib_ptr) +{ + U8 fib_cnt = 0; + U8 fic_cmd = 1; + + while (fib_cnt < 30) { + Get_FIG_Init(fib_ptr+fib_cnt); + + if (Get_FIG_Header(&fig_data) == PN_FIB_END_MARKER) + return RTV_OK; + if (fig_data.length == 0) + return RTV_FAIL; + + ((S32 (*) (U8)) FIG_PARSER[fig_data.type]) (fic_cmd); + + fib_cnt += (fig_data.length+1); + } + + return RTV_OK; +} + +S32 MCI_SI_DEC(U8 fic_cmd) +{ + U8 C_N, OE, P_D, EXT; + + Get_Bits(1, &C_N); + Get_Bits(1, &OE); + Get_Bits(1, &P_D); + Get_Bits(5, &EXT); + + ((S32 (*) (U8, U8, U8)) Get_FIG0_EXT[EXT]) (fic_cmd, P_D, C_N); + return RTV_OK; +} + +S32 SI_LABEL_DEC1(U8 fic_cmd) +{ + U8 Charset, OE, EXT; + + Get_Bits(4, &Charset); + Get_Bits(1, &OE); + Get_Bits(3, &EXT); + + ((S32 (*) (U8, U8)) Get_FIG1_EXT[EXT]) (fic_cmd, Charset); + return RTV_OK; +} + +S32 SI_LABEL_DEC2(U8 fic_cmd) +{ + U8 Toggle_Flag, Seg_Index, OE, EXT; + + Get_Bits(1, &Toggle_Flag); + Get_Bits(3, &Seg_Index); + Get_Bits(1, &OE); + Get_Bits(3, &EXT); + + ((S32 (*) (U8, U8)) Get_FIG2_EXT[EXT]) (fic_cmd, Seg_Index); + return RTV_OK; +} + +S32 RESERVED1(U8 fic_cmd) +{ + return RTV_OK; +} + +S32 RESERVED2(U8 fic_cmd) +{ + return RTV_OK; +} + +S32 FIDC_DEC(U8 fic_cmd) +{ + U8 D1, D2, TCid, EXT; + + Get_Bits(1, &D1); + Get_Bits(1, &D2); + Get_Bits(3, &TCid); + Get_Bits(3, &EXT); + + ((S32 (*) (U8, U8, U8, U8)) Get_FIG5_EXT[EXT]) (D1, D2, fic_cmd, TCid); + return RTV_OK; +} + +S32 CA_DEC(U8 fic_cmd) +{ + U8 F_L, EXT; + + Get_Bits(2, &F_L); + Get_Bits(6, &EXT); + return RTV_OK; +} + +S32 RESERVED3(U8 fic_cmd) +{ + return RTV_OK; +} + +/* +* FIG TYPE 0 Extension Function +* Ensemble Information */ +S32 Get_FIG0_EXT0(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + + struct FIG_TYPE0_Ext0 type0_ext0; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext0.Eid = (temp1 << 8) | temp2; + + Get_Bits(2, &type0_ext0.Change_flag); + Get_Bits(1, &type0_ext0.AI_flag); + + Get_Bits(5, &type0_ext0.CIF_Count0); + Get_Bytes(1, &type0_ext0.CIF_Count1); + + if (type0_ext0.Change_flag != 0) + Get_Bytes(1, &type0_ext0.Occurence_Change); + + if (fic_cmd) { + ENS_DESC.id = type0_ext0.Eid; + ENS_DESC.change_flag = type0_ext0.Change_flag; + ENS_DESC.Alarm_flag = type0_ext0.AI_flag; + } + } + + return RTV_OK; +} + +/* Basic sub-channel organization */ +S32 Get_FIG0_EXT1(U8 fic_cmd, U8 P_D, U8 C_N) +{ +U8 temp1, temp2, cnt; +S32 bit_rate, sub_ch_size, p_l; + +struct FIG_TYPE0_Ext1 type0_ext1; + +while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(6, &type0_ext1.SubChid); + Get_Bits(2, &temp1); + Get_Bytes(1, &temp2); + type0_ext1.StartAdd = (temp1 << 8) | temp2; + + Get_Bits(1, &type0_ext1.S_L_form); + if (type0_ext1.S_L_form) { + Get_Bits(3, &type0_ext1.Option); + Get_Bits(2, &type0_ext1.Protection_Level); + Get_Bits(2, &temp1); + Get_Bytes(1, &temp2); + type0_ext1.Sub_ch_size = (temp1 << 8) | temp2; + type0_ext1.Size_Protection = (type0_ext1.Option << 12) + | (type0_ext1.Protection_Level << 10) + | type0_ext1.Sub_ch_size; + } else { + Get_Bits(1, &type0_ext1.Table_sw); + Get_Bits(6, &type0_ext1.Table_index); + type0_ext1.Size_Protection = (type0_ext1.Table_sw << 6) + | type0_ext1.Table_index; + } + + if (fic_cmd) { + if (C_N) { + GET_SUBCH_INFO(&type0_ext1, &bit_rate, + &sub_ch_size, &p_l); + /*Old SId & New SId matching */ + for (cnt = 0 + ; cnt < NEXT_ENS_DESC.svr_comp_num + ; cnt++){ + + if (NEXT_ENS_DESC.svr_comp[cnt].SubChid + == type0_ext1.SubChid) { + + NEXT_ENS_DESC.svr_comp[cnt].START_Addr + = type0_ext1.StartAdd; + NEXT_ENS_DESC.svr_comp[cnt].SUB_CH_Size + = sub_ch_size; + NEXT_ENS_DESC.svr_comp[cnt].P_L + = p_l; + NEXT_ENS_DESC.svr_comp[cnt].BIT_RATE + = bit_rate; + } + } + } else { + GET_SUBCH_INFO(&type0_ext1, + &bit_rate, + &sub_ch_size, &p_l); + + for (cnt = 0 + ; cnt < ENS_DESC.svr_comp_num + ; cnt++) { + /*Old SId & New SId matching */ + if (ENS_DESC.svr_comp[cnt].SubChid + == type0_ext1.SubChid) { + ENS_DESC.svr_comp[cnt].START_Addr + = type0_ext1.StartAdd; + ENS_DESC.svr_comp[cnt].SUB_CH_Size + = sub_ch_size; + ENS_DESC.svr_comp[cnt].P_L + = p_l; + ENS_DESC.svr_comp[cnt].BIT_RATE + = bit_rate; + } + } + } + } +} + +return RTV_OK; +} + +static INLINE void update_next_ens_desc_type0_ext2( + struct ENSEMBLE_DESC *next, + struct FIG_TYPE0_Ext2 *type0_ext2, + U8 P_D) +{ + UINT l = 0; + + if (P_D) { + next->svr_desc[next->svr_num].P_D = 1; + next->svr_desc[next->svr_num].ECC + = type0_ext2->ECC; + } else + next->svr_desc[next->svr_num].P_D = 0; + + next->svr_desc[next->svr_num].Country_id = type0_ext2->Country_id; + next->svr_desc[next->svr_num].Service_ref = type0_ext2->Service_ref; + next->svr_desc[next->svr_num].Sid = type0_ext2->Sid; + + next->svr_desc[next->svr_num].Local_flag = type0_ext2->Local_flag; + next->svr_desc[next->svr_num].CAID = type0_ext2->CAID; + next->svr_desc[next->svr_num].Num_ser_comp = type0_ext2->Num_ser_comp; + + for (l = 0; l < type0_ext2->Num_ser_comp; l++) { + + next->svr_desc[next->svr_num].ser_comp_num[l] + = next->svr_comp_num; + next->svr_comp[next->svr_comp_num].TMID + = type0_ext2->svr_comp_des[l].TMID; + /* Transport Mechanism Identifier. */ + switch (type0_ext2->svr_comp_des[l].TMID) { + /* MSC stream Audio mode. */ + case MSC_STREAM_AUDIO: + next->svr_comp[next->svr_comp_num].Sid + = type0_ext2->Sid; + next->svr_comp[next->svr_comp_num].ASCTy + = type0_ext2->svr_comp_des[l].ASCTy; + next->svr_comp[next->svr_comp_num].SubChid + = type0_ext2->svr_comp_des[l].SubChid; + next->svr_comp[next->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + next->svr_comp[next->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + /* MSC stream data mode. */ + case MSC_STREAM_DATA: + next->svr_comp[next->svr_comp_num].Sid + = type0_ext2->Sid; + next->svr_comp[next->svr_comp_num].DSCTy + = type0_ext2->svr_comp_des[l].DSCTy; + next->svr_comp[next->svr_comp_num].SubChid + = type0_ext2->svr_comp_des[l].SubChid; + next->svr_comp[next->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + next->svr_comp[next->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + /* FIDC mode. */ + case FIDC: + next->svr_comp[next->svr_comp_num].Sid + = type0_ext2->Sid; + next->svr_comp[next->svr_comp_num].DSCTy + = type0_ext2->svr_comp_des[l].DSCTy; + next->svr_comp[next->svr_comp_num].FIDCid + = type0_ext2->svr_comp_des[l].FIDCid; + next->svr_comp[next->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + next->svr_comp[next->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + /* MSC Packet data mode. */ + case MSC_PACKET_DATA: + next->svr_comp[next->svr_comp_num].Sid + = type0_ext2->Sid; + next->svr_comp[next->svr_comp_num].SCid + = type0_ext2->svr_comp_des[l].SCid; + next->svr_comp[next->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + next->svr_comp[next->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + } + next->svr_comp_num++; + } + next->svr_num++; + +} + + +static INLINE void update_current_ens_desc_type0_ext2( + struct ENSEMBLE_DESC *cur, + struct FIG_TYPE0_Ext2 *type0_ext2, + U8 P_D) +{ + UINT l = 0; + + if (P_D) { + cur->svr_desc[cur->svr_num].P_D = 1; + cur->svr_desc[cur->svr_num].ECC = type0_ext2->ECC; + } else + cur->svr_desc[cur->svr_num].P_D = 0; + + cur->svr_desc[cur->svr_num].Country_id = type0_ext2->Country_id; + cur->svr_desc[cur->svr_num].Service_ref = type0_ext2->Service_ref; + cur->svr_desc[cur->svr_num].Sid = type0_ext2->Sid; + + cur->svr_desc[cur->svr_num].Local_flag = type0_ext2->Local_flag; + cur->svr_desc[cur->svr_num].CAID = type0_ext2->CAID; + cur->svr_desc[cur->svr_num].Num_ser_comp = type0_ext2->Num_ser_comp; + + for (l = 0; l < type0_ext2->Num_ser_comp; l++) { + cur->svr_desc[cur->svr_num].ser_comp_num[l] = cur->svr_comp_num; + cur->svr_comp[cur->svr_comp_num].TMID + = type0_ext2->svr_comp_des[l].TMID; + + switch (type0_ext2->svr_comp_des[l].TMID) { + case MSC_STREAM_AUDIO: + /* MSC stream Audio mode. */ + cur->svr_comp[cur->svr_comp_num].Sid + = type0_ext2->Sid; + cur->svr_comp[cur->svr_comp_num].ASCTy + = type0_ext2->svr_comp_des[l].ASCTy; + cur->svr_comp[cur->svr_comp_num].SubChid + = type0_ext2->svr_comp_des[l].SubChid; + cur->svr_comp[cur->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S ; + cur->svr_comp[cur->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + case MSC_STREAM_DATA: + /* MSC stream data mode.*/ + cur->svr_comp[cur->svr_comp_num].Sid + = type0_ext2->Sid; + cur->svr_comp[cur->svr_comp_num].DSCTy + = type0_ext2->svr_comp_des[l].DSCTy; + cur->svr_comp[cur->svr_comp_num].SubChid + = type0_ext2->svr_comp_des[l].SubChid; + cur->svr_comp[cur->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + cur->svr_comp[cur->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + case FIDC: + /* FIDC mode. */ + #if 0 + /* EWS Data have no Label in Korea */ + if (type0_ext2->svr_comp_des[l].DSCTy == 2) { + cur->svr_comp_num--; + cur->svr_num--; + } + #endif + cur->svr_comp[cur->svr_comp_num].Sid + = type0_ext2->Sid; + cur->svr_comp[cur->svr_comp_num].DSCTy + = type0_ext2->svr_comp_des[l].DSCTy; + cur->svr_comp[cur->svr_comp_num].FIDCid + = type0_ext2->svr_comp_des[l].FIDCid; + cur->svr_comp[cur->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + cur->svr_comp[cur->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + case MSC_PACKET_DATA: + /* MSC Packet data mode.*/ + cur->svr_comp[cur->svr_comp_num].Sid + = type0_ext2->Sid; + cur->svr_comp[cur->svr_comp_num].SCid + = type0_ext2->svr_comp_des[l].SCid; + cur->svr_comp[cur->svr_comp_num].P_S + = type0_ext2->svr_comp_des[l].P_S; + cur->svr_comp[cur->svr_comp_num].CA_flag + = type0_ext2->svr_comp_des[l].CA_flag; + break; + } + cur->svr_comp_num++; + } + cur->svr_num++; +} + + + + + +/* Basic service and service component definition */ +S32 Get_FIG0_EXT2(U8 fic_cmd, U8 P_D, U8 C_N) +{ +U8 temp1, temp2, temp3; +UINT cnt, update_flag = 0; +struct FIG_TYPE0_Ext2 type0_ext2; + +memset(&type0_ext2, 0xFF, sizeof(struct FIG_TYPE0_Ext2)); + +while (fig_data.byte_cnt < fig_data.length) { + if (P_D) { + Get_Bytes(1, &type0_ext2.ECC); + Get_Bits(4, &type0_ext2.Country_id); + Get_Bits(4, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + type0_ext2.Service_ref = (temp1 << 16) + | (temp2 << 8) | temp3; + type0_ext2.Sid = (type0_ext2.ECC << 24) + | (type0_ext2.Country_id << 20) + | type0_ext2.Service_ref; + } else { + Get_Bits(4, &type0_ext2.Country_id); + Get_Bits(4, &temp1); + Get_Bytes(1, &temp2); + type0_ext2.Service_ref = (temp1 << 8) | temp2; + type0_ext2.Sid = (type0_ext2.Country_id << 12) + | type0_ext2.Service_ref; + } + + Get_Bits(1, &type0_ext2.Local_flag); + Get_Bits(3, &type0_ext2.CAID); + Get_Bits(4, &type0_ext2.Num_ser_comp); + + for (cnt = 0; cnt < type0_ext2.Num_ser_comp; cnt++) { + Get_Bits(2, &type0_ext2.svr_comp_des[cnt].TMID); + switch (type0_ext2.svr_comp_des[cnt].TMID) { + case MSC_STREAM_AUDIO: + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].ASCTy); + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].SubChid); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].P_S); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].CA_flag); + break; + case MSC_STREAM_DATA: + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].DSCTy); + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].SubChid); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].P_S); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].CA_flag); + break; + case FIDC: + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].DSCTy); + Get_Bits(6, + &type0_ext2.svr_comp_des[cnt].FIDCid); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].P_S); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].CA_flag); + break; + case MSC_PACKET_DATA: + Get_Bits(6, &temp1); + Get_Bits(6, &temp2); + type0_ext2.svr_comp_des[cnt].SCid = (temp1 << 6) + |temp2; + Get_Bits(1, &type0_ext2.svr_comp_des[cnt].P_S); + Get_Bits(1, + &type0_ext2.svr_comp_des[cnt].CA_flag); + break; + } + } + + if (fic_cmd) { + if (C_N) { + update_flag = 1; + for (cnt = 0 + ; cnt < NEXT_ENS_DESC.svr_num + ; cnt++) { + /*Old SId & New SId matching */ + if (NEXT_ENS_DESC.svr_desc[cnt].Sid + == type0_ext2.Sid) { + update_flag = 0; + break; + } + } + + if (update_flag) { + update_next_ens_desc_type0_ext2(&NEXT_ENS_DESC, + &type0_ext2, P_D); + } + } else { + update_flag = 1; + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + /*Old SId & New SId matching */ + if (ENS_DESC.svr_desc[cnt].Sid + == type0_ext2.Sid) { + update_flag = 0; + break; + } + } + + if (update_flag) { + update_current_ens_desc_type0_ext2(&ENS_DESC, + &type0_ext2, P_D); + } + } + } +} + +return RTV_OK; +} + + +static INLINE void update_ens_desc_type0_ext3( + struct ENSEMBLE_DESC *next, + struct ENSEMBLE_DESC *cur, + struct FIG_TYPE0_Ext3 *type0_ext3, + U8 C_N) +{ + UINT k = 0; + + if (C_N) { + for (k = 0; k < next->svr_comp_num; k++) { + if ((next->svr_comp[k].TMID == MSC_PACKET_DATA) && + (next->svr_comp[k].SCid == type0_ext3->SCid)) { + next->svr_comp[k].SubChid + = type0_ext3->SubChid; + next->svr_comp[k].Packet_add + = type0_ext3->Packet_add; + next->svr_comp[k].DSCTy + = type0_ext3->DSCTy; + next->svr_comp[k].DG_flag + = type0_ext3->DG_flag; + + if (type0_ext3->CA_Org_flag) + next->svr_comp[k].CA_Org + = type0_ext3->CA_Org; + } + } + } else { + for (k = 0; k < cur->svr_comp_num; k++) { + if ((cur->svr_comp[k].TMID == MSC_PACKET_DATA) && + (cur->svr_comp[k].SCid == type0_ext3->SCid)) { + cur->svr_comp[k].SubChid + = type0_ext3->SubChid; + cur->svr_comp[k].Packet_add + = type0_ext3->Packet_add; + + cur->svr_comp[k].DSCTy + = type0_ext3->DSCTy; + cur->svr_comp[k].DG_flag + = type0_ext3->DG_flag; + + if (type0_ext3->CA_Org_flag) + cur->svr_comp[k].CA_Org + = type0_ext3->CA_Org; + } + } + } +} + +/* Service component in packet mode with or without Conditional Access */ +S32 Get_FIG0_EXT3(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + + struct FIG_TYPE0_Ext3 type0_ext3; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bits(4, &temp2); + type0_ext3.SCid = (temp1 << 4) | temp2; + + Get_Bits(3, &temp1); + Get_Bits(1, &type0_ext3.CA_Org_flag); + Get_Bits(1, &type0_ext3.DG_flag); + Get_Bits(1, &temp2); + Get_Bits(6, &type0_ext3.DSCTy); + Get_Bits(6, &type0_ext3.SubChid); + + Get_Bits(2, &temp1); + Get_Bytes(1, &temp2); + type0_ext3.Packet_add = (temp1 << 8) | temp2; + + if (type0_ext3.CA_Org_flag) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext3.CA_Org = (temp1 << 8) | temp2; + } + + if (fic_cmd) { + update_ens_desc_type0_ext3(&NEXT_ENS_DESC, + &ENS_DESC, &type0_ext3, + C_N); + } + } + + return RTV_OK; +} + + +static INLINE void update_ens_desc_type0_ext4( + struct ENSEMBLE_DESC *next, + struct ENSEMBLE_DESC *cur, + struct FIG_TYPE0_Ext4 *type0_ext4, + U8 C_N) +{ + UINT k = 0; + + if (C_N) { + for (k = 0; k < next->svr_comp_num; k++) { + if (type0_ext4->M_F) { + if ((next->svr_comp[k].FIDCid + == type0_ext4->FIDCid)) + next->svr_comp[k].CA_Org + = type0_ext4->CA_Org; + } else { + if ((next->svr_comp[k].SubChid + == type0_ext4->SubChid)) + next->svr_comp[k].CA_Org + = type0_ext4->CA_Org; + } + } + } else { + for (k = 0; k < cur->svr_comp_num; k++) { + if (type0_ext4->M_F) { + if ((cur->svr_comp[k].FIDCid + == type0_ext4->FIDCid)) + cur->svr_comp[k].CA_Org + = type0_ext4->CA_Org; + } else { + if ((cur->svr_comp[k].SubChid + == type0_ext4->SubChid)) + cur->svr_comp[k].CA_Org + = type0_ext4->CA_Org; + } + } + } + +} + + +/* Service component with Conditional Access in stream mode or FIC */ +S32 Get_FIG0_EXT4(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + + struct FIG_TYPE0_Ext4 type0_ext4; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &temp1); + Get_Bits(1, &type0_ext4.M_F); + + if (type0_ext4.M_F) + Get_Bits(6, &type0_ext4.FIDCid); + else + Get_Bits(6, &type0_ext4.SubChid); + + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext4.CA_Org = (temp1 << 8) | temp2; + + if (fic_cmd) { + update_ens_desc_type0_ext4(&NEXT_ENS_DESC, + &ENS_DESC, + &type0_ext4, + C_N); + } + } + + return RTV_OK; +} + +static INLINE void update_current_ens_desc_type0_ext5( + struct ENSEMBLE_DESC *cur, + struct FIG_TYPE0_Ext5 *type0_ext5) +{ + UINT k; + + for (k = 0; k < cur->svr_comp_num; k++) { + if (type0_ext5->L_S_flag) { + if (cur->svr_comp[k].SCid == type0_ext5->SCid) + cur->svr_comp[k].language + = type0_ext5->Language; + } else { + if (type0_ext5->MSC_FIC_flag) { + if (cur->svr_comp[k].FIDCid + == type0_ext5->FIDCid) + cur->svr_comp[k].language + = type0_ext5->Language; + } else { + if (cur->svr_comp[k].SubChid + == type0_ext5->SubChid) + cur->svr_comp[k].language + = type0_ext5->Language; + } + } + } +} + +/* Service Component Language */ +S32 Get_FIG0_EXT5(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3; + + struct FIG_TYPE0_Ext5 type0_ext5; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &type0_ext5.L_S_flag); + if (type0_ext5.L_S_flag) { + Get_Bits(3, &temp1); + Get_Bits(4, &temp2); + Get_Bytes(1, &temp3); + type0_ext5.SCid = (temp2 << 8) | temp3; + } else { + Get_Bits(1, &type0_ext5.MSC_FIC_flag); + if (type0_ext5.MSC_FIC_flag) + Get_Bits(6, &type0_ext5.FIDCid); + else + Get_Bits(6, &type0_ext5.SubChid); + + } + Get_Bytes(1, &type0_ext5.Language); + + if (fic_cmd) { + update_current_ens_desc_type0_ext5(&ENS_DESC, + &type0_ext5); + } + } + + return RTV_OK; +} + +/* Service Linking Information */ +S32 Get_FIG0_EXT6(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3, temp4; + U8 k; + + struct FIG_TYPE0_Ext6 type0_ext6; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &type0_ext6.id_list_flag); + Get_Bits(1, &type0_ext6.LA); + Get_Bits(1, &type0_ext6.S_H); + Get_Bits(1, &type0_ext6.ILS); + Get_Bits(4, &temp1); + Get_Bytes(1, &temp2); + type0_ext6.LSN = (temp1 << 8) | temp2; + + if (type0_ext6.id_list_flag) { + if (P_D) { + Get_Bits(4, &temp1); + Get_Bits(4, &type0_ext6.Num_ids); + + for (k = 0; k < type0_ext6.Num_ids; k++) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + type0_ext6.Sid[k] = (temp1 << 24) + | (temp2 << 16) | (temp3 << 8) + | temp4; + } + } else { + Get_Bits(1, &temp1); + Get_Bits(2, &type0_ext6.idLQ); + Get_Bits(1, &type0_ext6.Shd); + Get_Bits(4, &type0_ext6.Num_ids); + + for (k = 0; k < type0_ext6.Num_ids; k++) { + if (type0_ext6.ILS) + Get_Bytes(1, + &type0_ext6.ECC[k]); + + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext6.id[k] = (temp1 << 8) | temp2; + } + } + } + + if (fic_cmd) { + /* Not yet implementation + * + * */ + } + } + + return RTV_OK; +} + +S32 Get_FIG0_EXT7(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} + + +static INLINE void update_ens_desc_type0_ext8( + struct ENSEMBLE_DESC *next, + struct ENSEMBLE_DESC *cur, + struct FIG_TYPE0_Ext8 *type0_ext8, + U8 C_N) +{ +UINT k; + +if (C_N) { + for (k = 0; k < next->svr_comp_num; k++) { + if (type0_ext8->L_S_flag) { + if (next->svr_comp[k].SCid + == type0_ext8->SCid) { + if (next->svr_comp[k].Sid + == type0_ext8->Sid) + next->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } else { + if (type0_ext8->MSC_FIC_flag) { + if (next->svr_comp[k].FIDCid + == type0_ext8->FIDCid) { + if (next->svr_comp[k].Sid + == type0_ext8->Sid) + next->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } else { + if (next->svr_comp[k].SubChid + == type0_ext8->SubChid) { + if (next->svr_comp[k].Sid + == type0_ext8->Sid) + next->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } + } + } +} else { + for (k = 0; k < cur->svr_comp_num; k++) { + if (type0_ext8->L_S_flag) { + if (cur->svr_comp[k].SCid + == type0_ext8->SCid) { + if (cur->svr_comp[k].Sid + == type0_ext8->Sid) + cur->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } else { + if (type0_ext8->MSC_FIC_flag) { + if (cur->svr_comp[k].FIDCid + == type0_ext8->FIDCid) { + if (cur->svr_comp[k].Sid + == type0_ext8->Sid) + cur->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } else { + if (cur->svr_comp[k].SubChid + == type0_ext8->SubChid) { + if (cur->svr_comp[k].Sid + == type0_ext8->Sid) + cur->svr_comp[k].SCidS + = type0_ext8->SCidS; + } + } + } + } +} + +} + + + +/* Service component global definition*/ +S32 Get_FIG0_EXT8(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3, temp4; + + struct FIG_TYPE0_Ext8 type0_ext8; + + while (fig_data.byte_cnt < fig_data.length) { + if (P_D) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + type0_ext8.Sid = (temp1 << 24) + | (temp2 << 16) + | (temp3 << 8) + | temp4; + } else { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext8.Sid = (temp1 << 8) | temp2; + } + + Get_Bits(1, &type0_ext8.Ext_flag); + Get_Bits(3, &temp1); + Get_Bits(4, &type0_ext8.SCidS); + Get_Bits(1, &type0_ext8.L_S_flag); + + if (type0_ext8.L_S_flag) { + Get_Bits(3, &temp1); + Get_Bits(4, &temp2); + Get_Bytes(1, &temp3); + type0_ext8.SCid = (temp2 << 8) | temp3; + } else { + Get_Bits(1, &type0_ext8.MSC_FIC_flag); + if (type0_ext8.MSC_FIC_flag) + Get_Bits(6, &type0_ext8.FIDCid); + else + Get_Bits(6, &type0_ext8.SubChid); + } + + if (type0_ext8.Ext_flag) + Get_Bytes(1, &temp1); + + if (fic_cmd) { + update_ens_desc_type0_ext8(&NEXT_ENS_DESC, + &ENS_DESC, + &type0_ext8, + C_N); + } + } + + return RTV_OK; +} + +/* Country, LTO and International Table */ +S32 Get_FIG0_EXT9(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3, temp4; + U8 k = 0; + U8 NumOfService = 0; + + struct FIG_TYPE0_Ext9 type0_ext9; + memset(&type0_ext9, 0x0, sizeof(struct FIG_TYPE0_Ext9)); + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &type0_ext9.Ext_flag); + Get_Bits(1, &type0_ext9.LTO_unique); + Get_Bits(6, &type0_ext9.Ensemble_LTO); + + Get_Bytes(1, &type0_ext9.Ensemble_ECC); + Get_Bytes(1, &type0_ext9.Inter_Table_ID); + + if (type0_ext9.Ext_flag) { + while (k < fig_data.length) { + Get_Bits(2, + &type0_ext9.Num_Ser[type0_ext9.NumOfSubField]); + Get_Bits(6, + &type0_ext9.LTO[type0_ext9.NumOfSubField]); + k++; + + if (P_D) { + for (NumOfService = 0; + NumOfService < type0_ext9.Num_Ser[type0_ext9.NumOfSubField]; + NumOfService++) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + type0_ext9.Sid[type0_ext9.NumOfSubField][NumOfService] + = (temp1 << 24) + | (temp2 << 16) + | (temp3 << 8) + | temp4; + + k += 4; + } + } else { + if (type0_ext9.Num_Ser[type0_ext9.NumOfSubField] != 0) { + Get_Bytes(1, + &type0_ext9.ECC[type0_ext9.NumOfSubField]); + k++; + } + + for (NumOfService = 0; + NumOfService < type0_ext9.Num_Ser[type0_ext9.NumOfSubField]; + NumOfService++) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext9.Sid[type0_ext9.NumOfSubField][NumOfService] + = (temp1 << 8) | temp2; + + k += 2; + } + } + type0_ext9.NumOfSubField++; + } + + } + + if (fic_cmd) { + ENS_DESC.date_time_info.LTO = type0_ext9.Ensemble_LTO; + Ensemble_ECC = type0_ext9.Ensemble_ECC; + ENS_DESC.date_time_info.get_flag |= LTO_FLAG; + } + } + + return RTV_OK; +} + +/* Date and Time */ +S32 Get_FIG0_EXT10(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3; + + struct FIG_TYPE0_Ext10 type0_ext10; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &temp1); + Get_Bits(7, &temp1); + Get_Bytes(1, &temp2); + Get_Bits(2, &temp3); + + type0_ext10.MJD = (temp1 << 10) | (temp2 << 2) | temp3; + + Get_Bits(1, &type0_ext10.LSI); + Get_Bits(1, &type0_ext10.Conf_ind); + Get_Bits(1, &type0_ext10.UTC_flag); + Get_Bits(3, &temp1); + Get_Bits(2, &temp2); + type0_ext10.Hours = (temp1 << 2) | temp2; + Get_Bits(6, &type0_ext10.Minutes); + + if (type0_ext10.UTC_flag) { + Get_Bits(6, &type0_ext10.Seconds); + Get_Bits(2, &temp1); + Get_Bytes(1, &temp2); + type0_ext10.Milliseconds = (temp1 << 8) | temp2; + } + + if (fic_cmd) { + ENS_DESC.date_time_info.MJD = type0_ext10.MJD; + ENS_DESC.date_time_info.LSI = type0_ext10.LSI; + ENS_DESC.date_time_info.conf_ind = type0_ext10.Conf_ind; + ENS_DESC.date_time_info.utc_flag = type0_ext10.UTC_flag; + ENS_DESC.date_time_info.hours = type0_ext10.Hours; + ENS_DESC.date_time_info.minutes = type0_ext10.Minutes; + if (type0_ext10.UTC_flag) { + ENS_DESC.date_time_info.seconds + = type0_ext10.Seconds; + ENS_DESC.date_time_info.milliseconds + = type0_ext10.Milliseconds; + } + + ENS_DESC.date_time_info.get_flag |= TIME_FLAG; + } + } + + return RTV_OK; +} + +/* Region Definition */ +S32 Get_FIG0_EXT11(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +S32 Get_FIG0_EXT12(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} + + +static INLINE void update_ens_desc_type0_ext13( + struct FIG_TYPE0_Ext13 *type0_ext13) +{ +UINT i, k, j, p, cnt; + +for (i = 0; i < ENS_DESC.svr_num; i++) { + if (type0_ext13->Sid == ENS_DESC.svr_desc[i].Sid) { + for (cnt = 0; cnt < ENS_DESC.svr_desc[i].Num_ser_comp; cnt++) { + j = ENS_DESC.svr_desc[i].ser_comp_num[cnt]; + ENS_DESC.svr_comp[j].Num_User_App + = type0_ext13->Num_User_App; + for (k = 0; k < type0_ext13->Num_User_App; k++) { + ENS_DESC.svr_comp[j].User_APP_Type[k] + = type0_ext13->User_APP_Type[k]; + ENS_DESC.svr_comp[j].User_APP_data_length[k] + = type0_ext13->User_APP_data_length[k]; + for (p = 0; + p < type0_ext13->User_APP_data_length[k]; p++) + ENS_DESC.svr_comp[j].User_APP_data[p] + = type0_ext13->User_APP_data[p]; + } + } + } +} + +} + +/* User Application Information */ +S32 Get_FIG0_EXT13(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3, temp4; + UINT k, p; + + struct FIG_TYPE0_Ext13 type0_ext13; + + while (fig_data.byte_cnt < fig_data.length) { + if (P_D) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + type0_ext13.Sid = (temp1 << 24) | (temp2 << 16) + | (temp3 << 8) | temp4; + } else { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext13.Sid = (temp1 << 8) | temp2; + } + + Get_Bits(4, &type0_ext13.SCidS); + Get_Bits(4, &type0_ext13.Num_User_App); + + for (k = 0; k < type0_ext13.Num_User_App; k++) { + Get_Bytes(1, &temp1); + Get_Bits(3, &temp2); + type0_ext13.User_APP_Type[k] = (temp1 << 3) | temp2; + + Get_Bits(5, &type0_ext13.User_APP_data_length[k]); +/* + if (type0_ext13.User_APP_data_length[k]> 2) { + Get_Bits(1, &type0_ext13.CA_flag); + Get_Bits(1, &type0_ext13.CA_Org_flag); + Get_Bits(1, &temp1); + Get_Bits(5, &type0_ext13.X_PAD_App_Ty); + Get_Bits(1, &type0_ext13.DG_flag); + Get_Bits(1, &temp2); + Get_Bits(6, &type0_ext13.DSCTy); + + if (type0_ext13.CA_Org_flag) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext13.CA_Org + = (temp1 << 8) | temp2; + } + } +*/ + for (p = 0; p < type0_ext13.User_APP_data_length[k] + ; p++) + Get_Bytes(1, &type0_ext13.User_APP_data[p]); + + } + + if (fic_cmd) + update_ens_desc_type0_ext13(&type0_ext13); + } + + return RTV_OK; +} + +/* FEC sub-channel organization */ +S32 Get_FIG0_EXT14(U8 fic_cmd, U8 P_D, U8 C_N) +{ +UINT cnt; + +struct FIG_TYPE0_Ext14 type0_ext14; + +while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(6, &type0_ext14.SubChid); + Get_Bits(2, &type0_ext14.FEC_scheme); + + if (fic_cmd) { + if (C_N) { + for (cnt = 0; + cnt < NEXT_ENS_DESC.svr_comp_num; cnt++) { + if (type0_ext14.SubChid + == NEXT_ENS_DESC.svr_comp[cnt].SubChid) + NEXT_ENS_DESC.svr_comp[cnt].FEC_scheme + = type0_ext14.FEC_scheme; + } + } else { + for (cnt = 0; cnt < ENS_DESC.svr_comp_num; cnt++) { + if (type0_ext14.SubChid + == ENS_DESC.svr_comp[cnt].SubChid) + ENS_DESC.svr_comp[cnt].FEC_scheme + = type0_ext14.FEC_scheme; + } + } + } +} + +return RTV_OK; +} + +S32 Get_FIG0_EXT15(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} + +/* Program Number */ +S32 Get_FIG0_EXT16(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + /*U8 cnt;*/ + + struct FIG_TYPE0_Ext16 type0_ext16; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext16.Sid = (temp1 << 8) | temp2; + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext16.PNum = (temp1 << 8) | temp2; + Get_Bits(2, &temp1); + Get_Bits(4, &temp2); + Get_Bits(1, &type0_ext16.Continuation_flag); + Get_Bits(1, &type0_ext16.Update_flag); + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext16.New_Sid = (temp1 << 8) | temp2; + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext16.New_PNum = (temp1 << 8) | temp2; +#if 0 + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (type0_ext16.Sid + == ENS_DESC.svr_desc[cnt].Sid) + /* Not yet implementation */ + + } + } +#endif + } + + return RTV_OK; +} + +/* Program Type */ +S32 Get_FIG0_EXT17(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + U8 cnt; + + struct FIG_TYPE0_Ext17 type0_ext17; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext17.Sid = (temp1 << 8) | temp2; + + Get_Bits(1, &type0_ext17.S_D); + Get_Bits(1, &type0_ext17.P_S); + Get_Bits(1, &type0_ext17.L_flag); + Get_Bits(1, &type0_ext17.CC_flag); + Get_Bits(4, &temp1); + + if (type0_ext17.L_flag) + Get_Bytes(1, &type0_ext17.Language); + + Get_Bits(3, &temp2); + Get_Bits(5, &type0_ext17.Int_code); + + if (type0_ext17.CC_flag) { + Get_Bits(3, &temp1); + Get_Bits(5, &type0_ext17.Comp_code); + } + + if (fic_cmd) { + if (ENS_DESC.svr_num != 0) { + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (type0_ext17.Sid + == ENS_DESC.svr_desc[cnt].Sid) + ENS_DESC.svr_desc[cnt].int_code + = type0_ext17.Int_code; + + } + } + } + } + + return RTV_OK; +} + +/* Announcement support */ +S32 Get_FIG0_EXT18(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + U8 i; + /*U8 cnt; */ + + struct FIG_TYPE0_Ext18 type0_ext18; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext18.Sid = (temp1 << 8) | temp2; + + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext18.ASU_flags = (temp1 << 8) | temp2; + + Get_Bits(3, &temp1); + Get_Bits(5, &type0_ext18.Num_clusters); + + + for (i = 0; i < type0_ext18.Num_clusters; i++) + Get_Bytes(1, &type0_ext18.Cluster_ID[i]); + +#if 0 + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (type0_ext18.Sid + == ENS_DESC.svr_desc[cnt].Sid) + /* Not yet implementation */ + } + } +#endif + } + + return RTV_OK; +} + +/* Announcement switching */ +S32 Get_FIG0_EXT19(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + + struct FIG_TYPE0_Ext19 type0_ext19; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &type0_ext19.Cluster_ID); + + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext19.ASW_flags = (temp1 << 8) | temp2; + + Get_Bits(1, &type0_ext19.New_flag); + Get_Bits(1, &type0_ext19.Region_flag); + Get_Bits(6, &type0_ext19.SubChid); + + if (type0_ext19.Region_flag) { + Get_Bits(2, &temp1); + Get_Bits(6, &type0_ext19.Regionid_Lower_Part); + } +#if 0 + if (fic_cmd) + /* Not yet implementation */ +#endif + } + + return RTV_OK; +} + +S32 Get_FIG0_EXT20(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* Frequency Information */ +S32 Get_FIG0_EXT21(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* Transmitter Identification Information (TII) database */ +S32 Get_FIG0_EXT22(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2; + U8 i; + + struct FIG_TYPE0_Ext22 type0_ext22; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &type0_ext22.M_S); + if (type0_ext22.M_S) { + Get_Bits(7, &type0_ext22.Mainid); + Get_Bits(5, &temp1); + Get_Bits(3, &type0_ext22.Num_Subid_fields); + + for (i = 0; i < type0_ext22.Num_Subid_fields; i++) { + Get_Bits(5, &type0_ext22.Subid[i]); + Get_Bits(3, &temp1); + Get_Bytes(1, &temp2); + type0_ext22.TD[i] = (temp1 << 8) | temp2; + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext22.Latitude_offset[i] + = (temp1 << 8) | temp2; + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext22.Longitude_offset[i] + = (temp1 << 8) | temp2; + } + } else { + Get_Bits(7, &type0_ext22.Mainid); + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext22.Latitude_coarse = (temp1 << 8) | temp2; + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext22.Longitude_coarse = (temp1 << 8) | temp2; + Get_Bits(4, &type0_ext22.Latitude_fine); + Get_Bits(4, &type0_ext22.Longitude_fine); + } +#if 0 + if (fic_cmd) + /* Not yet implementation */ +#endif + } + + return RTV_OK; +} +S32 Get_FIG0_EXT23(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} + +/* Other Ensemble Service */ +S32 Get_FIG0_EXT24(U8 fic_cmd, U8 P_D, U8 C_N) +{ + U8 temp1, temp2, temp3, temp4; + U8 i; + /* U8 cnt;*/ + + struct FIG_TYPE0_Ext24 type0_ext24; + + while (fig_data.byte_cnt < fig_data.length) { + if (P_D) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + type0_ext24.Sid + = (temp1 << 24) + | (temp2 << 16) | (temp3 << 8) | temp4; + } else { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext24.Sid = (temp1 << 8) | temp2; + } + + Get_Bits(1, &temp1); + Get_Bits(3, &type0_ext24.CAid); + Get_Bits(4, &type0_ext24.Number_Eids); + + for (i = 0; i < type0_ext24.Number_Eids; i++) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + type0_ext24.Eid[i] = (temp1 << 8) | temp2; + } +#if 0 + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (type0_ext24.Sid + == ENS_DESC.svr_desc[cnt].Sid) + /* Not yet implementation*/ + + } + } +#endif + } + + return RTV_OK; +} + +/* Other Ensemble Announcement support */ +S32 Get_FIG0_EXT25(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* Other Ensemble Announcement switching */ +S32 Get_FIG0_EXT26(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* FM Announcement support */ +S32 Get_FIG0_EXT27(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* FM Announcement switching */ +S32 Get_FIG0_EXT28(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +S32 Get_FIG0_EXT29(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +S32 Get_FIG0_EXT30(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} +/* FIC re-direction */ +S32 Get_FIG0_EXT31(U8 fic_cmd, U8 P_D, U8 C_N) +{ + return RTV_OK; +} + + +/* FIG TYPE 1 Extension Function */ +/* Ensemble Label */ +S32 Get_FIG1_EXT0(U8 fic_cmd, U8 Char_Set) +{ + U16 Eid; + U8 label[17]; + S8 i = 0; + U8 temp1, temp2; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Eid = (temp1 << 8) | temp2; + + if (fic_cmd) { + Get_Bytes(16, label); + + if (!ENS_DESC.label_flag) { + for (i = 15; i >= 0; i--) { + if (label[i] != 0x20) { + label[i+1] = '\0'; + break; + } + } + label[16] = '\0'; + + ENS_DESC.charset = Char_Set; + memcpy(ENS_DESC.Label, label, 17); + ENS_DESC.label_flag = 1; + } + } + } + + return RTV_OK; +} + +/* Program Service Label */ +S32 Get_FIG1_EXT1(U8 fic_cmd, U8 Char_Set) +{ + U32 sid; + U8 label[17]; + U8 cnt; + S8 i; + U8 temp1, temp2; + +while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + sid = (temp1 << 8) | temp2; + + if (fic_cmd) { + Get_Bytes(16, label); + + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (sid == ENS_DESC.svr_desc[cnt].Sid) { + if (!ENS_DESC.svr_desc[cnt].label_flag) { + for (i = 15; i >= 0; i--) { + if (label[i] != 0x20) { + label[i+1] = '\0'; + break; + } + } + label[16] = '\0'; + + ENS_DESC.svr_desc[cnt].charset + = Char_Set; + memcpy(ENS_DESC.svr_desc[cnt].Label, + label, 17); + ENS_DESC.svr_desc[cnt].label_flag = 1; + ENS_DESC.label_num++; + } + } + } + } +} + +return RTV_OK; +} + +S32 Get_FIG1_EXT2(U8 fic_cmd, U8 Char_Set) +{ + return RTV_OK; +} + +/* Region Label */ +S32 Get_FIG1_EXT3(U8 fic_cmd, U8 Char_Set) +{ + U8 temp1; + U8 RegionId_Lower_part; + U8 label[17]; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(2, &temp1); + Get_Bits(6, &RegionId_Lower_part); + + if (fic_cmd) + Get_Bytes(16, label); + } + + return RTV_OK; +} + +/* Service Component Label */ +S32 Get_FIG1_EXT4(U8 fic_cmd, U8 Char_Set) +{ + U8 P_D; + U8 SCidS; + U32 sid; + U8 label[17]; + S8 i = 0, k = 0; + U8 temp1, temp2, temp3, temp4; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &P_D); + Get_Bits(3, &temp1); + Get_Bits(4, &SCidS); + + if (P_D) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + sid = (temp1 << 24) + | (temp2 << 16) | (temp3 << 8) | temp4; + } else { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + sid = (temp1 << 8) | temp2; + } + + if (fic_cmd) { + Get_Bytes(16, label); + + for (k = 0; k < ENS_DESC.svr_comp_num; k++) { + if ((ENS_DESC.svr_comp[k].Sid == sid) + && (ENS_DESC.svr_comp[k].SCidS + == SCidS)) { + for (i = 15; i >= 0; i--) { + if (label[i] != 0x20) { + label[i+1] = '\0'; + break; + } + } + label[16] = '\0'; + + ENS_DESC.svr_comp[k].charset + = Char_Set; + memcpy(ENS_DESC.svr_comp[k].Label, + label, 17); + break; + } + } + } + } + + return RTV_OK; +} + +/* Data Service Label */ +S32 Get_FIG1_EXT5(U8 fic_cmd, U8 Char_Set) +{ + U32 sid; + U8 label[17]; + U8 cnt; + S8 i; + U8 temp1, temp2, temp3, temp4; + +while (fig_data.byte_cnt < fig_data.length) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + sid = (temp1 << 24) | (temp2 << 16) | (temp3 << 8) | temp4; + + if (fic_cmd) { + Get_Bytes(16, label); + + for (cnt = 0; cnt < ENS_DESC.svr_num; cnt++) { + if (sid == ENS_DESC.svr_desc[cnt].Sid) { + if (!ENS_DESC.svr_desc[cnt].label_flag) { + for (i = 15; i >= 0; i--) { + if (label[i] != 0x20) { + label[i+1] = '\0'; + break; + } + } + label[16] = '\0'; + + ENS_DESC.svr_desc[cnt].charset + = Char_Set; + memcpy(ENS_DESC.svr_desc[cnt].Label, + label, 17); + ENS_DESC.svr_desc[cnt].label_flag = 1; + ENS_DESC.label_num++; + } + } + } + } +} + +return RTV_OK; +} + +/* X-PAD user application label */ +S32 Get_FIG1_EXT6(U8 fic_cmd, U8 Char_Set) +{ + U8 P_D; + U8 SCidS; + U32 sid; + U8 X_PAD_app_type; + U8 label[17]; + U8 temp1, temp2, temp3, temp4; + + while (fig_data.byte_cnt < fig_data.length) { + Get_Bits(1, &P_D); + Get_Bits(3, &temp1); + Get_Bits(4, &SCidS); + + if (P_D) { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + Get_Bytes(1, &temp3); + Get_Bytes(1, &temp4); + sid = (temp1 << 24) + | (temp2 << 16) | (temp3 << 8) | temp4; + } else { + Get_Bytes(1, &temp1); + Get_Bytes(1, &temp2); + sid = (temp1 << 8) | temp2; + } + + Get_Bits(2, &temp1); + Get_Bits(1, &temp2); + Get_Bits(5, &X_PAD_app_type); + + if (fic_cmd) + Get_Bytes(16, label); + } + + return RTV_OK; +} + +S32 Get_FIG1_EXT7(U8 fic_cmd, U8 Char_Set) +{ + return RTV_OK; +} + + +/* FIG TYPE 2 Extension Function */ +/* Ensemble Label */ +S32 Get_FIG2_EXT0(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* Program Service Label */ +S32 Get_FIG2_EXT1(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +S32 Get_FIG2_EXT2(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* Region Label */ +S32 Get_FIG2_EXT3(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* Service Component Label */ +S32 Get_FIG2_EXT4(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* Data Service Label */ +S32 Get_FIG2_EXT5(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* X-PAD user application label */ +S32 Get_FIG2_EXT6(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + +/* Character Definition */ +S32 Get_FIG2_EXT7(U8 fic_cmd, U8 Seg_Index) +{ + return RTV_OK; +} + + +/* FIG TYPE 5 Extension Function */ +/* Paging */ +S32 Get_FIG5_EXT0(U8 D1, U8 D2, U8 fic_cmd, U8 TCid) +{ + U8 cnt = 0; + U8 FIDC_ID; + + FIDC_ID = (TCid << 3) | 0x00; + + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_comp_num; cnt++) { + if (FIDC_ID == ENS_DESC.svr_comp[cnt].FIDCid) { + ENS_DESC.svr_comp[cnt].TCid = TCid; + ENS_DESC.svr_comp[cnt].Ext = 0; + } + } + } + + return RTV_OK; +} + +/* Traffic Message Channel (TMC) */ +S32 Get_FIG5_EXT1(U8 D1, U8 D2, U8 fic_cmd, U8 TCid) +{ + U8 cnt = 0; + U8 FIDC_ID; + + FIDC_ID = (TCid << 3) | 0x01; + + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_comp_num; cnt++) { + if (FIDC_ID == ENS_DESC.svr_comp[cnt].FIDCid) { + ENS_DESC.svr_comp[cnt].TCid = TCid; + ENS_DESC.svr_comp[cnt].Ext = 1; + } + } + } + + return RTV_OK; +} + +/* Emergency Warning System (EWS) */ +S32 Get_FIG5_EXT2(U8 D1, U8 D2, U8 fic_cmd, U8 TCid) +{ + U8 cnt = 0; + U8 FIDC_ID; + + FIDC_ID = (TCid << 3) | 0x02; + + if (fic_cmd) { + for (cnt = 0; cnt < ENS_DESC.svr_comp_num; cnt++) { + if (FIDC_ID == ENS_DESC.svr_comp[cnt].FIDCid) { + ENS_DESC.svr_comp[cnt].TCid = TCid; + ENS_DESC.svr_comp[cnt].Ext = 2; + } + } + } + + return RTV_OK; +} + + +U8 GET_SUBCH_INFO(struct FIG_TYPE0_Ext1 *type0_ext1, + S32 *BIT_RATE, S32 *SUB_CH_Size, S32 *P_L) +{ +/*Indicate the option used for the long form coding(Equal Error Protection)*/ + if (type0_ext1->S_L_form) { + *SUB_CH_Size = type0_ext1->Sub_ch_size; + *P_L = ((type0_ext1->S_L_form<<7) + | (type0_ext1->Option<<6) + | type0_ext1->Protection_Level); + + if (type0_ext1->Option == 0x1) { + switch (type0_ext1->Protection_Level) { + case 0: + *BIT_RATE = (type0_ext1->Sub_ch_size)*32/27; + break; + case 1: + *BIT_RATE = (type0_ext1->Sub_ch_size)*32/21; + break; + case 2: + *BIT_RATE = (type0_ext1->Sub_ch_size)*32/18; + break; + case 3: + *BIT_RATE = (type0_ext1->Sub_ch_size)*32/15; + break; + } + } else if (type0_ext1->Option == 0x0) { + switch (type0_ext1->Protection_Level) { + case 0: + *BIT_RATE = (type0_ext1->Sub_ch_size)*2/3; + break; + case 1: + *BIT_RATE = (type0_ext1->Sub_ch_size); + break; + case 2: + *BIT_RATE = (type0_ext1->Sub_ch_size)*4/3; + break; + case 3: + *BIT_RATE = (type0_ext1->Sub_ch_size)*2; + break; + } + } + } else { + *SUB_CH_Size = SUBCH_UEP_TABLE[type0_ext1->Table_index][0]; + *P_L = SUBCH_UEP_TABLE[type0_ext1->Table_index][1]; + *BIT_RATE = SUBCH_UEP_TABLE[type0_ext1->Table_index][2]; + } + + return RTV_OK; +} + +U8 GET_DATE_TIME(struct DATE_TIME_INFO *time_desc) +{ + U16 MJD_Ref[2] = {2000, 51544}; /*2000.01.01 reference day*/ + U8 month0_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + U8 month1_table[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + U16 UTC_hours, MJD_temp, day_temp; + U8 increase_year, leap_year_num; + U8 normal_year_num, offset_flag, offset_value; + U16 MJDRef_year; + U16 MJDRef_month; + U16 MJDRef_day = 0; + U8 week; + U8 k = 0, i = 0; + +/* sense of the Local Time Offset (0: positive offset 1: negative offset)*/ + offset_flag = (ENS_DESC.date_time_info.LTO & 0x20) >> 5; + + /* Local time offset value (0 ~ 23)*/ + offset_value = (ENS_DESC.date_time_info.LTO & 0x1f) / 2; + + /* UTC hours */ + UTC_hours = ENS_DESC.date_time_info.hours; + + if (offset_flag) { + if (UTC_hours < offset_value) + time_desc->time_flag = 0; + else + time_desc->time_flag = 1; + } else { + if (((23-offset_value) < UTC_hours) && (UTC_hours < 24)) + time_desc->time_flag = 0; + else + time_desc->time_flag = 1; + } + + /* current MJD - ref MJD */ + MJD_temp = ENS_DESC.date_time_info.MJD - MJD_Ref[1]; + increase_year = MJD_temp / 365; /* 2000 + x year */ + + /* detection 2000 + x year */ + time_desc->years = MJD_Ref[0] + increase_year; + leap_year_num = (increase_year - 1) / 4; /* 366 year number */ + normal_year_num = (increase_year - 1) % 4;/* 365 year number */ + + /* first MJD for current year */ + MJDRef_year + = MJD_Ref[1] + 366 * (leap_year_num + 1) + + 365 * ((3 * leap_year_num) + normal_year_num); + + + if (time_desc->time_flag) + MJDRef_month = ENS_DESC.date_time_info.MJD - MJDRef_year; + else { + if (offset_flag) + MJDRef_month + = ENS_DESC.date_time_info.MJD + - MJDRef_year - 1; + else + MJDRef_month = ENS_DESC.date_time_info.MJD + - MJDRef_year + 1; + } + + for (k = 0; k < 12; k++) { + day_temp = MJDRef_month - MJDRef_day; + + if (normal_year_num == 3) { + if (day_temp >= month1_table[k]) + MJDRef_day += month1_table[k]; + else { + /* detection month */ + time_desc->months_dec = k + 1; + strcpy((char *)time_desc->months_ste, + MONTH_TABLE[k]); + + /* detection day */ + time_desc->days = day_temp + 1; + break; + } + } else { + if (day_temp >= month0_table[k]) + MJDRef_day += month0_table[k]; + else { + /* detection month */ + time_desc->months_dec = k + 1; + strcpy((char *)time_desc->months_ste, + MONTH_TABLE[k]); + /* detection day */ + time_desc->days = day_temp + 1; + break; + } + } + } + + week = MJD_temp % 7; + for (i = 0; i < 7; i++) { + if (i == week) { + if (time_desc->time_flag) { + strcpy((char *)time_desc->weeks, + WEEK_TABLE[i]); + } else { + if (offset_flag) + strcpy((char *)time_desc->weeks, + WEEK_TABLE[i-1]); + else + strcpy((char *)time_desc->weeks, + WEEK_TABLE[i+1]); + } + break; + } + } + + if (ENS_DESC.date_time_info.utc_flag) { + if (time_desc->time_flag) { + time_desc->hours + = ENS_DESC.date_time_info.hours + offset_value; + if (time_desc->hours < 12) + time_desc->apm_flag = 0; + else if (time_desc->hours == 12) + time_desc->apm_flag = 1; + else { + time_desc->hours = time_desc->hours - 12; + time_desc->apm_flag = 1; + } + } else { + if (offset_flag) { + time_desc->hours + = (ENS_DESC.date_time_info.hours + 12) + - offset_value; + time_desc->apm_flag = 1; + } else { + time_desc->hours + = (ENS_DESC.date_time_info.hours + + offset_value) - 24; + time_desc->apm_flag = 0; + } + } + + time_desc->minutes = ENS_DESC.date_time_info.minutes; + time_desc->seconds = ENS_DESC.date_time_info.seconds; + time_desc->milliseconds = ENS_DESC.date_time_info.milliseconds; + } else { + if (time_desc->time_flag) { + time_desc->hours + = ENS_DESC.date_time_info.hours + offset_value; + if (time_desc->hours < 12) + time_desc->apm_flag = 0; + else if (time_desc->hours == 12) + time_desc->apm_flag = 1; + else { + time_desc->hours = time_desc->hours - 12; + time_desc->apm_flag = 1; + } + } else { + if (offset_flag) { + time_desc->hours + = (ENS_DESC.date_time_info.hours + 12) + - offset_value; + time_desc->apm_flag = 1; + } else { + time_desc->hours + = (ENS_DESC.date_time_info.hours + + offset_value) - 24; + time_desc->apm_flag = 0; + } + } + + time_desc->minutes = ENS_DESC.date_time_info.minutes; + } + + return RTV_OK; +} + + +char *PROGRAM_TYPE_CODE16[32] = { + "None", "News", "Current_Affairs", "Information", "Sport", + "Education", "Drama", "Arts", "Science", "Talk", + "Pop_Music", "Rock_Music", "Easy_Listening", + "Light_Classical", "Classical_Music", + "Other_Music", "Weather", "Finance", "Children's", "Factual", + "Religion", "Phone_In", "Travel", "Leisure", "Jazz_and_Blues", + "Country_Music", "National_Music", + "Oldies_Music", "Folk_Music", "Documentary" +}; + +char *PROGRAM_TYPE_CODE8[32] = { + "None", "News", "Affairs", "Info", "Sport", + "Educate", "Drama", "Arts", "Science", "Talk", + "Pop", "Rock", "Easy", "Classics", "Classics", + "Other_M", "Weather", "Finance", "Children", "Factual", + "Religion", "Phone_In", "Travel", "Leisure", "Jazz", + "Country", "Nation_M", "Oldies", "Folk", "Document" +}; + +char *USER_APP_TYPE_CODE[11] = { + "Reserved", "Not used", "MOT Slideshow", "MOT BWS", "TPEG", + "DGPS", "TMC", "EPG", "DAB Java", "DMB", "Reserved" +}; + +char *FIDC_EXT_CODE[3] = { + "Paging", "Traffic Message(TMC)", "Emergency Warning(EWS)" +}; + +char *ASCTy[3] = { + "Foreground Sound", "Background Sound", "Multi-CH Audio" +}; + +char *DSCTy[11] = { + "Unspecified Data", "Traffic Message(TMC)", "Emergency Warning(EWS)", + "ITTS", "Paging", "TDC", + "KDMB", "Embedded IP", "MOT", "Proprietary Service", "Reserved" +}; + +char *ANNOUNCEMENT_TYPE_CODE[12] = { + "Alarm", "Road Traffic flash", "Transport flash", "Warning/Service", + "News flash", "Area weather flash", + "Event announcement", "Special event", "Programme information", + "Sport report", "Financial report", + "Reserved for future definition" +}; + +int SUBCH_SIZE_TABLE[64] = { 32, 32, 32, 32, 32, 48, 48, 48, 48, 48, + 56, 56, 56, 56, 64, 64, 64, 64, 64, 80, + 80, 80, 80, 80, 96, 96, 96, 96, 96, 112, + 112, 112, 112, 128, 128, 128, 128, 128, 160, 160, + 160, 160, 160, 192, 192, 192, 192, 192, 224, 224, + 224, 224, 224, 256, 256, 256, 256, 256, 320, 320, + 320, 384, 384, 384}; + +int SUBCH_UEP_TABLE[64][3] = { + /* 0 {Sub-channel size, Protection level, Bit rate} */ + {16, 5, 32}, {21, 4, 32}, {24, 3, 32}, {29, 2, 32}, + {35, 1, 32}, {24, 5, 48}, {29, 4, 48}, {35, 3, 48}, /*4 */ + {42, 4, 48}, {52, 1, 48}, {29, 5, 56}, {35, 4, 56}, /* 8 */ + {42, 3, 56}, {52, 2, 56}, {32, 5, 64}, {42, 4, 64}, /* 12 */ + {48, 3, 64}, {58, 2, 64}, {70, 1, 64}, {40, 5, 80}, /* 16 */ + {52, 4, 80}, {58, 3, 80}, {70, 2, 80}, {84, 1, 80}, /* 20 */ + {48, 5, 96}, {58, 4, 96}, {70, 3, 96}, {84, 2, 96}, /* 24 */ + {104, 1, 96}, {58, 5, 112}, {70, 4, 112}, {84, 3, 112}, /* 28 */ + {104, 2, 112}, {64, 5, 128}, {84, 4, 128}, {96, 3, 128}, /* 32 */ + {116, 2, 128}, {140, 1, 128}, {80, 5, 160}, {104, 4, 160},/* 36 */ + {116, 3, 160}, {140, 2, 160}, {168, 1, 160}, {96, 5, 192}, /* 40 */ + {116, 4, 192}, {140, 3, 192}, {168, 2, 192}, {208, 1, 192}, /* 44 */ + {116, 5, 224}, {140, 4, 224}, {168, 3, 224}, {208, 2, 224}, /* 48 */ + {232, 1, 224}, {128, 5, 256}, {168, 4, 256}, {192, 3, 256}, /* 52 */ + {232, 2, 256}, {280, 1, 256}, {160, 5, 320}, {208, 4, 320}, /* 56 */ + {280, 2, 320}, {192, 5, 384}, {280, 3, 384}, {416, 1, 384}, /* 60 */ +}; + +char *MONTH_TABLE[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +char *WEEK_TABLE[8] = { + "SAT", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" +}; +/* +int MJD_TABLE[][] ={ + {53370, 1, 2005}, {53735, 1, 2006}, + {54100, 1, 2007}, {54465, 1, 2008}, + {53401, 2, 2005}, {53766, 2, 2006}, + {54131, 2, 2007}, {54496, 2, 2008}, + {53429, 3, 2005}, {53794, 3, 2006}, + {54159, 3, 2007}, {54525, 3, 2008}, + {53460, 4, 2005}, {53825, 4, 2006}, + {54190, 4, 2007}, {54556, 4, 2008}, + {53490, 5, 2005}, {53855, 5, 2006}, + {54220, 5, 2007}, {54586, 5, 2008}, + {53521, 6, 2005}, {53866, 6, 2006}, + {54251, 6, 2007}, {54617, 6, 2008}, + {53551, 7, 2005}, {53916, 7, 2006}, + {54281, 7, 2007}, {54647, 7, 2008}, + {53582, 8, 2005}, {53947, 8, 2006}, + {54312, 8, 2007}, {54678, 8, 2008}, + {53613, 9, 2005}, {53978, 9, 2006}, + {54343, 9, 2007}, {54709, 9, 2008}, + {53643, 10, 2005}, {54008, 10, 2006}, + {54373, 10, 2007}, {54739, 10, 2008}, + {53674, 11, 2005}, {54039, 11, 2006}, + {54404, 11, 2007}, {54770, 11, 2008}, + {53704, 12, 2005}, {54069, 12, 2006}, + {54434, 12, 2007}, {54800, 12, 2008}, +}; +*/ + +char *EWS_PRIORITY_TABLE[4] = { + "Unknown", "보통", "긴급", "매우긴급" +}; + +char *EWS_REGION_FORM_TABLE[4] = { + "대한민국 ì „êµ­", + "대한민국 정부 지정", + "í–‰ìžë¶€ í–‰ì •ë™ í‘œê¸°", + "Rfa" +}; + +char *EWS_OFFICIAL_ORGANIZATION_TABLE[4] = { + "소방방재청", "ì‹œ,ë„", "êµ°,ë„", "Rfa" +}; + +char *EWS_CATEGORY[67][3] = { + {"호우 주ì˜ë³´", "HRA", "Heavy Rain Watch"}, + {"호우 경보", "HRW", "Heavy Rain Warning"}, + {"대설 주ì˜ë³´", "HSW", "Heavy Snow Watch"}, + {"대설 경보", "HAS", "Heavy Snow Warning"}, + {"í­í’í•´ì¼ì£¼ì˜ë³´", "SSA", "Storm Surge Watch"}, + {"í­í’í•´ì¼ ê²½ë³´", "SSW", "Storm Surge Warning"}, + {"황사 경보", "YSW", "Yellow Sand Warning"}, + {"한파 주ì˜ë³´", "CWA", "Cold Wave Watch"}, + {"한파 경보", "CWW", "Cold Wave Warning"}, + {"í’ëž‘ 경보", "WWW", "Wind and Waves Warning"}, + {"ê±´ì¡° 경보", "HAW", "Heavy Arid Warning"}, + {"산불 경보", "MFW", "Mountain Fire Warning"}, + {"êµí†µ 통제", "RTW", "Regulate Traffic Warning"}, + {"êµ­ê°€ ë¹„ìƒ ìƒí™© ë°œìƒ", + "EAN", "Emergency Action Notification(National only)"}, + {"êµ­ê°€ ë¹„ìƒ ìƒí™© 종료", + "EAT", "Emergency Action Termination(National only)"}, + {"중앙 재난 안전 대책 본부", + "NIC", "National Information Center"}, + {"ì „êµ­ì  ì£¼ê¸° 테스트", "NPT", "National Periodic Test"}, + {"ì „êµ­ì  ì›”ë³„ ì˜ë¬´ 테스트", "RMT", "Required Monthly Test"}, + {"ì „êµ­ì  ì£¼ê°„ë³„ ì˜ë¬´ 테스트", "RWT", "Required Weekly Test"}, + {"특수 수신기 테스트", "STT", "Special Terminal Test"}, + {"행정 메시지", "ADR", "Administrative Message"}, + {"산사태 경보", "AVW", "Avalanche Warning"}, + {"산사태 주ì˜ë³´", "AVA", "Avalanche Watch"}, + {"í­í’설경보", "BZW", "Blizzard Warning"}, + {"ì–´ë¦°ì´ ìœ ê´´ 긴급 ìƒí™©", + "CAE", "Child Abduction Emergency"}, + {"시민 위험 ìƒí™© 경보", "CDW", "Civil Danger Warning"}, + {"시민 ì‘급 ìƒí™© 메시지", "CEM", "Civil Emergency Message"}, + {"해안 침수 경보", "CFW", "Coastal Flood Warning"}, + {"해안 침수 주ì˜ë³´", "CFA", "Coastal Flood Watch"}, + {"모래 í­í’ 경보", "DSW", "Dust Storm Warning"}, + {"지진 경보", "EQW", "Earthquake Warning"}, + {"즉시 대피", "EVI", "Evacuation Immediate"}, + {"화재 경보", "FRW", "Fire Warning"}, + {"긴급 í™ìˆ˜ 경보", "FFW", "Flash Flood Warning"}, + {"긴급 í™ìˆ˜ 주ì˜ë³´", "FFA", "Flash Flood Watch"}, + {"긴급 í™ìˆ˜ ìƒí™©", "FFS", "Flash Flood Statement"}, + {"í™ìˆ˜ 경보", "FLW", "Flood Warning"}, + {"í™ìˆ˜ 주ì˜ë³´", "FLA", "Flood Watch"}, + {"í™ìˆ˜ ìƒí™©", "FLS", "Flood Statement"}, + {"위험 물질 경보", + "HMW", "Hazardous Materials Warning"}, + {"ê°•í’ ê²½ë³´", "HWW", "High Wind Warning"}, + {"ê°•í’ ì£¼ì˜ë³´", "HWA", "High Wind Watch"}, + {"íƒœí’ ê²½ë³´", "HUW", "Hurricane Warning"}, + {"íƒœí’ ì£¼ì˜ë³´", "HUA", "Hurricane Watch"}, + {"태í’ì •ë³´", "HLS", "Hurricane Statement"}, + {"법집행 경고", "LEW", "Law Enforcement Warning"}, + {"지역 긴급 ìƒí™©", "LAE", "Local Area Emergency"}, + {"통신 메지시 알림", + "NMN", "Network Message Notification"}, + {"119 ì „í™” 불통 ì‘급 ìƒí™©", + "TOE", "119 Telephone Outage Emergency"}, + {"핵발전소 관련 경보", + "NUW", "Nuclear Power Plant Warning"}, + {"실제/연습 경보", "DMO", "Practice/Demo Warning"}, + {"방사능 위험 경보", + "RHW", "Radiological Hazard Warning"}, + {"뇌우 경보", "SVR", "Severe Thunderstorm Warning"}, + {"뇌우 주ì˜ë³´", "SVA", "Severe Thunderstorm Watch"}, + {"악기ìƒì •ë³´", "SVS", "Severe Weather Statement"}, + {"안전한 장소로 피난 경보", + "SPW", "Shelter in Place Warning"}, + {"특수 í•´ì–‘ 경보", "SMW", "Special Marine Warning"}, + {"íŠ¹ì´ ê¸°ìƒ ì •ë³´", "SPS", "Special Weather Statement"}, + {"토네ì´ë„ 경보", "TOR", "Tornado Warning"}, + {"토네ì´ë„ 주ì˜ë³´", "TOA", "Tornado Watch"}, + {"열대 í­í’(태í’) 경보", "TRW", "Tropical Storm Warning"}, + {"열대 í­í’(태í’) 주ì˜ë³´", "TRA", "Tropical Storm Watch"}, + {"ì§€ì§„í•´ì¼ ê²½ë³´", "TSW", "Tsunami Warning"}, + {"ì§€ì§„í•´ì¼ ì£¼ì˜ë³´", "TSA", "Tsunami Watch"}, + {"화산 경보", "VOW", "Volcano Warning"}, + {"눈í­í’ 경보", "WSW", "Winter Storm Warning"}, + {"눈í­í’ 주ì˜ë³´", "WSA", "Winter Storm Watch"} +}; + +static const U16 crc_ccitt_tab[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +static S32 CRC_CHECK(U8 *data, U16 data_len) +{ + + U16 crc = 0xffff; + U16 crc2 = 0xffff; + U16 crc_val, i; + U8 crc_cal_data; + + for (i = 0; i < (data_len - 2); i++) { + crc_cal_data = *(data+i); + crc = (crc<<8)^crc_ccitt_tab[(crc>>8)^(crc_cal_data)++]; + } + + crc_val = *(data+i)<<8; + crc_val = crc_val | *(data+i+1); + + crc2 = (crc_val^crc2); + + if (crc == crc2) + return RTV_OK; + else + return RTV_FAIL; +} + + +/*****************************/ +/* FIC Information Variable */ +/*****************************/ +struct ENSEMBLE_DESC ENS_DESC, NEXT_ENS_DESC; +static U32 FIC_CONUT; + + +static UINT fib_crc_err_cnt; +S32 FIC_Init_Dec(U8 *fic, U8 fib_num, U8 CN) +{ + U32 i; + S32 ret; + UINT fib_crc_pos = 0; + UINT fib_crc_err_sum = 0; + + FIC_CONUT++; + + for (i = 0; i < fib_num; i++) { + if (CRC_CHECK(fic+fib_crc_pos, 32) != RTV_OK) { + fib_crc_pos += 32; + fib_crc_err_sum++; + if (fib_crc_err_sum >= 12) + return FIC_CRC_ERR; + else + continue; + } + + ret = FIB_INIT_DEC(fic+fib_crc_pos); + if (ret == RTV_OK) { + if (ENS_DESC.svr_num) { + if ((ENS_DESC.svr_num == ENS_DESC.label_num) + && (ENS_DESC.label_flag == 1) + && (FIC_CONUT > 5)) { + FIC_CONUT = 0; + return FIC_DONE; + } + } + } + + fib_crc_pos += 32; + } + + return FIC_GOING; +} + + + +static BOOL fic_decode_run; + + +void rtvFICDEC_Init(void) +{ + UINT i; + + fic_decode_run = TRUE; + fib_crc_err_cnt = 0; + + FIC_CONUT = 0; + memset(&ENS_DESC, 0, sizeof(struct ENSEMBLE_DESC)); + + for (i = 0; i < MAX_SERV_COMP; i++) + ENS_DESC.svr_comp[i].SCidS = 0xFF; +} + + +enum E_RTV_FIC_DEC_RET_TYPE rtvFICDEC_Decode(unsigned char *fic_buf, + unsigned int fic_size) +{ + UINT ret; + unsigned int num_fib = fic_size >> 5; /* Divide by 32. */ + + ret = FIC_Init_Dec(fic_buf, num_fib, 0); + if (ret == FIC_DONE) + return RTV_FIC_RET_DONE; + else if (ret == FIC_CRC_ERR) { + fib_crc_err_cnt++; + if (fib_crc_err_cnt >= 7) + return RTV_FIC_RET_CRC_ERR; + } + + return RTV_FIC_RET_GOING; +} + + +void rtvFICDEC_Stop(void) +{ + /* Set the flag.*/ + fic_decode_run = FALSE; +} + +void rtvFICDEC_GetEnsembleInfo(struct ensemble_info_type *ensble, + unsigned long freq_khz) +{ + UINT i, j; + UINT comp_idx = 0; + UINT subch_idx = 0; + struct ENSEMBLE_DESC *desc = &ENS_DESC; + + ensble->ensem_freq = freq_khz; + ensble->ensem_id = desc->id; + + strncpy((char *)ensble->ensem_label, + desc->Label, RTV_MAX_ENSEMBLE_LABEL_SIZE); + + for (i = 0; i < desc->svr_num; i++) { + for (j = 0; j < desc->svr_desc[i].Num_ser_comp; j++) { + comp_idx = desc->svr_desc[i].ser_comp_num[j]; + switch (desc->svr_comp[comp_idx].TMID) { + case MSC_STREAM_AUDIO: + ensble->sub_ch[subch_idx].sub_ch_id + = desc->svr_comp[comp_idx].SubChid; + ensble->sub_ch[subch_idx].start_addr + = desc->svr_comp[comp_idx].START_Addr; + ensble->sub_ch[subch_idx].tmid + = desc->svr_comp[comp_idx].TMID; + ensble->sub_ch[subch_idx].svc_type + = desc->svr_comp[comp_idx].ASCTy; + ensble->sub_ch[subch_idx].svc_id + = desc->svr_desc[i].Sid; + memcpy(ensble->sub_ch[subch_idx].svc_label, + desc->svr_desc[i].Label, + RTV_MAX_ENSEMBLE_LABEL_SIZE); + ensble->sub_ch[subch_idx].scids + = desc->svr_comp[comp_idx].SCidS; + ensble->sub_ch[subch_idx].ecc = Ensemble_ECC; + subch_idx++; + break; + + case MSC_STREAM_DATA: + ensble->sub_ch[subch_idx].sub_ch_id + = desc->svr_comp[comp_idx].SubChid; + ensble->sub_ch[subch_idx].start_addr + = desc->svr_comp[comp_idx].START_Addr; + ensble->sub_ch[subch_idx].tmid + = desc->svr_comp[comp_idx].TMID; + ensble->sub_ch[subch_idx].svc_type + = desc->svr_comp[comp_idx].DSCTy; + ensble->sub_ch[subch_idx].svc_id + = desc->svr_desc[i].Sid; + memcpy(ensble->sub_ch[subch_idx].svc_label, + desc->svr_desc[i].Label, + RTV_MAX_ENSEMBLE_LABEL_SIZE); + ensble->sub_ch[subch_idx].scids + = desc->svr_comp[comp_idx].SCidS; + ensble->sub_ch[subch_idx].ecc = Ensemble_ECC; + subch_idx++; + break; + + case FIDC: /* No service */ +/* + ensble.sub_ch[subch_idx].tmid + = desc->svr_comp[comp_idx].TMID; + ensble.sub_ch[subch_idx].svc_id + = desc->svr_desc[i].Sid; + memcpy(ensble.sub_ch[subch_idx].svc_label, + desc->svr_desc[i].Label, + RTV_MAX_ENSEMBLE_LABEL_SIZE); + ensble->sub_ch[subch_idx].scids + = desc->svr_comp[comp_idx].SCidS; + ensble->sub_ch[subch_idx].ecc = Ensemble_ECC; + subch_idx++; +*/ + break; + + case MSC_PACKET_DATA: +/* + ensble->sub_ch[subch_idx].sub_ch_id + = desc->svr_comp[comp_idx].SubChid; + ensble->sub_ch[subch_idx].start_addr + = desc->svr_comp[comp_idx].START_Addr; + ensble->sub_ch[subch_idx].tmid + = desc->svr_comp[comp_idx].TMID; + ensble->sub_ch[subch_idx].svc_type + = desc->svr_comp[comp_idx].DSCTy; + ensble->sub_ch[subch_idx].svc_id + = desc->svr_desc[i].Sid; + memcpy(ensble->sub_ch[subch_idx].svc_label, + desc->svr_desc[i].Label, + RTV_MAX_ENSEMBLE_LABEL_SIZE); + ensble->sub_ch[subch_idx].scids + = desc->svr_comp[comp_idx].SCidS; + ensble->sub_ch[subch_idx].ecc = Ensemble_ECC; + subch_idx++; +*/ + break; + default: + /*RTV_DBGMSG0("NO TMID\n");*/ + DPRINTK("NO TMID\n"); + break; + } + +/* + RTV_DBGMSG2("ensble->sub_ch[%d].sub_ch_id: %d\n", + subch_idx, ensble->sub_ch[subch_idx].sub_ch_id); + RTV_DBGMSG2("ensble->sub_ch[%d].start_addr: %d\n", + subch_idx, ensble->sub_ch[subch_idx].start_addr); + RTV_DBGMSG2("ensble->sub_ch[%d].tmid: %d\n", + subch_idx, ensble->sub_ch[subch_idx].tmid); + RTV_DBGMSG2("ensble->sub_ch[%d].svc_type: %d\n", + subch_idx, ensble->sub_ch[subch_idx].svc_type); + RTV_DBGMSG2("ensble->sub_ch[%d].svc_id: 0x%lX\n", + subch_idx, ensble->sub_ch[subch_idx].svc_id); + + desc->svr_desc[i].Label[RTV_MAX_ENSEMBLE_LABEL_SIZE] = '\0'; + RTV_DBGMSG2("ensble->sub_ch[%d].ServiceLabel: %s\n\n", + subch_idx, desc->svr_desc[i].Label); +*/ + } + } + + ensble->tot_sub_ch = subch_idx; +/* + RTV_DBGMSG1("ensble->tot_sub_ch: %d\n\n", ensble->tot_sub_ch); +*/ +} + diff --git a/drivers/media/tdmb/mtv319/mtv319_ficdec.h b/drivers/media/tdmb/mtv319/mtv319_ficdec.h new file mode 100644 index 000000000000..920a0c6ba470 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_ficdec.h @@ -0,0 +1,52 @@ +/* + * + * File name: mtv319_ficdec.h + * + * Description : RAONTECH FIC Decoder API header file. + * + * Copyright (C) (2013, RAONTECH) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MTV319_FICDEC_H__ +#define __MTV319_FICDEC_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "mtv319.h" +#include "tdmb.h" + +#define RTV_MAX_NUM_SUB_CH 64 +#define RTV_MAX_ENSEMBLE_LABEL_SIZE 16 +#define RTV_MAX_SERVICE_LABEL_SIZE 16 + +enum E_RTV_FIC_DEC_RET_TYPE { + RTV_FIC_RET_GOING = 0, + RTV_FIC_RET_DONE, + RTV_FIC_RET_CRC_ERR +}; + +void rtvFICDEC_GetEnsembleInfo(struct ensemble_info_type *ensble, + ULONG freq_khz); +enum E_RTV_FIC_DEC_RET_TYPE rtvFICDEC_Decode(U8 *fic_buf, UINT fic_size); +void rtvFICDEC_Init(void); + + + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_FICDEC_H__ */ + diff --git a/drivers/media/tdmb/mtv319/mtv319_ficdec_internal.h b/drivers/media/tdmb/mtv319/mtv319_ficdec_internal.h new file mode 100644 index 000000000000..09b614707d2f --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_ficdec_internal.h @@ -0,0 +1,699 @@ +/* +* +* File name: mtv319_ficdec_internal.h +* +* Description : RAONTECH TV FIC Decoder internal header file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __MTV319_FICDEC_INTERNAL_H__ +#define __MTV319_FICDEC_INTERNAL_H__ + +/********************/ +/* Header Files */ +/********************/ +#include "mtv319_ficdec.h" + + +#define RTV_FAIL (-1) +#define RTV_UNLOCK (-10) +#define RTV_OK 0 +#define RTV_SCAN_OK 1 +#define RTV_LOCK_CHECK 10 +#define RTV_NOTHING 2 + + +#define FIC_GOING 0 +#define FIC_LABEL 0x01 +#define FIC_APP_TYPE 0x10 +#define FIC_DONE 0x11 +#define FIC_CRC_ERR 0x44 + + +/**************************/ +/* FIC Definition */ +/**************************/ +#define MSC_STREAM_AUDIO 0x00 +#define MSC_STREAM_DATA 0x01 +#define FIDC 0x02 +#define MSC_PACKET_DATA 0x03 + +/* Ensemble, service, service component label number */ +#define LABEL_NUM 17 + +/* maximum service component number in Ensemble channel */ +#define MAX_SERV_COMP 64 + +/* maximum service component number in one service */ +#define MAX_SUB_CH_NUM 12 + +/* maximum service number in one ensemble */ +#define MAX_SERVICE_NUM 64 + +/*maximum number of user applications */ +#define USER_APP_NUM 6 + +/* get FIC Time information complete */ +#define ALL_FLAG_MATCH 0x11 + +/* get FIC type0 extension10 complete */ +#define TIME_FLAG 0x01 + +/* get FIC type0 extension9 complete */ +#define LTO_FLAG 0x10 + +#define Unspec_DATA 0 +#define TMC_Type 1 +#define EWS_Type 2 +#define ITTS_Type 3 +#define Paging_Type 4 +#define TDC_Type 5 +#define KDMB_Type 24 +#define Em_IP_Type 59 +#define MOT_Type 60 +#define PS_noDSCTy 61 + +/****************************/ +/* FIC Data structure */ +/****************************/ +/*! Date and Time information for Application user */ +struct DATE_TIME_INFO { + U32 MJD; + U8 LSI; + U8 conf_ind; + U8 utc_flag; + U8 apm_flag; + U8 time_flag; + U8 get_flag; + U16 years; + U8 months_dec; + char months_ste[4]; + char weeks[4]; + U8 days; + U8 hours; + U8 minutes; + U8 seconds; + U16 milliseconds; + U8 LTO; /*Local Time Offset */ +}; + +/*! Service Component Descriptor for Application user */ +struct SVR_COM_DESP { + S32 BIT_RATE; + S32 P_L; + S32 START_Addr; + S32 SUB_CH_Size; + U8 TMID; + U8 ASCTy; + U8 SubChid; + U8 P_S; + U8 CA_flag; + U8 DSCTy; + U8 FIDCid; + U8 TCid; + U8 Ext; + U16 SCid; + U8 DG_flag; + U16 Packet_add; + U16 CA_Org; + U8 FEC_scheme; + U8 language; + U8 charset; + char Label[LABEL_NUM]; + U32 Sid; + U8 SCidS; + U8 Num_User_App; + U16 User_APP_Type[USER_APP_NUM]; + U8 User_APP_data_length[USER_APP_NUM]; + U8 User_APP_data[24]; +}; + +/*! Service Descriptor for Application user */ +struct SERVICE_DESC { + /*MCI Information*/ + U32 Sid; + U8 Country_id; + U32 Service_ref; + U8 ECC; + U8 Local_flag; + U8 CAID; + U8 Num_ser_comp; + U8 P_D; + /*SI Information */ + U8 label_flag; + U8 charset; + char Label[LABEL_NUM]; + /*Program type */ + U8 int_code; + U8 ser_comp_num[MAX_SUB_CH_NUM]; +}; + +/*! FIDC Descriptor for Application user */ +struct FIDC_EWS_Region { + U8 Sub_Region[11]; +}; + +struct FIDC_DESC { + U8 EWS_current_segmemt; + U8 EWS_total_segmemt; + U8 EWS_Message_ID; + S8 EWS_category[4]; + U8 EWS_priority; + U32 EWS_time_MJD; + U8 EWS_time_Hours; + U8 EWS_time_Minutes; + U8 EWS_region_form; + U8 EWS_region_num; + U8 EWS_Rev; + struct FIDC_EWS_Region EWS_Region[15]; + U8 EWS_short_sentence[409]; +}; + +/*! Ensemble Descriptor for Application user */ +struct ENSEMBLE_DESC { + /*COMMON Information*/ + U32 svr_num; + U32 svr_comp_num; + U32 label_num; + /*MCI Information*/ + U16 id; + U8 change_flag; + U8 Alarm_flag; + /*SI Information*/ + U8 charset; + char Label[LABEL_NUM]; + U32 freq; + U8 label_flag; + + struct DATE_TIME_INFO date_time_info; + struct SERVICE_DESC svr_desc[MAX_SERVICE_NUM]; + struct SVR_COM_DESP svr_comp[MAX_SERV_COMP]; + struct FIDC_DESC fidc_desc; + +}; + + +/*****************/ +/* EXTERNS */ +/*****************/ +extern char *PROGRAM_TYPE_CODE16[32]; +extern char *USER_APP_TYPE_CODE[11]; +extern char *FIDC_EXT_CODE[3]; +extern char *ASCTy[3]; +extern char *DSCTy[11]; +extern char *ANNOUNCEMENT_TYPE_CODE[12]; +extern S32 SUBCH_UEP_TABLE[64][3]; +extern char *WEEK_TABLE[8]; +extern char *MONTH_TABLE[12]; +extern struct ENSEMBLE_DESC ENS_DESC, NEXT_ENS_DESC; +extern struct ENSEMBLE_DESC ENS_DESC1, NEXT_ENS_DESC1; +extern struct ENSEMBLE_DESC ENS_DESC2, NEXT_ENS_DESC2; +extern char *EWS_CATEGORY[67][3]; +extern char *EWS_PRIORITY_TABLE[4]; +extern char *EWS_REGION_FORM_TABLE[4]; +extern char *EWS_OFFICIAL_ORGANIZATION_TABLE[4]; + + + +/********************/ +/* FIC Definition */ +/********************/ +#define PN_FIB_END_MARKER (0xFF) + +/****************************/ +/* FIC Parser function */ +/****************************/ +S32 FIB_Init_Dec(U8 *); +S32 MCI_SI_DEC(U8); +S32 SI_LABEL_DEC1(U8); +S32 SI_LABEL_DEC2(U8); +S32 FIDC_DEC(U8); +S32 CA_DEC(U8); +S32 RESERVED1(U8); +S32 RESERVED2(U8); +S32 RESERVED3(U8); + +/*****************************/ +/* FIG Data Type structure */ +/*****************************/ +struct FIG_DATA { + U8 type; + U8 length; + U8 *data; + U8 byte_cnt; + U8 bit_cnt; +}; + +/****************************/ +/* FIG type 0 data field */ +/****************************/ +struct FIG_TYPE0 { + U8 C_N; + U8 OE; + U8 P_D; + U8 Ext; +}; + +/* Ensemble Information */ +struct FIG_TYPE0_Ext0 { + U16 Eid; + U8 Country_ID; + U32 Ensemble_Ref; + U8 Change_flag; + U8 AI_flag; + U8 CIF_Count0; + U8 CIF_Count1; + U8 Occurence_Change; +}; + +/* Structure of the sub-channel organization field */ +struct FIG_TYPE0_Ext1 { + U8 SubChid; + U32 StartAdd; + U8 S_L_form; + U32 Size_Protection; + U8 Table_sw; + U8 Table_index; + U8 Option; + U8 Protection_Level; + U32 Sub_ch_size; +}; + +/* Structure of the service organization field */ +struct FIG_TYPE0_Ext2_ser_comp_des { + U8 TMID; + U8 ASCTy; + U8 SubChid; + U8 P_S; + U8 CA_flag; + U8 DSCTy; + U8 FIDCid; + U8 TCid; + U8 Ext; + U16 SCid; +}; + +/* Basic service and service component definition structure */ +struct FIG_TYPE0_Ext2 { + U32 Sid; + U8 Country_id; + U32 Service_ref; + U8 ECC; + U8 Local_flag; + U8 CAID; + U8 Num_ser_comp; + struct FIG_TYPE0_Ext2_ser_comp_des svr_comp_des[MAX_SERV_COMP]; +}; + +/* Structure of the service component in packet mode */ +struct FIG_TYPE0_Ext3 { + U16 SCid; + U8 CA_Org_flag; + U8 DG_flag; + U8 DSCTy; + U8 SubChid; + U16 Packet_add; + U16 CA_Org; +}; + +/* Structure of the service component field in Stream mode or FIC */ +struct FIG_TYPE0_Ext4 { + U8 M_F; + U8 SubChid; + U8 FIDCid; + U16 CA_Org; +}; + +/* Structure of the service component language field */ +struct FIG_TYPE0_Ext5 { + U8 L_S_flag; + U8 MSC_FIC_flag; + U8 SubChid; + U8 FIDCid; + U16 SCid; + U8 Language; +}; + +/* Service Linking Information */ +struct FIG_TYPE0_Ext6 { + U8 id_list_flag; + U8 LA; + U8 S_H; + U8 ILS; + U32 LSN; + U8 id_list_usage; + U8 idLQ; + U8 Shd; + U8 Num_ids; + U16 id[12]; + U8 ECC[12]; + U32 Sid[12]; +}; + +/* Structure of the service component global definition field */ +struct FIG_TYPE0_Ext8 { + U32 Sid; + U8 Ext_flag; + U8 SCidS; + U8 L_S_flag; + U8 MSC_FIC_flag; + U8 SubChid; + U8 FIDCid; + U32 SCid; +}; + +/* Structure of Country, LTO International field */ +struct FIG_TYPE0_Ext9 { + U8 Ext_flag; + U8 LTO_unique; + U8 Ensemble_LTO; + U8 Ensemble_ECC; + U8 Inter_Table_ID; + U8 NumOfSubField; + U8 Num_Ser[6]; + U8 LTO[6]; + U8 ECC[6]; + U32 Sid[6][3]; +}; + +/* Structure of the data and time field */ +struct FIG_TYPE0_Ext10 { + U32 MJD; + U8 LSI; + U8 Conf_ind; + U8 UTC_flag; + U32 UTC; + U8 Hours; + U8 Minutes; + U8 Seconds; + U16 Milliseconds; +}; + +/* Structure of the Region Definition */ +struct FIG_TYPE0_Ext11 { + U8 GATy; + U8 G_E_flag; + U8 Upper_part; + U8 Lower_part; + U8 length_TII_list; + U8 Mainid[12]; + U8 Length_Subid_list; + U8 Subid[36]; + U32 Latitude_Coarse; + U32 Longitude_coarse; + U32 Extent_Latitude; + U32 Extent_Longitude; +}; + +/* Structure of the User Application Information */ +struct FIG_TYPE0_Ext13 { + U32 Sid; + U8 SCidS; + U8 Num_User_App; + U16 User_APP_Type[6]; + U8 User_APP_data_length[6]; + U8 CA_flag; + U8 CA_Org_flag; + U8 X_PAD_App_Ty; + U8 DG_flag; + U8 DSCTy; + U16 CA_Org; + U8 User_APP_data[24]; +}; + +/* FEC sub-channel organization */ +struct FIG_TYPE0_Ext14 { + U8 SubChid; + U8 FEC_scheme; +}; + +/* Program Number structure */ +struct FIG_TYPE0_Ext16 { + U16 Sid; + U16 PNum; + U8 Continuation_flag; + U8 Update_flag; + U16 New_Sid; + U16 New_PNum; +}; + +/* Program Type structure */ +struct FIG_TYPE0_Ext17 { + U16 Sid; + U8 S_D; + U8 P_S; + U8 L_flag; + U8 CC_flag; + U8 Language; + U8 Int_code; + U8 Comp_code; +}; + +/* Announcement support */ +struct FIG_TYPE0_Ext18 { + U16 Sid; + U16 ASU_flags; + U8 Num_clusters; + U8 Cluster_ID[23]; +}; + +/* Announcement switching */ +struct FIG_TYPE0_Ext19 { + U8 Cluster_ID; + U16 ASW_flags; + U8 New_flag; + U8 Region_flag; + U8 SubChid; + U8 Regionid_Lower_Part; +}; + +/* Frequency Information */ +struct FIG_TYPE0_Ext21 { + U16 ResionID; + U8 Length_of_FI_list; + U16 id_field; + U8 R_M; + U8 Continuity_flag; + U8 Length_Freq_list; + U8 Control_field[5]; + U8 id_field2[4]; + U32 Freq_a[5]; + U8 Freq_b[17]; + U16 Freq_c[8]; + U16 Freq_d[7]; +}; + +/* Transmitter Identification Information (TII) database */ +struct FIG_TYPE0_Ext22 { + U8 M_S; + U8 Mainid; + U32 Latitude_coarse; + U32 Longitude_coarse; + U8 Latitude_fine; + U8 Longitude_fine; + U8 Num_Subid_fields; + U8 Subid[4]; + U16 TD[4]; + U16 Latitude_offset[4]; + U16 Longitude_offset[4]; +}; + +/* Other Ensemble Service */ +struct FIG_TYPE0_Ext24 { + U32 Sid; + U8 CAid; + U8 Number_Eids; + U16 Eid[12]; +}; + +/* Other Ensemble Announcement support */ +struct FIG_TYPE0_Ext25 { + U32 Sid; + U32 ASU_flag; + U8 Number_Eids; + U8 Eid[12]; +}; + +/* Other Ensemble Announcement switching */ +struct FIG_TYPE0_Ext26 { + U8 Cluster_id_Current_Ensemble; + U32 Asw_flags; + U8 New_flag; + U8 Region_flag; + U8 Region_id_current_Ensemble; + U32 Eid_Other_Ensemble; + U8 Cluster_id_other_Ensemble; + U8 Region_id_Oter_Ensemble; +}; + +/* FM Announcement support */ +struct FIG_TYPE0_Ext27 { + U32 Sid; + U8 Number_PI_Code; + U32 PI[12]; +}; + +/* FM Announcement switching */ +struct FIG_TYPE0_Ext28 { + U8 Cluster_id_Current_Ensemble; + U8 New_flag; + U8 Region_id_Current_Ensemble; + U32 PI; +}; + +/* FIC re-direction */ +struct FIG_TYPE0_Ext31 { + U32 FIG0_flag_field; + U8 FIG1_flag_field; + U8 FIG2_flag_field; +}; + +/****************************/ +/* FIG type 5 data field */ +/****************************/ +struct FIG_TYPE5 { + U8 D1; + U8 D2; + U8 TCid; + U8 Ext; +}; + +/* Paging */ +struct FIG_TPE5_Ext0 { + U8 SubChid; + U16 Packet_add; + U8 F1; + U8 F2; + U16 LFN; + U8 F3; + U16 Time; + U8 CAid; + U16 CA_Org; + U32 Paging_user_group; +}; + +/* TMC */ +struct FIG_TYPE5_Ext1 { + U32 TMC_User_Message[30]; + U16 TMC_System_Message[30]; +}; + +/* EWS */ +struct FIG_EWS_Region { + U8 Sub_Region[11]; +}; + +struct FIG_TYPE5_Ext2 { + U8 current_segmemt; + U8 total_segmemt; + U8 Message_ID; + S8 category[4]; + U8 priority; + U32 time_MJD; + U8 time_Hours; + U8 time_Minutes; + U8 region_form; + U8 region_num; + U8 Rev; + struct FIG_EWS_Region Region[15]; + U8 data[409]; +}; + +/****************************/ +/* FIG type 6 data field */ +/****************************/ +struct FIG_TYPE6 { + U8 C_N; + U8 OE; + U8 P_D; + U8 LEF; + U8 ShortCASysId; + U32 Sid; + U16 CASysId; + U16 CAIntChar; +}; + +/***************************/ +/* Function declarations */ +/***************************/ + +/* FIG TYPE 0 function */ +S32 Get_FIG0_EXT0(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT1(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT2(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT3(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT4(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT5(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT6(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT7(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT8(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT9(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT10(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT11(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT12(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT13(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT14(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT15(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT16(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT17(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT18(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT19(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT20(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT21(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT22(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT23(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT24(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT25(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT26(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT27(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT28(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT29(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT30(U8 fic_cmd, U8 P_D, U8 C_N); +S32 Get_FIG0_EXT31(U8 fic_cmd, U8 P_D, U8 C_N); + +/* FIG TYPE 1 function */ +S32 Get_FIG1_EXT0(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT1(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT2(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT3(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT4(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT5(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT6(U8 fic_cmd, U8 Char_Set); +S32 Get_FIG1_EXT7(U8 fic_cmd, U8 Char_Set); + +/* FIG TYPE 2 function */ +S32 Get_FIG2_EXT0(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT1(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT2(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT3(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT4(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT5(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT6(U8 fic_cmd, U8 Seg_Index); +S32 Get_FIG2_EXT7(U8 fic_cmd, U8 Seg_Index); + +/* FIG TYPE 5 function */ +S32 Get_FIG5_EXT0(U8 D1, U8 D2, U8 fic_cmd, U8 TCid); +S32 Get_FIG5_EXT1(U8 D1, U8 D2, U8 fic_cmd, U8 TCid); +S32 Get_FIG5_EXT2(U8 D1, U8 D2, U8 fic_cmd, U8 TCid); + + + +U8 GET_SUBCH_INFO(struct FIG_TYPE0_Ext1 *type0_ext1 + , S32 *BIT_RATE, S32 *SUB_CH_Size, S32 *P_L); +U8 GET_DATE_TIME(struct DATE_TIME_INFO *time_desc); +U8 GET_EWS_TIME(struct DATE_TIME_INFO *time_desc); + + + +#endif /* __MTV319_FICDEC_INTERNAL_H__ */ diff --git a/drivers/media/tdmb/mtv319/mtv319_internal.h b/drivers/media/tdmb/mtv319/mtv319_internal.h new file mode 100644 index 000000000000..731a58229e13 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_internal.h @@ -0,0 +1,696 @@ +/* +* +* File name: mtv319_internal.h +* +* Description : MTV319 internal header file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __MTV319_INTERNAL_H__ +#define __MTV319_INTERNAL_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "mtv319.h" + #include "mtv319_cifdec.h" + +#if defined(RTV_MULTIPLE_CHANNEL_MODE) && defined(RTV_MCHDEC_IN_DRIVER) + #define TDMB_CIF_MODE_DRIVER /* Internal use only */ +#endif + + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #if defined(RTV_INTR_POLARITY_LOW_ACTIVE) + #define SPI_INTR_POL_ACTIVE 0x00 + #elif defined(RTV_INTR_POLARITY_HIGH_ACTIVE) + #define SPI_INTR_POL_ACTIVE (1<<7) + #endif +#else + #if defined(RTV_INTR_POLARITY_LOW_ACTIVE) + #define I2C_INTR_POL_ACTIVE 0x08 /* level low */ + #elif defined(RTV_INTR_POLARITY_HIGH_ACTIVE) + #define I2C_INTR_POL_ACTIVE 0x18 /* level high */ + #endif +#endif + +struct RTV_REG_INIT_INFO { + U8 bReg; + U8 bVal; +}; + + +struct RTV_REG_MASK_INFO { + U8 bReg; + U8 bMask; + U8 bVal; +}; + +enum RTV_TDMB_CH_IDX_TYPE { + RTV_TDMB_CH_IDX_7A = 0, /* 175280: 7A */ + RTV_TDMB_CH_IDX_7B, /* 177008: 7B */ + RTV_TDMB_CH_IDX_7C, /* 178736: 7C */ + RTV_TDMB_CH_IDX_8A, /* 181280: 8A */ + RTV_TDMB_CH_IDX_8B, /* 183008: 8B */ + RTV_TDMB_CH_IDX_8C, /* 184736: 8C */ + RTV_TDMB_CH_IDX_9A, /* 187280: 9A */ + RTV_TDMB_CH_IDX_9B, /* 189008: 9B */ + RTV_TDMB_CH_IDX_9C, /* 190736: 9C */ + RTV_TDMB_CH_IDX_10A, /* 193280: 10A */ + RTV_TDMB_CH_IDX_10B, /* 195008: 10B */ + RTV_TDMB_CH_IDX_10C, /* 196736: 10C */ + RTV_TDMB_CH_IDX_11A, /* 199280: 11A */ + RTV_TDMB_CH_IDX_11B, /* 201008: 11B */ + RTV_TDMB_CH_IDX_11C, /* 202736: 11C */ + RTV_TDMB_CH_IDX_12A, /* 205280: 12A */ + RTV_TDMB_CH_IDX_12B, /* 207008: 12B */ + RTV_TDMB_CH_IDX_12C, /* 208736: 12C */ + RTV_TDMB_CH_IDX_13A, /* 211280: 13A */ + RTV_TDMB_CH_IDX_13B, /* 213008: 13B */ + RTV_TDMB_CH_IDX_13C, /* 214736: 13C */ + MAX_NUM_RTV_TDMB_CH_IDX +}; + +struct RTV_ADC_CFG_INFO { + U16 wFEBD; + U8 bREFD; + U32 dwTNCO; +}; + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + #if defined(RTV_TSIF_SPEED_3_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (12<<0) + #elif defined(RTV_TSIF_SPEED_4_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (8<<0) + #elif defined(RTV_TSIF_SPEED_5_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (6<<0) + #elif defined(RTV_TSIF_SPEED_6_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (5<<0) + #elif defined(RTV_TSIF_SPEED_8_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (4<<0) + #elif defined(RTV_TSIF_SPEED_10_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (3<<0) + #elif defined(RTV_TSIF_SPEED_15_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (2<<0) + #elif defined(RTV_TSIF_SPEED_30_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (1<<0) + #elif defined(RTV_TSIF_SPEED_60_Mbps) + #define RTV_FEC_TSIF_OUT_SPEED (0<<0) + #else + #error "Code not present" + #endif +#endif /* #if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) */ + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #if (RTV_SRC_CLK_FREQ_KHz == 4000) /* FPGA */ + #define RTV_SPI_INTR_DEACT_PRD_VAL 0x51 + + #elif (RTV_SRC_CLK_FREQ_KHz == 13000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 16000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 16384) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 18000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 19200) /* 1 clk: 52.08ns */ + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 24000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 24576) /* 1 clk: 40.7ns */ + #define RTV_SPI_INTR_DEACT_PRD_VAL ((7<<4)|2)/*about 10us*/ + + #elif (RTV_SRC_CLK_FREQ_KHz == 26000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 27000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 32000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 32768) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 36000) /* 1clk: 27.7 ns */ + #define RTV_SPI_INTR_DEACT_PRD_VAL ((7<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 38400) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 40000) + #define RTV_SPI_INTR_DEACT_PRD_VAL ((6<<4)|3) + + #elif (RTV_SRC_CLK_FREQ_KHz == 48000) /* 1clk: 20.8 ns */ + #define RTV_SPI_INTR_DEACT_PRD_VAL ((9<<4)|0) + #else + #error "Code not present" + #endif +#endif /* #if defined(RTV_IF_SPI) */ + +#if (RTV_TSP_XFER_SIZE == 188) + #define N_DATA_LEN_BITVAL 0x02 + #define ONE_DATA_LEN_BITVAL 0x00 +#elif (RTV_TSP_XFER_SIZE == 204) + #define N_DATA_LEN_BITVAL 0x03 + #define ONE_DATA_LEN_BITVAL (1<<5) +#endif + +#ifdef RTV_MSC_HDR_ENABLED + #define DMB_HEADER_LEN_BITVAL (1<<2) /* 4bytes header */ +#else + #define DMB_HEADER_LEN_BITVAL 0x00 +#endif + + + +#define SPI_OVERFLOW_INTR 0x02 +#define SPI_UNDERFLOW_INTR 0x20 +#define SPI_THRESHOLD_INTR 0x08 +#define SPI_INTR_BITS (SPI_THRESHOLD_INTR|SPI_UNDERFLOW_INTR|SPI_OVERFLOW_INTR) + + +#define TOP_PAGE 0x00 +#define HOST_PAGE 0x00 +#define OFDM_PAGE 0x08 +#define FEC_PAGE 0x09 +#define SPI_CTRL_PAGE 0x0E +#define RF_PAGE 0x0F +#define SPI_MEM_PAGE 0xFF /* Temp value. > 15 */ + + +#define DEMOD_0SC_DIV2_ON 0x80 +#define DEMOD_0SC_DIV2_OFF 0x00 + +#if (RTV_SRC_CLK_FREQ_KHz >= 32000) + #define DEMOD_OSC_DIV2 DEMOD_0SC_DIV2_ON +#else + #define DEMOD_OSC_DIV2 DEMOD_0SC_DIV2_OFF +#endif + + +#define MAP_SEL_REG 0x03 +#define MAP_SEL_VAL(page) (DEMOD_OSC_DIV2|page) + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #define RTV_REG_MAP_SEL(page) g_bRtvPage = page + #define RTV_REG_GET_MAP_SEL g_bRtvPage +#else + #define RTV_REG_MAP_SEL(page)\ + do {\ + g_bRtvPage = MAP_SEL_REG;\ + RTV_REG_SET(MAP_SEL_REG, MAP_SEL_VAL(page));\ + g_bRtvPage = page;\ + } while (0) + + #define RTV_REG_GET_MAP_SEL\ + (RTV_REG_GET(MAP_SEL_REG) & ~DEMOD_OSC_DIV2) +#endif + +#define TDMB_FREQ_START__KOREA 175280 +#define TDMB_FREQ_STEP__KOREA 1728 /* about... */ + +/* To use at open FIC */ +enum E_TDMB_STATE { + TDMB_STATE_INIT = 0, + TDMB_STATE_SCAN, + TDMB_STATE_PLAY +}; + +enum E_RTV_FIC_OPENED_PATH_TYPE { + FIC_NOT_OPENED = 0, + FIC_OPENED_PATH_NOT_USE_IN_PLAY, + FIC_OPENED_PATH_I2C_IN_SCAN, + FIC_OPENED_PATH_TSIF_IN_SCAN, + FIC_OPENED_PATH_I2C_IN_PLAY, + FIC_OPENED_PATH_TSIF_IN_PLAY +}; + +extern BOOL g_fRtvFicOpened; + + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +extern enum E_RTV_FIC_OPENED_PATH_TYPE g_nRtvFicOpenedStatePath; +#endif + +extern U8 g_bRtvIntrMaskReg; + +/*============================================================================== + * + * Common inline functions. + * + *============================================================================*/ + +/* Forward prototype. */ + +static INLINE void rtv_DisableTSIF(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xAA, 0x00); +} + +static INLINE void rtv_EnableTSIF(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xAA, 0x7F); +} + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +static INLINE void rtv_ConfigureTsifFormat(void) +{ +#if defined(RTV_TSIF_FORMAT_0) /* EN_high, CLK_rising */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x80); + RTV_REG_SET(0xAF, 0x00); + +#elif defined(RTV_TSIF_FORMAT_1) /* EN_high, CLK_falling */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x00); + RTV_REG_SET(0xAF, 0x00); + +#elif defined(RTV_TSIF_FORMAT_2) /* EN_low, CLK_rising */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x80); + RTV_REG_SET(0xAF, 0x10); + +#elif defined(RTV_TSIF_FORMAT_3) /* EN_low, CLK_falling */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x00); + RTV_REG_SET(0xAF, 0x10); + +#elif defined(RTV_TSIF_FORMAT_4) /* EN_high, CLK_rising + 1CLK add */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x84); + RTV_REG_SET(0xAF, 0x00); + +#elif defined(RTV_TSIF_FORMAT_5) /* EN_high, CLK_falling + 1CLK add */ + RTV_REG_SET(0xA4, 0x09); + RTV_REG_SET(0xA5, 0x04); + RTV_REG_SET(0xAF, 0x00); + +#elif defined(RTV_TSIF_FORMAT_6) /* Parallel: EN_high, CLK_falling */ + RTV_REG_SET(0xA4, 0x01); + RTV_REG_SET(0xA5, 0x00); + RTV_REG_SET(0xAF, 0x00); +#else + #error "Code not present" +#endif + +#ifdef RTV_NULL_PID_GENERATE +{ + U8 b0xA4 = RTV_REG_GET(0xA4); + RTV_REG_SET(0xA4, b0xA4|0x02); +} +#endif + +#ifdef RTV_ERROR_TSP_OUTPUT_DISABLE +{ + U8 b0xA5 = RTV_REG_GET(0xA5); + RTV_REG_SET(0xA5, b0xA5|0x40); +} +#endif +} +#endif /* #elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) */ + +static INLINE void rtv_DisablePadIntrrupt(void) +{ + RTV_REG_MAP_SEL(HOST_PAGE); +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + /* <2> SPI_INT0(GPP0) disable <4> I2C INT0 disable */ + RTV_REG_SET(0x1D, 0xC4); +#else + /* <2> SPI_INT0(GPP0) disable <4> I2C INT0 disable */ + RTV_REG_SET(0x1D, 0xD0); +#endif + +} + +static INLINE void rtv_EnablePadIntrrupt(void) +{ + RTV_REG_MAP_SEL(HOST_PAGE); +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + /* <2> SPI_INT0(GPP0) enable <4> I2C INT0 enable */ + RTV_REG_SET(0x1D, 0xC0); +#else + RTV_REG_SET(0x1D, 0xC0); +#endif +} + +static INLINE void rtv_StopDemod(void) +{ + U8 FEC_F8, FEC_FB; + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x10, 0xCA); + + RTV_REG_MAP_SEL(FEC_PAGE); + FEC_F8 = RTV_REG_GET(0xF8); +#ifdef RTV_FORCE_INSERT_SYNC_BYTE + FEC_F8 |= 0x02; +#endif + + FEC_FB = RTV_REG_GET(0xFB); + RTV_REG_SET(0xFB, (FEC_FB | 0x01)); + RTV_REG_SET(0xF8, (FEC_F8 | 0x80)); +} + + +static INLINE void rtv_SoftReset(void) +{ + U8 OFDM_10, FEC_F8, FEC_FB; + + RTV_REG_MAP_SEL(OFDM_PAGE); + OFDM_10 = RTV_REG_GET(0x10); + RTV_REG_SET(0x10, (OFDM_10 & 0xFE)); + RTV_REG_SET(0x10, (OFDM_10 | 0x01)); + + RTV_REG_MAP_SEL(FEC_PAGE); + FEC_F8 = RTV_REG_GET(0xF8); +#ifdef RTV_FORCE_INSERT_SYNC_BYTE + FEC_F8 |= 0x02; +#endif + + FEC_FB = RTV_REG_GET(0xFB); + RTV_REG_SET(0xFB, (FEC_FB | 0x01)); + RTV_REG_SET(0xFB, (FEC_FB & 0xFE)); + RTV_REG_SET(0xF8, (FEC_F8 | 0x80)); + RTV_REG_SET(0xF8, (FEC_F8 & 0x7F)); +} + +static INLINE void rtv_SetupInterruptThreshold(UINT nThresholdSize) +{ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + UINT nMod; + + nMod = nThresholdSize % RTV_TSP_XFER_SIZE; + if (nMod) /* next xfer align */ + nThresholdSize += (RTV_TSP_XFER_SIZE - nMod); + + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + RTV_REG_SET(0x23, nThresholdSize/188); + + /* Save for rtvTDMB_GetInterruptLevelSize() */ + g_nRtvInterruptLevelSize = nThresholdSize; +#endif +} + +/*============================================================================= +* +* T-DMB inline functions. +* +*============================================================================*/ +static INLINE void rtv_Disable_FIC(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x80); +} + +static INLINE void rtv_DisableFicTsifPath(void) +{ + U8 i2c0; + + RTV_REG_MAP_SEL(FEC_PAGE); + i2c0 = RTV_REG_GET(0x26); + i2c0 |= 0x01; + RTV_REG_SET(0x26, i2c0); +} + +static INLINE void rtv_EnableFicTsifPath(void) +{ + U8 i2c0; + + RTV_REG_MAP_SEL(FEC_PAGE); + i2c0 = RTV_REG_GET(0x26); + i2c0 &= ~0x01; + RTV_REG_SET(0x26, i2c0); +} + +static INLINE void rtv_DisableFicInterrupt(UINT nOpenedSubChNum) +{ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + if (!nOpenedSubChNum) { + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + g_bRtvIntrMaskReg |= SPI_INTR_BITS; /* for polling */ + RTV_REG_SET(0x24, g_bRtvIntrMaskReg); /* Disable interrupts. */ + + /* To clear interrupt and data. */ + RTV_REG_SET(0x2A, 1); + RTV_REG_SET(0x2A, 0); + } +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x17, 0xFF); +#endif +} + + +static INLINE void rtv_EnableFicInterrupt(UINT nOpenedSubChNum) +{ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #if defined(RTV_SPI_FIC_DECODE_IN_PLAY)\ + || defined(RTV_FIC__SCAN_I2C__PLAY_TSIF)\ + || defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + /* The size should equal to the size of MSC interrupt. */ + UINT nThresholdSize = RTV_SPI_CIF_MODE_INTERRUPT_SIZE; + #else + UINT nThresholdSize = 384; + #endif + + if (!nOpenedSubChNum) { + rtv_SetupInterruptThreshold(nThresholdSize); + + RTV_REG_SET(0x2A, 1); + RTV_REG_SET(0x2A, 0); + + /* Enable interrupts. */ + g_bRtvIntrMaskReg &= ~(SPI_INTR_BITS); + RTV_REG_SET(0x24, g_bRtvIntrMaskReg); + } + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x17, 0xEF); +#endif +} + +static INLINE void rtv_CloseFIC(UINT nOpenedSubChNum) +{ + rtv_Disable_FIC(); + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + rtv_DisableFicInterrupt(nOpenedSubChNum); + +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + switch (g_nRtvFicOpenedStatePath) { + case FIC_OPENED_PATH_I2C_IN_SCAN: /* No sub channel */ + case FIC_OPENED_PATH_I2C_IN_PLAY: + //#ifndef RTV_FIC_POLLING_MODE + RTV_REG_MAP_SEL(HOST_PAGE); + RTV_REG_SET(0x1A, 0x08); /* GPD3 PAD disable */ + rtv_DisableFicInterrupt(nOpenedSubChNum); /* From I2C intr */ + //#endif + break; + + case FIC_OPENED_PATH_TSIF_IN_SCAN: /* No sub channel */ + case FIC_OPENED_PATH_TSIF_IN_PLAY: /* Have sub channel */ + rtv_DisableFicTsifPath(); + break; + + case FIC_OPENED_PATH_NOT_USE_IN_PLAY: + #if defined(RTV_FIC__SCAN_I2C__PLAY_NA) + #ifndef RTV_FIC_POLLING_MODE + rtv_DisableFicInterrupt(1); + #endif + #elif defined(RTV_FIC__SCAN_TSIF__PLAY_NA) + rtv_DisableFicTsifPath(); + #endif + break; + + default: + break; + } +#endif +} + +static INLINE void rtv_OpenFIC_SPI_Play(void) +{ +#ifdef RTV_PLAY_FIC_HDR_ENABLED + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x04|N_DATA_LEN_BITVAL); /* out_en, hdr_on */ + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x00|N_DATA_LEN_BITVAL); /* out_en, no_hdr*/ +#endif +} + +static INLINE void rtv_OpenFIC_SPI_Scan(void) +{ +#ifdef RTV_FIC_POLLING_MODE + rtv_DisablePadIntrrupt(); +#else + rtv_EnablePadIntrrupt(); +#endif + + rtv_SetupInterruptThreshold(MTV319_FIC_BUF_SIZE); + + RTV_REG_SET(0x2A, 1); + RTV_REG_SET(0x2A, 0); + + g_bRtvIntrMaskReg &= ~(SPI_INTR_BITS); + RTV_REG_SET(0x24, g_bRtvIntrMaskReg); /* Enable interrupts. */ + +#ifdef RTV_SCAN_FIC_HDR_ENABLED + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x04|N_DATA_LEN_BITVAL); /* out_en, hdr_on */ + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x00|N_DATA_LEN_BITVAL); /* out_en, no_hdr*/ +#endif +} + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +static INLINE enum E_RTV_FIC_OPENED_PATH_TYPE rtv_OpenFIC_TSIF_Play(void) +{ + enum E_RTV_FIC_OPENED_PATH_TYPE ePath = FIC_OPENED_PATH_NOT_USE_IN_PLAY; + +#if defined(RTV_FIC__SCAN_I2C__PLAY_I2C)\ +|| defined(RTV_FIC__SCAN_TSIF__PLAY_I2C) + rtv_DisableFicTsifPath(); /* For I2C path */ + + #ifndef RTV_FIC_POLLING_MODE + RTV_REG_MAP_SEL(HOST_PAGE); + RTV_REG_SET(0x1A, 0x00); /* GPD3 PAD enable */ + #endif + + rtv_EnableFicInterrupt(1); + + ePath = FIC_OPENED_PATH_I2C_IN_PLAY; + +#elif defined(RTV_FIC__SCAN_I2C__PLAY_TSIF)\ +|| defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + rtv_EnableFicTsifPath(); + ePath = FIC_OPENED_PATH_TSIF_IN_PLAY; + +#elif defined(RTV_FIC__SCAN_I2C__PLAY_NA) + ePath = FIC_OPENED_PATH_NOT_USE_IN_PLAY; + +#elif defined(RTV_FIC__SCAN_TSIF__PLAY_NA) + rtv_DisableFicTsifPath(); + ePath = FIC_OPENED_PATH_NOT_USE_IN_PLAY; + +#else + #error "Code not present" +#endif + +#ifdef RTV_PLAY_FIC_HDR_ENABLED + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x04|N_DATA_LEN_BITVAL); /* out_en, hdr_on */ + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x00|N_DATA_LEN_BITVAL); /* out_en, no_hdr*/ +#endif + + return ePath; +} + + +static INLINE enum E_RTV_FIC_OPENED_PATH_TYPE rtv_OpenFIC_TSIF_Scan(void) +{ + enum E_RTV_FIC_OPENED_PATH_TYPE ePath = FIC_OPENED_PATH_NOT_USE_IN_PLAY; + +#if defined(RTV_FIC__SCAN_I2C__PLAY_NA)\ +|| defined(RTV_FIC__SCAN_I2C__PLAY_I2C)\ +|| defined(RTV_FIC__SCAN_I2C__PLAY_TSIF) + rtv_DisableFicTsifPath(); /* For I2C path */ + + #ifndef RTV_FIC_POLLING_MODE + RTV_REG_MAP_SEL(HOST_PAGE); + RTV_REG_SET(0x1A, 0x00); /* GPD3 PAD enable */ + #endif + + rtv_EnableFicInterrupt(1); + + ePath = FIC_OPENED_PATH_I2C_IN_SCAN; + +#elif defined(RTV_FIC__SCAN_TSIF__PLAY_NA)\ +|| defined(RTV_FIC__SCAN_TSIF__PLAY_I2C)\ +|| defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + rtv_EnableFicTsifPath(); + ePath = FIC_OPENED_PATH_TSIF_IN_SCAN; + +#else + #error "Code not present" +#endif + +#ifdef RTV_SCAN_FIC_HDR_ENABLED + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x04|N_DATA_LEN_BITVAL); /* out_en, hdr_on */ + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0xB2, 0x00|N_DATA_LEN_BITVAL); /* out_en, no_hdr*/ +#endif + + return ePath; +} +#endif /* #if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) */ + +static INLINE INT rtv_OpenFIC(enum E_TDMB_STATE eTdmbState) +{ + switch (eTdmbState) { + case TDMB_STATE_SCAN: + #if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + rtv_OpenFIC_SPI_Scan(); + #else + g_nRtvFicOpenedStatePath = rtv_OpenFIC_TSIF_Scan(); + #endif + break; + + case TDMB_STATE_PLAY: + #if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + rtv_OpenFIC_SPI_Play(); + #else + g_nRtvFicOpenedStatePath = rtv_OpenFIC_TSIF_Play(); + #endif + break; + + default: + return RTV_INVALID_FIC_OPEN_STATE; + } + + return RTV_SUCCESS; +} + +/*============================================================================= +* External functions for RAONTV driver core. +*============================================================================*/ +INT rtv_InitSystem(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_INTERNAL_H__ */ + + diff --git a/drivers/media/tdmb/mtv319/mtv319_port.c b/drivers/media/tdmb/mtv319/mtv319_port.c new file mode 100644 index 000000000000..77fc7dafdb9f --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_port.c @@ -0,0 +1,250 @@ +/* +* +* File name: mtv319_port.c +* +* Description : User-supplied Routines for RAONTECH TV Services. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include +#include + +#include "mtv319.h" +#include "mtv319_internal.h" +#include "mtv319_cifdec.h" + +#include "tdmb.h" + + +/* Declares a variable of gurad object if neccessry. */ +#if defined(__KERNEL__) +struct mutex raontv_guard; +#elif defined(WINCE) || defined(WINDOWS) || defined(WIN32) +CRITICAL_SECTION raontv_guard; +#else +/* non-OS and RTOS. */ +#endif + +#if defined(RTV_IF_SPI) +static struct spi_device *mtv_spi; +#else /* i2c */ +static struct i2c_client *mtv_i2c; +#endif + +void mtv319_set_port_if(unsigned long interface) +{ +#if defined(RTV_IF_SPI) + mtv_spi = (struct spi_device *)interface; +#else /* i2c */ + mtv_i2c = (struct i2c_client *)interface; +#endif +} + +#if defined(RTV_IF_SPI) +unsigned char mtv319_spi_read(unsigned char page, unsigned char reg) +{ + int ret; + u8 out_buf[4], in_buf[4]; + struct spi_message msg; + struct spi_transfer msg_xfer = { + .tx_buf = out_buf, + .rx_buf = in_buf, + .len = 4, + .cs_change = 0, + .delay_usecs = 0 + }; + + out_buf[0] = 0x90 | page; + out_buf[1] = reg; + out_buf[2] = 1; /* Read size */ + + spi_message_init(&msg); + spi_message_add_tail(&msg_xfer, &msg); + + ret = spi_sync(mtv_spi, &msg); + if (ret) { + DPRINTK("error: %d\n", ret); + return 0xFF; + } + +#if 0 + DPRINTK("0x%02X 0x%02X 0x%02X 0x%02X\n", + in_buf[0], in_buf[1], in_buf[2], in_buf[3]); +#endif + + return in_buf[MTV319_SPI_CMD_SIZE]; +} + +void mtv319_spi_read_burst(unsigned char page, unsigned char reg, + unsigned char *buf, int size) +{ + int ret; + u8 out_buf[MTV319_SPI_CMD_SIZE]; + struct spi_message msg; + struct spi_transfer xfer0 = { + .tx_buf = out_buf, + .rx_buf = buf, + .len = MTV319_SPI_CMD_SIZE, + .cs_change = 0, + .delay_usecs = 0 + }; + + struct spi_transfer xfer1 = { + .tx_buf = buf, + .rx_buf = buf, + .len = size, + .cs_change = 0, + .delay_usecs = 0, + }; + + out_buf[0] = 0xA0; /* Memory read */ + out_buf[1] = 0x00; + out_buf[2] = 188; /* Fix */ + + spi_message_init(&msg); + spi_message_add_tail(&xfer0, &msg); + spi_message_add_tail(&xfer1, &msg); + + ret = spi_sync(mtv_spi, &msg); + if (ret) { + DPRINTK("error: %d\n", ret); + return; + } +} + +void mtv319_spi_write(unsigned char page, unsigned char reg, unsigned char val) +{ + u8 out_buf[4]; + u8 in_buf[4]; + struct spi_message msg; + struct spi_transfer msg_xfer = { + .tx_buf = out_buf, + .rx_buf = in_buf, + .len = 4, + .cs_change = 0, + .delay_usecs = 0 + }; + int ret; + + out_buf[0] = 0x80 | page; + out_buf[1] = reg; + out_buf[2] = 1; /* size */ + out_buf[3] = val; + + spi_message_init(&msg); + spi_message_add_tail(&msg_xfer, &msg); + + ret = spi_sync(mtv_spi, &msg); + if (ret) + DPRINTK("error: %d\n", ret); +} + +void mtv319_spi_recover(unsigned char *buf, unsigned int intr_size) +{ + int ret; + struct spi_message msg; + struct spi_transfer msg_xfer = { + .tx_buf = buf, + .rx_buf = buf, + .len = MTV319_SPI_CMD_SIZE + intr_size, + .cs_change = 0, + .delay_usecs = 0, + }; + + memset(buf, 0xFF, MTV319_SPI_CMD_SIZE+intr_size); + + spi_message_init(&msg); + spi_message_add_tail(&msg_xfer, &msg); + + ret = spi_sync(mtv_spi, &msg); + if (ret) + DPRINTK("error: %d\n", ret); +} + +#else /* I2C */ +void mtv319_i2c_read_burst(unsigned char reg, unsigned char *buf, int size) +{ + int ret; + u8 wbuf[1] = {reg}; + + struct i2c_msg msg[2] = { + { + .addr = RTV_CHIP_ADDR>>1, + .flags = 0, + .buf = wbuf, + .len = 1 + }, + { + .addr = RTV_CHIP_ADDR>>1, + .flags = I2C_M_RD, + .buf = buf, + .len = size + } + }; + + ret = i2c_transfer(mtv_i2c->adapter, msg, 2); + if (ret != 2) { + DPRINTK("error: %d\n", ret); + } +} + +unsigned char mtv319_i2c_read(unsigned char chipid, unsigned char reg) +{ + int ret; + u8 wbuf[1] = {reg}; + u8 rbuf[1]; + + struct i2c_msg msg[2] = { + {.addr = chipid>>1, .flags = 0, .buf = wbuf, .len = 1}, + {.addr = chipid>>1, .flags = I2C_M_RD, .buf = rbuf, .len = 1} + }; + + ret = i2c_transfer(mtv_i2c->adapter, msg, 2); + if (ret != 2) { + DPRINTK("error: %d\n", ret); + return 0x00; + } + + return rbuf[0]; +} + +void mtv319_i2c_write(unsigned char chipid, unsigned char reg, unsigned char val) +{ + int ret; + u8 wbuf[2] = {reg, val}; + + struct i2c_msg msg = + {.addr = chipid>>1, .flags = 0, .buf = wbuf, .len = 2}; + + ret = i2c_transfer(mtv_i2c->adapter, &msg, 1); + if (ret != 1) { + DPRINTK("error: %d\n", ret); + } +} +#endif + +#ifdef RTV_SCAN_FIC_HDR_ENABLED +int mtv319_assemble_fic(unsigned char *fic_buf, const unsigned char *ts_data, + unsigned int ts_size) +{ + struct RTV_CIF_DEC_INFO cifdec; + + cifdec.fic_buf_ptr = fic_buf; + + rtvCIFDEC_Decode(&cifdec, ts_data, ts_size); + + return (int)cifdec.fic_size; +} +#endif + diff --git a/drivers/media/tdmb/mtv319/mtv319_port.h b/drivers/media/tdmb/mtv319/mtv319_port.h new file mode 100644 index 000000000000..421371d7f938 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_port.h @@ -0,0 +1,548 @@ +/* +* +* File name: mtv319_port.h +* +* Description : Configuration for RAONTECH MTV319 Services. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __MTV319_PORT_H__ +#define __MTV319_PORT_H__ + +/*============================================================================= + * Includes the user header files if neccessry. + *===========================================================================*/ +#if defined(__KERNEL__) /* Linux kernel */ + #include + #include + #include + #include + #include + #include + #include + #include + #include + +#elif defined(WINCE) || defined(WINDOWS) || defined(WIN32) + #include + #include + #include + #ifdef WINCE + #include + #endif +#else + #include + #include +#endif + +#ifdef __cplusplus +extern "C"{ +#endif + +/*############################################################################ +# +# COMMON configurations +# +############################################################################*/ +/*============================================================================ +* The slave address for I2C and SPI. +*===========================================================================*/ +#define RTV_CHIP_ADDR 0x86 + +/*============================================================================ +* Modifies the basic data types if neccessry. +*===========================================================================*/ +#define BOOL int +#define S8 s8 +#define U8 u8 +#define S16 s16 +#define U16 u16 +#define S32 s32 +#define U32 u32 + +#define INT int +#define UINT unsigned int +#define LONG long +#define ULONG unsigned long + +#define INLINE inline + +/*============================================================================ +* Defines the package type of chip to target product. +*===========================================================================*/ +#define RTV_CHIP_PKG_CSP +/* #define RTV_CHIP_PKG_QFN */ + +/*============================================================================ +* Defines the external source freqenecy in KHz. +* Ex> #define RTV_SRC_CLK_FREQ_KHz 36000 // 36MHz +*===========================================================================*/ +#define RTV_SRC_CLK_FREQ_KHz 24576 + +/*============================================================================ +* Defines the Host interface. +*===========================================================================*/ +#define RTV_IF_SPI /* AP: SPI Master Mode */ +/*#define RTV_IF_TSIF*/ /* I2C + TSIF Master Mode*/ +/* #define RTV_IF_SPI_SLAVE */ /* AP: SPI Slave Mode*/ + +/*============================================================================ +* Defines the polarity of interrupt if necessary. +*===========================================================================*/ +#define RTV_INTR_POLARITY_LOW_ACTIVE +/* #define RTV_INTR_POLARITY_HIGH_ACTIVE */ + +/*============================================================================ +* Defines the delay macro in milliseconds. +*===========================================================================*/ +#if defined(__KERNEL__) /* Linux kernel */ + static INLINE void RTV_DELAY_MS(UINT ms) + { + unsigned long start_jiffies, end_jiffies; + UINT diff_time; + UINT _1ms_cnt = ms; + + start_jiffies = get_jiffies_64(); + + do { + end_jiffies = get_jiffies_64(); + + diff_time = jiffies_to_msecs(end_jiffies - start_jiffies); + if (diff_time >= ms) + break; + + mdelay(1); + } while (--_1ms_cnt); + } + +#elif defined(WINCE) + #define RTV_DELAY_MS(ms) Sleep(ms) + +#else + extern void mtv_delay_ms(int ms); + #define RTV_DELAY_MS(ms) mtv_delay_ms(ms) // TODO +#endif + +/*============================================================================ +* Defines the debug message macro. +*===========================================================================*/ +#if 1 + #define RTV_DBGMSG0(fmt) printk(fmt) + #define RTV_DBGMSG1(fmt, arg1) printk(fmt, arg1) + #define RTV_DBGMSG2(fmt, arg1, arg2) printk(fmt, arg1, arg2) + #define RTV_DBGMSG3(fmt, arg1, arg2, arg3) printk(fmt, arg1, arg2, arg3) +#else + /* To eliminates the debug messages. */ + #define RTV_DBGMSG0(fmt) do {} while (0) + #define RTV_DBGMSG1(fmt, arg1) do {} while (0) + #define RTV_DBGMSG2(fmt, arg1, arg2) do {} while (0) + #define RTV_DBGMSG3(fmt, arg1, arg2, arg3) do {} while (0) +#endif +/*#### End of Common ###########*/ + + +/*############################################################################# +# +# T-DMB specific configurations +# +#############################################################################*/ +/* Determine if the FIC is not handled by interrupt. */ +/* #define RTV_FIC_POLLING_MODE */ + +/* Defines the number of sub channel to be open simultaneously. (AV + DATA) */ +#define RTV_MAX_NUM_USE_SUBCHANNEL 1 + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + /* #define RTV_SPI_FIC_DECODE_IN_PLAY */ + + /* The size of interrupt level for CIF mode of SPI interface. */ + #define RTV_SPI_CIF_MODE_INTERRUPT_SIZE (16 * 188) + +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + /*========================================================*/ + /* Selects FIC transmission path when SCAN and PLAY state */ + /* NA: Not Applicable */ + /*========================================================*/ + /* #define RTV_FIC__SCAN_I2C__PLAY_NA */ /* Polling or Intrrupt. */ + /* #define RTV_FIC__SCAN_I2C__PLAY_I2C */ /* Polling or Intrrupt */ + /* #define RTV_FIC__SCAN_I2C__PLAY_TSIF*/ /* Polling or Intrrupt */ + #define RTV_FIC__SCAN_TSIF__PLAY_NA /* Polling meaningless */ + /* #define RTV_FIC__SCAN_TSIF__PLAY_I2C */ /* Polling or Intrrupt */ + /* #define RTV_FIC__SCAN_TSIF__PLAY_TSIF */ /* Polling meaningless */ +#endif + +/* Determine whether or not FIC header generated by MTV319 is enabled. */ +#if defined(RTV_FIC__SCAN_TSIF__PLAY_NA) \ + || defined(RTV_FIC__SCAN_TSIF__PLAY_I2C) \ + || defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) +#define RTV_SCAN_FIC_HDR_ENABLED /* Scan state */ +#endif +/* Determine whether or not FIC header generated by MTV319 is enabled. */ +//#define RTV_PLAY_FIC_HDR_ENABLED /* Play state */ + +/* Determine whether or not MSC header generated by MTV319 is enabled. */ +//#define RTV_MSC_HDR_ENABLED + + +/* Determine if the output of error-tsp is disable. */ +/*#define RTV_ERROR_TSP_OUTPUT_DISABLE */ + +#ifndef RTV_ERROR_TSP_OUTPUT_DISABLE + /* Determine if the NULL PID will generated for error-tsp. */ + /*#define RTV_NULL_PID_GENERATE*/ + + /* Determine if the sync-byte was insert for error-tsp forcely. */ + #define RTV_FORCE_INSERT_SYNC_BYTE +#endif /* RTV_ERROR_TSP_OUTPUT_DISABLE */ + + +/* Determine if the multi channel decoder is compiled with RAONTECH driver. */ +#define RTV_MCHDEC_IN_DRIVER + +#ifdef RTV_MCHDEC_IN_DRIVER + /* Select the copying method of MCH decoded data(FIC and MSC). + CIF decoder copy the decoded data into user space buffer direcly + to fast operation. + NOTE: Only applicable in RTV_MULTIPLE_CHANNEL_MODE defined. */ + /* #define RTV_MCHDEC_DIRECT_COPY_USER_SPACE */ +#endif + + +/*############################################################################ +# +# Host Interface specific configurations +# +############################################################################*/ +#if defined(RTV_IF_SPI) + /*================================================================= + * Defines the register I/O macros. + *================================================================*/ + void mtv319_set_port_if(unsigned long interface); + U8 mtv319_spi_read(U8 page, U8 reg); + void mtv319_spi_read_burst(U8 page, U8 reg, U8 *buf, int size); + void mtv319_spi_write(U8 page, U8 reg, U8 val); + void mtv319_spi_recover(unsigned char *buf, unsigned int intr_size); + extern U8 g_bRtvPage; + + static INLINE U8 RTV_REG_GET(U8 reg) + { + if (g_bRtvPage == 0xF) + reg ^= 0x10; + + return (U8)mtv319_spi_read(g_bRtvPage, (U8)(reg)); + } + + #define RTV_REG_BURST_GET(reg, buf, size)\ + mtv319_spi_read_burst(g_bRtvPage, (U8)(reg), buf, (size)) + + static INLINE void RTV_REG_SET(U8 reg, U8 val) + { + if (g_bRtvPage == 0xF) + reg ^= 0x10; + + mtv319_spi_write(g_bRtvPage, (U8)(reg), (U8)(val)); + } + + #define RTV_REG_MASK_SET(reg, mask, val)\ + do { \ + U8 tmp; \ + tmp = (RTV_REG_GET(reg)|(U8)(mask))\ + & (U8)((~(mask))|(val));\ + RTV_REG_SET(reg, tmp); \ + } while (0) + + #define RTV_TSP_XFER_SIZE 188 + +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + /*================================================================= + * Defines the TS format. + *================================================================*/ + /* #define RTV_TSIF_FORMAT_0 */ /* EN_high, CLK_rising */ + /* #define RTV_TSIF_FORMAT_1 */ /* EN_high, CLK_falling */ + /* #define RTV_TSIF_FORMAT_2 */ /* EN_low, CLK_rising */ + /* #define RTV_TSIF_FORMAT_3 */ /* EN_low, CLK_falling */ + #define RTV_TSIF_FORMAT_4 /* EN_high, CLK_rising + 1CLK add */ + /* #define RTV_TSIF_FORMAT_5 */ /* EN_high, CLK_falling + 1CLK add */ + /* #define RTV_TSIF_FORMAT_6 */ /* Parallel: EN_high, CLK_falling */ + + /*================================================================= + * Defines the TSIF speed. + *================================================================*/ + /* #define RTV_TSIF_SPEED_3_Mbps */ /* 2.41MHz */ + #define RTV_TSIF_SPEED_4_Mbps /* 3.62MHz */ + /* #define RTV_TSIF_SPEED_5_Mbps */ /* 4.8MHz */ + /* #define RTV_TSIF_SPEED_6_Mbps */ /* 5.8MHz */ + /* #define RTV_TSIF_SPEED_8_Mbps */ /* 7.2MHz */ + /* #define RTV_TSIF_SPEED_10_Mbps */ /* 9.6MHz */ + /* #define RTV_TSIF_SPEED_15_Mbps */ /* 14.5MHz */ + /* #define RTV_TSIF_SPEED_30_Mbps */ /* 28.8MHz */ + /* #define RTV_TSIF_SPEED_60_Mbps */ /* 58.5MHz */ + + /*================================================================= + * Defines the TSP size. 188 or 204 + *================================================================*/ + #define RTV_TSP_XFER_SIZE 188 + + /*================================================================= + * Defines the register I/O macros. + *================================================================*/ + void mtv319_set_port_if(unsigned long interface); + U8 mtv319_i2c_read(U8 chipid, U8 reg); + void mtv319_i2c_read_burst(U8 reg, U8 *buf, int size); + void mtv319_i2c_write(U8 chipid, U8 reg, U8 val); + extern U8 g_bRtvPage; + + static INLINE U8 RTV_REG_GET(U8 reg) + { + U8 bRegVal; + + if (g_bRtvPage != 0xF) + bRegVal = mtv319_i2c_read((U8)RTV_CHIP_ADDR, (U8)(reg)); + else { + mtv319_i2c_write(RTV_CHIP_ADDR, 0x02, (0x62|0x80)); + bRegVal = mtv319_i2c_read((U8)(0x62<<1), (U8)(reg)); + } + + return bRegVal; + } + + #define RTV_REG_BURST_GET(reg, buf, size)\ + mtv319_i2c_read_burst((U8)(reg), buf, size) + + static INLINE void RTV_REG_SET(U8 reg, U8 val) + { + if (g_bRtvPage != 0xF) + mtv319_i2c_write(RTV_CHIP_ADDR, (U8)(reg), (U8)(val)); + else { + mtv319_i2c_write(RTV_CHIP_ADDR, 0x02, (0x62|0x80)); + mtv319_i2c_write((0x62<<1), (U8)(reg), (U8)(val)); + } + } + + #define RTV_REG_MASK_SET(reg, mask, val)\ + do { \ + U8 tmp; \ + tmp = (RTV_REG_GET(reg)|(U8)(mask))\ + & (U8)((~(mask))|(val));\ + RTV_REG_SET(reg, tmp); \ + } while (0) + +#elif defined(RTV_IF_EBI2) + /*================================================================= + * Defines the register I/O macros. + *================================================================*/ + U8 tdmb_ebi2_read(U8 page, U8 reg); + void tdmb_ebi2_read_burst(U8 page, U8 reg, U8 *buf, int size); + void tdmb_ebi2_write(U8 page, U8 reg, U8 val); + extern U8 g_bRtvPage; + + static INLINE U8 RTV_REG_GET(U8 reg) + { + if (g_bRtvPage == 0xF) + reg ^= 0x10; + + return (U8)tdmb_ebi2_read(g_bRtvPage, (U8)(reg)); + } + + #define RTV_REG_BURST_GET(reg, buf, size)\ + tdmb_ebi2_read_burst(g_bRtvPage, (U8)(reg), buf, (size)) + + static INLINE void RTV_REG_SET(U8 reg, U8 val) + { + if (g_bRtvPage == 0xF) + reg ^= 0x10; + + tdmb_ebi2_write(g_bRtvPage, (U8)(reg), (U8)(val)); + } + + #define RTV_REG_MASK_SET(reg, mask, val)\ + do { \ + U8 tmp; \ + tmp = (RTV_REG_GET(reg)|(U8)(mask))\ + & (U8)((~(mask))|(val));\ + RTV_REG_SET(reg, tmp); \ + } while (0) + + #define RTV_TSP_XFER_SIZE 188 +#else + #error "Must define the interface definition !" +#endif + + +/*############################################################################ +# +# Pre-definintion by RAONTECH. +# +############################################################################*/ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #ifndef RTV_FIC_POLLING_MODE + #define RTV_FIC_SPI_INTR_ENABLED /* FIC SPI Interrupt use. */ + #endif +#else + #if !defined(RTV_FIC_POLLING_MODE)\ + && !defined(RTV_FIC__SCAN_TSIF__PLAY_NA)\ + && !defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + #define RTV_FIC_I2C_INTR_ENABLED /* FIC I2C Interrupt use. */ + #endif +#endif + +/* Defines the multiple channel mode if all ts data was xfered in play state */ +#if (\ + (defined(RTV_SPI_FIC_DECODE_IN_PLAY)\ +|| defined(RTV_FIC__SCAN_I2C__PLAY_TSIF)\ + || defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF))\ + &&\ + (RTV_MAX_NUM_USE_SUBCHANNEL >= 1)\ + ) + + #define RTV_MULTIPLE_CHANNEL_MODE +#endif + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #define RTV_MCH_HEADER_SYNC_BYTE 0xE2 +#else + #define RTV_MCH_HEADER_SYNC_BYTE 0x47 +#endif + +/*############################################################################ +# +# Defines the critical object and macros. +# +############################################################################*/ +#if defined(__KERNEL__) +extern struct mutex raontv_guard; +#define RTV_GUARD_INIT mutex_init(&raontv_guard) +#define RTV_GUARD_LOCK mutex_lock(&raontv_guard) +#define RTV_GUARD_FREE mutex_unlock(&raontv_guard) +#define RTV_GUARD_DEINIT ((void)0) + +#elif defined(WINCE) || defined(WINDOWS) || defined(WIN32) +extern CRITICAL_SECTION raontv_guard; +#define RTV_GUARD_INIT InitializeCriticalSection(&raontv_guard) +#define RTV_GUARD_LOCK EnterCriticalSection(&raontv_guard) +#define RTV_GUARD_FREE LeaveCriticalSection(&raontv_guard) +#define RTV_GUARD_DEINIT DeleteCriticalSection(&raontv_guard) + +#else +/* temp: TODO */ +#define RTV_GUARD_INIT ((void)0) +#define RTV_GUARD_LOCK ((void)0) +#define RTV_GUARD_FREE ((void)0) +#define RTV_GUARD_DEINIT ((void)0) +#endif + + +/*############################################################################ +# +# Check erros by user-configurations. +# +############################################################################*/ +#if !defined(RTV_CHIP_PKG_CSP) && !defined(RTV_CHIP_PKG_QFN) + #error "Must define the package type !" +#endif + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE)\ +|| defined(RTV_IF_SPI) + #if (RTV_CHIP_ADDR >= 0xFF) + #error "Invalid chip address" + #endif + +#elif defined(RTV_IF_EBI2) + +#else + #error "Must define the interface definition !" +#endif + + +#ifndef RTV_MAX_NUM_USE_SUBCHANNEL + #error "Should be define number of subchannel!" +#endif + +#if (RTV_MAX_NUM_USE_SUBCHANNEL <= 0) || (RTV_MAX_NUM_USE_SUBCHANNEL > 4) + #error "Must from 0 to 4 for subchannel. TDMB(1ea), DAB(2ea), DABP(1ea)" +#endif + +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + #ifndef RTV_MSC_HDR_ENABLED + #error "Must define RTV_MSC_HDR_ENABLED definition" + #endif +#endif + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 0) + #ifdef RTV_MSC_HDR_ENABLED + #error "Must NOT define RTV_MSC_HDR_ENABLED definition" + #endif +#endif + + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + #if !defined(RTV_FIC__SCAN_I2C__PLAY_NA)\ + && !defined(RTV_FIC__SCAN_I2C__PLAY_I2C)\ + && !defined(RTV_FIC__SCAN_I2C__PLAY_TSIF)\ + && !defined(RTV_FIC__SCAN_TSIF__PLAY_NA)\ + && !defined(RTV_FIC__SCAN_TSIF__PLAY_I2C)\ + && !defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + #error "No FIC path was defined for TSIF!" + #endif + + #if defined(RTV_FIC__SCAN_I2C__PLAY_NA)\ + && defined(RTV_FIC__SCAN_I2C__PLAY_I2C)\ + && defined(RTV_FIC__SCAN_I2C__PLAY_TSIF)\ + && defined(RTV_FIC__SCAN_TSIF__PLAY_NA)\ + && defined(RTV_FIC__SCAN_TSIF__PLAY_I2C)\ + && defined(RTV_FIC__SCAN_TSIF__PLAY_TSIF) + #error "Should select only one FIC path for TSIF!" + #endif +#endif + + +#ifndef RTV_TSP_XFER_SIZE + #error "Must define the RTV_TSP_XFER_SIZE definition !" +#endif + +#if (RTV_TSP_XFER_SIZE != 188) && (RTV_TSP_XFER_SIZE != 204) + #error "Must 188 or 204 for TS size" +#endif + + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #ifdef RTV_MULTIPLE_CHANNEL_MODE + #ifdef RTV_SPI_CIF_MODE_INTERRUPT_SIZE + #if ((RTV_SPI_CIF_MODE_INTERRUPT_SIZE % 188) != 0) + #error "Must multiple of 188" + #endif + #else + #error "Should defined" + #endif + #endif + + #if defined(RTV_FIC_POLLING_MODE) && defined(RTV_SPI_FIC_DECODE_IN_PLAY) + #error "Not support!" + #endif +#endif + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +#endif + +int mtv319_assemble_fic(unsigned char *fic_buf, const unsigned char *ts_data, + unsigned int ts_size); + +void rtvOEM_PowerOn(int on); + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_PORT_H__ */ + diff --git a/drivers/media/tdmb/mtv319/mtv319_rf.c b/drivers/media/tdmb/mtv319/mtv319_rf.c new file mode 100644 index 000000000000..275b52ee94d1 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_rf.c @@ -0,0 +1,250 @@ +/* +* +* File name: mtv319_rf.c +* +* Description : MTV319 RF services source driver. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "mtv319_rf.h" +#include "mtv319_rf_adc_data.h" + +/* Down conversion Signal Monitoring. */ +/* #define DEBUG_A_TEST_ZERO */ + +static const struct RTV_REG_INIT_INFO t_TDMB_INIT[] = { + {0x21, 0x08}, + {0x22, 0x6c}, + {0x23, 0x54}, + {0x25, 0x0F}, /* FEBD[9:8], REFD[5:0] */ + {0x26, 0xE8}, /* FEBD[7:0] */ + {0x32, 0xff}, + {0x36, 0x88}, + {0x38, 0x49}, + {0x39, 0x31}, + {0x3A, 0xD0}, + {0x3B, 0x88}, + {0x3e, 0x71}, + {0x42, 0x06}, + {0x43, 0x4F}, + {0x44, 0x60}, + {0x45, 0x9A}, + {0x46, 0xd7}, + {0x48, 0x65}, + {0x49, 0x2c}, + {0x4a, 0x24}, + {0x4e, 0x60}, + {0x4f, 0x50}, + {0x51, 0x06}, + {0x52, 0x44}, + {0x56, 0xd8}, + {0x57, 0x86}, + {0x58, 0x1a}, + {0x59, 0x20}, + {0x63, 0x0c}, + {0x64, 0x0c}, + {0x65, 0x4c}, + {0x66, 0x0c}, + {0x67, 0x0c}, + {0x68, 0x4c}, + {0x69, 0x0c}, + {0x6a, 0x0c}, + {0x6b, 0x4c}, + {0x6d, 0x1e}, + {0x6e, 0x1e}, + {0x6f, 0x1e}, + {0x70, 0x1e}, + {0x71, 0x1e}, + {0x72, 0x1e}, + {0x73, 0x1f}, + {0x74, 0x1f}, + {0x78, 0x08}, + {0x7a, 0x07}, + {0x7b, 0x03}, + {0x7d, 0x08}, + {0x86, 0x84}, + {0x87, 0x34}, + {0x8e, 0xae}, + {0x8f, 0x94}, + {0x93, 0x1b}, + {0x94, 0xc3}, + {0x95, 0x70}, + {0x97, 0x7f}, + {0x99, 0x5c}, + {0x9a, 0xbf}, + {0x9b, 0xc6}, + {0x9d, 0x96}, + {0x9f, 0xd7}, + {0xa7, 0x11} +}; + +UINT g_dwRtvPrevChFreqKHz; + + +void rtvRF_InitOfdmTnco(void) +{ + const struct RTV_ADC_CFG_INFO *ptCfgTbl = &g_atAdcCfgTbl_TDMB[0]; + + RTV_REG_SET(0x38, ptCfgTbl->dwTNCO & 0xFF); + RTV_REG_SET(0x39, (ptCfgTbl->dwTNCO>>8) & 0xFF); + RTV_REG_SET(0x3A, (ptCfgTbl->dwTNCO>>16) & 0xFF); + RTV_REG_SET(0x3B, (ptCfgTbl->dwTNCO>>24) & 0xFF); +} + +static INT rtvRF_ChangeAdcClock(UINT nChIdx) +{ + UINT nRetryCnt = 10; + U8 RD02; + const struct RTV_ADC_CFG_INFO *ptCfgTbl = &g_atAdcCfgTbl_TDMB[nChIdx]; + + RTV_REG_MAP_SEL(RF_PAGE); + RTV_REG_SET(0x25, (((ptCfgTbl->wFEBD&0x300)>>8)<<6) | ptCfgTbl->bREFD); + RTV_REG_SET(0x26, ptCfgTbl->wFEBD & 0xFF); + + while (1) { + RTV_DELAY_MS(1); + + RD02 = RTV_REG_GET(0x02); + if (RD02 & 0x80) + break; + + if (--nRetryCnt == 0) { + RTV_DBGMSG0("[rtvRF_ChangeAdcClock] Syn Unlocked!\n"); + return RTV_ADC_CLK_UNLOCKED; + } + } + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x38, ptCfgTbl->dwTNCO & 0xFF); + RTV_REG_SET(0x39, (ptCfgTbl->dwTNCO>>8) & 0xFF); + RTV_REG_SET(0x3A, (ptCfgTbl->dwTNCO>>16) & 0xFF); + RTV_REG_SET(0x3B, (ptCfgTbl->dwTNCO>>24) & 0xFF); + + return RTV_SUCCESS; +} + +INT rtvRF_SetFrequency(U32 dwChFreqKHz) +{ + UINT nChIdx, nRetryCnt = 10; + U8 WR32, WR2A, RD00; + U32 dwPLLN, dwPLLF, dwPLLNF; + INT nRet; + U32 PLLFREQkHz = dwChFreqKHz << 2; /* x4 */ +#if (RTV_SRC_CLK_FREQ_KHz == 13000) || (RTV_SRC_CLK_FREQ_KHz == 27000) + #define pllf_mul 1 + #define r_div 3 +#else + #define pllf_mul 0 + #define r_div 4 +#endif + + nChIdx = (dwChFreqKHz - TDMB_FREQ_START__KOREA) / TDMB_FREQ_STEP__KOREA; + if (dwChFreqKHz >= 205280) + nChIdx -= 2; + else if (dwChFreqKHz >= 193280) + nChIdx -= 1; + + nRet = rtvRF_ChangeAdcClock(nChIdx); + if (nRet != RTV_SUCCESS) + goto RF_SET_FREQ_ERR; + + /* Set the PLLNF and channel. */ + dwPLLN = PLLFREQkHz / RTV_SRC_CLK_FREQ_KHz; + dwPLLF = PLLFREQkHz - (dwPLLN * RTV_SRC_CLK_FREQ_KHz); + dwPLLNF = (dwPLLN<<20) + + (((dwPLLF<<16) / (RTV_SRC_CLK_FREQ_KHz>>r_div)) << pllf_mul); + + RTV_REG_MAP_SEL(RF_PAGE); + RTV_REG_SET(0x21, (dwPLLNF>>22) & 0xFF); + RTV_REG_SET(0x22, (dwPLLNF>>14) & 0xFF); + RTV_REG_SET(0x23, (dwPLLNF>>6) & 0xFF); + + /* SAR */ + WR32 = RTV_REG_GET(0x32) & 0xFD; + WR2A = RTV_REG_GET(0x2A) & 0x3F; + RTV_REG_SET(0x32, (WR32 | 0x02)); /* ENVCOCAL_I2C = 1 */ + RTV_REG_SET(0x2A, (WR2A | 0x80)); /* RECONF_I2C = 1 */ + RTV_REG_SET(0x2A, (WR2A | 0xC0)); /* INIT_VCOCAL_I2C = 1 */ + RTV_DELAY_MS(1); + RTV_REG_SET(0x2A, (WR2A | 0x80)); /* INIT_VCOCAL_I2C = 0 */ + RTV_REG_SET(0x2A, (WR2A | 0x00)); /* RECONF_I2C = 0 */ + + while (1) { + RTV_DELAY_MS(1); + + RD00 = RTV_REG_GET(0x00); + if (RD00 & 0x20) { + RTV_DELAY_MS(1); + RD00 = RTV_REG_GET(0x00); + if (RD00 & 0x20) { + RTV_DELAY_MS(1); + RD00 = RTV_REG_GET(0x00); + if (RD00 & 0x20) { + RTV_DELAY_MS(1); + RD00 = RTV_REG_GET(0x00); + if (RD00 & 0x20) + break; + } + } + } + + RTV_REG_SET(0x2A, (WR2A | 0x80)); /* RECONF_I2C = 1 */ + RTV_REG_SET(0x2A, (WR2A | 0xC0)); /* INIT_VCOCAL_I2C = 1 */ + RTV_DELAY_MS(1); + RTV_REG_SET(0x2A, (WR2A | 0x80)); /* INIT_VCOCAL_I2C = 1 */ + RTV_REG_SET(0x2A, (WR2A | 0x00)); /* RECONF_I2C = 1 */ + + if (--nRetryCnt == 0) { + RTV_DBGMSG0("[rtvRF_SetFrequency] PLL Unlocked!\n"); + return RTV_PLL_UNLOCKED; + } + } + + g_dwRtvPrevChFreqKHz = dwChFreqKHz; + + return RTV_SUCCESS; + +RF_SET_FREQ_ERR: + RTV_DBGMSG1("[rtvRF_SetFrequency] Error(%d)\n", nRet); + return nRet; +} + +INT rtvRF_Initilize(void) +{ + UINT nNumTblEntry; + const struct RTV_REG_INIT_INFO *ptInitTbl; +#ifdef DEBUG_A_TEST_ZERO + U8 bA8; +#endif + + ptInitTbl = t_TDMB_INIT; + nNumTblEntry = sizeof(t_TDMB_INIT) / sizeof(struct RTV_REG_INIT_INFO); + + RTV_REG_MAP_SEL(RF_PAGE); + do { + RTV_REG_SET(ptInitTbl->bReg, ptInitTbl->bVal); + ptInitTbl++; + } while (--nNumTblEntry); + +#ifdef DEBUG_A_TEST_ZERO + bA8 = RTV_REG_GET(0xA8); + bA8 |= 0x01; + RTV_REG_SET(0xA8, bA8); +#endif + + g_dwRtvPrevChFreqKHz = 0; + + return RTV_SUCCESS; +} + diff --git a/drivers/media/tdmb/mtv319/mtv319_rf.h b/drivers/media/tdmb/mtv319/mtv319_rf.h new file mode 100644 index 000000000000..b01af9a45e41 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_rf.h @@ -0,0 +1,40 @@ +/* +* +* File name: mtv319_rf.h +* +* Description : MTV319 T-DMB services header file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef __MTV319_RF_H__ +#define __MTV319_RF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mtv319_internal.h" + +extern UINT g_dwRtvPrevChFreqKHz; + +INT rtvRF_SetFrequency(U32 dwFreqKHz); +void rtvRF_InitOfdmTnco(void); +INT rtvRF_Initilize(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __MTV319_RF_H__ */ + diff --git a/drivers/media/tdmb/mtv319/mtv319_rf_adc_data.h b/drivers/media/tdmb/mtv319/mtv319_rf_adc_data.h new file mode 100644 index 000000000000..e87a77b30879 --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_rf_adc_data.h @@ -0,0 +1,73 @@ +/* +* +* File name: mtv319_rf_adc_data.h +* +* Description : MTV319 T-DMB RF ADC data header file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#if (RTV_SRC_CLK_FREQ_KHz == 19200) + static const struct RTV_ADC_CFG_INFO g_atAdcCfgTbl_TDMB[] = { + /* FEBD REFD TNCO */ + {0x051, 0x04, 0x40BA16D6} /* 175280: 7A */, + {0x051, 0x04, 0x40BA16D6} /* 177008: 7B */, + {0x052, 0x04, 0x3FF003D4} /* 178736: 7C */, + {0x051, 0x04, 0x40BA16D6} /* 181280: 8A */, + {0x052, 0x04, 0x3FF003D4} /* 183008: 8B */, + {0x053, 0x04, 0x3F2ACF59} /* 184736: 8C */, + {0x052, 0x04, 0x3FF003D4} /* 187280: 9A */, + {0x053, 0x04, 0x3F2ACF59} /* 189008: 9B */, + {0x054, 0x04, 0x3E6A4CE1} /* 190736: 9C */, + {0x055, 0x04, 0x3DAE5200} /* 193280: 10A */, + {0x050, 0x04, 0x41893720} /* 195008: 10B */, + {0x055, 0x04, 0x3DAE5200} /* 196736: 10C */, + {0x04F, 0x04, 0x425D95CC} /* 199280: 11A */, + {0x050, 0x04, 0x41893720} /* 201008: 11B */, + {0x050, 0x04, 0x41893720} /* 202736: 11C */, + {0x051, 0x04, 0x40BA16D6} /* 205280: 12A */, + {0x052, 0x04, 0x3FF003D4} /* 207008: 12B */, + {0x053, 0x04, 0x3F2ACF59} /* 208736: 12C */, + {0x054, 0x04, 0x3E6A4CE1} /* 211280: 13A */, + {0x054, 0x04, 0x3E6A4CE1} /* 213008: 13B */, + {0x053, 0x04, 0x3F2ACF59} /* 214736: 13C */ + }; + +#elif (RTV_SRC_CLK_FREQ_KHz == 24576) + static const struct RTV_ADC_CFG_INFO g_atAdcCfgTbl_TDMB[] = { + /* FEBD REFD TNCO */ + {0x0E8, 0x0F, 0x4234F722} /* 175280: 7A */, + {0x0AA, 0x0B, 0x42424238} /* 177008: 7B */, + {0x060, 0x06, 0x3FFFFFF6} /* 178736: 7C */, + {0x07D, 0x08, 0x41893742} /* 181280: 8A */, + {0x0E5, 0x0E, 0x3E9A4546} /* 183008: 8B */, + {0x063, 0x06, 0x3E0F83D7} /* 184736: 8C */, + {0x0F8, 0x0F, 0x3DEF7BD5} /* 187280: 9A */, + {0x063, 0x06, 0x3E0F83D7} /* 189008: 9B */, + {0x0AC, 0x0A, 0x3B88EE1B} /* 190736: 9C */, + {0x0C6, 0x0C, 0x3E0F83D7} /* 193280: 10A */, + {0x0C8, 0x0C, 0x3D70A3CE} /* 195008: 10B */, + {0x07D, 0x08, 0x41893742} /* 196736: 10C */, + {0x07C, 0x08, 0x42108417} /* 199280: 11A */, + {0x07D, 0x08, 0x41893742} /* 201008: 11B */, + {0x0E1, 0x0D, 0x3B2A18FF} /* 202736: 11C */, + {0x0EF, 0x0F, 0x40448D7C} /* 205280: 12A */, + {0x0B3, 0x0B, 0x3EED685D} /* 207008: 12B */, + {0x0AF, 0x0B, 0x405D9F6A} /* 208736: 12C */, + {0x0B3, 0x0B, 0x3EED685D} /* 211280: 13A */, + {0x0B6, 0x0B, 0x3DE3DE34} /* 213008: 13B */, + {0x0B6, 0x0B, 0x3DE3DE34} /* 214736: 13C */ + }; +#else + #error "Unsupport clock freqency!" +#endif \ No newline at end of file diff --git a/drivers/media/tdmb/mtv319/mtv319_tdmb.c b/drivers/media/tdmb/mtv319/mtv319_tdmb.c new file mode 100644 index 000000000000..979457cbfd5e --- /dev/null +++ b/drivers/media/tdmb/mtv319/mtv319_tdmb.c @@ -0,0 +1,1574 @@ +/* +* +* File name: mtv319_tdmb.c +* +* Description : MTV319 T-DMB services source file. +* +* Copyright (C) (2013, RAONTECH) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "mtv319_rf.h" +#include "mtv319_internal.h" + +#define TDMB_MAX_NUM_ANTENNA_LEVEL 7 +#define MAX_NUM_TDMB_SUBCH 64 +#define TDMB_MAX_CER_VALUE 2000 + +/* #define DEBUG_LOG_FOR_RSSI_FITTING */ + +#define DIV32(x) ((x) >> 5) /* Divide by 32 */ +#define MOD32(x) ((x) & 31) + + +static enum E_TDMB_STATE g_eTdmbState; + +/* NOTE: Do not modify the order! */ +enum E_TDMB_HW_SUBCH_IDX_TYPE { + TDMB_HW_CH_IDX_TDMB = 0, + TDMB_HW_CH_IDX_DAB_0 = 1, +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + TDMB_HW_CH_IDX_DAB_1, +#endif + TDMB_HW_CH_IDX_DABPLUS, + MAX_NUM_TDMB_HW_CH_IDX +}; +static UINT g_nUsedHwSubChIdxBits; + +/* Registered sub channel information. */ +struct RTV_TDMB_REG_SUBCH_INFO { + UINT nSubChID; + enum E_TDMB_HW_SUBCH_IDX_TYPE eHwSubChIdx; + enum E_RTV_SERVICE_TYPE eServiceType; +}; +static struct RTV_TDMB_REG_SUBCH_INFO + g_atRegSubchInfo[RTV_MAX_NUM_USE_SUBCHANNEL]; + +static UINT g_nRegSubChArrayIdxBits; +static UINT g_nTdmbPrevAntennaLevel; +static UINT g_nOpenedSubChNum; + +/* Used sub channel ID bits. [0]: 0 ~ 31, [1]: 32 ~ 63 */ +static U32 g_aRegSubChIdBits[2]; + +static BOOL g_fTdmbFastScanEnabled; + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +enum E_RTV_FIC_OPENED_PATH_TYPE g_nRtvFicOpenedStatePath; +#endif + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) +UINT g_nRtvInterruptLevelSize; +#endif + +BOOL g_fRtvFicOpened; + +static void Disable_DABP_SUBCH(void) +{ + g_nUsedHwSubChIdxBits &= ~(1<= 2) +static void Disable_DAB_SUBCH1(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + + g_nUsedHwSubChIdxBits &= ~(1<= 2) */ + +static void Disable_DAB_SUBCH0(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + + g_nUsedHwSubChIdxBits &= ~(1<= 2) + /* Disable data path if the all DAB was closed. */ + if (!(g_nUsedHwSubChIdxBits + & (((1<= 2) + } +#endif + + RTV_REG_SET(0xB8, 0x00); +} + +static void Enable_DAB_SUBCH0(UINT nSubChID) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + /* Enable data path if the all DAB was closed. */ + if (!(g_nUsedHwSubChIdxBits + & (((1<= 2) + } +#endif + + RTV_REG_SET(0xB8, 0x80|nSubChID); + + g_nUsedHwSubChIdxBits |= (1<= 2) + Disable_DAB_SUBCH1, +#endif + Disable_DABP_SUBCH +}; + +static void (*g_pfnEnableSUBCH[MAX_NUM_TDMB_HW_CH_IDX])(UINT nSubChID) = { + Enable_TDMB_SUBCH, + Enable_DAB_SUBCH0, +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + Enable_DAB_SUBCH1, +#endif + Enable_DABP_SUBCH +}; + +static void tdmb_DisableFastScanMode(void) +{ + if (!g_fTdmbFastScanEnabled) + return; + + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x2D, 0x80); + RTV_REG_SET(0x2E, 0x5F); + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x14, 0x46); + RTV_REG_SET(0x50, 0x02); + RTV_REG_SET(0x40, 0x42); + RTV_REG_SET(0x4C, 0x42); + + g_fTdmbFastScanEnabled = FALSE; +} + +static void tdmb_EnableFastScanMode(void) +{ + if (g_fTdmbFastScanEnabled) + return; + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x14, 0x26); /* Force Stable Test */ + RTV_REG_SET(0x19, 0x34); + RTV_REG_SET(0x40, 0x40); + /* TLock Mode <3:0> + 1 ; 40 = 1EA COUNT, 42 = 3EA COUNT */ + RTV_REG_SET(0x4C, 0x40); + RTV_REG_SET(0x50, 0x06); /* Scan On */ + + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x2D, 0x0C); + RTV_REG_SET(0x2E, 0x07); + + g_fTdmbFastScanEnabled = TRUE; +} + +UINT tdmb_GetOfdmLockStatus(void) +{ + U8 OFDM_B8; + UINT lock_st = 0; + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_MASK_SET(0x12, 0x80, 0x80); + RTV_REG_MASK_SET(0x12, 0x80, 0x00); + + OFDM_B8 = RTV_REG_GET(0xB8); + if (OFDM_B8 & 0x01) + lock_st = RTV_TDMB_OFDM_LOCK_MASK; + + if (OFDM_B8 & 0x08) + lock_st |= RTV_TDMB_AGC_LOCK_MASK; + + return lock_st; +} + +static INLINE UINT tdmb_GetFecLockStatus(void) +{ + U8 FECL; + UINT lock_st = 0; + + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_MASK_SET(0x11, 0x04, 0x04); + RTV_REG_MASK_SET(0x11, 0x04, 0x00); + + FECL = RTV_REG_GET(0x10); /* FEC Lock (Viterbi Lock) */ + if (FECL & 0x01) + lock_st = RTV_TDMB_FEC_LOCK_MASK; + + return lock_st; +} + +UINT rtvTDMB_GetLockStatus(void) +{ + UINT lock_st; + + RTV_GUARD_LOCK; + + lock_st = tdmb_GetOfdmLockStatus(); + lock_st |= tdmb_GetFecLockStatus(); + + RTV_GUARD_FREE; + + return lock_st; +} + +UINT rtvTDMB_GetAntennaLevel(U32 dwCER) +{ + UINT nCurLevel = 0; + UINT nPrevLevel = g_nTdmbPrevAntennaLevel; + const UINT aAntLvlTbl[TDMB_MAX_NUM_ANTENNA_LEVEL] = { + /* 0 1 2 3 4 5 6 */ + 900, 800, 700, 600, 500, 400, 0}; + + if (dwCER == TDMB_MAX_CER_VALUE) + return 0; + + do { + if (dwCER >= aAntLvlTbl[nCurLevel]) /* Use equal for CER 0 */ + break; + } while (++nCurLevel != TDMB_MAX_NUM_ANTENNA_LEVEL); + + if (nCurLevel != nPrevLevel) { + if (nCurLevel < nPrevLevel) + nPrevLevel--; + else + nPrevLevel++; + + g_nTdmbPrevAntennaLevel = nPrevLevel; + } + + return nPrevLevel; +} + +/* FIC CER */ +U32 rtvTDMB_GetFicCER(void) +{ + U8 fec_sync, prd0, prd1, cnt0, cnt1; + U32 count = 0, period, cer; + + RTV_GUARD_LOCK; + + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_MASK_SET(0x11, 0x04, 0x04); + RTV_REG_MASK_SET(0x11, 0x04, 0x00); + + fec_sync = RTV_REG_GET(0x10); + if (fec_sync & 0x01) { + prd0 = RTV_REG_GET(0x3A); + prd1 = RTV_REG_GET(0x3B); + period = (prd0<<8) | prd1; + + cnt0 = RTV_REG_GET(0x3C); + cnt1 = RTV_REG_GET(0x3D); + count = (cnt0<<8) | cnt1; + } else + period = 0; + + RTV_GUARD_FREE; + + if (period) { + #if 0 + RTV_DBGMSG2("[rtvTDMB_GetFicCER] count(%u), period(%u)\n", + count, period); + #endif + cer = (count * 10000) / period; + if (cer > 1000) + cer = TDMB_MAX_CER_VALUE; /* No service */ + } else + cer = TDMB_MAX_CER_VALUE; /* No service */ + + return cer; +} + +/* MSC CER */ +U32 rtvTDMB_GetCER(void) +{ + U8 fec_sync, prd0, prd1, prd2, prd3, cnt0, cnt1, cnt2, cnt3; + U32 count = 0, period, cer; + + RTV_GUARD_LOCK; + + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_MASK_SET(0x11, 0x04, 0x04); + RTV_REG_MASK_SET(0x11, 0x04, 0x00); + + fec_sync = RTV_REG_GET(0x10); + if (fec_sync & 0x01) { + prd0 = RTV_REG_GET(0x3E); + prd1 = RTV_REG_GET(0x3F); + prd2 = RTV_REG_GET(0x40); + prd3 = RTV_REG_GET(0x41); + period = (prd0<<24) | (prd1<<16) | (prd2<<8) | prd3; + + cnt0 = RTV_REG_GET(0x42); + cnt1 = RTV_REG_GET(0x43); + cnt2 = RTV_REG_GET(0x44); + cnt3 = RTV_REG_GET(0x45); + count = (cnt0<<24) | (cnt1<<16) | (cnt2<<8) | cnt3; + } else + period = 0; + + RTV_GUARD_FREE; + + if (period) { + #if 0 + RTV_DBGMSG2("[rtvTDMB_GetCER] count(%u), period(%u)\n", + count, period); + #endif + cer = (count * 10000) / period; + if (cer > 1000) + cer = TDMB_MAX_CER_VALUE; /* No service */ + } else + cer = TDMB_MAX_CER_VALUE; /* No service */ + + return cer; +} + +#define RSSI_RFAGC_VAL(rfagc, coeffi)\ + ((rfagc) * (S32)((coeffi)*RTV_TDMB_RSSI_DIVIDER)) + +#define RSSI_GVBB_VAL(gvbb, coeffi)\ + ((gvbb) * (S32)((coeffi)*RTV_TDMB_RSSI_DIVIDER)) + +S32 rtvTDMB_GetRSSI(void) +{ + U8 RD00, GVBB, LNAGAIN, RFAGC; +#ifdef DEBUG_LOG_FOR_RSSI_FITTING + U8 CH_FLAG; +#endif + S32 nRssi = 0; + + RTV_GUARD_LOCK; + + RTV_REG_MAP_SEL(RF_PAGE); + RD00 = RTV_REG_GET(0x00); + GVBB = RTV_REG_GET(0x01); + + RTV_GUARD_FREE; + +#ifdef DEBUG_LOG_FOR_RSSI_FITTING + CH_FLAG = ((RD00 & 0xC0) >> 6); +#endif + LNAGAIN = ((RD00 & 0x18) >> 3); + RFAGC = (RD00 & 0x07); + + switch (LNAGAIN) { + case 0: + nRssi = -(RSSI_RFAGC_VAL(RFAGC, 2.8) + + RSSI_GVBB_VAL(GVBB, 0.44) + 0) + + 5 * RTV_TDMB_RSSI_DIVIDER; + break; + + case 1: + nRssi = -(RSSI_RFAGC_VAL(RFAGC, 3) + + RSSI_GVBB_VAL(GVBB, 0.3) + (19 * RTV_TDMB_RSSI_DIVIDER)) + + 0 * RTV_TDMB_RSSI_DIVIDER; + break; + + case 2: + nRssi = -(RSSI_RFAGC_VAL(RFAGC, 3) + + RSSI_GVBB_VAL(GVBB, 0.3) + (16 * 2 * RTV_TDMB_RSSI_DIVIDER)) + + 0 * RTV_TDMB_RSSI_DIVIDER; + break; + + case 3: + nRssi = -(RSSI_RFAGC_VAL(RFAGC, 2.6) + + RSSI_GVBB_VAL(GVBB, 0.4) + (11 * 3 * RTV_TDMB_RSSI_DIVIDER)) + + 0 * RTV_TDMB_RSSI_DIVIDER; + break; + + default: + break; + } + +#ifdef DEBUG_LOG_FOR_RSSI_FITTING + RTV_DBGMSG3("[rtvTDMB_GetRSSI] Channel Flag = %d 0x00=0x%02x, 0x01=0x%02x\n",CH_FLAG, RD00, GVBB); + RTV_DBGMSG3("LNAGAIN = %d, RFAGC = %d GVBB : %d\n", LNAGAIN, RFAGC,GVBB); +#endif + + return nRssi; +} + +/* SNR */ +U32 rtvTDMB_GetCNR(void) +{ + U8 data1, data2, fec_sync; + U32 data, snr = 0; + + RTV_GUARD_LOCK; + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_MASK_SET(0x12, 0x80, 0x80); + RTV_REG_MASK_SET(0x12, 0x80, 0x00); + + data1 = RTV_REG_GET(0xE0); + data2 = RTV_REG_GET(0xE1); + data = (((data2&0x3F)<<8) | data1) * 4; + + RTV_REG_MAP_SEL(FEC_PAGE); + fec_sync = RTV_REG_GET(0x10); + + RTV_GUARD_FREE; + + if (fec_sync & 0x01) { + if (data > 7800) + snr = 0; + else if ((data > 6600) && (data <= 7800)) + snr = (-4 * (S32)data/5200 * RTV_TDMB_CNR_DIVIDER) + + (U32)(8.3*RTV_TDMB_CNR_DIVIDER); + else if ((data > 4100) && (data <= 6600)) + snr = (-5 * (S32)data/4300 * RTV_TDMB_CNR_DIVIDER) + + (U32)(14.0*RTV_TDMB_CNR_DIVIDER); + else if ((data > 1400) && (data <= 4100)) + snr = (-5 * (S32)data/3500 * RTV_TDMB_CNR_DIVIDER) + + (U32)(16.0*RTV_TDMB_CNR_DIVIDER); + else if ((data > 600) && (data <= 1400)) + snr = (-10 * (S32)data/1200 * RTV_TDMB_CNR_DIVIDER) + + (U32)(27.0*RTV_TDMB_CNR_DIVIDER); + else if ((data > 200) && (data <= 600)) + snr = (-15 * (S32)data/400 * RTV_TDMB_CNR_DIVIDER) + + (U32)(42.5*RTV_TDMB_CNR_DIVIDER); + else /* if (data <= 200) */ + snr = 35 * RTV_TDMB_CNR_DIVIDER; + } else + snr = 5 * RTV_TDMB_CNR_DIVIDER; + + return snr; +} + +U32 rtvTDMB_GetPER(void) +{ + U8 rdata0, rdata1, rs_sync; + U32 per = 700; + + RTV_GUARD_LOCK; + + if (g_nUsedHwSubChIdxBits & (1<> 3) & 0x01; + if (rs_sync) { + rdata1 = RTV_REG_GET(0x5C); + rdata0 = RTV_REG_GET(0x5D); + per = (rdata1 << 8) | rdata0; + } + } else if (g_nUsedHwSubChIdxBits & (1<> 1) & 0x01; + if (rs_sync) { + rdata1 = RTV_REG_GET(0x6F); + rdata0 = RTV_REG_GET(0x70); + per = (rdata1 << 8) | rdata0; + } + } else + per = 0; + + RTV_GUARD_FREE; + + return per; + +} + +/* After Viterbi BER */ +U32 rtvTDMB_GetBER(void) +{ + U8 rs_sync, prd0, prd1, cnt0, cnt1, cnt2; + U32 count = 0, period, ber = RTV_TDMB_BER_DIVIDER; + + RTV_GUARD_LOCK; + + if (g_nUsedHwSubChIdxBits & (1<> 3) & 0x01; + if (rs_sync) { + prd0 = RTV_REG_GET(0x34); + prd1 = RTV_REG_GET(0x35); + period = (prd0<<8) | prd1; + + cnt0 = RTV_REG_GET(0x56); + cnt1 = RTV_REG_GET(0x57); + cnt2 = RTV_REG_GET(0x58); + count = ((cnt0&0x7f)<<16) | (cnt1<<8) | cnt2; + } else + period = 0; + } else if (g_nUsedHwSubChIdxBits & (1<> 1) & 0x01; + if (rs_sync) { + prd0 = RTV_REG_GET(0x37); + prd1 = RTV_REG_GET(0x38); + period = (prd0<<8) | prd1; + + cnt0 = RTV_REG_GET(0x69); + cnt1 = RTV_REG_GET(0x6A); + cnt2 = RTV_REG_GET(0x6B); + count = ((cnt0&0x7f)<<16) | (cnt1<<8) | cnt2; + } else + period = 0; + } else { + period = 0; + ber = 0; + } + + RTV_GUARD_FREE; + + if (period) + ber = (count * (U32)RTV_TDMB_BER_DIVIDER) / (period*8*204); + + return ber; +} + +UINT rtvTDMB_GetOpenedSubChannelCount(void) +{ + return g_nOpenedSubChNum; +} + +U32 rtvTDMB_GetPreviousFrequency(void) +{ + return g_dwRtvPrevChFreqKHz; +} + +static void tdmb_CloseSubChannel(UINT nRegSubChArrayIdx) +{ + UINT nSubChID; + enum E_TDMB_HW_SUBCH_IDX_TYPE eHwSubChIdx; + + nSubChID = g_atRegSubchInfo[nRegSubChArrayIdx].nSubChID; + eHwSubChIdx = g_atRegSubchInfo[nRegSubChArrayIdx].eHwSubChIdx; + + /* Call the specified disabling of SUBCH function. */ + g_pfnDisableSUBCH[eHwSubChIdx](); + + g_nRegSubChArrayIdxBits &= ~(1<= 2) + UINT i = 0; + UINT nRegSubChArrayIdxBits = g_nRegSubChArrayIdxBits; +#endif + + if (g_nOpenedSubChNum == 0) + return; /* not opened! already closed! */ + + RTV_GUARD_LOCK; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) /* Single Sub Channel */ + tdmb_CloseSubChannel(0); +#elif (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + while (nRegSubChArrayIdxBits) { + if (nRegSubChArrayIdxBits & 0x01) + tdmb_CloseSubChannel(i); + + nRegSubChArrayIdxBits >>= 1; + i++; + } +#endif + + RTV_GUARD_FREE; +} + +INT rtvTDMB_CloseSubChannel(UINT nSubChID) +{ +#if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + UINT i = 0; + UINT nRegSubChArrayIdxBits = g_nRegSubChArrayIdxBits; +#endif + + if (nSubChID > (MAX_NUM_TDMB_SUBCH-1)) + return RTV_INVAILD_SUBCHANNEL_ID; + + if (g_nOpenedSubChNum == 0) + return RTV_SUCCESS; /* not opened! already closed! */ + + RTV_GUARD_LOCK; + +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) /* Single Sub Channel */ + tdmb_CloseSubChannel(0); +#else + while (nRegSubChArrayIdxBits) { + if (nRegSubChArrayIdxBits & 0x01) { + if (nSubChID == g_atRegSubchInfo[i].nSubChID) + tdmb_CloseSubChannel(i); + } + + nRegSubChArrayIdxBits >>= 1; + i++; + } +#endif + + RTV_GUARD_FREE; + + return RTV_SUCCESS; +} + +static void tdmb_OpenSubChannel(UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType, UINT nThresholdSize, + enum E_TDMB_HW_SUBCH_IDX_TYPE eHwSubChIdx) +{ + UINT i; + + if (g_nOpenedSubChNum == 0) { /* The first open */ + #ifdef TDMB_CIF_MODE_DRIVER + rtvCIFDEC_Init(); + rtvCIFDEC_AddSubChannelID(nSubChID, eServiceType); + #endif + + #if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + rtv_SetupInterruptThreshold(nThresholdSize); + + RTV_REG_SET(0x2A, 1); + RTV_REG_SET(0x2A, 0); + + /* Enable SPI interrupts */ + g_bRtvIntrMaskReg &= ~(SPI_INTR_BITS); + RTV_REG_SET(0x24, g_bRtvIntrMaskReg); + + rtv_EnablePadIntrrupt(); + #endif + } else { + #ifdef TDMB_CIF_MODE_DRIVER + rtvCIFDEC_AddSubChannelID(nSubChID, eServiceType); + #endif + } + + /* Call the specified enabling of SUBCH function. */ + g_pfnEnableSUBCH[eHwSubChIdx](nSubChID); + + g_aRegSubChIdBits[DIV32(nSubChID)] |= (1 << MOD32(nSubChID)); + + /* To use when close .*/ +#if (RTV_MAX_NUM_USE_SUBCHANNEL == 1) + i = 0; +#else + for (i = 0; i < RTV_MAX_NUM_USE_SUBCHANNEL; i++) { + if ((g_nRegSubChArrayIdxBits & (1<= 2) + break; + } + } +#endif + + g_nOpenedSubChNum++; +} + +/* For Test */ +INT rtvTDMB_OpenSubChannelExt(U32 dwChFreqKHz, UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType, UINT nThresholdSize) +{ + INT nRet; + + rtvTDMB_CloseFIC(); + rtvTDMB_CloseAllSubChannels(); + + nRet = rtvTDMB_ScanFrequency(dwChFreqKHz); + rtvTDMB_CloseFIC(); + if (nRet == RTV_SUCCESS) + nRet = rtvTDMB_OpenSubChannel(dwChFreqKHz, nSubChID, + eServiceType, nThresholdSize); + else + RTV_DBGMSG1("rtvTDMB_OpenSubChannelExt() fail: %d\n", nRet); + + return nRet; +} + +INT rtvTDMB_OpenSubChannel(U32 dwChFreqKHz, UINT nSubChID, + enum E_RTV_SERVICE_TYPE eServiceType, UINT nThresholdSize) +{ + INT nRet = RTV_SUCCESS; + enum E_TDMB_HW_SUBCH_IDX_TYPE eHwChIdx; + + if (nSubChID > (MAX_NUM_TDMB_SUBCH - 1)) + return RTV_INVAILD_SUBCHANNEL_ID; + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + if (!nThresholdSize || (nThresholdSize > (32 * RTV_TSP_XFER_SIZE))) + return RTV_INVAILD_THRESHOLD_SIZE; +#endif + +#ifndef RTV_MULTIPLE_CHANNEL_MODE + if (g_fRtvFicOpened) + return RTV_SHOULD_CLOSE_FIC; +#endif + + if (g_nOpenedSubChNum > RTV_MAX_NUM_USE_SUBCHANNEL) + return RTV_NO_MORE_SUBCHANNEL; + +#if (defined(RTV_IF_SPI) || defined(RTV_IF_EBI2))\ +&& defined(RTV_MULTIPLE_CHANNEL_MODE) + nThresholdSize = RTV_SPI_CIF_MODE_INTERRUPT_SIZE; +#endif + + RTV_GUARD_LOCK; + + /* Check if the specified subch opened or closed? */ + if (dwChFreqKHz == g_dwRtvPrevChFreqKHz) { + /* Is registerd sub ch ID? */ + if (g_aRegSubChIdBits[DIV32(nSubChID)] & (1<= 2) + else if (!(g_nUsedHwSubChIdxBits & (1<= 2) + if (!g_nOpenedSubChNum) { + #endif + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x10, 0xCA); + RTV_REG_SET(0x10, 0xCB); + #if (RTV_MAX_NUM_USE_SUBCHANNEL >= 2) + } + #endif + + tdmb_OpenSubChannel(nSubChID, eServiceType, + nThresholdSize, eHwChIdx); + } else { + rtv_StopDemod(); /* To hold until rf set */ + + tdmb_OpenSubChannel(nSubChID, eServiceType, + nThresholdSize, eHwChIdx); + + /* Must place in the last */ + nRet = rtvRF_SetFrequency(dwChFreqKHz); + rtv_SoftReset(); + if (nRet != RTV_SUCCESS) + goto tdmb_open_subch_exit; + } + + /* Update the state of TDMB. */ + g_eTdmbState = TDMB_STATE_PLAY; + +tdmb_open_subch_exit: + RTV_GUARD_FREE; + + return nRet; +} + +static INLINE BOOL tdmb_CheckScanStatus(INT *sucess_flag, + U8 DAB_Mode, U8 OFDM_L, + U8 FIC_CRC, int ScanT, int *scan_status) +{ + BOOL fBreak = FALSE; + + if (DAB_Mode == 0x00) { + if (OFDM_L) { + if (FIC_CRC < 100) { + sucess_flag = RTV_SUCCESS; + fBreak = TRUE; + } else if (FIC_CRC != 255) { + *scan_status = 5; + *sucess_flag = RTV_CHANNEL_NOT_DETECTED; + fBreak = TRUE; + } + } else if (ScanT > 500) { /* Tuning pointer */ + *scan_status = 3; + *sucess_flag = RTV_CHANNEL_NOT_DETECTED; + fBreak = TRUE; + } + } else { + *scan_status = 2; + *sucess_flag = RTV_CHANNEL_NOT_DETECTED; + fBreak = TRUE; + } + + return fBreak; +} + +/* SCAN debuging log enable */ +/* #define DEBUG_LOG_FOR_SCAN */ + +/* NOTE: When this rountine executed, all sub channel and FIC should closed */ +INT rtvTDMB_ScanFrequency(U32 dwChFreqKHz) +{ + U8 Mon_FSM = 0; + int peak_pwr = 0; + U8 DAB_Mode, peak_pwr_Msb = 0, peak_pwr_Lsb = 0; + U8 OFDM_L = 0; + U8 AGC_L = 0; + U8 FIC_CRC = 255; + U8 Sdone = 0, Slock = 0; + INT sucess_flag = 0; + UINT ScanT = 0; + int pwr_threshold = 600; /* OPT */ + int scan_status = 0; + U8 FIC_Sync = 0; + U8 Ccnt = 0, Tcnt = 0; + UINT nDelayTime; +#if defined(__KERNEL__) /* Linux kernel */ + unsigned long start_jiffies, end_jiffies; + UINT diff_time = 0; +#endif + + sucess_flag = RTV_CHANNEL_NOT_DETECTED; + + if (g_fRtvFicOpened) /* For openFIC[hdr_on] => Scan[hdr_off] */ + return RTV_SHOULD_CLOSE_FIC; /* for header On/Off */ + + if (g_nOpenedSubChNum) + return RTV_SHOULD_CLOSE_SUBCHANNELS; + + RTV_GUARD_LOCK; + + /* Update the state of TDMB. */ + g_eTdmbState = TDMB_STATE_SCAN; + + tdmb_EnableFastScanMode(); + + rtv_StopDemod(); + + g_fRtvFicOpened = TRUE; +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + rtv_OpenFIC_SPI_Scan(); +#else + g_nRtvFicOpenedStatePath = rtv_OpenFIC_TSIF_Scan(); + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_MASK_SET(0x11, 0x04, 0x04); + RTV_REG_MASK_SET(0x11, 0x04, 0x00); +#endif + + sucess_flag = rtvRF_SetFrequency(dwChFreqKHz); + if (sucess_flag != RTV_SUCCESS) + goto TDMB_SCAN_EXIT; + +#if defined(RTV_SCAN_FIC_HDR_ENABLED) && defined(RTV_MCHDEC_IN_DRIVER) + rtvCIFDEC_Init(); +#endif + + RTV_DELAY_MS(50); + rtv_SoftReset(); + + while (1) { +#if defined(__KERNEL__) /* Linux kernel */ + start_jiffies = get_jiffies_64(); +#endif + + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_MASK_SET(0x82, 0x02,0x02); + RTV_REG_MASK_SET(0x82, 0x02,0x00); + + DAB_Mode = RTV_REG_GET(0xBA); + DAB_Mode = (DAB_Mode>>4) & 0x03; + + RTV_REG_MASK_SET(0x12, 0x80, 0x80); + RTV_REG_MASK_SET(0x12, 0x80, 0x00); + + RTV_REG_MAP_SEL(OFDM_PAGE); + peak_pwr_Msb = RTV_REG_GET(0xD6); + peak_pwr_Lsb = RTV_REG_GET(0xD5); + peak_pwr = ((peak_pwr_Msb&0xff)<<8) | (peak_pwr_Lsb&0xff); + + OFDM_L = RTV_REG_GET(0xB8); + OFDM_L = (OFDM_L>>0) & 0x01; + + RTV_REG_MAP_SEL(FEC_PAGE); + FIC_CRC = RTV_REG_GET(0x30); + + RTV_REG_MAP_SEL(OFDM_PAGE); + AGC_L = RTV_REG_GET(0xB8); + AGC_L = (AGC_L>>3) & 0x01; + + Mon_FSM = RTV_REG_GET(0xB8); + Mon_FSM = (Mon_FSM>>5)&0x07; + + Sdone = RTV_REG_GET(0xD4); + Slock = RTV_REG_GET(0xD4); + Sdone = (Sdone&0x02)>>1; + Slock = (Slock&0x01)>>0; + + RTV_REG_MAP_SEL(FEC_PAGE); + FIC_Sync = RTV_REG_GET(0x10); + FIC_Sync = FIC_Sync & 0x01; + + RTV_REG_MAP_SEL(OFDM_PAGE); + Ccnt = RTV_REG_GET(0xC1); + Tcnt = RTV_REG_GET(0xC2); + Ccnt = (Ccnt>>3)&0x1f; + Tcnt = Tcnt & 0x1f; + + if (AGC_L) { + if (Sdone || ScanT > 200) { + if (Slock || (peak_pwr > pwr_threshold)) { + if (tdmb_CheckScanStatus(&sucess_flag, + DAB_Mode, OFDM_L, + FIC_CRC, ScanT, &scan_status)) + break; + } else { + scan_status = 4; + sucess_flag = RTV_CHANNEL_NOT_DETECTED; + break; + } + } + } + +#if defined(__KERNEL__) /* Linux kernel */ + end_jiffies = get_jiffies_64(); + diff_time = jiffies_to_msecs(end_jiffies - start_jiffies); + if (diff_time < 4) + nDelayTime = 4 - diff_time; + else + nDelayTime = 0; + + ScanT += diff_time; +#else + nDelayTime = 4; +#endif + + if (ScanT >= 1000) { + RTV_DBGMSG0("[rtvTDMB_ScanFrequency] Scan Timeout!\n"); + scan_status = 7; + sucess_flag = RTV_CHANNEL_NOT_DETECTED; + break; + } + + if (nDelayTime) { /* Up to 4ms delay */ + ScanT += nDelayTime; + RTV_DELAY_MS(nDelayTime); + } + } + +TDMB_SCAN_EXIT: + tdmb_DisableFastScanMode(); + + if (sucess_flag != RTV_SUCCESS) { +#if defined(RTV_SCAN_FIC_HDR_ENABLED) && defined(RTV_MCHDEC_IN_DRIVER) + rtvCIFDEC_Deinit(); +#endif + rtv_CloseFIC(0); /* rtvTDMB_CloseFIC() was called when lock_s */ + g_eTdmbState = TDMB_STATE_INIT; + g_fRtvFicOpened = FALSE; + } + + RTV_GUARD_FREE; + +#ifdef DEBUG_LOG_FOR_SCAN + RTV_DBGMSG3("[rtvTDMB_ScanFrequency: %u] Power_Peak(%d), AGCL(%d)\n", + dwChFreqKHz, peak_pwr, AGC_L); + RTV_DBGMSG2("\tOFDML = %d, CRC = %d\n", OFDM_L, FIC_CRC); + RTV_DBGMSG3("\tScanT = %d Status = %d scan_done = %d\n", + ScanT, scan_status, Sdone); + RTV_DBGMSG3("\tscan_lock = %d FSM = %d scan_success = %d\n\n", + Slock, Mon_FSM, sucess_flag); +#endif + + return sucess_flag; + +} + +#define RTV_TDMB_READ_FIC_TIMEOUT_CNT 500 + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) +static INLINE INT tdmb_ReadFIC_SPI(U8 *pbBuf) +{ + int ret_size; + U8 istatus; + UINT lock_s; + UINT elapsed_cnt = 0; + UINT timeout_cnt = RTV_TDMB_READ_FIC_TIMEOUT_CNT; + + while (1) { + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + istatus = RTV_REG_GET(0x10); + if (istatus & SPI_INTR_BITS) { + if (!(istatus & SPI_UNDERFLOW_INTR)) { + RTV_REG_MAP_SEL(SPI_MEM_PAGE); + RTV_REG_BURST_GET(0x10, pbBuf, + g_nRtvInterruptLevelSize); + +#ifdef RTV_SCAN_FIC_HDR_ENABLED + ret_size = g_nRtvInterruptLevelSize; +#else + ret_size = 384; +#endif + +#if 0 + printk(KERN_INFO "[READ] 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", + pbBuf[0], pbBuf[1], pbBuf[2], pbBuf[3], pbBuf[4]); +#endif + + break; + } + } + + lock_s = tdmb_GetOfdmLockStatus(); + if (!(lock_s & RTV_TDMB_OFDM_LOCK_MASK)) { + RTV_DELAY_MS(30); + RTV_DBGMSG2("[tdmb_ReadFIC_SPI] ##lock_s(0x%02X)[%u]\n", + lock_s, elapsed_cnt); + ret_size = -55; + break; + } + + if (timeout_cnt--) + RTV_DELAY_MS(1); + else { + ret_size = RTV_FIC_READ_TIMEOUT; + break; + } + + elapsed_cnt = RTV_TDMB_READ_FIC_TIMEOUT_CNT - timeout_cnt; + } + + return ret_size; +} +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) +static INLINE INT tdmb_ReadFIC_I2C(U8 *pbBuf) +{ +#ifdef RTV_FIC_POLLING_MODE + U8 istatus; + int ret_size; + UINT lock_s; + UINT elapsed_cnt = 0; + UINT timeout_cnt = RTV_TDMB_READ_FIC_TIMEOUT_CNT; + + while (1) { + RTV_REG_MAP_SEL(FEC_PAGE); + istatus = RTV_REG_GET(0x13) & 0x10; /* [4] */ + #if 0 + RTV_DBGMSG1("[tdmb_ReadFIC_I2C] istatus(0x%02X)\n", istatus); + #endif + if (istatus) { + RTV_REG_MASK_SET(0x26, 0x10, 0x10); + RTV_REG_BURST_GET(0x29, pbBuf, 400); + RTV_REG_SET(0x26, 0x01); + + /* FIC I2C interrupt status clear. */ + RTV_REG_SET(0x11, I2C_INTR_POL_ACTIVE|0x04); + RTV_REG_SET(0x11, I2C_INTR_POL_ACTIVE); + + /* FIC I2C memory clear. */ + RTV_REG_MASK_SET(0x26, 0x04, 0x04); + RTV_REG_MASK_SET(0x26, 0x04, 0x00); + + memmove(pbBuf+215, pbBuf+231, 169); + ret_size = 384; + break; + } + + lock_s = tdmb_GetOfdmLockStatus(); + if (!(lock_s & RTV_TDMB_OFDM_LOCK_MASK)) { + RTV_DELAY_MS(30); + RTV_DBGMSG2("[tdmb_ReadFIC_I2C] ##lock_s(0x%02X)[%u]\n", + lock_s, elapsed_cnt); + ret_size = -55; + break; + } + + if (timeout_cnt--) + RTV_DELAY_MS(1); + else { + ret_size = RTV_FIC_READ_TIMEOUT; + break; + } + + elapsed_cnt = RTV_TDMB_READ_FIC_TIMEOUT_CNT - timeout_cnt; + } + + return ret_size; + +#else + RTV_REG_MAP_SEL(FEC_PAGE); + + RTV_REG_MASK_SET(0x26, 0x10, 0x10); + RTV_REG_BURST_GET(0x29, pbBuf, 400); + RTV_REG_SET(0x26, 0x01); + + /* FIC I2C interrupt status clear. */ + RTV_REG_SET(0x11, I2C_INTR_POL_ACTIVE|0x04); + RTV_REG_SET(0x11, I2C_INTR_POL_ACTIVE); + + /* FIC I2C memory clear. */ + RTV_REG_MASK_SET(0x26, 0x04, 0x04); + RTV_REG_MASK_SET(0x26, 0x04, 0x00); + + memmove(pbBuf+215, pbBuf+231, 169); + +#if 1 +printk(KERN_INFO "[READ] 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X [0x%02X 0x%02X] | 0x%02X 0x%02X\n", +pbBuf[0], pbBuf[1], pbBuf[2], pbBuf[3], pbBuf[4], pbBuf[5], +pbBuf[382], pbBuf[383], pbBuf[398], pbBuf[399]); +#endif + + return 384; +#endif +} +#endif + +/* +NOTE: Do NOT read at the ISR. +This function should called when scan state. +*/ +INT rtvTDMB_ReadFIC(U8 *pbBuf) +{ + int ret_size = 0; + + if (!g_fRtvFicOpened) { + RTV_DBGMSG0("[rtvTDMB_ReadFIC] NOT OPEN FIC\n"); + return RTV_NOT_OPENED_FIC; + } + + RTV_GUARD_LOCK; + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + ret_size = tdmb_ReadFIC_SPI(pbBuf); + +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + ret_size = tdmb_ReadFIC_I2C(pbBuf); +#endif + + RTV_GUARD_FREE; + + return ret_size; +} + +void rtvTDMB_CloseFIC(void) +{ + if (!g_fRtvFicOpened) + return; + + RTV_GUARD_LOCK; + + rtv_CloseFIC(g_nOpenedSubChNum); + + if (!g_nOpenedSubChNum) { +#if defined(TDMB_CIF_MODE_DRIVER) + rtvCIFDEC_Deinit(); /* Skip rtvCIFDEC_DeleteSubChannelID() */ +#elif defined(RTV_SCAN_FIC_HDR_ENABLED) && defined(RTV_MCHDEC_IN_DRIVER) + rtvCIFDEC_Deinit(); +#endif + g_eTdmbState = TDMB_STATE_INIT; /* Update the state of TDMB. */ + } + + g_fRtvFicOpened = FALSE; + + RTV_GUARD_FREE; +} + +INT rtvTDMB_OpenFIC(void) +{ + INT nRet = RTV_SUCCESS; + + /*RTV_DBGMSG1("[rtvTDMB_OpenFIC] g_eTdmbState(%d)\n", g_eTdmbState);*/ + + if (g_fRtvFicOpened) + return RTV_SUCCESS; + + RTV_GUARD_LOCK; + + nRet = rtv_OpenFIC(g_eTdmbState); + if (nRet == RTV_SUCCESS) + g_fRtvFicOpened = TRUE; + +#if 0 +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + RTV_DBGMSG1("[rtvTDMB_OpenFIC] Opened with FIC_state_path(%d)\n", + g_nRtvFicOpenedStatePath); +#endif +#endif + + RTV_GUARD_FREE; + + return nRet; +} + +static void tdmb_InitHOST(void) +{ + RTV_REG_MAP_SEL(HOST_PAGE); + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + RTV_REG_SET(0x05, (1<<7) | 0x00); + RTV_REG_SET(0x04, 0x40); /* demod INT dis. */ +#endif + +#if defined(RTV_CHIP_PKG_CSP) && defined(RTV_FIC_I2C_INTR_ENABLED) + RTV_DBGMSG2("[tdmb_InitHOST] 0x08(0x%02X), 0x1A(0x%02X)\n", + RTV_REG_GET(0x08), RTV_REG_GET(0x1A)); + +#if defined(RTV_FIC_I2C_INTR_ENABLED) + RTV_REG_SET(0x04, 0x40); + RTV_REG_SET(0x1A, 0x08); /* GPD3 PAD disable */ + RTV_REG_SET(0x08, (1<<5)|0x10); /* GPD3 => INT0 */ +#else + RTV_REG_SET(0x08, (3<<5)|0x10); +#endif + +#else +#if defined(RTV_FIC_I2C_INTR_ENABLED) + RTV_REG_SET(0x08, 0x10); /* INTR pin used */ +#else + RTV_REG_SET(0x08, 0x70); /* SYNC pin used */ +#endif +#endif + + RTV_REG_SET(0x09, 0x00); + RTV_REG_SET(0x10, 0xA0); + RTV_REG_SET(0x13, 0x04); + RTV_REG_SET(0x0B, 0xCE); + + RTV_REG_SET(0x0D, 0x17); + + RTV_REG_SET(0x19, 0x20); + RTV_REG_SET(0x20, 0x19); + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + RTV_REG_SET(0x05, (1<<7) | 0x3F); + + RTV_REG_SET(0x07, 0x41); + RTV_REG_SET(0x07, 0x40); + +#else + RTV_REG_SET(0x05, 0x3F); + + RTV_REG_SET(0x07, 0x01); + RTV_REG_SET(0x07, 0x00); +#endif + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + /* <2> SPI_INT0(GPP0) disable <4> I2C INT0 disable */ + RTV_REG_SET(0x1D, 0xC4); +#endif + +#if defined(RTV_CHIP_PKG_CSP) && defined(RTV_FIC_I2C_INTR_ENABLED) + #ifdef RTV_INTR_POLARITY_LOW_ACTIVE + RTV_REG_SET(0x15, 0x04); /* 2013: default high */ + #else + RTV_REG_SET(0x15, 0x00); /* 2013 */ + #endif +#endif +} + +static void tdmb_InitOFDM(void) +{ + RTV_REG_MAP_SEL(OFDM_PAGE); + RTV_REG_SET(0x10, 0xCB); + RTV_REG_SET(0x1F, 0x08); + + RTV_REG_SET(0x31, 0xFF); + RTV_REG_SET(0x32, 0xFF); + + rtvRF_InitOfdmTnco(); + + RTV_REG_SET(0x3F, 0x00); + RTV_REG_SET(0x6C, 0x0C); + RTV_REG_SET(0x6F, 0x40); + RTV_REG_SET(0x86, 0x20); + RTV_REG_SET(0x87, 0x3F); + + RTV_REG_SET(0x40, 0x42); + RTV_REG_SET(0x96, 0x02); +} + +static void tdmb_InitFEC(void) +{ + RTV_REG_MAP_SEL(FEC_PAGE); + + RTV_REG_SET(0x2D, 0x80); + RTV_REG_SET(0x2E, 0x5F); + + RTV_REG_SET(0x34, 0x00); + RTV_REG_SET(0x37, 0x00); + + RTV_REG_SET(0xA8, 0x7F); + + RTV_REG_SET(0xAA, 0x00); + RTV_REG_SET(0xB0, 0x07); + RTV_REG_SET(0xD5, 0x80); /* DEFAULT Time Slice OFF. */ + +#if defined(RTV_SCAN_FIC_HDR_ENABLED) || defined(RTV_PLAY_FIC_HDR_ENABLED)\ +|| defined(RTV_MSC_HDR_ENABLED) + RTV_REG_SET(0xEA, RTV_MCH_HEADER_SYNC_BYTE); /* Header sync byte */ +#endif + +#ifdef RTV_FORCE_INSERT_SYNC_BYTE + RTV_REG_SET(0xF8, 0x04|0x02); +#else + RTV_REG_SET(0xF8, 0x04); +#endif + + RTV_REG_SET(0xFA, 0x07); + + /* all disable output */ + RTV_REG_SET(0xB2, 0x80); /* FIC: */ + RTV_REG_SET(0xB3, 0xF6); /* MSC */ + RTV_REG_SET(0xB4, 0x86); /* TDMB */ + RTV_REG_SET(0xB5, 0xB6); /* FIDC, DABP */ + + RTV_REG_SET(0xAA, 0x00); /* TSIF OFF */ + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + #ifdef RTV_NULL_PID_GENERATE + RTV_REG_SET(0xA4, 0x81|0x02); + #else + RTV_REG_SET(0xA4, 0x81); + #endif + + #ifdef RTV_ERROR_TSP_OUTPUT_DISABLE + RTV_REG_SET(0xA5, 0xC0); + #else + RTV_REG_SET(0xA5, 0x80); + #endif + + RTV_REG_SET(0xAF, 0x00); + RTV_REG_SET(0xB0, 0x04); +#else + rtv_ConfigureTsifFormat(); + RTV_REG_SET(0xB0, 0x00|RTV_FEC_TSIF_OUT_SPEED); +#endif + + RTV_REG_SET(0xAA, 0x7F); + +#if defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x16, 0xFF); + RTV_REG_SET(0x17, 0xFF); /* I2C intr disable */ +#endif + + RTV_REG_SET(0xD3, 0x00); + +} + +void rtvOEM_ConfigureInterrupt(void) +{ +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + RTV_REG_SET(0x21, SPI_INTR_POL_ACTIVE|0x02); + + #ifdef RTV_IF_SPI + RTV_REG_SET(0x27, 0x00); /* AUTO_INTR: 0 */ + #else + RTV_REG_SET(0x27, 0x02); /* AUTO_INTR: 0 */ + #endif + RTV_REG_SET(0x2B, RTV_SPI_INTR_DEACT_PRD_VAL); + + RTV_REG_SET(0x2A, 1); /* SRAM init */ + RTV_REG_SET(0x2A, 0); +#else + RTV_REG_MAP_SEL(FEC_PAGE); + RTV_REG_SET(0x11, I2C_INTR_POL_ACTIVE); +#endif +} + +static void tdmb_InitDemod(void) +{ + tdmb_InitHOST(); + tdmb_InitOFDM(); + tdmb_InitFEC(); + rtvOEM_ConfigureInterrupt(); +} + +INT rtvTDMB_Initialize(unsigned long interface) +{ + INT nRet; + +#if defined(RTV_IF_SPI) || defined (RTV_IF_TSIF) + mtv319_set_port_if(interface); +#endif + g_nOpenedSubChNum = 0; + g_nRegSubChArrayIdxBits = 0x0; + + g_aRegSubChIdBits[0] = 0x00000000; + g_aRegSubChIdBits[1] = 0x00000000; + + g_nUsedHwSubChIdxBits = 0x00; + + g_nTdmbPrevAntennaLevel = 0; + + g_eTdmbState = TDMB_STATE_INIT; + + g_fRtvFicOpened = FALSE; + + g_fTdmbFastScanEnabled = FALSE; + +#if defined(RTV_IF_SPI) || defined(RTV_IF_EBI2) + g_nRtvInterruptLevelSize = 0; +#elif defined(RTV_IF_TSIF) || defined(RTV_IF_SPI_SLAVE) + g_nRtvFicOpenedStatePath = FIC_NOT_OPENED; +#endif + + nRet = rtv_InitSystem(); + if (nRet != RTV_SUCCESS) + return nRet; + + /* Must after rtv_InitSystem(). */ + tdmb_InitDemod(); + + nRet = rtvRF_Initilize(); + if (nRet != RTV_SUCCESS) + goto tdmb_init_exit; + + rtv_SoftReset(); + +tdmb_init_exit: + + return RTV_SUCCESS; +} + + + diff --git a/drivers/media/tdmb/tdmb_port_mtv319.c b/drivers/media/tdmb/tdmb_port_mtv319.c new file mode 100644 index 000000000000..e18c1a5d8926 --- /dev/null +++ b/drivers/media/tdmb/tdmb_port_mtv319.c @@ -0,0 +1,377 @@ +/* +* +* drivers/media/tdmb/tdmb_port_mtv319.c +* +* tdmb driver +* +* Copyright (C) (2013, Samsung Electronics) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation version 2. +* +* This program is distributed "as is" WITHOUT ANY WARRANTY of any +* kind, whether express or implied; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +/*#include */ + +#include "mtv319.h" +#include "mtv319_internal.h" +#include "mtv319_ficdec_internal.h" +#include "mtv319_ficdec.h" +#include "mtv319_port.h" + +#include "tdmb.h" + +#define MTV319_INTERRUPT_SIZE (188*16) +#define MTV319_TS_BUF_SIZE (MTV319_SPI_CMD_SIZE + MTV319_INTERRUPT_SIZE) + +#if defined(CONFIG_TDMB_TSIF_SLSI) || defined(CONFIG_TDMB_TSIF_QC) +#define TDMB_FIC_USE_TSIF +#define FIC_PACKET_COUNT 3 +#define MSC_PACKET_COUNT 16 +#endif + +/* #define TDMB_DEBUG_SCAN */ + +static bool mtv319_on_air; +static bool mtv319_pwr_on; + +#ifdef CONFIG_TDMB_SPI +static U8 stream_buff[MTV319_TS_BUF_SIZE] __cacheline_aligned; +#endif +static U8 fic_buf[MTV319_FIC_BUF_SIZE] __cacheline_aligned; + +#ifdef TDMB_DEBUG_SCAN +static void __print_ensemble_info(struct ensemble_info_type *e_info) +{ + int i = 0; + + DPRINTK("ensem_freq(%ld)\n", e_info->ensem_freq); + DPRINTK("ensem_label(%s)\n", e_info->ensem_label); + for (i = 0; i < e_info->tot_sub_ch; i++) { + DPRINTK("sub_ch_id(0x%x)\n", e_info->sub_ch[i].sub_ch_id); + DPRINTK("start_addr(0x%x)\n", e_info->sub_ch[i].start_addr); + DPRINTK("tmid(0x%x)\n", e_info->sub_ch[i].tmid); + DPRINTK("svc_type(0x%x)\n", e_info->sub_ch[i].svc_type); + DPRINTK("svc_label(%s)\n", e_info->sub_ch[i].svc_label); + DPRINTK("scids(0x%x)\n", e_info->sub_ch[i].scids); + DPRINTK("ecc(0x%x)\n", e_info->sub_ch[i].ecc); + } +} +#endif + +static bool __get_ensemble_info(struct ensemble_info_type *e_info + , unsigned long freq) +{ + DPRINTK("%s\n", __func__); + + rtvFICDEC_GetEnsembleInfo(e_info, freq); + + if (e_info->tot_sub_ch) { +#ifdef TDMB_DEBUG_SCAN + __print_ensemble_info(e_info); +#endif + return true; + } else { + return false; + } +} + +static void mtv319_power_off(void) +{ + DPRINTK("mtv319_power_off\n"); + + if (mtv319_pwr_on) { + mtv319_on_air = false; +#if defined(CONFIG_TDMB_TSIF_SLSI) || defined(CONFIG_TDMB_TSIF_QC) + tdmb_tsi_stop(); +#else + tdmb_control_irq(false); +#endif + tdmb_control_gpio(false); + + mtv319_pwr_on = false; + + RTV_GUARD_DEINIT; + } +} + +static bool mtv319_power_on(int param) +{ + DPRINTK("mtv319_power_on\n"); + + if (mtv319_pwr_on) { + return true; + } else { + tdmb_control_gpio(true); + + RTV_GUARD_INIT; + + if (rtvTDMB_Initialize(tdmb_get_if_handle()) != RTV_SUCCESS) { + tdmb_control_gpio(false); + return false; + } else { +#if !defined(CONFIG_TDMB_TSIF_SLSI) && !defined(CONFIG_TDMB_TSIF_QC) + tdmb_control_irq(true); +#endif + mtv319_pwr_on = true; + return true; + } + } +} + +static void mtv319_get_dm(struct tdmb_dm *info) +{ + if (mtv319_pwr_on == true && mtv319_on_air == true) { + info->rssi = (rtvTDMB_GetRSSI() / RTV_TDMB_RSSI_DIVIDER); + info->per = rtvTDMB_GetPER(); + info->ber = rtvTDMB_GetCER(); + info->antenna = rtvTDMB_GetAntennaLevel(info->ber); + } else { + info->rssi = 100; + info->ber = 2000; + info->per = 0; + info->antenna = 0; + } +} + +#if defined(CONFIG_TDMB_TSIF_SLSI) || defined(CONFIG_TDMB_TSIF_QC) +#ifdef TDMB_FIC_USE_TSIF +#define FIC_TIMEOUT 1200 +#define FIC_WAIT_TIME 20 +static int rtv_fic_dec_result; +static int rtv_fic_dec_timeout; +static void dmb_drv_fic_cb(u8 *data, u32 length) +{ + int fic_size; + if (rtv_fic_dec_result == RTV_FIC_RET_DONE) + return; + + fic_size = mtv319_assemble_fic(fic_buf, data, length); + if (fic_size >= 96) { + enum E_RTV_FIC_DEC_RET_TYPE dc; + dc = rtvFICDEC_Decode(fic_buf, fic_size); + rtv_fic_dec_result = dc; + } +#ifdef TDMB_DEBUG_SCAN + DPRINTK("%s : length:%d fic_size:%d decode:%d\n", + __func__, length, fic_size, rtv_fic_dec_result); +#endif +} +#endif + +static void dmb_drv_msc_cb(u8 *data, u32 length) +{ +/* DPRINTK("%s : 0x%x 0x%x 0x%x 0x%x \n", __func__, data[0], data[1], data[3], data[4]); */ + tdmb_store_data(data, length); +} +#endif +static bool mtv319_set_ch(unsigned long freq + , unsigned char subchid + , bool factory_test) +{ + bool ret = false; + enum E_RTV_SERVICE_TYPE svc_type; + + DPRINTK("%s : %ld %d\n", __func__, freq, subchid); + + if (mtv319_pwr_on) { + int ch_ret; + + rtvTDMB_CloseAllSubChannels(); +#if defined(CONFIG_TDMB_TSIF_SLSI) || defined(CONFIG_TDMB_TSIF_QC) + tdmb_tsi_stop(); + if (tdmb_tsi_start(dmb_drv_msc_cb, MSC_PACKET_COUNT) != 0) + return false; +#endif + if (subchid >= 64) { + subchid -= 64; + svc_type = RTV_SERVICE_DMB; + } else + svc_type = RTV_SERVICE_DAB; + + ch_ret = rtvTDMB_OpenSubChannel((freq/1000), + subchid, + svc_type, + MTV319_INTERRUPT_SIZE); + if (ch_ret == RTV_SUCCESS + || ch_ret == RTV_ALREADY_OPENED_SUBCHANNEL_ID) { + mtv319_on_air = true; + ret = TRUE; + DPRINTK("mtv319_set_ch Success\n"); + } else { + DPRINTK("mtv319_set_ch Fail (%d)\n", ch_ret); + } + } + + return ret; +} + +static bool mtv319_scan_ch(struct ensemble_info_type *e_info + , unsigned long freq) +{ + bool ret = false; + + if (mtv319_pwr_on == true && e_info != NULL) { + rtvTDMB_CloseAllSubChannels(); +#if defined(TDMB_FIC_USE_TSIF) + rtv_fic_dec_result = RTV_FIC_RET_GOING; + rtv_fic_dec_timeout = FIC_TIMEOUT; + + tdmb_tsi_stop(); + if (tdmb_tsi_start(dmb_drv_fic_cb, FIC_PACKET_COUNT) != 0) + return false; + rtvFICDEC_Init(); +#endif + if (rtvTDMB_ScanFrequency(freq/1000) == RTV_SUCCESS) { +#if defined(TDMB_FIC_USE_TSIF) + unsigned int lock_s; + while(rtv_fic_dec_result == RTV_FIC_RET_GOING \ + && rtv_fic_dec_timeout > 0) { + lock_s = tdmb_GetOfdmLockStatus(); + if (!(lock_s & RTV_TDMB_OFDM_LOCK_MASK)) { + DPRINTK("##lock_s(0x%02X)\n",lock_s); + break; + } + RTV_DELAY_MS(FIC_WAIT_TIME); + rtv_fic_dec_timeout -= FIC_WAIT_TIME; + }; + + rtvTDMB_CloseFIC(); + if (rtv_fic_dec_result == RTV_FIC_RET_DONE) + ret = true; +#else + enum E_RTV_FIC_DEC_RET_TYPE dc; + unsigned int i; + + rtvFICDEC_Init(); /* FIC parser Init */ + + for (i = 0; i < 30; i++) { + int ret_size; + ret_size = rtvTDMB_ReadFIC(fic_buf); + if (ret_size > 0) { + dc = rtvFICDEC_Decode(fic_buf, 384); + if (dc == RTV_FIC_RET_GOING) + continue; + + if (dc == RTV_FIC_RET_DONE) + ret = true; + + break; /* Stop */ + } else { + DPRINTK("mtv319_scan_ch READ Fail\n"); + } + } + + rtvTDMB_CloseFIC(); +#endif + if (ret == true) + ret = __get_ensemble_info(e_info, (freq)); + } else { + DPRINTK("%s : Scan fail : %ld\n", __func__, freq); + ret = false; + } + } + + return ret; +} + +#if !defined(CONFIG_TDMB_TSIF_SLSI) && !defined(CONFIG_TDMB_TSIF_QC) +static void mtv319_pull_data(void) +{ + U8 ifreg, istatus; + + RTV_GUARD_LOCK; + + RTV_REG_MAP_SEL(SPI_CTRL_PAGE); + + ifreg = RTV_REG_GET(0x55); + if (ifreg != 0xAA) { + mtv319_spi_recover(stream_buff, MTV319_INTERRUPT_SIZE); + DPRINTK("Interface error 1\n"); + } + + istatus = RTV_REG_GET(0x10); + if (istatus & (U8)(~SPI_INTR_BITS)) { + mtv319_spi_recover(stream_buff, MTV319_INTERRUPT_SIZE); + DPRINTK("Interface error 2 (0x%02X)\n", istatus); + goto exit_read_mem; + } + + if (istatus & SPI_UNDERFLOW_INTR) { + RTV_REG_SET(0x2A, 1); + RTV_REG_SET(0x2A, 0); + DPRINTK("UDF: 0x%02X\n", istatus); + goto exit_read_mem; + } + + if (istatus & SPI_THRESHOLD_INTR) { + RTV_REG_MAP_SEL(SPI_MEM_PAGE); + RTV_REG_BURST_GET(0x10, stream_buff, MTV319_INTERRUPT_SIZE); + + tdmb_store_data(stream_buff, MTV319_INTERRUPT_SIZE); + + if (istatus & SPI_OVERFLOW_INTR) + DPRINTK("OVF: 0x%02X\n", istatus); /* To debug */ + } else + DPRINTK("No data interrupt (0x%02X)\n", istatus); + +exit_read_mem: + RTV_GUARD_FREE; +} +#endif + +static unsigned long mtv319_int_size(void) +{ + return MTV319_INTERRUPT_SIZE; +} + +static bool mtv319_init(void) +{ + return true; +} + +static struct tdmb_drv_func raontech_mtv319_drv_func = { + .init = mtv319_init, + .power_on = mtv319_power_on, + .power_off = mtv319_power_off, + .scan_ch = mtv319_scan_ch, + .get_dm = mtv319_get_dm, + .set_ch = mtv319_set_ch, +#if !defined(CONFIG_TDMB_TSIF_SLSI) && !defined(CONFIG_TDMB_TSIF_QC) + .pull_data = mtv319_pull_data, +#endif + .get_int_size = mtv319_int_size, +}; + +struct tdmb_drv_func *mtv319_drv_func(void) +{ + DPRINTK("tdmb_get_drv_func : mtv319\n"); + return &raontech_mtv319_drv_func; +} diff --git a/drivers/media/v4l2-core/videobuf2-ion.c b/drivers/media/v4l2-core/videobuf2-ion.c index 9226bb2aa0b5..92ef657435b7 100644 --- a/drivers/media/v4l2-core/videobuf2-ion.c +++ b/drivers/media/v4l2-core/videobuf2-ion.c @@ -894,6 +894,7 @@ static struct vm_area_struct *vb2_ion_get_vma(struct device *dev, vb2ion_err(dev, "[%#lx, %#lx) crosses disparate vmas\n", vaddr, size); + vb2_put_vma(cur_vma); break; } new_vma->vm_next = cur_vma; @@ -932,13 +933,17 @@ static void *vb2_ion_get_userptr(void *alloc_ctx, unsigned long vaddr, void *p_ret; vma = vb2_ion_get_vma(ctx->dev, vaddr, size); - if (!vma) + if (!vma) { + dev_err(ctx->dev, + "%s: Failed to holding user buffer @ %#lx/%#lx\n", + __func__, vaddr, size); return ERR_PTR(-EINVAL); + } buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) { dev_err(ctx->dev, "%s: Not enough memory\n", __func__); - return ERR_PTR(-ENOMEM); + goto err_alloc_buf; } if (vma->vm_file) @@ -962,6 +967,7 @@ static void *vb2_ion_get_userptr(void *alloc_ctx, unsigned long vaddr, buf->ctx = ctx; buf->direction = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; buf->size = size; + buf->vma = vma; buf->attachment = dma_buf_attach(buf->dma_buf, ctx->dev); if (IS_ERR(buf->attachment)) { @@ -971,15 +977,6 @@ static void *vb2_ion_get_userptr(void *alloc_ctx, unsigned long vaddr, goto err_attach; } - buf->vma = vma; - if (IS_ERR(buf->vma)) { - dev_err(ctx->dev, - "%s: Failed to holding user buffer @ %#lx/%#lx\n", - __func__, vaddr, size); - p_ret = buf->vma; - goto err_get_vma; - } - buf->cookie.sgt = dma_buf_map_attachment(buf->attachment, buf->direction); if (IS_ERR(buf->cookie.sgt)) { @@ -1017,13 +1014,13 @@ static void *vb2_ion_get_userptr(void *alloc_ctx, unsigned long vaddr, dma_buf_unmap_attachment(buf->attachment, buf->cookie.sgt, buf->direction); err_map_attachment: - vb2_ion_put_vma(buf->vma); -err_get_vma: dma_buf_detach(buf->dma_buf, buf->attachment); err_attach: dma_buf_put(buf->dma_buf); err_get_user_pages: kfree(buf); +err_alloc_buf: + vb2_ion_put_vma(vma); return p_ret; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d1e46f8576c3..d0278ae1d657 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1139,11 +1139,11 @@ config MFD_FLORIDA Support for Wolfson Microelectronics Florida class low power audio SoC such as the WM8280 -config MFD_WM8998 - bool "Support Wolfson Microelectronics WM8998" +config MFD_VEGAS + bool "Support Wolfson Microelectronics Vegas" depends on MFD_ARIZONA help - Support for Wolfson Microelectronics WM8998 low power audio SoC + Support for Wolfson Microelectronics Vegas low power audio SoC config MFD_WM8997 bool "Wolfson Microelectronics WM8997" @@ -1158,11 +1158,17 @@ config MFD_CLEARWATER Support for Wolfson Microelectronics ClearWater class low power audio SoC such as the WM8285 -config MFD_CS47L24 - bool "Cirrus Logic CS47L24" +config MFD_LARGO + bool "Cirrus Logic Largo" depends on MFD_ARIZONA help - Support for Cirrus Logic CS47L24 low power audio SoC + Support for Cirrus Logic Largo low power audio SoC + +config MFD_MARLEY + bool "Cirrus Logic Marley" + depends on MFD_ARIZONA + help + Support for Cirrus Logic Marley low power audio SoC config MFD_WM8400 bool "Wolfson Microelectronics WM8400" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 4e9ee889b105..0ae185c63fd2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -46,14 +46,17 @@ endif ifneq ($(CONFIG_MFD_WM8997),n) obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o endif -ifneq ($(CONFIG_MFD_WM8998),n) -obj-$(CONFIG_MFD_ARIZONA) += wm8998-tables.o +ifneq ($(CONFIG_MFD_VEGAS),n) +obj-$(CONFIG_MFD_ARIZONA) += vegas-tables.o endif ifneq ($(CONFIG_MFD_CLEARWATER),n) obj-$(CONFIG_MFD_ARIZONA) += clearwater-tables.o endif -ifneq ($(CONFIG_MFD_CS47L24),n) -obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o +ifneq ($(CONFIG_MFD_MARLEY),n) +obj-$(CONFIG_MFD_ARIZONA) += marley-tables.o +endif +ifneq ($(CONFIG_MFD_LARGO),n) +obj-$(CONFIG_MFD_ARIZONA) += largo-tables.o endif obj-$(CONFIG_MFD_WM8400) += wm8400-core.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index da420cf386c2..b3ab8b96f6f4 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -840,6 +840,12 @@ static int arizona_runtime_suspend(struct device *dev) arizona_restore_dvfs(arizona); return ret; } +#else +static inline int arizona_dcvdd_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + return 0; +} #endif #ifdef CONFIG_PM_SLEEP @@ -1270,6 +1276,7 @@ const struct of_device_id arizona_of_match[] = { { .compatible = "wlf,wm1840", .data = (void *)WM1840 }, { .compatible = "wlf,wm1831", .data = (void *)WM1831 }, { .compatible = "cirrus,cs47l24", .data = (void *)CS47L24 }, + { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 }, {}, }; EXPORT_SYMBOL_GPL(arizona_of_match); @@ -1302,11 +1309,11 @@ static struct mfd_cell florida_devs[] = { { .name = "florida-codec" }, }; -static struct mfd_cell cs47l24_devs[] = { +static struct mfd_cell largo_devs[] = { { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, - { .name = "cs47l24-codec" }, + { .name = "largo-codec" }, }; static struct mfd_cell wm8997_devs[] = { @@ -1318,13 +1325,13 @@ static struct mfd_cell wm8997_devs[] = { { .name = "wm8997-codec" }, }; -static struct mfd_cell wm8998_devs[] = { +static struct mfd_cell vegas_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-extcon" }, { .name = "arizona-gpio" }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, - { .name = "wm8998-codec" }, + { .name = "vegas-codec" }, }; static struct mfd_cell clearwater_devs[] = { @@ -1336,6 +1343,15 @@ static struct mfd_cell clearwater_devs[] = { { .name = "clearwater-codec" }, }; +static struct mfd_cell marley_devs[] = { + { .name = "arizona-micsupp" }, + { .name = "arizona-extcon" }, + { .name = "arizona-gpio" }, + { .name = "arizona-haptics" }, + { .name = "arizona-pwm" }, + { .name = "marley-codec" }, +}; + static const struct { unsigned int enable; unsigned int conf_reg; @@ -1501,6 +1517,7 @@ int arizona_dev_init(struct arizona *arizona) case WM1840: case WM1831: case CS47L24: + case CS47L35: for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++) arizona->core_supplies[i].supply = wm5102_core_supplies[i]; @@ -1523,6 +1540,7 @@ int arizona_dev_init(struct arizona *arizona) switch (arizona->type) { case WM1831: case CS47L24: + case CS47L35: break; default: ret = mfd_add_devices(arizona->dev, -1, early_devs, @@ -1621,6 +1639,7 @@ int arizona_dev_init(struct arizona *arizona) case 0x6363: case 0x8997: case 0x6338: + case 0x6360: break; default: dev_err(arizona->dev, "Unknown device ID: %x\n", reg); @@ -1722,7 +1741,7 @@ int arizona_dev_init(struct arizona *arizona) apply_patch = florida_patch; break; #endif -#ifdef CONFIG_MFD_CS47L24 +#ifdef CONFIG_MFD_LARGO case 0x6363: switch (arizona->type) { case CS47L24: @@ -1736,14 +1755,14 @@ int arizona_dev_init(struct arizona *arizona) break; default: - dev_err(arizona->dev, "CS47L24 codec registered as %d\n", + dev_err(arizona->dev, "Largo codec registered as %d\n", arizona->type); arizona->type = CS47L24; - type_name = "CS47L24"; + type_name = "Largo"; revision_char = arizona->rev + 'A'; break; } - apply_patch = cs47l24_patch; + apply_patch = largo_patch; break; #endif #ifdef CONFIG_MFD_WM8997 @@ -1758,7 +1777,7 @@ int arizona_dev_init(struct arizona *arizona) apply_patch = wm8997_patch; break; #endif -#ifdef CONFIG_MFD_WM8998 +#ifdef CONFIG_MFD_VEGAS case 0x6349: switch (arizona->type) { case WM8998: @@ -1775,7 +1794,7 @@ int arizona_dev_init(struct arizona *arizona) arizona->type = WM8998; } - apply_patch = wm8998_patch; + apply_patch = vegas_patch; revision_char = arizona->rev + 'A'; break; #endif @@ -1800,7 +1819,24 @@ int arizona_dev_init(struct arizona *arizona) apply_patch = clearwater_patch; break; #endif - default: +#ifdef CONFIG_MFD_MARLEY + case 0x6360: + switch (arizona->type) { + case CS47L35: + type_name = "CS47L35"; + break; + + default: + dev_err(arizona->dev, + "Unknown Marley codec registered as CS47L35\n"); + arizona->type = CS47L35; + } + + revision_char = arizona->rev + 'A'; + apply_patch = marley_patch; + break; +#endif +default: dev_err(arizona->dev, "Unknown device ID %x\n", reg); goto err_reset; } @@ -2071,8 +2107,8 @@ int arizona_dev_init(struct arizona *arizona) break; case WM1831: case CS47L24: - ret = mfd_add_devices(arizona->dev, -1, cs47l24_devs, - ARRAY_SIZE(cs47l24_devs), NULL, 0, NULL); + ret = mfd_add_devices(arizona->dev, -1, largo_devs, + ARRAY_SIZE(largo_devs), NULL, 0, NULL); break; case WM8997: ret = mfd_add_devices(arizona->dev, -1, wm8997_devs, @@ -2080,14 +2116,18 @@ int arizona_dev_init(struct arizona *arizona) break; case WM8998: case WM1814: - ret = mfd_add_devices(arizona->dev, -1, wm8998_devs, - ARRAY_SIZE(wm8998_devs), NULL, 0, NULL); + ret = mfd_add_devices(arizona->dev, -1, vegas_devs, + ARRAY_SIZE(vegas_devs), NULL, 0, NULL); break; case WM8285: case WM1840: ret = mfd_add_devices(arizona->dev, -1, clearwater_devs, ARRAY_SIZE(clearwater_devs), NULL, 0, NULL); break; + case CS47L35: + ret = mfd_add_devices(arizona->dev, -1, marley_devs, + ARRAY_SIZE(marley_devs), NULL, 0, NULL); + break; } if (ret != 0) { diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index c5440d44514b..393696ab6465 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -53,10 +53,10 @@ static int arizona_i2c_probe(struct i2c_client *i2c, regmap_config = &wm8997_i2c_regmap; break; #endif -#ifdef CONFIG_MFD_WM8998 +#ifdef CONFIG_MFD_VEGAS case WM8998: case WM1814: - regmap_config = &wm8998_i2c_regmap; + regmap_config = &vegas_i2c_regmap; break; #endif #ifdef CONFIG_MFD_CLEARWATER @@ -65,6 +65,12 @@ static int arizona_i2c_probe(struct i2c_client *i2c, regmap_config = &clearwater_16bit_i2c_regmap; regmap_32bit_config = &clearwater_32bit_i2c_regmap; break; +#endif +#ifdef CONFIG_MFD_MARLEY + case CS47L35: + regmap_config = &marley_16bit_i2c_regmap; + regmap_32bit_config = &marley_32bit_i2c_regmap; + break; #endif default: dev_err(&i2c->dev, "Unknown device type %ld\n", @@ -120,6 +126,7 @@ static const struct i2c_device_id arizona_i2c_id[] = { { "wm1814", WM1814 }, { "wm8285", WM8285 }, { "wm1840", WM1840 }, + { "cs47l35", CS47L35 }, { } }; MODULE_DEVICE_TABLE(i2c, arizona_i2c_id); diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index d45bcfd359e7..54af8befd001 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -159,6 +159,13 @@ static void arizona_irq_dummy(struct irq_data *data) { } +static int arizona_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct arizona *arizona = irq_data_get_irq_chip_data(data); + + return irq_set_irq_wake(arizona->irq, on); +} + static struct irq_chip arizona_irq_chip = { .name = "arizona", .irq_disable = arizona_irq_dummy, @@ -166,6 +173,7 @@ static struct irq_chip arizona_irq_chip = { .irq_ack = arizona_irq_dummy, .irq_mask = arizona_irq_dummy, .irq_unmask = arizona_irq_dummy, + .irq_set_wake = arizona_irq_set_wake, }; static int arizona_irq_map(struct irq_domain *h, unsigned int virq, @@ -238,11 +246,11 @@ int arizona_irq_init(struct arizona *arizona) irq_ctrl_reg = CLEARWATER_IRQ1_CTRL; break; #endif -#ifdef CONFIG_MFD_CS47L24 +#ifdef CONFIG_MFD_LARGO case WM1831: case CS47L24: aod = NULL; - irq = &cs47l24_irq; + irq = &largo_irq; ctrlif_error = false; break; @@ -255,16 +263,25 @@ int arizona_irq_init(struct arizona *arizona) ctrlif_error = false; break; #endif -#ifdef CONFIG_MFD_WM8998 +#ifdef CONFIG_MFD_VEGAS case WM8998: case WM1814: - aod = &wm8998_aod; - irq = &wm8998_irq; + aod = &vegas_aod; + irq = &vegas_irq; ctrlif_error = false; break; #endif - default: +#ifdef CONFIG_MFD_MARLEY + case CS47L35: + aod = &marley_irq; + irq = NULL; + + ctrlif_error = false; + irq_ctrl_reg = CLEARWATER_IRQ1_CTRL; + break; +#endif +default: BUG_ON("Unknown Arizona class device" == NULL); return -EINVAL; } @@ -333,7 +350,7 @@ int arizona_irq_init(struct arizona *arizona) if (aod) { ret = regmap_add_irq_chip(arizona->regmap, irq_create_mapping(arizona->virq, 0), - IRQF_ONESHOT, -1, aod, + IRQF_ONESHOT, 0, aod, &arizona->aod_irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", @@ -345,7 +362,7 @@ int arizona_irq_init(struct arizona *arizona) if (irq) { ret = regmap_add_irq_chip(arizona->regmap, irq_create_mapping(arizona->virq, 1), - IRQF_ONESHOT, -1, irq, + IRQF_ONESHOT, 0, irq, &arizona->irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret); diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 1dddc6c456aa..a70e34558829 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -56,10 +56,16 @@ static int arizona_spi_probe(struct spi_device *spi) regmap_32bit_config = &clearwater_32bit_spi_regmap; break; #endif -#ifdef CONFIG_MFD_CS47L24 +#ifdef CONFIG_MFD_LARGO case WM1831: case CS47L24: - regmap_config = &cs47l24_spi_regmap; + regmap_config = &largo_spi_regmap; + break; +#endif +#ifdef CONFIG_MFD_MARLEY + case CS47L35: + regmap_config = &marley_16bit_spi_regmap; + regmap_32bit_config = &marley_32bit_spi_regmap; break; #endif default: @@ -115,6 +121,7 @@ static const struct spi_device_id arizona_spi_ids[] = { { "wm1840", WM1840 }, { "wm1831", WM1831 }, { "cs47l24", CS47L24 }, + { "cs47l35", CS47L35 }, { }, }; MODULE_DEVICE_TABLE(spi, arizona_spi_ids); diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h index ec54352c8ef1..76b6bb681842 100644 --- a/drivers/mfd/arizona.h +++ b/drivers/mfd/arizona.h @@ -31,11 +31,16 @@ extern const struct regmap_config clearwater_16bit_spi_regmap; extern const struct regmap_config clearwater_32bit_spi_regmap; extern const struct regmap_config clearwater_32bit_i2c_regmap; +extern const struct regmap_config marley_16bit_i2c_regmap; +extern const struct regmap_config marley_16bit_spi_regmap; +extern const struct regmap_config marley_32bit_spi_regmap; +extern const struct regmap_config marley_32bit_i2c_regmap; + extern const struct regmap_config wm8997_i2c_regmap; -extern const struct regmap_config wm8998_i2c_regmap; +extern const struct regmap_config vegas_i2c_regmap; -extern const struct regmap_config cs47l24_spi_regmap; +extern const struct regmap_config largo_spi_regmap; extern const struct dev_pm_ops arizona_pm_ops; @@ -53,10 +58,12 @@ extern const struct regmap_irq_chip clearwater_irq; extern const struct regmap_irq_chip wm8997_aod; extern const struct regmap_irq_chip wm8997_irq; -extern struct regmap_irq_chip wm8998_aod; -extern struct regmap_irq_chip wm8998_irq; +extern struct regmap_irq_chip vegas_aod; +extern struct regmap_irq_chip vegas_irq; + +extern const struct regmap_irq_chip largo_irq; -extern const struct regmap_irq_chip cs47l24_irq; +extern const struct regmap_irq_chip marley_irq; int arizona_dev_init(struct arizona *arizona); int arizona_dev_exit(struct arizona *arizona); diff --git a/drivers/mfd/clearwater-tables.c b/drivers/mfd/clearwater-tables.c index abdbf28700b8..f55df8be6c74 100644 --- a/drivers/mfd/clearwater-tables.c +++ b/drivers/mfd/clearwater-tables.c @@ -465,6 +465,7 @@ static const struct reg_default clearwater_reg_default[] = { { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics phase 2 duration */ { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics phase 3 intensity */ { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics phase 3 duration */ + { 0x000000A0, 0x0000 }, /* R160 (0xA0) - Clearwater Comfort Noise Generator */ { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */ { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */ { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample rate 1 */ @@ -544,16 +545,9 @@ static const struct reg_default clearwater_reg_default[] = { { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */ { 0x0000021a, 0x00e6 }, /* R538 (0x21A) - Mic Bias Ctrl 3 */ { 0x0000021B, 0x00e6 }, /* R539 - Mic Bias Ctrl 4 */ - { 0x00000225, 0x1406 }, - { 0x00000226, 0x1406 }, - { 0x00000227, 0x1406 }, - { 0x00000228, 0x1406 }, - { 0x00000229, 0x1406 }, - { 0x0000022a, 0x1406 }, { 0x0000027e, 0x0000 }, /* R638 (0x27E) - Clearwater EDRE HP stereo control */ { 0x00000293, 0x0000 }, /* R659 (0x293) - Accessory Detect Mode 1 */ { 0x0000029b, 0x0000 }, /* R667 (0x29B) - Headphone Detect 1 */ - { 0x0000029f, 0x0000 }, { 0x000002a3, 0x1102 }, /* R675 (0x2A3) - Mic Detect 1 */ { 0x000002a4, 0x009f }, /* R676 (0x2A4) - Mic Detect 2 */ { 0x000002a6, 0x3737 }, @@ -1512,6 +1506,7 @@ static const struct reg_default clearwater_reg_default[] = { { 0x00000F02, 0x0000 }, /* R3842 - Arizona DSP Status */ { 0x00000F08, 0x001c }, /* R3848 - ANC Coefficient */ { 0x00000F09, 0x0000 }, /* R3849 - ANC Coefficient */ + { 0x00000F0A, 0x0000 }, /* R3850 - ANC Coefficient */ { 0x00000F0B, 0x0000 }, /* R3851 - ANC Coefficient */ { 0x00000F0C, 0x0000 }, /* R3852 - ANC Coefficient */ { 0x00000F0D, 0x0000 }, /* R3853 - ANC Coefficient */ @@ -1919,7 +1914,6 @@ static bool clearwater_16bit_readable_register(struct device *dev, unsigned int case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: - case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: case ARIZONA_HAPTICS_PHASE_1_INTENSITY: @@ -1929,6 +1923,7 @@ static bool clearwater_16bit_readable_register(struct device *dev, unsigned int case ARIZONA_HAPTICS_PHASE_3_INTENSITY: case ARIZONA_HAPTICS_PHASE_3_DURATION: case ARIZONA_HAPTICS_STATUS: + case CLEARWATER_COMFORT_NOISE_GENERATOR: case ARIZONA_CLOCK_32K_1: case ARIZONA_SYSTEM_CLOCK_1: case ARIZONA_SAMPLE_RATE_1: @@ -2025,6 +2020,8 @@ static bool clearwater_16bit_readable_register(struct device *dev, unsigned int case ARIZONA_ACCESSORY_DETECT_MODE_1: case ARIZONA_HEADPHONE_DETECT_1: case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HEADPHONE_DETECT_3: + case ARIZONA_HP_DACVAL: case CLEARWATER_MICD_CLAMP_CONTROL: case ARIZONA_MIC_DETECT_1: case ARIZONA_MIC_DETECT_2: @@ -3233,11 +3230,20 @@ static bool clearwater_16bit_volatile_register(struct device *dev, unsigned int case ARIZONA_SAMPLE_RATE_2_STATUS: case ARIZONA_SAMPLE_RATE_3_STATUS: case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: + case ARIZONA_HP_CTRL_1L: + case ARIZONA_HP_CTRL_1R: + case ARIZONA_HP_CTRL_2L: + case ARIZONA_HP_CTRL_2R: + case ARIZONA_HP_CTRL_3L: + case ARIZONA_HP_CTRL_3R: case ARIZONA_DCS_HP1L_CONTROL: case ARIZONA_DCS_HP1R_CONTROL: case ARIZONA_MIC_DETECT_3: case ARIZONA_MIC_DETECT_4: case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HEADPHONE_DETECT_3: + case ARIZONA_HP_DACVAL: case ARIZONA_INPUT_ENABLES_STATUS: case ARIZONA_OUTPUT_STATUS_1: case ARIZONA_RAW_OUTPUT_STATUS_1: @@ -3310,6 +3316,7 @@ static bool clearwater_32bit_readable_register(struct device *dev, unsigned int { switch (reg) { case ARIZONA_WSEQ_SEQUENCE_1 ... ARIZONA_WSEQ_SEQUENCE_508: + case CLEARWATER_OTP_HPDET_CALIB_1 ... CLEARWATER_OTP_HPDET_CALIB_2: case CLEARWATER_DSP1_CONFIG ... CLEARWATER_DSP1_SCRATCH_3: case CLEARWATER_DSP2_CONFIG ... CLEARWATER_DSP2_SCRATCH_3: case CLEARWATER_DSP3_CONFIG ... CLEARWATER_DSP3_SCRATCH_3: @@ -3327,6 +3334,7 @@ static bool clearwater_32bit_volatile_register(struct device *dev, unsigned int { switch (reg) { case ARIZONA_WSEQ_SEQUENCE_1 ... ARIZONA_WSEQ_SEQUENCE_508: + case CLEARWATER_OTP_HPDET_CALIB_1 ... CLEARWATER_OTP_HPDET_CALIB_2: case CLEARWATER_DSP1_CONFIG ... CLEARWATER_DSP1_SCRATCH_3: case CLEARWATER_DSP2_CONFIG ... CLEARWATER_DSP2_SCRATCH_3: case CLEARWATER_DSP3_CONFIG ... CLEARWATER_DSP3_SCRATCH_3: diff --git a/drivers/mfd/florida-tables.c b/drivers/mfd/florida-tables.c index 99a7cf0d5351..f99a3dd2ba74 100644 --- a/drivers/mfd/florida-tables.c +++ b/drivers/mfd/florida-tables.c @@ -1659,6 +1659,7 @@ static const struct reg_default florida_reg_default[] = { { 0x00000F01, 0x0000 }, /* R3841 - ANC_SRC */ { 0x00000F08, 0x001c }, /* R3848 - ANC Coefficient */ { 0x00000F09, 0x0000 }, /* R3849 - ANC Coefficient */ + { 0x00000F0A, 0x0000 }, /* R3850 - ANC Coefficient */ { 0x00000F0B, 0x0000 }, /* R3851 - ANC Coefficient */ { 0x00000F0C, 0x0000 }, /* R3852 - ANC Coefficient */ { 0x00000F0D, 0x0000 }, /* R3853 - ANC Coefficient */ diff --git a/drivers/mfd/largo-tables.c b/drivers/mfd/largo-tables.c new file mode 100644 index 000000000000..62e99fa71021 --- /dev/null +++ b/drivers/mfd/largo-tables.c @@ -0,0 +1,1645 @@ +/* + * largo-tables.c -- data tables for Largo codec + * + * Copyright 2014 CirrusLogic, Inc. + * + * Author: Richard Fitzgerald + * + * 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. + */ + +#include + +#include +#include +#include + +#include "arizona.h" + +#define LARGO_NUM_ISR 5 + +static const struct reg_default largo_reva_patch[] = { + { 0x80, 0x3 }, + { 0x27C, 0x0010 }, + { 0x221, 0x0070 }, + { 0x80, 0x0 }, +}; + +/* We use a function so we can use ARRAY_SIZE() */ +int largo_patch(struct arizona *arizona) +{ + return regmap_register_patch(arizona->regmap, + largo_reva_patch, + ARRAY_SIZE(largo_reva_patch)); +} +EXPORT_SYMBOL_GPL(largo_patch); + +static const struct regmap_irq largo_irqs[ARIZONA_NUM_IRQ] = { + [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 }, + [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 }, + + [ARIZONA_IRQ_DSP3_RAM_RDY] = { + .reg_offset = 1, .mask = ARIZONA_DSP3_RAM_RDY_EINT1 + }, + [ARIZONA_IRQ_DSP2_RAM_RDY] = { + .reg_offset = 1, .mask = ARIZONA_DSP2_RAM_RDY_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ8] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ8_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ7] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ7_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ6] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ6_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ5] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ5_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ4] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ4_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ3] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ3_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ2] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ2_EINT1 + }, + [ARIZONA_IRQ_DSP_IRQ1] = { + .reg_offset = 1, .mask = ARIZONA_DSP_IRQ1_EINT1 + }, + + [ARIZONA_IRQ_SPK_OVERHEAT_WARN] = { + .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_WARN_EINT1 + }, + [ARIZONA_IRQ_SPK_OVERHEAT] = { + .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_EINT1 + }, + [ARIZONA_IRQ_WSEQ_DONE] = { + .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1 + }, + [ARIZONA_IRQ_DRC2_SIG_DET] = { + .reg_offset = 2, .mask = ARIZONA_DRC2_SIG_DET_EINT1 + }, + [ARIZONA_IRQ_DRC1_SIG_DET] = { + .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1 + }, + [ARIZONA_IRQ_ASRC2_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_ASRC2_LOCK_EINT1 + }, + [ARIZONA_IRQ_ASRC1_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_ASRC1_LOCK_EINT1 + }, + [ARIZONA_IRQ_UNDERCLOCKED] = { + .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1 + }, + [ARIZONA_IRQ_OVERCLOCKED] = { + .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1 + }, + [ARIZONA_IRQ_FLL2_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1 + }, + [ARIZONA_IRQ_FLL1_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1 + }, + [ARIZONA_IRQ_CLKGEN_ERR] = { + .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1 + }, + [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = { + .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1 + }, + + [ARIZONA_IRQ_CTRLIF_ERR] = { + .reg_offset = 3, .mask = ARIZONA_V2_CTRLIF_ERR_EINT1 + }, + [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = { + .reg_offset = 3, .mask = ARIZONA_V2_MIXER_DROPPED_SAMPLE_EINT1 + }, + [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = { + .reg_offset = 3, .mask = ARIZONA_V2_ASYNC_CLK_ENA_LOW_EINT1 + }, + [ARIZONA_IRQ_SYSCLK_ENA_LOW] = { + .reg_offset = 3, .mask = ARIZONA_V2_SYSCLK_ENA_LOW_EINT1 + }, + [ARIZONA_IRQ_ISRC1_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_V2_ISRC1_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_ISRC2_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_V2_ISRC2_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_ISRC3_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_V2_ISRC3_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_HP1R_DONE] = { + .reg_offset = 3, .mask = ARIZONA_HP1R_DONE_EINT1 + }, + [ARIZONA_IRQ_HP1L_DONE] = { + .reg_offset = 3, .mask = ARIZONA_HP1L_DONE_EINT1 + }, + + [ARIZONA_IRQ_BOOT_DONE] = { + .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1 + }, + [ARIZONA_IRQ_ASRC_CFG_ERR] = { + .reg_offset = 4, .mask = ARIZONA_V2_ASRC_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_FLL2_CLOCK_OK] = { + .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1 + }, + [ARIZONA_IRQ_FLL1_CLOCK_OK] = { + .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1 + }, + + [ARIZONA_IRQ_DSP_SHARED_WR_COLL] = { + .reg_offset = 5, .mask = ARIZONA_DSP_SHARED_WR_COLL_EINT1 + }, + [ARIZONA_IRQ_SPK_SHUTDOWN] = { + .reg_offset = 5, .mask = ARIZONA_SPK_SHUTDOWN_EINT1 + }, + [ARIZONA_IRQ_SPK1R_SHORT] = { + .reg_offset = 5, .mask = ARIZONA_SPK1R_SHORT_EINT1 + }, + [ARIZONA_IRQ_SPK1L_SHORT] = { + .reg_offset = 5, .mask = ARIZONA_SPK1L_SHORT_EINT1 + }, + [ARIZONA_IRQ_HP1R_SC_NEG] = { + .reg_offset = 5, .mask = ARIZONA_HP1R_SC_NEG_EINT1 + }, + [ARIZONA_IRQ_HP1R_SC_POS] = { + .reg_offset = 5, .mask = ARIZONA_HP1R_SC_POS_EINT1 + }, + [ARIZONA_IRQ_HP1L_SC_NEG] = { + .reg_offset = 5, .mask = ARIZONA_HP1L_SC_NEG_EINT1 + }, + [ARIZONA_IRQ_HP1L_SC_POS] = { + .reg_offset = 5, .mask = ARIZONA_HP1L_SC_POS_EINT1 + }, +}; + +const struct regmap_irq_chip largo_irq = { + .name = "largo IRQ", + .status_base = ARIZONA_INTERRUPT_STATUS_1, + .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK, + .ack_base = ARIZONA_INTERRUPT_STATUS_1, + .num_regs = 6, + .irqs = largo_irqs, + .num_irqs = ARRAY_SIZE(largo_irqs), +}; +EXPORT_SYMBOL_GPL(largo_irq); + +static const struct reg_default largo_reg_default[] = { + { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */ + { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ + { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ + { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ + { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ + { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */ + { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */ + { 0x00000101, 0x0504 }, /* R257 - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */ + { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */ + { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */ + { 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */ + { 0x00000149, 0x0000 }, /* R329 - Output system clock */ + { 0x0000014A, 0x0000 }, /* R330 - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ + { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ + { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ + { 0x00000175, 0x0006 }, /* R373 - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ + { 0x00000177, 0x0281 }, /* R375 - FLL1 Loop Filter Test 1 */ + { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R376 - FLL1 Control 7 */ + { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ + { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ + { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ + { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ + { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ + { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R390 - FLL1 Synchroniser 7 */ + { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ + { 0x0000018A, 0x000C }, /* R394 - FLL1 GPIO Clock */ + { 0x00000191, 0x0002 }, /* R401 - FLL2 Control 1 */ + { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */ + { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */ + { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */ + { 0x00000195, 0x000C }, /* R405 - FLL2 Control 5 */ + { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ + { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ + { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R408 - FLL2 Control 7 */ + { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ + { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ + { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ + { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ + { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ + { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R422 - FLL2 Synchroniser 7 */ + { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ + { 0x000001AA, 0x000C }, /* R426 - FLL2 GPIO Clock */ + { 0x00000218, 0x00E6 }, /* R536 - Mic Bias Ctrl 1 */ + { 0x00000219, 0x00E6 }, /* R537 - Mic Bias Ctrl 2 */ + { 0x00000300, 0x0000 }, /* R768 - Input Enables */ + { 0x00000308, 0x0000 }, /* R776 - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ + { 0x0000030C, 0x0002 }, /* R780 - HPF Control */ + { 0x00000310, 0x2000 }, /* R784 - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ + { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ + { 0x00000314, 0x0000 }, /* R788 - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */ + { 0x00000318, 0x2000 }, /* R792 - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */ + { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */ + { 0x0000031C, 0x0000 }, /* R796 - IN2R Control */ + { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */ + { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */ + { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ + { 0x00000410, 0x0080 }, /* R1040 - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ + { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ + { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ + { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ + { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ + { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ + { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ + { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ + { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ + { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ + { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */ + { 0x000004A0, 0x3480 }, /* R1184 - HP1 Short Circuit Ctrl */ + { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */ + { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */ + { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */ + { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */ + { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */ + { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */ + { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */ + { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */ + { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */ + { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */ + { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */ + { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */ + { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */ + { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */ + { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */ + { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */ + { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */ + { 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */ + { 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */ + { 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */ + { 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */ + { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */ + { 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */ + { 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */ + { 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */ + { 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */ + { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */ + { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */ + { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */ + { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */ + { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */ + { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */ + { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */ + { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */ + { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */ + { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */ + { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */ + { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */ + { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */ + { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */ + { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */ + { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */ + { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */ + { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */ + { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */ + { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */ + { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */ + { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */ + { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */ + { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */ + { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */ + { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */ + { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */ + { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */ + { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */ + { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */ + { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */ + { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */ + { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */ + { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */ + { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */ + { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */ + { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */ + { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */ + { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */ + { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */ + { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */ + { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */ + { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */ + { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */ + { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */ + { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */ + { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */ + { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */ + { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */ + { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */ + { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */ + { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */ + { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */ + { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */ + { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */ + { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */ + { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */ + { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */ + { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */ + { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */ + { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */ + { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */ + { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */ + { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */ + { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */ + { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */ + { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */ + { 0x00000750, 0x0000 }, /* R1872 - AIF2TX3MIX Input 1 Source */ + { 0x00000751, 0x0080 }, /* R1873 - AIF2TX3MIX Input 1 Volume */ + { 0x00000752, 0x0000 }, /* R1874 - AIF2TX3MIX Input 2 Source */ + { 0x00000753, 0x0080 }, /* R1875 - AIF2TX3MIX Input 2 Volume */ + { 0x00000754, 0x0000 }, /* R1876 - AIF2TX3MIX Input 3 Source */ + { 0x00000755, 0x0080 }, /* R1877 - AIF2TX3MIX Input 3 Volume */ + { 0x00000756, 0x0000 }, /* R1878 - AIF2TX3MIX Input 4 Source */ + { 0x00000757, 0x0080 }, /* R1879 - AIF2TX3MIX Input 4 Volume */ + { 0x00000758, 0x0000 }, /* R1880 - AIF2TX4MIX Input 1 Source */ + { 0x00000759, 0x0080 }, /* R1881 - AIF2TX4MIX Input 1 Volume */ + { 0x0000075A, 0x0000 }, /* R1882 - AIF2TX4MIX Input 2 Source */ + { 0x0000075B, 0x0080 }, /* R1883 - AIF2TX4MIX Input 2 Volume */ + { 0x0000075C, 0x0000 }, /* R1884 - AIF2TX4MIX Input 3 Source */ + { 0x0000075D, 0x0080 }, /* R1885 - AIF2TX4MIX Input 3 Volume */ + { 0x0000075E, 0x0000 }, /* R1886 - AIF2TX4MIX Input 4 Source */ + { 0x0000075F, 0x0080 }, /* R1887 - AIF2TX4MIX Input 4 Volume */ + { 0x00000760, 0x0000 }, /* R1888 - AIF2TX5MIX Input 1 Source */ + { 0x00000761, 0x0080 }, /* R1889 - AIF2TX5MIX Input 1 Volume */ + { 0x00000762, 0x0000 }, /* R1890 - AIF2TX5MIX Input 2 Source */ + { 0x00000763, 0x0080 }, /* R1891 - AIF2TX5MIX Input 2 Volume */ + { 0x00000764, 0x0000 }, /* R1892 - AIF2TX5MIX Input 3 Source */ + { 0x00000765, 0x0080 }, /* R1893 - AIF2TX5MIX Input 3 Volume */ + { 0x00000766, 0x0000 }, /* R1894 - AIF2TX5MIX Input 4 Source */ + { 0x00000767, 0x0080 }, /* R1895 - AIF2TX5MIX Input 4 Volume */ + { 0x00000768, 0x0000 }, /* R1896 - AIF2TX6MIX Input 1 Source */ + { 0x00000769, 0x0080 }, /* R1897 - AIF2TX6MIX Input 1 Volume */ + { 0x0000076A, 0x0000 }, /* R1898 - AIF2TX6MIX Input 2 Source */ + { 0x0000076B, 0x0080 }, /* R1899 - AIF2TX6MIX Input 2 Volume */ + { 0x0000076C, 0x0000 }, /* R1900 - AIF2TX6MIX Input 3 Source */ + { 0x0000076D, 0x0080 }, /* R1901 - AIF2TX6MIX Input 3 Volume */ + { 0x0000076E, 0x0000 }, /* R1902 - AIF2TX6MIX Input 4 Source */ + { 0x0000076F, 0x0080 }, /* R1903 - AIF2TX6MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */ + { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */ + { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */ + { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */ + { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */ + { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */ + { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */ + { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */ + { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */ + { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */ + { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */ + { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */ + { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */ + { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */ + { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */ + { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */ + { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */ + { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */ + { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */ + { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */ + { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */ + { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */ + { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */ + { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */ + { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */ + { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */ + { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */ + { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */ + { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */ + { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */ + { 0x000008D0, 0x0000 }, /* R2256 - DRC2LMIX Input 1 Source */ + { 0x000008D1, 0x0080 }, /* R2257 - DRC2LMIX Input 1 Volume */ + { 0x000008D2, 0x0000 }, /* R2258 - DRC2LMIX Input 2 Source */ + { 0x000008D3, 0x0080 }, /* R2259 - DRC2LMIX Input 2 Volume */ + { 0x000008D4, 0x0000 }, /* R2260 - DRC2LMIX Input 3 Source */ + { 0x000008D5, 0x0080 }, /* R2261 - DRC2LMIX Input 3 Volume */ + { 0x000008D6, 0x0000 }, /* R2262 - DRC2LMIX Input 4 Source */ + { 0x000008D7, 0x0080 }, /* R2263 - DRC2LMIX Input 4 Volume */ + { 0x000008D8, 0x0000 }, /* R2264 - DRC2RMIX Input 1 Source */ + { 0x000008D9, 0x0080 }, /* R2265 - DRC2RMIX Input 1 Volume */ + { 0x000008DA, 0x0000 }, /* R2266 - DRC2RMIX Input 2 Source */ + { 0x000008DB, 0x0080 }, /* R2267 - DRC2RMIX Input 2 Volume */ + { 0x000008DC, 0x0000 }, /* R2268 - DRC2RMIX Input 3 Source */ + { 0x000008DD, 0x0080 }, /* R2269 - DRC2RMIX Input 3 Volume */ + { 0x000008DE, 0x0000 }, /* R2270 - DRC2RMIX Input 4 Source */ + { 0x000008DF, 0x0080 }, /* R2271 - DRC2RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */ + { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */ + { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */ + { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */ + { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */ + { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */ + { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */ + { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */ + { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */ + { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */ + { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */ + { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */ + { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */ + { 0x00000980, 0x0000 }, /* R2432 - DSP2LMIX Input 1 Source */ + { 0x00000981, 0x0080 }, /* R2433 - DSP2LMIX Input 1 Volume */ + { 0x00000982, 0x0000 }, /* R2434 - DSP2LMIX Input 2 Source */ + { 0x00000983, 0x0080 }, /* R2435 - DSP2LMIX Input 2 Volume */ + { 0x00000984, 0x0000 }, /* R2436 - DSP2LMIX Input 3 Source */ + { 0x00000985, 0x0080 }, /* R2437 - DSP2LMIX Input 3 Volume */ + { 0x00000986, 0x0000 }, /* R2438 - DSP2LMIX Input 4 Source */ + { 0x00000987, 0x0080 }, /* R2439 - DSP2LMIX Input 4 Volume */ + { 0x00000988, 0x0000 }, /* R2440 - DSP2RMIX Input 1 Source */ + { 0x00000989, 0x0080 }, /* R2441 - DSP2RMIX Input 1 Volume */ + { 0x0000098A, 0x0000 }, /* R2442 - DSP2RMIX Input 2 Source */ + { 0x0000098B, 0x0080 }, /* R2443 - DSP2RMIX Input 2 Volume */ + { 0x0000098C, 0x0000 }, /* R2444 - DSP2RMIX Input 3 Source */ + { 0x0000098D, 0x0080 }, /* R2445 - DSP2RMIX Input 3 Volume */ + { 0x0000098E, 0x0000 }, /* R2446 - DSP2RMIX Input 4 Source */ + { 0x0000098F, 0x0080 }, /* R2447 - DSP2RMIX Input 4 Volume */ + { 0x00000990, 0x0000 }, /* R2448 - DSP2AUX1MIX Input 1 Source */ + { 0x00000998, 0x0000 }, /* R2456 - DSP2AUX2MIX Input 1 Source */ + { 0x000009A0, 0x0000 }, /* R2464 - DSP2AUX3MIX Input 1 Source */ + { 0x000009A8, 0x0000 }, /* R2472 - DSP2AUX4MIX Input 1 Source */ + { 0x000009B0, 0x0000 }, /* R2480 - DSP2AUX5MIX Input 1 Source */ + { 0x000009B8, 0x0000 }, /* R2488 - DSP2AUX6MIX Input 1 Source */ + { 0x000009C0, 0x0000 }, /* R2496 - DSP3LMIX Input 1 Source */ + { 0x000009C1, 0x0080 }, /* R2497 - DSP3LMIX Input 1 Volume */ + { 0x000009C2, 0x0000 }, /* R2498 - DSP3LMIX Input 2 Source */ + { 0x000009C3, 0x0080 }, /* R2499 - DSP3LMIX Input 2 Volume */ + { 0x000009C4, 0x0000 }, /* R2500 - DSP3LMIX Input 3 Source */ + { 0x000009C5, 0x0080 }, /* R2501 - DSP3LMIX Input 3 Volume */ + { 0x000009C6, 0x0000 }, /* R2502 - DSP3LMIX Input 4 Source */ + { 0x000009C7, 0x0080 }, /* R2503 - DSP3LMIX Input 4 Volume */ + { 0x000009C8, 0x0000 }, /* R2504 - DSP3RMIX Input 1 Source */ + { 0x000009C9, 0x0080 }, /* R2505 - DSP3RMIX Input 1 Volume */ + { 0x000009CA, 0x0000 }, /* R2506 - DSP3RMIX Input 2 Source */ + { 0x000009CB, 0x0080 }, /* R2507 - DSP3RMIX Input 2 Volume */ + { 0x000009CC, 0x0000 }, /* R2508 - DSP3RMIX Input 3 Source */ + { 0x000009CD, 0x0080 }, /* R2509 - DSP3RMIX Input 3 Volume */ + { 0x000009CE, 0x0000 }, /* R2510 - DSP3RMIX Input 4 Source */ + { 0x000009CF, 0x0080 }, /* R2511 - DSP3RMIX Input 4 Volume */ + { 0x000009D0, 0x0000 }, /* R2512 - DSP3AUX1MIX Input 1 Source */ + { 0x000009D8, 0x0000 }, /* R2520 - DSP3AUX2MIX Input 1 Source */ + { 0x000009E0, 0x0000 }, /* R2528 - DSP3AUX3MIX Input 1 Source */ + { 0x000009E8, 0x0000 }, /* R2536 - DSP3AUX4MIX Input 1 Source */ + { 0x000009F0, 0x0000 }, /* R2544 - DSP3AUX5MIX Input 1 Source */ + { 0x000009F8, 0x0000 }, /* R2552 - DSP3AUX6MIX Input 1 Source */ + { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */ + { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */ + { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */ + { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */ + { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */ + { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */ + { 0x00000B10, 0x0000 }, /* R2832 - ISRC1DEC3MIX Input 1 Source */ + { 0x00000B18, 0x0000 }, /* R2840 - ISRC1DEC4MIX Input 1 Source */ + { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */ + { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */ + { 0x00000B30, 0x0000 }, /* R2864 - ISRC1INT3MIX Input 1 Source */ + { 0x00000B38, 0x0000 }, /* R2872 - ISRC1INT4MIX Input 1 Source */ + { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */ + { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */ + { 0x00000B50, 0x0000 }, /* R2896 - ISRC2DEC3MIX Input 1 Source */ + { 0x00000B58, 0x0000 }, /* R2904 - ISRC2DEC4MIX Input 1 Source */ + { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */ + { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */ + { 0x00000B70, 0x0000 }, /* R2928 - ISRC2INT3MIX Input 1 Source */ + { 0x00000B78, 0x0000 }, /* R2936 - ISRC2INT4MIX Input 1 Source */ + { 0x00000B80, 0x0000 }, /* R2944 - ISRC3DEC1MIX Input 1 Source */ + { 0x00000B88, 0x0000 }, /* R2952 - ISRC3DEC2MIX Input 1 Source */ + { 0x00000B90, 0x0000 }, /* R2960 - ISRC3DEC3MIX Input 1 Source */ + { 0x00000B98, 0x0000 }, /* R2968 - ISRC3DEC4MIX Input 1 Source */ + { 0x00000BA0, 0x0000 }, /* R2976 - ISRC3INT1MIX Input 1 Source */ + { 0x00000BA8, 0x0000 }, /* R2984 - ISRC3INT2MIX Input 1 Source */ + { 0x00000BB0, 0x0000 }, /* R2992 - ISRC3INT3MIX Input 1 Source */ + { 0x00000BB8, 0x0000 }, /* R3000 - ISRC3INT4MIX Input 1 Source */ + { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */ + { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */ + { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */ + { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */ + { 0x00000C20, 0x0002 }, /* R3104 - Misc Pad Ctrl 1 */ + { 0x00000C21, 0x8001 }, /* R3105 - Misc Pad Ctrl 2 */ + { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */ + { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */ + { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */ + { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */ + { 0x00000C30, 0x0404 }, /* R3120 - Misc Pad Ctrl 7 */ + { 0x00000C32, 0x0404 }, /* R3122 - Misc Pad Ctrl 9 */ + { 0x00000C33, 0x0404 }, /* R3123 - Misc Pad Ctrl 10 */ + { 0x00000C34, 0x0404 }, /* R3124 - Misc Pad Ctrl 11 */ + { 0x00000C35, 0x0404 }, /* R3125 - Misc Pad Ctrl 12 */ + { 0x00000C36, 0x0400 }, /* R3126 - Misc Pad Ctrl 13 */ + { 0x00000C37, 0x0404 }, /* R3127 - Misc Pad Ctrl 14 */ + { 0x00000C39, 0x0400 }, /* R3129 - Misc Pad Ctrl 16 */ + { 0x00000D08, 0x0007 }, /* R3336 - Interrupt Status 1 Mask */ + { 0x00000D09, 0x06FF }, /* R3337 - Interrupt Status 2 Mask */ + { 0x00000D0A, 0xCFEF }, /* R3338 - Interrupt Status 3 Mask */ + { 0x00000D0B, 0xFFC3 }, /* R3339 - Interrupt Status 4 Mask */ + { 0x00000D0C, 0x000B }, /* R3340 - Interrupt Status 5 Mask */ + { 0x00000D0D, 0xD005 }, /* R3341 - Interrupt Status 6 Mask */ + { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */ + { 0x00000D18, 0x0007 }, /* R3352 - IRQ2 Status 1 Mask */ + { 0x00000D19, 0x06FF }, /* R3353 - IRQ2 Status 2 Mask */ + { 0x00000D1A, 0xCFEF }, /* R3354 - IRQ2 Status 3 Mask */ + { 0x00000D1B, 0xFFC3 }, /* R3355 - IRQ2 Status 4 Mask */ + { 0x00000D1C, 0x000B }, /* R3356 - IRQ2 Status 5 Mask */ + { 0x00000D1D, 0xD005 }, /* R3357 - IRQ2 Status 6 Mask */ + { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */ + { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */ + { 0x00000E01, 0x0000 }, /* R3585 - FX_Ctrl2 */ + { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */ + { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */ + { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */ + { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */ + { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */ + { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */ + { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */ + { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */ + { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */ + { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */ + { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */ + { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */ + { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */ + { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */ + { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */ + { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */ + { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */ + { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */ + { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */ + { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */ + { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */ + { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */ + { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */ + { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */ + { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */ + { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */ + { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */ + { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */ + { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */ + { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */ + { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */ + { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */ + { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */ + { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */ + { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */ + { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */ + { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */ + { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */ + { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */ + { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */ + { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */ + { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */ + { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */ + { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */ + { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */ + { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */ + { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */ + { 0x00000E89, 0x0018 }, /* R3721 - DRC2 ctrl1 */ + { 0x00000E8A, 0x0933 }, /* R3722 - DRC2 ctrl2 */ + { 0x00000E8B, 0x0018 }, /* R3723 - DRC2 ctrl3 */ + { 0x00000E8C, 0x0000 }, /* R3724 - DRC2 ctrl4 */ + { 0x00000E8D, 0x0000 }, /* R3725 - DRC2 ctrl5 */ + { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */ + { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */ + { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */ + { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */ + { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */ + { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */ + { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */ + { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */ + { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */ + { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */ + { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */ + { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */ + { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */ + { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */ + { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */ + { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */ + { 0x00000EF6, 0x0000 }, /* R3830 - ISRC 3 CTRL 1 */ + { 0x00000EF7, 0x0000 }, /* R3831 - ISRC 3 CTRL 2 */ + { 0x00000EF8, 0x0000 }, /* R3832 - ISRC 3 CTRL 3 */ + { 0x00001200, 0x0010 }, /* R4608 - DSP2 Control 1 */ + { 0x00001300, 0x0010 }, /* R4864 - DSP3 Control 1 */ +}; + +static bool largo_is_adsp_memory(struct device *dev, unsigned int reg) +{ + if ((reg >= 0x200000 && reg < 0x206000) || + (reg >= 0x280000 && reg < 0x282000) || + (reg >= 0x290000 && reg < 0x2a8000) || + (reg >= 0x2a8000 && reg < 0x2b4000) || + (reg >= 0x300000 && reg < 0x309000) || + (reg >= 0x380000 && reg < 0x382000) || + (reg >= 0x390000 && reg < 0x3a8000) || + (reg >= 0x3a8000 && reg < 0x3b4000)) + return true; + else + return false; +} + +static bool largo_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_CTRL_IF_SPI_CFG_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_TONE_GENERATOR_1: + case ARIZONA_TONE_GENERATOR_2: + case ARIZONA_TONE_GENERATOR_3: + case ARIZONA_TONE_GENERATOR_4: + case ARIZONA_TONE_GENERATOR_5: + case ARIZONA_PWM_DRIVE_1: + case ARIZONA_PWM_DRIVE_2: + case ARIZONA_PWM_DRIVE_3: + case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case ARIZONA_COMFORT_NOISE_GENERATOR: + case ARIZONA_HAPTICS_CONTROL_1: + case ARIZONA_HAPTICS_CONTROL_2: + case ARIZONA_HAPTICS_PHASE_1_INTENSITY: + case ARIZONA_HAPTICS_PHASE_1_DURATION: + case ARIZONA_HAPTICS_PHASE_2_INTENSITY: + case ARIZONA_HAPTICS_PHASE_2_DURATION: + case ARIZONA_HAPTICS_PHASE_3_INTENSITY: + case ARIZONA_HAPTICS_PHASE_3_DURATION: + case ARIZONA_HAPTICS_STATUS: + case ARIZONA_CLOCK_32K_1: + case ARIZONA_SYSTEM_CLOCK_1: + case ARIZONA_SAMPLE_RATE_1: + case ARIZONA_SAMPLE_RATE_2: + case ARIZONA_SAMPLE_RATE_3: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case ARIZONA_ASYNC_CLOCK_1: + case ARIZONA_ASYNC_SAMPLE_RATE_1: + case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: + case ARIZONA_OUTPUT_SYSTEM_CLOCK: + case ARIZONA_OUTPUT_ASYNC_CLOCK: + case ARIZONA_RATE_ESTIMATOR_1: + case ARIZONA_RATE_ESTIMATOR_2: + case ARIZONA_RATE_ESTIMATOR_3: + case ARIZONA_RATE_ESTIMATOR_4: + case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_FLL1_CONTROL_1: + case ARIZONA_FLL1_CONTROL_2: + case ARIZONA_FLL1_CONTROL_3: + case ARIZONA_FLL1_CONTROL_4: + case ARIZONA_FLL1_CONTROL_5: + case ARIZONA_FLL1_CONTROL_6: + case ARIZONA_FLL1_CONTROL_7: + case ARIZONA_FLL1_LOOP_FILTER_TEST_1: + case ARIZONA_FLL1_NCO_TEST_0: + case ARIZONA_FLL1_SYNCHRONISER_1: + case ARIZONA_FLL1_SYNCHRONISER_2: + case ARIZONA_FLL1_SYNCHRONISER_3: + case ARIZONA_FLL1_SYNCHRONISER_4: + case ARIZONA_FLL1_SYNCHRONISER_5: + case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: + case ARIZONA_FLL1_SPREAD_SPECTRUM: + case ARIZONA_FLL1_GPIO_CLOCK: + case ARIZONA_FLL2_CONTROL_1: + case ARIZONA_FLL2_CONTROL_2: + case ARIZONA_FLL2_CONTROL_3: + case ARIZONA_FLL2_CONTROL_4: + case ARIZONA_FLL2_CONTROL_5: + case ARIZONA_FLL2_CONTROL_6: + case ARIZONA_FLL2_CONTROL_7: + case ARIZONA_FLL2_LOOP_FILTER_TEST_1: + case ARIZONA_FLL2_NCO_TEST_0: + case ARIZONA_FLL2_SYNCHRONISER_1: + case ARIZONA_FLL2_SYNCHRONISER_2: + case ARIZONA_FLL2_SYNCHRONISER_3: + case ARIZONA_FLL2_SYNCHRONISER_4: + case ARIZONA_FLL2_SYNCHRONISER_5: + case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: + case ARIZONA_FLL2_SPREAD_SPECTRUM: + case ARIZONA_FLL2_GPIO_CLOCK: + case ARIZONA_MIC_BIAS_CTRL_1: + case ARIZONA_MIC_BIAS_CTRL_2: + case ARIZONA_HP_CTRL_1L: + case ARIZONA_HP_CTRL_1R: + case ARIZONA_INPUT_ENABLES: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_INPUT_RATE: + case ARIZONA_INPUT_VOLUME_RAMP: + case ARIZONA_HPF_CONTROL: + case ARIZONA_IN1L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1L: + case ARIZONA_DMIC1L_CONTROL: + case ARIZONA_IN1R_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1R: + case ARIZONA_DMIC1R_CONTROL: + case ARIZONA_IN2L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_2L: + case ARIZONA_DMIC2L_CONTROL: + case ARIZONA_IN2R_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_2R: + case ARIZONA_DMIC2R_CONTROL: + case ARIZONA_ADC_VCO_CAL_4: + case ARIZONA_ADC_VCO_CAL_5: + case ARIZONA_ADC_VCO_CAL_6: + case ARIZONA_ADC_VCO_CAL_7: + case ARIZONA_ADC_VCO_CAL_8: + case ARIZONA_ADC_VCO_CAL_9: + case ARIZONA_OUTPUT_ENABLES_1: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_OUTPUT_STANDBY_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_OUTPUT_RATE_1: + case ARIZONA_OUTPUT_VOLUME_RAMP: + case ARIZONA_OUTPUT_PATH_CONFIG_1L: + case ARIZONA_DAC_DIGITAL_VOLUME_1L: + case ARIZONA_DAC_VOLUME_LIMIT_1L: + case ARIZONA_NOISE_GATE_SELECT_1L: + case ARIZONA_DAC_DIGITAL_VOLUME_1R: + case ARIZONA_DAC_VOLUME_LIMIT_1R: + case ARIZONA_NOISE_GATE_SELECT_1R: + case ARIZONA_DAC_DIGITAL_VOLUME_4L: + case ARIZONA_OUT_VOLUME_4L: + case ARIZONA_NOISE_GATE_SELECT_4L: + case ARIZONA_DAC_AEC_CONTROL_1: + case ARIZONA_NOISE_GATE_CONTROL: + case ARIZONA_HP1_SHORT_CIRCUIT_CTRL: + case ARIZONA_SPK_CTRL_3: + case ARIZONA_AIF1_BCLK_CTRL: + case ARIZONA_AIF1_TX_PIN_CTRL: + case ARIZONA_AIF1_RX_PIN_CTRL: + case ARIZONA_AIF1_RATE_CTRL: + case ARIZONA_AIF1_FORMAT: + case ARIZONA_AIF1_RX_BCLK_RATE: + case ARIZONA_AIF1_FRAME_CTRL_1: + case ARIZONA_AIF1_FRAME_CTRL_2: + case ARIZONA_AIF1_FRAME_CTRL_3: + case ARIZONA_AIF1_FRAME_CTRL_4: + case ARIZONA_AIF1_FRAME_CTRL_5: + case ARIZONA_AIF1_FRAME_CTRL_6: + case ARIZONA_AIF1_FRAME_CTRL_7: + case ARIZONA_AIF1_FRAME_CTRL_8: + case ARIZONA_AIF1_FRAME_CTRL_9: + case ARIZONA_AIF1_FRAME_CTRL_10: + case ARIZONA_AIF1_FRAME_CTRL_11: + case ARIZONA_AIF1_FRAME_CTRL_12: + case ARIZONA_AIF1_FRAME_CTRL_13: + case ARIZONA_AIF1_FRAME_CTRL_14: + case ARIZONA_AIF1_FRAME_CTRL_15: + case ARIZONA_AIF1_FRAME_CTRL_16: + case ARIZONA_AIF1_FRAME_CTRL_17: + case ARIZONA_AIF1_FRAME_CTRL_18: + case ARIZONA_AIF1_TX_ENABLES: + case ARIZONA_AIF1_RX_ENABLES: + case ARIZONA_AIF2_BCLK_CTRL: + case ARIZONA_AIF2_TX_PIN_CTRL: + case ARIZONA_AIF2_RX_PIN_CTRL: + case ARIZONA_AIF2_RATE_CTRL: + case ARIZONA_AIF2_FORMAT: + case ARIZONA_AIF2_RX_BCLK_RATE: + case ARIZONA_AIF2_FRAME_CTRL_1: + case ARIZONA_AIF2_FRAME_CTRL_2: + case ARIZONA_AIF2_FRAME_CTRL_3: + case ARIZONA_AIF2_FRAME_CTRL_4: + case ARIZONA_AIF2_FRAME_CTRL_5: + case ARIZONA_AIF2_FRAME_CTRL_6: + case ARIZONA_AIF2_FRAME_CTRL_7: + case ARIZONA_AIF2_FRAME_CTRL_8: + case ARIZONA_AIF2_FRAME_CTRL_11: + case ARIZONA_AIF2_FRAME_CTRL_12: + case ARIZONA_AIF2_FRAME_CTRL_13: + case ARIZONA_AIF2_FRAME_CTRL_14: + case ARIZONA_AIF2_FRAME_CTRL_15: + case ARIZONA_AIF2_FRAME_CTRL_16: + case ARIZONA_AIF2_TX_ENABLES: + case ARIZONA_AIF2_RX_ENABLES: + case ARIZONA_AIF3_BCLK_CTRL: + case ARIZONA_AIF3_TX_PIN_CTRL: + case ARIZONA_AIF3_RX_PIN_CTRL: + case ARIZONA_AIF3_RATE_CTRL: + case ARIZONA_AIF3_FORMAT: + case ARIZONA_AIF3_RX_BCLK_RATE: + case ARIZONA_AIF3_FRAME_CTRL_1: + case ARIZONA_AIF3_FRAME_CTRL_2: + case ARIZONA_AIF3_FRAME_CTRL_3: + case ARIZONA_AIF3_FRAME_CTRL_4: + case ARIZONA_AIF3_FRAME_CTRL_11: + case ARIZONA_AIF3_FRAME_CTRL_12: + case ARIZONA_AIF3_TX_ENABLES: + case ARIZONA_AIF3_RX_ENABLES: + case ARIZONA_PWM1MIX_INPUT_1_SOURCE: + case ARIZONA_PWM1MIX_INPUT_1_VOLUME: + case ARIZONA_PWM1MIX_INPUT_2_SOURCE: + case ARIZONA_PWM1MIX_INPUT_2_VOLUME: + case ARIZONA_PWM1MIX_INPUT_3_SOURCE: + case ARIZONA_PWM1MIX_INPUT_3_VOLUME: + case ARIZONA_PWM1MIX_INPUT_4_SOURCE: + case ARIZONA_PWM1MIX_INPUT_4_VOLUME: + case ARIZONA_PWM2MIX_INPUT_1_SOURCE: + case ARIZONA_PWM2MIX_INPUT_1_VOLUME: + case ARIZONA_PWM2MIX_INPUT_2_SOURCE: + case ARIZONA_PWM2MIX_INPUT_2_VOLUME: + case ARIZONA_PWM2MIX_INPUT_3_SOURCE: + case ARIZONA_PWM2MIX_INPUT_3_VOLUME: + case ARIZONA_PWM2MIX_INPUT_4_SOURCE: + case ARIZONA_PWM2MIX_INPUT_4_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_4_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME: + case ARIZONA_EQ1MIX_INPUT_1_SOURCE: + case ARIZONA_EQ1MIX_INPUT_1_VOLUME: + case ARIZONA_EQ1MIX_INPUT_2_SOURCE: + case ARIZONA_EQ1MIX_INPUT_2_VOLUME: + case ARIZONA_EQ1MIX_INPUT_3_SOURCE: + case ARIZONA_EQ1MIX_INPUT_3_VOLUME: + case ARIZONA_EQ1MIX_INPUT_4_SOURCE: + case ARIZONA_EQ1MIX_INPUT_4_VOLUME: + case ARIZONA_EQ2MIX_INPUT_1_SOURCE: + case ARIZONA_EQ2MIX_INPUT_1_VOLUME: + case ARIZONA_EQ2MIX_INPUT_2_SOURCE: + case ARIZONA_EQ2MIX_INPUT_2_VOLUME: + case ARIZONA_EQ2MIX_INPUT_3_SOURCE: + case ARIZONA_EQ2MIX_INPUT_3_VOLUME: + case ARIZONA_EQ2MIX_INPUT_4_SOURCE: + case ARIZONA_EQ2MIX_INPUT_4_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_1_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_2_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_2_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_3_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_3_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_4_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_4_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_1_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_2_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_2_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_3_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_3_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_4_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_4_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_1_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_1_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_2_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_2_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_3_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_3_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_4_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_4_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_1_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_1_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_2_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_2_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_3_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_3_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_4_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_4_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_4_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_1_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_1_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_2_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_2_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_3_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_3_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_4_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_4_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_1_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_1_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_2_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_2_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_3_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_3_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_4_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_4_VOLUME: + case ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX2MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX3MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX4MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX5MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX6MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_1_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_1_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_2_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_2_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_3_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_3_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_4_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_4_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_1_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_1_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_2_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_2_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_3_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_3_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_4_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_4_VOLUME: + case ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX2MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX3MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX4MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX5MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX6MIX_INPUT_1_SOURCE: + case ARIZONA_ASRC1LMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC1RMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC2LMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC2RMIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE: + case ARIZONA_GPIO1_CTRL: + case ARIZONA_GPIO2_CTRL: + case ARIZONA_IRQ_CTRL_1: + case ARIZONA_GPIO_DEBOUNCE_CONFIG: + case ARIZONA_MISC_PAD_CTRL_1: + case ARIZONA_MISC_PAD_CTRL_2: + case ARIZONA_MISC_PAD_CTRL_3: + case ARIZONA_MISC_PAD_CTRL_4: + case ARIZONA_MISC_PAD_CTRL_5: + case ARIZONA_MISC_PAD_CTRL_6: + case ARIZONA_MISC_PAD_CTRL_7: + case ARIZONA_MISC_PAD_CTRL_9: + case ARIZONA_MISC_PAD_CTRL_10: + case ARIZONA_MISC_PAD_CTRL_11: + case ARIZONA_MISC_PAD_CTRL_12: + case ARIZONA_MISC_PAD_CTRL_13: + case ARIZONA_MISC_PAD_CTRL_14: + case ARIZONA_MISC_PAD_CTRL_16: + case ARIZONA_INTERRUPT_STATUS_1: + case ARIZONA_INTERRUPT_STATUS_2: + case ARIZONA_INTERRUPT_STATUS_3: + case ARIZONA_INTERRUPT_STATUS_4: + case ARIZONA_INTERRUPT_STATUS_5: + case ARIZONA_INTERRUPT_STATUS_6: + case ARIZONA_INTERRUPT_STATUS_1_MASK: + case ARIZONA_INTERRUPT_STATUS_2_MASK: + case ARIZONA_INTERRUPT_STATUS_3_MASK: + case ARIZONA_INTERRUPT_STATUS_4_MASK: + case ARIZONA_INTERRUPT_STATUS_5_MASK: + case ARIZONA_INTERRUPT_STATUS_6_MASK: + case ARIZONA_INTERRUPT_CONTROL: + case ARIZONA_IRQ2_STATUS_1: + case ARIZONA_IRQ2_STATUS_2: + case ARIZONA_IRQ2_STATUS_3: + case ARIZONA_IRQ2_STATUS_4: + case ARIZONA_IRQ2_STATUS_5: + case ARIZONA_IRQ2_STATUS_6: + case ARIZONA_IRQ2_STATUS_1_MASK: + case ARIZONA_IRQ2_STATUS_2_MASK: + case ARIZONA_IRQ2_STATUS_3_MASK: + case ARIZONA_IRQ2_STATUS_4_MASK: + case ARIZONA_IRQ2_STATUS_5_MASK: + case ARIZONA_IRQ2_STATUS_6_MASK: + case ARIZONA_IRQ2_CONTROL: + case ARIZONA_INTERRUPT_RAW_STATUS_2: + case ARIZONA_INTERRUPT_RAW_STATUS_3: + case ARIZONA_INTERRUPT_RAW_STATUS_4: + case ARIZONA_INTERRUPT_RAW_STATUS_5: + case ARIZONA_INTERRUPT_RAW_STATUS_6: + case ARIZONA_INTERRUPT_RAW_STATUS_7: + case ARIZONA_INTERRUPT_RAW_STATUS_8: + case ARIZONA_INTERRUPT_RAW_STATUS_9: + case ARIZONA_IRQ_PIN_STATUS: + case ARIZONA_FX_CTRL1: + case ARIZONA_FX_CTRL2: + case ARIZONA_EQ1_1: + case ARIZONA_EQ1_2: + case ARIZONA_EQ1_3: + case ARIZONA_EQ1_4: + case ARIZONA_EQ1_5: + case ARIZONA_EQ1_6: + case ARIZONA_EQ1_7: + case ARIZONA_EQ1_8: + case ARIZONA_EQ1_9: + case ARIZONA_EQ1_10: + case ARIZONA_EQ1_11: + case ARIZONA_EQ1_12: + case ARIZONA_EQ1_13: + case ARIZONA_EQ1_14: + case ARIZONA_EQ1_15: + case ARIZONA_EQ1_16: + case ARIZONA_EQ1_17: + case ARIZONA_EQ1_18: + case ARIZONA_EQ1_19: + case ARIZONA_EQ1_20: + case ARIZONA_EQ1_21: + case ARIZONA_EQ2_1: + case ARIZONA_EQ2_2: + case ARIZONA_EQ2_3: + case ARIZONA_EQ2_4: + case ARIZONA_EQ2_5: + case ARIZONA_EQ2_6: + case ARIZONA_EQ2_7: + case ARIZONA_EQ2_8: + case ARIZONA_EQ2_9: + case ARIZONA_EQ2_10: + case ARIZONA_EQ2_11: + case ARIZONA_EQ2_12: + case ARIZONA_EQ2_13: + case ARIZONA_EQ2_14: + case ARIZONA_EQ2_15: + case ARIZONA_EQ2_16: + case ARIZONA_EQ2_17: + case ARIZONA_EQ2_18: + case ARIZONA_EQ2_19: + case ARIZONA_EQ2_20: + case ARIZONA_EQ2_21: + case ARIZONA_DRC1_CTRL1: + case ARIZONA_DRC1_CTRL2: + case ARIZONA_DRC1_CTRL3: + case ARIZONA_DRC1_CTRL4: + case ARIZONA_DRC1_CTRL5: + case ARIZONA_DRC2_CTRL1: + case ARIZONA_DRC2_CTRL2: + case ARIZONA_DRC2_CTRL3: + case ARIZONA_DRC2_CTRL4: + case ARIZONA_DRC2_CTRL5: + case ARIZONA_HPLPF1_1: + case ARIZONA_HPLPF1_2: + case ARIZONA_HPLPF2_1: + case ARIZONA_HPLPF2_2: + case ARIZONA_HPLPF3_1: + case ARIZONA_HPLPF3_2: + case ARIZONA_HPLPF4_1: + case ARIZONA_HPLPF4_2: + case ARIZONA_ASRC_ENABLE: + case ARIZONA_ASRC_STATUS: + case ARIZONA_ASRC_RATE1: + case ARIZONA_ISRC_1_CTRL_1: + case ARIZONA_ISRC_1_CTRL_2: + case ARIZONA_ISRC_1_CTRL_3: + case ARIZONA_ISRC_2_CTRL_1: + case ARIZONA_ISRC_2_CTRL_2: + case ARIZONA_ISRC_2_CTRL_3: + case ARIZONA_ISRC_3_CTRL_1: + case ARIZONA_ISRC_3_CTRL_2: + case ARIZONA_ISRC_3_CTRL_3: + case ARIZONA_DSP2_CONTROL_1: + case ARIZONA_DSP2_CLOCKING_1: + case ARIZONA_DSP2_STATUS_1: + case ARIZONA_DSP2_STATUS_2: + case ARIZONA_DSP2_STATUS_3: + case ARIZONA_DSP2_STATUS_4: + case ARIZONA_DSP2_WDMA_BUFFER_1: + case ARIZONA_DSP2_WDMA_BUFFER_2: + case ARIZONA_DSP2_WDMA_BUFFER_3: + case ARIZONA_DSP2_WDMA_BUFFER_4: + case ARIZONA_DSP2_WDMA_BUFFER_5: + case ARIZONA_DSP2_WDMA_BUFFER_6: + case ARIZONA_DSP2_WDMA_BUFFER_7: + case ARIZONA_DSP2_WDMA_BUFFER_8: + case ARIZONA_DSP2_RDMA_BUFFER_1: + case ARIZONA_DSP2_RDMA_BUFFER_2: + case ARIZONA_DSP2_RDMA_BUFFER_3: + case ARIZONA_DSP2_RDMA_BUFFER_4: + case ARIZONA_DSP2_RDMA_BUFFER_5: + case ARIZONA_DSP2_RDMA_BUFFER_6: + case ARIZONA_DSP2_WDMA_CONFIG_1: + case ARIZONA_DSP2_WDMA_CONFIG_2: + case ARIZONA_DSP2_WDMA_OFFSET_1: + case ARIZONA_DSP2_RDMA_CONFIG_1: + case ARIZONA_DSP2_RDMA_OFFSET_1: + case ARIZONA_DSP2_EXTERNAL_START_SELECT_1: + case ARIZONA_DSP2_SCRATCH_0: + case ARIZONA_DSP2_SCRATCH_1: + case ARIZONA_DSP2_SCRATCH_2: + case ARIZONA_DSP2_SCRATCH_3: + case ARIZONA_DSP3_CONTROL_1: + case ARIZONA_DSP3_CLOCKING_1: + case ARIZONA_DSP3_STATUS_1: + case ARIZONA_DSP3_STATUS_2: + case ARIZONA_DSP3_STATUS_3: + case ARIZONA_DSP3_STATUS_4: + case ARIZONA_DSP3_WDMA_BUFFER_1: + case ARIZONA_DSP3_WDMA_BUFFER_2: + case ARIZONA_DSP3_WDMA_BUFFER_3: + case ARIZONA_DSP3_WDMA_BUFFER_4: + case ARIZONA_DSP3_WDMA_BUFFER_5: + case ARIZONA_DSP3_WDMA_BUFFER_6: + case ARIZONA_DSP3_WDMA_BUFFER_7: + case ARIZONA_DSP3_WDMA_BUFFER_8: + case ARIZONA_DSP3_RDMA_BUFFER_1: + case ARIZONA_DSP3_RDMA_BUFFER_2: + case ARIZONA_DSP3_RDMA_BUFFER_3: + case ARIZONA_DSP3_RDMA_BUFFER_4: + case ARIZONA_DSP3_RDMA_BUFFER_5: + case ARIZONA_DSP3_RDMA_BUFFER_6: + case ARIZONA_DSP3_WDMA_CONFIG_1: + case ARIZONA_DSP3_WDMA_CONFIG_2: + case ARIZONA_DSP3_WDMA_OFFSET_1: + case ARIZONA_DSP3_RDMA_CONFIG_1: + case ARIZONA_DSP3_RDMA_OFFSET_1: + case ARIZONA_DSP3_EXTERNAL_START_SELECT_1: + case ARIZONA_DSP3_SCRATCH_0: + case ARIZONA_DSP3_SCRATCH_1: + case ARIZONA_DSP3_SCRATCH_2: + case ARIZONA_DSP3_SCRATCH_3: + return true; + default: + return largo_is_adsp_memory(dev, reg); + } +} + +static bool largo_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_HAPTICS_STATUS: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: + case ARIZONA_HP_CTRL_1L: + case ARIZONA_HP_CTRL_1R: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_ADC_VCO_CAL_4: + case ARIZONA_ADC_VCO_CAL_5: + case ARIZONA_ADC_VCO_CAL_6: + case ARIZONA_ADC_VCO_CAL_7: + case ARIZONA_ADC_VCO_CAL_8: + case ARIZONA_ADC_VCO_CAL_9: + case ARIZONA_INTERRUPT_STATUS_1: + case ARIZONA_INTERRUPT_STATUS_2: + case ARIZONA_INTERRUPT_STATUS_3: + case ARIZONA_INTERRUPT_STATUS_4: + case ARIZONA_INTERRUPT_STATUS_5: + case ARIZONA_INTERRUPT_STATUS_6: + case ARIZONA_IRQ2_STATUS_1: + case ARIZONA_IRQ2_STATUS_2: + case ARIZONA_IRQ2_STATUS_3: + case ARIZONA_IRQ2_STATUS_4: + case ARIZONA_IRQ2_STATUS_5: + case ARIZONA_IRQ2_STATUS_6: + case ARIZONA_INTERRUPT_RAW_STATUS_2: + case ARIZONA_INTERRUPT_RAW_STATUS_3: + case ARIZONA_INTERRUPT_RAW_STATUS_4: + case ARIZONA_INTERRUPT_RAW_STATUS_5: + case ARIZONA_INTERRUPT_RAW_STATUS_6: + case ARIZONA_INTERRUPT_RAW_STATUS_7: + case ARIZONA_INTERRUPT_RAW_STATUS_8: + case ARIZONA_INTERRUPT_RAW_STATUS_9: + case ARIZONA_IRQ_PIN_STATUS: + case ARIZONA_FX_CTRL2: + case ARIZONA_ASRC_STATUS: + case ARIZONA_DSP2_STATUS_1: + case ARIZONA_DSP2_STATUS_2: + case ARIZONA_DSP2_STATUS_3: + case ARIZONA_DSP2_STATUS_4: + case ARIZONA_DSP2_WDMA_BUFFER_1: + case ARIZONA_DSP2_WDMA_BUFFER_2: + case ARIZONA_DSP2_WDMA_BUFFER_3: + case ARIZONA_DSP2_WDMA_BUFFER_4: + case ARIZONA_DSP2_WDMA_BUFFER_5: + case ARIZONA_DSP2_WDMA_BUFFER_6: + case ARIZONA_DSP2_WDMA_BUFFER_7: + case ARIZONA_DSP2_WDMA_BUFFER_8: + case ARIZONA_DSP2_RDMA_BUFFER_1: + case ARIZONA_DSP2_RDMA_BUFFER_2: + case ARIZONA_DSP2_RDMA_BUFFER_3: + case ARIZONA_DSP2_RDMA_BUFFER_4: + case ARIZONA_DSP2_RDMA_BUFFER_5: + case ARIZONA_DSP2_RDMA_BUFFER_6: + case ARIZONA_DSP2_WDMA_CONFIG_1: + case ARIZONA_DSP2_WDMA_CONFIG_2: + case ARIZONA_DSP2_WDMA_OFFSET_1: + case ARIZONA_DSP2_RDMA_CONFIG_1: + case ARIZONA_DSP2_RDMA_OFFSET_1: + case ARIZONA_DSP2_EXTERNAL_START_SELECT_1: + case ARIZONA_DSP2_SCRATCH_0: + case ARIZONA_DSP2_SCRATCH_1: + case ARIZONA_DSP2_SCRATCH_2: + case ARIZONA_DSP2_SCRATCH_3: + case ARIZONA_DSP2_CLOCKING_1: + case ARIZONA_DSP3_STATUS_1: + case ARIZONA_DSP3_STATUS_2: + case ARIZONA_DSP3_STATUS_3: + case ARIZONA_DSP3_STATUS_4: + case ARIZONA_DSP3_WDMA_BUFFER_1: + case ARIZONA_DSP3_WDMA_BUFFER_2: + case ARIZONA_DSP3_WDMA_BUFFER_3: + case ARIZONA_DSP3_WDMA_BUFFER_4: + case ARIZONA_DSP3_WDMA_BUFFER_5: + case ARIZONA_DSP3_WDMA_BUFFER_6: + case ARIZONA_DSP3_WDMA_BUFFER_7: + case ARIZONA_DSP3_WDMA_BUFFER_8: + case ARIZONA_DSP3_RDMA_BUFFER_1: + case ARIZONA_DSP3_RDMA_BUFFER_2: + case ARIZONA_DSP3_RDMA_BUFFER_3: + case ARIZONA_DSP3_RDMA_BUFFER_4: + case ARIZONA_DSP3_RDMA_BUFFER_5: + case ARIZONA_DSP3_RDMA_BUFFER_6: + case ARIZONA_DSP3_WDMA_CONFIG_1: + case ARIZONA_DSP3_WDMA_CONFIG_2: + case ARIZONA_DSP3_WDMA_OFFSET_1: + case ARIZONA_DSP3_RDMA_CONFIG_1: + case ARIZONA_DSP3_RDMA_OFFSET_1: + case ARIZONA_DSP3_EXTERNAL_START_SELECT_1: + case ARIZONA_DSP3_SCRATCH_0: + case ARIZONA_DSP3_SCRATCH_1: + case ARIZONA_DSP3_SCRATCH_2: + case ARIZONA_DSP3_SCRATCH_3: + case ARIZONA_DSP3_CLOCKING_1: + return true; + default: + return largo_is_adsp_memory(dev, reg); + } +} + +#define LARGO_MAX_REGISTER 0x3b3fff + +const struct regmap_config largo_spi_regmap = { + .reg_bits = 32, + .pad_bits = 16, + .val_bits = 16, + + .max_register = LARGO_MAX_REGISTER, + .readable_reg = largo_readable_register, + .volatile_reg = largo_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = largo_reg_default, + .num_reg_defaults = ARRAY_SIZE(largo_reg_default), +}; +EXPORT_SYMBOL_GPL(largo_spi_regmap); + diff --git a/drivers/mfd/marley-tables.c b/drivers/mfd/marley-tables.c new file mode 100644 index 000000000000..71e20ef45cbd --- /dev/null +++ b/drivers/mfd/marley-tables.c @@ -0,0 +1,1855 @@ +/* + * marley-tables.c -- data tables for Marley class codecs + * + * Copyright 2015 Cirrus Logic + * + * Author: Piotr Stankiewicz + * + * 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. + */ + +#include + +#include +#include +#include + +#include "arizona.h" + +/* We use a function so we can use ARRAY_SIZE() */ +int marley_patch(struct arizona *arizona) +{ + return 0; +} +EXPORT_SYMBOL_GPL(marley_patch); + +static const struct regmap_irq marley_irqs[ARIZONA_NUM_IRQ] = { + [ARIZONA_IRQ_BOOT_DONE] = { .reg_offset = 0, + .mask = CLEARWATER_BOOT_DONE_EINT1 }, + [ARIZONA_IRQ_CTRLIF_ERR] = { .reg_offset = 0, + .mask = CLEARWATER_CTRLIF_ERR_EINT1 }, + + [ARIZONA_IRQ_FLL1_CLOCK_OK] = { .reg_offset = 1, + .mask = CLEARWATER_FLL1_LOCK_EINT1 }, + + [ARIZONA_IRQ_MICDET] = { .reg_offset = 5, + .mask = CLEARWATER_MICDET_EINT1 }, + [ARIZONA_IRQ_HPDET] = { .reg_offset = 5, + .mask = CLEARWATER_HPDET_EINT1}, + + [ARIZONA_IRQ_MICD_CLAMP_RISE] = { .reg_offset = 6, + .mask = CLEARWATER_MICD_CLAMP_RISE_EINT1 }, + [ARIZONA_IRQ_MICD_CLAMP_FALL] = { .reg_offset = 6, + .mask = CLEARWATER_MICD_CLAMP_FALL_EINT1 }, + [ARIZONA_IRQ_JD_FALL] = { .reg_offset = 6, + .mask = CLEARWATER_JD1_FALL_EINT1 }, + [ARIZONA_IRQ_JD_RISE] = { .reg_offset = 6, + .mask = CLEARWATER_JD1_RISE_EINT1 }, + + [ARIZONA_IRQ_DRC2_SIG_DET] = { .reg_offset = 8, + .mask = CLEARWATER_DRC2_SIG_DET_EINT1 }, + [ARIZONA_IRQ_DRC1_SIG_DET] = { .reg_offset = 8, + .mask = CLEARWATER_DRC1_SIG_DET_EINT1 }, + + [ARIZONA_IRQ_DSP_IRQ1] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ1_EINT1}, + [ARIZONA_IRQ_DSP_IRQ2] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ2_EINT1}, + [ARIZONA_IRQ_DSP_IRQ3] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ3_EINT1}, + [ARIZONA_IRQ_DSP_IRQ4] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ4_EINT1}, + [ARIZONA_IRQ_DSP_IRQ5] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ5_EINT1}, + [ARIZONA_IRQ_DSP_IRQ6] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ6_EINT1}, + [ARIZONA_IRQ_DSP_IRQ7] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ7_EINT1}, + [ARIZONA_IRQ_DSP_IRQ8] = { .reg_offset = 10, + .mask = CLEARWATER_DSP_IRQ8_EINT1}, + + [ARIZONA_IRQ_SPK_OVERHEAT_WARN] = { .reg_offset = 14, + .mask = CLEARWATER_SPK_OVERHEAT_WARN_EINT1}, + [ARIZONA_IRQ_SPK_OVERHEAT] = { .reg_offset = 14, + .mask = CLEARWATER_SPK_SHUTDOWN_EINT1}, +}; + +const struct regmap_irq_chip marley_irq = { + .name = "marley IRQ", + .status_base = CLEARWATER_IRQ1_STATUS_1, + .mask_base = CLEARWATER_IRQ1_MASK_1, + .ack_base = CLEARWATER_IRQ1_STATUS_1, + .num_regs = 15, + .irqs = marley_irqs, + .num_irqs = ARRAY_SIZE(marley_irqs), +}; +EXPORT_SYMBOL_GPL(marley_irq); + +static const struct reg_default marley_reg_default[] = { + { 0x00000008, 0x0308 }, /* R8 (0x8) - Ctrl IF CFG 1 */ + { 0x00000009, 0x0200 }, /* R9 (0x9) - Ctrl IF CFG 2 */ + { 0x00000016, 0x0000 }, /* R22 (0x16) - Write Sequencer Ctrl 0 */ + { 0x00000017, 0x0000 }, /* R23 (0x17) - Write Sequencer Ctrl 1 */ + { 0x00000018, 0x0000 }, /* R24 (0x18) - Write Sequencer Ctrl 2 */ + { 0x0000001a, 0x0000 }, /* R26 (0x1A) - Write Sequencer PROM */ + { 0x00000020, 0x0000 }, /* R32 (0x20) - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 (0x21) - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 (0x22) - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 (0x23) - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 (0x24) - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 (0x30) - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 (0x31) - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 (0x32) - PWM Drive 3 */ + { 0x00000041, 0x0000 }, /* R65 (0x41) - Sequence control */ + { 0x00000061, 0x01ff }, /* R97 (0x61) - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01ff }, /* R98 (0x62) - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01ff }, /* R99 (0x63) - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01ff }, /* R100 (0x64) - Sample Rate Sequence Select 4*/ + { 0x00000066, 0x01ff }, /* R102 (0x66) - Always On Triggers Sequence + Select 1*/ + { 0x00000067, 0x01ff }, /* R103 (0x67) - Always On Triggers Sequence + Select 2*/ + { 0x00000090, 0x0000 }, /* R144 (0x90) - Haptics Control 1 */ + { 0x00000091, 0x7fff }, /* R145 (0x91) - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 (0x92) - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 (0x93) - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 (0x94) - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 (0x95) - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 (0x96) - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 (0x97) - Haptics phase 3 duration */ + { 0x000000A0, 0x0000 }, /* R160 (0xA0) - Comfort Noise Generator */ + { 0x00000100, 0x0002 }, /* R256 (0x100) - Clock 32k 1 */ + { 0x00000101, 0x0404 }, /* R257 (0x101) - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 (0x102) - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 (0x103) - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 (0x104) - Sample rate 3 */ + { 0x00000120, 0x0305 }, /* R288 (0x120) - DSP Clock 1 */ + { 0x00000122, 0x0000 }, /* R290 (0x122) - DSP Clock 2 */ + { 0x00000149, 0x0000 }, /* R329 (0x149) - Output system clock */ + { 0x0000014a, 0x0000 }, /* R330 (0x14A) - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 (0x152) - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 (0x153) - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 (0x154) - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 (0x155) - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 (0x156) - Rate Estimator 5 */ + { 0x00000171, 0x0002 }, /* R369 (0x171) - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 (0x172) - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 (0x173) - FLL1 Control 3 */ + { 0x00000174, 0x007d }, /* R372 (0x174) - FLL1 Control 4 */ + { 0x00000175, 0x0000 }, /* R373 (0x175) - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 (0x176) - FLL1 Control 6 */ + { 0x00000177, 0x0281 }, /* R375 (0x177) - FLL1 Loop Filter Test 1 */ + { 0x00000178, 0x0000 }, /* R376 (0x178) - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R377 (0x179) - FLL1 Control 7 */ + { 0x0000017f, 0x0000 }, /* R383 (0x17f) - FLL1 Synchroniser 1 */ + { 0x00000180, 0x0000 }, /* R384 (0x180) - FLL1 Synchroniser 2 */ + { 0x00000181, 0x0000 }, /* R385 (0x181) - FLL1 Synchroniser 3 */ + { 0x00000182, 0x0000 }, /* R386 (0x182) - FLL1 Synchroniser 4 */ + { 0x00000183, 0x0000 }, /* R387 (0x183) - FLL1 Synchroniser 5 */ + { 0x00000184, 0x0000 }, /* R388 (0x184) - FLL1 Synchroniser 6 */ + { 0x00000185, 0x0001 }, /* R389 (0x185) - FLL1 Synchroniser 7 */ + { 0x00000187, 0x0000 }, /* R391 (0x187) - FLL1 Spread Spectrum */ + { 0x00000188, 0x000c }, /* R392 (0x188) - FLL1 GPIO Clock */ + { 0x00000200, 0x0006 }, /* R512 (0x200) - Mic Charge Pump 1 */ + { 0x00000213, 0x03e4 }, /* R531 (0x213) - LDO2 Control 1 */ + { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */ + { 0x00000219, 0x00e6 }, /* R537 (0x219) - Mic Bias Ctrl 2 */ + { 0x0000021c, 0x0022 }, /* R540 (0x21c) - Mic Bias Ctrl 5 */ + { 0x0000021e, 0x0022 }, /* R542 (0x21e) - Mic Bias Ctrl 6 */ + { 0x0000027e, 0x0000 }, /* R638 (0x27E) - EDRE HP stereo control */ + { 0x00000293, 0x0080 }, /* R659 (0x293) - Accessory Detect Mode 1 */ + { 0x0000029b, 0x0000 }, /* R667 (0x29B) - Headphone Detect 1 */ + { 0x000002a3, 0x1102 }, /* R675 (0x2A3) - Mic Detect 1 */ + { 0x000002a4, 0x009f }, /* R676 (0x2A4) - Mic Detect 2 */ + { 0x000002a6, 0x3d3d }, /* R678 (0x2a6) - Mic Detect Level 1 */ + { 0x000002a7, 0x3d3d }, /* R679 (0x2a7) - Mic Detect Level 2 */ + { 0x000002a8, 0x333d }, /* R680 (0x2a8) - Mic Detect Level 3 */ + { 0x000002a9, 0x202d }, /* R681 (0x2a9) - Mic Detect Level 4 */ + { 0x000002c3, 0x0000 }, /* R707 (0x2c3) - Mic noise mix control 1 */ + { 0x000002c6, 0x0010 }, /* R710 (0x2c5) - Mic Clamp control */ + { 0x000002c8, 0x0000 }, /* R712 (0x2C8) - GP switch 1 */ + { 0x000002d3, 0x0000 }, /* R723 (0x2D3) - Jack detect analogue */ + { 0x00000308, 0x0000 }, /* R776 (0x308) - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 (0x309) - Input Volume Ramp */ + { 0x0000030c, 0x0002 }, /* R780 (0x30C) - HPF Control */ + { 0x00000310, 0x0080 }, /* R784 (0x310) - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 (0x311) - ADC Digital Volume 1L */ + { 0x00000312, 0x0500 }, /* R786 (0x312) - DMIC1L Control */ + { 0x00000314, 0x0080 }, /* R788 (0x314) - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 (0x315) - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 (0x316) - DMIC1R Control */ + { 0x00000318, 0x0080 }, /* R792 (0x318) - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 (0x319) - ADC Digital Volume 2L */ + { 0x0000031a, 0x0500 }, /* R794 (0x31A) - DMIC2L Control */ + { 0x0000031c, 0x0080 }, /* R796 (0x31C) - IN2R Control */ + { 0x0000031d, 0x0180 }, /* R797 (0x31D) - ADC Digital Volume 2R */ + { 0x0000031e, 0x0000 }, /* R798 (0x31E) - DMIC2R Control */ + { 0x00000400, 0x0000 }, /* R1024 (0x400) - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 (0x408) - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 (0x409) - Output Volume Ramp */ + { 0x00000410, 0x0080 }, /* R1040 (0x410) - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 (0x411) - DAC Digital Volume 1L */ + { 0x00000413, 0x0001 }, /* R1043 (0x413) - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 (0x414) - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 (0x415) - DAC Digital Volume 1R */ + { 0x00000417, 0x0002 }, /* R1047 (0x417) - Noise Gate Select 1R */ + { 0x00000428, 0x0000 }, /* R1064 (0x428) - Output Path Config 4L */ + { 0x00000429, 0x0180 }, /* R1065 (0x429) - DAC Digital Volume 4L */ + { 0x0000042b, 0x0040 }, /* R1067 (0x42B) - Noise Gate Select 4L */ + { 0x00000430, 0x0000 }, /* R1072 (0x430) - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 (0x431) - DAC Digital Volume 5L */ + { 0x00000433, 0x0100 }, /* R1075 (0x433) - Noise Gate Select 5L */ + { 0x00000434, 0x0000 }, /* R1076 (0x434) - Output Path Config 5R */ + { 0x00000435, 0x0180 }, /* R1077 (0x435) - DAC Digital Volume 5R */ + { 0x00000437, 0x0200 }, /* R1079 (0x437) - Noise Gate Select 5R */ + { 0x00000440, 0x0003 }, /* R1088 (0x440) - DRE Enable */ + { 0x00000441, 0xC050 }, /* R1089 (0x441) - DRE Control 1 */ + { 0x00000442, 0x0305 }, /* R1090 (0x442) - DRE Control 2 */ + { 0x00000443, 0x5cfa }, /* R1091 (0x443) - DRE Control 3 */ + { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */ + { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ + { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2*/ + { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ + { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ + { 0x000004a0, 0x3080 }, /* R1184 (0x4a0) - HP1 Short Circuit Ctrl */ + { 0x000004a8, 0x7120 }, /* R1192 (0x4a8) - HP Test Ctrl 5 */ + { 0x000004a9, 0x7120 }, /* R1193 (0x4a9) - HP Test Ctrl 6 */ + { 0x000004b6, 0x0080 }, /* R1206 (0x4b6) - SPK IF Control 9*/ + { 0x00000500, 0x000c }, /* R1280 (0x500) - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0000 }, /* R1281 (0x501) - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 (0x502) - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 (0x503) - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 (0x504) - AIF1 Format */ + { 0x00000505, 0x0040 }, /* R1285 (0x505) - AIF1 Tx BCLK Rate */ + { 0x00000506, 0x0040 }, /* R1286 (0x506) - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 (0x507) - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 (0x508) - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 (0x509) - AIF1 Frame Ctrl 3 */ + { 0x0000050a, 0x0001 }, /* R1290 (0x50A) - AIF1 Frame Ctrl 4 */ + { 0x0000050b, 0x0002 }, /* R1291 (0x50B) - AIF1 Frame Ctrl 5 */ + { 0x0000050c, 0x0003 }, /* R1292 (0x50C) - AIF1 Frame Ctrl 6 */ + { 0x0000050d, 0x0004 }, /* R1293 (0x50D) - AIF1 Frame Ctrl 7 */ + { 0x0000050e, 0x0005 }, /* R1294 (0x50E) - AIF1 Frame Ctrl 8 */ + { 0x00000511, 0x0000 }, /* R1297 (0x511) - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 (0x512) - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 (0x513) - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 (0x514) - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 (0x515) - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 (0x516) - AIF1 Frame Ctrl 16 */ + { 0x00000519, 0x0000 }, /* R1305 (0x519) - AIF1 Tx Enables */ + { 0x0000051a, 0x0000 }, /* R1306 (0x51A) - AIF1 Rx Enables */ + { 0x0000051b, 0x0000 }, /* R1307 (0x51B) - AIF1 Force Write */ + { 0x00000540, 0x000c }, /* R1344 (0x540) - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0000 }, /* R1345 (0x541) - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 (0x542) - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 (0x543) - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 (0x544) - AIF2 Format */ + { 0x00000545, 0x0040 }, /* R1349 (0x545) - AIF2 Tx BCLK Rate */ + { 0x00000546, 0x0040 }, /* R1350 (0x546) - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 (0x547) - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 (0x548) - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 (0x549) - AIF2 Frame Ctrl 3 */ + { 0x0000054a, 0x0001 }, /* R1354 (0x54A) - AIF2 Frame Ctrl 4 */ + { 0x00000551, 0x0000 }, /* R1361 (0x551) - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 (0x552) - AIF2 Frame Ctrl 12 */ + { 0x00000559, 0x0000 }, /* R1369 (0x559) - AIF2 Tx Enables */ + { 0x0000055a, 0x0000 }, /* R1370 (0x55A) - AIF2 Rx Enables */ + { 0x0000055b, 0x0000 }, /* R1371 (0x55B) - AIF2 Force Write */ + { 0x00000580, 0x000c }, /* R1408 (0x580) - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0000 }, /* R1409 (0x581) - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 (0x582) - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 (0x583) - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 (0x584) - AIF3 Format */ + { 0x00000585, 0x0040 }, /* R1413 (0x585) - AIF3 Tx BCLK Rate */ + { 0x00000586, 0x0040 }, /* R1414 (0x586) - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 (0x587) - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 (0x588) - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 (0x589) - AIF3 Frame Ctrl 3 */ + { 0x0000058a, 0x0001 }, /* R1418 (0x58A) - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 (0x591) - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 (0x592) - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 (0x599) - AIF3 Tx Enables */ + { 0x0000059a, 0x0000 }, /* R1434 (0x59A) - AIF3 Rx Enables */ + { 0x0000059b, 0x0000 }, /* R1435 (0x59B) - AIF3 Force Write */ + { 0x000005c2, 0x0000 }, /* R1474 (0x5c2) - SPD1 TX Control */ + { 0x000005e3, 0x0000 }, /* R1507 (0x5E3) - SLIMbus Framer Ref Gear */ + { 0x000005e5, 0x0000 }, /* R1509 (0x5E5) - SLIMbus Rates 1 */ + { 0x000005e6, 0x0000 }, /* R1510 (0x5E6) - SLIMbus Rates 2 */ + { 0x000005e7, 0x0000 }, /* R1511 (0x5E7) - SLIMbus Rates 3 */ + { 0x000005e9, 0x0000 }, /* R1513 (0x5E9) - SLIMbus Rates 5 */ + { 0x000005ea, 0x0000 }, /* R1514 (0x5EA) - SLIMbus Rates 6 */ + { 0x000005eb, 0x0000 }, /* R1515 (0x5EB) - SLIMbus Rates 7 */ + { 0x000005f5, 0x0000 }, /* R1525 (0x5F5) - SLIMbus RX Channel Enable */ + { 0x000005f6, 0x0000 }, /* R1526 (0x5F6) - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 (0x640) - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 (0x641) - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 (0x642) - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 (0x643) - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 (0x644) - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 (0x645) - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 (0x646) - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 (0x647) - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 (0x648) - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 (0x649) - PWM2MIX Input 1 Volume */ + { 0x0000064a, 0x0000 }, /* R1610 (0x64a) - PWM2MIX Input 2 Source */ + { 0x0000064b, 0x0080 }, /* R1611 (0x64b) - PWM2MIX Input 2 Volume */ + { 0x0000064c, 0x0000 }, /* R1612 (0x64c) - PWM2MIX Input 3 Source */ + { 0x0000064d, 0x0080 }, /* R1613 (0x64d) - PWM2MIX Input 3 Volume */ + { 0x0000064e, 0x0000 }, /* R1614 (0x64e) - PWM2MIX Input 4 Source */ + { 0x0000064f, 0x0080 }, /* R1615 (0x64f) - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 (0x680) - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 (0x681) - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 (0x682) - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 (0x683) - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 (0x684) - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 (0x685) - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 (0x686) - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 (0x687) - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 (0x688) - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 (0x689) - OUT1RMIX Input 1 Volume */ + { 0x0000068a, 0x0000 }, /* R1674 (0x68a) - OUT1RMIX Input 2 Source */ + { 0x0000068b, 0x0080 }, /* R1675 (0x68b) - OUT1RMIX Input 2 Volume */ + { 0x0000068c, 0x0000 }, /* R1672 (0x68c) - OUT1RMIX Input 3 Source */ + { 0x0000068d, 0x0080 }, /* R1673 (0x68d) - OUT1RMIX Input 3 Volume */ + { 0x0000068e, 0x0000 }, /* R1674 (0x68e) - OUT1RMIX Input 4 Source */ + { 0x0000068f, 0x0080 }, /* R1675 (0x68f) - OUT1RMIX Input 4 Volume */ + { 0x000006b0, 0x0000 }, /* R1712 (0x6b0) - OUT4LMIX Input 1 Source */ + { 0x000006b1, 0x0080 }, /* R1713 (0x6b1) - OUT4LMIX Input 1 Volume */ + { 0x000006b2, 0x0000 }, /* R1714 (0x6b2) - OUT4LMIX Input 2 Source */ + { 0x000006b3, 0x0080 }, /* R1715 (0x6b3) - OUT4LMIX Input 2 Volume */ + { 0x000006b4, 0x0000 }, /* R1716 (0x6b4) - OUT4LMIX Input 3 Source */ + { 0x000006b5, 0x0080 }, /* R1717 (0x6b5) - OUT4LMIX Input 3 Volume */ + { 0x000006b6, 0x0000 }, /* R1718 (0x6b6) - OUT4LMIX Input 4 Source */ + { 0x000006b7, 0x0080 }, /* R1719 (0x6b7) - OUT4LMIX Input 4 Volume */ + { 0x000006c0, 0x0000 }, /* R1728 (0x6c0) - OUT5LMIX Input 1 Source */ + { 0x000006c1, 0x0080 }, /* R1729 (0x6c1) - OUT5LMIX Input 1 Volume */ + { 0x000006c2, 0x0000 }, /* R1730 (0x6c2) - OUT5LMIX Input 2 Source */ + { 0x000006c3, 0x0080 }, /* R1731 (0x6c3) - OUT5LMIX Input 2 Volume */ + { 0x000006c4, 0x0000 }, /* R1732 (0x6c4) - OUT5LMIX Input 3 Source */ + { 0x000006c5, 0x0080 }, /* R1733 (0x6c5) - OUT5LMIX Input 3 Volume */ + { 0x000006c6, 0x0000 }, /* R1734 (0x6c6) - OUT5LMIX Input 4 Source */ + { 0x000006c7, 0x0080 }, /* R1735 (0x6c7) - OUT5LMIX Input 4 Volume */ + { 0x000006c8, 0x0000 }, /* R1736 (0x6c8) - OUT5RMIX Input 1 Source */ + { 0x000006c9, 0x0080 }, /* R1737 (0x6c9) - OUT5RMIX Input 1 Volume */ + { 0x000006ca, 0x0000 }, /* R1738 (0x6ca) - OUT5RMIX Input 2 Source */ + { 0x000006cb, 0x0080 }, /* R1739 (0x6cb) - OUT5RMIX Input 2 Volume */ + { 0x000006cc, 0x0000 }, /* R1740 (0x6cc) - OUT5RMIX Input 3 Source */ + { 0x000006cd, 0x0080 }, /* R1741 (0x6cd) - OUT5RMIX Input 3 Volume */ + { 0x000006ce, 0x0000 }, /* R1742 (0x6ce) - OUT5RMIX Input 4 Source */ + { 0x000006cf, 0x0080 }, /* R1743 (0x6cf) - OUT5RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 (0x700) - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 (0x701) - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 (0x702) - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 (0x703) - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 (0x704) - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 (0x705) - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 (0x706) - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 (0x707) - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 (0x708) - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 (0x709) - AIF1TX2MIX Input 1 Volume */ + { 0x0000070a, 0x0000 }, /* R1802 (0x70a) - AIF1TX2MIX Input 2 Source */ + { 0x0000070b, 0x0080 }, /* R1803 (0x70b) - AIF1TX2MIX Input 2 Volume */ + { 0x0000070c, 0x0000 }, /* R1804 (0x70c) - AIF1TX2MIX Input 3 Source */ + { 0x0000070d, 0x0080 }, /* R1805 (0x70d) - AIF1TX2MIX Input 3 Volume */ + { 0x0000070e, 0x0000 }, /* R1806 (0x70e) - AIF1TX2MIX Input 4 Source */ + { 0x0000070f, 0x0080 }, /* R1807 (0x70f) - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 (0x710) - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 (0x711) - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 (0x712) - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 (0x713) - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 (0x714) - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 (0x715) - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 (0x716) - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 (0x717) - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 (0x718) - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 (0x719) - AIF1TX4MIX Input 1 Volume */ + { 0x0000071a, 0x0000 }, /* R1818 (0x71a) - AIF1TX4MIX Input 2 Source */ + { 0x0000071b, 0x0080 }, /* R1819 (0x71b) - AIF1TX4MIX Input 2 Volume */ + { 0x0000071c, 0x0000 }, /* R1820 (0x71c) - AIF1TX4MIX Input 3 Source */ + { 0x0000071d, 0x0080 }, /* R1821 (0x71d) - AIF1TX4MIX Input 3 Volume */ + { 0x0000071e, 0x0000 }, /* R1822 (0x71e) - AIF1TX4MIX Input 4 Source */ + { 0x0000071f, 0x0080 }, /* R1823 (0x71f) - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 (0x720) - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 (0x721) - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 (0x722) - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 (0x723) - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 (0x724) - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 (0x725) - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 (0x726) - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 (0x727) - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 (0x728) - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 (0x729) - AIF1TX6MIX Input 1 Volume */ + { 0x0000072a, 0x0000 }, /* R1834 (0x72a) - AIF1TX6MIX Input 2 Source */ + { 0x0000072b, 0x0080 }, /* R1835 (0x72b) - AIF1TX6MIX Input 2 Volume */ + { 0x0000072c, 0x0000 }, /* R1836 (0x72c) - AIF1TX6MIX Input 3 Source */ + { 0x0000072d, 0x0080 }, /* R1837 (0x72d) - AIF1TX6MIX Input 3 Volume */ + { 0x0000072e, 0x0000 }, /* R1838 (0x72e) - AIF1TX6MIX Input 4 Source */ + { 0x0000072f, 0x0080 }, /* R1839 (0x72f) - AIF1TX6MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 (0x740) - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 (0x741) - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 (0x742) - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 (0x743) - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 (0x744) - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 (0x745) - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 (0x746) - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 (0x747) - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 (0x748) - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 (0x749) - AIF2TX2MIX Input 1 Volume */ + { 0x0000074a, 0x0000 }, /* R1866 (0x74a) - AIF2TX2MIX Input 2 Source */ + { 0x0000074b, 0x0080 }, /* R1867 (0x74b) - AIF2TX2MIX Input 2 Volume */ + { 0x0000074c, 0x0000 }, /* R1868 (0x74c) - AIF2TX2MIX Input 3 Source */ + { 0x0000074d, 0x0080 }, /* R1869 (0x74d) - AIF2TX2MIX Input 3 Volume */ + { 0x0000074e, 0x0000 }, /* R1870 (0x74e) - AIF2TX2MIX Input 4 Source */ + { 0x0000074f, 0x0080 }, /* R1871 (0x74f) - AIF2TX2MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 (0x780) - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 (0x781) - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 (0x782) - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 (0x783) - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 (0x784) - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 (0x785) - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 (0x786) - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 (0x787) - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 (0x788) - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 (0x789) - AIF3TX2MIX Input 1 Volume */ + { 0x0000078a, 0x0000 }, /* R1930 (0x78a) - AIF3TX2MIX Input 2 Source */ + { 0x0000078b, 0x0080 }, /* R1931 (0x78b) - AIF3TX2MIX Input 2 Volume */ + { 0x0000078c, 0x0000 }, /* R1932 (0x78c) - AIF3TX2MIX Input 3 Source */ + { 0x0000078d, 0x0080 }, /* R1933 (0x78d) - AIF3TX2MIX Input 3 Volume */ + { 0x0000078e, 0x0000 }, /* R1934 (0x78e) - AIF3TX2MIX Input 4 Source */ + { 0x0000078f, 0x0080 }, /* R1935 (0x78f) - AIF3TX2MIX Input 4 Volume */ + { 0x000007c0, 0x0000 }, /* R1984 (0x7c0) - SLIMTX1MIX Input 1 Source */ + { 0x000007c1, 0x0080 }, /* R1985 (0x7c1) - SLIMTX1MIX Input 1 Volume */ + { 0x000007c2, 0x0000 }, /* R1986 (0x7c2) - SLIMTX1MIX Input 2 Source */ + { 0x000007c3, 0x0080 }, /* R1987 (0x7c3) - SLIMTX1MIX Input 2 Volume */ + { 0x000007c4, 0x0000 }, /* R1988 (0x7c4) - SLIMTX1MIX Input 3 Source */ + { 0x000007c5, 0x0080 }, /* R1989 (0x7c5) - SLIMTX1MIX Input 3 Volume */ + { 0x000007c6, 0x0000 }, /* R1990 (0x7c6) - SLIMTX1MIX Input 4 Source */ + { 0x000007c7, 0x0080 }, /* R1991 (0x7c7) - SLIMTX1MIX Input 4 Volume */ + { 0x000007c8, 0x0000 }, /* R1992 (0x7c8) - SLIMTX2MIX Input 1 Source */ + { 0x000007c9, 0x0080 }, /* R1993 (0x7c9) - SLIMTX2MIX Input 1 Volume */ + { 0x000007ca, 0x0000 }, /* R1994 (0x7ca) - SLIMTX2MIX Input 2 Source */ + { 0x000007cb, 0x0080 }, /* R1995 (0x7cb) - SLIMTX2MIX Input 2 Volume */ + { 0x000007cc, 0x0000 }, /* R1996 (0x7cc) - SLIMTX2MIX Input 3 Source */ + { 0x000007cd, 0x0080 }, /* R1997 (0x7cd) - SLIMTX2MIX Input 3 Volume */ + { 0x000007ce, 0x0000 }, /* R1998 (0x7ce) - SLIMTX2MIX Input 4 Source */ + { 0x000007cf, 0x0080 }, /* R1999 (0x7cf) - SLIMTX2MIX Input 4 Volume */ + { 0x000007d0, 0x0000 }, /* R2000 (0x7d0) - SLIMTX3MIX Input 1 Source */ + { 0x000007d1, 0x0080 }, /* R2001 (0x7d1) - SLIMTX3MIX Input 1 Volume */ + { 0x000007d2, 0x0000 }, /* R2002 (0x7d2) - SLIMTX3MIX Input 2 Source */ + { 0x000007d3, 0x0080 }, /* R2003 (0x7d3) - SLIMTX3MIX Input 2 Volume */ + { 0x000007d4, 0x0000 }, /* R2004 (0x7d4) - SLIMTX3MIX Input 3 Source */ + { 0x000007d5, 0x0080 }, /* R2005 (0x7d5) - SLIMTX3MIX Input 3 Volume */ + { 0x000007d6, 0x0000 }, /* R2006 (0x7d6) - SLIMTX3MIX Input 4 Source */ + { 0x000007d7, 0x0080 }, /* R2007 (0x7d7) - SLIMTX3MIX Input 4 Volume */ + { 0x000007d8, 0x0000 }, /* R2008 (0x7d8) - SLIMTX4MIX Input 1 Source */ + { 0x000007d9, 0x0080 }, /* R2009 (0x7d9) - SLIMTX4MIX Input 1 Volume */ + { 0x000007da, 0x0000 }, /* R2010 (0x7da) - SLIMTX4MIX Input 2 Source */ + { 0x000007db, 0x0080 }, /* R2011 (0x7db) - SLIMTX4MIX Input 2 Volume */ + { 0x000007dc, 0x0000 }, /* R2012 (0x7dc) - SLIMTX4MIX Input 3 Source */ + { 0x000007dd, 0x0080 }, /* R2013 (0x7dd) - SLIMTX4MIX Input 3 Volume */ + { 0x000007de, 0x0000 }, /* R2014 (0x7de) - SLIMTX4MIX Input 4 Source */ + { 0x000007df, 0x0080 }, /* R2015 (0x7df) - SLIMTX4MIX Input 4 Volume */ + { 0x000007e0, 0x0000 }, /* R2016 (0x7e0) - SLIMTX5MIX Input 1 Source */ + { 0x000007e1, 0x0080 }, /* R2017 (0x7e1) - SLIMTX5MIX Input 1 Volume */ + { 0x000007e2, 0x0000 }, /* R2018 (0x7e2) - SLIMTX5MIX Input 2 Source */ + { 0x000007e3, 0x0080 }, /* R2019 (0x7e3) - SLIMTX5MIX Input 2 Volume */ + { 0x000007e4, 0x0000 }, /* R2020 (0x7e4) - SLIMTX5MIX Input 3 Source */ + { 0x000007e5, 0x0080 }, /* R2021 (0x7e5) - SLIMTX5MIX Input 3 Volume */ + { 0x000007e6, 0x0000 }, /* R2022 (0x7e6) - SLIMTX5MIX Input 4 Source */ + { 0x000007e7, 0x0080 }, /* R2023 (0x7e7) - SLIMTX5MIX Input 4 Volume */ + { 0x000007e8, 0x0000 }, /* R2024 (0x7e8) - SLIMTX6MIX Input 1 Source */ + { 0x000007e9, 0x0080 }, /* R2025 (0x7e9) - SLIMTX6MIX Input 1 Volume */ + { 0x000007ea, 0x0000 }, /* R2026 (0x7ea) - SLIMTX6MIX Input 2 Source */ + { 0x000007eb, 0x0080 }, /* R2027 (0x7eb) - SLIMTX6MIX Input 2 Volume */ + { 0x000007ec, 0x0000 }, /* R2028 (0x7ec) - SLIMTX6MIX Input 3 Source */ + { 0x000007ed, 0x0080 }, /* R2029 (0x7ed) - SLIMTX6MIX Input 3 Volume */ + { 0x000007ee, 0x0000 }, /* R2030 (0x7ee) - SLIMTX6MIX Input 4 Source */ + { 0x000007ef, 0x0080 }, /* R2031 (0x7ef) - SLIMTX6MIX Input 4 Volume */ + { 0x00000800, 0x0000 }, /* R2048 (0x800) - SPDIF1TX1MIX Input 1 Source*/ + { 0x00000801, 0x0080 }, /* R2049 (0x801) - SPDIF1TX1MIX Input 1 Volume*/ + { 0x00000808, 0x0000 }, /* R2056 (0x808) - SPDIF1TX2MIX Input 1 Source*/ + { 0x00000809, 0x0080 }, /* R2057 (0x809) - SPDIF1TX2MIX Input 1 Volume*/ + { 0x00000880, 0x0000 }, /* R2176 (0x880) - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 (0x881) - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 (0x882) - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 (0x883) - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 (0x884) - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 (0x885) - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 (0x886) - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 (0x887) - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 (0x888) - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 (0x889) - EQ2MIX Input 1 Volume */ + { 0x0000088a, 0x0000 }, /* R2186 (0x88a) - EQ2MIX Input 2 Source */ + { 0x0000088b, 0x0080 }, /* R2187 (0x88b) - EQ2MIX Input 2 Volume */ + { 0x0000088c, 0x0000 }, /* R2188 (0x88c) - EQ2MIX Input 3 Source */ + { 0x0000088d, 0x0080 }, /* R2189 (0x88d) - EQ2MIX Input 3 Volume */ + { 0x0000088e, 0x0000 }, /* R2190 (0x88e) - EQ2MIX Input 4 Source */ + { 0x0000088f, 0x0080 }, /* R2191 (0x88f) - EQ2MIX Input 4 Volume */ + { 0x00000890, 0x0000 }, /* R2192 (0x890) - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 (0x891) - EQ3MIX Input 1 Volume */ + { 0x00000892, 0x0000 }, /* R2194 (0x892) - EQ3MIX Input 2 Source */ + { 0x00000893, 0x0080 }, /* R2195 (0x893) - EQ3MIX Input 2 Volume */ + { 0x00000894, 0x0000 }, /* R2196 (0x894) - EQ3MIX Input 3 Source */ + { 0x00000895, 0x0080 }, /* R2197 (0x895) - EQ3MIX Input 3 Volume */ + { 0x00000896, 0x0000 }, /* R2198 (0x896) - EQ3MIX Input 4 Source */ + { 0x00000897, 0x0080 }, /* R2199 (0x897) - EQ3MIX Input 4 Volume */ + { 0x00000898, 0x0000 }, /* R2200 (0x898) - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 (0x899) - EQ4MIX Input 1 Volume */ + { 0x0000089a, 0x0000 }, /* R2202 (0x89a) - EQ4MIX Input 2 Source */ + { 0x0000089b, 0x0080 }, /* R2203 (0x89b) - EQ4MIX Input 2 Volume */ + { 0x0000089c, 0x0000 }, /* R2204 (0x89c) - EQ4MIX Input 3 Source */ + { 0x0000089d, 0x0080 }, /* R2205 (0x89d) - EQ4MIX Input 3 Volume */ + { 0x0000089e, 0x0000 }, /* R2206 (0x89e) - EQ4MIX Input 4 Source */ + { 0x0000089f, 0x0080 }, /* R2207 (0x89f) - EQ4MIX Input 4 Volume */ + { 0x000008c0, 0x0000 }, /* R2240 (0x8c0) - DRC1LMIX Input 1 Source */ + { 0x000008c1, 0x0080 }, /* R2241 (0x8c1) - DRC1LMIX Input 1 Volume */ + { 0x000008c2, 0x0000 }, /* R2242 (0x8c2) - DRC1LMIX Input 2 Source */ + { 0x000008c3, 0x0080 }, /* R2243 (0x8c3) - DRC1LMIX Input 2 Volume */ + { 0x000008c4, 0x0000 }, /* R2244 (0x8c4) - DRC1LMIX Input 3 Source */ + { 0x000008c5, 0x0080 }, /* R2245 (0x8c5) - DRC1LMIX Input 3 Volume */ + { 0x000008c6, 0x0000 }, /* R2246 (0x8c6) - DRC1LMIX Input 4 Source */ + { 0x000008c7, 0x0080 }, /* R2247 (0x8c7) - DRC1LMIX Input 4 Volume */ + { 0x000008c8, 0x0000 }, /* R2248 (0x8c8) - DRC1RMIX Input 1 Source */ + { 0x000008c9, 0x0080 }, /* R2249 (0x8c9) - DRC1RMIX Input 1 Volume */ + { 0x000008ca, 0x0000 }, /* R2250 (0x8ca) - DRC1RMIX Input 2 Source */ + { 0x000008cb, 0x0080 }, /* R2251 (0x8cb) - DRC1RMIX Input 2 Volume */ + { 0x000008cc, 0x0000 }, /* R2252 (0x8cc) - DRC1RMIX Input 3 Source */ + { 0x000008cd, 0x0080 }, /* R2253 (0x8cd) - DRC1RMIX Input 3 Volume */ + { 0x000008ce, 0x0000 }, /* R2254 (0x8ce) - DRC1RMIX Input 4 Source */ + { 0x000008cf, 0x0080 }, /* R2255 (0x8cf) - DRC1RMIX Input 4 Volume */ + { 0x000008d0, 0x0000 }, /* R2256 (0x8d0) - DRC2LMIX Input 1 Source */ + { 0x000008d1, 0x0080 }, /* R2257 (0x8d1) - DRC2LMIX Input 1 Volume */ + { 0x000008d2, 0x0000 }, /* R2258 (0x8d2) - DRC2LMIX Input 2 Source */ + { 0x000008d3, 0x0080 }, /* R2259 (0x8d3) - DRC2LMIX Input 2 Volume */ + { 0x000008d4, 0x0000 }, /* R2260 (0x8d4) - DRC2LMIX Input 3 Source */ + { 0x000008d5, 0x0080 }, /* R2261 (0x8d5) - DRC2LMIX Input 3 Volume */ + { 0x000008d6, 0x0000 }, /* R2262 (0x8d6) - DRC2LMIX Input 4 Source */ + { 0x000008d7, 0x0080 }, /* R2263 (0x8d7) - DRC2LMIX Input 4 Volume */ + { 0x000008d8, 0x0000 }, /* R2264 (0x8d8) - DRC2RMIX Input 1 Source */ + { 0x000008d9, 0x0080 }, /* R2265 (0x8d9) - DRC2RMIX Input 1 Volume */ + { 0x000008da, 0x0000 }, /* R2266 (0x8da) - DRC2RMIX Input 2 Source */ + { 0x000008db, 0x0080 }, /* R2267 (0x8db) - DRC2RMIX Input 2 Volume */ + { 0x000008dc, 0x0000 }, /* R2268 (0x8dc) - DRC2RMIX Input 3 Source */ + { 0x000008dd, 0x0080 }, /* R2269 (0x8dd) - DRC2RMIX Input 3 Volume */ + { 0x000008de, 0x0000 }, /* R2270 (0x8de) - DRC2RMIX Input 4 Source */ + { 0x000008df, 0x0080 }, /* R2271 (0x8df) - DRC2RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 (0x900) - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 (0x901) - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 (0x902) - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 (0x903) - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 (0x904) - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 (0x905) - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 (0x906) - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 (0x907) - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 (0x908) - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 (0x909) - HPLP2MIX Input 1 Volume */ + { 0x0000090a, 0x0000 }, /* R2314 (0x90a) - HPLP2MIX Input 2 Source */ + { 0x0000090b, 0x0080 }, /* R2315 (0x90b) - HPLP2MIX Input 2 Volume */ + { 0x0000090c, 0x0000 }, /* R2316 (0x90c) - HPLP2MIX Input 3 Source */ + { 0x0000090d, 0x0080 }, /* R2317 (0x90d) - HPLP2MIX Input 3 Volume */ + { 0x0000090e, 0x0000 }, /* R2318 (0x90e) - HPLP2MIX Input 4 Source */ + { 0x0000090f, 0x0080 }, /* R2319 (0x90f) - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 (0x910) - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 (0x911) - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 (0x912) - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 (0x913) - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 (0x914) - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 (0x915) - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 (0x916) - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 (0x917) - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 (0x918) - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 (0x919) - HPLP4MIX Input 1 Volume */ + { 0x0000091a, 0x0000 }, /* R2330 (0x91a) - HPLP4MIX Input 2 Source */ + { 0x0000091b, 0x0080 }, /* R2331 (0x91b) - HPLP4MIX Input 2 Volume */ + { 0x0000091c, 0x0000 }, /* R2332 (0x91c) - HPLP4MIX Input 3 Source */ + { 0x0000091d, 0x0080 }, /* R2333 (0x91d) - HPLP4MIX Input 3 Volume */ + { 0x0000091e, 0x0000 }, /* R2334 (0x91e) - HPLP4MIX Input 4 Source */ + { 0x0000091f, 0x0080 }, /* R2335 (0x91f) - HPLP4MIX Input 4 Volume */ + { 0x00000940, 0x0000 }, /* R2368 (0x940) - DSP1LMIX Input 1 Source */ + { 0x00000941, 0x0080 }, /* R2369 (0x941) - DSP1LMIX Input 1 Volume */ + { 0x00000942, 0x0000 }, /* R2370 (0x942) - DSP1LMIX Input 2 Source */ + { 0x00000943, 0x0080 }, /* R2371 (0x943) - DSP1LMIX Input 2 Volume */ + { 0x00000944, 0x0000 }, /* R2372 (0x944) - DSP1LMIX Input 3 Source */ + { 0x00000945, 0x0080 }, /* R2373 (0x945) - DSP1LMIX Input 3 Volume */ + { 0x00000946, 0x0000 }, /* R2374 (0x946) - DSP1LMIX Input 4 Source */ + { 0x00000947, 0x0080 }, /* R2375 (0x947) - DSP1LMIX Input 4 Volume */ + { 0x00000948, 0x0000 }, /* R2376 (0x948) - DSP1RMIX Input 1 Source */ + { 0x00000949, 0x0080 }, /* R2377 (0x949) - DSP1RMIX Input 1 Volume */ + { 0x0000094a, 0x0000 }, /* R2378 (0x94a) - DSP1RMIX Input 2 Source */ + { 0x0000094b, 0x0080 }, /* R2379 (0x94b) - DSP1RMIX Input 2 Volume */ + { 0x0000094c, 0x0000 }, /* R2380 (0x94c) - DSP1RMIX Input 3 Source */ + { 0x0000094d, 0x0080 }, /* R2381 (0x94d) - DSP1RMIX Input 3 Volume */ + { 0x0000094e, 0x0000 }, /* R2382 (0x94e) - DSP1RMIX Input 4 Source */ + { 0x0000094f, 0x0080 }, /* R2383 (0x94f) - DSP1RMIX Input 4 Volume */ + { 0x00000950, 0x0000 }, /* R2384 (0x950) - DSP1AUX1MIX Input 1 Source */ + { 0x00000958, 0x0000 }, /* R2392 (0x958) - DSP1AUX2MIX Input 1 Source */ + { 0x00000960, 0x0000 }, /* R2400 (0x960) - DSP1AUX3MIX Input 1 Source */ + { 0x00000968, 0x0000 }, /* R2408 (0x968) - DSP1AUX4MIX Input 1 Source */ + { 0x00000970, 0x0000 }, /* R2416 (0x970) - DSP1AUX5MIX Input 1 Source */ + { 0x00000978, 0x0000 }, /* R2424 (0x978) - DSP1AUX6MIX Input 1 Source */ + { 0x00000980, 0x0000 }, /* R2432 (0x980) - DSP2LMIX Input 1 Source */ + { 0x00000981, 0x0080 }, /* R2433 (0x981) - DSP2LMIX Input 1 Volume */ + { 0x00000982, 0x0000 }, /* R2434 (0x982) - DSP2LMIX Input 2 Source */ + { 0x00000983, 0x0080 }, /* R2435 (0x983) - DSP2LMIX Input 2 Volume */ + { 0x00000984, 0x0000 }, /* R2436 (0x984) - DSP2LMIX Input 3 Source */ + { 0x00000985, 0x0080 }, /* R2437 (0x985) - DSP2LMIX Input 3 Volume */ + { 0x00000986, 0x0000 }, /* R2438 (0x986) - DSP2LMIX Input 4 Source */ + { 0x00000987, 0x0080 }, /* R2439 (0x987) - DSP2LMIX Input 4 Volume */ + { 0x00000988, 0x0000 }, /* R2440 (0x988) - DSP2RMIX Input 1 Source */ + { 0x00000989, 0x0080 }, /* R2441 (0x989) - DSP2RMIX Input 1 Volume */ + { 0x0000098a, 0x0000 }, /* R2442 (0x98a) - DSP2RMIX Input 2 Source */ + { 0x0000098b, 0x0080 }, /* R2443 (0x98b) - DSP2RMIX Input 2 Volume */ + { 0x0000098c, 0x0000 }, /* R2444 (0x98c) - DSP2RMIX Input 3 Source */ + { 0x0000098d, 0x0080 }, /* R2445 (0x98d) - DSP2RMIX Input 3 Volume */ + { 0x0000098e, 0x0000 }, /* R2446 (0x98e) - DSP2RMIX Input 4 Source */ + { 0x0000098f, 0x0080 }, /* R2447 (0x98f) - DSP2RMIX Input 4 Volume */ + { 0x00000990, 0x0000 }, /* R2448 (0x990) - DSP2AUX1MIX Input 1 Source */ + { 0x00000998, 0x0000 }, /* R2456 (0x998) - DSP2AUX2MIX Input 1 Source */ + { 0x000009a0, 0x0000 }, /* R2464 (0x9a0) - DSP2AUX3MIX Input 1 Source */ + { 0x000009a8, 0x0000 }, /* R2472 (0x9a8) - DSP2AUX4MIX Input 1 Source */ + { 0x000009b0, 0x0000 }, /* R2480 (0x9b0) - DSP2AUX5MIX Input 1 Source */ + { 0x000009b8, 0x0000 }, /* R2488 (0x9b8) - DSP2AUX6MIX Input 1 Source */ + { 0x000009c0, 0x0000 }, /* R2496 (0x9c0) - DSP3LMIX Input 1 Source */ + { 0x000009c1, 0x0080 }, /* R2497 (0x9c1) - DSP3LMIX Input 1 Volume */ + { 0x000009c2, 0x0000 }, /* R2498 (0x9c2) - DSP3LMIX Input 2 Source */ + { 0x000009c3, 0x0080 }, /* R2499 (0x9c3) - DSP3LMIX Input 2 Volume */ + { 0x000009c4, 0x0000 }, /* R2500 (0x9c4) - DSP3LMIX Input 3 Source */ + { 0x000009c5, 0x0080 }, /* R2501 (0x9c5) - DSP3LMIX Input 3 Volume */ + { 0x000009c6, 0x0000 }, /* R2502 (0x9c6) - DSP3LMIX Input 4 Source */ + { 0x000009c7, 0x0080 }, /* R2503 (0x9c7) - DSP3LMIX Input 4 Volume */ + { 0x000009c8, 0x0000 }, /* R2504 (0x9c8) - DSP3RMIX Input 1 Source */ + { 0x000009c9, 0x0080 }, /* R2505 (0x9c9) - DSP3RMIX Input 1 Volume */ + { 0x000009ca, 0x0000 }, /* R2506 (0x9ca) - DSP3RMIX Input 2 Source */ + { 0x000009cb, 0x0080 }, /* R2507 (0x9cb) - DSP3RMIX Input 2 Volume */ + { 0x000009cc, 0x0000 }, /* R2508 (0x9cc) - DSP3RMIX Input 3 Source */ + { 0x000009cd, 0x0080 }, /* R2509 (0x9cd) - DSP3RMIX Input 3 Volume */ + { 0x000009ce, 0x0000 }, /* R2510 (0x9ce) - DSP3RMIX Input 4 Source */ + { 0x000009cf, 0x0080 }, /* R2511 (0x9cf) - DSP3RMIX Input 4 Volume */ + { 0x000009d0, 0x0000 }, /* R2512 (0x9d0) - DSP3AUX1MIX Input 1 Source */ + { 0x000009d8, 0x0000 }, /* R2520 (0x9d8) - DSP3AUX2MIX Input 1 Source */ + { 0x000009e0, 0x0000 }, /* R2528 (0x9e0) - DSP3AUX3MIX Input 1 Source */ + { 0x000009e8, 0x0000 }, /* R2536 (0x9e8) - DSP3AUX4MIX Input 1 Source */ + { 0x000009f0, 0x0000 }, /* R2544 (0x9f0) - DSP3AUX5MIX Input 1 Source */ + { 0x000009f8, 0x0000 }, /* R2552 (0x9f8) - DSP3AUX6MIX Input 1 Source */ + { 0x00000b00, 0x0000 }, /* R2816 (0xb00) - ISRC1DEC1MIX Input 1 Source*/ + { 0x00000b08, 0x0000 }, /* R2824 (0xb08) - ISRC1DEC2MIX Input 1 Source*/ + { 0x00000b10, 0x0000 }, /* R2832 (0xb10) - ISRC1DEC3MIX Input 1 Source*/ + { 0x00000b18, 0x0000 }, /* R2840 (0xb18) - ISRC1DEC4MIX Input 1 Source*/ + { 0x00000b20, 0x0000 }, /* R2848 (0xb20) - ISRC1INT1MIX Input 1 Source*/ + { 0x00000b28, 0x0000 }, /* R2856 (0xb28) - ISRC1INT2MIX Input 1 Source*/ + { 0x00000b30, 0x0000 }, /* R2864 (0xb30) - ISRC1INT3MIX Input 1 Source*/ + { 0x00000b38, 0x0000 }, /* R2872 (0xb38) - ISRC1INT4MIX Input 1 Source*/ + { 0x00000b40, 0x0000 }, /* R2880 (0xb40) - ISRC2DEC1MIX Input 1 Source*/ + { 0x00000b48, 0x0000 }, /* R2888 (0xb48) - ISRC2DEC2MIX Input 1 Source*/ + { 0x00000b50, 0x0000 }, /* R2896 (0xb50) - ISRC2DEC3MIX Input 1 Source*/ + { 0x00000b58, 0x0000 }, /* R2904 (0xb58) - ISRC2DEC4MIX Input 1 Source*/ + { 0x00000b60, 0x0000 }, /* R2912 (0xb60) - ISRC2INT1MIX Input 1 Source*/ + { 0x00000b68, 0x0000 }, /* R2920 (0xb68) - ISRC2INT2MIX Input 1 Source*/ + { 0x00000b70, 0x0000 }, /* R2928 (0xb70) - ISRC2INT3MIX Input 1 Source*/ + { 0x00000b78, 0x0000 }, /* R2936 (0xb78) - ISRC2INT4MIX Input 1 Source*/ + { 0x00000e00, 0x0000 }, /* R3584 (0xe00) - FX Ctrl1 */ + { 0x00000e10, 0x6318 }, /* R3600 (0xe10) - EQ1_1 */ + { 0x00000e11, 0x6300 }, /* R3601 (0xe11) - EQ1_2 */ + { 0x00000e12, 0x0fc8 }, /* R3602 (0xe12) - EQ1_3 */ + { 0x00000e13, 0x03fe }, /* R3603 (0xe13) - EQ1_4 */ + { 0x00000e14, 0x00e0 }, /* R3604 (0xe14) - EQ1_5 */ + { 0x00000e15, 0x1ec4 }, /* R3605 (0xe15) - EQ1_6 */ + { 0x00000e16, 0xf136 }, /* R3606 (0xe16) - EQ1_7 */ + { 0x00000e17, 0x0409 }, /* R3607 (0xe17) - EQ1_8 */ + { 0x00000e18, 0x04cc }, /* R3608 (0xe18) - EQ1_9 */ + { 0x00000e19, 0x1c9b }, /* R3609 (0xe19) - EQ1_10 */ + { 0x00000e1a, 0xf337 }, /* R3610 (0xe1a) - EQ1_11 */ + { 0x00000e1b, 0x040b }, /* R3611 (0xe1b) - EQ1_12 */ + { 0x00000e1c, 0x0cbb }, /* R3612 (0xe1c) - EQ1_13 */ + { 0x00000e1d, 0x16f8 }, /* R3613 (0xe1d) - EQ1_14 */ + { 0x00000e1e, 0xf7d9 }, /* R3614 (0xe1e) - EQ1_15 */ + { 0x00000e1f, 0x040a }, /* R3615 (0xe1f) - EQ1_16 */ + { 0x00000e20, 0x1f14 }, /* R3616 (0xe20) - EQ1_17 */ + { 0x00000e21, 0x058c }, /* R3617 (0xe21) - EQ1_18 */ + { 0x00000e22, 0x0563 }, /* R3618 (0xe22) - EQ1_19 */ + { 0x00000e23, 0x4000 }, /* R3619 (0xe23) - EQ1_20 */ + { 0x00000e24, 0x0b75 }, /* R3620 (0xe24) - EQ1_21 */ + { 0x00000e26, 0x6318 }, /* R3622 (0xe26) - EQ2_1 */ + { 0x00000e27, 0x6300 }, /* R3623 (0xe27) - EQ2_2 */ + { 0x00000e28, 0x0fc8 }, /* R3624 (0xe28) - EQ2_3 */ + { 0x00000e29, 0x03fe }, /* R3625 (0xe29) - EQ2_4 */ + { 0x00000e2a, 0x00e0 }, /* R3626 (0xe2a) - EQ2_5 */ + { 0x00000e2b, 0x1ec4 }, /* R3627 (0xe2b) - EQ2_6 */ + { 0x00000e2c, 0xf136 }, /* R3628 (0xe2c) - EQ2_7 */ + { 0x00000e2d, 0x0409 }, /* R3629 (0xe2d) - EQ2_8 */ + { 0x00000e2e, 0x04cc }, /* R3630 (0xe2e) - EQ2_9 */ + { 0x00000e2f, 0x1c9b }, /* R3631 (0xe2f) - EQ2_10 */ + { 0x00000e30, 0xf337 }, /* R3632 (0xe30) - EQ2_11 */ + { 0x00000e31, 0x040b }, /* R3633 (0xe31) - EQ2_12 */ + { 0x00000e32, 0x0cbb }, /* R3634 (0xe32) - EQ2_13 */ + { 0x00000e33, 0x16f8 }, /* R3635 (0xe33) - EQ2_14 */ + { 0x00000e34, 0xf7d9 }, /* R3636 (0xe34) - EQ2_15 */ + { 0x00000e35, 0x040a }, /* R3637 (0xe35) - EQ2_16 */ + { 0x00000e36, 0x1f14 }, /* R3638 (0xe36) - EQ2_17 */ + { 0x00000e37, 0x058c }, /* R3639 (0xe37) - EQ2_18 */ + { 0x00000e38, 0x0563 }, /* R3640 (0xe38) - EQ2_19 */ + { 0x00000e39, 0x4000 }, /* R3641 (0xe39) - EQ2_20 */ + { 0x00000e3a, 0x0b75 }, /* R3642 (0xe3a) - EQ2_21 */ + { 0x00000e3c, 0x6318 }, /* R3644 (0xe3c) - EQ3_1 */ + { 0x00000e3d, 0x6300 }, /* R3645 (0xe3d) - EQ3_2 */ + { 0x00000e3e, 0x0fc8 }, /* R3646 (0xe3e) - EQ3_3 */ + { 0x00000e3f, 0x03fe }, /* R3647 (0xe3f) - EQ3_4 */ + { 0x00000e40, 0x00e0 }, /* R3648 (0xe40) - EQ3_5 */ + { 0x00000e41, 0x1ec4 }, /* R3649 (0xe41) - EQ3_6 */ + { 0x00000e42, 0xf136 }, /* R3650 (0xe42) - EQ3_7 */ + { 0x00000e43, 0x0409 }, /* R3651 (0xe43) - EQ3_8 */ + { 0x00000e44, 0x04cc }, /* R3652 (0xe44) - EQ3_9 */ + { 0x00000e45, 0x1c9b }, /* R3653 (0xe45) - EQ3_10 */ + { 0x00000e46, 0xf337 }, /* R3654 (0xe46) - EQ3_11 */ + { 0x00000e47, 0x040b }, /* R3655 (0xe47) - EQ3_12 */ + { 0x00000e48, 0x0cbb }, /* R3656 (0xe48) - EQ3_13 */ + { 0x00000e49, 0x16f8 }, /* R3657 (0xe49) - EQ3_14 */ + { 0x00000e4a, 0xf7d9 }, /* R3658 (0xe4a) - EQ3_15 */ + { 0x00000e4b, 0x040a }, /* R3659 (0xe4b) - EQ3_16 */ + { 0x00000e4c, 0x1f14 }, /* R3660 (0xe4c) - EQ3_17 */ + { 0x00000e4d, 0x058c }, /* R3661 (0xe4d) - EQ3_18 */ + { 0x00000e4e, 0x0563 }, /* R3662 (0xe4e) - EQ3_19 */ + { 0x00000e4f, 0x4000 }, /* R3663 (0xe4f) - EQ3_20 */ + { 0x00000e50, 0x0b75 }, /* R3664 (0xe50) - EQ3_21 */ + { 0x00000e52, 0x6318 }, /* R3666 (0xe52) - EQ4_1 */ + { 0x00000e53, 0x6300 }, /* R3667 (0xe53) - EQ4_2 */ + { 0x00000e54, 0x0fc8 }, /* R3668 (0xe54) - EQ4_3 */ + { 0x00000e55, 0x03fe }, /* R3669 (0xe55) - EQ4_4 */ + { 0x00000e56, 0x00e0 }, /* R3670 (0xe56) - EQ4_5 */ + { 0x00000e57, 0x1ec4 }, /* R3671 (0xe57) - EQ4_6 */ + { 0x00000e58, 0xf136 }, /* R3672 (0xe58) - EQ4_7 */ + { 0x00000e59, 0x0409 }, /* R3673 (0xe59) - EQ4_8 */ + { 0x00000e5a, 0x04cc }, /* R3674 (0xe5a) - EQ4_9 */ + { 0x00000e5b, 0x1c9b }, /* R3675 (0xe5b) - EQ4_10 */ + { 0x00000e5c, 0xf337 }, /* R3676 (0xe5c) - EQ4_11 */ + { 0x00000e5d, 0x040b }, /* R3677 (0xe5d) - EQ4_12 */ + { 0x00000e5e, 0x0cbb }, /* R3678 (0xe5e) - EQ4_13 */ + { 0x00000e5f, 0x16f8 }, /* R3679 (0xe5f) - EQ4_14 */ + { 0x00000e60, 0xf7d9 }, /* R3680 (0xe60) - EQ4_15 */ + { 0x00000e61, 0x040a }, /* R3681 (0xe61) - EQ4_16 */ + { 0x00000e62, 0x1f14 }, /* R3682 (0xe62) - EQ4_17 */ + { 0x00000e63, 0x058c }, /* R3683 (0xe63) - EQ4_18 */ + { 0x00000e64, 0x0563 }, /* R3684 (0xe64) - EQ4_19 */ + { 0x00000e65, 0x4000 }, /* R3685 (0xe65) - EQ4_20 */ + { 0x00000e66, 0x0b75 }, /* R3686 (0xe66) - EQ4_21 */ + { 0x00000e80, 0x0018 }, /* R3712 (0xe80) - DRC1 ctrl1 */ + { 0x00000e81, 0x0933 }, /* R3713 (0xe81) - DRC1 ctrl2 */ + { 0x00000e82, 0x0018 }, /* R3714 (0xe82) - DRC1 ctrl3 */ + { 0x00000e83, 0x0000 }, /* R3715 (0xe83) - DRC1 ctrl4 */ + { 0x00000e84, 0x0000 }, /* R3716 (0xe84) - DRC1 ctrl5 */ + { 0x00000e88, 0x0018 }, /* R3720 (0xe88) - DRC2 ctrl1 */ + { 0x00000e89, 0x0933 }, /* R3721 (0xe89) - DRC2 ctrl2 */ + { 0x00000e8a, 0x0018 }, /* R3722 (0xe8a) - DRC2 ctrl3 */ + { 0x00000e8b, 0x0000 }, /* R3723 (0xe8b) - DRC2 ctrl4 */ + { 0x00000e8c, 0x0000 }, /* R3724 (0xe8c) - DRC2 ctrl5 */ + { 0x00000ec0, 0x0000 }, /* R3776 (0xec0) - HPLPF1_1 */ + { 0x00000ec1, 0x0000 }, /* R3777 (0xec1) - HPLPF1_2 */ + { 0x00000ec4, 0x0000 }, /* R3780 (0xec4) - HPLPF2_1 */ + { 0x00000ec5, 0x0000 }, /* R3781 (0xec5) - HPLPF2_2 */ + { 0x00000ec8, 0x0000 }, /* R3784 (0xec8) - HPLPF3_1 */ + { 0x00000ec9, 0x0000 }, /* R3785 (0xec9) - HPLPF3_2 */ + { 0x00000ecc, 0x0000 }, /* R3788 (0xecc) - HPLPF4_1 */ + { 0x00000ecd, 0x0000 }, /* R3789 (0xecd) - HPLPF4_2 */ + { 0x00000ef0, 0x0000 }, /* R3824 (0xef0) - ISRC 1 CTRL 1 */ + { 0x00000ef1, 0x0001 }, /* R3825 (0xef1) - ISRC 1 CTRL 2 */ + { 0x00000ef2, 0x0000 }, /* R3826 (0xef2) - ISRC 1 CTRL 3 */ + { 0x00000ef3, 0x0000 }, /* R3827 (0xef3) - ISRC 2 CTRL 1 */ + { 0x00000ef4, 0x0001 }, /* R3828 (0xef4) - ISRC 2 CTRL 2 */ + { 0x00000ef5, 0x0000 }, /* R3829 (0xef5) - ISRC 2 CTRL 3 */ + { 0x00001200, 0x0000 }, /* R4608 (0x1200) - Clock enable overrides 1 */ + { 0x00001204, 0x0000 }, /* R4612 (0x1204) - Clock enable overrides 3 */ + { 0x00001206, 0x0000 }, /* R4614 (0x1206) - Clock enable overrides 4 */ + { 0x00001210, 0x0000 }, /* R4624 (0x1210) - Clock enable overrides 9 */ + { 0x00001212, 0x0000 }, /* R4626 (0x1212) - Clock enable overrides 10 */ + { 0x00001214, 0x0000 }, /* R4628 (0x1214) - Clock enable overrides 11 */ + { 0x00001216, 0x0000 }, /* R4630 (0x1216) - Clock enable overrides 12 */ + { 0x00001300, 0x0000 }, /* R4864 (0x1300) - DAC Comp 1 */ + { 0x00001302, 0x0000 }, /* R4866 (0x1302) - DAC Comp 2 */ + { 0x00001340, 0x0000 }, /* R4928 (0x1340) - DAC comp 1L */ + { 0x00001341, 0x0000 }, /* R4929 (0x1341) - DAC comp 1R */ + { 0x00001346, 0x0000 }, /* R4929 (0x1346) - DAC comp 4L */ + { 0x00001348, 0x0000 }, /* R4936 (0x1348) - DAC comp 5L */ + { 0x00001349, 0x0000 }, /* R4937 (0x1349) - DAC comp 5R */ + { 0x00001380, 0x0000 }, /* R4992 (0x1380) - FRF Coefficient 1L 1 */ + { 0x00001381, 0x0000 }, /* R4993 (0x1381) - FRF Coefficient 1L 2 */ + { 0x00001382, 0x0000 }, /* R4994 (0x1382) - FRF Coefficient 1L 3 */ + { 0x00001383, 0x0000 }, /* R4995 (0x1383) - FRF Coefficient 1L 4 */ + { 0x00001390, 0x0000 }, /* R5008 (0x1390) - FRF Coefficient 1R 1 */ + { 0x00001391, 0x0000 }, /* R5009 (0x1391) - FRF Coefficient 1R 2 */ + { 0x00001392, 0x0000 }, /* R5010 (0x1392) - FRF Coefficient 1R 3 */ + { 0x00001393, 0x0000 }, /* R5011 (0x1393) - FRF Coefficient 1R 4 */ + { 0x000013a0, 0x0000 }, /* R5024 (0x13a0) - FRF Coefficient 4L 1 */ + { 0x000013a1, 0x0000 }, /* R5025 (0x13a1) - FRF Coefficient 4L 2 */ + { 0x000013a2, 0x0000 }, /* R5026 (0x13a2) - FRF Coefficient 4L 3 */ + { 0x000013a3, 0x0000 }, /* R5027 (0x13a3) - FRF Coefficient 4L 4 */ + { 0x000013b0, 0x0000 }, /* R5040 (0x13b0) - FRF Coefficient 5L 1 */ + { 0x000013b1, 0x0000 }, /* R5041 (0x13b1) - FRF Coefficient 5L 2 */ + { 0x000013b2, 0x0000 }, /* R5042 (0x13b2) - FRF Coefficient 5L 3 */ + { 0x000013b3, 0x0000 }, /* R5043 (0x13b3) - FRF Coefficient 5L 4 */ + { 0x000013c0, 0x0000 }, /* R5040 (0x13c0) - FRF Coefficient 5R 1 */ + { 0x000013c1, 0x0000 }, /* R5041 (0x13c1) - FRF Coefficient 5R 2 */ + { 0x000013c2, 0x0000 }, /* R5042 (0x13c2) - FRF Coefficient 5R 3 */ + { 0x000013c3, 0x0000 }, /* R5043 (0x13c3) - FRF Coefficient 5R 4 */ + { 0x00001700, 0x2001 }, /* R5888 (0x1700) - GPIO1 Control 1 */ + { 0x00001701, 0xf000 }, /* R5889 (0x1701) - GPIO1 Control 2 */ + { 0x00001702, 0x2001 }, /* R5890 (0x1702) - GPIO2 Control 1 */ + { 0x00001703, 0xf000 }, /* R5891 (0x1703) - GPIO2 Control 2 */ + { 0x00001704, 0x2001 }, /* R5892 (0x1704) - GPIO3 Control 1 */ + { 0x00001705, 0xf000 }, /* R5893 (0x1705) - GPIO3 Control 2 */ + { 0x00001706, 0x2001 }, /* R5894 (0x1706) - GPIO4 Control 1 */ + { 0x00001707, 0xf000 }, /* R5895 (0x1707) - GPIO4 Control 2 */ + { 0x00001708, 0x2001 }, /* R5896 (0x1708) - GPIO5 Control 1 */ + { 0x00001709, 0xf000 }, /* R5897 (0x1709) - GPIO5 Control 2 */ + { 0x0000170a, 0x2001 }, /* R5898 (0x170a) - GPIO6 Control 1 */ + { 0x0000170b, 0xf000 }, /* R5899 (0x170b) - GPIO6 Control 2 */ + { 0x0000170c, 0x2001 }, /* R5900 (0x170c) - GPIO7 Control 1 */ + { 0x0000170d, 0xf000 }, /* R5901 (0x170d) - GPIO7 Control 2 */ + { 0x0000170e, 0x2001 }, /* R5902 (0x170e) - GPIO8 Control 1 */ + { 0x0000170f, 0xf000 }, /* R5903 (0x170f) - GPIO8 Control 2 */ + { 0x00001710, 0x2001 }, /* R5904 (0x1710) - GPIO9 Control 1 */ + { 0x00001711, 0xf000 }, /* R5905 (0x1711) - GPIO9 Control 2 */ + { 0x00001712, 0x2001 }, /* R5906 (0x1712) - GPIO10 Control 1 */ + { 0x00001713, 0xf000 }, /* R5907 (0x1713) - GPIO10 Control 2 */ + { 0x00001714, 0x2001 }, /* R5908 (0x1714) - GPIO11 Control 1 */ + { 0x00001715, 0xf000 }, /* R5909 (0x1715) - GPIO11 Control 2 */ + { 0x00001716, 0x2001 }, /* R5910 (0x1716) - GPIO12 Control 1 */ + { 0x00001717, 0xf000 }, /* R5911 (0x1717) - GPIO12 Control 2 */ + { 0x00001718, 0x2001 }, /* R5912 (0x1718) - GPIO13 Control 1 */ + { 0x00001719, 0xf000 }, /* R5913 (0x1719) - GPIO13 Control 2 */ + { 0x0000171A, 0x2001 }, /* R5914 (0x171A) - GPIO14 Control 1 */ + { 0x0000171B, 0xf000 }, /* R5915 (0x171B) - GPIO14 Control 2 */ + { 0x0000171C, 0x2001 }, /* R5916 (0x171C) - GPIO15 Control 1 */ + { 0x0000171D, 0xf000 }, /* R5917 (0x171D) - GPIO15 Control 2 */ + { 0x0000171E, 0x2001 }, /* R5918 (0x171E) - GPIO16 Control 1 */ + { 0x0000171F, 0xf000 }, /* R5919 (0x171F) - GPIO16 Control 2 */ + { 0x00001840, 0xffff }, /* R6208 (0x1840) - IRQ1 Mask 1 */ + { 0x00001841, 0xffff }, /* R6209 (0x1841) - IRQ1 Mask 2 */ + { 0x00001842, 0xffff }, /* R6210 (0x1842) - IRQ1 Mask 3 */ + { 0x00001843, 0xffff }, /* R6211 (0x1843) - IRQ1 Mask 4 */ + { 0x00001844, 0xffff }, /* R6212 (0x1844) - IRQ1 Mask 5 */ + { 0x00001845, 0xffff }, /* R6213 (0x1845) - IRQ1 Mask 6 */ + { 0x00001846, 0xffff }, /* R6214 (0x1846) - IRQ1 Mask 7 */ + { 0x00001847, 0xffff }, /* R6215 (0x1847) - IRQ1 Mask 8 */ + { 0x00001848, 0xffff }, /* R6216 (0x1848) - IRQ1 Mask 9 */ + { 0x00001849, 0xffff }, /* R6217 (0x1849) - IRQ1 Mask 10 */ + { 0x0000184a, 0xffff }, /* R6218 (0x184a) - IRQ1 Mask 11 */ + { 0x0000184b, 0xffff }, /* R6219 (0x184b) - IRQ1 Mask 12 */ + { 0x0000184c, 0xffff }, /* R6220 (0x184c) - IRQ1 Mask 13 */ + { 0x0000184d, 0xffff }, /* R6221 (0x184d) - IRQ1 Mask 14 */ + { 0x0000184e, 0xffff }, /* R6222 (0x184e) - IRQ1 Mask 15 */ + { 0x00001948, 0xffff }, /* R6472 (0x1948) - IRQ2 Mask 9 */ + { 0x00001a80, 0x4400 }, /* R6784 (0x1a80) - IRQ1 CTRL */ +}; + +static bool marley_is_adsp_memory(struct device *dev, unsigned int reg) +{ + if ((reg >= 0x080000 && reg <= 0x085ffe) || + (reg >= 0x0a0000 && reg <= 0x0a7ffe) || + (reg >= 0x0c0000 && reg <= 0x0c1ffe) || + (reg >= 0x0e0000 && reg <= 0x0e1ffe) || + (reg >= 0x100000 && reg <= 0x10effe) || + (reg >= 0x120000 && reg <= 0x12bffe) || + (reg >= 0x136000 && reg <= 0x137ffe) || + (reg >= 0x140000 && reg <= 0x14bffe) || + (reg >= 0x160000 && reg <= 0x161ffe) || + (reg >= 0x180000 && reg <= 0x18effe) || + (reg >= 0x1a0000 && reg <= 0x1b1ffe) || + (reg >= 0x1b6000 && reg <= 0x1b7ffe) || + (reg >= 0x1c0000 && reg <= 0x1cbffe) || + (reg >= 0x1e0000 && reg <= 0x1e1ffe)) + return true; + else + return false; +} + +static bool marley_16bit_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_CTRL_IF_SPI_CFG_1: + case ARIZONA_CTRL_IF_I2C1_CFG_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_TONE_GENERATOR_1: + case ARIZONA_TONE_GENERATOR_2: + case ARIZONA_TONE_GENERATOR_3: + case ARIZONA_TONE_GENERATOR_4: + case ARIZONA_TONE_GENERATOR_5: + case ARIZONA_PWM_DRIVE_1: + case ARIZONA_PWM_DRIVE_2: + case ARIZONA_PWM_DRIVE_3: + case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: + case ARIZONA_HAPTICS_CONTROL_1: + case ARIZONA_HAPTICS_CONTROL_2: + case ARIZONA_HAPTICS_PHASE_1_INTENSITY: + case ARIZONA_HAPTICS_PHASE_1_DURATION: + case ARIZONA_HAPTICS_PHASE_2_INTENSITY: + case ARIZONA_HAPTICS_PHASE_2_DURATION: + case ARIZONA_HAPTICS_PHASE_3_INTENSITY: + case ARIZONA_HAPTICS_PHASE_3_DURATION: + case ARIZONA_HAPTICS_STATUS: + case CLEARWATER_COMFORT_NOISE_GENERATOR: + case ARIZONA_CLOCK_32K_1: + case ARIZONA_SYSTEM_CLOCK_1: + case ARIZONA_SAMPLE_RATE_1: + case ARIZONA_SAMPLE_RATE_2: + case ARIZONA_SAMPLE_RATE_3: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case CLEARWATER_DSP_CLOCK_1: + case CLEARWATER_DSP_CLOCK_2: + case ARIZONA_OUTPUT_SYSTEM_CLOCK: + case ARIZONA_OUTPUT_ASYNC_CLOCK: + case ARIZONA_RATE_ESTIMATOR_1: + case ARIZONA_RATE_ESTIMATOR_2: + case ARIZONA_RATE_ESTIMATOR_3: + case ARIZONA_RATE_ESTIMATOR_4: + case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_FLL1_CONTROL_1: + case ARIZONA_FLL1_CONTROL_2: + case ARIZONA_FLL1_CONTROL_3: + case ARIZONA_FLL1_CONTROL_4: + case ARIZONA_FLL1_CONTROL_5: + case ARIZONA_FLL1_CONTROL_6: + case ARIZONA_FLL1_CONTROL_7: + case ARIZONA_FLL1_LOOP_FILTER_TEST_1: + case ARIZONA_FLL1_NCO_TEST_0: + case MARLEY_FLL1_SYNCHRONISER_1: + case MARLEY_FLL1_SYNCHRONISER_2: + case MARLEY_FLL1_SYNCHRONISER_3: + case MARLEY_FLL1_SYNCHRONISER_4: + case MARLEY_FLL1_SYNCHRONISER_5: + case MARLEY_FLL1_SYNCHRONISER_6: + case MARLEY_FLL1_SYNCHRONISER_7: + case MARLEY_FLL1_SPREAD_SPECTRUM: + case MARLEY_FLL1_GPIO_CLOCK: + case ARIZONA_MIC_CHARGE_PUMP_1: + case CLEARWATER_CP_MODE: + case ARIZONA_LDO2_CONTROL_1: + case ARIZONA_MIC_BIAS_CTRL_1: + case ARIZONA_MIC_BIAS_CTRL_2: + case ARIZONA_MIC_BIAS_CTRL_5: + case ARIZONA_MIC_BIAS_CTRL_6: + case ARIZONA_HP_CTRL_1L: + case ARIZONA_HP_CTRL_1R: + case ARIZONA_DCS_HP1L_CONTROL: + case ARIZONA_DCS_HP1R_CONTROL: + case CLEARWATER_EDRE_HP_STEREO_CONTROL: + case ARIZONA_ACCESSORY_DETECT_MODE_1: + case ARIZONA_HEADPHONE_DETECT_1: + case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HEADPHONE_DETECT_3: + case ARIZONA_HP_DACVAL: + case CLEARWATER_MICD_CLAMP_CONTROL: + case ARIZONA_MIC_DETECT_1: + case ARIZONA_MIC_DETECT_2: + case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: + case ARIZONA_MIC_DETECT_LEVEL_1: + case ARIZONA_MIC_DETECT_LEVEL_2: + case ARIZONA_MIC_DETECT_LEVEL_3: + case ARIZONA_MIC_DETECT_LEVEL_4: + case ARIZONA_MIC_NOISE_MIX_CONTROL_1: + case CLEARWATER_GP_SWITCH_1: + case ARIZONA_JACK_DETECT_ANALOGUE: + case ARIZONA_INPUT_ENABLES: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_INPUT_RATE: + case ARIZONA_INPUT_VOLUME_RAMP: + case ARIZONA_HPF_CONTROL: + case ARIZONA_IN1L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1L: + case ARIZONA_DMIC1L_CONTROL: + case ARIZONA_IN1R_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1R: + case ARIZONA_DMIC1R_CONTROL: + case ARIZONA_IN2L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_2L: + case ARIZONA_DMIC2L_CONTROL: + case ARIZONA_IN2R_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_2R: + case ARIZONA_DMIC2R_CONTROL: + case ARIZONA_ADC_VCO_CAL_4: + case ARIZONA_ADC_VCO_CAL_5: + case ARIZONA_ADC_VCO_CAL_6: + case ARIZONA_ADC_VCO_CAL_7: + case ARIZONA_OUTPUT_ENABLES_1: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_OUTPUT_STANDBY_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_OUTPUT_RATE_1: + case ARIZONA_OUTPUT_VOLUME_RAMP: + case ARIZONA_OUTPUT_PATH_CONFIG_1L: + case ARIZONA_DAC_DIGITAL_VOLUME_1L: + case ARIZONA_DAC_VOLUME_LIMIT_1L: + case ARIZONA_NOISE_GATE_SELECT_1L: + case ARIZONA_OUTPUT_PATH_CONFIG_1R: + case ARIZONA_DAC_DIGITAL_VOLUME_1R: + case ARIZONA_DAC_VOLUME_LIMIT_1R: + case ARIZONA_NOISE_GATE_SELECT_1R: + case ARIZONA_OUTPUT_PATH_CONFIG_4L: + case ARIZONA_DAC_DIGITAL_VOLUME_4L: + case ARIZONA_OUT_VOLUME_4L: + case ARIZONA_NOISE_GATE_SELECT_4L: + case ARIZONA_OUTPUT_PATH_CONFIG_4R: + case ARIZONA_DAC_DIGITAL_VOLUME_4R: + case ARIZONA_OUT_VOLUME_4R: + case ARIZONA_NOISE_GATE_SELECT_4R: + case ARIZONA_OUTPUT_PATH_CONFIG_5L: + case ARIZONA_DAC_DIGITAL_VOLUME_5L: + case ARIZONA_DAC_VOLUME_LIMIT_5L: + case ARIZONA_NOISE_GATE_SELECT_5L: + case ARIZONA_OUTPUT_PATH_CONFIG_5R: + case ARIZONA_DAC_DIGITAL_VOLUME_5R: + case ARIZONA_DAC_VOLUME_LIMIT_5R: + case ARIZONA_NOISE_GATE_SELECT_5R: + case ARIZONA_DRE_ENABLE: + case CLEARWATER_EDRE_ENABLE: + case ARIZONA_DAC_AEC_CONTROL_1: + case ARIZONA_NOISE_GATE_CONTROL: + case ARIZONA_PDM_SPK1_CTRL_1: + case ARIZONA_PDM_SPK1_CTRL_2: + case ARIZONA_HP1_SHORT_CIRCUIT_CTRL: + case ARIZONA_HP_TEST_CTRL_5: + case ARIZONA_HP_TEST_CTRL_6: + case ARIZONA_SPK_CTRL_3: + case ARIZONA_AIF1_BCLK_CTRL: + case ARIZONA_AIF1_TX_PIN_CTRL: + case ARIZONA_AIF1_RX_PIN_CTRL: + case ARIZONA_AIF1_RATE_CTRL: + case ARIZONA_AIF1_FORMAT: + case ARIZONA_AIF1_TX_BCLK_RATE: + case ARIZONA_AIF1_RX_BCLK_RATE: + case ARIZONA_AIF1_FRAME_CTRL_1: + case ARIZONA_AIF1_FRAME_CTRL_2: + case ARIZONA_AIF1_FRAME_CTRL_3: + case ARIZONA_AIF1_FRAME_CTRL_4: + case ARIZONA_AIF1_FRAME_CTRL_5: + case ARIZONA_AIF1_FRAME_CTRL_6: + case ARIZONA_AIF1_FRAME_CTRL_7: + case ARIZONA_AIF1_FRAME_CTRL_8: + case ARIZONA_AIF1_FRAME_CTRL_11: + case ARIZONA_AIF1_FRAME_CTRL_12: + case ARIZONA_AIF1_FRAME_CTRL_13: + case ARIZONA_AIF1_FRAME_CTRL_14: + case ARIZONA_AIF1_FRAME_CTRL_15: + case ARIZONA_AIF1_FRAME_CTRL_16: + case ARIZONA_AIF1_TX_ENABLES: + case ARIZONA_AIF1_RX_ENABLES: + case ARIZONA_AIF2_BCLK_CTRL: + case ARIZONA_AIF2_TX_PIN_CTRL: + case ARIZONA_AIF2_RX_PIN_CTRL: + case ARIZONA_AIF2_RATE_CTRL: + case ARIZONA_AIF2_FORMAT: + case ARIZONA_AIF2_TX_BCLK_RATE: + case ARIZONA_AIF2_RX_BCLK_RATE: + case ARIZONA_AIF2_FRAME_CTRL_1: + case ARIZONA_AIF2_FRAME_CTRL_2: + case ARIZONA_AIF2_FRAME_CTRL_3: + case ARIZONA_AIF2_FRAME_CTRL_4: + case ARIZONA_AIF2_FRAME_CTRL_11: + case ARIZONA_AIF2_FRAME_CTRL_12: + case ARIZONA_AIF2_TX_ENABLES: + case ARIZONA_AIF2_RX_ENABLES: + case ARIZONA_AIF3_BCLK_CTRL: + case ARIZONA_AIF3_TX_PIN_CTRL: + case ARIZONA_AIF3_RX_PIN_CTRL: + case ARIZONA_AIF3_RATE_CTRL: + case ARIZONA_AIF3_FORMAT: + case ARIZONA_AIF3_TX_BCLK_RATE: + case ARIZONA_AIF3_RX_BCLK_RATE: + case ARIZONA_AIF3_FRAME_CTRL_1: + case ARIZONA_AIF3_FRAME_CTRL_2: + case ARIZONA_AIF3_FRAME_CTRL_3: + case ARIZONA_AIF3_FRAME_CTRL_4: + case ARIZONA_AIF3_FRAME_CTRL_11: + case ARIZONA_AIF3_FRAME_CTRL_12: + case ARIZONA_AIF3_TX_ENABLES: + case ARIZONA_AIF3_RX_ENABLES: + case ARIZONA_SPD1_TX_CONTROL: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_1: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_2: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_3: + case ARIZONA_SLIMBUS_FRAMER_REF_GEAR: + case ARIZONA_SLIMBUS_RATES_1: + case ARIZONA_SLIMBUS_RATES_2: + case ARIZONA_SLIMBUS_RATES_3: + case ARIZONA_SLIMBUS_RATES_5: + case ARIZONA_SLIMBUS_RATES_6: + case ARIZONA_SLIMBUS_RATES_7: + case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE: + case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE: + case ARIZONA_SLIMBUS_RX_PORT_STATUS: + case ARIZONA_SLIMBUS_TX_PORT_STATUS: + case ARIZONA_PWM1MIX_INPUT_1_SOURCE: + case ARIZONA_PWM1MIX_INPUT_1_VOLUME: + case ARIZONA_PWM1MIX_INPUT_2_SOURCE: + case ARIZONA_PWM1MIX_INPUT_2_VOLUME: + case ARIZONA_PWM1MIX_INPUT_3_SOURCE: + case ARIZONA_PWM1MIX_INPUT_3_VOLUME: + case ARIZONA_PWM1MIX_INPUT_4_SOURCE: + case ARIZONA_PWM1MIX_INPUT_4_VOLUME: + case ARIZONA_PWM2MIX_INPUT_1_SOURCE: + case ARIZONA_PWM2MIX_INPUT_1_VOLUME: + case ARIZONA_PWM2MIX_INPUT_2_SOURCE: + case ARIZONA_PWM2MIX_INPUT_2_VOLUME: + case ARIZONA_PWM2MIX_INPUT_3_SOURCE: + case ARIZONA_PWM2MIX_INPUT_3_VOLUME: + case ARIZONA_PWM2MIX_INPUT_4_SOURCE: + case ARIZONA_PWM2MIX_INPUT_4_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_4_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE: + case ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME: + case ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE: + case ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME: + case ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE: + case ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME: + case ARIZONA_EQ1MIX_INPUT_1_SOURCE: + case ARIZONA_EQ1MIX_INPUT_1_VOLUME: + case ARIZONA_EQ1MIX_INPUT_2_SOURCE: + case ARIZONA_EQ1MIX_INPUT_2_VOLUME: + case ARIZONA_EQ1MIX_INPUT_3_SOURCE: + case ARIZONA_EQ1MIX_INPUT_3_VOLUME: + case ARIZONA_EQ1MIX_INPUT_4_SOURCE: + case ARIZONA_EQ1MIX_INPUT_4_VOLUME: + case ARIZONA_EQ2MIX_INPUT_1_SOURCE: + case ARIZONA_EQ2MIX_INPUT_1_VOLUME: + case ARIZONA_EQ2MIX_INPUT_2_SOURCE: + case ARIZONA_EQ2MIX_INPUT_2_VOLUME: + case ARIZONA_EQ2MIX_INPUT_3_SOURCE: + case ARIZONA_EQ2MIX_INPUT_3_VOLUME: + case ARIZONA_EQ2MIX_INPUT_4_SOURCE: + case ARIZONA_EQ2MIX_INPUT_4_VOLUME: + case ARIZONA_EQ3MIX_INPUT_1_SOURCE: + case ARIZONA_EQ3MIX_INPUT_1_VOLUME: + case ARIZONA_EQ3MIX_INPUT_2_SOURCE: + case ARIZONA_EQ3MIX_INPUT_2_VOLUME: + case ARIZONA_EQ3MIX_INPUT_3_SOURCE: + case ARIZONA_EQ3MIX_INPUT_3_VOLUME: + case ARIZONA_EQ3MIX_INPUT_4_SOURCE: + case ARIZONA_EQ3MIX_INPUT_4_VOLUME: + case ARIZONA_EQ4MIX_INPUT_1_SOURCE: + case ARIZONA_EQ4MIX_INPUT_1_VOLUME: + case ARIZONA_EQ4MIX_INPUT_2_SOURCE: + case ARIZONA_EQ4MIX_INPUT_2_VOLUME: + case ARIZONA_EQ4MIX_INPUT_3_SOURCE: + case ARIZONA_EQ4MIX_INPUT_3_VOLUME: + case ARIZONA_EQ4MIX_INPUT_4_SOURCE: + case ARIZONA_EQ4MIX_INPUT_4_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_1_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_2_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_2_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_3_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_3_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_4_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_4_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_1_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_2_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_2_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_3_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_3_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_4_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_4_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_1_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_1_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_2_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_2_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_3_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_3_VOLUME: + case ARIZONA_DRC2LMIX_INPUT_4_SOURCE: + case ARIZONA_DRC2LMIX_INPUT_4_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_1_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_1_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_2_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_2_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_3_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_3_VOLUME: + case ARIZONA_DRC2RMIX_INPUT_4_SOURCE: + case ARIZONA_DRC2RMIX_INPUT_4_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_4_VOLUME: + case ARIZONA_DSP1LMIX_INPUT_1_SOURCE: + case ARIZONA_DSP1LMIX_INPUT_1_VOLUME: + case ARIZONA_DSP1LMIX_INPUT_2_SOURCE: + case ARIZONA_DSP1LMIX_INPUT_2_VOLUME: + case ARIZONA_DSP1LMIX_INPUT_3_SOURCE: + case ARIZONA_DSP1LMIX_INPUT_3_VOLUME: + case ARIZONA_DSP1LMIX_INPUT_4_SOURCE: + case ARIZONA_DSP1LMIX_INPUT_4_VOLUME: + case ARIZONA_DSP1RMIX_INPUT_1_SOURCE: + case ARIZONA_DSP1RMIX_INPUT_1_VOLUME: + case ARIZONA_DSP1RMIX_INPUT_2_SOURCE: + case ARIZONA_DSP1RMIX_INPUT_2_VOLUME: + case ARIZONA_DSP1RMIX_INPUT_3_SOURCE: + case ARIZONA_DSP1RMIX_INPUT_3_VOLUME: + case ARIZONA_DSP1RMIX_INPUT_4_SOURCE: + case ARIZONA_DSP1RMIX_INPUT_4_VOLUME: + case ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE: + case ARIZONA_DSP1AUX2MIX_INPUT_1_SOURCE: + case ARIZONA_DSP1AUX3MIX_INPUT_1_SOURCE: + case ARIZONA_DSP1AUX4MIX_INPUT_1_SOURCE: + case ARIZONA_DSP1AUX5MIX_INPUT_1_SOURCE: + case ARIZONA_DSP1AUX6MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_1_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_1_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_2_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_2_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_3_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_3_VOLUME: + case ARIZONA_DSP2LMIX_INPUT_4_SOURCE: + case ARIZONA_DSP2LMIX_INPUT_4_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_1_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_1_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_2_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_2_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_3_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_3_VOLUME: + case ARIZONA_DSP2RMIX_INPUT_4_SOURCE: + case ARIZONA_DSP2RMIX_INPUT_4_VOLUME: + case ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX2MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX3MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX4MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX5MIX_INPUT_1_SOURCE: + case ARIZONA_DSP2AUX6MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_1_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_1_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_2_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_2_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_3_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_3_VOLUME: + case ARIZONA_DSP3LMIX_INPUT_4_SOURCE: + case ARIZONA_DSP3LMIX_INPUT_4_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_1_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_1_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_2_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_2_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_3_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_3_VOLUME: + case ARIZONA_DSP3RMIX_INPUT_4_SOURCE: + case ARIZONA_DSP3RMIX_INPUT_4_VOLUME: + case ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX2MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX3MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX4MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX5MIX_INPUT_1_SOURCE: + case ARIZONA_DSP3AUX6MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE: + case ARIZONA_FX_CTRL1: + case ARIZONA_FX_CTRL2: + case ARIZONA_EQ1_1: + case ARIZONA_EQ1_2: + case ARIZONA_EQ1_3: + case ARIZONA_EQ1_4: + case ARIZONA_EQ1_5: + case ARIZONA_EQ1_6: + case ARIZONA_EQ1_7: + case ARIZONA_EQ1_8: + case ARIZONA_EQ1_9: + case ARIZONA_EQ1_10: + case ARIZONA_EQ1_11: + case ARIZONA_EQ1_12: + case ARIZONA_EQ1_13: + case ARIZONA_EQ1_14: + case ARIZONA_EQ1_15: + case ARIZONA_EQ1_16: + case ARIZONA_EQ1_17: + case ARIZONA_EQ1_18: + case ARIZONA_EQ1_19: + case ARIZONA_EQ1_20: + case ARIZONA_EQ1_21: + case ARIZONA_EQ2_1: + case ARIZONA_EQ2_2: + case ARIZONA_EQ2_3: + case ARIZONA_EQ2_4: + case ARIZONA_EQ2_5: + case ARIZONA_EQ2_6: + case ARIZONA_EQ2_7: + case ARIZONA_EQ2_8: + case ARIZONA_EQ2_9: + case ARIZONA_EQ2_10: + case ARIZONA_EQ2_11: + case ARIZONA_EQ2_12: + case ARIZONA_EQ2_13: + case ARIZONA_EQ2_14: + case ARIZONA_EQ2_15: + case ARIZONA_EQ2_16: + case ARIZONA_EQ2_17: + case ARIZONA_EQ2_18: + case ARIZONA_EQ2_19: + case ARIZONA_EQ2_20: + case ARIZONA_EQ2_21: + case ARIZONA_EQ3_1: + case ARIZONA_EQ3_2: + case ARIZONA_EQ3_3: + case ARIZONA_EQ3_4: + case ARIZONA_EQ3_5: + case ARIZONA_EQ3_6: + case ARIZONA_EQ3_7: + case ARIZONA_EQ3_8: + case ARIZONA_EQ3_9: + case ARIZONA_EQ3_10: + case ARIZONA_EQ3_11: + case ARIZONA_EQ3_12: + case ARIZONA_EQ3_13: + case ARIZONA_EQ3_14: + case ARIZONA_EQ3_15: + case ARIZONA_EQ3_16: + case ARIZONA_EQ3_17: + case ARIZONA_EQ3_18: + case ARIZONA_EQ3_19: + case ARIZONA_EQ3_20: + case ARIZONA_EQ3_21: + case ARIZONA_EQ4_1: + case ARIZONA_EQ4_2: + case ARIZONA_EQ4_3: + case ARIZONA_EQ4_4: + case ARIZONA_EQ4_5: + case ARIZONA_EQ4_6: + case ARIZONA_EQ4_7: + case ARIZONA_EQ4_8: + case ARIZONA_EQ4_9: + case ARIZONA_EQ4_10: + case ARIZONA_EQ4_11: + case ARIZONA_EQ4_12: + case ARIZONA_EQ4_13: + case ARIZONA_EQ4_14: + case ARIZONA_EQ4_15: + case ARIZONA_EQ4_16: + case ARIZONA_EQ4_17: + case ARIZONA_EQ4_18: + case ARIZONA_EQ4_19: + case ARIZONA_EQ4_20: + case ARIZONA_EQ4_21: + case ARIZONA_DRC1_CTRL1: + case ARIZONA_DRC1_CTRL2: + case ARIZONA_DRC1_CTRL3: + case ARIZONA_DRC1_CTRL4: + case ARIZONA_DRC1_CTRL5: + case CLEARWATER_DRC2_CTRL1: + case CLEARWATER_DRC2_CTRL2: + case CLEARWATER_DRC2_CTRL3: + case CLEARWATER_DRC2_CTRL4: + case CLEARWATER_DRC2_CTRL5: + case ARIZONA_HPLPF1_1: + case ARIZONA_HPLPF1_2: + case ARIZONA_HPLPF2_1: + case ARIZONA_HPLPF2_2: + case ARIZONA_HPLPF3_1: + case ARIZONA_HPLPF3_2: + case ARIZONA_HPLPF4_1: + case ARIZONA_HPLPF4_2: + case ARIZONA_ISRC_1_CTRL_1: + case ARIZONA_ISRC_1_CTRL_2: + case ARIZONA_ISRC_1_CTRL_3: + case ARIZONA_ISRC_2_CTRL_1: + case ARIZONA_ISRC_2_CTRL_2: + case ARIZONA_ISRC_2_CTRL_3: + case CLEARWATER_DAC_COMP_1: + case CLEARWATER_DAC_COMP_2: + case CLEARWATER_FRF_COEFFICIENT_1L_1: + case CLEARWATER_FRF_COEFFICIENT_1L_2: + case CLEARWATER_FRF_COEFFICIENT_1L_3: + case CLEARWATER_FRF_COEFFICIENT_1L_4: + case CLEARWATER_FRF_COEFFICIENT_1R_1: + case CLEARWATER_FRF_COEFFICIENT_1R_2: + case CLEARWATER_FRF_COEFFICIENT_1R_3: + case CLEARWATER_FRF_COEFFICIENT_1R_4: + case MARLEY_FRF_COEFFICIENT_4L_1: + case MARLEY_FRF_COEFFICIENT_4L_2: + case MARLEY_FRF_COEFFICIENT_4L_3: + case MARLEY_FRF_COEFFICIENT_4L_4: + case MARLEY_FRF_COEFFICIENT_5L_1: + case MARLEY_FRF_COEFFICIENT_5L_2: + case MARLEY_FRF_COEFFICIENT_5L_3: + case MARLEY_FRF_COEFFICIENT_5L_4: + case MARLEY_FRF_COEFFICIENT_5R_1: + case MARLEY_FRF_COEFFICIENT_5R_2: + case MARLEY_FRF_COEFFICIENT_5R_3: + case MARLEY_FRF_COEFFICIENT_5R_4: + case CLEARWATER_GPIO1_CTRL_1: + case CLEARWATER_GPIO1_CTRL_2: + case CLEARWATER_GPIO2_CTRL_1: + case CLEARWATER_GPIO2_CTRL_2: + case CLEARWATER_GPIO3_CTRL_1: + case CLEARWATER_GPIO3_CTRL_2: + case CLEARWATER_GPIO4_CTRL_1: + case CLEARWATER_GPIO4_CTRL_2: + case CLEARWATER_GPIO5_CTRL_1: + case CLEARWATER_GPIO5_CTRL_2: + case CLEARWATER_GPIO6_CTRL_1: + case CLEARWATER_GPIO6_CTRL_2: + case CLEARWATER_GPIO7_CTRL_1: + case CLEARWATER_GPIO7_CTRL_2: + case CLEARWATER_GPIO8_CTRL_1: + case CLEARWATER_GPIO8_CTRL_2: + case CLEARWATER_GPIO9_CTRL_1: + case CLEARWATER_GPIO9_CTRL_2: + case CLEARWATER_GPIO10_CTRL_1: + case CLEARWATER_GPIO10_CTRL_2: + case CLEARWATER_GPIO11_CTRL_1: + case CLEARWATER_GPIO11_CTRL_2: + case CLEARWATER_GPIO12_CTRL_1: + case CLEARWATER_GPIO12_CTRL_2: + case CLEARWATER_GPIO13_CTRL_1: + case CLEARWATER_GPIO13_CTRL_2: + case CLEARWATER_GPIO14_CTRL_1: + case CLEARWATER_GPIO14_CTRL_2: + case CLEARWATER_GPIO15_CTRL_1: + case CLEARWATER_GPIO15_CTRL_2: + case CLEARWATER_GPIO16_CTRL_1: + case CLEARWATER_GPIO16_CTRL_2: + case CLEARWATER_IRQ1_STATUS_1: + case CLEARWATER_IRQ1_STATUS_2: + case CLEARWATER_IRQ1_STATUS_6: + case CLEARWATER_IRQ1_STATUS_7: + case CLEARWATER_IRQ1_STATUS_9: + case CLEARWATER_IRQ1_STATUS_11: + case CLEARWATER_IRQ1_STATUS_12: + case CLEARWATER_IRQ1_STATUS_13: + case CLEARWATER_IRQ1_STATUS_14: + case CLEARWATER_IRQ1_STATUS_15: + case CLEARWATER_IRQ1_STATUS_17: + case CLEARWATER_IRQ1_STATUS_21: + case CLEARWATER_IRQ1_STATUS_22: + case CLEARWATER_IRQ1_STATUS_23: + case CLEARWATER_IRQ1_STATUS_24: + case CLEARWATER_IRQ1_STATUS_25: + case CLEARWATER_IRQ1_STATUS_27: + case CLEARWATER_IRQ1_STATUS_28: + case CLEARWATER_IRQ1_STATUS_30: + case CLEARWATER_IRQ1_STATUS_31: + case CLEARWATER_IRQ1_STATUS_32: + case CLEARWATER_IRQ1_MASK_1: + case CLEARWATER_IRQ1_MASK_2: + case CLEARWATER_IRQ1_MASK_6: + case CLEARWATER_IRQ1_MASK_7: + case CLEARWATER_IRQ1_MASK_9: + case CLEARWATER_IRQ1_MASK_10: + case CLEARWATER_IRQ1_MASK_11: + case CLEARWATER_IRQ1_MASK_12: + case CLEARWATER_IRQ1_MASK_13: + case CLEARWATER_IRQ1_MASK_14: + case CLEARWATER_IRQ1_MASK_15: + case CLEARWATER_IRQ1_MASK_17: + case CLEARWATER_IRQ1_MASK_21: + case CLEARWATER_IRQ1_MASK_22: + case CLEARWATER_IRQ1_MASK_23: + case CLEARWATER_IRQ1_MASK_24: + case CLEARWATER_IRQ1_MASK_25: + case CLEARWATER_IRQ1_MASK_27: + case CLEARWATER_IRQ1_MASK_28: + case CLEARWATER_IRQ1_MASK_30: + case CLEARWATER_IRQ1_MASK_31: + case CLEARWATER_IRQ1_MASK_32: + case CLEARWATER_IRQ1_RAW_STATUS_1: + case CLEARWATER_IRQ1_RAW_STATUS_2: + case CLEARWATER_IRQ1_RAW_STATUS_7: + case CLEARWATER_IRQ1_RAW_STATUS_9: + case CLEARWATER_IRQ1_RAW_STATUS_12: + case CLEARWATER_IRQ1_RAW_STATUS_13: + case CLEARWATER_IRQ1_RAW_STATUS_14: + case CLEARWATER_IRQ1_RAW_STATUS_15: + case CLEARWATER_IRQ1_RAW_STATUS_17: + case CLEARWATER_IRQ1_RAW_STATUS_21: + case CLEARWATER_IRQ1_RAW_STATUS_22: + case CLEARWATER_IRQ1_RAW_STATUS_23: + case CLEARWATER_IRQ1_RAW_STATUS_24: + case CLEARWATER_IRQ1_RAW_STATUS_25: + case CLEARWATER_IRQ1_RAW_STATUS_30: + case CLEARWATER_IRQ1_RAW_STATUS_31: + case CLEARWATER_IRQ1_RAW_STATUS_32: + case CLEARWATER_IRQ2_STATUS_9: + case CLEARWATER_IRQ2_MASK_9: + case CLEARWATER_IRQ2_RAW_STATUS_9: + case CLEARWATER_IRQ1_CTRL: + return true; + default: + return false; + } +} + +static bool marley_16bit_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_HAPTICS_STATUS: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case ARIZONA_HP_CTRL_1L: + case ARIZONA_HP_CTRL_1R: + case ARIZONA_DCS_HP1L_CONTROL: + case ARIZONA_DCS_HP1R_CONTROL: + case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: + case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_HEADPHONE_DETECT_3: + case ARIZONA_HP_DACVAL: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_ADC_VCO_CAL_4: + case ARIZONA_ADC_VCO_CAL_5: + case ARIZONA_ADC_VCO_CAL_6: + case ARIZONA_ADC_VCO_CAL_7: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_1: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_2: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_3: + case ARIZONA_SLIMBUS_RX_PORT_STATUS: + case ARIZONA_SLIMBUS_TX_PORT_STATUS: + case ARIZONA_FX_CTRL2: + case CLEARWATER_IRQ1_STATUS_1: + case CLEARWATER_IRQ1_STATUS_2: + case CLEARWATER_IRQ1_STATUS_6: + case CLEARWATER_IRQ1_STATUS_7: + case CLEARWATER_IRQ1_STATUS_9: + case CLEARWATER_IRQ1_STATUS_11: + case CLEARWATER_IRQ1_STATUS_12: + case CLEARWATER_IRQ1_STATUS_13: + case CLEARWATER_IRQ1_STATUS_14: + case CLEARWATER_IRQ1_STATUS_15: + case CLEARWATER_IRQ1_STATUS_17: + case CLEARWATER_IRQ1_STATUS_21: + case CLEARWATER_IRQ1_STATUS_22: + case CLEARWATER_IRQ1_STATUS_23: + case CLEARWATER_IRQ1_STATUS_24: + case CLEARWATER_IRQ1_STATUS_25: + case CLEARWATER_IRQ1_STATUS_27: + case CLEARWATER_IRQ1_STATUS_28: + case CLEARWATER_IRQ1_STATUS_30: + case CLEARWATER_IRQ1_STATUS_31: + case CLEARWATER_IRQ1_STATUS_32: + case CLEARWATER_IRQ1_RAW_STATUS_1: + case CLEARWATER_IRQ1_RAW_STATUS_2: + case CLEARWATER_IRQ1_RAW_STATUS_7: + case CLEARWATER_IRQ1_RAW_STATUS_9: + case CLEARWATER_IRQ1_RAW_STATUS_12: + case CLEARWATER_IRQ1_RAW_STATUS_13: + case CLEARWATER_IRQ1_RAW_STATUS_14: + case CLEARWATER_IRQ1_RAW_STATUS_15: + case CLEARWATER_IRQ1_RAW_STATUS_17: + case CLEARWATER_IRQ1_RAW_STATUS_21: + case CLEARWATER_IRQ1_RAW_STATUS_22: + case CLEARWATER_IRQ1_RAW_STATUS_23: + case CLEARWATER_IRQ1_RAW_STATUS_24: + case CLEARWATER_IRQ1_RAW_STATUS_25: + case CLEARWATER_IRQ1_RAW_STATUS_30: + case CLEARWATER_IRQ1_RAW_STATUS_31: + case CLEARWATER_IRQ1_RAW_STATUS_32: + case CLEARWATER_IRQ2_STATUS_9: + case CLEARWATER_IRQ2_RAW_STATUS_9: + return true; + default: + return false; + } +} + +static bool marley_32bit_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_WSEQ_SEQUENCE_1 ... ARIZONA_WSEQ_SEQUENCE_252: + case MARLEY_OTP_HPDET_CALIB_1 ... MARLEY_OTP_HPDET_CALIB_2: + case CLEARWATER_DSP1_CONFIG ... CLEARWATER_DSP1_SCRATCH_3: + case CLEARWATER_DSP2_CONFIG ... CLEARWATER_DSP2_SCRATCH_3: + case CLEARWATER_DSP3_CONFIG ... CLEARWATER_DSP3_SCRATCH_3: + return true; + default: + return marley_is_adsp_memory(dev, reg); + } +} + +static bool marley_32bit_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_WSEQ_SEQUENCE_1 ... ARIZONA_WSEQ_SEQUENCE_252: + case MARLEY_OTP_HPDET_CALIB_1 ... MARLEY_OTP_HPDET_CALIB_2: + case CLEARWATER_DSP1_CONFIG ... CLEARWATER_DSP1_SCRATCH_3: + case CLEARWATER_DSP2_CONFIG ... CLEARWATER_DSP2_SCRATCH_3: + case CLEARWATER_DSP3_CONFIG ... CLEARWATER_DSP3_SCRATCH_3: + return true; + default: + return marley_is_adsp_memory(dev, reg); + } +} + +const struct regmap_config marley_16bit_spi_regmap = { + .name = "marley_16bit", + .reg_bits = 32, + .pad_bits = 16, + .val_bits = 16, + + .max_register = 0x1b00, + .readable_reg = marley_16bit_readable_register, + .volatile_reg = marley_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = marley_reg_default, + .num_reg_defaults = ARRAY_SIZE(marley_reg_default), +}; +EXPORT_SYMBOL_GPL(marley_16bit_spi_regmap); + +const struct regmap_config marley_16bit_i2c_regmap = { + .name = "marley_16bit", + .reg_bits = 32, + .val_bits = 16, + + .max_register = 0x1b00, + .readable_reg = marley_16bit_readable_register, + .volatile_reg = marley_16bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = marley_reg_default, + .num_reg_defaults = ARRAY_SIZE(marley_reg_default), +}; +EXPORT_SYMBOL_GPL(marley_16bit_i2c_regmap); + +const struct regmap_config marley_32bit_spi_regmap = { + .name = "marley_32bit", + .reg_bits = 32, + .reg_stride = 2, + .pad_bits = 16, + .val_bits = 32, + + .max_register = CLEARWATER_DSP3_SCRATCH_3, + .readable_reg = marley_32bit_readable_register, + .volatile_reg = marley_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(marley_32bit_spi_regmap); + +const struct regmap_config marley_32bit_i2c_regmap = { + .name = "marley_32bit", + .reg_bits = 32, + .reg_stride = 2, + .val_bits = 32, + + .max_register = CLEARWATER_DSP3_SCRATCH_3, + .readable_reg = marley_32bit_readable_register, + .volatile_reg = marley_32bit_volatile_register, + + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(marley_32bit_i2c_regmap); diff --git a/drivers/mfd/max77833-irq.c b/drivers/mfd/max77833-irq.c index 76049a9d6f3d..ba67608543f1 100644 --- a/drivers/mfd/max77833-irq.c +++ b/drivers/mfd/max77833-irq.c @@ -64,10 +64,13 @@ struct max77833_irq_data { #define DECLARE_IRQ(idx, _group, _mask) \ [(idx)] = { .group = (_group), .mask = (_mask) } static const struct max77833_irq_data max77833_irqs[] = { + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_T100C_INT, TOP_INT, 1 << 0), + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_T120C_INT, TOP_INT, 1 << 1), + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_T140C_INT, TOP_INT, 1 << 2), + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_I2C_WD_INT, TOP_INT, 1 << 3), DECLARE_IRQ(MAX77833_SYSTEM_IRQ_SYSUVLO_INT, TOP_INT, 1 << 4), - DECLARE_IRQ(MAX77833_SYSTEM_IRQ_SYSOVLO_INT, TOP_INT, 1 << 5), - DECLARE_IRQ(MAX77833_SYSTEM_IRQ_TSHDN_INT, TOP_INT, 1 << 6), - DECLARE_IRQ(MAX77833_SYSTEM_IRQ_TM_INT, TOP_INT, 1 << 7), + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_MRSTB_INT, TOP_INT, 1 << 5), + DECLARE_IRQ(MAX77833_SYSTEM_IRQ_TS_INT, TOP_INT, 1 << 7), DECLARE_IRQ(MAX77833_CHG_IRQ_BYP_I, CHG_INT, 1 << 0), DECLARE_IRQ(MAX77833_CHG_IRQ_BATP_I, CHG_INT, 1 << 2), @@ -75,18 +78,18 @@ static const struct max77833_irq_data max77833_irqs[] = { DECLARE_IRQ(MAX77833_CHG_IRQ_CHG_I, CHG_INT, 1 << 4), DECLARE_IRQ(MAX77833_CHG_IRQ_WCIN_I, CHG_INT, 1 << 5), DECLARE_IRQ(MAX77833_CHG_IRQ_CHGIN_I, CHG_INT, 1 << 6), + DECLARE_IRQ(MAX77833_CHG_IRQ_AICL_I, CHG_INT, 1 << 7), // DECLARE_IRQ(MAX77833_FG_IRQ_ALERT, FUEL_INT, 1 << 4), DECLARE_IRQ(MAX77833_MUIC_IRQ_INT1_RESERVED, MUIC_INT1, 0 << 0), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT2_RESERVED, MUIC_INT2, 0 << 0), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_IDRESINT, MUIC_INT3, 1 << 0), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_CHGTYPINT, MUIC_INT3, 1 << 1), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_CHGTYPRUNINT,MUIC_INT3, 1 << 2), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_UICSYSMSGINT,MUIC_INT3, 1 << 6), - DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_APCMDRESPINT,MUIC_INT3, 1 << 7), + DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_IDRES_INT, MUIC_INT3, 1 << 0), + DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_CHGTYP_INT, MUIC_INT3, 1 << 1), + DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_CHGTYP_RUN_INT, MUIC_INT3, 1 << 2), + DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_SYSMSG_INT, MUIC_INT3, 1 << 6), + DECLARE_IRQ(MAX77833_MUIC_IRQ_INT3_APCMD_RESP_INT, MUIC_INT3, 1 << 7), }; static void max77833_irq_lock(struct irq_data *data) diff --git a/drivers/mfd/max77833.c b/drivers/mfd/max77833.c index fa8122128bc3..245970abbbcb 100644 --- a/drivers/mfd/max77833.c +++ b/drivers/mfd/max77833.c @@ -33,7 +33,6 @@ #include #include -#include #include #if defined (CONFIG_OF) @@ -69,11 +68,20 @@ static struct mfd_cell max77833_devs[] = { #endif }; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) +extern int p9220_otp_update; +#endif int max77833_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) { struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_read_byte_data(i2c, reg); mutex_unlock(&max77833->i2c_lock); @@ -93,6 +101,12 @@ int max77833_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); mutex_unlock(&max77833->i2c_lock); @@ -108,6 +122,12 @@ int max77833_read_word(struct i2c_client *i2c, u8 reg) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_read_word_data(i2c, reg); mutex_unlock(&max77833->i2c_lock); @@ -123,6 +143,12 @@ int max77833_write_reg(struct i2c_client *i2c, u8 reg, u8 value) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_write_byte_data(i2c, reg, value); mutex_unlock(&max77833->i2c_lock); @@ -139,6 +165,12 @@ int max77833_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); mutex_unlock(&max77833->i2c_lock); @@ -154,6 +186,12 @@ int max77833_write_word(struct i2c_client *i2c, u8 reg, u16 value) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_write_word_data(i2c, reg, value); mutex_unlock(&max77833->i2c_lock); @@ -168,6 +206,12 @@ int max77833_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) struct max77833_dev *max77833 = i2c_get_clientdata(i2c); int ret; +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif mutex_lock(&max77833->i2c_lock); ret = i2c_smbus_read_byte_data(i2c, reg); if (ret >= 0) { @@ -225,6 +269,12 @@ int max77833_write_fg(struct i2c_client *i2c, u16 reg, u16 val) return -ENODEV; } +#if defined(CONFIG_WIRELESS_FIRMWARE_UPDATE) + if(p9220_otp_update) { + pr_info("%s:%s i2c fail dueto opt update\n", MFD_DEV_NAME, __func__); + return -1; + } +#endif msg->addr = i2c->addr; msg->flags = 0; msg->len = 4; @@ -457,7 +507,6 @@ u8 max77833_dumpaddr_pmic[] = { MAX77833_PMIC_REG_MAINCTRL1, MAX77833_PMIC_REG_MCONFIG, }; -*/ u8 max77833_dumpaddr_muic[] = { MAX77833_MUIC_REG_INTMASK1, @@ -470,7 +519,6 @@ u8 max77833_dumpaddr_muic[] = { MAX77833_MUIC_REG_CTRL3, }; -/* u8 max77833_dumpaddr_haptic[] = { MAX77833_HAPTIC_REG_CONFIG1, MAX77833_HAPTIC_REG_CONFIG2, @@ -509,11 +557,11 @@ static int max77833_freeze(struct device *dev) for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_pmic); i++) max77833_read_reg(i2c, max77833_dumpaddr_pmic[i], &max77833->reg_pmic_dump[i]); - +#if 0 for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_muic); i++) max77833_read_reg(i2c, max77833_dumpaddr_muic[i], &max77833->reg_muic_dump[i]); - +#endif for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_led); i++) max77833_read_reg(i2c, max77833_dumpaddr_led[i], &max77833->reg_led_dump[i]); @@ -534,11 +582,11 @@ static int max77833_restore(struct device *dev) for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_pmic); i++) max77833_write_reg(i2c, max77833_dumpaddr_pmic[i], max77833->reg_pmic_dump[i]); - +#if 0 for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_muic); i++) max77833_write_reg(i2c, max77833_dumpaddr_muic[i], max77833->reg_muic_dump[i]); - +#endif for (i = 0; i < ARRAY_SIZE(max77833_dumpaddr_led); i++) max77833_write_reg(i2c, max77833_dumpaddr_led[i], max77833->reg_led_dump[i]); diff --git a/drivers/mfd/vegas-tables.c b/drivers/mfd/vegas-tables.c new file mode 100644 index 000000000000..577a757b45a1 --- /dev/null +++ b/drivers/mfd/vegas-tables.c @@ -0,0 +1,1588 @@ +/* + * vegas-tables.c -- data tables for vegas-class codecs + * + * Copyright 2014-2015 Cirrus Logic + * + * Author: Richard Fitzgerald + * + * 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. + */ + +#include + +#include +#include +#include + +#include "arizona.h" + +#define VEGAS_NUM_AOD_ISR 2 +#define VEGAS_NUM_ISR 5 + +static const struct reg_default vegas_rev_a_patch[] = { + { 0x0212, 0x0000 }, + { 0x0211, 0x0014 }, + { 0x04E4, 0x0E0D }, + { 0x04E5, 0x0E0D }, + { 0x04E6, 0x0E0D }, + { 0x04EB, 0x060E }, + { 0x0441, 0xC759 }, + { 0x0442, 0x2A08 }, + { 0x0443, 0x5CFA }, + { 0x026E, 0x0064 }, + { 0x026F, 0x00EA }, + { 0x0270, 0x1F16 }, + { 0x0410, 0x2080 }, + { 0x0418, 0x2080 }, + { 0x0420, 0x2080 }, + { 0x04B8, 0x1120 }, + { 0x047E, 0x080E }, + { 0x0448, 0x03EF }, +}; + +/* We use a function so we can use ARRAY_SIZE() */ +int vegas_patch(struct arizona *arizona) +{ + return regmap_register_patch(arizona->regmap, + vegas_rev_a_patch, + ARRAY_SIZE(vegas_rev_a_patch)); +} +EXPORT_SYMBOL_GPL(vegas_patch); + +static const struct regmap_irq vegas_aod_irqs[ARIZONA_NUM_IRQ] = { + [ARIZONA_IRQ_MICD_CLAMP_FALL] = { + .mask = ARIZONA_MICD_CLAMP_FALL_EINT1 + }, + [ARIZONA_IRQ_MICD_CLAMP_RISE] = { + .mask = ARIZONA_MICD_CLAMP_RISE_EINT1 + }, + [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 }, + [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 }, + [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 }, + [ARIZONA_IRQ_JD_RISE] = { .mask = ARIZONA_JD1_RISE_EINT1 }, +}; + +struct regmap_irq_chip vegas_aod = { + .name = "vegas AOD", + .status_base = ARIZONA_AOD_IRQ1, + .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1, + .ack_base = ARIZONA_AOD_IRQ1, + .num_regs = 1, + .irqs = vegas_aod_irqs, + .num_irqs = ARRAY_SIZE(vegas_aod_irqs), +}; +EXPORT_SYMBOL_GPL(vegas_aod); + +static const struct regmap_irq vegas_irqs[ARIZONA_NUM_IRQ] = { + [ARIZONA_IRQ_GP4] = { .reg_offset = 0, .mask = ARIZONA_GP4_EINT1 }, + [ARIZONA_IRQ_GP3] = { .reg_offset = 0, .mask = ARIZONA_GP3_EINT1 }, + [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 }, + [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 }, + + [ARIZONA_IRQ_SPK_OVERHEAT_WARN] = { + .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_WARN_EINT1 + }, + [ARIZONA_IRQ_SPK_OVERHEAT] = { + .reg_offset = 2, .mask = ARIZONA_SPK_OVERHEAT_EINT1 + }, + [ARIZONA_IRQ_HPDET] = { + .reg_offset = 2, .mask = ARIZONA_HPDET_EINT1 + }, + [ARIZONA_IRQ_MICDET] = { + .reg_offset = 2, .mask = ARIZONA_MICDET_EINT1 + }, + [ARIZONA_IRQ_WSEQ_DONE] = { + .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1 + }, + [ARIZONA_IRQ_DRC1_SIG_DET] = { + .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1 + }, + [ARIZONA_IRQ_ASRC2_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_ASRC2_LOCK_EINT1 + }, + [ARIZONA_IRQ_ASRC1_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_ASRC1_LOCK_EINT1 + }, + [ARIZONA_IRQ_UNDERCLOCKED] = { + .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1 + }, + [ARIZONA_IRQ_OVERCLOCKED] = { + .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1 + }, + [ARIZONA_IRQ_FLL2_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1 + }, + [ARIZONA_IRQ_FLL1_LOCK] = { + .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1 + }, + [ARIZONA_IRQ_CLKGEN_ERR] = { + .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1 + }, + [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = { + .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1 + }, + + [ARIZONA_IRQ_ASRC_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_ASRC_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_AIF3_ERR] = { + .reg_offset = 3, .mask = ARIZONA_AIF3_ERR_EINT1 + }, + [ARIZONA_IRQ_AIF2_ERR] = { + .reg_offset = 3, .mask = ARIZONA_AIF2_ERR_EINT1 + }, + [ARIZONA_IRQ_AIF1_ERR] = { + .reg_offset = 3, .mask = ARIZONA_AIF1_ERR_EINT1 + }, + [ARIZONA_IRQ_CTRLIF_ERR] = { + .reg_offset = 3, .mask = ARIZONA_CTRLIF_ERR_EINT1 + }, + [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = { + .reg_offset = 3, .mask = ARIZONA_MIXER_DROPPED_SAMPLE_EINT1 + }, + [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = { + .reg_offset = 3, .mask = ARIZONA_ASYNC_CLK_ENA_LOW_EINT1 + }, + [ARIZONA_IRQ_SYSCLK_ENA_LOW] = { + .reg_offset = 3, .mask = ARIZONA_SYSCLK_ENA_LOW_EINT1 + }, + [ARIZONA_IRQ_ISRC1_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_ISRC1_CFG_ERR_EINT1 + }, + [ARIZONA_IRQ_ISRC2_CFG_ERR] = { + .reg_offset = 3, .mask = ARIZONA_ISRC2_CFG_ERR_EINT1 + }, + + [ARIZONA_IRQ_BOOT_DONE] = { + .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1 + }, + [ARIZONA_IRQ_FLL2_CLOCK_OK] = { + .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1 + }, + [ARIZONA_IRQ_FLL1_CLOCK_OK] = { + .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1 + }, +}; + +struct regmap_irq_chip vegas_irq = { + .name = "vegas IRQ", + .status_base = ARIZONA_INTERRUPT_STATUS_1, + .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK, + .ack_base = ARIZONA_INTERRUPT_STATUS_1, + .num_regs = 5, + .irqs = vegas_irqs, + .num_irqs = ARRAY_SIZE(vegas_irqs), +}; +EXPORT_SYMBOL_GPL(vegas_irq); + +static const struct reg_default vegas_reg_default[] = { + { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */ + { 0x0000000B, 0x001A }, /* R11 - Ctrl IF I2C1 CFG 2 */ + { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ + { 0x00000040, 0x0000 }, /* R64 - Wake control */ + { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ + { 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */ + { 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */ + { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ + { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ + { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ + { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ + { 0x0000006E, 0x01FF }, /* R110 - Trigger Sequence Select 32 */ + { 0x0000006F, 0x01FF }, /* R111 - Trigger Sequence Select 33 */ + { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ + { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */ + { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */ + { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */ + { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */ + { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */ + { 0x00000149, 0x0000 }, /* R329 - Output system clock */ + { 0x0000014A, 0x0000 }, /* R330 - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ + { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ + { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */ + { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ + { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ + { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ + { 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */ + { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */ + { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ + { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ + { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ + { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ + { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ + { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */ + { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ + { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ + { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ + { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */ + { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */ + { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */ + { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */ + { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ + { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ + { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */ + { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ + { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ + { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ + { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ + { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ + { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */ + { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ + { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ + { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ + { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ + { 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */ + { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ + { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ + { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ + { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */ + { 0x00000293, 0x0080 }, /* R659 - Accessory Detect Mode 1 */ + { 0x0000029B, 0x0000 }, /* R667 - Headphone Detect 1 */ + { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */ + { 0x000002A2, 0x0000 }, /* R674 - Micd Clamp control */ + { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ + { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ + { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */ + { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */ + { 0x000002A7, 0x2C37 }, /* R679 - Mic Detect Level 2 */ + { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ + { 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */ + { 0x000002AB, 0x0000 }, /* R683 - Mic Detect 4 */ + { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ + { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ + { 0x00000300, 0x0000 }, /* R768 - Input Enables */ + { 0x00000308, 0x0000 }, /* R776 - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ + { 0x0000030C, 0x0002 }, /* R780 - HPF Control */ + { 0x00000310, 0x2080 }, /* R784 - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ + { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ + { 0x00000314, 0x0080 }, /* R788 - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */ + { 0x00000318, 0x2080 }, /* R792 - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */ + { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */ + { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ + { 0x00000410, 0x2080 }, /* R1040 - Output Path Config 1L */ + { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ + { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ + { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ + { 0x00000418, 0x2080 }, /* R1048 - Output Path Config 2L */ + { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ + { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ + { 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */ + { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ + { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ + { 0x00000420, 0x2080 }, /* R1056 - Output Path Config 3L */ + { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ + { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ + { 0x00000428, 0x0000 }, /* R1064 - Output Path Config 4L */ + { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ + { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ + { 0x0000042C, 0x0000 }, /* R1068 - Output Path Config 4R */ + { 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */ + { 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */ + { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */ + { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */ + { 0x00000434, 0x0000 }, /* R1076 - Output Path Config 5R */ + { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */ + { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ + { 0x00000440, 0x8FFF }, /* R1088 - DRE Enable */ + { 0x00000441, 0xC759 }, /* R1089 - DRE Control 1 */ + { 0x00000442, 0x2A08 }, /* R1089 - DRE Control 2 */ + { 0x00000443, 0x5CFA }, /* R1089 - DRE Control 3 */ + { 0x00000448, 0x03EF }, /* R1096 - EDRE Enable */ + { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ + { 0x00000451, 0x0000 }, /* R1105 - DAC AEC Control 2 */ + { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */ + { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ + { 0x0000049A, 0x0000 }, /* R1178 - HP_TEST_CTRL_13 */ + { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */ + { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */ + { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */ + { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */ + { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */ + { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */ + { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */ + { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */ + { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */ + { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */ + { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */ + { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */ + { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */ + { 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */ + { 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */ + { 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */ + { 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */ + { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */ + { 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */ + { 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */ + { 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */ + { 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */ + { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */ + { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */ + { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */ + { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */ + { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */ + { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */ + { 0x000005C2, 0x0000 }, /* R1474 - SPD1 TX Control */ + { 0x000005C3, 0x0000 }, /* R1475 - SPD1 TX Channel Status 1 */ + { 0x000005C4, 0x0B01 }, /* R1476 - SPD1 TX Channel Status 2 */ + { 0x000005C5, 0x0000 }, /* R1477 - SPD1 TX Channel Status 3 */ + { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */ + { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */ + { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */ + { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */ + { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */ + { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */ + { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */ + { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */ + { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */ + { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */ + { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */ + { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */ + { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */ + { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */ + { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */ + { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */ + { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */ + { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */ + { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */ + { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */ + { 0x00000690, 0x0000 }, /* R1680 - OUT2LMIX Input 1 Source */ + { 0x00000691, 0x0080 }, /* R1681 - OUT2LMIX Input 1 Volume */ + { 0x00000692, 0x0000 }, /* R1682 - OUT2LMIX Input 2 Source */ + { 0x00000693, 0x0080 }, /* R1683 - OUT2LMIX Input 2 Volume */ + { 0x00000694, 0x0000 }, /* R1684 - OUT2LMIX Input 3 Source */ + { 0x00000695, 0x0080 }, /* R1685 - OUT2LMIX Input 3 Volume */ + { 0x00000696, 0x0000 }, /* R1686 - OUT2LMIX Input 4 Source */ + { 0x00000697, 0x0080 }, /* R1687 - OUT2LMIX Input 4 Volume */ + { 0x00000698, 0x0000 }, /* R1688 - OUT2RMIX Input 1 Source */ + { 0x00000699, 0x0080 }, /* R1689 - OUT2RMIX Input 1 Volume */ + { 0x0000069A, 0x0000 }, /* R1690 - OUT2RMIX Input 2 Source */ + { 0x0000069B, 0x0080 }, /* R1691 - OUT2RMIX Input 2 Volume */ + { 0x0000069C, 0x0000 }, /* R1692 - OUT2RMIX Input 3 Source */ + { 0x0000069D, 0x0080 }, /* R1693 - OUT2RMIX Input 3 Volume */ + { 0x0000069E, 0x0000 }, /* R1694 - OUT2RMIX Input 4 Source */ + { 0x0000069F, 0x0080 }, /* R1695 - OUT2RMIX Input 4 Volume */ + { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */ + { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */ + { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */ + { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */ + { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */ + { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */ + { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */ + { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */ + { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */ + { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */ + { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */ + { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */ + { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */ + { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */ + { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */ + { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */ + { 0x000006B8, 0x0000 }, /* R1720 - OUT4RMIX Input 1 Source */ + { 0x000006B9, 0x0080 }, /* R1721 - OUT4RMIX Input 1 Volume */ + { 0x000006BA, 0x0000 }, /* R1722 - OUT4RMIX Input 2 Source */ + { 0x000006BB, 0x0080 }, /* R1723 - OUT4RMIX Input 2 Volume */ + { 0x000006BC, 0x0000 }, /* R1724 - OUT4RMIX Input 3 Source */ + { 0x000006BD, 0x0080 }, /* R1725 - OUT4RMIX Input 3 Volume */ + { 0x000006BE, 0x0000 }, /* R1726 - OUT4RMIX Input 4 Source */ + { 0x000006BF, 0x0080 }, /* R1727 - OUT4RMIX Input 4 Volume */ + { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */ + { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */ + { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */ + { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */ + { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */ + { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */ + { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */ + { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */ + { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */ + { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */ + { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */ + { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */ + { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */ + { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */ + { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */ + { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */ + { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */ + { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */ + { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */ + { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */ + { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */ + { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */ + { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */ + { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */ + { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */ + { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */ + { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */ + { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */ + { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */ + { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */ + { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */ + { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */ + { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */ + { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */ + { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */ + { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */ + { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */ + { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */ + { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */ + { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */ + { 0x00000750, 0x0000 }, /* R1872 - AIF2TX3MIX Input 1 Source */ + { 0x00000751, 0x0080 }, /* R1873 - AIF2TX3MIX Input 1 Volume */ + { 0x00000752, 0x0000 }, /* R1874 - AIF2TX3MIX Input 2 Source */ + { 0x00000753, 0x0080 }, /* R1875 - AIF2TX3MIX Input 2 Volume */ + { 0x00000754, 0x0000 }, /* R1876 - AIF2TX3MIX Input 3 Source */ + { 0x00000755, 0x0080 }, /* R1877 - AIF2TX3MIX Input 3 Volume */ + { 0x00000756, 0x0000 }, /* R1878 - AIF2TX3MIX Input 4 Source */ + { 0x00000757, 0x0080 }, /* R1879 - AIF2TX3MIX Input 4 Volume */ + { 0x00000758, 0x0000 }, /* R1880 - AIF2TX4MIX Input 1 Source */ + { 0x00000759, 0x0080 }, /* R1881 - AIF2TX4MIX Input 1 Volume */ + { 0x0000075A, 0x0000 }, /* R1882 - AIF2TX4MIX Input 2 Source */ + { 0x0000075B, 0x0080 }, /* R1883 - AIF2TX4MIX Input 2 Volume */ + { 0x0000075C, 0x0000 }, /* R1884 - AIF2TX4MIX Input 3 Source */ + { 0x0000075D, 0x0080 }, /* R1885 - AIF2TX4MIX Input 3 Volume */ + { 0x0000075E, 0x0000 }, /* R1886 - AIF2TX4MIX Input 4 Source */ + { 0x0000075F, 0x0080 }, /* R1887 - AIF2TX4MIX Input 4 Volume */ + { 0x00000760, 0x0000 }, /* R1888 - AIF2TX5MIX Input 1 Source */ + { 0x00000761, 0x0080 }, /* R1889 - AIF2TX5MIX Input 1 Volume */ + { 0x00000762, 0x0000 }, /* R1890 - AIF2TX5MIX Input 2 Source */ + { 0x00000763, 0x0080 }, /* R1891 - AIF2TX5MIX Input 2 Volume */ + { 0x00000764, 0x0000 }, /* R1892 - AIF2TX5MIX Input 3 Source */ + { 0x00000765, 0x0080 }, /* R1893 - AIF2TX5MIX Input 3 Volume */ + { 0x00000766, 0x0000 }, /* R1894 - AIF2TX5MIX Input 4 Source */ + { 0x00000767, 0x0080 }, /* R1895 - AIF2TX5MIX Input 4 Volume */ + { 0x00000768, 0x0000 }, /* R1896 - AIF2TX6MIX Input 1 Source */ + { 0x00000769, 0x0080 }, /* R1897 - AIF2TX6MIX Input 1 Volume */ + { 0x0000076A, 0x0000 }, /* R1898 - AIF2TX6MIX Input 2 Source */ + { 0x0000076B, 0x0080 }, /* R1899 - AIF2TX6MIX Input 2 Volume */ + { 0x0000076C, 0x0000 }, /* R1900 - AIF2TX6MIX Input 3 Source */ + { 0x0000076D, 0x0080 }, /* R1901 - AIF2TX6MIX Input 3 Volume */ + { 0x0000076E, 0x0000 }, /* R1902 - AIF2TX6MIX Input 4 Source */ + { 0x0000076F, 0x0080 }, /* R1903 - AIF2TX6MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */ + { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */ + { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */ + { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */ + { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */ + { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */ + { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */ + { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */ + { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */ + { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */ + { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */ + { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */ + { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */ + { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */ + { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */ + { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */ + { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */ + { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */ + { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */ + { 0x00000800, 0x0000 }, /* R2048 - SPDIF1TX1MIX Input 1 Source */ + { 0x00000801, 0x0080 }, /* R2049 - SPDIF1TX1MIX Input 1 Volume */ + { 0x00000808, 0x0000 }, /* R2056 - SPDIF1TX2MIX Input 1 Source */ + { 0x00000809, 0x0080 }, /* R2057 - SPDIF1TX2MIX Input 1 Volume */ + { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */ + { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */ + { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */ + { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */ + { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */ + { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */ + { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */ + { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */ + { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */ + { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */ + { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */ + { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */ + { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */ + { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */ + { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */ + { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */ + { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */ + { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */ + { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */ + { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */ + { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */ + { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */ + { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */ + { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */ + { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */ + { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */ + { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */ + { 0x00000B10, 0x0000 }, /* R2832 - ISRC1DEC3MIX Input 1 Source */ + { 0x00000B18, 0x0000 }, /* R2840 - ISRC1DEC4MIX Input 1 Source */ + { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */ + { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */ + { 0x00000B30, 0x0000 }, /* R2864 - ISRC1INT3MIX Input 1 Source */ + { 0x00000B38, 0x0000 }, /* R2872 - ISRC1INT4MIX Input 1 Source */ + { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */ + { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */ + { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */ + { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */ + { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */ + { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */ + { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */ + { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */ + { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */ + { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */ + { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */ + { 0x00000C18, 0x0000 }, /* R3096 - GP Switch 1 */ + { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */ + { 0x00000C21, 0x8001 }, /* R3105 - Misc Pad Ctrl 2 */ + { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */ + { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */ + { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */ + { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */ + { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */ + { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */ + { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */ + { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */ + { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */ + { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */ + { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */ + { 0x00000D19, 0xFFFF }, /* R3353 - IRQ2 Status 2 Mask */ + { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */ + { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */ + { 0x00000D1C, 0xFEFF }, /* R3356 - IRQ2 Status 5 Mask */ + { 0x00000D1D, 0xFFFF }, /* R3357 - IRQ2 Status 6 Mask */ + { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */ + { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */ + { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */ + { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */ + { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */ + { 0x00000E01, 0x0000 }, /* R3585 - FX_Ctrl2 */ + { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */ + { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */ + { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */ + { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */ + { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */ + { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */ + { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */ + { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */ + { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */ + { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */ + { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */ + { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */ + { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */ + { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */ + { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */ + { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */ + { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */ + { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */ + { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */ + { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */ + { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */ + { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */ + { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */ + { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */ + { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */ + { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */ + { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */ + { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */ + { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */ + { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */ + { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */ + { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */ + { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */ + { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */ + { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */ + { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */ + { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */ + { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */ + { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */ + { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */ + { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */ + { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */ + { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */ + { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */ + { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */ + { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */ + { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */ + { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */ + { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */ + { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */ + { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */ + { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */ + { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */ + { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */ + { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */ + { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */ + { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */ + { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */ + { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */ + { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */ + { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */ + { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */ + { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */ + { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */ + { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */ + { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */ + { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */ + { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */ + { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */ + { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */ + { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */ + { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */ + { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */ + { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */ + { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */ + { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */ + { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */ + { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */ + { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */ + { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */ + { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */ + { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */ + { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */ + { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */ + { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */ + { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */ + { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */ + { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */ + { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */ + { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */ + { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */ + { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */ + { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */ + { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */ + { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */ + { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */ + { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */ + { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */ + { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */ + { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */ + { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */ + { 0x00000EF1, 0x0001 }, /* R3825 - ISRC 1 CTRL 2 */ + { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */ + { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */ + { 0x00000EF4, 0x0001 }, /* R3828 - ISRC 2 CTRL 2 */ + { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */ + { 0x00001700, 0x0000 }, /* R5888 - FRF_COEFF_1 */ + { 0x00001701, 0x0000 }, /* R5889 - FRF_COEFF_2 */ + { 0x00001702, 0x0000 }, /* R5890 - FRF_COEFF_3 */ + { 0x00001703, 0x0000 }, /* R5891 - FRF_COEFF_4 */ + { 0x00001704, 0x0000 }, /* R5892 - DAC_COMP_1 */ + { 0x00001705, 0x0000 }, /* R5893 - DAC_COMP_2 */ +}; + +static bool vegas_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_CTRL_IF_SPI_CFG_1: + case ARIZONA_CTRL_IF_I2C1_CFG_1: + case ARIZONA_CTRL_IF_I2C1_CFG_2: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_TONE_GENERATOR_1: + case ARIZONA_TONE_GENERATOR_2: + case ARIZONA_TONE_GENERATOR_3: + case ARIZONA_TONE_GENERATOR_4: + case ARIZONA_TONE_GENERATOR_5: + case ARIZONA_PWM_DRIVE_1: + case ARIZONA_PWM_DRIVE_2: + case ARIZONA_PWM_DRIVE_3: + case ARIZONA_WAKE_CONTROL: + case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: + case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: + case ARIZONA_HAPTICS_CONTROL_1: + case ARIZONA_HAPTICS_CONTROL_2: + case ARIZONA_HAPTICS_PHASE_1_INTENSITY: + case ARIZONA_HAPTICS_PHASE_1_DURATION: + case ARIZONA_HAPTICS_PHASE_2_INTENSITY: + case ARIZONA_HAPTICS_PHASE_2_DURATION: + case ARIZONA_HAPTICS_PHASE_3_INTENSITY: + case ARIZONA_HAPTICS_PHASE_3_DURATION: + case ARIZONA_HAPTICS_STATUS: + case ARIZONA_CLOCK_32K_1: + case ARIZONA_SYSTEM_CLOCK_1: + case ARIZONA_SAMPLE_RATE_1: + case ARIZONA_SAMPLE_RATE_2: + case ARIZONA_SAMPLE_RATE_3: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case ARIZONA_ASYNC_CLOCK_1: + case ARIZONA_ASYNC_SAMPLE_RATE_1: + case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_OUTPUT_SYSTEM_CLOCK: + case ARIZONA_OUTPUT_ASYNC_CLOCK: + case ARIZONA_RATE_ESTIMATOR_1: + case ARIZONA_RATE_ESTIMATOR_2: + case ARIZONA_RATE_ESTIMATOR_3: + case ARIZONA_RATE_ESTIMATOR_4: + case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_DYNAMIC_FREQUENCY_SCALING_1: + case ARIZONA_FLL1_CONTROL_1: + case ARIZONA_FLL1_CONTROL_2: + case ARIZONA_FLL1_CONTROL_3: + case ARIZONA_FLL1_CONTROL_4: + case ARIZONA_FLL1_CONTROL_5: + case ARIZONA_FLL1_CONTROL_6: + case ARIZONA_FLL1_CONTROL_7: + case ARIZONA_FLL1_LOOP_FILTER_TEST_1: + case ARIZONA_FLL1_NCO_TEST_0: + case ARIZONA_FLL1_SYNCHRONISER_1: + case ARIZONA_FLL1_SYNCHRONISER_2: + case ARIZONA_FLL1_SYNCHRONISER_3: + case ARIZONA_FLL1_SYNCHRONISER_4: + case ARIZONA_FLL1_SYNCHRONISER_5: + case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: + case ARIZONA_FLL1_SPREAD_SPECTRUM: + case ARIZONA_FLL1_GPIO_CLOCK: + case ARIZONA_FLL2_CONTROL_1: + case ARIZONA_FLL2_CONTROL_2: + case ARIZONA_FLL2_CONTROL_3: + case ARIZONA_FLL2_CONTROL_4: + case ARIZONA_FLL2_CONTROL_5: + case ARIZONA_FLL2_CONTROL_6: + case ARIZONA_FLL2_CONTROL_7: + case ARIZONA_FLL2_LOOP_FILTER_TEST_1: + case ARIZONA_FLL2_NCO_TEST_0: + case ARIZONA_FLL2_SYNCHRONISER_1: + case ARIZONA_FLL2_SYNCHRONISER_2: + case ARIZONA_FLL2_SYNCHRONISER_3: + case ARIZONA_FLL2_SYNCHRONISER_4: + case ARIZONA_FLL2_SYNCHRONISER_5: + case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: + case ARIZONA_FLL2_SPREAD_SPECTRUM: + case ARIZONA_FLL2_GPIO_CLOCK: + case ARIZONA_MIC_CHARGE_PUMP_1: + case ARIZONA_LDO1_CONTROL_1: + case ARIZONA_LDO1_CONTROL_2: + case ARIZONA_LDO2_CONTROL_1: + case ARIZONA_MIC_BIAS_CTRL_1: + case ARIZONA_MIC_BIAS_CTRL_2: + case ARIZONA_MIC_BIAS_CTRL_3: + case ARIZONA_ACCESSORY_DETECT_MODE_1: + case ARIZONA_HEADPHONE_DETECT_1: + case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_MICD_CLAMP_CONTROL: + case ARIZONA_MIC_DETECT_1: + case ARIZONA_MIC_DETECT_2: + case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: + case ARIZONA_MIC_DETECT_LEVEL_1: + case ARIZONA_MIC_DETECT_LEVEL_2: + case ARIZONA_MIC_DETECT_LEVEL_3: + case ARIZONA_MIC_DETECT_LEVEL_4: + case ARIZONA_ISOLATION_CONTROL: + case ARIZONA_JACK_DETECT_ANALOGUE: + case ARIZONA_INPUT_ENABLES: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_INPUT_RATE: + case ARIZONA_INPUT_VOLUME_RAMP: + case ARIZONA_HPF_CONTROL: + case ARIZONA_IN1L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1L: + case ARIZONA_DMIC1L_CONTROL: + case ARIZONA_IN1R_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_1R: + case ARIZONA_DMIC1R_CONTROL: + case ARIZONA_IN2L_CONTROL: + case ARIZONA_ADC_DIGITAL_VOLUME_2L: + case ARIZONA_DMIC2L_CONTROL: + case ARIZONA_OUTPUT_ENABLES_1: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_OUTPUT_RATE_1: + case ARIZONA_OUTPUT_VOLUME_RAMP: + case ARIZONA_OUTPUT_PATH_CONFIG_1L: + case ARIZONA_DAC_DIGITAL_VOLUME_1L: + case ARIZONA_NOISE_GATE_SELECT_1L: + case ARIZONA_OUTPUT_PATH_CONFIG_1R: + case ARIZONA_DAC_DIGITAL_VOLUME_1R: + case ARIZONA_NOISE_GATE_SELECT_1R: + case ARIZONA_OUTPUT_PATH_CONFIG_2L: + case ARIZONA_DAC_DIGITAL_VOLUME_2L: + case ARIZONA_NOISE_GATE_SELECT_2L: + case ARIZONA_OUTPUT_PATH_CONFIG_2R: + case ARIZONA_DAC_DIGITAL_VOLUME_2R: + case ARIZONA_NOISE_GATE_SELECT_2R: + case ARIZONA_OUTPUT_PATH_CONFIG_3L: + case ARIZONA_DAC_DIGITAL_VOLUME_3L: + case ARIZONA_NOISE_GATE_SELECT_3L: + case ARIZONA_OUTPUT_PATH_CONFIG_4L: + case ARIZONA_DAC_DIGITAL_VOLUME_4L: + case ARIZONA_NOISE_GATE_SELECT_4L: + case ARIZONA_OUTPUT_PATH_CONFIG_4R: + case ARIZONA_DAC_DIGITAL_VOLUME_4R: + case ARIZONA_NOISE_GATE_SELECT_4R: + case ARIZONA_OUTPUT_PATH_CONFIG_5L: + case ARIZONA_DAC_DIGITAL_VOLUME_5L: + case ARIZONA_NOISE_GATE_SELECT_5L: + case ARIZONA_OUTPUT_PATH_CONFIG_5R: + case ARIZONA_DAC_DIGITAL_VOLUME_5R: + case ARIZONA_NOISE_GATE_SELECT_5R: + case ARIZONA_DRE_ENABLE: + case ARIZONA_DRE_CONTROL_1: + case ARIZONA_DRE_CONTROL_2: + case ARIZONA_DRE_CONTROL_3: + case CLEARWATER_EDRE_ENABLE: + case ARIZONA_DAC_AEC_CONTROL_1: + case ARIZONA_DAC_AEC_CONTROL_2: + case ARIZONA_NOISE_GATE_CONTROL: + case ARIZONA_PDM_SPK1_CTRL_1: + case ARIZONA_PDM_SPK1_CTRL_2: + case ARIZONA_HP_TEST_CTRL_13: + case ARIZONA_AIF1_BCLK_CTRL: + case ARIZONA_AIF1_TX_PIN_CTRL: + case ARIZONA_AIF1_RX_PIN_CTRL: + case ARIZONA_AIF1_RATE_CTRL: + case ARIZONA_AIF1_FORMAT: + case ARIZONA_AIF1_RX_BCLK_RATE: + case ARIZONA_AIF1_FRAME_CTRL_1: + case ARIZONA_AIF1_FRAME_CTRL_2: + case ARIZONA_AIF1_FRAME_CTRL_3: + case ARIZONA_AIF1_FRAME_CTRL_4: + case ARIZONA_AIF1_FRAME_CTRL_5: + case ARIZONA_AIF1_FRAME_CTRL_6: + case ARIZONA_AIF1_FRAME_CTRL_7: + case ARIZONA_AIF1_FRAME_CTRL_8: + case ARIZONA_AIF1_FRAME_CTRL_11: + case ARIZONA_AIF1_FRAME_CTRL_12: + case ARIZONA_AIF1_FRAME_CTRL_13: + case ARIZONA_AIF1_FRAME_CTRL_14: + case ARIZONA_AIF1_FRAME_CTRL_15: + case ARIZONA_AIF1_FRAME_CTRL_16: + case ARIZONA_AIF1_TX_ENABLES: + case ARIZONA_AIF1_RX_ENABLES: + case ARIZONA_AIF2_BCLK_CTRL: + case ARIZONA_AIF2_TX_PIN_CTRL: + case ARIZONA_AIF2_RX_PIN_CTRL: + case ARIZONA_AIF2_RATE_CTRL: + case ARIZONA_AIF2_FORMAT: + case ARIZONA_AIF2_RX_BCLK_RATE: + case ARIZONA_AIF2_FRAME_CTRL_1: + case ARIZONA_AIF2_FRAME_CTRL_2: + case ARIZONA_AIF2_FRAME_CTRL_3: + case ARIZONA_AIF2_FRAME_CTRL_4: + case ARIZONA_AIF2_FRAME_CTRL_5: + case ARIZONA_AIF2_FRAME_CTRL_6: + case ARIZONA_AIF2_FRAME_CTRL_7: + case ARIZONA_AIF2_FRAME_CTRL_8: + case ARIZONA_AIF2_FRAME_CTRL_11: + case ARIZONA_AIF2_FRAME_CTRL_12: + case ARIZONA_AIF2_FRAME_CTRL_13: + case ARIZONA_AIF2_FRAME_CTRL_14: + case ARIZONA_AIF2_FRAME_CTRL_15: + case ARIZONA_AIF2_FRAME_CTRL_16: + case ARIZONA_AIF2_TX_ENABLES: + case ARIZONA_AIF2_RX_ENABLES: + case ARIZONA_AIF3_BCLK_CTRL: + case ARIZONA_AIF3_TX_PIN_CTRL: + case ARIZONA_AIF3_RX_PIN_CTRL: + case ARIZONA_AIF3_RATE_CTRL: + case ARIZONA_AIF3_FORMAT: + case ARIZONA_AIF3_RX_BCLK_RATE: + case ARIZONA_AIF3_FRAME_CTRL_1: + case ARIZONA_AIF3_FRAME_CTRL_2: + case ARIZONA_AIF3_FRAME_CTRL_3: + case ARIZONA_AIF3_FRAME_CTRL_4: + case ARIZONA_AIF3_FRAME_CTRL_11: + case ARIZONA_AIF3_FRAME_CTRL_12: + case ARIZONA_AIF3_TX_ENABLES: + case ARIZONA_AIF3_RX_ENABLES: + case ARIZONA_SPD1_TX_CONTROL: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_1: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_2: + case ARIZONA_SPD1_TX_CHANNEL_STATUS_3: + case ARIZONA_SLIMBUS_FRAMER_REF_GEAR: + case ARIZONA_SLIMBUS_RATES_1: + case ARIZONA_SLIMBUS_RATES_2: + case ARIZONA_SLIMBUS_RATES_5: + case ARIZONA_SLIMBUS_RATES_6: + case ARIZONA_SLIMBUS_RATES_7: + case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE: + case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE: + case ARIZONA_SLIMBUS_RX_PORT_STATUS: + case ARIZONA_SLIMBUS_TX_PORT_STATUS: + case ARIZONA_PWM1MIX_INPUT_1_SOURCE: + case ARIZONA_PWM1MIX_INPUT_1_VOLUME: + case ARIZONA_PWM1MIX_INPUT_2_SOURCE: + case ARIZONA_PWM1MIX_INPUT_2_VOLUME: + case ARIZONA_PWM1MIX_INPUT_3_SOURCE: + case ARIZONA_PWM1MIX_INPUT_3_VOLUME: + case ARIZONA_PWM1MIX_INPUT_4_SOURCE: + case ARIZONA_PWM1MIX_INPUT_4_VOLUME: + case ARIZONA_PWM2MIX_INPUT_1_SOURCE: + case ARIZONA_PWM2MIX_INPUT_1_VOLUME: + case ARIZONA_PWM2MIX_INPUT_2_SOURCE: + case ARIZONA_PWM2MIX_INPUT_2_VOLUME: + case ARIZONA_PWM2MIX_INPUT_3_SOURCE: + case ARIZONA_PWM2MIX_INPUT_3_VOLUME: + case ARIZONA_PWM2MIX_INPUT_4_SOURCE: + case ARIZONA_PWM2MIX_INPUT_4_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT1RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT1RMIX_INPUT_4_VOLUME: + case ARIZONA_OUT2LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT2LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT2LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT2LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT2LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT2LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT2LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT2LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT2RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT2RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT2RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT2RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT2RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT2RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT2RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT2RMIX_INPUT_4_VOLUME: + case ARIZONA_OUT3LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT3LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT3LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT3LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT3LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT3LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT3LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT3LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT4LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT4LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT4RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT4RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT4RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT4RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT4RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT4RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT4RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT4RMIX_INPUT_4_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_1_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_1_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_2_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_2_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_3_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_3_VOLUME: + case ARIZONA_OUT5LMIX_INPUT_4_SOURCE: + case ARIZONA_OUT5LMIX_INPUT_4_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_1_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_1_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_2_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_2_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_3_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_3_VOLUME: + case ARIZONA_OUT5RMIX_INPUT_4_SOURCE: + case ARIZONA_OUT5RMIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME: + case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE: + case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME: + case ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE: + case ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX1MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX1MIX_INPUT_4_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_1_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_2_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_2_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_3_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_3_VOLUME: + case ARIZONA_AIF3TX2MIX_INPUT_4_SOURCE: + case ARIZONA_AIF3TX2MIX_INPUT_4_VOLUME: + case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME: + case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE: + case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME: + case ARIZONA_SPDIFTX1MIX_INPUT_1_SOURCE: + case ARIZONA_SPDIFTX1MIX_INPUT_1_VOLUME: + case ARIZONA_SPDIFTX2MIX_INPUT_1_SOURCE: + case ARIZONA_SPDIFTX2MIX_INPUT_1_VOLUME: + case ARIZONA_EQ1MIX_INPUT_1_SOURCE: + case ARIZONA_EQ1MIX_INPUT_1_VOLUME: + case ARIZONA_EQ2MIX_INPUT_1_SOURCE: + case ARIZONA_EQ2MIX_INPUT_1_VOLUME: + case ARIZONA_EQ3MIX_INPUT_1_SOURCE: + case ARIZONA_EQ3MIX_INPUT_1_VOLUME: + case ARIZONA_EQ4MIX_INPUT_1_SOURCE: + case ARIZONA_EQ4MIX_INPUT_1_VOLUME: + case ARIZONA_DRC1LMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1LMIX_INPUT_1_VOLUME: + case ARIZONA_DRC1RMIX_INPUT_1_SOURCE: + case ARIZONA_DRC1RMIX_INPUT_1_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP1MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP1MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP2MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP2MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP3MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP3MIX_INPUT_4_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_1_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_1_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_2_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_2_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_3_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_3_VOLUME: + case ARIZONA_HPLP4MIX_INPUT_4_SOURCE: + case ARIZONA_HPLP4MIX_INPUT_4_VOLUME: + case ARIZONA_ASRC1LMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC1RMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC2LMIX_INPUT_1_SOURCE: + case ARIZONA_ASRC2RMIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE: + case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE: + case ARIZONA_GPIO1_CTRL: + case ARIZONA_GPIO2_CTRL: + case ARIZONA_GPIO3_CTRL: + case ARIZONA_GPIO4_CTRL: + case ARIZONA_GPIO5_CTRL: + case ARIZONA_IRQ_CTRL_1: + case ARIZONA_GPIO_DEBOUNCE_CONFIG: + case ARIZONA_GP_SWITCH_1: + case ARIZONA_MISC_PAD_CTRL_1: + case ARIZONA_MISC_PAD_CTRL_2: + case ARIZONA_MISC_PAD_CTRL_3: + case ARIZONA_MISC_PAD_CTRL_4: + case ARIZONA_MISC_PAD_CTRL_5: + case ARIZONA_MISC_PAD_CTRL_6: + case ARIZONA_INTERRUPT_STATUS_1: + case ARIZONA_INTERRUPT_STATUS_2: + case ARIZONA_INTERRUPT_STATUS_3: + case ARIZONA_INTERRUPT_STATUS_4: + case ARIZONA_INTERRUPT_STATUS_5: + case ARIZONA_INTERRUPT_STATUS_1_MASK: + case ARIZONA_INTERRUPT_STATUS_2_MASK: + case ARIZONA_INTERRUPT_STATUS_3_MASK: + case ARIZONA_INTERRUPT_STATUS_4_MASK: + case ARIZONA_INTERRUPT_STATUS_5_MASK: + case ARIZONA_INTERRUPT_CONTROL: + case ARIZONA_IRQ2_STATUS_1: + case ARIZONA_IRQ2_STATUS_2: + case ARIZONA_IRQ2_STATUS_3: + case ARIZONA_IRQ2_STATUS_4: + case ARIZONA_IRQ2_STATUS_5: + case ARIZONA_IRQ2_STATUS_1_MASK: + case ARIZONA_IRQ2_STATUS_2_MASK: + case ARIZONA_IRQ2_STATUS_3_MASK: + case ARIZONA_IRQ2_STATUS_4_MASK: + case ARIZONA_IRQ2_STATUS_5_MASK: + case ARIZONA_IRQ2_CONTROL: + case ARIZONA_INTERRUPT_RAW_STATUS_2: + case ARIZONA_INTERRUPT_RAW_STATUS_3: + case ARIZONA_INTERRUPT_RAW_STATUS_4: + case ARIZONA_INTERRUPT_RAW_STATUS_5: + case ARIZONA_INTERRUPT_RAW_STATUS_6: + case ARIZONA_INTERRUPT_RAW_STATUS_7: + case ARIZONA_INTERRUPT_RAW_STATUS_8: + case ARIZONA_IRQ_PIN_STATUS: + case ARIZONA_AOD_WKUP_AND_TRIG: + case ARIZONA_AOD_IRQ1: + case ARIZONA_AOD_IRQ2: + case ARIZONA_AOD_IRQ_MASK_IRQ1: + case ARIZONA_AOD_IRQ_MASK_IRQ2: + case ARIZONA_AOD_IRQ_RAW_STATUS: + case ARIZONA_JACK_DETECT_DEBOUNCE: + case ARIZONA_FX_CTRL1: + case ARIZONA_FX_CTRL2: + case ARIZONA_EQ1_1: + case ARIZONA_EQ1_2: + case ARIZONA_EQ1_3: + case ARIZONA_EQ1_4: + case ARIZONA_EQ1_5: + case ARIZONA_EQ1_6: + case ARIZONA_EQ1_7: + case ARIZONA_EQ1_8: + case ARIZONA_EQ1_9: + case ARIZONA_EQ1_10: + case ARIZONA_EQ1_11: + case ARIZONA_EQ1_12: + case ARIZONA_EQ1_13: + case ARIZONA_EQ1_14: + case ARIZONA_EQ1_15: + case ARIZONA_EQ1_16: + case ARIZONA_EQ1_17: + case ARIZONA_EQ1_18: + case ARIZONA_EQ1_19: + case ARIZONA_EQ1_20: + case ARIZONA_EQ1_21: + case ARIZONA_EQ2_1: + case ARIZONA_EQ2_2: + case ARIZONA_EQ2_3: + case ARIZONA_EQ2_4: + case ARIZONA_EQ2_5: + case ARIZONA_EQ2_6: + case ARIZONA_EQ2_7: + case ARIZONA_EQ2_8: + case ARIZONA_EQ2_9: + case ARIZONA_EQ2_10: + case ARIZONA_EQ2_11: + case ARIZONA_EQ2_12: + case ARIZONA_EQ2_13: + case ARIZONA_EQ2_14: + case ARIZONA_EQ2_15: + case ARIZONA_EQ2_16: + case ARIZONA_EQ2_17: + case ARIZONA_EQ2_18: + case ARIZONA_EQ2_19: + case ARIZONA_EQ2_20: + case ARIZONA_EQ2_21: + case ARIZONA_EQ3_1: + case ARIZONA_EQ3_2: + case ARIZONA_EQ3_3: + case ARIZONA_EQ3_4: + case ARIZONA_EQ3_5: + case ARIZONA_EQ3_6: + case ARIZONA_EQ3_7: + case ARIZONA_EQ3_8: + case ARIZONA_EQ3_9: + case ARIZONA_EQ3_10: + case ARIZONA_EQ3_11: + case ARIZONA_EQ3_12: + case ARIZONA_EQ3_13: + case ARIZONA_EQ3_14: + case ARIZONA_EQ3_15: + case ARIZONA_EQ3_16: + case ARIZONA_EQ3_17: + case ARIZONA_EQ3_18: + case ARIZONA_EQ3_19: + case ARIZONA_EQ3_20: + case ARIZONA_EQ3_21: + case ARIZONA_EQ4_1: + case ARIZONA_EQ4_2: + case ARIZONA_EQ4_3: + case ARIZONA_EQ4_4: + case ARIZONA_EQ4_5: + case ARIZONA_EQ4_6: + case ARIZONA_EQ4_7: + case ARIZONA_EQ4_8: + case ARIZONA_EQ4_9: + case ARIZONA_EQ4_10: + case ARIZONA_EQ4_11: + case ARIZONA_EQ4_12: + case ARIZONA_EQ4_13: + case ARIZONA_EQ4_14: + case ARIZONA_EQ4_15: + case ARIZONA_EQ4_16: + case ARIZONA_EQ4_17: + case ARIZONA_EQ4_18: + case ARIZONA_EQ4_19: + case ARIZONA_EQ4_20: + case ARIZONA_EQ4_21: + case ARIZONA_DRC1_CTRL1: + case ARIZONA_DRC1_CTRL2: + case ARIZONA_DRC1_CTRL3: + case ARIZONA_DRC1_CTRL4: + case ARIZONA_DRC1_CTRL5: + case ARIZONA_HPLPF1_1: + case ARIZONA_HPLPF1_2: + case ARIZONA_HPLPF2_1: + case ARIZONA_HPLPF2_2: + case ARIZONA_HPLPF3_1: + case ARIZONA_HPLPF3_2: + case ARIZONA_HPLPF4_1: + case ARIZONA_HPLPF4_2: + case ARIZONA_ASRC_ENABLE: + case ARIZONA_ASRC_STATUS: + case ARIZONA_ASRC_RATE1: + case ARIZONA_ISRC_1_CTRL_1: + case ARIZONA_ISRC_1_CTRL_2: + case ARIZONA_ISRC_1_CTRL_3: + case ARIZONA_ISRC_2_CTRL_1: + case ARIZONA_ISRC_2_CTRL_2: + case ARIZONA_ISRC_2_CTRL_3: + case ARIZONA_FRF_COEFF_1: + case ARIZONA_FRF_COEFF_2: + case ARIZONA_FRF_COEFF_3: + case ARIZONA_FRF_COEFF_4: + case ARIZONA_V2_DAC_COMP_1: + case ARIZONA_V2_DAC_COMP_2: + return true; + default: + return false; + } +} + +static bool vegas_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ARIZONA_SOFTWARE_RESET: + case ARIZONA_DEVICE_REVISION: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_HAPTICS_STATUS: + case ARIZONA_SAMPLE_RATE_1_STATUS: + case ARIZONA_SAMPLE_RATE_2_STATUS: + case ARIZONA_SAMPLE_RATE_3_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_4: + case ARIZONA_HEADPHONE_DETECT_2: + case ARIZONA_INPUT_ENABLES_STATUS: + case ARIZONA_OUTPUT_STATUS_1: + case ARIZONA_RAW_OUTPUT_STATUS_1: + case ARIZONA_SLIMBUS_RX_PORT_STATUS: + case ARIZONA_SLIMBUS_TX_PORT_STATUS: + case ARIZONA_INTERRUPT_STATUS_1: + case ARIZONA_INTERRUPT_STATUS_2: + case ARIZONA_INTERRUPT_STATUS_3: + case ARIZONA_INTERRUPT_STATUS_4: + case ARIZONA_INTERRUPT_STATUS_5: + case ARIZONA_IRQ2_STATUS_1: + case ARIZONA_IRQ2_STATUS_2: + case ARIZONA_IRQ2_STATUS_3: + case ARIZONA_IRQ2_STATUS_4: + case ARIZONA_IRQ2_STATUS_5: + case ARIZONA_INTERRUPT_RAW_STATUS_2: + case ARIZONA_INTERRUPT_RAW_STATUS_3: + case ARIZONA_INTERRUPT_RAW_STATUS_4: + case ARIZONA_INTERRUPT_RAW_STATUS_5: + case ARIZONA_INTERRUPT_RAW_STATUS_6: + case ARIZONA_INTERRUPT_RAW_STATUS_7: + case ARIZONA_INTERRUPT_RAW_STATUS_8: + case ARIZONA_IRQ_PIN_STATUS: + case ARIZONA_AOD_WKUP_AND_TRIG: + case ARIZONA_AOD_IRQ1: + case ARIZONA_AOD_IRQ2: + case ARIZONA_AOD_IRQ_RAW_STATUS: + case ARIZONA_FX_CTRL2: + case ARIZONA_ASRC_STATUS: + return true; + default: + return false; + } +} + +#define VEGAS_MAX_REGISTER 0x31ff + +const struct regmap_config vegas_i2c_regmap = { + .reg_bits = 32, + .val_bits = 16, + + .max_register = VEGAS_MAX_REGISTER, + .readable_reg = vegas_readable_register, + .volatile_reg = vegas_volatile_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = vegas_reg_default, + .num_reg_defaults = ARRAY_SIZE(vegas_reg_default), +}; +EXPORT_SYMBOL_GPL(vegas_i2c_regmap); diff --git a/drivers/mhi/Kconfig b/drivers/mhi/Kconfig index c4dc4d0870de..a6e269d177e8 100644 --- a/drivers/mhi/Kconfig +++ b/drivers/mhi/Kconfig @@ -4,3 +4,7 @@ config MHI config MHI_RMNET_DUMP bool "MHI RMNET DUMP" default y + +config DEBUG_PKTLOG + bool "IPC pcap logging feature" + default n diff --git a/drivers/mhi/Makefile b/drivers/mhi/Makefile index 099dfb763d56..4ea819221efc 100644 --- a/drivers/mhi/Makefile +++ b/drivers/mhi/Makefile @@ -1,2 +1,3 @@ obj-y += mhi_main.o mhi_iface.o mhi_init.o mhi_isr.o mhi_mmio_ops.o mhi_ring_ops.o mhi_states.o mhi_sys.o \ mhi_uci.o msm_rmnet_mhi.o mhi_bhi.o mhi_pm.o mhi_ssr.o +obj-$(CONFIG_DEBUG_PKTLOG) += modem_pktlog.o diff --git a/drivers/mhi/mhi_pm.c b/drivers/mhi/mhi_pm.c index a8c5d6e70046..8eb2db3f6293 100644 --- a/drivers/mhi/mhi_pm.c +++ b/drivers/mhi/mhi_pm.c @@ -22,6 +22,7 @@ extern int exynos_pcie_pm_resume(int ch_num); extern int exynos_pcie_save_config(struct pci_dev *dev); extern int exynos_pcie_restore_config(struct pci_dev *dev); +extern void exynos_pcie_rxelecidle_toggle(int ch_num); /* Write only sysfs attributes */ static DEVICE_ATTR(MHI_M3, S_IWUSR, NULL, sysfs_init_M3); static DEVICE_ATTR(MHI_M0, S_IWUSR, NULL, sysfs_init_M0); @@ -210,7 +211,7 @@ MHI_STATUS mhi_turn_off_pcie_link(mhi_device_ctxt *mhi_dev_ctxt) mhi_log(MHI_MSG_CRITICAL | MHI_DBG_POWER, "Failed to save pcie config space: %x\n", r); } - + exynos_pcie_rxelecidle_toggle(0); r = pci_set_power_state(mhi_dev_ctxt->dev_info->pcie_device, PCI_D3hot); if (r) { mhi_log(MHI_MSG_CRITICAL | MHI_DBG_POWER, diff --git a/drivers/mhi/mhi_ring_ops.c b/drivers/mhi/mhi_ring_ops.c index 9027cd04c055..75cadc78b46a 100644 --- a/drivers/mhi/mhi_ring_ops.c +++ b/drivers/mhi/mhi_ring_ops.c @@ -91,8 +91,8 @@ MHI_STATUS delete_element(mhi_ring *ring, void * volatile *rp, return MHI_STATUS_ERROR; } if (d_wp == d_rp) { - mhi_log(MHI_MSG_VERBOSE, "Ring 0x%lX is empty\n", - (uintptr_t)ring->base); + mhi_log(MHI_MSG_VERBOSE, "Ring 0x%lX is empty, rp:0x%lX, wp:0x%lX\n", + (uintptr_t)ring->base, (long)*rp ,(long)*wp); if (NULL != assigned_addr) *assigned_addr = NULL; return MHI_STATUS_RING_EMPTY; diff --git a/drivers/mhi/mhi_states.c b/drivers/mhi/mhi_states.c index 2d6228652b0f..050508b7a23f 100644 --- a/drivers/mhi/mhi_states.c +++ b/drivers/mhi/mhi_states.c @@ -13,6 +13,7 @@ #include "mhi_sys.h" #include "mhi_hwio.h" +extern void set_ap2mdm_errfatal(void); extern u32 m3_timer_val_ms; int mhi_state_change_thread(void *ctxt) { @@ -45,13 +46,17 @@ int mhi_state_change_thread(void *ctxt) "Caught exit signal, quitting\n"); return 0; } - mhi_dev_ctxt->st_thread_stopped = 0; spin_lock_irqsave(work_q->q_lock, flags); + mhi_dev_ctxt->st_thread_stopped = 0; cur_work_item = *(STATE_TRANSITION *)(state_change_q->rp); ret_val = ctxt_del_element(&work_q->q_info, NULL); - MHI_ASSERT(ret_val == MHI_STATUS_SUCCESS, - "Failed to delete element from STT workqueue\n"); spin_unlock_irqrestore(work_q->q_lock, flags); + if(ret_val != MHI_STATUS_SUCCESS){ + mhi_log(MHI_MSG_ERROR, + "Failed to delete element from STT workqueue\n"); + msleep(10); + continue; + } ret_val = process_stt_work_item(mhi_dev_ctxt, cur_work_item); } return 0; @@ -590,8 +595,6 @@ MHI_STATUS process_RESET_transition(mhi_device_ctxt *mhi_dev_ctxt, } } - /* reset outbound_ack count */ - atomic_set(&mhi_dev_ctxt->counters.outbound_acks, 0); return ret_val; } MHI_STATUS process_SYSERR_transition(mhi_device_ctxt *mhi_dev_ctxt, @@ -756,10 +759,18 @@ MHI_STATUS process_AMSS_transition(mhi_device_ctxt *mhi_dev_ctxt, } void delayed_m3(struct work_struct *work) { + int retry = 0; struct delayed_work *del_work = to_delayed_work(work); mhi_device_ctxt *mhi_dev_ctxt = container_of(del_work, mhi_device_ctxt, m3_work); - mhi_initiate_m3(mhi_dev_ctxt); + while (mhi_initiate_m3(mhi_dev_ctxt) == -ETIMEDOUT) + { + retry++; + if (retry > 10) + set_ap2mdm_errfatal(); + mhi_log(MHI_MSG_ERROR, "Call mhi_initiate_m3 again after 500 ms, retry %d\n", retry); + msleep(500); + } } void m0_work(struct work_struct *work) { @@ -950,6 +961,7 @@ int mhi_initiate_m3(mhi_device_ctxt *mhi_dev_ctxt) if (0 == r || -ERESTARTSYS == r) { mhi_log(MHI_MSG_INFO | MHI_DBG_POWER, "MDM failed to come out of M2.\n"); + r = -ETIMEDOUT; goto exit; } break; @@ -958,11 +970,23 @@ int mhi_initiate_m3(mhi_device_ctxt *mhi_dev_ctxt) "MHI state %d, link state %d.\n", mhi_dev_ctxt->mhi_state, mhi_dev_ctxt->flags.link_up); - if (mhi_dev_ctxt->flags.link_up) - r = -EPERM; - else + if (mhi_dev_ctxt->flags.link_up) { + write_lock_irqsave(&mhi_dev_ctxt->xfer_lock, flags); + if (mhi_dev_ctxt->flags.pending_M0) { + write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); + mhi_log(MHI_MSG_INFO, + "Pending M0 detected, aborting M3 procedure\n"); + r = -EPERM; + goto exit; + } + write_unlock_irqrestore(&mhi_dev_ctxt->xfer_lock, flags); + mhi_log(MHI_MSG_ERROR, "goto m3_pcie_off\n"); + goto m3_pcie_off; + } + else { r = 0; - goto exit; + goto exit; + } case MHI_STATE_RESET: mhi_log(MHI_MSG_INFO, "MHI in RESET turning link off and quitting\n"); @@ -1022,7 +1046,7 @@ int mhi_initiate_m3(mhi_device_ctxt *mhi_dev_ctxt) MHI_MAX_SUSPEND_TIMEOUT); mhi_dev_ctxt->counters.m3_event_timeouts++; mhi_dev_ctxt->flags.pending_M3 = 0; - r = -EAGAIN; + r = -ETIMEDOUT; goto exit; break; case -ERESTARTSYS: @@ -1035,6 +1059,7 @@ int mhi_initiate_m3(mhi_device_ctxt *mhi_dev_ctxt) "M3 completion received\n"); break; } +m3_pcie_off: mhi_deassert_device_wake(mhi_dev_ctxt); /* Turn off PCIe link*/ mhi_turn_off_pcie_link(mhi_dev_ctxt); diff --git a/drivers/mhi/modem_pktlog.c b/drivers/mhi/modem_pktlog.c new file mode 100644 index 000000000000..2348281a28e0 --- /dev/null +++ b/drivers/mhi/modem_pktlog.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2010 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "modem_pktlog.h" + +#if 0 +#define PKTLOG_MAX_LEN 256 +void pktlog_copy_buf(struct pktlog_data *pktlog, int type, void *buf) +{ + struct sk_buff *pkt; + int len; + + if (!pktlog || !pktlog->qmax) + return; + + pkt = alloc_skb(PKTLOG_MAX_LEN, + int_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!pkt) { + pr_err("%s: fail to alloc skb for pktlog buf\n", __func__); + return; + } + pkt->tstamp = ktime_get_real(); + pktpriv(pkt)->type = type; + + /*TODO: log from fmt variable prameters */ + + //skb_put(); + + skb_queue_tail(&pktlog->logq, pkt); + if (pktlog->logq->qlen > qmax) { + struct sk_buff *drop = skb_dequene(&pktlog->logq); + if (drop) + dev_kfree_skb_any(drop); + } +} +#endif + +void pktlog_queue_skb(struct pktlog_data *pktlog, unsigned char dir, + struct sk_buff *skb) +{ + struct sk_buff *pkt; + + if (!pktlog || !pktlog->qmax) + return; + + pkt = skb_clone(skb, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); + if (!pkt) { + pr_err("%s: fail to skb_clone for pktlog buf\n", __func__); + return; + } + pkt->tstamp = timespec_to_ktime(current_kernel_time()); + pktpriv(pkt)->dir = dir; + + skb_queue_tail(&pktlog->logq, pkt); + if (pktlog->logq.qlen > pktlog->qmax) { + struct sk_buff *drop = skb_dequeue(&pktlog->logq); + if (drop) + dev_kfree_skb_any(drop); + printk_ratelimited(KERN_INFO "%s: over qmax(%d)\n", __func__, + pktlog->logq.qlen); + } + wake_up(&pktlog->wq); +} + +static int pktlog_open(struct inode *inode, struct file *filp) +{ + struct pktlog_data *pktlog = filp->private_data; + + if (!pktlog) { + pr_err("%s: Invalid pktlog data\n", __func__); + return -EINVAL; + } + + if (atomic_inc_return(&pktlog->opened) >= 2) { + pr_err("%s: Not support multi user oepn(%d)\n", __func__, + atomic_read(&pktlog->opened)); + atomic_dec(&pktlog->opened); + return -EINVAL; + } + pktlog->file_hdr.snaplen = pktlog->snaplen; + pktlog->copy_file_header = true; + + pr_info("%s: qmax = %d open by %s\n", __func__, pktlog->qmax, + current->comm); + return 0; +} + +static int pktlog_release(struct inode *inode, struct file *filp) +{ + struct pktlog_data *pktlog = filp->private_data; + + pr_info("%s: qmax = %d close by %s- %d\n", __func__, pktlog->qmax, + current->comm, atomic_dec_return(&pktlog->opened)); + return 0; +} + +static unsigned int pktlog_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct pktlog_data *pktlog = filp->private_data; + + if (!pktlog) { + pr_err("%s: Invalid pktlog data\n", __func__); + return POLLERR; + } + + if (skb_queue_empty(&pktlog->logq)) + poll_wait(filp, &pktlog->wq, wait); + + return POLLIN; +} + +static ssize_t pktlog_read(struct file *filp, char *buf, size_t count, + loff_t *fpos) +{ + struct pktlog_data *pktlog = filp->private_data; + struct sk_buff *pkt; + char *p = buf; + struct pktdump_hdr *hdr = &pktlog->hdr; + struct timeval tv; + int ret; + unsigned cook_hdr_len = sizeof(struct pktdump_hdr) + - sizeof(struct pcap_hdr); + unsigned payload_len, cplen = 0; + + if (!pktlog) { + pr_err("%s: Invalid pktlog data\n", __func__); + return -EINVAL; + } + + if (pktlog->copy_file_header) { + pktlog->copy_file_header = false; + ret = copy_to_user(p, &pktlog->file_hdr, + sizeof(struct pcap_file_header)); + if (ret < 0) + printk_ratelimited(KERN_ERR + "%s: fileheader copy fail\n", __func__); + cplen += sizeof(struct pcap_file_header); + p += sizeof(struct pcap_file_header); + } + + pkt = skb_dequeue(&pktlog->logq); + if (unlikely(!pkt)) { + printk_ratelimited(KERN_ERR "%s: no log pakcets\n", __func__); + return 0; + } + + tv = ktime_to_timeval(pkt->tstamp); + hdr->pcap.tv_sec = tv.tv_sec; + hdr->pcap.tv_usec = tv.tv_usec; + hdr->pcap.len = cook_hdr_len + pkt->len; + hdr->pcap.caplen = min(hdr->pcap.len, pktlog->snaplen); + + hdr->sd.dir = pktpriv(pkt)->dir; + + ret = copy_to_user(p, hdr, sizeof(struct pktdump_hdr)); + if (ret < 0) { + printk_ratelimited(KERN_ERR "%s: pcap header copy fail\n", + __func__); + goto exit; + } + cplen += sizeof(struct pktdump_hdr); + + p += sizeof(struct pktdump_hdr); + payload_len = min(pkt->len, pktlog->snaplen - cook_hdr_len); + ret = copy_to_user(p, pkt->data, payload_len); + if (ret < 0) { + printk_ratelimited(KERN_ERR "%s: pcap data copy fail\n", + __func__); + goto exit; + } + cplen += payload_len; + +exit: + dev_kfree_skb_any(pkt); + return cplen; +} + +static ssize_t show_snaplen(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktlog_data *pktlog = dev_get_drvdata(dev); + char *p = buf; + + p += sprintf(buf, "packet log snaplen : %u\n", pktlog->snaplen); + + return p - buf; +} + +static ssize_t store_snaplen(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pktlog_data *pktlog = dev_get_drvdata(dev); + unsigned snaplen; + int ret; + + ret = kstrtouint(buf, 10, &snaplen); + if (ret) + return count; + + pktlog->snaplen = snaplen; + return count; +} + +static struct device_attribute attr_snaplen = + __ATTR(snaplen, S_IRUGO | S_IWUSR, show_snaplen, store_snaplen); + +static ssize_t show_qmax(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pktlog_data *pktlog = dev_get_drvdata(dev); + char *p = buf; + + p += sprintf(buf, "packet log queue max : %u\n", pktlog->qmax); + + return p - buf; +} + +static ssize_t store_qmax(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pktlog_data *pktlog = dev_get_drvdata(dev); + unsigned qmax; + int ret; + + ret = kstrtouint(buf, 10, &qmax); + if (ret) + return count; + + pktlog->qmax = qmax; + return count; +} + +static struct device_attribute attr_qmax = + __ATTR(qmax, S_IRUGO | S_IWUSR, show_qmax, store_qmax); + +static const struct file_operations pktlog_fops = { + .owner = THIS_MODULE, + .open = pktlog_open, + .release = pktlog_release, + .poll = pktlog_poll, + .read = pktlog_read, +}; + +static void init_pcap_fileheader(struct pktlog_data *pktlog) +{ + struct pcap_file_header *hdr = &pktlog->file_hdr; + + hdr->magic = TCPDUMP_MAGIC; + hdr->version_major = PCAP_VERSION_MAJOR; + hdr->version_minor = PCAP_VERSION_MINOR; + hdr->thiszone = 0; + hdr->sigflag = 0; + hdr->snaplen = pktlog->snaplen; + hdr->linktype = WTAP_ENCAP_USER0; +} + +struct pktlog_data *create_pktlog(char *name) +{ + struct pktlog_data *pktlog; + int ret; + char node[64] = "pktlog_"; /* /dev/pktlog/{name} */ + + pktlog = kzalloc(sizeof(struct pktlog_data), GFP_KERNEL); + if (!pktlog) { + pr_err("%s: pktlog data alloc fail\n", __func__); + return NULL; + } + + pktlog->misc.minor = MISC_DYNAMIC_MINOR; + pktlog->misc.name = strncat(node, name, 50); + pktlog->misc.fops = &pktlog_fops; + pktlog->misc.parent = NULL; + + init_waitqueue_head(&pktlog->wq); + skb_queue_head_init(&pktlog->logq); + pktlog->qmax = 0; + pktlog->snaplen = 256; + atomic_set(&pktlog->opened, 0); + + ret = misc_register(&pktlog->misc); + if (ret < 0) { + pr_err("%s: fail to register misc device '%s'\n", __func__, + pktlog->misc.name); + goto free_exit; + } + + ret = device_create_file(pktlog->misc.this_device, &attr_qmax); + if (ret) { + pr_err("%s: fail to create qmax sysfs file: %s\n", __func__, + name); + goto free_exit; + } + + ret = device_create_file(pktlog->misc.this_device, &attr_snaplen); + if (ret) { + pr_err("%s: fail to create snaplen sysfs file: %s\n", __func__, + name); + goto free_exit; + } + init_pcap_fileheader(pktlog); + pr_info("%s: probed - %s\n", __func__, name); + + return pktlog; + +free_exit: + kfree(pktlog); + return NULL; +} + +void remove_pktlog(struct pktlog_data *pktlog) +{ + if (!pktlog) + return; + + device_remove_file(pktlog->misc.this_device, &attr_qmax); + misc_deregister(&pktlog->misc); + kfree(pktlog); +} diff --git a/drivers/mhi/modem_pktlog.h b/drivers/mhi/modem_pktlog.h new file mode 100644 index 000000000000..4adddb945f03 --- /dev/null +++ b/drivers/mhi/modem_pktlog.h @@ -0,0 +1,105 @@ +#ifndef __MODEM_PKTLOG_H__ +#define __MODEM_PKTLOG_H__ + +#ifdef CONFIG_DEBUG_PKTLOG + +#include + +struct pktbuf_private { + unsigned char dir; +} __packed; +#define pktpriv(pkt) ((struct pktbuf_private *)&pkt->cb) + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +#define DLT_LINUX_SLL 113 +#define WTAP_ENCAP_USER0 147 /* sipc5 header */ + +struct pcap_file_header { + unsigned magic; + unsigned short version_major; + unsigned short version_minor; + int thiszone; + unsigned sigflag; + unsigned snaplen; + unsigned linktype; +} __packed; + +struct pcap_hdr { + unsigned tv_sec; + unsigned tv_usec; + unsigned caplen; + unsigned len; +} __packed; + +#define SLL_ADDRLEN 8 +struct sll_hdr { + unsigned short pkttype; + unsigned short hatype; + unsigned short halen; + unsigned char addr[SLL_ADDRLEN]; + unsigned short protocol; +} __packed; + +struct sipc_debug { + unsigned char dir; +} __packed; + +struct pktdump_hdr { + struct pcap_hdr pcap; + struct sipc_debug sd; +} __packed; + +struct pktlog_data { + struct miscdevice misc; + atomic_t opened; + wait_queue_head_t wq; + + unsigned qmax; + unsigned snaplen; + + struct sk_buff_head logq; + + bool copy_file_header; + struct pcap_file_header file_hdr; + struct pktdump_hdr hdr; +}; + +enum { + PKTLOG_BOTTOM, /* to/from phy layer */ + PKTLOG_TOP, /* to/from network/ril layer */ + PKTLOG_TEXT, +}; + +#define PKT_TX 0x10 +#define PKT_RX 0x20 +#define PKT_IP 0x40 + +#define PKT_BOT 0x0 +#define PKT_TOP 0xF + + +extern struct pktlog_data *create_pktlog(char *name); +extern void remove_pktlog(struct pktlog_data *pktlog); +extern void pktlog_queue_skb(struct pktlog_data *pktlog, unsigned char dir, + struct sk_buff *skb); + +#define pktlog_tx_bottom_skb(pktlog, skb) pktlog_queue_skb(pktlog, (PKT_TX | PKT_BOT) , skb) +#define pktlog_tx_top_skb(pktlog, skb) pktlog_queue_skb(pktlog, (PKT_TX | PKT_TOP) , skb) +#define pktlog_rx_bottom_skb(pktlog, skb) pktlog_queue_skb(pktlog, (PKT_RX | PKT_BOT) , skb) +#define pktlog_rx_top_skb(pktlog, skb) pktlog_queue_skb(pktlog, (PKT_RX | PKT_TOP) , skb) +#define pktlog_text_buf(pktlog, buf) do {} while(0) + +#else /* else of DEBUG_PKTLOG */ +inline static struct pktlog_data *create_pktlog(char *name) { return NULL; } +#define remove_pktlog(pktlog) do {} while(0) +#define pktlog_tx_bottom_skb(pktlog, skb) do {} while(0) +#define pktlog_tx_top_skb(pktlog, skb) do {} while(0) +#define pktlog_rx_bottom_skb(pktlog, skb) do {} while(0) +#define pktlog_rx_top_skb(pktlog, skb) do {} while(0) +#define pktlog_text_buf(pktlog, buf) do {} while(0) +#endif /* end of DEBUG_PKTLOG */ + +#endif diff --git a/drivers/mhi/msm_rmnet_mhi.c b/drivers/mhi/msm_rmnet_mhi.c index 6ef3ec58e973..81066e69cdf0 100644 --- a/drivers/mhi/msm_rmnet_mhi.c +++ b/drivers/mhi/msm_rmnet_mhi.c @@ -35,6 +35,10 @@ #include "mhi.h" +#ifdef CONFIG_DEBUG_PKTLOG +#include "modem_pktlog.h" +#endif + #define RMNET_MHI_DRIVER_NAME "rmnet_mhi" #define RMNET_MHI_DEV_NAME "rmnet_mhi%d" #define MHI_DEFAULT_MTU (4096 - 512) @@ -80,6 +84,10 @@ static void *mhi_rmnet_ipc_log; "[%s] " _msg, __func__, ##__VA_ARGS__); \ } while (0) +#ifdef CONFIG_DEBUG_PKTLOG +struct pktlog_data *pktlog; +#endif + #ifdef CONFIG_MHI_RMNET_DUMP void mhi_rmnet_dump_log(int log_lvl, const char *prefix_str, size_t len, const void *buf) @@ -410,6 +418,11 @@ static int rmnet_mhi_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_MHI_RMNET_DUMP mhi_rmnet_dump_log(RMNET_DBG_VERBOSE, "mhi_rmnet poll[RX]: ", (skb->len > 16 ? 16 : skb->len), skb->data); #endif + +#ifdef CONFIG_DEBUG_PKTLOG + pktlog_rx_bottom_skb(pktlog, skb); +#endif + netif_receive_skb(skb); /* Statistics */ @@ -918,6 +931,11 @@ static int rmnet_mhi_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef CONFIG_MHI_RMNET_DUMP mhi_rmnet_dump_log(RMNET_DBG_VERBOSE, "mhi_rmnet xmit[TX]: ", (skb->len > 16 ? 16 : skb->len), skb->data); #endif + +#ifdef CONFIG_DEBUG_PKTLOG + pktlog_tx_bottom_skb(pktlog, skb); +#endif + /* Lets map it first! */ dma_addr = dma_map_single(&(dev->dev), skb->data, skb->len, DMA_TO_DEVICE); @@ -1163,6 +1181,14 @@ int rmnet_mhi_probe(struct platform_device *dev) "Failed to create IPC logging context\n"); } +#ifdef CONFIG_DEBUG_PKTLOG + pktlog = create_pktlog("mhi"); + if (!pktlog) { + mhi_rmnet_log(RMNET_DBG_ERROR, + "Failed to create pktlog\n"); + } +#endif + for (index = 0; index < MHI_RMNET_DEVICE_COUNT; index++) { mhi_rmnet_devices[index] = alloc_netdev(sizeof(struct rmnet_mhi_private), diff --git a/drivers/misc/mipi-lli/exynos-mipi-lli.c b/drivers/misc/mipi-lli/exynos-mipi-lli.c index bb0fd300b127..d454bda4c3ec 100644 --- a/drivers/misc/mipi-lli/exynos-mipi-lli.c +++ b/drivers/misc/mipi-lli/exynos-mipi-lli.c @@ -498,10 +498,12 @@ static int exynos_lli_intr_enable(struct mipi_lli *lli) if (mipi_lli_suspended()) return -1; - lli_intr = readl(lli->regs + EXYNOS_DME_LLI_INTR_ENABLE); + if((atomic_read(&lli->state) != LLI_UNMOUNTED) && lli->is_clk_enabled) { + lli_intr = readl(lli->regs + EXYNOS_DME_LLI_INTR_ENABLE); - if (lli_intr != 0x3FFFF) - writel(0x3FFFF, lli->regs + EXYNOS_DME_LLI_INTR_ENABLE); + if (lli_intr != 0x3FFFF) + writel(0x3FFFF, lli->regs + EXYNOS_DME_LLI_INTR_ENABLE); + } return 0; } diff --git a/drivers/misc/modem_v1/Kconfig b/drivers/misc/modem_v1/Kconfig index 9f70cccfcef4..54932dd146d6 100644 --- a/drivers/misc/modem_v1/Kconfig +++ b/drivers/misc/modem_v1/Kconfig @@ -10,6 +10,11 @@ config BOOT_DEVICE_SPI depends on SEC_MODEM_V1 default n +config LINK_DEVICE_SPI + bool "link device: SPI" + depends on SEC_MODEM_V1 + default n + config LINK_DEVICE_MEMORY bool "Memory-type (i.e. shared memory) interface medium" depends on SEC_MODEM_V1 @@ -113,7 +118,7 @@ config UMTS_MODEM_SS300 config UMTS_MODEM_SS333 bool "Samsung SS333 modem" - select BOOT_DEVICE_SPI + select LINK_DEVICE_SPI select LINK_DEVICE_LLI select LINK_POWER_MANAGEMENT_WITH_FSM select LINK_CONTROL_MSG_COMMAND diff --git a/drivers/misc/modem_v1/Makefile b/drivers/misc/modem_v1/Makefile index abd13bcbeed1..16cc2c12272a 100644 --- a/drivers/misc/modem_v1/Makefile +++ b/drivers/misc/modem_v1/Makefile @@ -4,7 +4,9 @@ EXTRA_CFLAGS += -Idrivers/misc/modem_v1 obj-y += modem_main.o modem_variation.o modem_io_device.o modem_utils.o -obj-$(CONFIG_LINK_DEVICE_MEMORY) += link_device_memory_main.o \ +obj-$(CONFIG_LINK_DEVICE_MEMORY) += link_device_memory.o \ + link_device_bootdump.o \ + link_device_memory_main.o \ link_device_memory_snapshot.o \ link_device_memory_flow_control.o \ link_device_memory_debug.o @@ -21,6 +23,7 @@ obj-$(CONFIG_LINK_DEVICE_SHMEM) += link_device_shmem.o obj-$(CONFIG_LINK_DEVICE_HSIC) += link_device_hsic.o obj-$(CONFIG_BOOT_DEVICE_SPI) += boot_device_spi.o +obj-$(CONFIG_LINK_DEVICE_SPI) += link_device_spi.o obj-$(CONFIG_UMTS_MODEM_SS222) += modem_ctrl_ss222.o obj-$(CONFIG_UMTS_MODEM_SS300) += modem_ctrl_ss300.o diff --git a/drivers/misc/modem_v1/docs/sbd_rx_flow.dot b/drivers/misc/modem_v1/docs/sbd_rx_flow.dot new file mode 100644 index 000000000000..3e0d7619d1d2 --- /dev/null +++ b/drivers/misc/modem_v1/docs/sbd_rx_flow.dot @@ -0,0 +1,178 @@ +digraph mem_rx { +graph [ + label="\n\n\n" + labelloc="top" + fontname="Helvetica" + fontsize=20 +]; + +node [shape=box fontname="Helvetica"]; + +edge [fontname="Helvetica"]; + +node [] + subgraph irq_handling { + node [] + mem_irq_handler [ + label="mem_irq_handler" + URL="@ref mem_irq_handler" + ]; + + mem_rx_task [ + label="mem_rx_task" + URL="@ref mem_rx_task" + ]; + + udl_rx_work [ + label="udl_rx_work" + URL="@ref udl_rx_work" + ]; + + ipc_rx_func [ + label="ipc_rx_func" + URL="@ref ipc_rx_func" + ]; + + edge [color="red:green4:blue" fontcolor=black]; + mem_irq_handler -> mem_rx_task [ + label="Tasklet" + ]; + + edge [color=blue fontcolor=blue]; + mem_rx_task -> udl_rx_work [ + label="Delayed\nWork" + arrowhead=vee + style=dotted + ]; + + udl_rx_work -> ipc_rx_func [ + label="Process\nContext" + ]; + + edge [color="red:green4" fontcolor=brown]; + mem_rx_task -> ipc_rx_func [ + label="Tasklet\nContext" + ]; + } + + subgraph rx_processing { + node [] + mem_cmd_handler [ + label="mem_cmd_handler" + URL="@ref mem_cmd_handler" + ]; + + recv_ipc_frames [ + label="recv_ipc_frames" + URL="@ref recv_ipc_frames" + ]; + + rx_frames_from_dev [ + label="rx_frames_from_dev" + URL="@ref rx_frames_from_dev" + ]; + + rxq_read [ + label="rxq_read" + URL="@ref rxq_read" + ]; + + schedule_link_to_demux [ + label="schedule_link_to_demux" + URL="@ref schedule_link_to_demux" + ]; + + link_to_demux_work [ + label="link_to_demux_work" + URL="@ref link_to_demux_work" + ]; + + pass_skb_to_demux [ + label="pass_skb_to_demux" + URL="@ref pass_skb_to_demux" + ]; + + skb_rxq [ + shape=record + label="| |skb_rxq| |" + color=green4 + fontcolor=green4 + ]; + + edge [color=black fontcolor=black]; + ipc_rx_func -> mem_cmd_handler [ + label="command" + ]; + + edge [color="red:green4:blue" fontcolor=black]; + ipc_rx_func -> recv_ipc_frames [ + label="while (msb)" + ]; + + recv_ipc_frames -> rx_frames_from_dev [ + label="1. for (each IPC device)" + ]; + + rx_frames_from_dev -> rxq_read [ + label="2.\nwhile (rcvd < size)" + ]; + + edge [color=blue fontcolor=blue]; + rxq_read -> rx_frames_from_dev [ + label="2-1.\nUDL skb\n[process]" + ]; + + rx_frames_from_dev -> pass_skb_to_demux [ + label="2-2.\nUDL skb\n[process]" + ]; + + edge [color="red:green4" fontcolor=brown]; + rxq_read -> rx_frames_from_dev [ + label="2-1.\nFMT skb\nRFS skb\nPS skb\n[tasklet]" + ]; + + edge [color=red fontcolor=red]; + rx_frames_from_dev -> pass_skb_to_demux [ + label="2-2.\nFMT skb\nRFS skb\n[tasklet]" + ]; + + edge [color=green4 fontcolor=green4]; + rx_frames_from_dev -> skb_rxq:f1 [ + label="2-2.\nPS skb\n[tasklet]" + arrowhead=vee + style=dashed + ]; + + edge [color="red:green4" fontcolor=brown]; + rx_frames_from_dev -> recv_ipc_frames [ + label="3. Return" + ]; + + edge [color=green4 fontcolor=green4]; + recv_ipc_frames -> schedule_link_to_demux [ + label="4. Scheduling" + ]; + + edge [color="red:green4" fontcolor=brown]; + recv_ipc_frames -> ipc_rx_func [ + label="5. Return" + ]; + + edge [color=green4 fontcolor=green4]; + schedule_link_to_demux -> link_to_demux_work [ + label="6. Delayed\nwork\n[process]" + arrowhead=vee + style=dotted + ]; + + skb_rxq:f0 -> link_to_demux_work [ + label="6-1.\nPS skb" + arrowhead=vee + style=dashed + ]; + + link_to_demux_work -> pass_skb_to_demux [ + label="6-2.\nPS skb" + ]; + } +} diff --git a/drivers/misc/modem_v1/docs/sbd_tx_flow.dot b/drivers/misc/modem_v1/docs/sbd_tx_flow.dot new file mode 100644 index 000000000000..19b8e410bee7 --- /dev/null +++ b/drivers/misc/modem_v1/docs/sbd_tx_flow.dot @@ -0,0 +1,104 @@ +digraph mem_tx { +graph [ + label="\n\n\n" + labelloc="top" + fontname="Helvetica" + fontsize=20 +]; + +node [shape=box fontname="Helvetica"]; + +edge [fontname="Helvetica"]; + +node [] + mem_send [ + label="mem_send" + URL="@ref mem_send" + ]; + + xmit_udl [ + label="xmit_udl" + URL="@ref xmit_udl" + ]; + + xmit_ipc [ + label="xmit_ipc" + URL="@ref xmit_ipc" + ]; + + skb_txq [ + shape=record + label="| |skb_txq| |" + ]; + + start_tx_timer [ + label="start_tx_timer" + URL="@ref start_tx_timer" + ]; + + tx_timer_func [ + label="tx_timer_func" + URL="@ref tx_timer_func" + ]; + + tx_frames_to_dev [ + label="tx_frames_to_dev" + URL="@ref tx_frames_to_dev" + ]; + + txq_write [ + label="txq_write" + URL="@ref txq_write" + ]; + +edge [color=blue fontcolor=blue]; + mem_send -> xmit_udl [ + label="1. UDL frame\n(skb)" + ]; + + xmit_udl -> skb_txq:f1 [ + label="2. skb_queue_tail\n(UDL frame skb)" + arrowhead=vee + style=dashed + ]; + + xmit_udl -> start_tx_timer [ + label="3. Scheduling" + ]; + +edge [color=brown fontcolor=brown]; + mem_send -> xmit_ipc [ + label="1. IPC frame\n(skb)" + ]; + + xmit_ipc -> skb_txq:f1 [ + label="2. skb_queue_tail\n(IPC frame skb)" + arrowhead=vee + style=dashed + ]; + + xmit_ipc -> start_tx_timer [ + label="3. Scheduling" + ]; + +edge [color=black fontcolor=black]; + start_tx_timer -> tx_timer_func [ + label="4. HR timer" + arrowhead=vee + style=dotted + ]; + + tx_timer_func -> tx_frames_to_dev [ + label="for (every IPC device)" + ]; + + skb_txq:f0 -> tx_frames_to_dev [ + label="5. UDL/IPC frame\n(skb)" + arrowhead=vee + style=dashed + ]; + + tx_frames_to_dev -> txq_write [ + label="6. UDL/IPC frame\n(skb)" + ]; +} diff --git a/drivers/misc/modem_v1/include/sbd.h b/drivers/misc/modem_v1/include/sbd.h index 692814f231d2..3ede6b276b86 100644 --- a/drivers/misc/modem_v1/include/sbd.h +++ b/drivers/misc/modem_v1/include/sbd.h @@ -438,6 +438,7 @@ int init_sbd_link(struct sbd_link_device *sl); int sbd_pio_tx(struct sbd_ring_buffer *rb, struct sk_buff *skb); struct sk_buff *sbd_pio_rx(struct sbd_ring_buffer *rb); +int tx_frames_to_rb(struct sbd_ring_buffer *rb); #define SBD_UL_LIMIT 16 /* Uplink burst limit */ diff --git a/drivers/misc/modem_v1/link_device_bootdump.c b/drivers/misc/modem_v1/link_device_bootdump.c new file mode 100644 index 000000000000..ccd2dece66bb --- /dev/null +++ b/drivers/misc/modem_v1/link_device_bootdump.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#include "modem_prj.h" +#include "modem_utils.h" +#include "link_device_memory.h" + +static inline int check_udl_space(struct mem_link_device *mld, + struct mem_ipc_device *dev, + unsigned int qsize, unsigned int in, + unsigned int out, unsigned int count) +{ + struct link_device *ld = &mld->link_dev; + unsigned int space; + + if (!circ_valid(qsize, in, out)) { + mif_err("%s: ERR! Invalid %s_TXQ{qsize:%d in:%d out:%d}\n", + ld->name, dev->name, qsize, in, out); + return -EIO; + } + + space = circ_get_space(qsize, in, out); + if (unlikely(space < count)) { + mif_err("%s: NOSPC in %s_TXQ{qsize:%d in:%d " + "out:%d space:%d count:%d}\n", ld->name, + dev->name, qsize, in, out, space, count); + return -ENOSPC; + } + + return 0; +} + +/** +@brief copy UDL data in an skb to a circular TXQ + +Enqueues a frame in @b @@skb to the @b @@dev TXQ if there is enough space in the +TXQ, then releases @b @@skb. + +@param mld the pointer to a mem_link_device instance +@param dev the pointer to a mem_ipc_device instance +@param skb the pointer to an sk_buff instance + +@retval "> 0" the size of the frame written in the TXQ +@retval "< 0" an error code (-EBUSY, -ENOSPC, or -EIO) +*/ +static inline int udl_write(struct mem_link_device *mld, + struct mem_ipc_device *dev, struct sk_buff *skb) +{ + unsigned int count = skb->len; + char *src = skb->data; + char *dst = get_txq_buff(dev); + unsigned int qsize = get_txq_buff_size(dev); + unsigned int in = get_txq_head(dev); + unsigned int out = get_txq_tail(dev); + int space; + + space = check_udl_space(mld, dev, qsize, in, out, count); + if (unlikely(space < 0)) + return space; + + barrier(); + + circ_write(dst, src, qsize, in, count); + + barrier(); + + set_txq_head(dev, circ_new_ptr(qsize, in, count)); + + /* Commit the item before incrementing the head */ + smp_mb(); + + return count; +} + +/** +@brief transmit a BOOT/DUMP data packet + +@param mld the pointer to a mem_link_device instance +@param ch the channel ID +@param skb the pointer to an skb that will be transmitted + +@retval "> 0" the size of the data in @b @@skb +*/ +int xmit_udl(struct mem_link_device *mld, struct io_device *iod, + enum sipc_ch_id ch, struct sk_buff *skb) +{ + int ret; + struct mem_ipc_device *dev = mld->dev[IPC_RAW]; + int count = skb->len; + int tried = 0; + + while (1) { + ret = udl_write(mld, dev, skb); + if (ret == count) + break; + + if (ret != -ENOSPC) + goto exit; + + tried++; + if (tried >= 20) + goto exit; + + if (in_interrupt()) + mdelay(50); + else + msleep(50); + } + + dev_kfree_skb_any(skb); + +exit: + return ret; +} + +/** +@brief function for the @b xmit_boot method in a link_device instance + +Copies a CP bootloader binary in a user space to the BOOT region for CP + +@param ld the pointer to a link_device instance +@param iod the pointer to an io_device instance +@param arg the pointer to a modem_firmware instance + +@retval "= 0" if NO error +@retval "< 0" an error code +*/ +int mem_xmit_boot(struct link_device *ld, struct io_device *iod, + unsigned long arg) +{ + struct mem_link_device *mld = to_mem_link_device(ld); + void __iomem *dst; + void __user *src; + int err; + struct modem_firmware mf; + + /** + * Get the information about the boot image + */ + memset(&mf, 0, sizeof(struct modem_firmware)); + + err = copy_from_user(&mf, (const void __user *)arg, sizeof(mf)); + if (err) { + mif_err("%s: ERR! INFO copy_from_user fail\n", ld->name); + return -EFAULT; + } + + /** + * Check the size of the boot image + */ + if (mf.size > mld->boot_size) { + mif_err("%s: ERR! Invalid BOOT size %d\n", ld->name, mf.size); + return -EINVAL; + } + mif_err("%s: BOOT size = %d bytes\n", ld->name, mf.size); + + /** + * Copy the boot image to the BOOT region + */ + memset(mld->boot_base, 0, mld->boot_size); + + dst = (void __iomem *)mld->boot_base; + src = (void __user *)mf.binary; + err = copy_from_user(dst, src, mf.size); + if (err) { + mif_err("%s: ERR! BOOT copy_from_user fail\n", ld->name); + return err; + } + + return 0; +} + +/** +@brief function for the @b dload_start method in a link_device instance + +Set all flags and environments for CP binary download + +@param ld the pointer to a link_device instance +@param iod the pointer to an io_device instance +*/ +int mem_start_download(struct link_device *ld, struct io_device *iod) +{ + struct mem_link_device *mld = to_mem_link_device(ld); + + reset_ipc_map(mld); + + if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_BOOT)) + sbd_deactivate(&mld->sbd_link_dev); + + if (mld->attrs & LINK_ATTR(LINK_ATTR_BOOT_ALIGNED)) + ld->aligned = true; + else + ld->aligned = false; + + if (mld->dpram_magic) { + unsigned int magic; + + set_magic(mld, MEM_BOOT_MAGIC); + magic = get_magic(mld); + if (magic != MEM_BOOT_MAGIC) { + mif_err("%s: ERR! magic 0x%08X != BOOT_MAGIC 0x%08X\n", + ld->name, magic, MEM_BOOT_MAGIC); + return -EFAULT; + } + mif_err("%s: magic == 0x%08X\n", ld->name, magic); + } + + return 0; +} + +/** +@brief function for the @b firm_update method in a link_device instance + +Updates download information for each CP binary image by copying download +information for a CP binary image from a user space to a local buffer in a +mem_link_device instance. + +@param ld the pointer to a link_device instance +@param iod the pointer to an io_device instance +@param arg the pointer to a std_dload_info instance +*/ +int mem_update_firm_info(struct link_device *ld, struct io_device *iod, + unsigned long arg) +{ + struct mem_link_device *mld = to_mem_link_device(ld); + int ret; + + ret = copy_from_user(&mld->img_info, (void __user *)arg, + sizeof(struct std_dload_info)); + if (ret) { + mif_err("ERR! copy_from_user fail!\n"); + return -EFAULT; + } + + return 0; +} + +/** +@brief function for the @b dump_start method in a link_device instance + +@param ld the pointer to a link_device instance +@param iod the pointer to an io_device instance +*/ +int mem_start_upload(struct link_device *ld, struct io_device *iod) +{ + struct mem_link_device *mld = to_mem_link_device(ld); + + if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_DUMP)) + sbd_deactivate(&mld->sbd_link_dev); + + reset_ipc_map(mld); + + if (mld->attrs & LINK_ATTR(LINK_ATTR_DUMP_ALIGNED)) + ld->aligned = true; + else + ld->aligned = false; + + if (mld->dpram_magic) { + unsigned int magic; + + set_magic(mld, MEM_DUMP_MAGIC); + magic = get_magic(mld); + if (magic != MEM_DUMP_MAGIC) { + mif_err("%s: ERR! magic 0x%08X != DUMP_MAGIC 0x%08X\n", + ld->name, magic, MEM_DUMP_MAGIC); + return -EFAULT; + } + mif_err("%s: magic == 0x%08X\n", ld->name, magic); + } + + return 0; +} + diff --git a/drivers/misc/modem_v1/link_device_lli.c b/drivers/misc/modem_v1/link_device_lli.c index de5f79dc6ef1..eb126501a763 100644 --- a/drivers/misc/modem_v1/link_device_lli.c +++ b/drivers/misc/modem_v1/link_device_lli.c @@ -1,11 +1,3 @@ -/** -@file link_device_lli.c -@brief functions for a pseudo shared-memory based on a chip-to-chip - (C2C) interface -@date 2014/02/05 -@author Hankook Jang (hankook.jang@samsung.com) -*/ - /* * Copyright (C) 2010 Samsung Electronics. * @@ -560,15 +552,10 @@ static int init_pm(struct mem_link_device *mld) #endif #endif -static void lli_link_ready(struct link_device *ld) -{ - mif_err("%s: PM %s <%pf>\n", ld->name, FUNC, CALLER); - stop_pm(ld_to_mem_link_device(ld)); -} - static void lli_link_reset(struct link_device *ld) { mif_err("%s: PM %s <%pf>\n", ld->name, FUNC, CALLER); + mipi_lli_intr_enable(); mipi_lli_reset(); } @@ -792,7 +779,6 @@ struct link_device *lli_create_link_device(struct platform_device *pdev) ld = &mld->link_dev; - ld->ready = lli_link_ready; ld->reset = lli_link_reset; ld->reload = lli_link_reload; ld->off = lli_link_off; diff --git a/drivers/misc/modem_v1/link_device_memory.c b/drivers/misc/modem_v1/link_device_memory.c new file mode 100644 index 000000000000..b3cab7edad44 --- /dev/null +++ b/drivers/misc/modem_v1/link_device_memory.c @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#include "modem_prj.h" +#include "modem_utils.h" +#include "link_device_memory.h" + +/** +@brief copy each IPC link frame from a circular queue to an skb + +1) Analyzes a link frame header and get the size of the current link frame.\n +2) Allocates a socket buffer (skb).\n +3) Extracts a link frame from the current @b $out (tail) pointer in the @b + @@dev RXQ up to @b @@in (head) pointer in the @b @@dev RXQ, then copies it + to the skb allocated in the step 2.\n +4) Updates the TAIL (OUT) pointer in the @b @@dev RXQ.\n + +@param mld the pointer to a mem_link_device instance +@param dev the pointer to a mem_ipc_device instance (IPC_FMT, etc.) +@param in the IN (HEAD) pointer value of the @b @@dev RXQ + +@retval "struct sk_buff *" if there is NO error +@retval "NULL" if there is ANY error +*/ +static struct sk_buff *rxq_read(struct mem_link_device *mld, + struct mem_ipc_device *dev, + unsigned int in) +{ + struct link_device *ld = &mld->link_dev; + struct sk_buff *skb; + char *src = get_rxq_buff(dev); + unsigned int qsize = get_rxq_buff_size(dev); + unsigned int out = get_rxq_tail(dev); + unsigned int rest = circ_get_usage(qsize, in, out); + unsigned int len; + char hdr[SIPC5_MIN_HEADER_SIZE]; + + /* Copy the header in a frame to the header buffer */ + circ_read(hdr, src, qsize, out, SIPC5_MIN_HEADER_SIZE); + + /* Check the config field in the header */ + if (unlikely(!sipc5_start_valid(hdr))) { + mif_err("%s: ERR! %s BAD CFG 0x%02X (in:%d out:%d rest:%d)\n", + ld->name, dev->name, hdr[SIPC5_CONFIG_OFFSET], + in, out, rest); + goto bad_msg; + } + + /* Verify the length of the frame (data + padding) */ + len = sipc5_get_total_len(hdr); + if (unlikely(len > rest)) { + mif_err("%s: ERR! %s BAD LEN %d > rest %d\n", + ld->name, dev->name, len, rest); + goto bad_msg; + } + + /* Allocate an skb */ + skb = mem_alloc_skb(len); + if (!skb) { + mif_err("%s: ERR! %s mem_alloc_skb(%d) fail\n", + ld->name, dev->name, len); + goto no_mem; + } + + /* Read the frame from the RXQ */ + circ_read(skb_put(skb, len), src, qsize, out, len); + + /* Update tail (out) pointer to the frame to be read in the future */ + set_rxq_tail(dev, circ_new_ptr(qsize, out, len)); + + /* Finish reading data before incrementing tail */ + smp_mb(); + + return skb; + +bad_msg: + mif_err("%s: %s%s%s: ERR! BAD MSG: %02x %02x %02x %02x\n", + FUNC, ld->name, arrow(RX), ld->mc->name, + hdr[0], hdr[1], hdr[2], hdr[3]); + set_rxq_tail(dev, in); /* Reset tail (out) pointer */ + modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); + +no_mem: + return NULL; +} + +/*============================================================================*/ + +/** +@brief pass a socket buffer to the DEMUX layer + +Invokes the recv_skb_single method in the io_device instance to perform +receiving IPC messages from each skb. + +@param mld the pointer to a mem_link_device instance +@param skb the pointer to an sk_buff instance + +@retval "> 0" if succeeded to pass an @b @@skb to the DEMUX layer +@retval "< 0" an error code +*/ +static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) +{ + struct link_device *ld = &mld->link_dev; + struct io_device *iod = skbpriv(skb)->iod; + int ret; + u8 ch = skbpriv(skb)->sipc_ch; + + if (unlikely(!iod)) { + mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); + dev_kfree_skb_any(skb); + modemctl_notify_event(MDM_CRASH_INVALID_IOD); + return; + } + + log_ipc_pkt(LNK_RX, ch, skb); + + ret = iod->recv_skb_single(iod, ld, skb); + if (unlikely(ret < 0)) { + struct modem_ctl *mc = ld->mc; + mif_err_limited("%s: %s<-%s: ERR! %s->recv_skb fail (%d)\n", + ld->name, iod->name, mc->name, iod->name, ret); + dev_kfree_skb_any(skb); + } +} + +inline void link_to_demux(struct mem_link_device *mld) +{ + int i; + + for (i = 0; i < MAX_SIPC5_DEVICES; i++) { + struct mem_ipc_device *dev = mld->dev[i]; + struct sk_buff_head *skb_rxq = dev->skb_rxq; + + while (1) { + struct sk_buff *skb; + + skb = skb_dequeue(skb_rxq); + if (!skb) + break; + + pass_skb_to_demux(mld, skb); + } + } +} + +/** +@brief pass socket buffers in every skb_rxq to the DEMUX layer + +@param ws the pointer to a work_struct instance + +@see schedule_link_to_demux() +@see rx_frames_from_dev() +@see mem_create_link_device() +*/ +void link_to_demux_work(struct work_struct *ws) +{ + struct link_device *ld; + struct mem_link_device *mld; + + ld = container_of(ws, struct link_device, rx_delayed_work.work); + mld = to_mem_link_device(ld); + + link_to_demux(mld); +} + +static inline void schedule_link_to_demux(struct mem_link_device *mld) +{ + struct link_device *ld = &mld->link_dev; + struct delayed_work *dwork = &ld->rx_delayed_work; + + /*queue_delayed_work(ld->rx_wq, dwork, 0);*/ + queue_work_on(7, ld->rx_wq, &dwork->work); +} + +/** +@brief extract all IPC link frames from a circular queue + +In a while loop,\n +1) Receives each IPC link frame stored in the @b @@dev RXQ.\n +2) If the frame is a PS (network) data frame, stores it to an skb_rxq and + schedules a delayed work for PS data reception.\n +3) Otherwise, passes it to the DEMUX layer immediately.\n + +@param mld the pointer to a mem_link_device instance +@param dev the pointer to a mem_ipc_device instance (IPC_FMT, etc.) + +@retval "> 0" if valid data received +@retval "= 0" if no data received +@retval "< 0" if ANY error +*/ +static int rx_frames_from_dev(struct mem_link_device *mld, + struct mem_ipc_device *dev) +{ + struct link_device *ld = &mld->link_dev; + struct sk_buff_head *skb_rxq = dev->skb_rxq; + unsigned int qsize = get_rxq_buff_size(dev); + unsigned int in = get_rxq_head(dev); + unsigned int out = get_rxq_tail(dev); + unsigned int size = circ_get_usage(qsize, in, out); + int rcvd = 0; + + if (unlikely(circ_empty(in, out))) + return 0; + + while (rcvd < size) { + struct sk_buff *skb; + u8 ch; + struct io_device *iod; + + skb = rxq_read(mld, dev, in); + if (!skb) + break; + + ch = sipc5_get_ch(skb->data); + iod = link_get_iod_with_channel(ld, ch); + if (!iod) { + mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); + dev_kfree_skb_any(skb); + modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); + break; + } + + /* Record the IO device and the link device into the &skb->cb */ + skbpriv(skb)->iod = iod; + skbpriv(skb)->ld = ld; + + skbpriv(skb)->lnk_hdr = iod->link_header; + skbpriv(skb)->sipc_ch = ch; + + /* The $rcvd must be accumulated here, because $skb can be freed + in pass_skb_to_demux(). */ + rcvd += skb->len; + + if (likely(sipc_ps_ch(ch))) + skb_queue_tail(skb_rxq, skb); + else + pass_skb_to_demux(mld, skb); + } + + if (rcvd < size) { + struct link_device *ld = &mld->link_dev; + mif_err("%s: WARN! rcvd %d < size %d\n", ld->name, rcvd, size); + } + + return rcvd; +} + +/** +@brief receive all @b IPC message frames in all RXQs + +In a for loop,\n +1) Checks any REQ_ACK received.\n +2) Receives all IPC link frames in every RXQ.\n +3) Sends RES_ACK if there was REQ_ACK from CP.\n +4) Checks any RES_ACK received.\n + +@param mld the pointer to a mem_link_device instance +@param mst the pointer to a mem_snapshot instance +*/ +void recv_ipc_frames(struct mem_link_device *mld, struct mem_snapshot *mst) +{ + int i; + u16 intr = mst->int2ap; + + for (i = 0; i < MAX_SIPC5_DEVICES; i++) { + struct mem_ipc_device *dev = mld->dev[i]; + int rcvd; + + if (req_ack_valid(dev, intr)) + recv_req_ack(mld, dev, mst); + + rcvd = rx_frames_from_dev(mld, dev); + if (rcvd < 0) + break; + + schedule_link_to_demux(mld); + + if (req_ack_valid(dev, intr)) + send_res_ack(mld, dev); + + if (res_ack_valid(dev, intr)) + recv_res_ack(mld, dev, mst); + } +} + +/** +@brief reset all member variables in every IPC device + +@param mld the pointer to a mem_link_device instance +*/ +inline void reset_ipc_map(struct mem_link_device *mld) +{ + int i; + + for (i = 0; i < MAX_SIPC5_DEVICES; i++) { + struct mem_ipc_device *dev = mld->dev[i]; + + set_txq_head(dev, 0); + set_txq_tail(dev, 0); + set_rxq_head(dev, 0); + set_rxq_tail(dev, 0); + } +} + +int mem_reset_ipc_link(struct mem_link_device *mld) +{ + struct link_device *ld = &mld->link_dev; + unsigned int magic; + unsigned int access; + int i; + + set_access(mld, 0); + set_magic(mld, 0); + + reset_ipc_map(mld); + + for (i = 0; i < MAX_SIPC5_DEVICES; i++) { + struct mem_ipc_device *dev = mld->dev[i]; + + skb_queue_purge(dev->skb_txq); + atomic_set(&dev->txq.busy, 0); + dev->req_ack_cnt[TX] = 0; + + skb_queue_purge(dev->skb_rxq); + atomic_set(&dev->rxq.busy, 0); + dev->req_ack_cnt[RX] = 0; + } + + atomic_set(&ld->netif_stopped, 0); + + set_magic(mld, MEM_IPC_MAGIC); + set_access(mld, 1); + + magic = get_magic(mld); + access = get_access(mld); + if (magic != MEM_IPC_MAGIC || access != 1) + return -EACCES; + + return 0; +} + +void remap_4mb_map_to_ipc_dev(struct mem_link_device *mld) +{ + struct link_device *ld = &mld->link_dev; + struct shmem_4mb_phys_map *map; + struct mem_ipc_device *dev; + + map = (struct shmem_4mb_phys_map *)mld->base; + + /* magic code and access enable fields */ + mld->magic = (u32 __iomem *)&map->magic; + mld->access = (u32 __iomem *)&map->access; + + /* IPC_FMT */ + dev = &mld->ipc_dev[IPC_FMT]; + + dev->id = IPC_FMT; + strcpy(dev->name, "FMT"); + + spin_lock_init(&dev->txq.lock); + atomic_set(&dev->txq.busy, 0); + dev->txq.head = &map->fmt_tx_head; + dev->txq.tail = &map->fmt_tx_tail; + dev->txq.buff = &map->fmt_tx_buff[0]; + dev->txq.size = SHM_4M_FMT_TX_BUFF_SZ; + + spin_lock_init(&dev->rxq.lock); + atomic_set(&dev->rxq.busy, 0); + dev->rxq.head = &map->fmt_rx_head; + dev->rxq.tail = &map->fmt_rx_tail; + dev->rxq.buff = &map->fmt_rx_buff[0]; + dev->rxq.size = SHM_4M_FMT_RX_BUFF_SZ; + + dev->msg_mask = MASK_SEND_FMT; + dev->req_ack_mask = MASK_REQ_ACK_FMT; + dev->res_ack_mask = MASK_RES_ACK_FMT; + + dev->tx_lock = &ld->tx_lock[IPC_FMT]; + dev->skb_txq = &ld->sk_fmt_tx_q; + + dev->rx_lock = &ld->rx_lock[IPC_FMT]; + dev->skb_rxq = &ld->sk_fmt_rx_q; + + dev->req_ack_cnt[TX] = 0; + dev->req_ack_cnt[RX] = 0; + + mld->dev[IPC_FMT] = dev; + + /* IPC_RAW */ + dev = &mld->ipc_dev[IPC_RAW]; + + dev->id = IPC_RAW; + strcpy(dev->name, "RAW"); + + spin_lock_init(&dev->txq.lock); + atomic_set(&dev->txq.busy, 0); + dev->txq.head = &map->raw_tx_head; + dev->txq.tail = &map->raw_tx_tail; + dev->txq.buff = &map->raw_tx_buff[0]; + dev->txq.size = SHM_4M_RAW_TX_BUFF_SZ; + + spin_lock_init(&dev->rxq.lock); + atomic_set(&dev->rxq.busy, 0); + dev->rxq.head = &map->raw_rx_head; + dev->rxq.tail = &map->raw_rx_tail; + dev->rxq.buff = &map->raw_rx_buff[0]; + dev->rxq.size = SHM_4M_RAW_RX_BUFF_SZ; + + dev->msg_mask = MASK_SEND_RAW; + dev->req_ack_mask = MASK_REQ_ACK_RAW; + dev->res_ack_mask = MASK_RES_ACK_RAW; + + dev->tx_lock = &ld->tx_lock[IPC_RAW]; + dev->skb_txq = &ld->sk_raw_tx_q; + + dev->rx_lock = &ld->rx_lock[IPC_RAW]; + dev->skb_rxq = &ld->sk_raw_rx_q; + + dev->req_ack_cnt[TX] = 0; + dev->req_ack_cnt[RX] = 0; + + mld->dev[IPC_RAW] = dev; +} + diff --git a/drivers/misc/modem_v1/link_device_memory.h b/drivers/misc/modem_v1/link_device_memory.h index aa3a5ca66071..9415b1de6119 100644 --- a/drivers/misc/modem_v1/link_device_memory.h +++ b/drivers/misc/modem_v1/link_device_memory.h @@ -351,15 +351,6 @@ struct mem_link_device { cpumask_var_t tmask; /* task affinity cpu mask */ cpumask_var_t imask; /* irq affinity cpu mask */ - /** - * GPIO#, MBOX#, IRQ# for IPC - */ - unsigned int mbx_cp2ap_msg; /* MBOX# for IPC RX */ - unsigned int irq_cp2ap_msg; /* IRQ# for IPC RX */ - - unsigned int mbx_ap2cp_msg; /* MBOX# for IPC TX */ - unsigned int int_ap2cp_msg; /* INTR# for IPC TX */ - /** * Member variables for TX & RX */ @@ -368,7 +359,6 @@ struct mem_link_device { struct tasklet_struct rx_tsk; - struct hrtimer tx_timer; struct hrtimer sbd_tx_timer; /** @@ -930,9 +920,6 @@ void mem_irq_handler(struct mem_link_device *mld, struct mst_buff *msb); void __iomem *mem_vmap(phys_addr_t pa, size_t size, struct page *pages[]); void mem_vunmap(void *va); -int mem_register_boot_rgn(struct mem_link_device *mld, phys_addr_t start, - size_t size); -void mem_unregister_boot_rgn(struct mem_link_device *mld); int mem_setup_boot_map(struct mem_link_device *mld); int mem_register_ipc_rgn(struct mem_link_device *mld, phys_addr_t start, @@ -948,22 +935,9 @@ struct mem_link_device *mem_create_link_device(enum mem_iface_type type, */ #endif -/*============================================================================*/ - -#ifdef GROUP_MEM_LINK_COMMAND -/** -@addtogroup group_mem_link_command -@{ -*/ - int mem_reset_ipc_link(struct mem_link_device *mld); void mem_cmd_handler(struct mem_link_device *mld, u16 cmd); -/** -@} -*/ -#endif - /*============================================================================*/ #ifdef GROUP_MEM_FLOW_CONTROL @@ -1052,4 +1026,21 @@ static inline struct sk_buff *mem_alloc_skb(unsigned int len) return skb; } +/*============================================================================*/ + +void link_to_demux(struct mem_link_device *mld); +void link_to_demux_work(struct work_struct *ws); +void recv_ipc_frames(struct mem_link_device *mld, struct mem_snapshot *mst); +int xmit_udl(struct mem_link_device *mld, struct io_device *iod, + enum sipc_ch_id ch, struct sk_buff *skb); +int mem_xmit_boot(struct link_device *ld, struct io_device *iod, + unsigned long arg); +int mem_start_download(struct link_device *ld, struct io_device *iod); +int mem_update_firm_info(struct link_device *ld, struct io_device *iod, + unsigned long arg); +int mem_start_upload(struct link_device *ld, struct io_device *iod); +void reset_ipc_map(struct mem_link_device *mld); +void remap_4mb_map_to_ipc_dev(struct mem_link_device *mld); +void recv_sbd_ipc_frames(struct mem_link_device *mld); + #endif diff --git a/drivers/misc/modem_v1/link_device_memory_main.c b/drivers/misc/modem_v1/link_device_memory_main.c index e1d8c52c3c74..e347a5a8283d 100644 --- a/drivers/misc/modem_v1/link_device_memory_main.c +++ b/drivers/misc/modem_v1/link_device_memory_main.c @@ -1,10 +1,3 @@ -/** -@file link_device_memory_main.c -@brief common functions for all types of memory interface media -@date 2014/02/05 -@author Hankook Jang (hankook.jang@samsung.com) -*/ - /* * Copyright (C) 2011 Samsung Electronics. * @@ -32,12 +25,6 @@ static unsigned long tx_timer_ns = 1000000; module_param(tx_timer_ns, ulong, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(tx_timer_ns, "modem_v1 tx_timer period time"); -#ifdef GROUP_MEM_LINK_DEVICE -/** -@weakgroup group_mem_link_device -@{ -*/ - /** @brief common interrupt handler for all MEMORY interfaces @@ -118,7 +105,6 @@ static inline void purge_txq(struct mem_link_device *mld) struct link_device *ld = &mld->link_dev; int i; -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH /* Purge the skb_q in every TX RB */ if (ld->sbd_ipc) { struct sbd_link_device *sl = &mld->sbd_link_dev; @@ -127,7 +113,6 @@ static inline void purge_txq(struct mem_link_device *mld) skb_queue_purge(&rb->skb_q); } } -#endif /* Purge the skb_txq in every IPC device (IPC_FMT, IPC_RAW, etc.) */ for (i = 0; i < MAX_SIPC5_DEVICES; i++) { @@ -136,350 +121,6 @@ static inline void purge_txq(struct mem_link_device *mld) } } -/** -@} -*/ -#endif - -/*============================================================================*/ - -#ifdef GROUP_MEM_IPC_TX - -/** -@weakgroup group_mem_ipc_tx - -@dot -digraph mem_tx { -graph [ - label="\n\n\n" - labelloc="top" - fontname="Helvetica" - fontsize=20 -]; - -node [shape=box fontname="Helvetica"]; - -edge [fontname="Helvetica"]; - -node [] - mem_send [ - label="mem_send" - URL="@ref mem_send" - ]; - - xmit_udl [ - label="xmit_udl" - URL="@ref xmit_udl" - ]; - - xmit_ipc [ - label="xmit_ipc" - URL="@ref xmit_ipc" - ]; - - skb_txq [ - shape=record - label="| |skb_txq| |" - ]; - - start_tx_timer [ - label="start_tx_timer" - URL="@ref start_tx_timer" - ]; - - tx_timer_func [ - label="tx_timer_func" - URL="@ref tx_timer_func" - ]; - - tx_frames_to_dev [ - label="tx_frames_to_dev" - URL="@ref tx_frames_to_dev" - ]; - - txq_write [ - label="txq_write" - URL="@ref txq_write" - ]; - -edge [color=blue fontcolor=blue]; - mem_send -> xmit_udl [ - label="1. UDL frame\n(skb)" - ]; - - xmit_udl -> skb_txq:f1 [ - label="2. skb_queue_tail\n(UDL frame skb)" - arrowhead=vee - style=dashed - ]; - - xmit_udl -> start_tx_timer [ - label="3. Scheduling" - ]; - -edge [color=brown fontcolor=brown]; - mem_send -> xmit_ipc [ - label="1. IPC frame\n(skb)" - ]; - - xmit_ipc -> skb_txq:f1 [ - label="2. skb_queue_tail\n(IPC frame skb)" - arrowhead=vee - style=dashed - ]; - - xmit_ipc -> start_tx_timer [ - label="3. Scheduling" - ]; - -edge [color=black fontcolor=black]; - start_tx_timer -> tx_timer_func [ - label="4. HR timer" - arrowhead=vee - style=dotted - ]; - - tx_timer_func -> tx_frames_to_dev [ - label="for (every IPC device)" - ]; - - skb_txq:f0 -> tx_frames_to_dev [ - label="5. UDL/IPC frame\n(skb)" - arrowhead=vee - style=dashed - ]; - - tx_frames_to_dev -> txq_write [ - label="6. UDL/IPC frame\n(skb)" - ]; -} -@enddot -*/ - -/** -@weakgroup group_mem_ipc_tx -@{ -*/ - -/** -@brief check the free space in a circular TXQ - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance -@param qsize the size of the buffer in @b @@dev TXQ -@param in the IN (HEAD) pointer value of the TXQ -@param out the OUT (TAIL) pointer value of the TXQ -@param count the size of the data to be transmitted - -@retval "> 0" the size of free space in the @b @@dev TXQ -@retval "< 0" an error code -*/ -static inline int check_txq_space(struct mem_link_device *mld, - struct mem_ipc_device *dev, - unsigned int qsize, unsigned int in, - unsigned int out, unsigned int count) -{ - struct link_device *ld = &mld->link_dev; - struct modem_ctl *mc = ld->mc; - unsigned int usage; - unsigned int space; - - if (!circ_valid(qsize, in, out)) { - mif_err("%s: ERR! Invalid %s_TXQ{qsize:%d in:%d out:%d}\n", - ld->name, dev->name, qsize, in, out); - return -EIO; - } - - usage = circ_get_usage(qsize, in, out); - if (unlikely(usage > SHM_UL_USAGE_LIMIT) && cp_online(mc)) { - mif_debug("%s: CAUTION! BUSY in %s_TXQ{qsize:%d in:%d out:%d " - "usage:%d (count:%d)}\n", ld->name, dev->name, qsize, - in, out, usage, count); - return -EBUSY; - } - - space = circ_get_space(qsize, in, out); - if (unlikely(space < count)) { - if (cp_online(mc)) { - mif_err("%s: CAUTION! NOSPC in %s_TXQ{qsize:%d in:%d " - "out:%d space:%d count:%d}\n", ld->name, - dev->name, qsize, in, out, space, count); - } - return -ENOSPC; - } - - return space; -} - -/** -@brief copy data in an skb to a circular TXQ - -Enqueues a frame in @b @@skb to the @b @@dev TXQ if there is enough space in the -TXQ, then releases @b @@skb. - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance -@param skb the pointer to an sk_buff instance - -@retval "> 0" the size of the frame written in the TXQ -@retval "< 0" an error code (-EBUSY, -ENOSPC, or -EIO) -*/ -static int txq_write(struct mem_link_device *mld, struct mem_ipc_device *dev, - struct sk_buff *skb) -{ - char *src = skb->data; - unsigned int count = skb->len; - char *dst = get_txq_buff(dev); - unsigned int qsize = get_txq_buff_size(dev); - unsigned int in = get_txq_head(dev); - unsigned int out = get_txq_tail(dev); - int space; - - space = check_txq_space(mld, dev, qsize, in, out, count); - if (unlikely(space < 0)) - return space; - - barrier(); - - circ_write(dst, src, qsize, in, count); - - barrier(); - - set_txq_head(dev, circ_new_ptr(qsize, in, count)); - - /* Commit the item before incrementing the head */ - smp_mb(); - - return count; -} - -/** -@brief try to transmit all IPC frames in an skb_txq to CP - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance - -@retval "> 0" accumulated data size written to a circular TXQ -@retval "< 0" an error code -*/ -static int tx_frames_to_dev(struct mem_link_device *mld, - struct mem_ipc_device *dev) -{ - struct sk_buff_head *skb_txq = dev->skb_txq; - int tx_bytes = 0; - int ret = 0; - - while (1) { - struct sk_buff *skb; - - skb = skb_dequeue(skb_txq); - if (unlikely(!skb)) - break; - - ret = txq_write(mld, dev, skb); - if (unlikely(ret < 0)) { - /* Take the skb back to the skb_txq */ - skb_queue_head(skb_txq, skb); - break; - } - - tx_bytes += ret; - dev_kfree_skb_any(skb); - } - - return (ret < 0) ? ret : tx_bytes; -} - -static enum hrtimer_restart tx_timer_func(struct hrtimer *timer) -{ - struct mem_link_device *mld; - struct link_device *ld; - struct modem_ctl *mc; - int i; - bool need_schedule; - u16 mask; - unsigned long flags; - - mld = container_of(timer, struct mem_link_device, tx_timer); - ld = &mld->link_dev; - mc = ld->mc; - - need_schedule = false; - mask = 0; - - spin_lock_irqsave(&mc->lock, flags); - - if (unlikely(!ipc_active(mld))) - goto exit; - - if (mld->link_active) { - if (!mld->link_active(mld)) { - need_schedule = true; - goto exit; - } - } - - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - struct mem_ipc_device *dev = mld->dev[i]; - int ret; - - if (unlikely(under_tx_flow_ctrl(mld, dev))) { - ret = check_tx_flow_ctrl(mld, dev); - if (ret < 0) { - if (ret == -EBUSY || ret == -ETIME) { - need_schedule = true; - continue; - } else { - modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); - need_schedule = false; - goto exit; - } - } - } - - ret = tx_frames_to_dev(mld, dev); - if (unlikely(ret < 0)) { - if (ret == -EBUSY || ret == -ENOSPC) { - need_schedule = true; - start_tx_flow_ctrl(mld, dev); - continue; - } else { - modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); - need_schedule = false; - goto exit; - } - } - - if (ret > 0) - mask |= msg_mask(dev); - - if (!skb_queue_empty(dev->skb_txq)) - need_schedule = true; - } - - if (!need_schedule) { - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - if (!txq_empty(mld->dev[i])) { - need_schedule = true; - break; - } - } - } - - if (mask) - send_ipc_irq(mld, mask2int(mask)); - -exit: - if (need_schedule) { - ktime_t ktime = ktime_set(0, ms2ns(TX_PERIOD_MS)); - hrtimer_start(timer, ktime, HRTIMER_MODE_REL); - } - - spin_unlock_irqrestore(&mc->lock, flags); - - return HRTIMER_NORESTART; -} - static inline void start_tx_timer(struct mem_link_device *mld, struct hrtimer *timer) { @@ -516,39 +157,6 @@ static inline void cancel_tx_timer(struct mem_link_device *mld, spin_unlock_irqrestore(&mc->lock, flags); } -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH -static int tx_frames_to_rb(struct sbd_ring_buffer *rb) -{ - struct sk_buff_head *skb_txq = &rb->skb_q; - int tx_bytes = 0; - int ret = 0; - - while (1) { - struct sk_buff *skb; - - skb = skb_dequeue(skb_txq); - if (unlikely(!skb)) - break; - - ret = sbd_pio_tx(rb, skb); - if (unlikely(ret < 0)) { - /* Take the skb back to the skb_txq */ - skb_queue_head(skb_txq, skb); - break; - } - - tx_bytes += ret; - - log_ipc_pkt(LNK_TX, rb->ch, skb); - - trace_mif_event(skb, skb->len, FUNC); - - dev_kfree_skb_any(skb); - } - - return (ret < 0) ? ret : tx_bytes; -} - static enum hrtimer_restart sbd_tx_timer_func(struct hrtimer *timer) { struct mem_link_device *mld; @@ -700,680 +308,44 @@ static int xmit_ipc_to_rb(struct mem_link_device *mld, enum sipc_ch_id ch, return ret; } -#endif - -/** -@brief transmit an IPC message packet - -@param mld the pointer to a mem_link_device instance -@param ch the channel ID -@param skb the pointer to an skb that will be transmitted - -@retval "> 0" the size of the data in @b @@skb -@retval "< 0" an error code (-ENODEV or -EBUSY) -*/ -static int xmit_ipc_to_dev(struct mem_link_device *mld, enum sipc_ch_id ch, - struct sk_buff *skb) -{ - int ret; - struct link_device *ld = &mld->link_dev; - struct io_device *iod = skbpriv(skb)->iod; - struct modem_ctl *mc = ld->mc; - struct mem_ipc_device *dev = mld->dev[dev_id(ch)]; - struct sk_buff_head *skb_txq; - unsigned long flags; - - if (!dev) { - mif_err("%s: %s->%s: ERR! NO IPC DEV {ch:%d}\n", - ld->name, iod->name, mc->name, ch); - return -ENODEV; - } - - skb_txq = dev->skb_txq; - -#ifdef CONFIG_LINK_POWER_MANAGEMENT - if (cp_online(mc) && mld->forbid_cp_sleep) - mld->forbid_cp_sleep(mld); -#endif - - spin_lock_irqsave(dev->tx_lock, flags); - - if (unlikely(skb_txq->qlen >= MAX_SKB_TXQ_DEPTH)) { - mif_err_limited("%s: %s->%s: ERR! %s TXQ.qlen %d >= limit %d\n", - ld->name, iod->name, mc->name, dev->name, - skb_txq->qlen, MAX_SKB_TXQ_DEPTH); - ret = -EBUSY; - } else { - ret = skb->len; - skb_queue_tail(dev->skb_txq, skb); - start_tx_timer(mld, &mld->tx_timer); - } - - spin_unlock_irqrestore(dev->tx_lock, flags); - -#ifdef CONFIG_LINK_POWER_MANAGEMENT - if (cp_online(mc) && mld->permit_cp_sleep) - mld->permit_cp_sleep(mld); -#endif - - return ret; -} - -/** -@brief transmit an IPC message packet - -@param mld the pointer to a mem_link_device instance -@param ch the channel ID -@param skb the pointer to an skb that will be transmitted - -@retval "> 0" the size of the data in @b @@skb -@retval "< 0" an error code (-EIO, -ENODEV, -EBUSY) -*/ -static int xmit_ipc(struct mem_link_device *mld, struct io_device *iod, - enum sipc_ch_id ch, struct sk_buff *skb) -{ - if (unlikely(!ipc_active(mld))) - return -EIO; - -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH - if (iod->sbd_ipc) { - if (likely(sbd_active(&mld->sbd_link_dev))) - return xmit_ipc_to_rb(mld, ch, skb); - else - return -ENODEV; - } else { - return xmit_ipc_to_dev(mld, ch, skb); - } -#else - return xmit_ipc_to_dev(mld, ch, skb); -#endif -} - -static inline int check_udl_space(struct mem_link_device *mld, - struct mem_ipc_device *dev, - unsigned int qsize, unsigned int in, - unsigned int out, unsigned int count) -{ - struct link_device *ld = &mld->link_dev; - unsigned int space; - - if (!circ_valid(qsize, in, out)) { - mif_err("%s: ERR! Invalid %s_TXQ{qsize:%d in:%d out:%d}\n", - ld->name, dev->name, qsize, in, out); - return -EIO; - } - - space = circ_get_space(qsize, in, out); - if (unlikely(space < count)) { - mif_err("%s: NOSPC in %s_TXQ{qsize:%d in:%d " - "out:%d space:%d count:%d}\n", ld->name, - dev->name, qsize, in, out, space, count); - return -ENOSPC; - } - - return 0; -} - -/** -@brief copy UDL data in an skb to a circular TXQ - -Enqueues a frame in @b @@skb to the @b @@dev TXQ if there is enough space in the -TXQ, then releases @b @@skb. - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance -@param skb the pointer to an sk_buff instance - -@retval "> 0" the size of the frame written in the TXQ -@retval "< 0" an error code (-EBUSY, -ENOSPC, or -EIO) -*/ -static inline int udl_write(struct mem_link_device *mld, - struct mem_ipc_device *dev, struct sk_buff *skb) -{ - unsigned int count = skb->len; - char *src = skb->data; - char *dst = get_txq_buff(dev); - unsigned int qsize = get_txq_buff_size(dev); - unsigned int in = get_txq_head(dev); - unsigned int out = get_txq_tail(dev); - int space; - - space = check_udl_space(mld, dev, qsize, in, out, count); - if (unlikely(space < 0)) - return space; - - barrier(); - - circ_write(dst, src, qsize, in, count); - - barrier(); - - set_txq_head(dev, circ_new_ptr(qsize, in, count)); - - /* Commit the item before incrementing the head */ - smp_mb(); - - return count; -} - -/** -@brief transmit a BOOT/DUMP data packet - -@param mld the pointer to a mem_link_device instance -@param ch the channel ID -@param skb the pointer to an skb that will be transmitted - -@retval "> 0" the size of the data in @b @@skb -*/ -static int xmit_udl(struct mem_link_device *mld, struct io_device *iod, - enum sipc_ch_id ch, struct sk_buff *skb) -{ - int ret; - struct mem_ipc_device *dev = mld->dev[IPC_RAW]; - int count = skb->len; - int tried = 0; - - while (1) { - ret = udl_write(mld, dev, skb); - if (ret == count) - break; - - if (ret != -ENOSPC) - goto exit; - - tried++; - if (tried >= 20) - goto exit; - - if (in_interrupt()) - mdelay(50); - else - msleep(50); - } - - dev_kfree_skb_any(skb); - -exit: - return ret; -} - -/** -@} -*/ -#endif - -/*============================================================================*/ - -#ifdef GROUP_MEM_IPC_RX - -/** -@weakgroup group_mem_ipc_rx - -@dot -digraph mem_rx { -graph [ - label="\n\n\n" - labelloc="top" - fontname="Helvetica" - fontsize=20 -]; - -node [shape=box fontname="Helvetica"]; - -edge [fontname="Helvetica"]; - -node [] - subgraph irq_handling { - node [] - mem_irq_handler [ - label="mem_irq_handler" - URL="@ref mem_irq_handler" - ]; - - mem_rx_task [ - label="mem_rx_task" - URL="@ref mem_rx_task" - ]; - - udl_rx_work [ - label="udl_rx_work" - URL="@ref udl_rx_work" - ]; - - ipc_rx_func [ - label="ipc_rx_func" - URL="@ref ipc_rx_func" - ]; - - edge [color="red:green4:blue" fontcolor=black]; - mem_irq_handler -> mem_rx_task [ - label="Tasklet" - ]; - - edge [color=blue fontcolor=blue]; - mem_rx_task -> udl_rx_work [ - label="Delayed\nWork" - arrowhead=vee - style=dotted - ]; - - udl_rx_work -> ipc_rx_func [ - label="Process\nContext" - ]; - - edge [color="red:green4" fontcolor=brown]; - mem_rx_task -> ipc_rx_func [ - label="Tasklet\nContext" - ]; - } - - subgraph rx_processing { - node [] - mem_cmd_handler [ - label="mem_cmd_handler" - URL="@ref mem_cmd_handler" - ]; - - recv_ipc_frames [ - label="recv_ipc_frames" - URL="@ref recv_ipc_frames" - ]; - - rx_frames_from_dev [ - label="rx_frames_from_dev" - URL="@ref rx_frames_from_dev" - ]; - - rxq_read [ - label="rxq_read" - URL="@ref rxq_read" - ]; - - schedule_link_to_demux [ - label="schedule_link_to_demux" - URL="@ref schedule_link_to_demux" - ]; - - link_to_demux_work [ - label="link_to_demux_work" - URL="@ref link_to_demux_work" - ]; - - pass_skb_to_demux [ - label="pass_skb_to_demux" - URL="@ref pass_skb_to_demux" - ]; - - skb_rxq [ - shape=record - label="| |skb_rxq| |" - color=green4 - fontcolor=green4 - ]; - - edge [color=black fontcolor=black]; - ipc_rx_func -> mem_cmd_handler [ - label="command" - ]; - - edge [color="red:green4:blue" fontcolor=black]; - ipc_rx_func -> recv_ipc_frames [ - label="while (msb)" - ]; - - recv_ipc_frames -> rx_frames_from_dev [ - label="1. for (each IPC device)" - ]; - - rx_frames_from_dev -> rxq_read [ - label="2.\nwhile (rcvd < size)" - ]; - - edge [color=blue fontcolor=blue]; - rxq_read -> rx_frames_from_dev [ - label="2-1.\nUDL skb\n[process]" - ]; - - rx_frames_from_dev -> pass_skb_to_demux [ - label="2-2.\nUDL skb\n[process]" - ]; - - edge [color="red:green4" fontcolor=brown]; - rxq_read -> rx_frames_from_dev [ - label="2-1.\nFMT skb\nRFS skb\nPS skb\n[tasklet]" - ]; - - edge [color=red fontcolor=red]; - rx_frames_from_dev -> pass_skb_to_demux [ - label="2-2.\nFMT skb\nRFS skb\n[tasklet]" - ]; - - edge [color=green4 fontcolor=green4]; - rx_frames_from_dev -> skb_rxq:f1 [ - label="2-2.\nPS skb\n[tasklet]" - arrowhead=vee - style=dashed - ]; - - edge [color="red:green4" fontcolor=brown]; - rx_frames_from_dev -> recv_ipc_frames [ - label="3. Return" - ]; - - edge [color=green4 fontcolor=green4]; - recv_ipc_frames -> schedule_link_to_demux [ - label="4. Scheduling" - ]; - - edge [color="red:green4" fontcolor=brown]; - recv_ipc_frames -> ipc_rx_func [ - label="5. Return" - ]; - - edge [color=green4 fontcolor=green4]; - schedule_link_to_demux -> link_to_demux_work [ - label="6. Delayed\nwork\n[process]" - arrowhead=vee - style=dotted - ]; - - skb_rxq:f0 -> link_to_demux_work [ - label="6-1.\nPS skb" - arrowhead=vee - style=dashed - ]; - - link_to_demux_work -> pass_skb_to_demux [ - label="6-2.\nPS skb" - ]; - } -} -@enddot -*/ - -/** -@weakgroup group_mem_ipc_rx -@{ -*/ /** @brief pass a socket buffer to the DEMUX layer -Invokes the recv_skb_single method in the io_device instance to perform -receiving IPC messages from each skb. - -@param mld the pointer to a mem_link_device instance -@param skb the pointer to an sk_buff instance - -@retval "> 0" if succeeded to pass an @b @@skb to the DEMUX layer -@retval "< 0" an error code -*/ -static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) -{ - struct link_device *ld = &mld->link_dev; - struct io_device *iod = skbpriv(skb)->iod; - int ret; - u8 ch = skbpriv(skb)->sipc_ch; - - if (unlikely(!iod)) { - mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); - dev_kfree_skb_any(skb); - modemctl_notify_event(MDM_CRASH_INVALID_IOD); - return; - } - - log_ipc_pkt(LNK_RX, ch, skb); - - ret = iod->recv_skb_single(iod, ld, skb); - if (unlikely(ret < 0)) { - struct modem_ctl *mc = ld->mc; - mif_err_limited("%s: %s<-%s: ERR! %s->recv_skb fail (%d)\n", - ld->name, iod->name, mc->name, iod->name, ret); - dev_kfree_skb_any(skb); - } -} - -static inline void link_to_demux(struct mem_link_device *mld) -{ - int i; - - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - struct mem_ipc_device *dev = mld->dev[i]; - struct sk_buff_head *skb_rxq = dev->skb_rxq; - - while (1) { - struct sk_buff *skb; - - skb = skb_dequeue(skb_rxq); - if (!skb) - break; - - pass_skb_to_demux(mld, skb); - } - } -} - -/** -@brief pass socket buffers in every skb_rxq to the DEMUX layer - -@param ws the pointer to a work_struct instance - -@see schedule_link_to_demux() -@see rx_frames_from_dev() -@see mem_create_link_device() -*/ -static void link_to_demux_work(struct work_struct *ws) -{ - struct link_device *ld; - struct mem_link_device *mld; - - ld = container_of(ws, struct link_device, rx_delayed_work.work); - mld = to_mem_link_device(ld); - - link_to_demux(mld); -} - -static inline void schedule_link_to_demux(struct mem_link_device *mld) -{ - struct link_device *ld = &mld->link_dev; - struct delayed_work *dwork = &ld->rx_delayed_work; - - /*queue_delayed_work(ld->rx_wq, dwork, 0);*/ - queue_work_on(7, ld->rx_wq, &dwork->work); -} - -/** -@brief copy each IPC link frame from a circular queue to an skb - -1) Analyzes a link frame header and get the size of the current link frame.\n -2) Allocates a socket buffer (skb).\n -3) Extracts a link frame from the current @b $out (tail) pointer in the @b - @@dev RXQ up to @b @@in (head) pointer in the @b @@dev RXQ, then copies it - to the skb allocated in the step 2.\n -4) Updates the TAIL (OUT) pointer in the @b @@dev RXQ.\n - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance (IPC_FMT, etc.) -@param in the IN (HEAD) pointer value of the @b @@dev RXQ - -@retval "struct sk_buff *" if there is NO error -@retval "NULL" if there is ANY error -*/ -static struct sk_buff *rxq_read(struct mem_link_device *mld, - struct mem_ipc_device *dev, - unsigned int in) -{ - struct link_device *ld = &mld->link_dev; - struct sk_buff *skb; - char *src = get_rxq_buff(dev); - unsigned int qsize = get_rxq_buff_size(dev); - unsigned int out = get_rxq_tail(dev); - unsigned int rest = circ_get_usage(qsize, in, out); - unsigned int len; - char hdr[SIPC5_MIN_HEADER_SIZE]; - - /* Copy the header in a frame to the header buffer */ - circ_read(hdr, src, qsize, out, SIPC5_MIN_HEADER_SIZE); - - /* Check the config field in the header */ - if (unlikely(!sipc5_start_valid(hdr))) { - mif_err("%s: ERR! %s BAD CFG 0x%02X (in:%d out:%d rest:%d)\n", - ld->name, dev->name, hdr[SIPC5_CONFIG_OFFSET], - in, out, rest); - goto bad_msg; - } - - /* Verify the length of the frame (data + padding) */ - len = sipc5_get_total_len(hdr); - if (unlikely(len > rest)) { - mif_err("%s: ERR! %s BAD LEN %d > rest %d\n", - ld->name, dev->name, len, rest); - goto bad_msg; - } - - /* Allocate an skb */ - skb = mem_alloc_skb(len); - if (!skb) { - mif_err("%s: ERR! %s mem_alloc_skb(%d) fail\n", - ld->name, dev->name, len); - goto no_mem; - } - - /* Read the frame from the RXQ */ - circ_read(skb_put(skb, len), src, qsize, out, len); - - /* Update tail (out) pointer to the frame to be read in the future */ - set_rxq_tail(dev, circ_new_ptr(qsize, out, len)); - - /* Finish reading data before incrementing tail */ - smp_mb(); - - return skb; - -bad_msg: - mif_err("%s: %s%s%s: ERR! BAD MSG: %02x %02x %02x %02x\n", - FUNC, ld->name, arrow(RX), ld->mc->name, - hdr[0], hdr[1], hdr[2], hdr[3]); - set_rxq_tail(dev, in); /* Reset tail (out) pointer */ - modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); - -no_mem: - return NULL; -} - -/** -@brief extract all IPC link frames from a circular queue - -In a while loop,\n -1) Receives each IPC link frame stored in the @b @@dev RXQ.\n -2) If the frame is a PS (network) data frame, stores it to an skb_rxq and - schedules a delayed work for PS data reception.\n -3) Otherwise, passes it to the DEMUX layer immediately.\n - -@param mld the pointer to a mem_link_device instance -@param dev the pointer to a mem_ipc_device instance (IPC_FMT, etc.) - -@retval "> 0" if valid data received -@retval "= 0" if no data received -@retval "< 0" if ANY error -*/ -static int rx_frames_from_dev(struct mem_link_device *mld, - struct mem_ipc_device *dev) -{ - struct link_device *ld = &mld->link_dev; - struct sk_buff_head *skb_rxq = dev->skb_rxq; - unsigned int qsize = get_rxq_buff_size(dev); - unsigned int in = get_rxq_head(dev); - unsigned int out = get_rxq_tail(dev); - unsigned int size = circ_get_usage(qsize, in, out); - int rcvd = 0; - - if (unlikely(circ_empty(in, out))) - return 0; - - while (rcvd < size) { - struct sk_buff *skb; - u8 ch; - struct io_device *iod; - - skb = rxq_read(mld, dev, in); - if (!skb) - break; - - ch = sipc5_get_ch(skb->data); - iod = link_get_iod_with_channel(ld, ch); - if (!iod) { - mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); - dev_kfree_skb_any(skb); - modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); - break; - } - - /* Record the IO device and the link device into the &skb->cb */ - skbpriv(skb)->iod = iod; - skbpriv(skb)->ld = ld; - - skbpriv(skb)->lnk_hdr = iod->link_header; - skbpriv(skb)->sipc_ch = ch; - - /* The $rcvd must be accumulated here, because $skb can be freed - in pass_skb_to_demux(). */ - rcvd += skb->len; - - if (likely(sipc_ps_ch(ch))) - skb_queue_tail(skb_rxq, skb); - else - pass_skb_to_demux(mld, skb); - } - - if (rcvd < size) { - struct link_device *ld = &mld->link_dev; - mif_err("%s: WARN! rcvd %d < size %d\n", ld->name, rcvd, size); - } - - return rcvd; -} - -/** -@brief receive all @b IPC message frames in all RXQs - -In a for loop,\n -1) Checks any REQ_ACK received.\n -2) Receives all IPC link frames in every RXQ.\n -3) Sends RES_ACK if there was REQ_ACK from CP.\n -4) Checks any RES_ACK received.\n +Invokes the recv_skb_single method in the io_device instance to perform +receiving IPC messages from each skb. @param mld the pointer to a mem_link_device instance -@param mst the pointer to a mem_snapshot instance +@param skb the pointer to an sk_buff instance + +@retval "> 0" if succeeded to pass an @b @@skb to the DEMUX layer +@retval "< 0" an error code */ -static void recv_ipc_frames(struct mem_link_device *mld, - struct mem_snapshot *mst) +static void pass_skb_to_demux(struct mem_link_device *mld, struct sk_buff *skb) { - int i; - u16 intr = mst->int2ap; - - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - struct mem_ipc_device *dev = mld->dev[i]; - int rcvd; - - if (req_ack_valid(dev, intr)) - recv_req_ack(mld, dev, mst); - - rcvd = rx_frames_from_dev(mld, dev); - if (rcvd < 0) - break; + struct link_device *ld = &mld->link_dev; + struct io_device *iod = skbpriv(skb)->iod; + int ret; + u8 ch = skbpriv(skb)->sipc_ch; - schedule_link_to_demux(mld); + if (unlikely(!iod)) { + mif_err("%s: ERR! No IOD for CH.%d\n", ld->name, ch); + dev_kfree_skb_any(skb); + modemctl_notify_event(MDM_CRASH_INVALID_IOD); + return; + } - if (req_ack_valid(dev, intr)) - send_res_ack(mld, dev); + log_ipc_pkt(LNK_RX, ch, skb); - if (res_ack_valid(dev, intr)) - recv_res_ack(mld, dev, mst); + ret = iod->recv_skb_single(iod, ld, skb); + if (unlikely(ret < 0)) { + struct modem_ctl *mc = ld->mc; + mif_err_limited("%s: %s<-%s: ERR! %s->recv_skb fail (%d)\n", + ld->name, iod->name, mc->name, iod->name, ret); + dev_kfree_skb_any(skb); } } -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH static void pass_skb_to_net(struct mem_link_device *mld, struct sk_buff *skb) { struct link_device *ld = &mld->link_dev; @@ -1559,8 +531,7 @@ In a for loop,\n @param mld the pointer to a mem_link_device instance @param mst the pointer to a mem_snapshot instance */ -static void recv_sbd_ipc_frames(struct mem_link_device *mld, - struct mem_snapshot *mst) +void recv_sbd_ipc_frames(struct mem_link_device *mld) { struct sbd_link_device *sl = &mld->sbd_link_dev; int i; @@ -1584,7 +555,6 @@ static void recv_sbd_ipc_frames(struct mem_link_device *mld, } } } -#endif /** @brief function for IPC message reception @@ -1595,9 +565,7 @@ Invokes cmd_handler for a command or recv_ipc_frames for IPC messages. */ static void ipc_rx_func(struct mem_link_device *mld) { -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH struct sbd_link_device *sl = &mld->sbd_link_dev; -#endif while (1) { struct mst_buff *msb; @@ -1612,20 +580,12 @@ static void ipc_rx_func(struct mem_link_device *mld) if (cmd_valid(intr)) mld->cmd_handler(mld, int2cmd(intr)); -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH if (sbd_active(sl)) - recv_sbd_ipc_frames(mld, &msb->snapshot); + recv_sbd_ipc_frames(mld); else recv_ipc_frames(mld, &msb->snapshot); -#else - recv_ipc_frames(mld, &msb->snapshot); -#endif -#if 0 - msb_queue_tail(&mld->msb_log, msb); -#else msb_free(msb); -#endif } } @@ -1658,88 +618,7 @@ static void mem_rx_task(unsigned long data) queue_delayed_work(ld->rx_wq, &mld->udl_rx_dwork, 0); } -/** -@} -*/ -#endif - -/*============================================================================*/ - -#ifdef GROUP_MEM_LINK_COMMAND -/** -@weakgroup group_mem_link_command -@{ -*/ - -/** -@brief reset all member variables in every IPC device - -@param mld the pointer to a mem_link_device instance -*/ -static inline void reset_ipc_map(struct mem_link_device *mld) -{ - int i; - - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - struct mem_ipc_device *dev = mld->dev[i]; - - set_txq_head(dev, 0); - set_txq_tail(dev, 0); - set_rxq_head(dev, 0); - set_rxq_tail(dev, 0); - } -} - -int mem_reset_ipc_link(struct mem_link_device *mld) -{ - struct link_device *ld = &mld->link_dev; - unsigned int magic; - unsigned int access; - int i; - - set_access(mld, 0); - set_magic(mld, 0); - - reset_ipc_map(mld); - - for (i = 0; i < MAX_SIPC5_DEVICES; i++) { - struct mem_ipc_device *dev = mld->dev[i]; - - skb_queue_purge(dev->skb_txq); - atomic_set(&dev->txq.busy, 0); - dev->req_ack_cnt[TX] = 0; - - skb_queue_purge(dev->skb_rxq); - atomic_set(&dev->rxq.busy, 0); - dev->req_ack_cnt[RX] = 0; - } - - atomic_set(&ld->netif_stopped, 0); - - set_magic(mld, MEM_IPC_MAGIC); - set_access(mld, 1); - - magic = get_magic(mld); - access = get_access(mld); - if (magic != MEM_IPC_MAGIC || access != 1) - return -EACCES; - - return 0; -} - -/** -@} -*/ -#endif - -/*============================================================================*/ - #ifdef GROUP_MEM_LINK_METHOD -/** -@weakgroup group_mem_link_method -@{ -*/ - /** @brief function for the @b init_comm method in a link_device instance @@ -1846,10 +725,21 @@ static int mem_send(struct link_device *ld, struct io_device *iod, case IPC_FMT: case IPC_RAW: case IPC_RFS: - if (likely(sipc5_ipc_ch(ch))) - return xmit_ipc(mld, iod, ch, skb); - else + if (likely(sipc5_ipc_ch(ch))) { + if (unlikely(!ipc_active(mld))) + return -EIO; + + if (iod->sbd_ipc) { + if (likely(sbd_active(&mld->sbd_link_dev))) + return xmit_ipc_to_rb(mld, ch, skb); + else + return -ENODEV; + } else { + BUG_ON(1); + } + } else { return xmit_udl(mld, iod, ch, skb); + } case IPC_BOOT: case IPC_DUMP: @@ -1884,9 +774,6 @@ static void mem_boot_on(struct link_device *ld, struct io_device *iod) ld->state = LINK_STATE_OFFLINE; spin_unlock_irqrestore(&ld->lock, flags); - cancel_tx_timer(mld, &mld->tx_timer); - -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH #ifdef CONFIG_LTE_MODEM_XMM7260 sbd_deactivate(&mld->sbd_link_dev); #endif @@ -1896,168 +783,10 @@ static void mem_boot_on(struct link_device *ld, struct io_device *iod) memset(mld->base + CMD_RGN_OFFSET, 0, CMD_RGN_SIZE); mif_info("Control message region has been initialized\n"); } -#endif purge_txq(mld); } -/** -@brief function for the @b xmit_boot method in a link_device instance - -Copies a CP bootloader binary in a user space to the BOOT region for CP - -@param ld the pointer to a link_device instance -@param iod the pointer to an io_device instance -@param arg the pointer to a modem_firmware instance - -@retval "= 0" if NO error -@retval "< 0" an error code -*/ -static int mem_xmit_boot(struct link_device *ld, struct io_device *iod, - unsigned long arg) -{ - struct mem_link_device *mld = to_mem_link_device(ld); - void __iomem *dst; - void __user *src; - int err; - struct modem_firmware mf; - - /** - * Get the information about the boot image - */ - memset(&mf, 0, sizeof(struct modem_firmware)); - - err = copy_from_user(&mf, (const void __user *)arg, sizeof(mf)); - if (err) { - mif_err("%s: ERR! INFO copy_from_user fail\n", ld->name); - return -EFAULT; - } - - /** - * Check the size of the boot image - */ - if (mf.size > mld->boot_size) { - mif_err("%s: ERR! Invalid BOOT size %d\n", ld->name, mf.size); - return -EINVAL; - } - mif_err("%s: BOOT size = %d bytes\n", ld->name, mf.size); - - /** - * Copy the boot image to the BOOT region - */ - memset(mld->boot_base, 0, mld->boot_size); - - dst = (void __iomem *)mld->boot_base; - src = (void __user *)mf.binary; - err = copy_from_user(dst, src, mf.size); - if (err) { - mif_err("%s: ERR! BOOT copy_from_user fail\n", ld->name); - return err; - } - - return 0; -} - -/** -@brief function for the @b dload_start method in a link_device instance - -Set all flags and environments for CP binary download - -@param ld the pointer to a link_device instance -@param iod the pointer to an io_device instance -*/ -static int mem_start_download(struct link_device *ld, struct io_device *iod) -{ - struct mem_link_device *mld = to_mem_link_device(ld); - - reset_ipc_map(mld); - - if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_BOOT)) - sbd_deactivate(&mld->sbd_link_dev); - - if (mld->attrs & LINK_ATTR(LINK_ATTR_BOOT_ALIGNED)) - ld->aligned = true; - else - ld->aligned = false; - - if (mld->dpram_magic) { - unsigned int magic; - - set_magic(mld, MEM_BOOT_MAGIC); - magic = get_magic(mld); - if (magic != MEM_BOOT_MAGIC) { - mif_err("%s: ERR! magic 0x%08X != BOOT_MAGIC 0x%08X\n", - ld->name, magic, MEM_BOOT_MAGIC); - return -EFAULT; - } - mif_err("%s: magic == 0x%08X\n", ld->name, magic); - } - - return 0; -} - -/** -@brief function for the @b firm_update method in a link_device instance - -Updates download information for each CP binary image by copying download -information for a CP binary image from a user space to a local buffer in a -mem_link_device instance. - -@param ld the pointer to a link_device instance -@param iod the pointer to an io_device instance -@param arg the pointer to a std_dload_info instance -*/ -static int mem_update_firm_info(struct link_device *ld, struct io_device *iod, - unsigned long arg) -{ - struct mem_link_device *mld = to_mem_link_device(ld); - int ret; - - ret = copy_from_user(&mld->img_info, (void __user *)arg, - sizeof(struct std_dload_info)); - if (ret) { - mif_err("ERR! copy_from_user fail!\n"); - return -EFAULT; - } - - return 0; -} - -/** -@brief function for the @b dump_start method in a link_device instance - -@param ld the pointer to a link_device instance -@param iod the pointer to an io_device instance -*/ -static int mem_start_upload(struct link_device *ld, struct io_device *iod) -{ - struct mem_link_device *mld = to_mem_link_device(ld); - - if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_DUMP)) - sbd_deactivate(&mld->sbd_link_dev); - - reset_ipc_map(mld); - - if (mld->attrs & LINK_ATTR(LINK_ATTR_DUMP_ALIGNED)) - ld->aligned = true; - else - ld->aligned = false; - - if (mld->dpram_magic) { - unsigned int magic; - - set_magic(mld, MEM_DUMP_MAGIC); - magic = get_magic(mld); - if (magic != MEM_DUMP_MAGIC) { - mif_err("%s: ERR! magic 0x%08X != DUMP_MAGIC 0x%08X\n", - ld->name, magic, MEM_DUMP_MAGIC); - return -EFAULT; - } - mif_err("%s: magic == 0x%08X\n", ld->name, magic); - } - - return 0; -} /** @brief function for the @b stop method in a link_device instance @@ -2078,20 +807,9 @@ static void mem_close_tx(struct link_device *ld) stop_tx(mld); } - -/** -@} -*/ #endif -/*============================================================================*/ - #ifdef GROUP_MEM_LINK_SETUP -/** -@weakgroup group_mem_link_setup -@{ -*/ - void __iomem *mem_vmap(phys_addr_t pa, size_t size, struct page *pages[]) { size_t num_pages = (size >> PAGE_SHIFT); @@ -2111,158 +829,6 @@ void mem_vunmap(void *va) vunmap(va); } -/** -@brief register a physical memory region for a BOOT region - -@param mld the pointer to a mem_link_device instance -@param start the physical address of an IPC region -@param size the size of the IPC region -*/ -int mem_register_boot_rgn(struct mem_link_device *mld, phys_addr_t start, - size_t size) -{ - struct link_device *ld = &mld->link_dev; - size_t num_pages = (size >> PAGE_SHIFT); - struct page **pages; - - pages = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC); - if (!pages) - return -ENOMEM; - - mif_err("%s: BOOT_RGN start:%pa size:%zu\n", ld->name, &start, size); - - mld->boot_start = start; - mld->boot_size = size; - mld->boot_pages = pages; - - return 0; -} - -/** -@brief unregister a physical memory region for a BOOT region - -@param mld the pointer to a mem_link_device instance -*/ -void mem_unregister_boot_rgn(struct mem_link_device *mld) -{ - kfree(mld->boot_pages); - mld->boot_pages = NULL; - mld->boot_size = 0; - mld->boot_start = 0; -} - -/** -@brief setup the logical map for an BOOT region - -@param mld the pointer to a mem_link_device instance -@param start the physical address of an IPC region -@param size the size of the IPC region -*/ -int mem_setup_boot_map(struct mem_link_device *mld) -{ - struct link_device *ld = &mld->link_dev; - phys_addr_t start = mld->boot_start; - size_t size = mld->boot_size; - struct page **pages = mld->boot_pages; - char __iomem *base; - - base = mem_vmap(start, size, pages); - if (!base) { - mif_err("%s: ERR! mem_vmap fail\n", ld->name); - return -EINVAL; - } - memset(base, 0, size); - - mld->boot_base = (char __iomem *)base; - - mif_err("%s: BOOT_RGN phys_addr:%pa virt_addr:%p size:%zu\n", - ld->name, &start, base, size); - - return 0; -} - -static void remap_4mb_map_to_ipc_dev(struct mem_link_device *mld) -{ - struct link_device *ld = &mld->link_dev; - struct shmem_4mb_phys_map *map; - struct mem_ipc_device *dev; - - map = (struct shmem_4mb_phys_map *)mld->base; - - /* magic code and access enable fields */ - mld->magic = (u32 __iomem *)&map->magic; - mld->access = (u32 __iomem *)&map->access; - - /* IPC_FMT */ - dev = &mld->ipc_dev[IPC_FMT]; - - dev->id = IPC_FMT; - strcpy(dev->name, "FMT"); - - spin_lock_init(&dev->txq.lock); - atomic_set(&dev->txq.busy, 0); - dev->txq.head = &map->fmt_tx_head; - dev->txq.tail = &map->fmt_tx_tail; - dev->txq.buff = &map->fmt_tx_buff[0]; - dev->txq.size = SHM_4M_FMT_TX_BUFF_SZ; - - spin_lock_init(&dev->rxq.lock); - atomic_set(&dev->rxq.busy, 0); - dev->rxq.head = &map->fmt_rx_head; - dev->rxq.tail = &map->fmt_rx_tail; - dev->rxq.buff = &map->fmt_rx_buff[0]; - dev->rxq.size = SHM_4M_FMT_RX_BUFF_SZ; - - dev->msg_mask = MASK_SEND_FMT; - dev->req_ack_mask = MASK_REQ_ACK_FMT; - dev->res_ack_mask = MASK_RES_ACK_FMT; - - dev->tx_lock = &ld->tx_lock[IPC_FMT]; - dev->skb_txq = &ld->sk_fmt_tx_q; - - dev->rx_lock = &ld->rx_lock[IPC_FMT]; - dev->skb_rxq = &ld->sk_fmt_rx_q; - - dev->req_ack_cnt[TX] = 0; - dev->req_ack_cnt[RX] = 0; - - mld->dev[IPC_FMT] = dev; - - /* IPC_RAW */ - dev = &mld->ipc_dev[IPC_RAW]; - - dev->id = IPC_RAW; - strcpy(dev->name, "RAW"); - - spin_lock_init(&dev->txq.lock); - atomic_set(&dev->txq.busy, 0); - dev->txq.head = &map->raw_tx_head; - dev->txq.tail = &map->raw_tx_tail; - dev->txq.buff = &map->raw_tx_buff[0]; - dev->txq.size = SHM_4M_RAW_TX_BUFF_SZ; - - spin_lock_init(&dev->rxq.lock); - atomic_set(&dev->rxq.busy, 0); - dev->rxq.head = &map->raw_rx_head; - dev->rxq.tail = &map->raw_rx_tail; - dev->rxq.buff = &map->raw_rx_buff[0]; - dev->rxq.size = SHM_4M_RAW_RX_BUFF_SZ; - - dev->msg_mask = MASK_SEND_RAW; - dev->req_ack_mask = MASK_REQ_ACK_RAW; - dev->res_ack_mask = MASK_RES_ACK_RAW; - - dev->tx_lock = &ld->tx_lock[IPC_RAW]; - dev->skb_txq = &ld->sk_raw_tx_q; - - dev->rx_lock = &ld->rx_lock[IPC_RAW]; - dev->skb_rxq = &ld->sk_raw_rx_q; - - dev->req_ack_cnt[TX] = 0; - dev->req_ack_cnt[RX] = 0; - - mld->dev[IPC_RAW] = dev; -} /** @brief register a physical memory region for an IPC region @@ -2361,12 +927,6 @@ static int mem_rx_setup(struct link_device *ld) argos_irq_affinity_setup_label(241, "IPC", mld->imask, mld->dmask); #endif - ld->tx_wq = create_singlethread_workqueue("mem_tx_work"); - if (!ld->tx_wq) { - mif_err("%s: ERR! fail to create tx_wq\n", ld->name); - return -ENOMEM; - } - ld->rx_wq = alloc_workqueue( "mem_rx_work", WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); if (!ld->rx_wq) { @@ -2450,9 +1010,7 @@ struct mem_link_device *mem_create_link_device(enum mem_iface_type type, Set up link device methods */ ld->init_comm = mem_init_comm; -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH ld->terminate_comm = mem_terminate_comm; -#endif ld->send = mem_send; ld->netdev_poll = mem_netdev_poll; @@ -2519,13 +1077,8 @@ struct mem_link_device *mem_create_link_device(enum mem_iface_type type, tasklet_init(&mld->rx_tsk, mem_rx_task, (unsigned long)mld); - hrtimer_init(&mld->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - mld->tx_timer.function = tx_timer_func; - -#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH hrtimer_init(&mld->sbd_tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mld->sbd_tx_timer.function = sbd_tx_timer_func; -#endif /* ** Initialize variables for CP booting and crash dump @@ -2541,9 +1094,5 @@ struct mem_link_device *mem_create_link_device(enum mem_iface_type type, return NULL; } -/** -@} -*/ #endif - diff --git a/drivers/misc/modem_v1/link_device_memory_sbd.c b/drivers/misc/modem_v1/link_device_memory_sbd.c index 8ec5f35d5de1..8655c1751781 100644 --- a/drivers/misc/modem_v1/link_device_memory_sbd.c +++ b/drivers/misc/modem_v1/link_device_memory_sbd.c @@ -605,6 +605,38 @@ struct sk_buff *sbd_pio_rx(struct sbd_ring_buffer *rb) return skb; } +int tx_frames_to_rb(struct sbd_ring_buffer *rb) +{ + struct sk_buff_head *skb_txq = &rb->skb_q; + int tx_bytes = 0; + int ret = 0; + + while (1) { + struct sk_buff *skb; + + skb = skb_dequeue(skb_txq); + if (unlikely(!skb)) + break; + + ret = sbd_pio_tx(rb, skb); + if (unlikely(ret < 0)) { + /* Take the skb back to the skb_txq */ + skb_queue_head(skb_txq, skb); + break; + } + + tx_bytes += ret; + + log_ipc_pkt(LNK_TX, rb->ch, skb); + + trace_mif_event(skb, skb->len, FUNC); + + dev_kfree_skb_any(skb); + } + + return (ret < 0) ? ret : tx_bytes; +} + /** @} */ diff --git a/drivers/misc/modem_v1/link_device_spi.c b/drivers/misc/modem_v1/link_device_spi.c new file mode 100644 index 000000000000..4d67fb77cecf --- /dev/null +++ b/drivers/misc/modem_v1/link_device_spi.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2011 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#include +#include +#include +#ifdef CONFIG_LINK_DEVICE_LLI +#include +#endif + +#include +#include +#include +#include "modem_utils.h" + +#include "modem_prj.h" +#include "modem_link_device_spi_boot.h" + +#define to_spi_boot_link_dev(linkdev) \ + container_of(linkdev, struct spi_boot_link_device, ld) + +#define SPI_XMIT_DELEY 100 + + +struct spi_boot_link_device *spi_boot_id; + +static int spi_boot_init(struct link_device *ld, struct io_device *iod) +{ + return 0; +} + +static void spi_boot_terminate(struct link_device *ld, struct io_device *iod) +{ +} + +static int spi_transmit_data(struct spi_device *spi, + unsigned char *buf, size_t len) +{ + int ret; + + struct spi_message msg; + struct spi_transfer t = { + .len = len, + .tx_buf = buf, + .delay_usecs = 10, + }; + + spi_message_init(&msg); + spi_message_add_tail(&t, &msg); + + ret = spi_sync(spi, &msg); + if (ret < 0) + mif_err("spi_sync() fail(%d)\n", ret); + + return ret; +} + +static int spi_boot_tx_skb(struct link_device *ld, struct io_device *iod, + struct sk_buff *skb) +{ + int ret = -EINVAL; + + struct spi_boot_link_device *sbld = to_spi_boot_link_dev(ld); + + unsigned char *buf = skb->data + SIPC5_MIN_HEADER_SIZE; + int len = skb->len - SIPC5_MIN_HEADER_SIZE; + + skb_queue_tail(&sbld->tx_q, skb); + + ret = spi_transmit_data(sbld->spi, buf, len); + if (ret < 0) { + mif_err("spi_transmit_data() failed(%d)\n", ret); + goto exit; + } + +exit: + skb_unlink(skb, &sbld->tx_q); + + return ret; +} + +static int spi_boot_send(struct link_device *ld, struct io_device *iod, + struct sk_buff *skb) +{ + int ret = -EINVAL; + + if (iod->format != IPC_BOOT) { + mif_err("iod->format: %d", + iod->format); + goto err; + } + + ret = spi_boot_tx_skb(ld, iod, skb); + if (ret < 0) { + mif_err("spi_boot_tx_skb() failed(%d)\n", ret); + goto err; + } + + return skb->len; +err: + + dev_kfree_skb_any(skb); + return 0; +} + +static int spi_boot_probe(struct spi_device *spi) +{ + int ret = -ENODEV; + struct device *dev = &spi->dev; + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + + ret = spi_setup(spi); + if (ret < 0) { + mif_err("spi_setup() fail(%d)\n", ret); + return ret; + } + + spi_boot_id->spi = spi; + + if (dev->of_node) { + struct device_node *np; + unsigned gpio_cp_status; + + np = of_find_compatible_node(NULL, NULL, + "sec_modem,modem_pdata"); + if (!np) { + mif_err("DT, failed to get node\n"); + ret = -EINVAL; + goto err_setup; + } + + gpio_cp_status = of_get_named_gpio(np, "mif,gpio_cp_status", 0); + if (!gpio_is_valid(gpio_cp_status)) { + mif_err("gpio_cp_status: Invalied gpio pins\n"); + ret = -EINVAL; + goto err_setup; + } + mif_err("gpio_cp_status: %d\n", gpio_cp_status); + + spi_boot_id->gpio_cp_status = gpio_cp_status; + } else { + struct modem_boot_spi_platform_data *pdata; + + pdata = dev->platform_data; + if (!pdata) { + mif_err("Non-DT, incorrect pdata!\n"); + ret = -EINVAL; + goto err_setup; + } + + spi_boot_id->gpio_cp_status = pdata->gpio_cp_status; + } + + spi_set_drvdata(spi, spi_boot_id); + + mif_info("success\n"); + return 0; + +err_setup: + kfree(spi_boot_id); + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id modem_boot_spi_match[] = { + { .compatible = "spi_boot_link", }, + {}, +}; +MODULE_DEVICE_TABLE(of, modem_boot_spi_match); +#endif + +static struct spi_driver spi_boot_driver = { + .probe = spi_boot_probe, + .driver = { + .name = "spi_modem_boot", + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = of_match_ptr(modem_boot_spi_match), +#endif + }, +}; + +struct link_device *spi_create_link_device(struct platform_device *pdev) +{ + int ret; + + struct modem_data *pdata = pdev->dev.platform_data; + struct link_device *ld; + + mif_err("&&** spi create link device \n"); + + if (!pdata) { + mif_err("modem_data is null\n"); + return NULL; + } + + spi_boot_id = kzalloc(sizeof(struct spi_boot_link_device), GFP_KERNEL); + if (!spi_boot_id) { + mif_err("allocation fail for spi_boot_id\n"); + return NULL; + } + + INIT_LIST_HEAD(&spi_boot_id->ld.list); + + ld = &spi_boot_id->ld; + + ld->name = "spi_boot"; + ld->init_comm = spi_boot_init; + ld->terminate_comm = spi_boot_terminate; + ld->send = spi_boot_send; + //ld->com_state = COM_NONE; + + ret = spi_register_driver(&spi_boot_driver); + if (ret) { + mif_err("spi_register_driver() fail(%d)\n", ret); + goto err; + } + + skb_queue_head_init(&spi_boot_id->tx_q); + + mif_info("success\n"); + + return ld; +err: + kfree(spi_boot_id); + + return NULL; +} + diff --git a/drivers/misc/modem_v1/modem_ctrl_ss300.c b/drivers/misc/modem_v1/modem_ctrl_ss300.c index 48b8fa5aba4b..6cdd2d5e450f 100644 --- a/drivers/misc/modem_v1/modem_ctrl_ss300.c +++ b/drivers/misc/modem_v1/modem_ctrl_ss300.c @@ -176,8 +176,8 @@ static int ss300_on(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } - if (ld->ready) - ld->ready(ld); + if (ld->off) + ld->off(ld); spin_unlock_irqrestore(&mc->lock, flags); @@ -283,6 +283,9 @@ static int ss300_reset(struct modem_ctl *mc) static int ss300_force_crash_exit(struct modem_ctl *mc) { + struct io_device *iod = mc->iod; + struct link_device *ld = get_current_link(iod); + mif_err("+++\n"); if (mc->wake_lock && !wake_lock_active(mc->wake_lock)) { @@ -290,6 +293,9 @@ static int ss300_force_crash_exit(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } + if (ld->off) + ld->off(ld); + gpio_set_value(mc->gpio_ap_dump_int, 1); mif_info("set ap_dump_int(%d) to high=%d\n", mc->gpio_ap_dump_int, gpio_get_value(mc->gpio_ap_dump_int)); @@ -320,8 +326,8 @@ static int ss300_dump_reset(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } - if (ld->ready) - ld->ready(ld); + if (ld->off) + ld->off(ld); spin_unlock_irqrestore(&mc->lock, flags); diff --git a/drivers/misc/modem_v1/modem_ctrl_ss333.c b/drivers/misc/modem_v1/modem_ctrl_ss333.c index 134b97fdc504..a826aef354e2 100644 --- a/drivers/misc/modem_v1/modem_ctrl_ss333.c +++ b/drivers/misc/modem_v1/modem_ctrl_ss333.c @@ -52,7 +52,7 @@ void modem_state_change(struct modem_ctl *mc, enum modem_state new_state) if (mc->iod_ds && mc->iod_ds->modem_state_changed) mc->iod_ds->modem_state_changed(mc->iod_ds, new_state); - if (mc->bootd && mc->iod->modem_state_changed) + if (mc->bootd && mc->bootd->modem_state_changed) mc->bootd->modem_state_changed(mc->bootd, new_state); } @@ -192,8 +192,8 @@ static int ss333_on(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } - if (ld->ready) - ld->ready(ld); + if (ld->off) + ld->off(ld); spin_unlock_irqrestore(&mc->lock, flags); @@ -324,6 +324,9 @@ static void handle_no_response_cp_crash(unsigned long arg) static int ss333_force_crash_exit(struct modem_ctl *mc) { + struct io_device *iod = mc->iod; + struct link_device *ld = get_current_link(iod); + mif_err("+++\n"); mif_add_timer(&mc->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, @@ -334,6 +337,9 @@ static int ss333_force_crash_exit(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } + if (ld->off) + ld->off(ld); + gpio_set_value(mc->gpio_ap_dump_int, 1); mif_info("set ap_dump_int(%d) to high=%d\n", mc->gpio_ap_dump_int, gpio_get_value(mc->gpio_ap_dump_int)); @@ -364,8 +370,8 @@ static int ss333_dump_reset(struct modem_ctl *mc) mif_err("%s->wake_lock locked\n", mc->name); } - if (ld->ready) - ld->ready(ld); + if (ld->off) + ld->off(ld); spin_unlock_irqrestore(&mc->lock, flags); diff --git a/drivers/misc/modem_v1/modem_link_device_spi_boot.h b/drivers/misc/modem_v1/modem_link_device_spi_boot.h new file mode 100644 index 000000000000..228e6cc2d469 --- /dev/null +++ b/drivers/misc/modem_v1/modem_link_device_spi_boot.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2010 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MODEM_LINK_DEVICE_SPI_BOOT_H__ +#define __MODEM_LINK_DEVICE_SPI_BOOT_H__ + +struct spi_boot_link_device { + struct link_device ld; + struct spi_device *spi; + struct sk_buff_head tx_q; + unsigned int gpio_cp_status; +}; + +#endif diff --git a/drivers/misc/modem_v1/modem_main.c b/drivers/misc/modem_v1/modem_main.c index d834bcc8eeb1..9f5411104f81 100644 --- a/drivers/misc/modem_v1/modem_main.c +++ b/drivers/misc/modem_v1/modem_main.c @@ -506,6 +506,9 @@ static struct modem_data *modem_if_parse_dt_pdata(struct device *dev) goto error; } + board_gpio_export(dev, pdata->gpio_cp_status, + false, "cp_status"); + iodevs = of_get_child_by_name(dev->of_node, "iodevs"); if (!iodevs) { mif_err("DT error: failed to get child node\n"); @@ -586,9 +589,11 @@ static int modem_probe(struct platform_device *pdev) /* find matching link type */ if (pdata->link_types & LINKTYPE(i)) { ld = call_link_init_func(pdev, i); - if (!ld) - goto free_mc; - + if (!ld) { + mif_err("%s: link creation failed: continue\n", + pdata->name); + continue; + } mif_err("%s: %s link created\n", pdata->name, ld->name); spin_lock_init(&ld->lock); @@ -601,6 +606,11 @@ static int modem_probe(struct platform_device *pdev) } } + if (list_empty(&msd->link_dev_list)) { + mif_err("Link dev list is empty!!\n"); + goto free_mc; + } + /* create io deivces and connect to modemctl device */ size = sizeof(struct io_device *) * pdata->num_iodevs; iod = kzalloc(size, GFP_KERNEL); @@ -617,6 +627,8 @@ static int modem_probe(struct platform_device *pdev) platform_set_drvdata(pdev, modemctl); + create_baseband_info(modemctl); + kfree(iod); mif_err("%s: ---\n", pdev->name); diff --git a/drivers/misc/modem_v1/modem_prj.h b/drivers/misc/modem_v1/modem_prj.h index 950690804c47..43923f511a47 100644 --- a/drivers/misc/modem_v1/modem_prj.h +++ b/drivers/misc/modem_v1/modem_prj.h @@ -471,10 +471,6 @@ struct link_device { /* flag of stopped state for all channels */ atomic_t netif_stopped; - struct workqueue_struct *tx_wq; - struct work_struct tx_work; - struct delayed_work tx_delayed_work; - struct delayed_work *tx_dwork[MAX_SIPC_DEVICES]; struct delayed_work fmt_tx_dwork; struct delayed_work raw_tx_dwork; @@ -526,9 +522,6 @@ struct link_device { /*====================================================================*/ /* Below are specific methods to each physical link device */ - /* ready a link_device instance */ - void (*ready)(struct link_device *ld); - /* reset physical link */ void (*reset)(struct link_device *ld); @@ -766,6 +759,8 @@ struct modem_ctl { bool need_switch_to_usb; bool sim_polarity; + struct list_head bbinfo; + bool sim_shutdown_req; void (*modem_complete)(struct modem_ctl *mc); diff --git a/drivers/misc/modem_v1/modem_utils.c b/drivers/misc/modem_v1/modem_utils.c index 0e5548f89386..505e85024082 100644 --- a/drivers/misc/modem_v1/modem_utils.c +++ b/drivers/misc/modem_v1/modem_utils.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "modem_prj.h" #include "modem_utils.h" @@ -266,11 +267,9 @@ static inline void dump2hex(char *buff, size_t buff_size, static inline bool log_enabled(u8 ch, enum ipc_layer layer) { -#ifdef CONFIG_SEC_MODEM_DEBUGFS if (unlikely(layer == IOD_RX || layer == IOD_TX)) if (unlikely(!test_bit(DEBUG_FLAG_IOD, &dflags))) return false; -#endif if (sipc5_fmt_ch(ch)) return test_bit(DEBUG_FLAG_FMT, &dflags); @@ -329,10 +328,11 @@ inline void log_ipc_pkt(enum ipc_layer layer, u8 ch, struct sk_buff *skb) buflen = dump_skb(str, SZ_16, skb); #ifdef CONFIG_SEC_MODEM_DEBUGFS - trace_mif_log(layer_str(layer), buflen, str); + if (!sipc5_udl_ch(ch)) + trace_mif_log(layer_str(layer), buflen, str); #endif - pr_info("%s: %s(%d): %s\n", MIF_TAG, layer_str(layer), buflen, str); + pr_info("%s: %s(%d): %s\n", MIF_TAG, layer_str(layer), buflen, str); } /* print buffer as hex string */ @@ -1214,3 +1214,97 @@ void __ref modemctl_notify_event(enum modemctl_event evt) raw_notifier_call_chain(&cp_crash_notifier, evt, NULL); } +/* Create Baseband info proc */ +static struct mif_baseband_info { + atomic_t num; + struct list_head modems; + spinlock_t lock; +} bb_info = { + .num = {.counter = 0}, + .modems = LIST_HEAD_INIT(bb_info.modems), + .lock = __SPIN_LOCK_UNLOCKED(bb_info.lock), +}; + +static int mif_bbinfo_show(struct seq_file *f, void *offset) +{ + int num = atomic_read(&bb_info.num); + struct modem_ctl *mc; + + seq_printf(f, "Baseband:%d\n", num); + spin_lock_bh(&bb_info.lock); + list_for_each_entry(mc, &bb_info.modems, bbinfo) { + seq_printf(f, "Modem:%s\n" + "Link:%s\n" + "LinkBoot:%s\n" + "LinkMain:%s\n" + "spi_lnk:%s\n" + "Boot:%s\n" + "Binary:%s\n\n", + mc->name, + dev_name(mc->dev), + get_current_link(mc->bootd)->name, + get_current_link(mc->iod)->name, +#ifdef CONFIG_LINK_DEVICE_SPI + "LNK", +#else + "BOOT", +#endif + mc->bootd->name, + "TBD"); + } + spin_unlock_bh(&bb_info.lock); + return 0; +} + +static int bbinfo_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mif_bbinfo_show, inode->i_private); +} + +static const struct file_operations baseband_file_ops = { + .owner = THIS_MODULE, + .open = bbinfo_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +int create_baseband_info(struct modem_ctl *mc) +{ + int num = atomic_inc_return(&bb_info.num); + + mif_err("&&** new base band info created\n" ); + spin_lock_bh(&bb_info.lock); + list_add(&mc->bbinfo, &bb_info.modems); + spin_unlock_bh(&bb_info.lock); + + if (num == 1) { + struct proc_dir_entry *entry; + entry = proc_create_data("baseband", S_IFREG | S_IRUGO, NULL, &baseband_file_ops, mc); + if (!entry) { + mif_err("failed to create proc/baseband entry\n" ); + return 0; + } + } + mif_info("Baseband:%d\n" + "Modem:%s\n" + "Link:%s\n" + "LinkBoot:%s\n" + "LinkMain:%s\n" + "spi_lnk:%s\n" + "Boot:%s\n" + "Binary:%s\n\n", + num, + mc->name, + dev_name(mc->dev), + get_current_link(mc->bootd)->name, + get_current_link(mc->iod)->name, +#ifdef CONFIG_LINK_DEVICE_SPI + "LNK", +#else + "BOOT", +#endif + mc->bootd->name, + "TBD"); + + return 0; +} diff --git a/drivers/misc/modem_v1/modem_utils.h b/drivers/misc/modem_v1/modem_utils.h index b756c13d3ffe..da7c6615c38f 100644 --- a/drivers/misc/modem_v1/modem_utils.h +++ b/drivers/misc/modem_v1/modem_utils.h @@ -532,6 +532,8 @@ int board_gpio_export(struct device *dev, void make_gpio_floating(unsigned int gpio, bool floating); +int create_baseband_info(struct modem_ctl *mc); + #ifdef CONFIG_ARGOS /* kernel team needs to provide argos header file. !!! * As of now, there's nothing to use. */ diff --git a/drivers/misc/tima_debug_log.c b/drivers/misc/tima_debug_log.c index 452194193219..e0c47fa5a8b6 100644 --- a/drivers/misc/tima_debug_log.c +++ b/drivers/misc/tima_debug_log.c @@ -15,7 +15,7 @@ #define DEBUG_LOG_START (0x48002000) #define SECURE_LOG_START (0x48102000) #define DEBUG_RKP_LOG_START (0x52300000) -#define SECURE_RKP_LOG_START (0x4d800000) +#define SECURE_RKP_LOG_START (0x529f8000) #define DEBUG_LOG_SIZE (1<<20) #define DEBUG_LOG_MAGIC (0xaabbccdd) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ac0f597cae7b..9f7a569fbaf2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -861,7 +861,8 @@ static int mmc_select_hs200(struct mmc_card *card, u8 driver_type) /* switch to HS200 mode if bus width set successfully */ if (!err) err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - driver_type | EXT_CSD_HS_TIMING, 2, 0); + EXT_CSD_HS_TIMING, + driver_type | MMC_HS_TIMING_HS200, 0); return err; } diff --git a/drivers/motor/max77833_haptic.c b/drivers/motor/max77833_haptic.c index 4c2484626500..d8a557086911 100644 --- a/drivers/motor/max77833_haptic.c +++ b/drivers/motor/max77833_haptic.c @@ -35,8 +35,13 @@ #define MAX77833_REG_MAINCTRL1_MREN (1 << 3) #define MAX77833_REG_MAINCTRL1_BIASEN (1 << 7) +#ifdef CONFIG_MOTOR_DRV_MAX77843 extern void (*vibtonz_en)(bool); extern void (*vibtonz_pwm)(int); +#else +void (*vibtonz_en)(bool); +void (*vibtonz_pwm)(int); +#endif static struct device *motor_dev; @@ -491,6 +496,71 @@ static int max77833_haptic_probe(struct platform_device *pdev) vibtonz_en = max77833_vibtonz_en; vibtonz_pwm = max77833_vibtonz_pwm; + /* autoresonance range setting */ + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_CONFIG, 0x00); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_CONFIG, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_MIN_FREQ_LOW, 0xA9); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_MIN_FREQ_LOW, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_MAX_FREQ_LOW, 0x7C); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_MAX_FREQ_LOW, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_INIT_GUESS_LOW, 0x92); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_MAX_FREQ_LOW, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_NOMINAL_STRENGTH, 0x5A); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_NOMINAL_STRENGTH, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_RES_MIN_FREQ_HIGH, 0x03); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_RES_MIN_FREQ_HIGH, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_RES_MAX_FREQ_HIGH, 0x03); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_RES_MAX_FREQ_HIGH, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_INIT_GUESS_HIGH, 0x03); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_INIT_GUESS_HIGH, error); + } + + error = max77833_write_reg(hap_data->i2c, + MAX77833_AUTORES_LOCK_WINDOW, 0x22); + if (error < 0) { + pr_err("[VIB] %s Failed to write REG(0x%02x) [%d]\n", + __func__, MAX77833_AUTORES_LOCK_WINDOW, error); + } + + pr_info("[VIB] -- %s\n", __func__); return error; @@ -574,3 +644,4 @@ module_exit(max77833_haptic_exit); MODULE_AUTHOR("ByungChang Cha "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("max77833 haptic driver"); + diff --git a/drivers/muic/Kconfig b/drivers/muic/Kconfig index 47c9ab4d2fd8..477e2ad43b43 100644 --- a/drivers/muic/Kconfig +++ b/drivers/muic/Kconfig @@ -127,19 +127,12 @@ config HV_MUIC_MAX77833_AFC help If you say yes here you will get support for the MAX77833 AFC MUIC. -config MUIC_MAX77833_IGNORE_ADCERR_WA - bool "Using MAX77833 MUIC ignore ADCERR WA" +config MUIC_MAX77833_SHAKEID_WA + bool "Using MAX77833 MUIC SHAKE ID WA" depends on MUIC_MAX77833 default n help - If you say yes here you will get support for the MAX77833 MUIC RESET WA. - -config MUIC_MAX77833_RESET_WA - bool "Using MAX77833 MUIC RESET WA" - depends on MUIC_MAX77833 - default n - help - If you say yes here you will get support for the MAX77833 MUIC RESET WA. + If you say yes here you will get support for the MAX77833 MUIC SHAKE ID WA. config MUIC_MAX77888 bool "Using MAX77888 MUIC" diff --git a/drivers/muic/max77833-muic-afc.c b/drivers/muic/max77833-muic-afc.c index 3cc61ccca7fb..ecbb412af491 100644 --- a/drivers/muic/max77833-muic-afc.c +++ b/drivers/muic/max77833-muic-afc.c @@ -1,8 +1,8 @@ /* * max77833-muic.c - MUIC driver for the Maxim 77833 * - * Copyright (C) 2012 Samsung Electronics - * Seoyoung Jeong + * Copyright (C) 2015 Samsung Electronics + * Insun Choi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,6 @@ /* MUIC header file */ #include -#include #include #include @@ -42,1666 +41,216 @@ #include #endif /* CONFIG_MUIC_NOTIFIER */ -#if !defined(CONFIG_SEC_FACTORY) -#if defined(CONFIG_MUIC_ADCMODE_SWITCH_WA) -#include -#endif /* CONFIG_MUIC_ADCMODE_SWITCH_WA */ -#endif /* !CONFIG_SEC_FACTORY */ - -static bool debug_en_checklist = false; - -/* temp function for function pointer (TODO) */ -enum act_function_num { - FUNC_TA_TO_PREPARE = 0, - FUNC_PREPARE_TO_PREPARE_DUPLI, - FUNC_PREPARE_TO_AFC_5V, - FUNC_PREPARE_TO_QC_PREPARE, - FUNC_PREPARE_DUPLI_TO_PREPARE_DUPLI, - FUNC_PREPARE_DUPLI_TO_AFC_5V, - FUNC_PREPARE_DUPLI_TO_AFC_ERR_V, - FUNC_PREPARE_DUPLI_TO_AFC_9V, - FUNC_PREPARE_DUPLI_TO_QC_PREPARE, - FUNC_AFC_5V_TO_AFC_5V_DUPLI, - FUNC_AFC_5V_TO_AFC_ERR_V, - FUNC_AFC_5V_TO_AFC_9V, - FUNC_AFC_5V_TO_QC_PREPARE, - FUNC_AFC_5V_DUPLI_TO_AFC_5V_DUPLI, - FUNC_AFC_5V_DUPLI_TO_AFC_ERR_V, - FUNC_AFC_5V_DUPLI_TO_AFC_9V, - FUNC_AFC_5V_DUPLI_TO_QC_PREPARE, - FUNC_AFC_ERR_V_TO_AFC_ERR_V_DUPLI, - FUNC_AFC_ERR_V_TO_AFC_9V, - FUNC_AFC_ERR_V_TO_QC_PREPARE, - FUNC_AFC_ERR_V_DUPLI_TO_AFC_ERR_V_DUPLI, - FUNC_AFC_ERR_V_DUPLI_TO_AFC_9V, - FUNC_AFC_ERR_V_DUPLI_TO_QC_PREPARE, - FUNC_AFC_9V_TO_AFC_9V, - FUNC_QC_PREPARE_TO_QC_5V, - FUNC_QC_PREPARE_TO_QC_9V, - FUNC_QC_5V_TO_QC_5V, - FUNC_QC_5V_TO_QC_9V, - FUNC_QC_9V_TO_QC_9V, -}; - -/* afc_condition_checklist[ATTACHED_DEV_TA_MUIC] */ -muic_afc_data_t ta_to_prepare = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC, - .afc_name = "AFC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_VDNMON, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_LOW, - .function_num = FUNC_TA_TO_PREPARE, - .next = &ta_to_prepare, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC] */ -muic_afc_data_t prepare_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_TO_QC_PREPARE, - .next = &prepare_to_qc_prepare, -}; - -muic_afc_data_t prepare_to_afc_5v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_5V_MUIC, - .afc_name = "AFC charger 5V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_TO_AFC_5V, - .next = &prepare_to_qc_prepare, -}; - -muic_afc_data_t prepare_to_prepare_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC, - .afc_name = "AFC charger prepare (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_TO_PREPARE_DUPLI, - .next = &prepare_to_afc_5v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC] */ -muic_afc_data_t prepare_dupli_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_DUPLI_TO_QC_PREPARE, - .next = &prepare_dupli_to_qc_prepare, -}; - -muic_afc_data_t prepare_dupli_to_prepare_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC, - .afc_name = "AFC charger prepare (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_DUPLI_TO_PREPARE_DUPLI, - .next = &prepare_dupli_to_qc_prepare, -}; - -muic_afc_data_t prepare_dupli_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_DUPLI_TO_AFC_9V, - .next = &prepare_dupli_to_prepare_dupli, -}; - -muic_afc_data_t prepare_dupli_to_afc_err_v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC, - .afc_name = "AFC charger ERR V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_ERR_V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_DUPLI_TO_AFC_ERR_V, - .next = &prepare_dupli_to_afc_9v, -}; - -muic_afc_data_t prepare_dupli_to_afc_5v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_5V_MUIC, - .afc_name = "AFC charger 5V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_PREPARE_DUPLI_TO_AFC_5V, - .next = &prepare_dupli_to_afc_err_v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_5V_MUIC] */ -muic_afc_data_t afc_5v_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_TO_QC_PREPARE, - .next = &afc_5v_to_qc_prepare, -}; - -muic_afc_data_t afc_5v_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_TO_AFC_9V, - .next = &afc_5v_to_qc_prepare, -}; - -muic_afc_data_t afc_5v_to_afc_err_v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC, - .afc_name = "AFC charger ERR V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_ERR_V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_TO_AFC_ERR_V, - .next = &afc_5v_to_afc_9v, -}; - -muic_afc_data_t afc_5v_to_afc_5v_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC, - .afc_name = "AFC charger 5V (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_TO_AFC_5V_DUPLI, - .next = &afc_5v_to_afc_err_v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC] */ -muic_afc_data_t afc_5v_dupli_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_DUPLI_TO_QC_PREPARE, - .next = &afc_5v_dupli_to_qc_prepare, -}; - -muic_afc_data_t afc_5v_dupli_to_afc_5v_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC, - .afc_name = "AFC charger 5V (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_DUPLI_TO_AFC_5V_DUPLI, - .next = &afc_5v_dupli_to_qc_prepare, -}; - -muic_afc_data_t afc_5v_dupli_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_DUPLI_TO_AFC_9V, - .next = &afc_5v_dupli_to_afc_5v_dupli, -}; - -muic_afc_data_t afc_5v_dupli_to_afc_err_v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC, - .afc_name = "AFC charger ERR V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_ERR_V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_5V_DUPLI_TO_AFC_ERR_V, - .next = &afc_5v_dupli_to_afc_9v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC] */ -muic_afc_data_t afc_err_v_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_TO_QC_PREPARE, - .next = &afc_err_v_to_qc_prepare, -}; - -muic_afc_data_t afc_err_v_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_TO_AFC_9V, - .next = &afc_err_v_to_qc_prepare, -}; - -muic_afc_data_t afc_err_v_to_afc_err_v_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC, - .afc_name = "AFC charger ERR V (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_ERR_V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_TO_AFC_ERR_V_DUPLI, - .next = &afc_err_v_to_afc_9v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC] */ -muic_afc_data_t afc_err_v_dupli_to_qc_prepare = { - .new_dev = ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC, - .afc_name = "QC charger Prepare", - .afc_irq = MUIC_AFC_IRQ_MPNACK, - .hvcontrol1_dpdnvden = DPDNVDEN_DONTCARE, - .status3_vbadc = VBADC_DONTCARE, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_DUPLI_TO_QC_PREPARE, - .next = &afc_err_v_dupli_to_qc_prepare, -}; - -muic_afc_data_t afc_err_v_dupli_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_DUPLI_TO_AFC_9V, - .next = &afc_err_v_dupli_to_qc_prepare, -}; - -muic_afc_data_t afc_err_v_dupli_to_afc_err_v_dupli = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC, - .afc_name = "AFC charger ERR V (mrxrdy)", - .afc_irq = MUIC_AFC_IRQ_MRXRDY, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_ERR_V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_ERR_V_DUPLI_TO_AFC_ERR_V_DUPLI, - .next = &afc_err_v_dupli_to_afc_9v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_AFC_CHARGER_9V_MUIC] */ -muic_afc_data_t afc_9v_to_afc_9v = { - .new_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, - .afc_name = "AFC charger 9V", - .afc_irq = MUIC_AFC_IRQ_DONTCARE, - .hvcontrol1_dpdnvden = DPDNVDEN_DISABLE, - .status3_vbadc = VBADC_AFC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_AFC_9V_TO_AFC_9V, - .next = &afc_9v_to_afc_9v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC] */ -muic_afc_data_t qc_prepare_to_qc_9v = { - .new_dev = ATTACHED_DEV_QC_CHARGER_9V_MUIC, - .afc_name = "QC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_QC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_QC_PREPARE_TO_QC_9V, - .next = &qc_prepare_to_qc_9v, -}; - -muic_afc_data_t qc_prepare_to_qc_5v = { - .new_dev = ATTACHED_DEV_QC_CHARGER_5V_MUIC, - .afc_name = "QC charger 5V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_QC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_QC_PREPARE_TO_QC_5V, - .next = &qc_prepare_to_qc_9v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_QC_CHARGER_5V_MUIC] */ -muic_afc_data_t qc_5v_to_qc_5v = { - .new_dev = ATTACHED_DEV_QC_CHARGER_5V_MUIC, - .afc_name = "QC charger 5V", - .afc_irq = MUIC_AFC_IRQ_DONTCARE, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_QC_5V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_QC_5V_TO_QC_5V, - .next = &qc_5v_to_qc_5v, -}; - -muic_afc_data_t qc_5v_to_qc_9v = { - .new_dev = ATTACHED_DEV_QC_CHARGER_9V_MUIC, - .afc_name = "QC charger 9V", - .afc_irq = MUIC_AFC_IRQ_VBADC, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_QC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_QC_5V_TO_QC_9V, - .next = &qc_5v_to_qc_5v, -}; - -/* afc_condition_checklist[ATTACHED_DEV_QC_CHARGER_9V_MUIC] */ -muic_afc_data_t qc_9v_to_qc_9v = { - .new_dev = ATTACHED_DEV_QC_CHARGER_9V_MUIC, - .afc_name = "QC charger 9V", - .afc_irq = MUIC_AFC_IRQ_DONTCARE, - .hvcontrol1_dpdnvden = DPDNVDEN_ENABLE, - .status3_vbadc = VBADC_QC_9V, - .status3_vdnmon = VDNMON_DONTCARE, - .function_num = FUNC_QC_9V_TO_QC_9V, - .next = &qc_9v_to_qc_9v, -}; - -muic_afc_data_t *afc_condition_checklist[ATTACHED_DEV_NUM] = { - [ATTACHED_DEV_TA_MUIC] = &ta_to_prepare, - [ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC] = &prepare_to_prepare_dupli, - [ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC] = &prepare_dupli_to_afc_5v, - [ATTACHED_DEV_AFC_CHARGER_5V_MUIC] = &afc_5v_to_afc_5v_dupli, - [ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC]= &afc_5v_dupli_to_afc_err_v, - [ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC] = &afc_err_v_to_afc_err_v_dupli, - [ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC] = &afc_err_v_dupli_to_afc_err_v_dupli, - [ATTACHED_DEV_AFC_CHARGER_9V_MUIC] = &afc_9v_to_afc_9v, - [ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC] = &qc_prepare_to_qc_9v, - [ATTACHED_DEV_QC_CHARGER_5V_MUIC] = &qc_5v_to_qc_5v, - [ATTACHED_DEV_QC_CHARGER_9V_MUIC] = &qc_9v_to_qc_9v, -}; - -struct afc_init_data_s { - struct work_struct muic_afc_init_work; - struct max77833_muic_data *muic_data; -}; -struct afc_init_data_s afc_init_data; - -bool muic_check_is_hv_dev(struct max77833_muic_data *muic_data) -{ - bool ret = false; - - switch (muic_data->attached_dev) { - case ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC: - case ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC: - case ATTACHED_DEV_AFC_CHARGER_9V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC: - case ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC: - case ATTACHED_DEV_QC_CHARGER_5V_MUIC: - case ATTACHED_DEV_QC_CHARGER_9V_MUIC: - case ATTACHED_DEV_HV_ID_ERR_UNDEFINED_MUIC: - case ATTACHED_DEV_HV_ID_ERR_UNSUPPORTED_MUIC: - case ATTACHED_DEV_HV_ID_ERR_SUPPORTED_MUIC: - ret = true; - break; - default: - ret = false; - break; - } - - if (debug_en_checklist) - pr_info("%s:%s attached_dev(%d)[%c]\n", MUIC_HV_DEV_NAME, - __func__, muic_data->attached_dev, (ret ? 'T' : 'F')); - - return ret; -} - -muic_attached_dev_t hv_muic_check_id_err - (struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) -{ - muic_attached_dev_t after_new_dev = new_dev; - - if (!muic_check_is_hv_dev(muic_data)) - goto out; - - switch(new_dev) { - case ATTACHED_DEV_TA_MUIC: - pr_info("%s:%s cannot change HV(%d)->TA(%d)!\n", MUIC_DEV_NAME, - __func__, muic_data->attached_dev, new_dev); - after_new_dev = muic_data->attached_dev; - break; - case ATTACHED_DEV_UNDEFINED_CHARGING_MUIC: - pr_info("%s:%s HV ID Err - Undefined\n", MUIC_DEV_NAME, __func__); - after_new_dev = ATTACHED_DEV_HV_ID_ERR_UNDEFINED_MUIC; - break; - case ATTACHED_DEV_UNSUPPORTED_ID_VB_MUIC: - pr_info("%s:%s HV ID Err - Unsupported\n", MUIC_DEV_NAME, __func__); - after_new_dev = ATTACHED_DEV_HV_ID_ERR_UNSUPPORTED_MUIC; - break; - default: - pr_info("%s:%s HV ID Err - Supported\n", MUIC_DEV_NAME, __func__); - after_new_dev = ATTACHED_DEV_HV_ID_ERR_SUPPORTED_MUIC; - break; - } -out: - return after_new_dev; -} - -static int max77833_hv_muic_read_reg(struct i2c_client *i2c, u8 reg, u8 *value) -{ - int ret; - - ret = max77833_read_reg(i2c, reg, value); - if (ret < 0) - pr_err("%s:%s err read REG(0x%02x) [%d]\n", MUIC_HV_DEV_NAME, - __func__, reg, ret); - return ret; -} - -static int max77833_hv_muic_write_reg(struct i2c_client *i2c, u8 reg, u8 value) -{ - u8 before_val, after_val; - int ret; - - max77833_read_reg(i2c, reg, &before_val); - ret = max77833_write_reg(i2c, reg, value); - max77833_read_reg(i2c, reg, &after_val); - - pr_info("%s:%s reg[0x%02x] = [0x%02x] + [0x%02x] -> [0x%02x]\n", - MUIC_HV_DEV_NAME, __func__, reg, before_val, value, after_val); - return ret; -} - -int max77833_muic_hv_update_reg(struct i2c_client *i2c, - const u8 reg, const u8 val, const u8 mask, const bool debug_en) -{ - u8 before_val, new_val, after_val; - int ret = 0; - - ret = max77833_read_reg(i2c, reg, &before_val); - if (ret) - pr_err("%s:%s err read REG(0x%02x) [%d] \n", MUIC_DEV_NAME, - __func__, reg, ret); - - new_val = (val & mask) | (before_val & (~mask)); - - if (before_val ^ new_val) { - ret = max77833_hv_muic_write_reg(i2c, reg, new_val); - if (ret) - pr_err("%s:%s err write REG(0x%02x) [%d]\n", - MUIC_DEV_NAME, __func__, reg, ret); - } else if (debug_en) { - pr_info("%s:%s REG(0x%02x): already [0x%02x], don't write reg\n", - MUIC_DEV_NAME, __func__, reg, before_val); - goto out; - } - - if (debug_en) { - ret = max77833_read_reg(i2c, reg, &after_val); - if (ret < 0) - pr_err("%s:%s err read REG(0x%02x) [%d]\n", - MUIC_DEV_NAME, __func__, reg, ret); - - pr_info("%s:%s REG(0x%02x): [0x%02x]+[0x%02x:0x%02x]=[0x%02x]\n", - MUIC_DEV_NAME, __func__, reg, before_val, - val, mask, after_val); - } - -out: - return ret; -} - -void max77833_hv_muic_reset_hvcontrol_reg(struct max77833_muic_data *muic_data) -{ - struct i2c_client *i2c = muic_data->i2c; - - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x00); - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL2, 0x00); -} - -void max77833_muic_set_afc_ready(struct max77833_muic_data *muic_data, bool value) -{ - bool before, after; - - before = muic_data->is_afc_muic_ready; - muic_data->is_afc_muic_ready = value; - after = muic_data->is_afc_muic_ready; - - pr_info("%s:%s afc_muic_ready[%d->%d]\n", MUIC_DEV_NAME, __func__, before, after); -} - -static int max77833_hv_muic_state_maintain(struct max77833_muic_data *muic_data) +void max77833_muic_hv_qc_autoset(struct max77833_muic_data *muic_data, u8 val, u8 mask) { - int ret = 0; - - pr_info("%s:%s \n", MUIC_HV_DEV_NAME, __func__); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_QC_AUTOSET_WRITE; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; - if (muic_data->attached_dev == ATTACHED_DEV_NONE_MUIC) { - pr_info("%s:%s Detached(%d), need to check after\n", MUIC_HV_DEV_NAME, - __func__, muic_data->attached_dev); - return ret; - } - - return ret; -} - -static void max77833_hv_muic_set_afc_after_prepare - (struct max77833_muic_data *muic_data) -{ - struct i2c_client *i2c = muic_data->i2c; - u8 value; - - pr_info("%s:%s HV charger is detected\n", MUIC_HV_DEV_NAME, __func__); - - /* Set HVCONTROL2 = 0x02 */ - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL2, - HVCONTROL2_DP06EN_MASK); - - /* Set HVCONTROL1 - disable DPVD, DPDNVDEN */ - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x20); - - /* Set TX DATA */ - value = muic_data->tx_data; - - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVTXBYTE, value); - - /* Set HVCONTROL2 = 0x1B */ - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL2, MAX77833_MUIC_HVCONTROL2_1B); - -} - -static void max77833_hv_muic_set_afc_charger_handshaking - (struct max77833_muic_data *muic_data) -{ - struct i2c_client *i2c = muic_data->i2c; - u8 hvtxbyte; - u8 hvrxbyte[HVRXBYTE_MAX]; - u8 selecthvtxbyte=0; - int i, ret; - - pr_info("%s:%s \n", MUIC_HV_DEV_NAME, __func__); + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); - ret = max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL2, 0x13); - if (IS_ERR_VALUE(ret)) - pr_err("%s:%s cannot write hvcontrol2(%d)\n", MUIC_HV_DEV_NAME, __func__, ret); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; - max77833_hv_muic_read_reg(i2c, MAX77833_MUIC_REG_HVTXBYTE, &hvtxbyte); + enqueue_muic_cmd(cmd_queue, cmd_data); - for(i = 0; i < HVRXBYTE_MAX; i++) { - max77833_hv_muic_read_reg(i2c, (MAX77833_MUIC_REG_HVRXBYTE1+i), &hvrxbyte[i]); - if(hvrxbyte[i] == 0) - break; - } + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; - if(hvrxbyte[0] != hvtxbyte) { - for(i = 0; (i < HVRXBYTE_MAX) && (hvrxbyte[i] != 0); i++) { - if(((hvrxbyte[i] & 0xF0) == 0x40) && (hvtxbyte > selecthvtxbyte)) - selecthvtxbyte = hvrxbyte[i]; - } - if(selecthvtxbyte != 0) - max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVTXBYTE, selecthvtxbyte); - } + enqueue_muic_cmd(cmd_queue, cmd_data); return; } -static void max77833_hv_muic_afc_control_ping - (struct max77833_muic_data *muic_data, bool ping_continue) +void max77833_muic_hv_qc_enable(struct max77833_muic_data *muic_data) { - int ret; - - pr_info("%s:%s control ping[%d, %c]\n", MUIC_HV_DEV_NAME, __func__, - muic_data->afc_count, ping_continue ? 'T' : 'F'); - - if (ping_continue) - ret = max77833_hv_muic_write_reg(muic_data->i2c, MAX77833_MUIC_REG_HVCONTROL2, 0x5B); - else - ret = max77833_hv_muic_write_reg(muic_data->i2c, MAX77833_MUIC_REG_HVCONTROL2, 0x03); - - if (ret) { - pr_err("%s:%s cannot writing HVCONTROL2 reg(%d)\n", - MUIC_HV_DEV_NAME, __func__, ret); - } -} - -static void max77833_hv_muic_qc_charger(struct max77833_muic_data *muic_data) -{ - struct i2c_client *i2c = muic_data->i2c; - int ret; - u8 status3; - - ret = max77833_hv_muic_read_reg(i2c, MAX77833_MUIC_REG_STATUS3, &status3); - if (ret) { - pr_err("%s:%s cannot read STATUS3 reg(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - } - - pr_info("%s:%s STATUS3:0x%02x qc_hv:%x\n", MUIC_HV_DEV_NAME, __func__, - status3, muic_data->qc_hv); - - switch (muic_data->qc_hv) { - case HV_SUPPORT_QC_9V: - ret = max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x3D); - break; - case HV_SUPPORT_QC_12V: - ret = max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x35); - break; - case HV_SUPPORT_QC_20V: - ret = max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x3F); - break; - case HV_SUPPORT_QC_5V: - ret = max77833_hv_muic_write_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, 0x33); - break; - default: - pr_err("%s:%s not support QC Charger\n", MUIC_HV_DEV_NAME, __func__); - break; - } - - if (ret) { - pr_err("%s:%s cannot writing HVCONTROL2 reg(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - } -} - -static void max77833_hv_muic_after_qc_prepare(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - muic_data->is_qc_vb_settle = false; - - schedule_delayed_work(&muic_data->hv_muic_qc_vb_work, msecs_to_jiffies(300)); -} - -static void max77833_hv_muic_adcmode_switch - (struct max77833_muic_data *muic_data, bool always_on) -{ - struct i2c_client *i2c = muic_data->i2c; - int ret; - - pr_info("%s:%s always_on:%c\n", MUIC_HV_DEV_NAME, __func__, (always_on ? 'T' : 'F')); - - if (always_on) { -#if !defined(CONFIG_SEC_FACTORY) - max77833_muic_set_idmode_continuous(muic_data); -#endif /* CONFIG_SEC_FACTORY */ - ret = max77833_muic_hv_update_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, - (MAX77833_ENABLE_BIT << HVCONTROL1_VBUSADCEN_SHIFT), - HVCONTROL1_VBUSADCEN_MASK, true); - } else { -#if !defined(CONFIG_SEC_FACTORY) - max77833_muic_set_idmode_oneshot(muic_data); -#endif /* CONFIG_SEC_FACTORY */ - /* non MAXIM */ - ret = max77833_muic_hv_update_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, - (MAX77833_DISABLE_BIT << HVCONTROL1_VBUSADCEN_SHIFT), - HVCONTROL1_VBUSADCEN_MASK, true); - } - - if (ret) - pr_err("%s:%s cannot switch adcmode(%d)\n", MUIC_HV_DEV_NAME, __func__, ret); -} - -static void max77833_hv_muic_adcmode_always_on(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - max77833_hv_muic_adcmode_switch(muic_data, true); -} - -void max77833_hv_muic_adcmode_oneshot(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - max77833_hv_muic_adcmode_switch(muic_data, false); -} - -static int max77833_hv_muic_handle_attach - (struct max77833_muic_data *muic_data, const muic_afc_data_t *new_afc_data) -{ - int ret = 0; - bool noti = true; - muic_attached_dev_t new_dev = new_afc_data->new_dev; - - pr_info("%s:%s \n", MUIC_HV_DEV_NAME, __func__); - - if (muic_data->is_charger_ready == false) { - if (new_afc_data->new_dev == ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC) { - muic_data->is_afc_muic_prepare = true; - pr_info("%s:%s is_charger_ready[%c], is_afc_muic_prepare[%c]\n", - MUIC_HV_DEV_NAME, __func__, - (muic_data->is_charger_ready ? 'T' : 'F'), - (muic_data->is_afc_muic_prepare ? 'T' : 'F')); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_QC_ENABLE_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - return ret; - } - pr_info("%s:%s is_charger_ready[%c], just return\n", MUIC_HV_DEV_NAME, - __func__, (muic_data->is_charger_ready ? 'T' : 'F')); - return ret; - } - - switch (new_afc_data->function_num) { - case FUNC_TA_TO_PREPARE: - max77833_hv_muic_adcmode_always_on(muic_data); - max77833_hv_muic_set_afc_after_prepare(muic_data); - muic_data->afc_count = 0; - muic_data->is_afc_handshaking = false; - break; - case FUNC_PREPARE_TO_PREPARE_DUPLI: - muic_data->afc_count++; - max77833_hv_muic_set_afc_charger_handshaking(muic_data); - muic_data->is_afc_handshaking = true; - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_PREPARE_TO_AFC_5V: - /* NEED ?? */ - if (!muic_data->is_afc_handshaking) { - max77833_hv_muic_set_afc_charger_handshaking(muic_data); - muic_data->is_afc_handshaking = true; - } - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_PREPARE_TO_QC_PREPARE: - /* ping STOP */ - ret = max77833_hv_muic_write_reg(muic_data->i2c, MAX77833_MUIC_REG_HVCONTROL2, 0x03); - if (ret) { - pr_err("%s:%s cannot writing HVCONTROL2 reg(%d)\n", - MUIC_HV_DEV_NAME, __func__, ret); - } - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_PREPARE_DUPLI_TO_PREPARE_DUPLI: - muic_data->afc_count++; - if (!muic_data->is_afc_handshaking) { - max77833_hv_muic_set_afc_charger_handshaking(muic_data); - muic_data->is_afc_handshaking = true; - } - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_PREPARE_DUPLI_TO_AFC_5V: - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_PREPARE_DUPLI_TO_AFC_ERR_V: - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_PREPARE_DUPLI_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_PREPARE_DUPLI_TO_QC_PREPARE: - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_AFC_5V_TO_AFC_5V_DUPLI: - muic_data->afc_count++; - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_always_on(muic_data); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_5V_TO_AFC_ERR_V: - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_5V_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_AFC_5V_TO_QC_PREPARE: - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_AFC_5V_DUPLI_TO_AFC_5V_DUPLI: - muic_data->afc_count++; - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_always_on(muic_data); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_5V_DUPLI_TO_AFC_ERR_V: - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_5V_DUPLI_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_AFC_5V_DUPLI_TO_QC_PREPARE: - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_AFC_ERR_V_TO_AFC_ERR_V_DUPLI: - muic_data->afc_count++; - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_always_on(muic_data); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_ERR_V_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_AFC_ERR_V_TO_QC_PREPARE: - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_AFC_ERR_V_DUPLI_TO_AFC_ERR_V_DUPLI: - muic_data->afc_count++; - if (muic_data->afc_count > AFC_CHARGER_WA_PING) { - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_always_on(muic_data); - } else { - max77833_hv_muic_afc_control_ping(muic_data, true); - noti = false; - } - break; - case FUNC_AFC_ERR_V_DUPLI_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_AFC_ERR_V_DUPLI_TO_QC_PREPARE: - max77833_hv_muic_qc_charger(muic_data); - max77833_hv_muic_after_qc_prepare(muic_data); - break; - case FUNC_AFC_9V_TO_AFC_9V: - max77833_hv_muic_afc_control_ping(muic_data, false); - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_QC_PREPARE_TO_QC_5V: - if (muic_data->is_qc_vb_settle == true) - max77833_hv_muic_adcmode_oneshot(muic_data); - else - noti = false; - break; - case FUNC_QC_PREPARE_TO_QC_9V: - muic_data->is_qc_vb_settle = true; - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_QC_5V_TO_QC_5V: - if (muic_data->is_qc_vb_settle == true) - max77833_hv_muic_adcmode_oneshot(muic_data); - else - noti = false; - break; - case FUNC_QC_5V_TO_QC_9V: - muic_data->is_qc_vb_settle = true; - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - case FUNC_QC_9V_TO_QC_9V: - max77833_hv_muic_adcmode_oneshot(muic_data); - break; - default: - pr_warn("%s:%s undefinded hv function num(%d)\n", MUIC_HV_DEV_NAME, - __func__, new_afc_data->function_num); - ret = -ESRCH; - goto out; - } - -#if defined(CONFIG_MUIC_NOTIFIER) - if (muic_data->attached_dev == new_dev) - noti = false; - else if (new_dev == ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC) - noti = false; - - if (noti) - muic_notifier_attach_attached_dev(new_dev); -#endif /* CONFIG_MUIC_NOTIFIER */ - - muic_data->attached_dev = new_dev; -out: - return ret; -} - -static bool muic_check_hv_irq - (struct max77833_muic_data *muic_data, - const muic_afc_data_t *tmp_afc_data, int irq) -{ - int afc_irq = 0; - bool ret = false; - - /* change irq num to muic_afc_irq_t */ - if(irq == muic_data->irq_vdnmon) - afc_irq = MUIC_AFC_IRQ_VDNMON; - else if (irq == muic_data->irq_mrxrdy) - afc_irq = MUIC_AFC_IRQ_MRXRDY; - else if (irq == muic_data->irq_mpnack) - afc_irq = MUIC_AFC_IRQ_MPNACK; - else if (irq == muic_data->irq_vbadc) - afc_irq = MUIC_AFC_IRQ_VBADC; - else { - pr_err("%s:%s cannot find irq #(%d)\n", MUIC_HV_DEV_NAME, __func__, irq); - ret = false; - goto out; - } - - if (tmp_afc_data->afc_irq == afc_irq) { - ret = true; - goto out; - } - - if (tmp_afc_data->afc_irq == MUIC_AFC_IRQ_DONTCARE) { - ret = true; - goto out; - } - -out: - if (debug_en_checklist) { - pr_info("%s:%s check_data dev(%d) irq(%d:%d) ret(%c)\n", - MUIC_HV_DEV_NAME, __func__, tmp_afc_data->new_dev, - tmp_afc_data->afc_irq, afc_irq, ret ? 'T' : 'F'); - } - - return ret; -} - -static bool muic_check_hvcontrol1_dpdnvden - (const muic_afc_data_t *tmp_afc_data, u8 dpdnvden) -{ - bool ret = false; - - if (tmp_afc_data->hvcontrol1_dpdnvden == dpdnvden) { - ret = true; - goto out; - } - - if (tmp_afc_data->hvcontrol1_dpdnvden == DPDNVDEN_DONTCARE) { - ret = true; - goto out; - } - -out: - if (debug_en_checklist) { - pr_info("%s:%s check_data dev(%d) dpdnvden(0x%x:0x%x) ret(%c)\n", - MUIC_HV_DEV_NAME, __func__, tmp_afc_data->new_dev, - tmp_afc_data->hvcontrol1_dpdnvden, dpdnvden, - ret ? 'T' : 'F'); - } - - return ret; -} - -static bool muic_check_status3_vbadc - (const muic_afc_data_t *tmp_afc_data, u8 vbadc) -{ - bool ret = false; - - if (tmp_afc_data->status3_vbadc == vbadc) { - ret = true; - goto out; - } - - if (tmp_afc_data->status3_vbadc == VBADC_AFC_5V) { - switch (vbadc) { - case VBADC_4V_5V: - case VBADC_5V_6V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_AFC_9V) { - switch (vbadc) { - case VBADC_8V_9V: - case VBADC_9V_10V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_AFC_ERR_V_NOT_0) { - switch (vbadc) { - case VBADC_6V_7V: - case VBADC_7V_8V: - case VBADC_10V_12V: - case VBADC_12V_13V: - case VBADC_13V_14V: - case VBADC_14V_15V: - case VBADC_15V_16V: - case VBADC_16V_17V: - case VBADC_17V_18V: - case VBADC_18V_19V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_AFC_ERR_V) { - switch (vbadc) { - case VBADC_VBDET: - case VBADC_6V_7V: - case VBADC_7V_8V: - case VBADC_10V_12V: - case VBADC_12V_13V: - case VBADC_13V_14V: - case VBADC_14V_15V: - case VBADC_15V_16V: - case VBADC_16V_17V: - case VBADC_17V_18V: - case VBADC_18V_19V: - case VBADC_19V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_QC_5V) { - switch (vbadc) { - case VBADC_4V_5V: - case VBADC_5V_6V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_QC_9V) { - switch (vbadc) { - case VBADC_6V_7V: - case VBADC_7V_8V: - case VBADC_8V_9V: - case VBADC_9V_10V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_ANY) { - switch (vbadc) { - case VBADC_4V_5V: - case VBADC_5V_6V: - case VBADC_6V_7V: - case VBADC_7V_8V: - case VBADC_8V_9V: - case VBADC_9V_10V: - case VBADC_10V_12V: - case VBADC_12V_13V: - case VBADC_13V_14V: - case VBADC_14V_15V: - case VBADC_15V_16V: - case VBADC_16V_17V: - case VBADC_17V_18V: - case VBADC_18V_19V: - case VBADC_19V: - ret = true; - goto out; - default: - break; - } - } - - if (tmp_afc_data->status3_vbadc == VBADC_DONTCARE) { - ret = true; - goto out; - } - -out: - if (debug_en_checklist) { - pr_info("%s:%s check_data dev(%d) vbadc(0x%x:0x%x) ret(%c)\n", - MUIC_HV_DEV_NAME, __func__, tmp_afc_data->new_dev, - tmp_afc_data->status3_vbadc, vbadc, ret ? 'T' : 'F'); - } - - return ret; -} - -static bool muic_check_status3_vdnmon - (const muic_afc_data_t *tmp_afc_data, u8 vdnmon) -{ - bool ret = false; - - if (tmp_afc_data->status3_vdnmon == vdnmon) { - ret = true; - goto out; - } - - if (tmp_afc_data->status3_vdnmon == VDNMON_DONTCARE) { - ret = true; - goto out; - } - -out: - if (debug_en_checklist) { - pr_info("%s:%s check_data dev(%d) vdnmon(0x%x:0x%x) ret(%c)\n", - MUIC_HV_DEV_NAME, __func__, tmp_afc_data->new_dev, - tmp_afc_data->status3_vdnmon, vdnmon, ret ? 'T' : 'F'); - } - - return ret; -} - -bool muic_check_dev_ta(struct max77833_muic_data *muic_data) -{ - u8 status1 = muic_data->status1; - u8 status2 = muic_data->status2; - u8 adc, vbvolt, chgdetrun, chgtyp; - - adc = status1 & STATUS1_ADC_MASK; - vbvolt = status2 & STATUS2_VBVOLT_MASK; - chgdetrun = status2 & STATUS2_CHGDETRUN_MASK; - chgtyp = status2 & STATUS2_CHGTYP_MASK; - - if (adc != ADC_OPEN) { - max77833_muic_set_afc_ready(muic_data, false); - return false; - } - if (vbvolt == VB_LOW || chgdetrun == CHGDETRUN_TRUE || chgtyp != CHGTYP_DEDICATED_CHARGER) { - max77833_muic_set_afc_ready(muic_data, false); -#if defined(CONFIG_MUIC_NOTIFIER) - muic_notifier_detach_attached_dev(muic_data->attached_dev); -#endif - muic_data->attached_dev = ATTACHED_DEV_NONE_MUIC; - return false; - } - - return true; -} - -static void max77833_hv_muic_detect_dev(struct max77833_muic_data *muic_data, int irq) -{ - struct i2c_client *i2c = muic_data->i2c; - const muic_afc_data_t *tmp_afc_data = afc_condition_checklist[muic_data->attached_dev]; - - int intr = MUIC_INTR_DETACH; - int ret; - int i; - u8 status[3]; - u8 hvcontrol[2]; - u8 vdnmon, dpdnvden, mpnack, vbadc; - bool flag_next = true; - bool muic_dev_ta = false; - - pr_info("%s:%s irq(%d)\n", MUIC_HV_DEV_NAME, __func__, irq); - - if (tmp_afc_data == NULL) { - pr_info("%s:%s non AFC Charger, just return!\n", MUIC_HV_DEV_NAME, __func__); - return; - } - - ret = max77833_bulk_read(muic_data->i2c, MAX77833_MUIC_REG_STATUS1, 3, status); - if (ret) { - pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_DEV_NAME, __func__, ret); - return; - } - - pr_info("%s:%s STATUS1:0x%02x, 2:0x%02x, 3:0x%02x\n", MUIC_DEV_NAME, __func__, - status[0], status[1], status[2]); - - /* attached status */ - muic_data->status1 = status[0]; - muic_data->status2 = status[1]; - muic_data->status3 = status[2]; - - /* check TA type */ - muic_dev_ta = muic_check_dev_ta(muic_data); - if (!muic_dev_ta) { - pr_err("%s:%s device type is not TA!\n", MUIC_HV_DEV_NAME, __func__); - return; - } - - /* attached status */ - mpnack = status[2] & STATUS3_MPNACK_MASK; - vdnmon = status[2] & STATUS3_VDNMON_MASK; - vbadc = status[2] & STATUS3_VBADC_MASK; - - ret = max77833_bulk_read(i2c, MAX77833_MUIC_REG_HVCONTROL1, 2, hvcontrol); - if (ret) { - pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - return; - } - - pr_info("%s:%s HVCONTROL1:0x%02x, 2:0x%02x\n", MUIC_HV_DEV_NAME, __func__, - hvcontrol[0], hvcontrol[1]); - - /* attached - control */ - muic_data->hvcontrol1 = hvcontrol[0]; - muic_data->hvcontrol2 = hvcontrol[1]; - - dpdnvden = hvcontrol[0] & HVCONTROL1_DPDNVDEN_MASK; - - pr_info("%s:%s vdnmon:0x%x mpnack:0x%x vbadc:0x%x dpdnvden:0x%x\n", - MUIC_HV_DEV_NAME, __func__, vdnmon, mpnack, vbadc, dpdnvden); - - for (i = 0; i < ATTACHED_DEV_NUM; i++, tmp_afc_data = tmp_afc_data->next) { - - if (!flag_next) { - pr_info("%s:%s not found new_dev in afc_condition_checklist\n", - MUIC_HV_DEV_NAME, __func__); - break; - } - - if (tmp_afc_data->next == tmp_afc_data) - flag_next = false; - - if (!(muic_check_hv_irq(muic_data, tmp_afc_data, irq))) - continue; - - if (!(muic_check_hvcontrol1_dpdnvden(tmp_afc_data, dpdnvden))) - continue; - - if (!(muic_check_status3_vbadc(tmp_afc_data, vbadc))) - continue; - - if(!(muic_check_status3_vdnmon(tmp_afc_data, vdnmon))) - continue; - - pr_info("%s:%s checklist match found at i(%d), %s(%d)\n", - MUIC_HV_DEV_NAME, __func__, i, tmp_afc_data->afc_name, - tmp_afc_data->new_dev); + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - intr = MUIC_INTR_ATTACH; + enqueue_muic_cmd(cmd_queue, cmd_data); - break; - } + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - if (intr == MUIC_INTR_ATTACH) { - pr_info("%s:%s AFC ATTACHED\n", MUIC_HV_DEV_NAME, __func__); - pr_info("%s:%s %d->%d\n", MUIC_HV_DEV_NAME, __func__, - muic_data->attached_dev, tmp_afc_data->new_dev); - ret = max77833_hv_muic_handle_attach(muic_data, tmp_afc_data); - if (ret) - pr_err("%s:%s cannot handle attach(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - } else { - pr_info("%s:%s AFC MAINTAIN (%d)\n", MUIC_HV_DEV_NAME, __func__, - muic_data->attached_dev); - ret = max77833_hv_muic_state_maintain(muic_data); - if (ret) - pr_err("%s:%s cannot maintain state(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - goto out; - } + enqueue_muic_cmd(cmd_queue, cmd_data); -out: return; } -/* TA setting in max77833-muic.c */ -void max77833_muic_prepare_afc_charger(struct max77833_muic_data *muic_data) +void max77833_muic_hv_qc_disable(struct max77833_muic_data *muic_data) { - struct i2c_client *i2c = muic_data->i2c; - int ret; - - pr_info("%s:%s \n", MUIC_DEV_NAME, __func__); - - max77833_hv_muic_adcmode_oneshot(muic_data); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_QC_DISABLE_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - /* set HVCONTROL1=0x11 */ - ret = max77833_muic_hv_update_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, - (0x2 << HVCONTROL1_DPVD_SHIFT), HVCONTROL1_DPVD_MASK, true); - if (ret) - goto err_write; - - ret = max77833_muic_hv_update_reg(i2c, MAX77833_MUIC_REG_HVCONTROL1, - (MAX77833_ENABLE_BIT << HVCONTROL1_DPDNVDEN_SHIFT), - HVCONTROL1_DPDNVDEN_MASK, true); - if (ret) - goto err_write; + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - /* Set VBusADCEn = 1 after the time of changing adcmode*/ + enqueue_muic_cmd(cmd_queue, cmd_data); - max77833_muic_set_afc_ready(muic_data, true); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - return; + enqueue_muic_cmd(cmd_queue, cmd_data); -err_write: - pr_err("%s:%s fail to write muic reg(%d)\n", MUIC_DEV_NAME, __func__, ret); return; } -/* TA setting in max77833-muic.c */ -bool max77833_muic_check_change_dev_afc_charger - (struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) -{ - bool ret = true; - - if (new_dev == ATTACHED_DEV_TA_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_5V_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_9V_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC || \ - new_dev == ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC || \ - new_dev == ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC || \ - new_dev == ATTACHED_DEV_QC_CHARGER_5V_MUIC || \ - new_dev == ATTACHED_DEV_QC_CHARGER_9V_MUIC) { - if(muic_check_dev_ta(muic_data)) { - ret = false; - } - } - - return ret; -} - -static void max77833_hv_muic_detect_after_charger_init(struct work_struct *work) +void max77833_muic_hv_chgin_read(struct max77833_muic_data *muic_data) { - struct afc_init_data_s *init_data = - container_of(work, struct afc_init_data_s, muic_afc_init_work); - struct max77833_muic_data *muic_data = init_data->muic_data; - int ret; - u8 status3; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_CHGIN_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - mutex_lock(&muic_data->muic_mutex); + enqueue_muic_cmd(cmd_queue, cmd_data); - /* check vdnmon status value */ - ret = max77833_read_reg(muic_data->i2c, MAX77833_MUIC_REG_STATUS3, &status3); - if (ret) { - pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_HV_DEV_NAME, - __func__, ret); - return; - } - pr_info("%s:%s STATUS3:0x%02x\n", MUIC_HV_DEV_NAME, __func__, status3); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - if (muic_data->is_afc_muic_ready) { - if (muic_data->is_afc_muic_prepare) - max77833_hv_muic_detect_dev(muic_data, muic_data->irq_vdnmon); - else - max77833_hv_muic_detect_dev(muic_data, -1); - } + enqueue_muic_cmd(cmd_queue, cmd_data); - mutex_unlock(&muic_data->muic_mutex); -} - -void max77833_hv_muic_charger_init(void) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - - if(afc_init_data.muic_data) { - afc_init_data.muic_data->is_charger_ready = true; - schedule_work(&afc_init_data.muic_afc_init_work); - } + return; } -static void max77833_hv_muic_check_qc_vb(struct work_struct *work) +void max77833_muic_hv_fchv_capa_read(struct max77833_muic_data *muic_data) { - struct max77833_muic_data *muic_data = - container_of(work, struct max77833_muic_data, hv_muic_qc_vb_work.work); - u8 status3, vbadc; - - if (!muic_data) { - pr_err("%s:%s cannot read muic_data!\n", MUIC_HV_DEV_NAME, __func__); - return; - } - - mutex_lock(&muic_data->muic_mutex); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_AFC_CAPA_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - if (muic_data->is_qc_vb_settle == true) { - pr_info("%s:%s already qc vb settled\n", MUIC_HV_DEV_NAME, __func__); - goto out; - } + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); + enqueue_muic_cmd(cmd_queue, cmd_data); - max77833_hv_muic_read_reg(muic_data->i2c, MAX77833_MUIC_REG_STATUS3, &status3); - vbadc = status3 & STATUS3_VBADC_MASK; + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - if (vbadc == VBADC_4V_5V || vbadc == VBADC_5V_6V) { - muic_data->is_qc_vb_settle = true; - max77833_hv_muic_detect_dev(muic_data, muic_data->irq_vbadc); - } + enqueue_muic_cmd(cmd_queue, cmd_data); -out: - mutex_unlock(&muic_data->muic_mutex); return; } -void max77833_hv_muic_init_detect(struct max77833_muic_data *muic_data) +void max77833_muic_hv_fchv_set(struct max77833_muic_data *muic_data, u8 val, u8 mask) { - int ret; - u8 status3, vdnmon; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_AFC_SET_WRITE; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; - mutex_lock(&muic_data->muic_mutex); - - if (muic_data->is_boot_dpdnvden == DPDNVDEN_ENABLE) - pr_info("%s:%s dpdnvden already ENABLE\n", MUIC_HV_DEV_NAME, __func__); - else if (muic_data->is_boot_dpdnvden == DPDNVDEN_DISABLE) { - mdelay(30); - pr_info("%s:%s dpdnvden == DISABLE, 30ms delay\n", MUIC_HV_DEV_NAME, __func__); - } else { - pr_err("%s:%s dpdnvden is not correct(0x%x)!\n", MUIC_HV_DEV_NAME, - __func__, muic_data->is_boot_dpdnvden); - goto out; - } + enqueue_muic_cmd(cmd_queue, cmd_data); - ret = max77833_read_reg(muic_data->i2c, MAX77833_MUIC_REG_STATUS3, &status3); - if (ret) { - pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_DEV_NAME, __func__, ret); - vdnmon = VDNMON_DONTCARE; - } else - vdnmon = status3 & STATUS3_VDNMON_MASK; + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; - if (vdnmon == VDNMON_LOW) - max77833_hv_muic_detect_dev(muic_data, muic_data->irq_vdnmon); - else - pr_info("%s:%s vdnmon != LOW(0x%x)\n", MUIC_HV_DEV_NAME, __func__, vdnmon); + enqueue_muic_cmd(cmd_queue, cmd_data); -out: - mutex_unlock(&muic_data->muic_mutex); + return; } -void max77833_hv_muic_init_check_dpdnvden(struct max77833_muic_data *muic_data) +void max77833_muic_hv_fchv_enable(struct max77833_muic_data *muic_data, u8 val, u8 mask) { - u8 hvcontrol1; - int ret; - - mutex_lock(&muic_data->muic_mutex); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_AFC_ENABLE_READ; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; - ret = max77833_hv_muic_read_reg(muic_data->i2c, MAX77833_MUIC_REG_HVCONTROL1, &hvcontrol1); - if (ret) { - pr_err("%s:%s cannot read HVCONTROL1 reg!\n", MUIC_HV_DEV_NAME, __func__); - muic_data->is_boot_dpdnvden = DPDNVDEN_DONTCARE; - } else - muic_data->is_boot_dpdnvden = hvcontrol1 & HVCONTROL1_DPDNVDEN_MASK; - - mutex_unlock(&muic_data->muic_mutex); -} + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; -static irqreturn_t max77833_muic_hv_irq(int irq, void *data) -{ - struct max77833_muic_data *muic_data = data; - pr_info("%s:%s irq:%d\n", MUIC_HV_DEV_NAME, __func__, irq); + enqueue_muic_cmd(cmd_queue, cmd_data); - mutex_lock(&muic_data->muic_mutex); - if (muic_data->is_muic_ready == false) - pr_info("%s:%s MUIC is not ready, just return\n", MUIC_HV_DEV_NAME, - __func__); - else if (muic_data->is_afc_muic_ready == false) - pr_info("%s:%s not ready yet(afc_muic_ready[%c])\n", MUIC_HV_DEV_NAME, - __func__, (muic_data->is_afc_muic_ready ? 'T' : 'F')); - else if (muic_data->is_charger_ready == false && irq != muic_data->irq_vdnmon) - pr_info("%s:%s not ready yet(charger_ready[%c])\n", MUIC_HV_DEV_NAME, - __func__, (muic_data->is_charger_ready ? 'T' : 'F')); - else if (muic_data->pdata->afc_disable) - pr_info("%s:%s AFC disable by USER (afc_disable[%c]\n", MUIC_HV_DEV_NAME, - __func__, (muic_data->pdata->afc_disable ? 'T' : 'F')); - else - max77833_hv_muic_detect_dev(muic_data, irq); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; - mutex_unlock(&muic_data->muic_mutex); + enqueue_muic_cmd(cmd_queue, cmd_data); - return IRQ_HANDLED; + return; } -#define REQUEST_HV_IRQ(_irq, _dev_id, _name) \ -do { \ - ret = request_threaded_irq(_irq, NULL, max77833_muic_hv_irq, \ - IRQF_NO_SUSPEND, _name, _dev_id); \ - if (ret < 0) { \ - pr_err("%s:%s Failed to request IRQ #%d: %d\n", \ - MUIC_HV_DEV_NAME, __func__, _irq, ret); \ - _irq = 0; \ - } \ -} while (0) - -int max77833_afc_muic_irq_init(struct max77833_muic_data *muic_data) +void max77833_muic_hv_fchv_disable(struct max77833_muic_data *muic_data) { - int ret = 0; - - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - - if (muic_data->mfd_pdata && (muic_data->mfd_pdata->irq_base > 0)) { - int irq_base = muic_data->mfd_pdata->irq_base; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_AFC_DISABLE_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - /* request AFC MUIC IRQ */ - muic_data->irq_vdnmon = irq_base + MAX77833_MUIC_IRQ_INT3_VDNMON; - REQUEST_HV_IRQ(muic_data->irq_vdnmon, muic_data, "muic-vdnmon"); - muic_data->irq_mrxrdy = irq_base + MAX77833_MUIC_IRQ_MRXRDY; - REQUEST_HV_IRQ(muic_data->irq_mrxrdy, muic_data, "muic-mrxrdy"); - muic_data->irq_mpnack = irq_base + MAX77833_MUIC_IRQ_INT3_MPNACK; - REQUEST_HV_IRQ(muic_data->irq_mpnack, muic_data, "muic-mpnack"); - muic_data->irq_vbadc = irq_base + MAX77833_MUIC_IRQ_INT3_VBADC; - REQUEST_HV_IRQ(muic_data->irq_vbadc, muic_data, "muic-vbadc"); - - pr_info("%s:%s vdnmon(%d), mrxrdy(%d), mpnack(%d), vbadc(%d)\n", - MUIC_HV_DEV_NAME, __func__, - muic_data->irq_vdnmon, muic_data->irq_mrxrdy, - muic_data->irq_mpnack, muic_data->irq_vbadc); - } + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - return ret; -} + enqueue_muic_cmd(cmd_queue, cmd_data); -#define FREE_HV_IRQ(_irq, _dev_id, _name) \ -do { \ - if (_irq) { \ - free_irq(_irq, _dev_id); \ - pr_info("%s:%s IRQ(%d):%s free done\n", MUIC_HV_DEV_NAME, \ - __func__, _irq, _name); \ - } \ -} while (0) + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; -void max77833_hv_muic_free_irqs(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); + enqueue_muic_cmd(cmd_queue, cmd_data); - /* free MUIC IRQ */ - FREE_HV_IRQ(muic_data->irq_vdnmon, muic_data, "muic-vdnmon"); - FREE_HV_IRQ(muic_data->irq_mrxrdy, muic_data, "muic-mrxrdy"); - FREE_HV_IRQ(muic_data->irq_mpnack, muic_data, "muic-mpnack"); - FREE_HV_IRQ(muic_data->irq_vbadc, muic_data, "muic-vbadc"); + return; } -#if defined(CONFIG_OF) -int of_max77833_hv_muic_dt(struct max77833_muic_data *muic_data) +void max77833_muic_set_afc_ready(struct max77833_muic_data *muic_data, bool value) { - struct device_node *np_muic; - int ret = 0; - - np_muic = of_find_node_by_path("/muic"); - if (np_muic == NULL) - return -EINVAL; - - ret = of_property_read_u8(np_muic, "muic,qc-hv", &muic_data->qc_hv); - if (ret) { - pr_err("%s:%s There is no Property of muic,qc-hv\n", - MUIC_DEV_NAME, __func__); - goto err; - } - - pr_info("%s:%s muic_data->qc-hv:0x%02x\n", MUIC_DEV_NAME, __func__, - muic_data->qc_hv); + bool before, after; -err: - of_node_put(np_muic); + before = muic_data->is_check_hv; + muic_data->is_check_hv = value; + after = muic_data->is_check_hv; - return ret; + pr_info("%s:%s check_hv[%d->%d]\n", MUIC_DEV_NAME, __func__, before, after); } -#endif /* CONFIG_OF */ -void max77833_hv_muic_initialize(struct max77833_muic_data *muic_data) +void max77833_muic_hv_fchv_disable_set(struct max77833_muic_data *muic_data) { - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - - muic_data->is_afc_handshaking = false; - muic_data->is_afc_muic_prepare = false; - muic_data->is_charger_ready = false; - muic_data->is_boot_dpdnvden = DPDNVDEN_DONTCARE; + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - afc_init_data.muic_data = muic_data; - INIT_WORK(&afc_init_data.muic_afc_init_work, max77833_hv_muic_detect_after_charger_init); + max77833_muic_set_afc_ready(muic_data, false); + max77833_muic_hv_fchv_disable(muic_data); - INIT_DELAYED_WORK(&muic_data->hv_muic_qc_vb_work, max77833_hv_muic_check_qc_vb); + return; } -void max77833_hv_muic_remove(struct max77833_muic_data *muic_data) +void max77833_muic_hv_qc_disable_set(struct max77833_muic_data *muic_data) { - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - cancel_work_sync(&afc_init_data.muic_afc_init_work); - cancel_delayed_work_sync(&muic_data->hv_muic_qc_vb_work); + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - max77833_hv_muic_free_irqs(muic_data); -} + max77833_muic_set_afc_ready(muic_data, false); + max77833_muic_hv_qc_disable(muic_data); -void max77833_hv_muic_remove_wo_free_irq(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_HV_DEV_NAME, __func__); - cancel_work_sync(&afc_init_data.muic_afc_init_work); - cancel_delayed_work_sync(&muic_data->hv_muic_qc_vb_work); + return; } - diff --git a/drivers/muic/max77833-muic.c b/drivers/muic/max77833-muic.c index 638e54b2a248..7a050d583e32 100644 --- a/drivers/muic/max77833-muic.c +++ b/drivers/muic/max77833-muic.c @@ -1,8 +1,8 @@ /* * max77833-muic.c - MUIC driver for the Maxim 77833 * - * Copyright (C) 2012 Samsung Electronics - * Seoyoung Jeong + * Copyright (C) 2015 Samsung Electronics + * Insun Choi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,450 +32,298 @@ /* MUIC header file */ #include -#include #include -//#if defined(CONFIG_HV_MUIC_MAX77833_AFC) +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) #include -//#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ +#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ #if defined(CONFIG_MUIC_NOTIFIER) #include #endif /* CONFIG_MUIC_NOTIFIER */ -#if !defined(CONFIG_SEC_FACTORY) -#if defined(CONFIG_MUIC_ADCMODE_SWITCH_WA) -#include -#endif /* CONFIG_MUIC_ADCMODE_SWITCH_WA */ -#endif /* !CONFIG_SEC_FACTORY */ - -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) -#include -#endif - extern struct muic_platform_data muic_pdata; static bool debug_en_vps = false; +static bool debug_en_cmd = false; +u8 vi_val = FCHV_SET_9V; +u8 pass_rev; // For PASS4/Old rev onebinary struct max77833_muic_vps_data { - muic_adc_t adc; + max77833_adc_t adc; + chgdetcon_t chgdetcon; chgdetrun_t chgdetrun; chgtyp_t chgtyp; - max77833_reg_ctrl1_t control1; + max77833_switch_cmd_t muic_switch; const char *vps_name; const muic_attached_dev_t attached_dev; }; static const struct max77833_muic_vps_data muic_vps_table[] = { -#if 1 - { - .adc = ADC_JIG_USB_ON, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, - .vps_name = "Jig USB On", - .attached_dev = ATTACHED_DEV_JIG_USB_ON_MUIC, - }, - { - .adc = ADC_JIG_USB_ON, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_1A, - .control1 = CTRL1_USB, - .vps_name = "Jig USB On + VB", - .attached_dev = ATTACHED_DEV_JIG_USB_ON_MUIC, - }, +// Default. { - .adc = ADC_JIG_UART_OFF, - .chgdetrun = CHGDETRUN_FALSE, + .adc = MAX77833_ADC_JIG_UART_OFF, + .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_UART, + .muic_switch = COM_UART, .vps_name = "Jig UART Off", .attached_dev = ATTACHED_DEV_JIG_UART_OFF_MUIC, }, { - .adc = ADC_OPEN, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_DEDICATED_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "TA", - .attached_dev = ATTACHED_DEV_TA_MUIC, - }, - { - .adc = ADC_OPEN, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_UNOFFICIAL_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "unofficial TA", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_TA_MUIC, + .adc = MAX77833_ADC_JIG_UART_OFF, + .chgdetrun = CHGDETRUN_DONTCARE, + .chgtyp = CHGTYP_HALT, + .muic_switch = COM_UART, + .vps_name = "Jig UART Off + VB", + .attached_dev = ATTACHED_DEV_JIG_UART_OFF_VB_MUIC, }, { - .adc = ADC_OPEN, + .adc = MAX77833_ADC_JIG_UART_ON, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_USB, - .control1 = CTRL1_USB, - .vps_name = "USB", - .attached_dev = ATTACHED_DEV_USB_MUIC, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_UART, + .vps_name = "Jig UART On", + .attached_dev = ATTACHED_DEV_JIG_UART_ON_MUIC, }, -#else { - .adc1k = (0x1 << STATUS1_ADC1K_SHIFT), - .adcerr = 0x00, - .adc = ADC_DONTCARE, - .vbvolt = VB_DONTCARE, + .adc = MAX77833_ADC_JIG_USB_OFF, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "MHL", - .attached_dev = ATTACHED_DEV_MHL_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_GND, - .vbvolt = VB_LOW, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, - .vps_name = "OTG", - .attached_dev = ATTACHED_DEV_OTG_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_GND, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, - .vps_name = "OTG charging pump (vbvolt)", - .attached_dev = ATTACHED_DEV_OTG_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_CHARGING_CABLE, - .vbvolt = VB_DONTCARE, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, - .vps_name = "Charging Cable", - .attached_dev = ATTACHED_DEV_CHARGING_CABLE_MUIC, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial ID", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_JIG_USB_ON, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_JIG_USB_ON, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_USB, .vps_name = "Jig USB On", .attached_dev = ATTACHED_DEV_JIG_USB_ON_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_JIG_UART_OFF, - .vbvolt = VB_LOW, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_UART, - .vps_name = "Jig UART Off", - .attached_dev = ATTACHED_DEV_JIG_UART_OFF_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_JIG_UART_OFF, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_UART, - .vps_name = "Jig UART Off + VB", - .attached_dev = ATTACHED_DEV_JIG_UART_OFF_VB_MUIC, - }, -#if defined(CONFIG_SEC_FACTORY) - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_JIG_UART_ON, - .vbvolt = VB_LOW, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_UART, - .vps_name = "Jig UART On", - .attached_dev = ATTACHED_DEV_JIG_UART_ON_MUIC, - }, -#endif /* CONFIG_SEC_FACTORY */ - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_OPEN, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_OPEN, .chgdetrun = CHGDETRUN_FALSE, .chgtyp = CHGTYP_DEDICATED_CHARGER, - .control1 = CTRL1_OPEN, + .muic_switch = COM_OPEN, .vps_name = "TA", .attached_dev = ATTACHED_DEV_TA_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_OPEN, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_UNOFFICIAL_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "unofficial TA", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_TA_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_OPEN, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_OPEN, .chgdetrun = CHGDETRUN_FALSE, .chgtyp = CHGTYP_USB, - .control1 = CTRL1_USB, + .muic_switch = COM_USB, .vps_name = "USB", .attached_dev = ATTACHED_DEV_USB_MUIC, }, +// For TA or Charging etc. { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_OPEN, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_OPEN, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_CDP, - .control1 = CTRL1_USB, - .vps_name = "CDP", - .attached_dev = ATTACHED_DEV_CDP_MUIC, + .chgtyp = CHGTYP_UNOFFICIAL_CHARGER, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial TA", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_TA_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_JIG_USB_OFF, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_CEA936ATYPE2_CHG, .chgdetrun = CHGDETRUN_DONTCARE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_OPEN, - .vps_name = "Unofficial ID", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_MUIC, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_OPEN, + .vps_name = "TYPE2 Charger", + .attached_dev = ATTACHED_DEV_TYPE2_CHG_MUIC, + }, + { + .adc = MAX77833_ADC_UNDEFINED, + .chgdetrun = CHGDETRUN_DONTCARE, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_OPEN, + .vps_name = "Undefined Charging", + .attached_dev = ATTACHED_DEV_UNDEFINED_CHARGING_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_219, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_OPEN, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_DEDICATED_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "Unofficial ID + TA", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_TA_MUIC, + .chgtyp = CHGTYP_TIMEOUT_OPEN, + .muic_switch = COM_OPEN, + .vps_name = "Timeout Open Charging", + .attached_dev = ATTACHED_DEV_TA_MUIC, // CHECK. }, +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_219, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_OPEN, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_DEDICATED_CHARGER, + .muic_switch = COM_OPEN, + .vps_name = "AFC charger", + .attached_dev = ATTACHED_DEV_AFC_CHARGER_9V_MUIC, + }, + { + .adc = MAX77833_ADC_OPEN, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_DEDICATED_CHARGER, + .muic_switch = COM_OPEN, + .vps_name = "QC charger", + .attached_dev = ATTACHED_DEV_QC_CHARGER_9V_MUIC, + }, +#endif +// For Accessary. + { + .adc = MAX77833_ADC_OPEN, .chgdetrun = CHGDETRUN_FALSE, .chgtyp = CHGTYP_CDP, - .control1 = CTRL1_OPEN, - .vps_name = "Unofficial ID + CDP", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC, + .muic_switch = COM_USB, + .vps_name = "CDP", + .attached_dev = ATTACHED_DEV_CDP_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_219, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_UNOFFICIAL_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "Unofficial ID + ANY TA", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_ANY_MUIC, + .adc = MAX77833_ADC_1K, + .chgdetrun = CHGDETRUN_DONTCARE, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_OPEN, + .vps_name = "MHL", + .attached_dev = ATTACHED_DEV_MHL_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_219, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_GND, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_USB, - .control1 = CTRL1_OPEN, - .vps_name = "Unofficial ID + USB", - .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_USB, + .vps_name = "OTG", + .attached_dev = ATTACHED_DEV_OTG_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_OPEN, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_CHARGING_CABLE, .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_DEDICATED_CHARGER, - .control1 = CTRL1_OPEN, - .vps_name = "TA or AFC", - .attached_dev = ATTACHED_DEV_TA_MUIC, + .chgtyp = CHGTYP_DONTCARE, + .muic_switch = COM_USB, + .vps_name = "PowerSharing Cable", + .attached_dev = ATTACHED_DEV_CHARGING_CABLE_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_UNDEFINED, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_HMT, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "Undefined Charging", - .attached_dev = ATTACHED_DEV_UNDEFINED_CHARGING_MUIC, + .muic_switch = COM_USB, + .vps_name = "HMT", + .attached_dev = ATTACHED_DEV_HMT_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_DESKDOCK, - .vbvolt = VB_LOW, + .adc = MAX77833_ADC_DESKDOCK, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_OPEN, + .muic_switch = COM_OPEN, .vps_name = "Deskdock", .attached_dev = ATTACHED_DEV_DESKDOCK_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_DESKDOCK, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_DONTCARE, - .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "Deskdock + VB", - .attached_dev = ATTACHED_DEV_DESKDOCK_VB_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_SMARTDOCK, - .vbvolt = VB_LOW, + .adc = MAX77833_ADC_SMARTDOCK, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_OPEN, + .muic_switch = COM_OPEN, .vps_name = "Smartdock", .attached_dev = ATTACHED_DEV_SMARTDOCK_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_SMARTDOCK, - .vbvolt = VB_HIGH, - .chgdetrun = CHGDETRUN_DONTCARE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_OPEN, - .vps_name = "Smartdock + VB", - .attached_dev = ATTACHED_DEV_SMARTDOCK_VB_MUIC, - }, - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_SMARTDOCK, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_SMARTDOCK, .chgdetrun = CHGDETRUN_FALSE, .chgtyp = CHGTYP_DEDICATED_CHARGER, - .control1 = CTRL1_USB_DOCK, + .muic_switch = COM_USB_DOCK, .vps_name = "Smartdock + TA", .attached_dev = ATTACHED_DEV_SMARTDOCK_TA_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_SMARTDOCK, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_SMARTDOCK, .chgdetrun = CHGDETRUN_FALSE, .chgtyp = CHGTYP_USB, - .control1 = CTRL1_USB_DOCK, + .muic_switch = COM_USB_DOCK, .vps_name = "Smartdock + USB", .attached_dev = ATTACHED_DEV_SMARTDOCK_USB_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_AUDIODOCK, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_AUDIODOCK, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_USB, + .muic_switch = COM_USB, .vps_name = "Audiodock", .attached_dev = ATTACHED_DEV_AUDIODOCK_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_HMT, - .vbvolt = VB_DONTCARE, - .chgdetrun = CHGDETRUN_FALSE, - .chgtyp = CHGTYP_NO_VOLTAGE, - .control1 = CTRL1_USB, - .vps_name = "HMT", - .attached_dev = ATTACHED_DEV_HMT_MUIC, - }, - /* Unsupported Device Type - Charging */ - { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_UNIVERSAL_MMDOCK, - .vbvolt = VB_HIGH, + .adc = MAX77833_ADC_UNIVERSAL_MMDOCK, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_USB, + .muic_switch = COM_USB, .vps_name = "Universal Multimedia dock", .attached_dev = ATTACHED_DEV_UNIVERSAL_MMDOCK_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_RESERVED_VZW, - .vbvolt = VB_DONTCARE, + .adc = MAX77833_ADC_USB_LANHUB, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "VZW Accessory", - .attached_dev = ATTACHED_DEV_VZW_ACC_MUIC, + .muic_switch = COM_OPEN, + .vps_name = "USB LANHUB", + .attached_dev = ATTACHED_DEV_USB_LANHUB_MUIC, }, +// For support 219Kohm { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_INCOMPATIBLE_VZW, - .vbvolt = VB_DONTCARE, - .chgdetrun = CHGDETRUN_DONTCARE, - .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "VZW Incompatible", - .attached_dev = ATTACHED_DEV_VZW_INCOMPATIBLE_MUIC, + .adc = MAX77833_ADC_219, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_DEDICATED_CHARGER, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial ID + TA", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_TA_MUIC, + }, + { + .adc = MAX77833_ADC_219, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_CDP, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial ID + CDP", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_CDP_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_USB_LANHUB, - .vbvolt = VB_DONTCARE, + .adc = MAX77833_ADC_219, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_UNOFFICIAL_CHARGER, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial ID + ANY TA", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_ANY_MUIC, + }, + { + .adc = MAX77833_ADC_219, + .chgdetrun = CHGDETRUN_FALSE, + .chgtyp = CHGTYP_USB, + .muic_switch = COM_OPEN, + .vps_name = "Unofficial ID + USB", + .attached_dev = ATTACHED_DEV_UNOFFICIAL_ID_USB_MUIC, + }, +// For VZW. + { + .adc = MAX77833_ADC_RESERVED_VZW, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "USB LANHUB", - .attached_dev = ATTACHED_DEV_USB_LANHUB_MUIC, + .muic_switch = COM_OPEN, + .vps_name = "VZW Accessory", + .attached_dev = ATTACHED_DEV_VZW_ACC_MUIC, }, { - .adc1k = 0x00, - .adcerr = 0x00, - .adc = ADC_CEA936ATYPE2_CHG, - .vbvolt = VB_DONTCARE, + .adc = MAX77833_ADC_INCOMPATIBLE_VZW, .chgdetrun = CHGDETRUN_DONTCARE, .chgtyp = CHGTYP_DONTCARE, - .control1 = CTRL1_OPEN, - .vps_name = "TYPE2 Charger", - .attached_dev = ATTACHED_DEV_TYPE2_CHG_MUIC, + .muic_switch = COM_OPEN, + .vps_name = "VZW Incompatible", + .attached_dev = ATTACHED_DEV_VZW_INCOMPATIBLE_MUIC, }, -#endif }; -static int muic_lookup_vps_table(muic_attached_dev_t new_dev) +static int muic_lookup_vps_table(muic_attached_dev_t new_dev, struct max77833_muic_data *muic_data) { int i; + struct i2c_client *i2c = muic_data->i2c; + u8 reg_data; + + max77833_read_reg(i2c, MAX77833_MUIC_REG_STATUS3, ®_data); + reg_data = reg_data & STATUS3_SYSMSG_MASK; + pr_info("%s:%s Last sysmsg = 0x%02x\n", MUIC_DEV_NAME, __func__, reg_data); for (i = 0; i < ARRAY_SIZE(muic_vps_table); i++) { const struct max77833_muic_vps_data *tmp_vps; @@ -520,299 +368,975 @@ static int max77833_muic_write_reg return ret; } -static int max77833_muic_update_reg(struct i2c_client *i2c, const u8 reg, - const u8 val, const u8 mask, const bool debug_en) +void init_muic_cmd_data(muic_cmd_data *cmd_data) { - int ret = 0; - u8 before_val, new_val, after_val; - - ret = max77833_read_reg(i2c, reg, &before_val); - if (ret < 0) - pr_err("%s:%s err read REG(0x%02x) [%d]\n", MUIC_DEV_NAME, - __func__, reg, ret); - - new_val = (val & mask) | (before_val & (~mask)); - - if (before_val ^ new_val) { - ret = max77833_write_reg(i2c, reg, new_val); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x) [%d]\n", - MUIC_DEV_NAME, __func__, reg, ret); - } else if (debug_en) { - pr_info("%s:%s REG(0x%02x): already [0x%02x], don't write reg\n", - MUIC_DEV_NAME, __func__, reg, before_val); - goto out; + if (debug_en_cmd) + pr_info("%s:%s \n", MUIC_DEV_NAME, __func__); + + cmd_data->opcode = COMMAND_NONE; + cmd_data->response = COMMAND_NONE; + cmd_data->read_data = REG_NONE; + cmd_data->write_data = REG_NONE; + cmd_data->val = REG_NONE; + cmd_data->mask = REG_NONE; + cmd_data->reg = REG_NONE; + cmd_data->noti_dev = ATTACHED_DEV_UNKNOWN_MUIC; + + return; +} + +static void init_muic_command(muic_cmd_node *muic_cmd_node) +{ + muic_cmd_data *cmd_data = &(muic_cmd_node->cmd_data); + + if (debug_en_cmd) + pr_info("%s:%s \n", MUIC_DEV_NAME, __func__); + + muic_cmd_node->next = NULL; + + init_muic_cmd_data(cmd_data); + return; +} + +static void copy_muic_cmd_data(muic_cmd_data *from, muic_cmd_data *to) +{ + to->opcode = from->opcode; + to->response = from->response; + to->read_data = from->read_data; + to->write_data = from->write_data; + to->reg = from->reg; + to->mask = from->mask; + to->val = from->val; + + to->noti_dev = from->noti_dev; +} + +bool is_empty_muic_cmd_queue(cmd_queue_t *muic_cmd_queue) +{ + bool ret = false; + + if (muic_cmd_queue->front == NULL) + ret = true; + + if (ret) + pr_info("%s:%s muic_cmd_queue Empty(%c)\n", + MUIC_DEV_NAME, __func__, ret ? 'T' : 'F'); + + return ret; +} + +void enqueue_muic_cmd(cmd_queue_t *muic_cmd_queue, muic_cmd_data cmd_data) +{ + muic_cmd_node *temp_node = kzalloc(sizeof(muic_cmd_node), GFP_KERNEL); + + if (!temp_node) { + pr_err("%s: failed to allocate muic command queue\n", __func__); + return; + } + + init_muic_command(temp_node); + +// mutex_lock(&muic_cmd_queue->command_mutex); + + copy_muic_cmd_data(&cmd_data, &(temp_node->cmd_data)); + + if (is_empty_muic_cmd_queue(muic_cmd_queue)) { + muic_cmd_queue->front = temp_node; + muic_cmd_queue->rear = temp_node; + } else { + muic_cmd_queue->rear->next = temp_node; + muic_cmd_queue->rear = temp_node; } - if (debug_en) { - ret = max77833_read_reg(i2c, reg, &after_val); - if (ret < 0) - pr_err("%s:%s err read REG(0x%02x) [%d]\n", - MUIC_DEV_NAME, __func__, reg, ret); +// mutex_unlock(&muic_cmd_queue->command_mutex); +} + +static void enqueue_muic_notifier(cmd_queue_t *cmd_queue, + muic_cmd_opcode opcode, muic_attached_dev_t noti_dev) +{ + muic_cmd_data cmd_data; + + pr_info("%s:%s opcode[0x%02x] noti_dev[%d]\n", + MUIC_DEV_NAME, __func__, opcode, noti_dev); + + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.noti_dev = noti_dev; + + enqueue_muic_cmd(cmd_queue, cmd_data); + + return; +} + +static void dequeue_muic_cmd + (cmd_queue_t *muic_cmd_queue, muic_cmd_data *cmd_data) +{ + muic_cmd_node *temp_node; + + if (is_empty_muic_cmd_queue(muic_cmd_queue)) { + pr_err("%s:%s Queue, Empty!\n", MUIC_DEV_NAME, __func__); + return; + } + + temp_node = muic_cmd_queue->front; + copy_muic_cmd_data(&(temp_node->cmd_data), cmd_data); + + pr_info("%s:%s Opcode(0x%02x)\n", + MUIC_DEV_NAME, __func__, cmd_data->opcode); + + /* debugging */ + if (muic_cmd_queue->front->next == NULL) { + pr_info("%s:%s front->next = NULL\n", MUIC_DEV_NAME, __func__); + muic_cmd_queue->front = NULL; + } else + muic_cmd_queue->front = muic_cmd_queue->front->next; + + if (is_empty_muic_cmd_queue(muic_cmd_queue)) + muic_cmd_queue->rear = NULL; + + kfree(temp_node); + + return; +} + +static bool front_muic_cmd + (cmd_queue_t *cmd_queue, muic_cmd_data *cmd_data) +{ + if (is_empty_muic_cmd_queue(cmd_queue)) { + pr_err("%s:%s Queue, Empty!\n", MUIC_DEV_NAME, __func__); + return false; + } + + copy_muic_cmd_data(&(cmd_queue->front->cmd_data), cmd_data); + pr_info("%s:%s Opcode(0x%02x)\n", + MUIC_DEV_NAME, __func__, cmd_data->opcode); + + return true; +} + +static u8 read_muic_cmd_response(struct max77833_muic_data *muic_data) +{ + struct i2c_client *i2c = muic_data->i2c; + u8 response, reg; + + reg = MAX77833_MUIC_REG_DAT_OUT_OP; + max77833_read_reg(i2c, reg, &response); + pr_info("%s:%s Response[0x%02x] = 0x%02x\n", + MUIC_DEV_NAME, __func__, reg, response); + + return response; +} + +static bool is_read_response(u8 response, u8 *reg) +{ + bool read; + + switch (response) { + case COMMAND_CONFIG_READ: + case COMMAND_SWITCH_READ: + case COMMAND_SYSMSG_READ: + case COMMAND_CHGDET_READ: + case COMMAND_MONITOR_READ: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_QC_DISABLE_READ: + case COMMAND_QC_ENABLE_READ: + case COMMAND_QC_AUTOSET_WRITE: + case COMMAND_AFC_DISABLE_READ: + case COMMAND_AFC_ENABLE_READ: + case COMMAND_AFC_CAPA_READ: + case COMMAND_AFC_SET_WRITE: +#endif + case COMMAND_CHGIN_READ: + *reg = MAX77833_MUIC_REG_DAT_OUT1; + read = true; + break; + case COMMAND_CONFIG_WRITE: + case COMMAND_SWITCH_WRITE: + case COMMAND_MONITOR_WRITE: + read = false; + break; + default: + pr_err("%s:%s Invalid CMD response[0x%02x]\n", + MUIC_DEV_NAME, __func__, response); + break; + } + + return read; +} + +static bool is_read_opcode(u8 opcode) +{ + bool read; + + switch (opcode) { + case COMMAND_CONFIG_READ: + case COMMAND_SWITCH_READ: + case COMMAND_SYSMSG_READ: + case COMMAND_CHGDET_READ: + case COMMAND_MONITOR_READ: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_QC_DISABLE_READ: + case COMMAND_QC_ENABLE_READ: + case COMMAND_AFC_DISABLE_READ: + case COMMAND_AFC_CAPA_READ: +#endif + case COMMAND_CHGIN_READ: + read = true; + break; + case COMMAND_CONFIG_WRITE: + case COMMAND_SWITCH_WRITE: + case COMMAND_MONITOR_WRITE: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_AFC_ENABLE_READ: + case COMMAND_QC_AUTOSET_WRITE: + case COMMAND_AFC_SET_WRITE: +#endif + read = false; + break; + default: + pr_err("%s:%s Invalid CMD Opcode[%d]\n", + MUIC_DEV_NAME, __func__, opcode); + break; + } + + return read; +} + +static bool is_notifier_opcode(u8 opcode) +{ + bool noti; + + switch (opcode) { + case NOTI_ATTACH: + case NOTI_DETACH: + case NOTI_LOGICALLY_ATTACH: + case NOTI_LOGICALLY_DETACH: + noti = true; + break; + case COMMAND_CONFIG_READ: + case COMMAND_CONFIG_WRITE: + case COMMAND_SWITCH_READ: + case COMMAND_SWITCH_WRITE: + case COMMAND_SYSMSG_READ: + case COMMAND_CHGDET_READ: + case COMMAND_MONITOR_READ: + case COMMAND_MONITOR_WRITE: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_QC_DISABLE_READ: + case COMMAND_QC_ENABLE_READ: + case COMMAND_QC_AUTOSET_WRITE: + case COMMAND_AFC_DISABLE_READ: + case COMMAND_AFC_ENABLE_READ: + case COMMAND_AFC_SET_WRITE: + case COMMAND_AFC_CAPA_READ: +#endif + case COMMAND_CHGIN_READ: + noti = false; + break; + default: + pr_err("%s:%s Invalid Opcode[%d]\n", + MUIC_DEV_NAME, __func__, opcode); + break; + } + + return noti; +} + +static u8 get_reg_written_opcode(u8 opcode) +{ + u8 reg = REG_NONE; + + switch (opcode) { + case COMMAND_CONFIG_READ: + case COMMAND_CONFIG_WRITE: + case COMMAND_SWITCH_READ: + case COMMAND_SWITCH_WRITE: + case COMMAND_MONITOR_READ: + case COMMAND_MONITOR_WRITE: + case COMMAND_CHGDET_READ: + case COMMAND_SYSMSG_READ: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_QC_DISABLE_READ: + case COMMAND_QC_ENABLE_READ: + case COMMAND_QC_AUTOSET_WRITE: + case COMMAND_AFC_DISABLE_READ: + case COMMAND_AFC_ENABLE_READ: + case COMMAND_AFC_SET_WRITE: + case COMMAND_AFC_CAPA_READ: +#endif + case COMMAND_CHGIN_READ: + reg = MAX77833_MUIC_REG_DAT_IN_OP; + break; + default: + pr_err("%s:%s Invalid Opcode[%d]\n", + MUIC_DEV_NAME, __func__, opcode); + break; + } + + return reg; +} + +static void max77833_muic_cmd_write_lastopcode + (struct max77833_muic_data *muic_data, u8 opcode) +{ + struct i2c_client *i2c = muic_data->i2c; + u8 reg; + int ret; + + reg = MAX77833_MUIC_REG_DAT_IN8; + ret = max77833_muic_write_reg(i2c, reg, opcode, REG_NONE); + if (ret) + pr_err("%s:%s Cannot write reg[0x%02x], [%d]\n", + MUIC_DEV_NAME, __func__, reg, opcode); + + return; +} + +static void max77833_muic_cmd_write_opcode + (struct max77833_muic_data *muic_data, u8 opcode, bool read) +{ + struct i2c_client *i2c = muic_data->i2c; + u8 reg; + int ret; + + reg = get_reg_written_opcode(opcode); + ret = max77833_muic_write_reg(i2c, reg, opcode, true); + if (ret) + pr_err("%s:%s Cannot write reg[0x%02x], [%d]\n", + MUIC_DEV_NAME, __func__, reg, opcode); + if (!!read) + max77833_muic_cmd_write_lastopcode(muic_data, opcode); + + return; +} + +static void calculate_write_data(muic_cmd_data *cmd_data) +{ + cmd_data->write_data = (cmd_data->val & cmd_data->mask) | \ + (cmd_data->read_data & (~cmd_data->mask)); + + pr_info("%s:%s R-data[0x%02x] + [0x%02x:0x%02x] = W-data[0x%02x]\n", + MUIC_DEV_NAME, __func__, cmd_data->read_data, + cmd_data->val, cmd_data->mask, cmd_data->write_data); + + return; +} + +static void max77833_muic_cmd_write_reg + (struct max77833_muic_data *muic_data, muic_cmd_data *cmd_data) +{ + struct i2c_client *i2c = muic_data->i2c; + + calculate_write_data(cmd_data); + +#if 0 /* MAXIM - CHECK ME!!! */ + if (cmd_data->read_data == cmd_data->write_data) { + pr_info("%s:%s Opcode[0x%02x]:[0x%02x]->[0x%02x], not write\n", + MUIC_DEV_NAME, __func__, (u8)cmd_data->opcode, + cmd_data->read_data, cmd_data->write_data); + return; + } +#endif + + max77833_muic_write_reg(i2c, cmd_data->reg, cmd_data->write_data, true); + + pr_info("%s:%s Opcode[0x%02x]:[0x%02x]->[0x%02x]\n", + MUIC_DEV_NAME, __func__, (u8)cmd_data->opcode, + cmd_data->read_data, cmd_data->write_data); + + return; +} + +static bool is_read_write_muic_cmd + (cmd_queue_t *muic_cmd_queue, u8 response) +{ + muic_cmd_data next_cmd_data; + u8 next_opcode; + bool ret = false; + + if (!front_muic_cmd(muic_cmd_queue, &next_cmd_data)) + return ret; + + next_opcode = next_cmd_data.opcode; + + switch (response) { + case COMMAND_CONFIG_READ: + if (next_opcode == COMMAND_CONFIG_WRITE) + ret = true; + break; + case COMMAND_SWITCH_READ: + if (next_opcode == COMMAND_SWITCH_WRITE) + ret = true; + break; + case COMMAND_MONITOR_READ: + if (next_opcode == COMMAND_MONITOR_WRITE) + ret = true; + break; + case COMMAND_SYSMSG_READ: + case COMMAND_CHGDET_READ: + break; +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_QC_ENABLE_READ: + if (next_opcode == COMMAND_QC_AUTOSET_WRITE) + ret = true; + break; + case COMMAND_AFC_ENABLE_READ: + case COMMAND_AFC_CAPA_READ: + if (next_opcode == COMMAND_AFC_SET_WRITE) + ret = true; + break; +#endif + default: + pr_err("%s:%s Invalid Res[0x%02x], n-Opcode[0x%02x]\n", + MUIC_DEV_NAME, __func__, response, next_opcode); + break; + } + + pr_info("%s:%s Res[0x%02x]->n-Opcode[0x%02x],RW [%c]\n", + MUIC_DEV_NAME, __func__, response, next_opcode, + (ret ? 'T' : 'F')); + + return ret; +} + +static int write_vps_regs(struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev); +static int max77833_muic_init_regs(struct max77833_muic_data *muic_data); +static void max77833_muic_free_irqs(struct max77833_muic_data *muic_data); +static int max77833_muic_handle_detach(struct max77833_muic_data *muic_data); +void max77833_muic_set_idmode_oneshot(struct max77833_muic_data *muic_data); +void max77833_muic_set_idmode_continuous(struct max77833_muic_data *muic_data); + +static void muic_cmd_run(struct max77833_muic_data *muic_data) +{ + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + struct i2c_client *i2c = muic_data->i2c; + muic_cmd_node *run_node; + muic_cmd_data cmd_data; + + run_node = kzalloc(sizeof(muic_cmd_node), GFP_KERNEL); + if (!run_node) { + pr_err("%s: failed to allocate muic command queue\n", __func__); + return; + } + + init_muic_command(run_node); + + cmd_data = run_node->cmd_data; + + if (is_empty_muic_cmd_queue(cmd_queue)) { + pr_err("%s:%s Queue, Empty!\n", MUIC_DEV_NAME, __func__); + kfree(run_node); + return; + } + + dequeue_muic_cmd(cmd_queue, &cmd_data); + + if (is_notifier_opcode(cmd_data.opcode)) { + muic_attached_dev_t noti_dev = cmd_data.noti_dev; + + switch (cmd_data.opcode) { + case NOTI_ATTACH: + muic_notifier_attach_attached_dev(noti_dev); + muic_data->attached_dev = noti_dev; + break; + case NOTI_DETACH: + muic_notifier_detach_attached_dev(noti_dev); + muic_data->attached_dev = ATTACHED_DEV_NONE_MUIC; + break; + case NOTI_LOGICALLY_ATTACH: + muic_notifier_logically_attach_attached_dev(noti_dev); + break; + case NOTI_LOGICALLY_DETACH: + muic_notifier_logically_detach_attached_dev(noti_dev); + break; + default: + pr_info("%s:%s Invalid notifier type[%d]\n", + MUIC_DEV_NAME, __func__, cmd_data.opcode); + break; + } + + muic_cmd_run(muic_data); + } else if (cmd_data.opcode == COMMAND_NONE) { /* Apcmdres isr */ + u8 response = read_muic_cmd_response(muic_data); + u8 read_reg, read_data, reg_data[5]; + int chgin, val; + + u8 muic_irq_mask[3] = {}; + u8 reset_val = 0x0; + + if (response != cmd_data.response) { + pr_err("%s:%s Response [0x%02x] != [0x%02x]\n", + MUIC_DEV_NAME, __func__, + response, cmd_data.response); + } + if (is_read_response(response, &read_reg)) { + max77833_read_reg(i2c, read_reg, &read_data); + pr_info("%s:%s Reg[0x%02x] = [0x%02x]\n", + MUIC_DEV_NAME, __func__, read_reg, read_data); + + if (is_read_write_muic_cmd(cmd_queue, response)) { + cmd_queue->front->cmd_data.read_data = read_data; + } + + switch (response) { + case COMMAND_MONITOR_READ: // For ACA issue; + pr_info("%s: %s ID MONITOR: [0x%02x]\n", MUIC_DEV_NAME, __func__, read_data); + read_data &= 0x10; + if (read_data > 0) + panic("ACA mode panic!!!"); + break; + case COMMAND_SYSMSG_READ: + /* For Reset problem */ + if (read_data == 0x05) { + mutex_lock(&muic_data->muic_mutex); + max77833_bulk_read(muic_data->i2c, MAX77833_MUIC_REG_INTMASK1, 3, muic_irq_mask); + if ((reset_val == muic_irq_mask[0]) + && (reset_val == muic_irq_mask[1]) + && (reset_val == muic_irq_mask[2])) { + pr_warn("%s:%s MUIC was reset, try re-write MUIC registers\n", + MUIC_DEV_NAME, __func__); + max77833_muic_handle_detach(muic_data); + mutex_unlock(&muic_data->muic_mutex); + max77833_muic_free_irqs(muic_data); + + mutex_lock(&muic_data->muic_mutex); + max77833_muic_init_regs(muic_data); + } + else + pr_info("%s:%s MUIC was not reset, just return\n", MUIC_DEV_NAME, __func__); + + mutex_unlock(&muic_data->muic_mutex); + } + + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT2, ®_data[0]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT3, ®_data[1]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT4, ®_data[2]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT5, ®_data[3]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT6, ®_data[4]); + + pr_info("%s:%s Check sysmsg: [6]0x%02x [5]0x%02x [4]0x%02x\n", MUIC_DEV_NAME, __func__, + read_data, reg_data[0], reg_data[1]); + pr_info("%s:%s Check sysmsg: [3]0x%02x [2]0x%02x [1]0x%02x\n", MUIC_DEV_NAME, __func__, + reg_data[2], reg_data[3], reg_data[4]); + break; +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + case COMMAND_AFC_ENABLE_READ: + if (read_data == HV_CMD_PASS) { + vi_val = FCHV_SET_9V; + max77833_muic_set_idmode_continuous(muic_data); + max77833_muic_hv_fchv_set(muic_data, vi_val, 0xff); + } + else { + if (read_data != 0x04) + max77833_muic_set_afc_ready(muic_data, false); + max77833_muic_hv_fchv_disable(muic_data); + } + break; + case COMMAND_AFC_DISABLE_READ: + if ((read_data == HV_CMD_PASS) && (muic_data->is_check_hv == true)) + max77833_muic_hv_qc_enable(muic_data); + else { + pr_info("%s:%s It's NOT HV Charger.\n", MUIC_DEV_NAME, __func__); + max77833_muic_set_idmode_oneshot(muic_data); + } + break; + case COMMAND_AFC_SET_WRITE: + if (read_data == HV_CMD_PASS) { + if (vi_val == FCHV_SET_POWERPACK) + pr_info("%s:%s POWERPACK ATTACHED.\n",MUIC_DEV_NAME,__func__); + else + max77833_muic_hv_chgin_read(muic_data); + } + else if (read_data == 0x02) + max77833_muic_hv_fchv_capa_read(muic_data); + else if (read_data == 0x03) + max77833_muic_hv_chgin_read(muic_data); + else + max77833_muic_hv_fchv_disable_set(muic_data); + break; + case COMMAND_CHGIN_READ: + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT2, ®_data[0]); + chgin = (int)(reg_data[0] * 794 / 10000); // Calculate CHGIN Volt. + + if (read_data == HV_CMD_PASS) { + if ((chgin >= 8) && (chgin <= 9)) { + pr_info("%s:%s AFC Charger ATTACHED.\n",MUIC_DEV_NAME,__func__); + max77833_muic_set_afc_ready(muic_data, false); + val = write_vps_regs(muic_data, ATTACHED_DEV_AFC_CHARGER_9V_MUIC); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), + NOTI_ATTACH, ATTACHED_DEV_AFC_CHARGER_9V_MUIC); + max77833_muic_set_idmode_oneshot(muic_data); + } + else + max77833_muic_hv_fchv_disable_set(muic_data); + } + else + max77833_muic_hv_fchv_disable_set(muic_data); + break; + case COMMAND_AFC_CAPA_READ: + if (read_data == HV_CMD_PASS) { + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT2, &vi_val); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT3, ®_data[0]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT4, ®_data[1]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT5, ®_data[2]); + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT6, ®_data[3]); + + for (val = 0; val < 4; val++) { + if (vi_val < reg_data[val]) + vi_val = reg_data[val]; + } + max77833_muic_hv_fchv_set(muic_data, vi_val, 0xff); + } + else + max77833_muic_hv_fchv_disable_set(muic_data); + break; + case COMMAND_QC_ENABLE_READ: + if (read_data == HV_CMD_PASS) { + vi_val = QC_SET_9V; + max77833_muic_hv_qc_autoset(muic_data, vi_val, 0xff); + } + else + max77833_muic_hv_qc_disable_set(muic_data); + break; + case COMMAND_QC_DISABLE_READ: + if (read_data == HV_CMD_PASS) + pr_info("%s:%s It's NOT HV Charger.\n", MUIC_DEV_NAME, __func__); + else + pr_err("%s:%s Fail HV Invalid State.\n", MUIC_DEV_NAME, __func__); + max77833_muic_set_idmode_oneshot(muic_data); + break; + case COMMAND_QC_AUTOSET_WRITE: + max77833_read_reg(i2c, MAX77833_MUIC_REG_DAT_OUT2, ®_data[0]); + chgin = (int)(reg_data[0] * 794 / 10000); // Calculate CHGIN Volt. + + if (read_data == HV_CMD_PASS) { + if ((chgin >= 8) && (chgin <= 9)) { + pr_info("%s:%s QC Charger ATTACHED.\n",MUIC_DEV_NAME,__func__); + max77833_muic_set_afc_ready(muic_data, false); + val = write_vps_regs(muic_data, ATTACHED_DEV_QC_CHARGER_9V_MUIC); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), + NOTI_ATTACH, ATTACHED_DEV_QC_CHARGER_9V_MUIC); + max77833_muic_set_idmode_oneshot(muic_data); + } + else + max77833_muic_hv_qc_disable_set(muic_data); + } + else + max77833_muic_hv_qc_disable_set(muic_data); + break; +#endif + } + } + + muic_cmd_run(muic_data); + } else { /* No isr */ + u8 opcode = cmd_data.opcode; + + if (is_read_opcode(opcode)) { + max77833_muic_cmd_write_opcode(muic_data, opcode, true); + } + else { + max77833_muic_cmd_write_opcode(muic_data, opcode, false); + max77833_muic_cmd_write_reg(muic_data, &cmd_data); + max77833_muic_cmd_write_lastopcode(muic_data, opcode); + } + } + + kfree(run_node); + + return; +} + +static void max77833_muic_handle_cmd + (struct max77833_muic_data *muic_data, int irq) +{ + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + + pr_info("%s:%s irq(%d)\n", MUIC_DEV_NAME, __func__, irq); + +// mutex_lock(&(cmd_queue->command_mutex)); + + front_muic_cmd(cmd_queue, &cmd_data); + + if (cmd_data.opcode != COMMAND_NONE) + pr_err("%s:%s Opcode[%d], CHECK!\n", + MUIC_DEV_NAME, __func__, cmd_data.opcode); + + muic_cmd_run(muic_data); + +// mutex_unlock(&cmd_queue->command_mutex); +} + +#if 0 +static void max77833_muic_read_chgdet + (struct max77833_muic_data *muic_data) +{ + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_CHGDET_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; + + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + + enqueue_muic_cmd(cmd_queue, cmd_data); + + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; + + enqueue_muic_cmd(cmd_queue, cmd_data); + + return; +} +#endif + +static void max77833_muic_read_config(struct max77833_muic_data *muic_data) +{ + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_CONFIG_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - pr_info("%s:%s REG(0x%02x): [0x%02x]+[0x%02x:0x%02x]=[0x%02x]\n", - MUIC_DEV_NAME, __func__, reg, before_val, - val, mask, after_val); - } + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; -out: - return ret; -} + enqueue_muic_cmd(cmd_queue, cmd_data); -static void muic_command_reset(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s \n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - mutex_lock(&muic_data->muic_command->command_mutex); - muic_data->muic_command->state = STATE_CMD_NONE; - muic_data->muic_command->opcode = COMMAND_NONE; - muic_data->muic_command->reg = 0xff; - muic_data->muic_command->val = 0xff; - muic_data->muic_command->rw_reg = 0xff; - muic_data->muic_command->rw_mask = 0xff; - muic_data->muic_command->rw_val = 0xff; - muic_data->muic_command->rw_before_val = 0xff; - muic_data->muic_command->rw_opcode = COMMAND_NONE; - mutex_unlock(&muic_data->muic_command->command_mutex); + enqueue_muic_cmd(cmd_queue, cmd_data); return; } -static void write_muic_end_command(struct max77833_muic_data *muic_data) +static void max77833_muic_write_config + (struct max77833_muic_data *muic_data, u8 val, u8 mask) { - u8 reg; - int ret; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_CONFIG_WRITE; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; - reg = MAX77833_MUIC_REG_DAT_IN8; - ret = max77833_muic_write_reg(muic_data->i2c, reg, 0x00, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, reg, 0x00, ret); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; + + enqueue_muic_cmd(cmd_queue, cmd_data); + + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + + enqueue_muic_cmd(cmd_queue, cmd_data); + + return; } -#if defined(CONFIG_MUIC_USE_READ_WRITE_COMMAND) -static void write_muic_read_command(struct max77833_muic_data *muic_data) +static void max77833_muic_read_switch(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command - struct i2c_client *i2c = muic_data->i2c; - u8 reg; - int ret; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_SWITCH_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + + enqueue_muic_cmd(cmd_queue, cmd_data); - reg = MAX77833_MUIC_REG_DAT_IN_OP; - ret = max77833_muic_write_reg(i2c, reg, muic_command->opcode, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, reg, muic_command->opcode, ret); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - write_muic_end_command(muic_data); + enqueue_muic_cmd(cmd_queue, cmd_data); - mutex_lock(&muic_command->command_mutex); - muic_command->state = STATE_CMD_READ_TRANS; - mutex_unlock(&muic_command->command_mutex); + return; } -static void write_muic_write_command(struct max77833_muic_data *muic_data) +static void max77833_muic_write_switch + (struct max77833_muic_data *muic_data, u8 val, u8 mask) { - struct max77833_muic_command *muic_command = muic_data->muic_command; - struct i2c_client *i2c = muic_data->i2c; - u8 reg; - int ret; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_SWITCH_WRITE; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; - reg = MAX77833_MUIC_REG_DAT_IN_OP; - ret = max77833_muic_write_reg(i2c, reg, muic_command->opcode, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, reg, opcode, ret); - - reg = muic_command->reg; - ret = max77833_muic_write_reg(i2c, reg, muic_command->val, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, reg, muic_command->val, ret); - else - write_muic_end_command(muic_data); + enqueue_muic_cmd(cmd_queue, cmd_data); - mutex_lock(&muic_command->command_mutex); - muic_data->state = STATE_CMD_WRITE_TRANS; - mutex_unlock(&muic_command->command_mutex); -} + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; -#endif + enqueue_muic_cmd(cmd_queue, cmd_data); -static void write_muic_rw_read_command(struct max77833_muic_data *muic_data) + return; +} + +static void max77833_muic_read_idmon_config + (struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; - struct i2c_client *i2c = muic_data->i2c; - u8 reg; - int ret; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_MONITOR_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + + enqueue_muic_cmd(cmd_queue, cmd_data); - reg = MAX77833_MUIC_REG_DAT_IN_OP; - ret = max77833_muic_write_reg(i2c, reg, muic_command->opcode, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, reg, muic_command->opcode, ret); + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - write_muic_end_command(muic_data); + enqueue_muic_cmd(cmd_queue, cmd_data); - mutex_lock(&muic_command->command_mutex); - muic_command->state = STATE_CMD_READ_TRANS_READY_W; - mutex_unlock(&muic_command->command_mutex); + return; } -static void write_muic_rw_write_command(struct max77833_muic_data *muic_data) +static void max77833_muic_write_idmon_config + (struct max77833_muic_data *muic_data, u8 val, u8 mask) { - struct max77833_muic_command *muic_command = muic_data->muic_command; - struct i2c_client *i2c = muic_data->i2c; - u8 reg, new_val; - - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); - muic_command->opcode = muic_command->rw_opcode; + muic_cmd_data cmd_data; + u8 opcode = COMMAND_MONITOR_WRITE; + u8 reg = MAX77833_MUIC_REG_DAT_IN1; - new_val = (muic_command->rw_val & muic_command->rw_mask) | \ - (muic_command->rw_before_val & (~(muic_command->rw_mask))); + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; + cmd_data.reg = reg; + cmd_data.val = val; + cmd_data.mask = mask; - if (muic_command->rw_before_val ^ new_val) { - int ret; - reg = MAX77833_MUIC_REG_DAT_IN_OP; - ret = max77833_muic_write_reg(i2c, reg, muic_command->opcode, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x):0x%02x [%d]\n", - MUIC_DEV_NAME, __func__, - reg, muic_command->opcode, ret); - - reg = muic_command->rw_reg; - ret = max77833_muic_write_reg(i2c, reg, new_val, true); - if (ret < 0) - pr_err("%s:%s err write REG(0x%02x) [%d]\n", - MUIC_DEV_NAME, __func__, reg, ret); - - write_muic_end_command(muic_data); - } else { - pr_info("%s:%s REG(0x%02x): already [0x%02x], don't write reg\n", - MUIC_DEV_NAME, __func__, - reg, muic_command->rw_before_val); - - mutex_lock(&muic_command->command_mutex); - muic_command->state = STATE_CMD_NONE; - mutex_unlock(&muic_command->command_mutex); + enqueue_muic_cmd(cmd_queue, cmd_data); - return; - } + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; - mutex_lock(&muic_command->command_mutex); - muic_command->state = STATE_CMD_WRITE_TRANS; - mutex_unlock(&muic_command->command_mutex); + enqueue_muic_cmd(cmd_queue, cmd_data); return; } -static void write_muic_ctrl_reg(struct max77833_muic_data *muic_data, - const u8 reg, const u8 val) +static void max77833_muic_read_sysmsg(struct max77833_muic_data *muic_data, int irq) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + cmd_queue_t *cmd_queue = &(muic_data->muic_cmd_queue); + muic_cmd_data cmd_data; + u8 opcode = COMMAND_SYSMSG_READ; + u8 reg = MAX77833_MUIC_REG_DAT_OUT1; + bool empty_q = is_empty_muic_cmd_queue(&(muic_data->muic_cmd_queue)); - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + pr_info("%s:%s irq(%d)\n", MUIC_DEV_NAME, __func__, irq); + + init_muic_cmd_data(&cmd_data); + cmd_data.opcode = opcode; - muic_command->opcode = COMMAND_SWITCH_READ; + enqueue_muic_cmd(cmd_queue, cmd_data); - muic_command->rw_reg = reg; - muic_command->rw_mask = 0xff; - muic_command->rw_val = val; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; + init_muic_cmd_data(&cmd_data); + cmd_data.response = opcode; + cmd_data.reg = reg; - write_muic_rw_read_command(muic_data); + enqueue_muic_cmd(cmd_queue, cmd_data); + + if (empty_q) + max77833_muic_handle_cmd(muic_data, -5); + + return; } static void com_to_open(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + u8 reg_val; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - muic_command->opcode = COMMAND_SWITCH_READ; - - muic_command->rw_reg = MAX77833_MUIC_REG_DAT_IN1; - muic_command->rw_mask = 0xff; - muic_command->rw_val = CTRL1_OPEN; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; + reg_val = COM_OPEN; - /* write control1 register */ - write_muic_rw_read_command(muic_data); + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, reg_val, 0xff); } -static void com_to_usb_ap(struct max77833_muic_data *muic_data) +static int com_to_usb_ap(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + u8 reg_val; + int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - muic_command->opcode = COMMAND_SWITCH_READ; + reg_val = COM_USB; + + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, reg_val, 0xff); - muic_command->rw_reg = MAX77833_MUIC_REG_DAT_IN1; - muic_command->rw_mask = 0xff; - muic_command->rw_val = CTRL1_USB; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; + if (muic_data->pdata->set_safeout) { + ret = muic_data->pdata->set_safeout(MUIC_PATH_USB_AP); + if (ret) + pr_err("%s:%s set_safeout err(%d)\n", MUIC_DEV_NAME, __func__, ret); + } - /* write control1 register */ - write_muic_rw_read_command(muic_data); + return ret; } -static void com_to_usb_cp(struct max77833_muic_data *muic_data) +static int com_to_usb_cp(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + u8 reg_val; + int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - muic_command->opcode = COMMAND_SWITCH_READ; + reg_val = COM_USB_CP; - muic_command->rw_reg = MAX77833_MUIC_REG_DAT_IN1; - muic_command->rw_mask = 0xff; - muic_command->rw_val = CTRL1_USB_CP; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, reg_val, 0xff); + + if (muic_data->pdata->set_safeout) { + ret = muic_data->pdata->set_safeout(MUIC_PATH_USB_CP); + if (ret) + pr_err("%s:%s set_safeout err(%d)\n", MUIC_DEV_NAME, __func__, ret); + } - /* write control1 register */ - write_muic_rw_read_command(muic_data); + return ret; } static void com_to_uart_ap(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + u8 reg_val; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - muic_command->opcode = COMMAND_SWITCH_READ; + reg_val = COM_UART; - muic_command->rw_reg = MAX77833_MUIC_REG_DAT_IN1; - muic_command->rw_mask = 0xff; - muic_command->rw_val = CTRL1_UART; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; - - /* write control1 register */ - write_muic_rw_read_command(muic_data); + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, reg_val, 0xff); } static void com_to_uart_cp(struct max77833_muic_data *muic_data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; + u8 reg_val; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - muic_command->opcode = COMMAND_SWITCH_READ; - - muic_command->rw_reg = MAX77833_MUIC_REG_DAT_IN1; - muic_command->rw_mask = 0xff; - muic_command->rw_val = CTRL1_UART_CP; - muic_command->rw_opcode = COMMAND_SWITCH_WRITE; + reg_val = COM_UART_CP; - /* write control1 register */ - write_muic_rw_read_command(muic_data); + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, reg_val, 0xff); } static int write_vps_regs(struct max77833_muic_data *muic_data, @@ -821,15 +1345,18 @@ static int write_vps_regs(struct max77833_muic_data *muic_data, const struct max77833_muic_vps_data *tmp_vps; int vps_index; - vps_index = muic_lookup_vps_table(new_dev); + vps_index = muic_lookup_vps_table(new_dev, muic_data); if (vps_index < 0) return -ENODEV; tmp_vps = &(muic_vps_table[vps_index]); - /* write control1 register */ - write_muic_ctrl_reg(muic_data, MAX77833_MUIC_REG_DAT_IN1, - tmp_vps->control1); +if ((new_dev != ATTACHED_DEV_QC_CHARGER_9V_MUIC) && (new_dev != ATTACHED_DEV_AFC_CHARGER_9V_MUIC)) { + /* write command - switch */ + max77833_muic_read_switch(muic_data); + max77833_muic_write_switch(muic_data, tmp_vps->muic_switch, 0xff); +} + return 0; } @@ -841,8 +1368,9 @@ static int switch_to_ap_uart(struct max77833_muic_data *muic_data, switch (new_dev) { case ATTACHED_DEV_JIG_UART_OFF_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: + case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC: +// case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: +// case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: com_to_uart_ap(muic_data); break; default: @@ -861,8 +1389,9 @@ static int switch_to_cp_uart(struct max77833_muic_data *muic_data, switch (new_dev) { case ATTACHED_DEV_JIG_UART_OFF_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: + case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC: +// case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: +// case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: com_to_uart_cp(muic_data); break; default: @@ -874,16 +1403,25 @@ static int switch_to_cp_uart(struct max77833_muic_data *muic_data, return ret; } -static int max77833_muic_enable_chgdet(struct max77833_muic_data *muic_data) +static void max77833_muic_enable_chgdet(struct max77833_muic_data *muic_data) { - return 0; + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + + /* write command - config */ + max77833_muic_read_config(muic_data); + max77833_muic_write_config(muic_data, CHGDET_ENABLE, 0xff); } -static int max77833_muic_disable_chgdet(struct max77833_muic_data *muic_data) +static void max77833_muic_disable_chgdet(struct max77833_muic_data *muic_data) { - return 0; + pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); + + /* write command - config */ + max77833_muic_read_config(muic_data); + max77833_muic_write_config(muic_data, CHGDET_DISABLE, 0xff); } +#if 0 static int max77833_muic_enable_accdet(struct max77833_muic_data *muic_data) { return 0; @@ -893,11 +1431,12 @@ static int max77833_muic_disable_accdet(struct max77833_muic_data *muic_data) { return 0; } +#endif static u8 max77833_muic_get_adc_value(struct max77833_muic_data *muic_data) { u8 status; - u8 adc = ADC_ERROR; + u8 adc = MAX77833_ADC_ERROR; int ret; ret = max77833_read_reg(muic_data->i2c, MAX77833_MUIC_REG_STATUS1, @@ -906,9 +1445,7 @@ static u8 max77833_muic_get_adc_value(struct max77833_muic_data *muic_data) pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_DEV_NAME, __func__, ret); else - adc = status & STATUS1_ADC_MASK; - - if(adc >= 0x10) adc-= 0x10; + adc = status & STATUS1_IDRES_MASK; return adc; } @@ -942,6 +1479,7 @@ static ssize_t max77833_muic_set_uart_sel(struct device *dev, { struct max77833_muic_data *muic_data = dev_get_drvdata(dev); struct muic_platform_data *pdata = muic_data->pdata; + bool empty_q = is_empty_muic_cmd_queue(&(muic_data->muic_cmd_queue)); if (!strncasecmp(buf, "AP", 2)) { pdata->uart_path = MUIC_PATH_UART_AP; @@ -956,6 +1494,9 @@ static ssize_t max77833_muic_set_uart_sel(struct device *dev, pr_info("%s:%s uart_path(%d)\n", MUIC_DEV_NAME, __func__, pdata->uart_path); + if (empty_q) + max77833_muic_handle_cmd(muic_data, -3); + return count; } @@ -1050,7 +1591,7 @@ static ssize_t max77833_muic_show_adc(struct device *dev, adc = max77833_muic_get_adc_value(muic_data); pr_info("%s:%s adc(0x%02x)\n", MUIC_DEV_NAME, __func__, adc); - if (adc == ADC_ERROR) { + if (adc == MAX77833_ADC_ERROR) { pr_err("%s:%s fail to read adc value\n", MUIC_DEV_NAME, __func__); return sprintf(buf, "UNKNOWN\n"); @@ -1086,7 +1627,7 @@ static ssize_t max77833_muic_show_attached_dev(struct device *dev, const struct max77833_muic_vps_data *tmp_vps; int vps_index; - vps_index = muic_lookup_vps_table(muic_data->attached_dev); + vps_index = muic_lookup_vps_table(muic_data->attached_dev, muic_data); if (vps_index < 0) return sprintf(buf, "Error No Device\n"); @@ -1099,19 +1640,19 @@ static ssize_t max77833_muic_show_otg_test(struct device *dev, struct device_attribute *attr, char *buf) { struct max77833_muic_data *muic_data = dev_get_drvdata(dev); - struct i2c_client *i2c = muic_data->i2c; int ret = -ENODEV; - u8 val; if (muic_check_support_dev(muic_data, ATTACHED_DEV_OTG_MUIC)) { - ret = max77833_read_reg(i2c, MAX77833_MUIC_REG_CDETCTRL1, &val); - pr_info("%s:%s ret:%d val:%x buf:%s\n", MUIC_DEV_NAME, __func__, ret, val, buf); - if (ret) { - pr_err("%s:%s: fail to read muic reg\n", MUIC_DEV_NAME, __func__); - return sprintf(buf, "UNKNOWN\n"); - } - val &= CHGDETEN_MASK; - return sprintf(buf, "%x\n", val); + if (muic_data->is_otg_test == true) + ret = 0; + else + ret = 1; + pr_info("%s:%s ret:%d buf:%s\n", MUIC_DEV_NAME, __func__, ret, buf); + + return ret; + + // Read chgdet value - CHECK ME!!! + //return sprintf(buf, "%x\n", val); } else return ret; } @@ -1121,44 +1662,32 @@ static ssize_t max77833_muic_set_otg_test(struct device *dev, const char *buf, size_t count) { struct max77833_muic_data *muic_data = dev_get_drvdata(dev); - struct i2c_client *i2c = muic_data->i2c; - u8 val = 0; int ret = -ENODEV; + bool empty_q = is_empty_muic_cmd_queue(&(muic_data->muic_cmd_queue)); if (muic_check_support_dev(muic_data, ATTACHED_DEV_OTG_MUIC)) { pr_info("%s:%s buf:%s\n", MUIC_DEV_NAME, __func__, buf); if (!strncmp(buf, "0", 1)) { muic_data->is_otg_test = true; - ret = max77833_muic_disable_chgdet(muic_data); - if (ret) - goto err_chgdet; - ret = max77833_muic_enable_accdet(muic_data); - if (ret) - goto err_accdet; + max77833_muic_disable_chgdet(muic_data); + ret = 0; } else if (!strncmp(buf, "1", 1)) { muic_data->is_otg_test = false; - ret = max77833_muic_enable_chgdet(muic_data); - if (ret) - goto err_chgdet; + max77833_muic_enable_chgdet(muic_data); + ret = 1; } else { pr_warn("%s:%s Wrong command\n", MUIC_DEV_NAME, __func__); return count; } - max77833_read_reg(i2c, MAX77833_MUIC_REG_CDETCTRL1, &val); - pr_info("%s:%s CDETCTRL(0x%02x)\n", MUIC_DEV_NAME, __func__, val); + pr_info("%s:%s ret: %d\n", MUIC_DEV_NAME, __func__, ret); + + if (empty_q) + max77833_muic_handle_cmd(muic_data, -6); return count; } else return ret; - -err_chgdet: - pr_err("%s:%s cannot change chgdet!\n", MUIC_DEV_NAME, __func__); - return ret; - -err_accdet: - pr_err("%s:%s cannot change accdet!\n", MUIC_DEV_NAME, __func__); - return ret; } static ssize_t max77833_muic_show_apo_factory(struct device *dev, @@ -1206,68 +1735,6 @@ static ssize_t max77833_muic_set_apo_factory(struct device *dev, return count; } -#if defined(CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA) && defined(CONFIG_SEC_FACTORY) -static ssize_t max77833_muic_show_ignore_adcerr(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct max77833_muic_data *muic_data = dev_get_drvdata(dev); - - pr_info("%s:%s ignore_adcerr[%c]", MUIC_DEV_NAME, __func__, - (muic_data->ignore_adcerr ? 'T' : 'F')); - - if (muic_data->ignore_adcerr) - return sprintf(buf, "1\n"); - - return sprintf(buf, "0\n"); -} - -static ssize_t max77833_muic_set_ignore_adcerr(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct max77833_muic_data *muic_data = dev_get_drvdata(dev); - - if (!strncasecmp(buf, "1", 1)) { - muic_data->ignore_adcerr = true; - } else if (!strncasecmp(buf, "0", 0)) { - muic_data->ignore_adcerr = false; - } else { - pr_warn("%s:%s invalid value\n", MUIC_DEV_NAME, __func__); - } - - pr_info("%s:%s ignore adc_err(%d)\n", MUIC_DEV_NAME, __func__, - muic_data->ignore_adcerr); - - return count; -} -#endif /* CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA && CONFIG_SEC_FACTORY */ - -static void max77833_muic_set_adcdbset - (struct max77833_muic_data *muic_data, int value) -{ - struct i2c_client *i2c = muic_data->i2c; - int ret; - u8 val; - - if (value > 3) { - pr_err("%s:%s invalid value(%d)\n", MUIC_DEV_NAME, __func__, - value); - return; - } - - if (!i2c) { - pr_err("%s:%s no muic i2c client\n", MUIC_DEV_NAME, __func__); - return; - } - - val = (value << CTRL4_ADCDBSET_SHIFT); - ret = max77833_muic_update_reg(i2c, MAX77833_MUIC_REG_CTRL4, val, - CTRL4_ADCDBSET_MASK, true); - if (ret < 0) - pr_err("%s: fail to write reg\n", __func__); -} - #if defined(CONFIG_HV_MUIC_MAX77833_AFC) static ssize_t max77833_muic_show_afc_disable(struct device *dev, struct device_attribute *attr, char *buf) @@ -1322,10 +1789,6 @@ static DEVICE_ATTR(otg_test, 0664, max77833_muic_show_otg_test, max77833_muic_set_otg_test); static DEVICE_ATTR(apo_factory, 0664, max77833_muic_show_apo_factory, max77833_muic_set_apo_factory); -#if defined(CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA) && defined(CONFIG_SEC_FACTORY) -static DEVICE_ATTR(ignore_adcerr, 0664, - max77833_muic_show_ignore_adcerr, max77833_muic_set_ignore_adcerr); -#endif /* CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA && CONFIG_SEC_FACTORY */ #if defined(CONFIG_HV_MUIC_MAX77833_AFC) static DEVICE_ATTR(afc_disable, 0664, max77833_muic_show_afc_disable, max77833_muic_set_afc_disable); @@ -1343,9 +1806,6 @@ static struct attribute *max77833_muic_attributes[] = { #endif /* CONFIG_MUIC_MAX77833_SUPPROT_AUDIO_LINE_OUT_CONTROL */ &dev_attr_otg_test.attr, &dev_attr_apo_factory.attr, -#if defined(CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA) && defined(CONFIG_SEC_FACTORY) - &dev_attr_ignore_adcerr.attr, -#endif /* CONFIG_MUIC_MAX77833_IGNORE_ADCERR_WA && CONFIG_SEC_FACTORY */ #if defined(CONFIG_HV_MUIC_MAX77833_AFC) &dev_attr_afc_disable.attr, #endif /* CONFIG_HV_MUIC_MAX77833_AFC */ @@ -1359,21 +1819,13 @@ static const struct attribute_group max77833_muic_group = { void max77833_muic_read_register(struct i2c_client *i2c) { const enum max77833_muic_reg regfile[] = { - MAX77833_MUIC_REG_ID, + MAX77833_MUIC_REG_HW_REV, MAX77833_MUIC_REG_STATUS1, MAX77833_MUIC_REG_STATUS2, MAX77833_MUIC_REG_STATUS3, MAX77833_MUIC_REG_INTMASK1, MAX77833_MUIC_REG_INTMASK2, MAX77833_MUIC_REG_INTMASK3, - MAX77833_MUIC_REG_CDETCTRL1, - MAX77833_MUIC_REG_CDETCTRL2, - MAX77833_MUIC_REG_CTRL1, - MAX77833_MUIC_REG_CTRL2, - MAX77833_MUIC_REG_CTRL3, - MAX77833_MUIC_REG_CTRL4, - MAX77833_MUIC_REG_HVCONTROL1, - MAX77833_MUIC_REG_HVCONTROL2, }; u8 val; int i; @@ -1394,71 +1846,30 @@ void max77833_muic_read_register(struct i2c_client *i2c) pr_info("%s:%s end register---------------\n", MUIC_DEV_NAME, __func__); } -static bool max77833_muic_check_dev_factory_charging(struct max77833_muic_data *muic_data) +static void max77833_muic_set_adcmode + (struct max77833_muic_data *muic_data, u8 val) { - u8 adc = (muic_data->status1) & STATUS1_ADC_MASK; - u8 vbvolt = (muic_data->status2) & STATUS2_VBVOLT_MASK; + const u8 mask = MODE_MASK; - switch (adc) { - case ADC_JIG_USB_OFF: - if (vbvolt == VB_HIGH) - return true; - break; - default: - break; + if (muic_data->adcmode == val) { + pr_info("%s: %s: ADCMODE Duplicated.\n", MUIC_DEV_NAME, __func__); + return; + } + else { + muic_data->adcmode = val; + max77833_muic_read_idmon_config(muic_data); + val = val << MODE_SHIFT; + max77833_muic_write_idmon_config(muic_data, val, mask); + max77833_muic_read_idmon_config(muic_data); // For ACA issue. } - return false; -} - -static int max77833_muic_set_adcmode(struct max77833_muic_data *muic_data, - u8 val) -{ -#if 0 - struct i2c_client *i2c = muic_data->i2c; - u8 adc_val = (val << MODE_SHIFT); - u8 response, reg; - int ret = 0; - - reg = MAX77833_MUIC_REG_DAT_IN_OP; - ret = max77833_write_reg(i2c, reg, COMMAND_ID_MONITOR_CONFIG_WRITE); - if (ret) - pr_err("%s:%s fail to write reg[0x%02x], ret(%d)\n", - MUIC_DEV_NAME, __func__, reg, ret); - - reg = MAX77833_MUIC_REG_DAT_IN1; - ret = max77833_write_reg(i2c, reg, adc_val); - if (ret) - pr_err("%s:%s fail to read reg[0x%02x], ret(%d)\n", - MUIC_DEV_NAME, __func__, reg, ret); - - reg = MAX77833_MUIC_REG_DAT_IN8; - ret = max77833_write_reg(i2c, reg, 0x00); - if (ret) - pr_err("%s:%s fail to read reg[0x%02x], ret(%d)\n", - MUIC_DEV_NAME, __func__, reg, ret); - - mdelay(10); - - reg = MAX77833_MUIC_REG_DAT_OUT_OP; - ret = max77833_read_reg(i2c, reg, &response); - if (ret) - pr_err("%s:%s fail to read reg[0x%02x], ret(%d)\n", - MUIC_DEV_NAME, __func__, reg, ret); - else - pr_info("%s:%s reg(0x%02x) = 0x%02x\n", - MUIC_DEV_NAME, __func__, reg, response); - - return ret; -#endif - return 0; + return; } -static void max77833_muic_adcmode_switch(struct max77833_muic_data *muic_data, - const u8 val) +static void max77833_muic_adcmode_switch + (struct max77833_muic_data *muic_data, const u8 val) { const char *name; - int ret = 0; switch (val) { case MAX77833_MUIC_IDMODE_CONTINUOUS: @@ -1479,12 +1890,10 @@ static void max77833_muic_adcmode_switch(struct max77833_muic_data *muic_data, return; } - ret = max77833_muic_set_adcmode(muic_data, val); - if (ret) { - pr_err("%s:%s fail to adcmode change to %s ret:%d\n", - MUIC_DEV_NAME, __func__, name, ret); - return; - } + pr_info("%s:%s %s val[0x%02x]\n", MUIC_DEV_NAME, __func__, name, val); + max77833_muic_set_adcmode(muic_data, val); + + return; } void max77833_muic_set_idmode_continuous(struct max77833_muic_data *muic_data) @@ -1496,25 +1905,23 @@ void max77833_muic_set_idmode_continuous(struct max77833_muic_data *muic_data) return; } -#if !defined(CONFIG_SEC_FACTORY) -static void max77833_muic_set_idmode_factory_oneshot(struct max77833_muic_data *muic_data) +void max77833_muic_set_idmode_oneshot(struct max77833_muic_data *muic_data) { - const u8 val = MAX77833_MUIC_IDMODE_FACTORY_ONE_SHOT; + const u8 val = MAX77833_MUIC_IDMODE_ONE_SHOT; max77833_muic_adcmode_switch(muic_data, val); return; } -void max77833_muic_set_idmode_oneshot(struct max77833_muic_data *muic_data) +void max77833_muic_set_idmode_pulse(struct max77833_muic_data *muic_data) { - const u8 val = MAX77833_MUIC_IDMODE_ONE_SHOT; + const u8 val = MAX77833_MUIC_IDMODE_PULSE; max77833_muic_adcmode_switch(muic_data, val); return; } -#endif /* !CONFIG_SEC_FACTORY */ static int max77833_muic_attach_uart_path(struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) @@ -1544,10 +1951,10 @@ static int max77833_muic_attach_usb_path(struct max77833_muic_data *muic_data, pr_info("%s:%s usb_path=%d\n", MUIC_DEV_NAME, __func__, pdata->usb_path); if (pdata->usb_path == MUIC_PATH_USB_AP) { - com_to_usb_ap(muic_data); + ret = com_to_usb_ap(muic_data); } else if (pdata->usb_path == MUIC_PATH_USB_CP) { - com_to_usb_cp(muic_data); + ret = com_to_usb_cp(muic_data); } else pr_warn("%s:%s invalid usb_path\n", MUIC_DEV_NAME, __func__); @@ -1555,14 +1962,15 @@ static int max77833_muic_attach_usb_path(struct max77833_muic_data *muic_data, return ret; } +#if defined(CONFIG_SEC_FACTORY) static muic_attached_dev_t check_jig_uart_on_factory_test (struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) { muic_attached_dev_t ret_ndev; if (muic_data->is_factory_start && - muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) { - ret_ndev = ATTACHED_DEV_JIG_UART_ON_MUIC; + muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) { + ret_ndev = ATTACHED_DEV_JIG_UART_ON_MUIC; } else ret_ndev = ATTACHED_DEV_JIG_UART_OFF_MUIC; @@ -1571,6 +1979,7 @@ static muic_attached_dev_t check_jig_uart_on_factory_test return ret_ndev; } +#endif static int max77833_muic_handle_detach(struct max77833_muic_data *muic_data) { @@ -1585,16 +1994,9 @@ static int max77833_muic_handle_detach(struct max77833_muic_data *muic_data) } /* Enable Factory Accessory Detection State Machine */ - max77833_muic_enable_accdet(muic_data); - -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_muic_set_afc_ready(muic_data, false); - muic_data->is_afc_muic_prepare = false; - - cancel_delayed_work_sync(&muic_data->hv_muic_qc_vb_work); -#endif +// max77833_muic_enable_accdet(muic_data); - muic_lookup_vps_table(muic_data->attached_dev); + muic_lookup_vps_table(muic_data->attached_dev, muic_data); switch (muic_data->attached_dev) { case ATTACHED_DEV_OTG_MUIC: @@ -1607,22 +2009,16 @@ static int max77833_muic_handle_detach(struct max77833_muic_data *muic_data) goto out_without_noti; case ATTACHED_DEV_SMARTDOCK_MUIC: goto out_without_noti; - case ATTACHED_DEV_SMARTDOCK_VB_MUIC: - noti = false; - logically_noti = true; - break; case ATTACHED_DEV_SMARTDOCK_TA_MUIC: case ATTACHED_DEV_SMARTDOCK_USB_MUIC: logically_noti = true; break; case ATTACHED_DEV_TA_MUIC: - case ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC: - case ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC: +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) case ATTACHED_DEV_AFC_CHARGER_9V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC: + case ATTACHED_DEV_QC_CHARGER_9V_MUIC: +#endif + case ATTACHED_DEV_TIMEOUT_OPEN_MUIC: // For chgtyp 0x04 issue. break; default: break; @@ -1630,12 +2026,20 @@ static int max77833_muic_handle_detach(struct max77833_muic_data *muic_data) #if defined(CONFIG_MUIC_NOTIFIER) if (noti) - muic_notifier_detach_attached_dev(muic_data->attached_dev); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), + NOTI_DETACH, muic_data->attached_dev); - if (logically_noti) - muic_notifier_logically_detach_attached_dev(ATTACHED_DEV_SMARTDOCK_VB_MUIC); +// if (logically_noti) +// enqueue_muic_notifier(&(muic_data->muic_cmd_queue), +// NOTI_LOGICALLY_DETACH, ATTACHED_DEV_SMARTDOCK_VB_MUIC); #endif /* CONFIG_MUIC_NOTIFIER */ +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + max77833_muic_set_afc_ready(muic_data, false); + max77833_muic_hv_qc_disable(muic_data); + max77833_muic_hv_fchv_disable(muic_data); +#endif + out_without_noti: com_to_open(muic_data); @@ -1648,25 +2052,24 @@ static int max77833_muic_logically_detach(struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) { bool noti = true; - bool logically_notify = false; +// bool logically_notify = false; bool force_path_open = true; - bool enable_accdet = true; +// bool enable_accdet = true; int ret = 0; - if (max77833_muic_check_dev_factory_charging(muic_data)) - enable_accdet = false; - switch (muic_data->attached_dev) { - case ATTACHED_DEV_USB_MUIC: - case ATTACHED_DEV_CDP_MUIC: case ATTACHED_DEV_OTG_MUIC: case ATTACHED_DEV_CHARGING_CABLE_MUIC: case ATTACHED_DEV_HMT_MUIC: + /* Enable Charger Detection */ + max77833_muic_enable_chgdet(muic_data); + break; + case ATTACHED_DEV_USB_MUIC: + case ATTACHED_DEV_CDP_MUIC: case ATTACHED_DEV_UNDEFINED_CHARGING_MUIC: case ATTACHED_DEV_JIG_USB_ON_MUIC: case ATTACHED_DEV_MHL_MUIC: case ATTACHED_DEV_AUDIODOCK_MUIC: - case ATTACHED_DEV_UNSUPPORTED_ID_VB_MUIC: case ATTACHED_DEV_UNOFFICIAL_TA_MUIC: break; case ATTACHED_DEV_UNOFFICIAL_ID_TA_MUIC: @@ -1679,13 +2082,11 @@ static int max77833_muic_logically_detach(struct max77833_muic_data *muic_data, case ATTACHED_DEV_UNOFFICIAL_ID_MUIC: goto out; case ATTACHED_DEV_JIG_UART_OFF_MUIC: - if (new_dev == ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC || - new_dev == ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC || - new_dev == ATTACHED_DEV_JIG_UART_ON_MUIC) + if (new_dev == ATTACHED_DEV_JIG_UART_OFF_VB_MUIC || + new_dev == ATTACHED_DEV_JIG_UART_ON_MUIC) force_path_open = false; break; - case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: + case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC: if (new_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) force_path_open = false; break; @@ -1695,48 +2096,23 @@ static int max77833_muic_logically_detach(struct max77833_muic_data *muic_data, force_path_open = false; break; case ATTACHED_DEV_DESKDOCK_MUIC: - if (new_dev == ATTACHED_DEV_DESKDOCK_VB_MUIC) - goto out; - break; - case ATTACHED_DEV_DESKDOCK_VB_MUIC: - if (new_dev == ATTACHED_DEV_DESKDOCK_MUIC) - goto out; - break; - case ATTACHED_DEV_SMARTDOCK_VB_MUIC: - if ((new_dev == ATTACHED_DEV_SMARTDOCK_USB_MUIC) || - (new_dev == ATTACHED_DEV_SMARTDOCK_TA_MUIC)) - goto out; - - logically_notify = true; break; case ATTACHED_DEV_SMARTDOCK_USB_MUIC: case ATTACHED_DEV_SMARTDOCK_TA_MUIC: - if (new_dev != ATTACHED_DEV_SMARTDOCK_VB_MUIC) - logically_notify = true; +// if (new_dev != ATTACHED_DEV_SMARTDOCK_VB_MUIC) +// logically_notify = true; break; case ATTACHED_DEV_SMARTDOCK_MUIC: goto out; case ATTACHED_DEV_TA_MUIC: #if defined(CONFIG_HV_MUIC_MAX77833_AFC) - case ATTACHED_DEV_AFC_CHARGER_PREPARE_MUIC: - case ATTACHED_DEV_AFC_CHARGER_PREPARE_DUPLI_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_5V_DUPLI_MUIC: - case ATTACHED_DEV_AFC_CHARGER_9V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_MUIC: - case ATTACHED_DEV_AFC_CHARGER_ERR_V_DUPLI_MUIC: - case ATTACHED_DEV_QC_CHARGER_PREPARE_MUIC: - case ATTACHED_DEV_QC_CHARGER_5V_MUIC: - case ATTACHED_DEV_QC_CHARGER_9V_MUIC: - noti = max77833_muic_check_change_dev_afc_charger(muic_data, new_dev); - if (noti) { - max77833_muic_set_afc_ready(muic_data, false); - muic_data->is_afc_muic_prepare = false; - max77833_hv_muic_reset_hvcontrol_reg(muic_data); - cancel_delayed_work_sync(&muic_data->hv_muic_qc_vb_work); - } + max77833_muic_set_afc_ready(muic_data, false); + max77833_muic_hv_qc_disable(muic_data); + max77833_muic_hv_fchv_disable(muic_data); #endif break; + case ATTACHED_DEV_TIMEOUT_OPEN_MUIC: // For chgtyp 0x04 issue. + break; case ATTACHED_DEV_NONE_MUIC: force_path_open = false; goto out; @@ -1751,16 +2127,15 @@ static int max77833_muic_logically_detach(struct max77833_muic_data *muic_data, #if defined(CONFIG_MUIC_NOTIFIER) if (noti) - muic_notifier_detach_attached_dev(muic_data->attached_dev); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), NOTI_DETACH, + muic_data->attached_dev); - if (logically_notify) - muic_notifier_logically_detach_attached_dev(ATTACHED_DEV_SMARTDOCK_VB_MUIC); +// if (logically_notify) +// enqueue_muic_notifier(&(muic_data->muic_cmd_queue), +// NOTI_LOGICALLY_DETACH, ATTACHED_DEV_SMARTDOCK_VB_MUIC); #endif /* CONFIG_MUIC_NOTIFIER */ out: - if (enable_accdet) - max77833_muic_enable_accdet(muic_data); - if (force_path_open) com_to_open(muic_data); @@ -1771,24 +2146,15 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) { bool logically_notify = false; - bool noti_smartdock = false; +// bool noti_smartdock = false; int ret = 0; -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - if (muic_data->attached_dev == ATTACHED_DEV_HV_ID_ERR_UNDEFINED_MUIC || - muic_data->attached_dev == ATTACHED_DEV_HV_ID_ERR_UNSUPPORTED_MUIC || - muic_data->attached_dev == ATTACHED_DEV_HV_ID_ERR_SUPPORTED_MUIC) - return ret; -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ + pr_info("%s:%s \n", MUIC_DEV_NAME, __func__); if (new_dev == muic_data->attached_dev) { - if (muic_data->attached_dev != ATTACHED_DEV_AFC_CHARGER_5V_MUIC || - muic_data->is_mrxrdy != true) { - pr_info("%s:%s Duplicated(%d), mrxrdy(%c), just ignore \n", - MUIC_DEV_NAME, __func__, muic_data->attached_dev, - muic_data->is_mrxrdy ? 'T' : 'F'); - return ret; - } + pr_info("%s:%s Duplicated(%d), just ignore \n", + MUIC_DEV_NAME, __func__, muic_data->attached_dev); + return ret; } ret = max77833_muic_logically_detach(muic_data, new_dev); @@ -1805,25 +2171,17 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, max77833_muic_disable_chgdet(muic_data); break; case ATTACHED_DEV_JIG_UART_OFF_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC: - case ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC: + case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC: ret = max77833_muic_attach_uart_path(muic_data, new_dev); break; case ATTACHED_DEV_JIG_UART_ON_MUIC: +#if defined(CONFIG_SEC_FACTORY) new_dev = check_jig_uart_on_factory_test(muic_data, new_dev); if (new_dev != ATTACHED_DEV_JIG_UART_ON_MUIC) goto out; +#endif break; case ATTACHED_DEV_TA_MUIC: -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - if (muic_data->pdata->afc_disable) - pr_info("%s:%s AFC Disable(%d) by USER!\n", MUIC_DEV_NAME, - __func__, muic_data->pdata->afc_disable); - else { - if (muic_data->is_afc_muic_ready == false) - max77833_muic_prepare_afc_charger(muic_data); - } -#endif ret = write_vps_regs(muic_data, new_dev); break; case ATTACHED_DEV_UNDEFINED_CHARGING_MUIC: @@ -1844,7 +2202,7 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, ret = max77833_muic_attach_usb_path(muic_data, new_dev); break; case ATTACHED_DEV_UNOFFICIAL_ID_MUIC: - max77833_muic_disable_accdet(muic_data); +// max77833_muic_disable_accdet(muic_data); goto out_without_noti; case ATTACHED_DEV_MHL_MUIC: ret = write_vps_regs(muic_data, new_dev); @@ -1853,21 +2211,13 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, if (muic_data->attached_dev == ATTACHED_DEV_DESKDOCK_VB_MUIC) logically_notify = true; break; - case ATTACHED_DEV_DESKDOCK_VB_MUIC: - if (muic_data->attached_dev == ATTACHED_DEV_DESKDOCK_MUIC) - logically_notify = true; - break; case ATTACHED_DEV_SMARTDOCK_MUIC: ret = write_vps_regs(muic_data, new_dev); goto out_without_noti; - case ATTACHED_DEV_SMARTDOCK_VB_MUIC: - logically_notify = true; - ret = write_vps_regs(muic_data, new_dev); - break; case ATTACHED_DEV_SMARTDOCK_TA_MUIC: case ATTACHED_DEV_SMARTDOCK_USB_MUIC: - if (muic_data->attached_dev != ATTACHED_DEV_SMARTDOCK_VB_MUIC) - noti_smartdock = true; +// if (muic_data->attached_dev != ATTACHED_DEV_SMARTDOCK_VB_MUIC) +// noti_smartdock = true; ret = write_vps_regs(muic_data, new_dev); break; case ATTACHED_DEV_AUDIODOCK_MUIC: @@ -1876,9 +2226,8 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, case ATTACHED_DEV_UNIVERSAL_MMDOCK_MUIC: ret = write_vps_regs(muic_data, new_dev); break; - case ATTACHED_DEV_UNSUPPORTED_ID_VB_MUIC: - write_muic_ctrl_reg(muic_data, MAX77833_MUIC_REG_DAT_IN1, - CTRL1_OPEN); + case ATTACHED_DEV_TIMEOUT_OPEN_MUIC: // For chgtyp 0x04 issue. + ret = write_vps_regs(muic_data, new_dev); break; default: pr_warn("%s:%s unsupported dev(%d)\n", MUIC_DEV_NAME, __func__, @@ -1887,53 +2236,54 @@ static int max77833_muic_handle_attach(struct max77833_muic_data *muic_data, goto out; } -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - new_dev = hv_muic_check_id_err(muic_data, new_dev); -#endif - #if defined(CONFIG_MUIC_NOTIFIER) - if (noti_smartdock) - muic_notifier_logically_attach_attached_dev(ATTACHED_DEV_SMARTDOCK_VB_MUIC); +// if (noti_smartdock) +// enqueue_muic_notifier(&(muic_data->muic_cmd_queue), +// NOTI_LOGICALLY_ATTACH, ATTACHED_DEV_SMARTDOCK_VB_MUIC); if (logically_notify) - muic_notifier_logically_attach_attached_dev(new_dev); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), + NOTI_LOGICALLY_ATTACH, new_dev); else - muic_notifier_attach_attached_dev(new_dev); + enqueue_muic_notifier(&(muic_data->muic_cmd_queue), + NOTI_ATTACH, new_dev); #endif /* CONFIG_MUIC_NOTIFIER */ +#if defined(CONFIG_HV_MUIC_MAX77833_AFC) + if (muic_data->pdata->afc_disable) + pr_info("%s:%s AFC Disable(%d) by USER!\n", MUIC_DEV_NAME, + __func__, muic_data->pdata->afc_disable); + else { + if (new_dev == ATTACHED_DEV_TA_MUIC) { + max77833_muic_set_afc_ready(muic_data, true); + max77833_muic_hv_fchv_enable(muic_data, MPING_5TIMES, 0xff); + } + } +#endif + +out: + return ret; + out_without_noti: muic_data->attached_dev = new_dev; -out: + return ret; } static bool muic_check_vps_adc - (const struct max77833_muic_vps_data *tmp_vps, u8 adc) -{ - bool ret = false; - - if (tmp_vps->adc == adc) { - ret = true; - goto out; - } - - if (tmp_vps->adc == ADC_219) { - switch(adc) { - case ADC_CEA936ATYPE1_CHG: - case ADC_JIG_USB_OFF: - ret = true; - goto out; - break; - default: - break; - } + (const struct max77833_muic_vps_data *tmp_vps, u8 adc) +{ + bool ret = false; + + if (tmp_vps->adc == adc) { + ret = true; + goto out; } - if (tmp_vps->adc == ADC_UNDEFINED) { + if (tmp_vps->adc == MAX77833_ADC_219) { switch(adc) { - case ADC_SEND_END ... ADC_REMOTE_S12: - case ADC_UART_CABLE: - case ADC_AUDIOMODE_W_REMOTE: + case MAX77833_ADC_CEA936ATYPE1_CHG: + case MAX77833_ADC_JIG_USB_OFF: ret = true; goto out; break; @@ -1942,12 +2292,11 @@ static bool muic_check_vps_adc } } -/* - if (tmp_vps->adc == ADC_JIG_UART_OFF_WA) { + if (tmp_vps->adc == MAX77833_ADC_UNDEFINED) { switch(adc) { - case ADC_DESKDOCK: - case ADC_CEA936ATYPE2_CHG: - case ADC_JIG_UART_ON: + case MAX77833_ADC_SEND_END ... MAX77833_ADC_REMOTE_S12: + case MAX77833_ADC_UART_CABLE: + case MAX77833_ADC_AUDIOMODE_W_REMOTE: ret = true; goto out; break; @@ -1955,9 +2304,8 @@ static bool muic_check_vps_adc break; } } -*/ - if (tmp_vps->adc == ADC_DONTCARE) + if (tmp_vps->adc == MAX77833_ADC_DONTCARE) ret = true; out: @@ -2005,10 +2353,10 @@ static bool muic_check_vps_chgtyp if (tmp_vps->chgtyp == CHGTYP_UNOFFICIAL_CHARGER) { switch (chgtyp) { - case CHGTYP_500MA: - case CHGTYP_1A: - ret = true; - goto out; +// case CHGTYP_500MA: +// case CHGTYP_1A: +// ret = true; +// goto out; default: break; } @@ -2019,8 +2367,8 @@ static bool muic_check_vps_chgtyp case CHGTYP_USB: case CHGTYP_CDP: case CHGTYP_DEDICATED_CHARGER: - case CHGTYP_500MA: - case CHGTYP_1A: +// case CHGTYP_500MA: +// case CHGTYP_1A: ret = true; goto out; default: @@ -2041,38 +2389,45 @@ static bool muic_check_vps_chgtyp return ret; } -static bool muic_check_otg_test(struct max77833_muic_data *muic_data) +muic_attached_dev_t max77833_muic_check_new_dev(struct max77833_muic_data *muic_data, int *intr) { - bool ret = false; + const struct max77833_muic_vps_data *tmp_vps; + muic_attached_dev_t new_dev = ATTACHED_DEV_NONE_MUIC; + u8 adc = muic_data->status1 & STATUS1_IDRES_MASK; + u8 chgdetrun = muic_data->status2 & STATUS2_CHGTYPRUN_MASK; + u8 chgtyp = muic_data->status2 & STATUS2_CHGTYP_MASK; + int i; - if (muic_data->is_otg_test) { - if (muic_check_support_dev(muic_data, ATTACHED_DEV_OTG_MUIC)) - ret = true; - else - pr_info("%s:%s Not support 'OTG'\n", MUIC_DEV_NAME, __func__); - } + for (i = 0; i < ARRAY_SIZE(muic_vps_table); i++) { + tmp_vps = &(muic_vps_table[i]); - pr_info("%s:%s [%c]\n", MUIC_DEV_NAME, __func__, ret ? 'T':'F'); + if (!(muic_check_vps_adc(tmp_vps, adc))) + continue; - return ret; -} + if (!(muic_check_vps_chgdetrun(tmp_vps, chgdetrun))) + continue; -static muic_attached_dev_t muic_get_new_dev - (struct max77833_muic_data *muic_data, muic_attached_dev_t new_dev) -{ - muic_attached_dev_t tmp_dev = new_dev; + if (!(muic_check_vps_chgtyp(tmp_vps, chgtyp))) + continue; - if (new_dev == ATTACHED_DEV_JIG_UART_OFF_VB_MUIC) { - if(muic_check_otg_test(muic_data)) - tmp_dev = ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC; - else - tmp_dev = ATTACHED_DEV_JIG_UART_OFF_VB_FG_MUIC; + if (!(muic_check_support_dev(muic_data, tmp_vps->attached_dev))) { + new_dev = ATTACHED_DEV_UNSUPPORTED_ID_MUIC; + *intr = MUIC_INTR_ATTACH; + pr_info("%s:%s unsupported ID\n", MUIC_DEV_NAME, __func__); + break; + } + + pr_info("%s:%s vps table match found at i(%d), %s\n", + MUIC_DEV_NAME, __func__, i, tmp_vps->vps_name); - pr_info("%s:%s new_dev(%d), is_otg_test[%c]\n", MUIC_DEV_NAME, - __func__, tmp_dev, muic_data->is_otg_test ? 'T' : 'F'); + new_dev = tmp_vps->attached_dev; + *intr = MUIC_INTR_ATTACH; + break; } - return tmp_dev; + pr_info("%s:%s %d->%d\n", MUIC_DEV_NAME, __func__, muic_data->attached_dev, new_dev); + + return new_dev; } #if !defined(CONFIG_SEC_FACTORY) @@ -2082,7 +2437,6 @@ static bool is_need_muic_idmode_continuous(muic_attached_dev_t new_dev) switch (new_dev) { case ATTACHED_DEV_SMARTDOCK_MUIC: - case ATTACHED_DEV_SMARTDOCK_VB_MUIC: case ATTACHED_DEV_SMARTDOCK_TA_MUIC: case ATTACHED_DEV_SMARTDOCK_USB_MUIC: ret = true; @@ -2097,33 +2451,30 @@ static bool is_need_muic_idmode_continuous(muic_attached_dev_t new_dev) return ret; } -static bool is_need_muic_idmode_factory_oneshot(struct max77833_muic_data *muic_data) +static bool is_need_muic_idmode_pulse(struct max77833_muic_data *muic_data) { - u8 adc = (muic_data->status1) & STATUS1_IDRES_MASK; + u8 adc = muic_data->status1 & STATUS1_IDRES_MASK; bool ret = false; -// if (adc == ADC_JIG_UART_OFF) -// ret = true; + if (adc == MAX77833_ADC_JIG_UART_OFF) + ret = true; - pr_info("%s:%s id(0x%02x)%c\n", MUIC_DEV_NAME, __func__, adc, + pr_info("%s:%s ID: 0x%02x(%c)\n", MUIC_DEV_NAME, __func__, adc, ret ? 'T' : 'F'); return ret; } -#endif /* !CONFIG_SEC_FACTORY */ +#endif static void max77833_muic_detect_dev(struct max77833_muic_data *muic_data, int irq) { struct i2c_client *i2c = muic_data->i2c; - const struct max77833_muic_vps_data *tmp_vps; muic_attached_dev_t new_dev = ATTACHED_DEV_UNKNOWN_MUIC; int intr = MUIC_INTR_DETACH; u8 status[3]; - u8 hvcontrol[2]; - u8 adc1k, adcerr, adc, vbvolt, chgdetrun, chgtyp; - u8 vdnmon, dpdnvden, mpnack, vbadc; + u8 adc, chgdetrun, chgtyp, sysmsg; int ret; - int i; + bool empty_q = is_empty_muic_cmd_queue(&(muic_data->muic_cmd_queue)); ret = max77833_bulk_read(i2c, MAX77833_MUIC_REG_STATUS1, 3, status); if (ret) { @@ -2134,239 +2485,109 @@ static void max77833_muic_detect_dev(struct max77833_muic_data *muic_data, int i pr_info("%s:%s STATUS1:0x%02x, 2:0x%02x, 3:0x%02x\n", MUIC_DEV_NAME, __func__, status[0], status[1], status[2]); - ret = max77833_bulk_read(i2c, MAX77833_MUIC_REG_HVCONTROL1, 2, hvcontrol); - if (ret) { - pr_err("%s:%s fail to read muic reg(%d)\n", MUIC_DEV_NAME, - __func__, ret); - return; - } - - pr_info("%s:%s HVCONTROL1:0x%02x, 2:0x%02x\n", MUIC_DEV_NAME, __func__, - hvcontrol[0], hvcontrol[1]); - - /* attached status */ muic_data->status1 = status[0]; muic_data->status2 = status[1]; + muic_data->status3 = status[2]; adc = status[0] & STATUS1_IDRES_MASK; - if(adc >= 0x10) adc-= 0x10; chgdetrun = status[1] & STATUS2_CHGTYPRUN_MASK; chgtyp = status[1] & STATUS2_CHGTYP_MASK; + sysmsg = status[2] & STATUS3_SYSMSG_MASK; - mpnack = status[2] & STATUS3_MPNACK_MASK; - vdnmon = status[2] & STATUS3_VDNMON_MASK; - vbadc = status[2] & STATUS3_VBADC_MASK; - dpdnvden = hvcontrol[0] & HVCONTROL1_DPDNVDEN_MASK; - - if (irq == muic_data->irq_mrxrdy) - muic_data->is_mrxrdy = true; - else - muic_data->is_mrxrdy = false; - - pr_info("%s:%s adc1k:0x%x adcerr:0x%x[%c] adc:0x%x vb:0x%x chgdetrun:0x%x" - " chgtyp:0x%x\n", MUIC_DEV_NAME, __func__, adc1k, - adcerr, (muic_data->ignore_adcerr ? 'T' : 'F'), - adc, vbvolt, chgdetrun, chgtyp); - - pr_info("%s:%s vdnmon:0x%x mpnack:0x%x vbadc:0x%x dpdnvden:0x%x\n", - MUIC_DEV_NAME, __func__, vdnmon, mpnack, vbadc, dpdnvden); + pr_info("%s:%s adc:0x%x chgdetrun:0x%x chgtyp:0x%x sysmsg:0x%x\n", + MUIC_DEV_NAME, __func__, adc, chgdetrun, chgtyp, sysmsg); +#ifdef CONFIG_MUIC_MAX77833_SHAKEID_WA /* Workaround for Factory mode. * Abandon adc interrupt of approximately +-100K range * if previous cable status was JIG UART BOOT OFF. */ - if (muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) { - if ((adc == (ADC_JIG_UART_OFF + 1)) || - (adc == (ADC_JIG_UART_OFF - 1))) { - if (!muic_data->is_factory_start || adc != ADC_JIG_UART_ON) { - pr_warn("%s:%s abandon ADC\n", MUIC_DEV_NAME, __func__); + if ((muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_MUIC) || + (muic_data->attached_dev == ATTACHED_DEV_JIG_UART_OFF_VB_MUIC)) { + if ((adc == (MAX77833_ADC_JIG_UART_OFF + 1)) || + (adc == (MAX77833_ADC_JIG_UART_OFF - 1))) { + if (!muic_data->is_factory_start || adc != MAX77833_ADC_JIG_UART_ON) { + pr_warn("%s:%s abandon JIG UART\n", MUIC_DEV_NAME, __func__); return; } } } - - for (i = 0; i < ARRAY_SIZE(muic_vps_table); i++) { - tmp_vps = &(muic_vps_table[i]); - - if (!(muic_check_vps_adc(tmp_vps, adc))) - continue; - - if (!(muic_check_vps_chgdetrun(tmp_vps, chgdetrun))) - continue; - - if (!(muic_check_vps_chgtyp(tmp_vps, chgtyp))) - continue; - - if (!(muic_check_support_dev(muic_data, tmp_vps->attached_dev))) { - if (vbvolt == VB_HIGH) { - new_dev = ATTACHED_DEV_UNSUPPORTED_ID_VB_MUIC; - intr = MUIC_INTR_ATTACH; - pr_info("%s:%s unsupported ID + VB\n", MUIC_DEV_NAME, __func__); - } - break; +#ifdef CONFIG_SEC_FACTORY + /* Workaround for JIG Download issue in Factory mode. */ + if (muic_data->attached_dev == ATTACHED_DEV_JIG_USB_ON_MUIC) { + if (adc == (ADC_JIG_USB_ON - 1)) { + pr_warn("%s:%s abandon JIG USB\n", MUIC_DEV_NAME, __func__); + return; } - - pr_info("%s:%s vps table match found at i(%d), %s\n", - MUIC_DEV_NAME, __func__, i, tmp_vps->vps_name); - - new_dev = tmp_vps->attached_dev; - - /* check a muic device type - JIG_UART_OFF_VB */ - new_dev = muic_get_new_dev(muic_data, new_dev); - - intr = MUIC_INTR_ATTACH; - break; } +#endif +#endif - pr_info("%s:%s %d->%d\n", MUIC_DEV_NAME, __func__, muic_data->attached_dev, - new_dev); + new_dev = max77833_muic_check_new_dev(muic_data, &intr); + if (pass_rev >= MUIC_PASS4) { // For PASS4/Old rev onebinary + pr_info("%s: %s: ADCMODE / PASS4\n",MUIC_DEV_NAME,__func__); #if !defined(CONFIG_SEC_FACTORY) - if (is_need_muic_idmode_continuous(new_dev)) { - /* ADC Mode switch to the Continuous Mode */ - max77833_muic_set_idmode_continuous(muic_data); - } else if (is_need_muic_idmode_factory_oneshot(muic_data)) { - /* ID Mode switch to the Factory One Shot Mode */ - max77833_muic_set_idmode_factory_oneshot(muic_data); - } else { - /* ADC Mode restore to the One Shot Mode */ - max77833_muic_set_idmode_oneshot(muic_data); - } + if (is_need_muic_idmode_continuous(new_dev)) { + /* ADC Mode switch to the Continuous Mode */ + max77833_muic_set_idmode_continuous(muic_data); + } else if (is_need_muic_idmode_pulse(muic_data)) { + /* ID Mode switch to the Pulse Mode */ + max77833_muic_set_idmode_pulse(muic_data); + } else { + /* ADC Mode restore to the One Shot Mode */ + max77833_muic_set_idmode_oneshot(muic_data); + } #endif /* CONFIG_SEC_FACTORY */ + } + else + pr_info("%s: %s: ADCMODE / Not PASS4\n",MUIC_DEV_NAME,__func__); if (intr == MUIC_INTR_ATTACH) { pr_info("%s:%s ATTACHED\n", MUIC_DEV_NAME, __func__); ret = max77833_muic_handle_attach(muic_data, new_dev); if (ret) - pr_err("%s:%s cannot handle attach(%d)\n", MUIC_DEV_NAME, - __func__, ret); + pr_err("%s:%s cannot handle attach(%d)\n", MUIC_DEV_NAME, __func__, ret); } else { pr_info("%s:%s DETACHED\n", MUIC_DEV_NAME, __func__); ret = max77833_muic_handle_detach(muic_data); if (ret) - pr_err("%s:%s cannot handle detach(%d)\n", MUIC_DEV_NAME, - __func__, ret); + pr_err("%s:%s cannot handle detach(%d)\n", MUIC_DEV_NAME, __func__, ret); } - return; -} - -static u8 read_muic_response(struct max77833_muic_data *muic_data, u8 reg) -{ - u8 response; - - max77833_read_reg(muic_data->i2c, reg, &response); - pr_info("%s:%s REG[0x%02x]:0x%02x\n", MUIC_DEV_NAME, __func__, reg, response); + if (empty_q) + max77833_muic_handle_cmd(muic_data, -1); - return response; + return; } -static void max77833_muic_handle_cmd(struct max77833_muic_data *muic_data, int irq) +static irqreturn_t max77833_muic_irq(int irq, void *data) { - struct max77833_muic_command *muic_command = muic_data->muic_command; - u8 opcode = read_muic_response(muic_data, MAX77833_MUIC_REG_DAT_OUT_OP); - u8 data; - - mutex_lock(&muic_command->command_mutex); - if (muic_command->state == STATE_CMD_RESPONSE || - muic_command->state == STATE_CMD_NONE) { - mutex_unlock(&muic_command->command_mutex); - pr_err("%s:%s Not transmit(%d)\n", MUIC_DEV_NAME, __func__, - muic_command->state); - return; - } - mutex_unlock(&muic_command->command_mutex); - - if (muic_command->opcode != opcode) { - pr_err("%s:%s Not correct opcode - 0x%02x!=0x%02x\n", - MUIC_DEV_NAME, __func__, - muic_command->opcode, opcode); - muic_command_reset(muic_data); - return; - } - - switch (opcode) { - case COMMAND_CONFIG_READ: - break; - case COMMAND_CONFIG_WRITE: - break; - case COMMAND_SWITCH_READ: - data = read_muic_response(muic_data, MAX77833_MUIC_REG_DAT_OUT1); - pr_info("%s:%s opcode(0x%02x):data(0x%02x)\n", - MUIC_DEV_NAME, __func__, opcode, data); - - mutex_lock(&muic_command->command_mutex); - if (muic_command->state == STATE_CMD_READ_TRANS_READY_W) { - muic_command->rw_before_val = data; - mutex_unlock(&muic_command->command_mutex); - write_muic_rw_write_command(muic_data); - } else - mutex_unlock(&muic_command->command_mutex); - - break; - case COMMAND_SWITCH_WRITE: - pr_info("%s:%s Write command, opcode(0x%02x)\n", - MUIC_DEV_NAME, __func__, opcode); - break; - case COMMAND_SYSTEM_MSG_READ: - break; - case COMMAND_CHGDET_CONFIG_WRITE: - break; - case COMMAND_ID_MONITOR_CONFIG_READ: - break; - case COMMAND_ID_MONITOR_CONFIG_WRITE: - break; - default : - pr_err("%s:%s Not correct response\n", MUIC_DEV_NAME, __func__); - break; - } - - mutex_lock(&muic_command->command_mutex); - if (muic_command->state != STATE_CMD_READ_TRANS_READY_W) - muic_command->state = STATE_CMD_RESPONSE; - mutex_unlock(&muic_command->command_mutex); -} + struct max77833_muic_data *muic_data = data; -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) -inline static bool is_muic_check_reset(struct max77833_muic_data *muic_data) -{ - bool ret; + pr_info("%s:%s irq:%d\n", MUIC_DEV_NAME, __func__, irq); - mutex_lock(&muic_data->reset_mutex); - if (muic_data->is_muic_reset) - ret = true; + mutex_lock(&muic_data->muic_mutex); + if (muic_data->is_muic_ready == true) + max77833_muic_detect_dev(muic_data, irq); else - ret = false; - mutex_unlock(&muic_data->reset_mutex); - - return ret; -} + pr_info("%s:%s MUIC is not ready, just return\n", MUIC_DEV_NAME, + __func__); + mutex_unlock(&muic_data->muic_mutex); -inline static void set_muic_reset(struct max77833_muic_data *muic_data, bool val) -{ - mutex_lock(&muic_data->reset_mutex); - muic_data->is_muic_reset = val; - mutex_unlock(&muic_data->reset_mutex); + return IRQ_HANDLED; } -#endif -static irqreturn_t max77833_muic_irq(int irq, void *data) +static irqreturn_t max77833_muic_irq_cmd(int irq, void *data) { struct max77833_muic_data *muic_data = data; - pr_info("%s:%s irq:%d\n", MUIC_DEV_NAME, __func__, irq); -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) - if (is_muic_check_reset(muic_data)) { - pr_info("%s:%s is_muic_reset is true, just return\n", - MFD_DEV_NAME, __func__); - return IRQ_HANDLED; - } -#endif + pr_info("%s:%s irq:%d\n", MUIC_DEV_NAME, __func__, irq); mutex_lock(&muic_data->muic_mutex); if (muic_data->is_muic_ready == true) - max77833_muic_detect_dev(muic_data, irq); + max77833_muic_handle_cmd(muic_data, irq); else pr_info("%s:%s MUIC is not ready, just return\n", MUIC_DEV_NAME, __func__); @@ -2375,14 +2596,15 @@ static irqreturn_t max77833_muic_irq(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t max77833_muic_irq_cmd(int irq, void *data) +static irqreturn_t max77833_muic_irq_sysmsg(int irq, void *data) { struct max77833_muic_data *muic_data = data; + pr_info("%s:%s irq:%d\n", MUIC_DEV_NAME, __func__, irq); mutex_lock(&muic_data->muic_mutex); if (muic_data->is_muic_ready == true) - max77833_muic_handle_cmd(muic_data, irq); + max77833_muic_read_sysmsg(muic_data, irq); else pr_info("%s:%s MUIC is not ready, just return\n", MUIC_DEV_NAME, __func__); @@ -2403,15 +2625,26 @@ do { \ } while (0) #define REQUEST_IRQ_CMD(_irq, _dev_id, _name) \ - do { \ - ret = request_threaded_irq(_irq, NULL, max77833_muic_irq_cmd, \ - IRQF_NO_SUSPEND, _name, _dev_id); \ - if (ret < 0) { \ - pr_err("%s:%s Failed to request IRQ #%d: %d\n", \ - MUIC_DEV_NAME, __func__, _irq, ret); \ - _irq = 0; \ - } \ - } while (0) +({ \ + ret = request_threaded_irq(_irq, NULL, max77833_muic_irq_cmd, \ + IRQF_NO_SUSPEND, _name, _dev_id); \ + if (ret < 0) { \ + pr_err("%s:%s Failed to request IRQ #%d: %d\n", \ + MUIC_DEV_NAME, __func__, _irq, ret); \ + _irq = 0; \ + } \ +}) + +#define REQUEST_IRQ_SYSMSG(_irq, _dev_id, _name) \ +({ \ + ret = request_threaded_irq(_irq, NULL, max77833_muic_irq_sysmsg, \ + IRQF_NO_SUSPEND, _name, _dev_id); \ + if (ret < 0) { \ + pr_err("%s:%s Failed to request IRQ #%d: %d\n", \ + MUIC_DEV_NAME, __func__, _irq, ret); \ + _irq = 0; \ + } \ +}) static int max77833_muic_irq_init(struct max77833_muic_data *muic_data) { @@ -2423,22 +2656,22 @@ static int max77833_muic_irq_init(struct max77833_muic_data *muic_data) int irq_base = muic_data->mfd_pdata->irq_base; /* request MUIC IRQ */ - muic_data->irq_idreg = irq_base + MAX77833_MUIC_IRQ_INT3_IDRESINT; - REQUEST_IRQ(muic_data->irq_idreg, muic_data, "muic-idreg"); + muic_data->irq_idres = irq_base + MAX77833_MUIC_IRQ_INT3_IDRES_INT; + REQUEST_IRQ(muic_data->irq_idres, muic_data, "muic-idres"); - muic_data->irq_chgtyp = irq_base + MAX77833_MUIC_IRQ_INT3_CHGTYPINT; + muic_data->irq_chgtyp = irq_base + MAX77833_MUIC_IRQ_INT3_CHGTYP_INT; REQUEST_IRQ(muic_data->irq_chgtyp, muic_data, "muic-chgtyp"); - muic_data->irq_sysmsg = irq_base + MAX77833_MUIC_IRQ_INT3_UICSYSMSGINT; - REQUEST_IRQ(muic_data->irq_sysmsg, muic_data, "muic-sysmsg"); + muic_data->irq_sysmsg = irq_base + MAX77833_MUIC_IRQ_INT3_SYSMSG_INT; + REQUEST_IRQ_SYSMSG(muic_data->irq_sysmsg, muic_data, "muic-sysmsg"); - muic_data->irq_apcmdres = irq_base + MAX77833_MUIC_IRQ_INT3_APCMDRESPINT; + muic_data->irq_apcmdres = irq_base + MAX77833_MUIC_IRQ_INT3_APCMD_RESP_INT; REQUEST_IRQ_CMD(muic_data->irq_apcmdres, muic_data, "muic-apcmdres"); } - pr_info("%s:%s idreg(%d), chgtyp(%d), sysmsg(%d), apcmdres(%d)\n", + pr_info("%s:%s idres(%d), chgtyp(%d), sysmsg(%d), apcmdres(%d)\n", MUIC_DEV_NAME, __func__, - muic_data->irq_idreg, muic_data->irq_chgtyp, + muic_data->irq_idres, muic_data->irq_chgtyp, muic_data->irq_sysmsg, muic_data->irq_apcmdres); return ret; } @@ -2457,22 +2690,12 @@ static void max77833_muic_free_irqs(struct max77833_muic_data *muic_data) pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); /* free MUIC IRQ */ - FREE_IRQ(muic_data->irq_idreg, muic_data, "muic-idreg"); + FREE_IRQ(muic_data->irq_idres, muic_data, "muic-idres"); FREE_IRQ(muic_data->irq_chgtyp, muic_data, "muic-chgtyp"); FREE_IRQ(muic_data->irq_sysmsg, muic_data, "muic-sysmsg"); FREE_IRQ(muic_data->irq_apcmdres, muic_data, "muic-apcmdres"); } -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) -static void max77833_muic_free_reset_irq(struct max77833_muic_data *muic_data) -{ - pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); - - /* free MUIC RESET IRQ */ - FREE_IRQ(muic_data->irq_reset_acokbf, muic_data, "muic-reset-acokbf"); -} -#endif /* CONFIG_MUIC_MAX77833_RESET_WA */ - #define CHECK_GPIO(_gpio, _name) \ do { \ if (!_gpio) { \ @@ -2491,6 +2714,9 @@ static void max77833_muic_init_detect(struct max77833_muic_data *muic_data) mutex_lock(&muic_data->muic_mutex); muic_data->is_muic_ready = true; + if(!is_empty_muic_cmd_queue(&(muic_data->muic_cmd_queue))) + max77833_muic_handle_cmd(muic_data, -2); + max77833_muic_detect_dev(muic_data, -1); mutex_unlock(&muic_data->muic_mutex); @@ -2543,16 +2769,6 @@ static int of_max77833_muic_dt(struct max77833_muic_data *muic_data) i, (muic_data->muic_support_list[i] ? 'T' : 'F')); } - ret = of_property_read_u8(np_muic, "muic,afcmode-tx", &muic_data->tx_data); - if (ret) { - pr_err("%s:%s There is no Property of muic,afcmode-tx\n", - MUIC_DEV_NAME, __func__); - return -EINVAL; - } - - pr_info("%s:%s muic_data->tx_data:0x%02x\n", MUIC_DEV_NAME, __func__, - muic_data->tx_data); - err: of_node_put(np_muic); @@ -2592,22 +2808,19 @@ static int max77833_muic_init_regs(struct max77833_muic_data *muic_data) max77833_muic_clear_interrupt(muic_data); - /* Set ADC debounce time: 25ms */ - max77833_muic_set_adcdbset(muic_data, 2); - + if (pass_rev >= MUIC_PASS4) { // For PASS4/Old rev onebinary + pr_info("%s: %s: init ADCMODE / PASS4\n",MUIC_DEV_NAME,__func__); #if defined(CONFIG_SEC_FACTORY) - /* ADC Mode switch to the Continuous Mode */ -// max77833_muic_set_idmode_continuous(muic_data); + /* ADC Mode switch to the Continuous Mode */ + max77833_muic_set_idmode_continuous(muic_data); #endif /* CONFIG_SEC_FACTORY */ - -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - ret = max77833_afc_muic_irq_init(muic_data); - if (ret < 0) { - pr_err("%s:%s Failed to initialize HV MUIC irq:%d\n", MUIC_DEV_NAME, - __func__, ret); - max77833_hv_muic_free_irqs(muic_data); } -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ + else { + pr_info("%s: %s: init ADCMODE / Not PASS4\n",MUIC_DEV_NAME,__func__); + pr_info("%s:%s ***** Test pulsemode - HE, advanced HW group *****\n", + MUIC_DEV_NAME, __func__); + max77833_muic_set_idmode_pulse(muic_data); + } ret = max77833_muic_irq_init(muic_data); if (ret < 0) { @@ -2619,96 +2832,11 @@ static int max77833_muic_init_regs(struct max77833_muic_data *muic_data) return ret; } -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) -static irqreturn_t muic_reset_irq_thread(int irq, void* data) -{ - struct max77833_muic_data *muic_data = data; - u8 muic_irq_mask[3] = {}; - u8 reset_val = 0x0; - - mutex_lock(&muic_data->muic_mutex); - - pr_info("%s:%s irq:%d\n", MUIC_DEV_NAME, __func__, irq); - - /* MUIC INT1 ~ INT3 MASK register check */ - max77833_bulk_read(muic_data->i2c, MAX77833_MUIC_REG_INTMASK1, 3, - muic_irq_mask); - - if ((reset_val == muic_irq_mask[0]) - && (reset_val == muic_irq_mask[1]) - && (reset_val == muic_irq_mask[2])) { - pr_warn("%s:%s MUIC was reset, try re-write MUIC registers\n", - MUIC_DEV_NAME, __func__); - - set_muic_reset(muic_data, true); - - max77833_muic_handle_detach(muic_data); - -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_hv_muic_remove_wo_free_irq(muic_data); - max77833_hv_muic_reset_hvcontrol_reg(muic_data); -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - mutex_unlock(&muic_data->muic_mutex); - -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_hv_muic_free_irqs(muic_data); -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - max77833_muic_free_irqs(muic_data); - - mutex_lock(&muic_data->muic_mutex); - max77833_muic_init_regs(muic_data); - - set_muic_reset(muic_data, false); - } else { - pr_info("%s:%s MUIC was not reset, just return\n", MUIC_DEV_NAME, - __func__); - } - - mutex_unlock(&muic_data->muic_mutex); - - return IRQ_HANDLED; -} - -static int max77833_muic_reset_irq_init(struct max77833_muic_data *muic_data) -{ - int irq_reset_base = sec_pmic_get_irq_base(); - int ret = 0; - - if (irq_reset_base > 0) { - muic_data->irq_reset_acokbf = irq_reset_base + S2MPS13_IRQ_ACOKBF; - - ret = request_threaded_irq(muic_data->irq_reset_acokbf, NULL, - muic_reset_irq_thread, 0, "muic-reset-acokbf", - muic_data); - if (ret) { - pr_err("%s:%s Failed to request, pmic IRQ %d [%d]\n", - MUIC_DEV_NAME, __func__, muic_data->irq_reset_acokbf, - ret); - muic_data->irq_reset_acokbf = 0; - goto out; - } - } else { - pr_err("%s:%s cannot find reset IRQ base(%d)\n", MUIC_DEV_NAME, - __func__, irq_reset_base); - muic_data->irq_reset_acokbf = 0; - ret = -EINVAL; - goto out; - } - - pr_info("%s:%s reset_acokbf(%d)\n", MUIC_DEV_NAME, __func__, - muic_data->irq_reset_acokbf); - -out: - return ret; -} -#endif - static int max77833_muic_probe(struct platform_device *pdev) { struct max77833_dev *max77833 = dev_get_drvdata(pdev->dev.parent); struct max77833_platform_data *mfd_pdata = dev_get_platdata(max77833->dev); struct max77833_muic_data *muic_data; - struct max77833_muic_command *muic_command; int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); @@ -2720,13 +2848,6 @@ static int max77833_muic_probe(struct platform_device *pdev) goto err_return; } - muic_command = kzalloc(sizeof(struct max77833_muic_command), GFP_KERNEL); - if (!muic_command) { - pr_err("%s: failed to allocate driver command data\n", __func__); - ret = -ENOMEM; - goto err_return_free_data; - } - if (!mfd_pdata) { pr_err("%s: failed to get max77833 mfd platform data\n", __func__); ret = -ENOMEM; @@ -2739,19 +2860,12 @@ static int max77833_muic_probe(struct platform_device *pdev) pr_err("%s:%s not found muic dt! ret[%d]\n", MUIC_DEV_NAME, __func__, ret); } -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - ret = of_max77833_hv_muic_dt(muic_data); - if (ret < 0) { - pr_err("%s:%s not found muic dt! ret[%d]\n", MUIC_DEV_NAME, __func__, ret); - } -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - #endif /* CONFIG_OF */ muic_data->dev = &pdev->dev; mutex_init(&muic_data->muic_mutex); mutex_init(&muic_data->reset_mutex); - mutex_init(&muic_command->command_mutex); +// mutex_init(&muic_data->muic_cmd_queue.command_mutex); muic_data->i2c = max77833->muic; muic_data->mfd_pdata = mfd_pdata; muic_data->pdata = &muic_pdata; @@ -2759,17 +2873,17 @@ static int max77833_muic_probe(struct platform_device *pdev) muic_data->is_muic_ready = false; muic_data->is_otg_test = false; muic_data->is_factory_start = false; - muic_data->muic_command = muic_command; -// max77833_muic_set_afc_ready(muic_data, false); //CIS - muic_data->afc_count = 0; -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) - set_muic_reset(muic_data, false); -#endif + max77833_muic_set_afc_ready(muic_data, false); + muic_data->adcmode = MAX77833_MUIC_IDMODE_NONE; - muic_command_reset(muic_data); + muic_data->muic_cmd_queue.front = NULL; + muic_data->muic_cmd_queue.rear = NULL; platform_set_drvdata(pdev, muic_data); + // For PASS4/Old rev onebinary + pass_rev = max77833->pmic_rev; + if (muic_data->pdata->init_gpio_cb) { ret = muic_data->pdata->init_gpio_cb(get_switch_sel()); if (ret) { @@ -2799,34 +2913,11 @@ static int max77833_muic_probe(struct platform_device *pdev) goto fail_init_irq; } -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_hv_muic_initialize(muic_data); -#endif - -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) - ret = max77833_muic_reset_irq_init(muic_data); - if (ret < 0) { - pr_err("%s:%s Failed to initialize MUIC RESET irq:%d\n", - MUIC_DEV_NAME, __func__, ret); - } -#endif - mutex_unlock(&muic_data->muic_mutex); -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - /* initial check dpdnvden before cable detection */ - max77833_hv_muic_init_check_dpdnvden(muic_data); -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - /* initial cable detection */ max77833_muic_init_detect(muic_data); -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - /* initial hv cable detection */ - if (muic_data->is_afc_muic_ready) - max77833_hv_muic_init_detect(muic_data); -#endif - return 0; fail_init_irq: @@ -2839,10 +2930,8 @@ static int max77833_muic_probe(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); mutex_destroy(&muic_data->muic_mutex); mutex_destroy(&muic_data->reset_mutex); - mutex_destroy(&muic_data->muic_command->command_mutex); +// mutex_destroy(&muic_data->muic_cmd_queue.command_mutex); err_kfree: - kfree(muic_command); -err_return_free_data: kfree(muic_data); err_return: return ret; @@ -2857,13 +2946,6 @@ static int max77833_muic_remove(struct platform_device *pdev) if (muic_data) { pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_hv_muic_remove(muic_data); -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) - max77833_muic_free_reset_irq(muic_data); -#endif max77833_muic_free_irqs(muic_data); if (muic_data->pdata->cleanup_switch_dev_cb) @@ -2872,8 +2954,7 @@ static int max77833_muic_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); mutex_destroy(&muic_data->muic_mutex); mutex_destroy(&muic_data->reset_mutex); - mutex_destroy(&muic_data->muic_command->command_mutex); - kfree(muic_data->muic_command); +// mutex_destroy(&muic_data->muic_cmd_queue.command_mutex); kfree(muic_data); } @@ -2885,8 +2966,6 @@ void max77833_muic_shutdown(struct device *dev) struct max77833_muic_data *muic_data = dev_get_drvdata(dev); struct i2c_client *i2c; struct max77833_dev *max77833; - int ret; - u8 val; pr_info("%s:%s +\n", MUIC_DEV_NAME, __func__); @@ -2897,13 +2976,6 @@ void max77833_muic_shutdown(struct device *dev) goto out; } -#if defined(CONFIG_HV_MUIC_MAX77833_AFC) - max77833_hv_muic_remove(muic_data); -#endif /* CONFIG_HV_MUIC_MAX77833_AFC */ - -#if defined(CONFIG_MUIC_MAX77833_RESET_WA) - max77833_muic_free_reset_irq(muic_data); -#endif max77833_muic_free_irqs(muic_data); i2c = muic_data->i2c; @@ -2917,20 +2989,13 @@ void max77833_muic_shutdown(struct device *dev) pr_info("%s:%s max77833->i2c_lock.count.counter=%d\n", MUIC_DEV_NAME, __func__, max77833->i2c_lock.count.counter); - ret = max77833_read_reg(i2c, MAX77833_MUIC_REG_CTRL3, &val); - if (ret < 0) - pr_err("%s:%s fail to update reg\n", MUIC_DEV_NAME, __func__); - - pr_info("%s:%s CTRL3: 0x%02x\n", MUIC_DEV_NAME, __func__, val); - out_cleanup: if (muic_data->pdata && muic_data->pdata->cleanup_switch_dev_cb) muic_data->pdata->cleanup_switch_dev_cb(); mutex_destroy(&muic_data->muic_mutex); mutex_destroy(&muic_data->reset_mutex); - mutex_destroy(&muic_data->muic_command->command_mutex); - kfree(muic_data->muic_command); +// mutex_destroy(&muic_data->muic_cmd_queue.command_mutex); kfree(muic_data); out: @@ -2962,5 +3027,5 @@ static void __exit max77833_muic_exit(void) module_exit(max77833_muic_exit); MODULE_DESCRIPTION("Maxim MAX77833 MUIC driver"); -MODULE_AUTHOR(""); +MODULE_AUTHOR(""); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 821c83a4e781..bc72cecab45a 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -55,12 +55,15 @@ obj-$(CONFIG_WL_TI) += ti/ obj-$(CONFIG_MWIFIEX) += mwifiex/ +ifneq ($(CONFIG_BCM4359),) +obj-$(CONFIG_BCM4359) += bcmdhd4359/ +obj-$(CONFIG_MACH_UNIVERSAL7420) += bcmdhd4359/dhd_custom_memprealloc.o +obj-$(CONFIG_MACH_UNIVERSAL7420) += bcmdhd4359/dhd_custom_exynos.o +else obj-$(CONFIG_BCM4358) += bcmdhd4358/ - -ifneq ($(CONFIG_BCM4358),) obj-$(CONFIG_MACH_UNIVERSAL7420) += bcmdhd4358/dhd_custom_memprealloc.o obj-$(CONFIG_MACH_UNIVERSAL7420) += bcmdhd4358/dhd_custom_exynos.o -endif # CONFIG_BCM4358 +endif obj-$(CONFIG_BRCMFMAC) += brcm80211/ obj-$(CONFIG_BRCMSMAC) += brcm80211/ diff --git a/drivers/net/wireless/bcmdhd4358/Kconfig b/drivers/net/wireless/bcmdhd4358/Kconfig index b9170c3f6889..918932145382 100644 --- a/drivers/net/wireless/bcmdhd4358/Kconfig +++ b/drivers/net/wireless/bcmdhd4358/Kconfig @@ -54,6 +54,13 @@ config BCM4358 This module adds support for wireless adapters based on Broadcom 4358 chipset. +config BCM4358_A3 + tristate "Broadcom 4358 wireless cards support" + depends on BROADCOM_WIFI + ---help--- + This module adds support for wireless adapters based on + Broadcom 4358 chipset. + config BCM43241 tristate "Broadcom 43241 wireless cards support" depends on BROADCOM_WIFI diff --git a/drivers/net/wireless/bcmdhd4358/Makefile b/drivers/net/wireless/bcmdhd4358/Makefile index b9fe7c26b7ec..1e27ff3c3338 100644 --- a/drivers/net/wireless/bcmdhd4358/Makefile +++ b/drivers/net/wireless/bcmdhd4358/Makefile @@ -94,6 +94,7 @@ DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 DHDCFLAGS += -DROAM_AP_ENV_DETECTION DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND +DHDCFLAGS += -DDHD_LOSSLESS_ROAMING # CCX ifeq ($(CONFIG_BRCM_CCX),y) @@ -273,7 +274,7 @@ endif DHDCFLAGS += -DWLTDLS DHDCFLAGS += -DWLFBT DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DWLAIBSS -DWLAIBSS_PS DHDCFLAGS += -DSUPPORT_LTECX DHDCFLAGS += -DSUPPORT_2G_VHT DHDCFLAGS += -DSUPPORT_WL_TXPOWER diff --git a/drivers/net/wireless/bcmdhd4358/Makefile.kk b/drivers/net/wireless/bcmdhd4358/Makefile.kk index 81df5ee6d9fc..9de0912ed224 100644 --- a/drivers/net/wireless/bcmdhd4358/Makefile.kk +++ b/drivers/net/wireless/bcmdhd4358/Makefile.kk @@ -94,6 +94,7 @@ DHDCFLAGS += -DCUSTOM_TDLS_RSSI_THRESHOLD_LOW=-85 DHDCFLAGS += -DROAM_AP_ENV_DETECTION DHDCFLAGS += -DROAM_ENABLE -DROAM_CHANNEL_CACHE -DROAM_API DHDCFLAGS += -DENABLE_FW_ROAM_SUSPEND +DHDCFLAGS += -DDHD_LOSSLESS_ROAMING # CCX ifeq ($(CONFIG_BRCM_CCX),y) @@ -258,7 +259,7 @@ endif DHDCFLAGS += -DWLTDLS DHDCFLAGS += -DWLFBT DHDCFLAGS += -DDHD_ENABLE_LPC - DHDCFLAGS += -DWLAIBSS + DHDCFLAGS += -DWLAIBSS -DWLAIBSS_PS DHDCFLAGS += -DSUPPORT_LTECX DHDCFLAGS += -DSUPPORT_2G_VHT DHDCFLAGS += -DSUPPORT_WL_TXPOWER diff --git a/drivers/net/wireless/bcmdhd4358/bcmutils.c b/drivers/net/wireless/bcmdhd4358/bcmutils.c index 6dacaf58f561..917eade4597f 100644 --- a/drivers/net/wireless/bcmdhd4358/bcmutils.c +++ b/drivers/net/wireless/bcmdhd4358/bcmutils.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmutils.c 530648 2015-01-30 12:57:32Z $ + * $Id: bcmutils.c 547738 2015-04-09 09:22:30Z $ */ #include @@ -794,6 +794,11 @@ pktsetprio(void *pkt, bool update_vtag) evh->vlan_tag = hton16(vlan_tag); rc |= PKTPRIO_UPD; } +#ifdef DHD_LOSSLESS_ROAMING + } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { + priority = PRIO_8021D_NC; + rc = PKTPRIO_DSCP; +#endif /* DHD_LOSSLESS_ROAMING */ } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { uint8 *ip_body = pktdata + sizeof(struct ether_header); diff --git a/drivers/net/wireless/bcmdhd4358/dhd.h b/drivers/net/wireless/bcmdhd4358/dhd.h index 884acd74281e..00d78181bbed 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd.h +++ b/drivers/net/wireless/bcmdhd4358/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 539956 2015-03-10 12:20:45Z $ + * $Id: dhd.h 547738 2015-04-09 09:22:30Z $ */ /**************** @@ -468,6 +468,9 @@ typedef struct dhd_pub { #ifdef WLTDLS uint32 tdls_mode; #endif +#ifdef DHD_LOSSLESS_ROAMING + uint8 dequeue_prec_map; +#endif } dhd_pub_t; #if defined(CUSTOMER_HW4) #define MAX_RESCHED_CNT 600 diff --git a/drivers/net/wireless/bcmdhd4358/dhd_custom_sec.c b/drivers/net/wireless/bcmdhd4358/dhd_custom_sec.c index 61aca8ec617a..b32db221586b 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_custom_sec.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_custom_sec.c @@ -39,6 +39,10 @@ #include #include +#if defined(OTP_WRITE_ON) +#include +#endif /* OTP_WRITE_ON */ + struct dhd_info; extern int _dhd_set_mac_address(struct dhd_info *dhd, int ifidx, struct ether_addr *addr); @@ -298,7 +302,7 @@ const struct cntry_locales_custom translate_custom_table[] = { {"KR", "KR", 48}, #endif {"RU", "RU", 13}, - {"UA", "UM", 3}, + {"UA", "UA", 8}, {"GT", "GT", 1}, {"MN", "MN", 1}, {"NI", "NI", 2}, @@ -312,6 +316,7 @@ const struct cntry_locales_custom translate_custom_table[] = { {"LY", "LI", 4}, {"BO", "NG", 0}, {"UM", "PR", 38}, + {"CU", "US", 0}, #endif /* default ccode/regrev */ }; @@ -1358,4 +1363,137 @@ int dhd_check_module_b85a(dhd_pub_t *dhd) return ret; } #endif /* defined(SUPPORT_MULTIPLE_MODULE_CIS) && defined(USE_CID_CHECK) */ + +#ifdef OTP_WRITE_ON +#define htod32(i) (i) + +int dhd_write_otp(dhd_pub_t *dhd) +{ + int ret; + char buf[CIS_BUF_SIZE] = {0}; + char *bufp; + const char *otp_vars; + int otp_header_size; + int otp_vars_size; + uint32 len = 0; + uint chipid; + cis_rw_t cish; + char *cisp, *cisdata; + int max = 0; + bool sta_mode = FALSE; + cis_rw_t *cish_r = (cis_rw_t *)&buf[8]; + struct file *fp; + mm_segment_t old_fs; + loff_t pos = 0; + + chipid = dhd_bus_chip_id(dhd); + + if (chipid == BCM43569_CHIP_ID) { + otp_vars = BCM4358A3_otp_vars; + otp_vars_size = sizeof(BCM4358A3_otp_vars); + otp_header_size = BCM4358A3_OTP_HEADER_SIZE; + } else { + DHD_ERROR(("%s: can't find OTP header for chip\n", __FUNCTION__)); + return BCME_ERROR; + } + + cish_r->source = 0; + cish_r->byteoff = 0; + cish_r->nbytes = sizeof(buf); + + strcpy(buf, "cisdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), 0, 0); + if (ret < 0) { + DHD_ERROR(("[WIFI_SEC] %s: CIS reading failed, ret=%d\n", + __FUNCTION__, ret)); + sta_mode = TRUE; + goto exit; + } + + max = otp_header_size; + if (memcmp(&buf[12], otp_vars, otp_header_size) == 0) { + DHD_ERROR(("%s:OTP already was written\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: OTP length: %d bytes \n", __FUNCTION__, otp_vars_size)); + + max = sizeof(buf); + bufp = buf; + memset(buf, 0, sizeof(buf)); + strcpy(bufp, "ciswrite"); + bufp += strlen("ciswrite") + 1; + cisp = bufp; + cisdata = cisp + sizeof(cish); + + cish.source = htod32(0); + + memcpy(cisdata, (char *)otp_vars, otp_vars_size); + len = otp_vars_size; + + cish.byteoff = htod32(0); + cish.nbytes = htod32(len); + memcpy(cisp, (char*)&cish, sizeof(cish)); + + ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, + (cisp - buf) + sizeof(cish) + len, TRUE, 0); + if (ret) { + DHD_ERROR(("%s: Fail to write otp, ret = %d \n", __FUNCTION__, ret)); + } else { + DHD_ERROR(("Success to write otp \n")); + } + } + /* check or create .otp.info */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + + fp = filp_open("/data/.otp.info", O_RDONLY, 0); + if (IS_ERR(fp)) { + + /* prepare .otp.info data through reading OTP from chip */ + memset(buf, 0, sizeof(buf)); + strcpy(buf, "cisdump"); + ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), 0, 0); + if (ret < 0) { + DHD_ERROR(("[WIFI_SEC] %s: CIS reading failed After writing ret=%d\n", + __FUNCTION__, ret)); + goto exit; + } + + /* create .otp.info */ + fp = filp_open("/data/.otp.info", O_RDWR|O_CREAT, 0666); + if (!fp) { + DHD_ERROR(("%s:(MFG mode) file create error\n", __FUNCTION__)); + return BCME_ERROR; + } + + /* Write buf to file */ + fp->f_op->write(fp, buf, CIS_BUF_SIZE, &pos); + } + + if (fp) { + filp_close(fp, current->files); + } + DHD_ERROR(("%s: .otp.info is created or existing already\n", __FUNCTION__)); + /* restore previous address limit */ + set_fs(old_fs); + +exit: + if (sta_mode == TRUE) { + fp = filp_open("/data/.otp.info", O_RDONLY, 0); + if (IS_ERR(fp)) { + DHD_ERROR(("%s: file open error.\n", __FUNCTION__)); + return BCME_ERROR; + } + + ret = kernel_read(fp, 0, buf, CIS_BUF_SIZE); + + if (memcmp(&buf[12], otp_vars, otp_header_size) == 0) { + DHD_ERROR(("%s: OTP checking -> OK\n", __FUNCTION__)); + } else { + DHD_ERROR(("%s: OTP checking -> OTP has ERROR.\n", __FUNCTION__)); + } + filp_close(fp, current->files); + } + return ret; +} +#endif /* OTP_WRITE_ON */ #endif /* CUSTOMER_HW4 */ diff --git a/drivers/net/wireless/bcmdhd4358/dhd_custom_sec_otpbinary.h b/drivers/net/wireless/bcmdhd4358/dhd_custom_sec_otpbinary.h new file mode 100644 index 000000000000..837c560ad638 --- /dev/null +++ b/drivers/net/wireless/bcmdhd4358/dhd_custom_sec_otpbinary.h @@ -0,0 +1,93 @@ +/* + * customer HW 4 dependant file + * OTP header for device of COB && PCIE type + * + * Copyright (C) 1999-2015, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: dhd_custom_sec_otpbinary.h 556072 2015-05-12 12:32:05Z $ + * + */ + +#define BCM4358A3_OTP_HEADER_SIZE 128 + +static const char BCM4358A3_otp_vars[] = { + 0x0f, 0x38, 0x00, 0x38, 0x52, 0x07, 0xe4, 0x14, + 0x1c, 0x02, 0x7e, 0x1b, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd4, 0x00, 0x3c, 0x25, 0x64, 0x21, 0x03, 0x32, + 0x5f, 0x3e, 0x05, 0x96, 0x2f, 0x9f, 0xb6, 0x79, + 0x80, 0x80, 0x03, 0x0c, 0x00, 0x40, 0x40, 0x32, + 0x00, 0x5f, 0xf4, 0x4d, 0x90, 0x80, 0x00, 0xee, + 0x30, 0x86, 0x80, 0x01, 0x2b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0a, 0x03, + 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xec, 0x43, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, + 0xf5, 0x3f, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff +}; diff --git a/drivers/net/wireless/bcmdhd4358/dhd_flowring.c b/drivers/net/wireless/bcmdhd4358/dhd_flowring.c index 51c0cd69fab9..ceb13aff7bf1 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_flowring.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_flowring.c @@ -57,7 +57,11 @@ int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); #define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) #define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) +#ifdef DHD_LOSSLESS_ROAMING +const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 7 }; +#else const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; +#endif const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; int BCMFASTPATH @@ -163,7 +167,7 @@ dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) { uint32 idx; uint32 flow_ring_table_sz; - uint32 if_flow_lkup_sz; + uint32 if_flow_lkup_sz = 0; void * flowid_allocator; flow_ring_table_t *flow_ring_table; if_flow_lkup_t *if_flow_lkup = NULL; @@ -231,7 +235,9 @@ dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP; bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - +#ifdef DHD_LOSSLESS_ROAMING + dhdp->dequeue_prec_map = ALLPRIO; +#endif /* Now populate into dhd pub */ DHD_FLOWID_LOCK(lock, flags); dhdp->num_flow_rings = num_flow_rings; @@ -246,7 +252,7 @@ dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) fail: /* Destruct the per interface flow lkup table */ - if (dhdp->if_flow_lkup != NULL) { + if (if_flow_lkup != NULL) { DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz); } if (flow_ring_table != NULL) { diff --git a/drivers/net/wireless/bcmdhd4358/dhd_linux.c b/drivers/net/wireless/bcmdhd4358/dhd_linux.c index 74f7d40781dd..e643457fcb55 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_linux.c @@ -3,13 +3,13 @@ * Basically selected code segments from usb-cdc.c and usb-rndis.c * * Copyright (C) 1999-2015, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -17,12 +17,12 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 541327 2015-03-16 11:08:22Z $ + * $Id: dhd_linux.c 552793 2015-04-28 04:09:31Z $ */ #include @@ -207,7 +207,7 @@ extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); -#endif +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) MODULE_LICENSE("GPL v2"); #endif /* LinuxVer */ @@ -267,6 +267,9 @@ extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); #endif #ifdef CUSTOMER_HW4 +#ifdef OTP_WRITE_ON +extern int dhd_write_otp(dhd_pub_t *dhd); +#endif /* OTP_WRITE_ON */ #ifdef READ_MACADDR extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); #endif @@ -2376,7 +2379,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) #if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) if (bus_wakeup(dhdp) == TRUE) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + DHD_ERROR(("%s : pcie is still in suspend state!! bus_wakeup\n", __FUNCTION__)); PKTFREE(dhdp->osh, pktbuf, TRUE); return -EBUSY; } @@ -2384,7 +2387,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) #ifdef PCIE_FULL_DONGLE if (dhdp->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + DHD_ERROR(("%s : pcie is still in suspend state!! busstate\n", __FUNCTION__)); PKTFREE(dhdp->osh, pktbuf, TRUE); return -EBUSY; } @@ -2527,7 +2530,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); #if defined(DHD_USE_IDLECOUNT) && defined(BCMPCIE) if (bus_wakeup(&dhd->pub) == TRUE) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + DHD_ERROR(("%s : pcie is still in suspend state!! bus_wakeup\n", __FUNCTION__)); dev_kfree_skb(skb); ifp = DHD_DEV_IFP(net); ifp->stats.tx_dropped++; @@ -2540,7 +2543,7 @@ dhd_start_xmit(struct sk_buff *skb, struct net_device *net) dhd->pub.tx_in_progress = TRUE; #ifdef PCIE_FULL_DONGLE if (dhd->pub.busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); + DHD_ERROR(("%s : pcie is still in suspend state!! busstate\n", __FUNCTION__)); dev_kfree_skb(skb); ifp = DHD_DEV_IFP(net); ifp->stats.tx_dropped++; @@ -2713,6 +2716,13 @@ dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) ASSERT(dhd); +#ifdef DHD_LOSSLESS_ROAMING + /* block flowcontrol during roaming */ + if ((dhdp->dequeue_prec_map == 1 << PRIO_8021D_NC) && state == ON) { + return; + } +#endif + if (ifidx == ALL_INTERFACES) { /* Flow control on all active interfaces */ dhdp->txoff = state; @@ -3276,6 +3286,11 @@ static void dhd_watchdog(ulong data) return; } + if (dhd->pub.busstate == DHD_BUS_SUSPEND) { + DHD_ERROR(("%s wd while suspend in progress \n", __FUNCTION__)); + return; + } + if (dhd->thr_wdt_ctl.thr_pid >= 0) { up(&dhd->thr_wdt_ctl.sema); return; @@ -3894,7 +3909,7 @@ static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); return FALSE; } -#endif +#endif #ifdef CONFIG_MACH_UNIVERSAL5433 /* old revision does not send hang message */ @@ -4299,7 +4314,7 @@ dhd_stop(struct net_device *net) } } #endif /* SUPPORT_DEEP_SLEEP */ -#endif +#endif dhd->pub.hang_was_sent = 0; @@ -4387,7 +4402,9 @@ dhd_open(struct net_device *net) DHD_PERIM_LOCK(&dhd->pub); dhd->pub.dongle_trap_occured = 0; dhd->pub.hang_was_sent = 0; - +#ifdef DHD_LOSSLESS_ROAMING + dhd->pub.dequeue_prec_map = ALLPRIO; +#endif #if !defined(WL_CFG80211) /* * Force start if ifconfig_up gets called before START command @@ -4401,7 +4418,7 @@ dhd_open(struct net_device *net) goto exit; } -#endif +#endif ifidx = dhd_net2idx(dhd, net); DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); @@ -4455,7 +4472,7 @@ dhd_open(struct net_device *net) dhd_fix_cpu_freq(dhd); } #endif /* defined(CUSTOMER_HW4) && defined(FIX_CPU_MIN_CLOCK) */ -#endif +#endif if (dhd->pub.busstate != DHD_BUS_DATA) { @@ -4967,7 +4984,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) /* will implement get_ids for DBUS later */ #if defined(BCMSDIO) dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); -#endif +#endif adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); /* Allocate primary dhd_info */ @@ -5517,6 +5534,10 @@ dhd_bus_start(dhd_pub_t *dhdp) } #endif /* ARP_OFFLOAD_SUPPORT */ +#if defined(OTP_WRITE_ON) && defined(CUSTOMER_HW4) + dhd_write_otp(dhdp); +#endif /* OTP_WRITE_ON && CUSTOMER_HW4 */ + DHD_PERIM_UNLOCK(dhdp); return 0; } @@ -5687,7 +5708,7 @@ void dhd_tdls_update_peer_info(struct net_device *dev, bool connect, uint8 *da) } } #endif /* PCIE_FULL_DONGLE */ -#endif +#endif bool dhd_is_concurrent_mode(dhd_pub_t *dhd) { @@ -5757,7 +5778,7 @@ dhd_get_concurrent_capabilites(dhd_pub_t *dhd) } return 0; } -#endif +#endif @@ -5804,7 +5825,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint32 hostreorder = 1; #endif /* DISABLE_11N */ #endif /* PROP_TXSTATUS */ -#endif +#endif #ifdef PCIE_FULL_DONGLE uint32 wl_ap_isolate; #endif /* PCIE_FULL_DONGLE */ @@ -6080,7 +6101,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #else (void)concurrent_mode; -#endif +#endif } DHD_ERROR(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", @@ -6217,7 +6238,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (ap_fw_loaded == TRUE) { dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); } -#endif +#endif #if defined(KEEP_ALIVE) { @@ -6226,7 +6247,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(SOFTAP) if (ap_fw_loaded == FALSE) -#endif +#endif if (!(dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { if ((res = dhd_keep_alive_onoff(dhd)) < 0) @@ -6478,6 +6499,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) } #if defined(CUSTOMER_HW4) && defined(WES_SUPPORT) else { +#ifdef WLAIBSS + if (!(dhd->op_mode & DHD_FLAG_IBSS_MODE)) +#endif /* WLAIBSS */ setbit(eventmask, WLC_E_ACTION_FRAME_RX); } #endif /* WES_SUPPORT */ @@ -6486,7 +6510,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_AIBSS_TXFAIL); #endif /* WLAIBSS */ setbit(eventmask, WLC_E_TRACE); - +#ifdef DHD_LOSSLESS_ROAMING + setbit(eventmask, WLC_E_ROAM_PREP); +#endif /* Write updated Event mask */ bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { @@ -6553,7 +6579,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) if (arpoe && !ap_fw_loaded) { #else if (arpoe) { -#endif +#endif dhd_arp_offload_enable(dhd, TRUE); dhd_arp_offload_set(dhd, dhd_arp_mode); } else { @@ -7168,6 +7194,9 @@ dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) up(&dhd_registration_sem); #endif if (!dhd_download_fw_on_driverload) { +#ifdef WL_CFG80211 + wl_terminate_event_handler(); +#endif /* WL_CFG80211 */ dhd_net_bus_devreset(net, TRUE); #ifdef BCMLXSDMMC dhd_net_bus_suspend(net); @@ -8883,7 +8912,7 @@ int dhd_net_set_fw_path(struct net_device *dev, char *fw) DHD_INFO(("GOT STA FIRMWARE\n")); ap_fw_loaded = FALSE; } -#endif +#endif return 0; } @@ -9252,6 +9281,11 @@ int dhd_os_check_wakelock(dhd_pub_t *pub) int dhd_os_check_wakelock_all(dhd_pub_t *pub) { +#ifdef CONFIG_HAS_WAKELOCK + int l1, l2, l3, l4; + int l5 = 0; + int c, lock_active; +#endif /* CONFIG_HAS_WAKELOCK */ #if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ KERNEL_VERSION(2, 6, 36))) dhd_info_t *dhd; @@ -9259,24 +9293,32 @@ int dhd_os_check_wakelock_all(dhd_pub_t *pub) if (!pub) return 0; dhd = (dhd_info_t *)(pub->info); + if (!dhd) { + return 0; + } #endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ #ifdef CONFIG_HAS_WAKELOCK - /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ - if (dhd && (wake_lock_active(&dhd->wl_wifi) || - wake_lock_active(&dhd->wl_wdwake) || - wake_lock_active(&dhd->wl_rxwake) || + c = dhd->wakelock_counter; + l1 = wake_lock_active(&dhd->wl_wifi); + l2 = wake_lock_active(&dhd->wl_wdwake); + l3 = wake_lock_active(&dhd->wl_rxwake); + l4 = wake_lock_active(&dhd->wl_ctrlwake); #ifdef BCMPCIE_OOB_HOST_WAKE - wake_lock_active(&dhd->wl_intrwake) || + l5 = wake_lock_active(&dhd->wl_intrwake); #endif /* BCMPCIE_OOB_HOST_WAKE */ - wake_lock_active(&dhd->wl_ctrlwake))) { - DHD_ERROR(("%s wakelock_counter %d\n", __FUNCTION__, dhd->wakelock_counter)); + lock_active = (l1 || l2 || l3 || l4 || l5); + + /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ + if (dhd && lock_active) { + DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d ctl-%d intr-%d\n", + __FUNCTION__, c, l1, l2, l3, l4, l5)); return 1; } #elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) return 1; -#endif +#endif /* CONFIG_HAS_WAKELOCK */ return 0; } @@ -10269,7 +10311,8 @@ int argos_status_notifier_wifi_cb(struct notifier_block *notifier, DHD_ERROR(("DHD: %s: RPS_Set fail, Core=%d Offline\n", __FUNCTION__, RPS_CPUS_WLAN_CORE_ID)); } - } else if (speed <= RPS_TPUT_THRESHOLD && argos_rps_ctrl_data.wlan_primary_netdev != NULL) { + } else if (speed <= RPS_TPUT_THRESHOLD && argos_rps_ctrl_data.wlan_primary_netdev != NULL && + argos_rps_ctrl_data.argos_rps_cpus_enabled == 1) { custom_rps_map_clear(argos_rps_ctrl_data.wlan_primary_netdev->_rx); DHD_ERROR(("DHD: %s: Clear RPS_CPUs, speed=%ld\n", __FUNCTION__, speed)); argos_rps_ctrl_data.argos_rps_cpus_enabled = 0; diff --git a/drivers/net/wireless/bcmdhd4358/dhd_pcie.c b/drivers/net/wireless/bcmdhd4358/dhd_pcie.c index 53a2d08905fd..b1dcff59f38a 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_pcie.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_pcie.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_pcie.c 539248 2015-03-06 04:50:53Z $ + * $Id: dhd_pcie.c 553525 2015-04-30 03:25:33Z $ */ @@ -61,6 +61,7 @@ #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ #define MAX_NVRAMBUF_SIZE 6144 /* max nvram buf size */ +#define MAX_WKLK_IDLE_CHECK 3 /* times wake_lock checked before deciding not to suspend */ #define ARMCR4REG_BANKIDX (0x40/sizeof(uint32)) #define ARMCR4REG_BANKPDA (0x4C/sizeof(uint32)) @@ -120,6 +121,10 @@ static int dhdpcie_download_code_array(dhd_bus_t *bus); +#if defined(CUSTOMER_HW4) && defined(CONFIG_MACH_UNIVERSAL7420) +extern void exynos_pcie_register_dump(int ch_num); +#endif /* CUSTOMER_HW4 && CONFIG_MACH_UNIVERSAL7420 */ + #define PCI_VENDOR_ID_BROADCOM 0x14e4 /* IOVar table */ @@ -1743,6 +1748,10 @@ dhdpcie_mem_dump(dhd_bus_t *bus) int read_size = 0; /* Read size of each iteration */ uint8 *buf = NULL, *databuf = NULL; +#if defined(CUSTOMER_HW4) && defined(CONFIG_MACH_UNIVERSAL7420) + exynos_pcie_register_dump(1); +#endif /* CUSTOMER_HW4 && CONFIG_MACH_UNIVERSAL7420 */ + /* Get full mem size */ size = bus->ramsize; #ifdef USE_STATIC_MEMDUMP @@ -1866,7 +1875,9 @@ dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs) { flow_ring_node_t *flow_ring_node; int ret = BCME_OK; - +#ifdef DHD_LOSSLESS_ROAMING + dhd_pub_t *dhdp = bus->dhd; +#endif DHD_INFO(("%s: flow_id is %d\n", __FUNCTION__, flow_id)); /* ASSERT on flow_id */ if (flow_id >= bus->max_sub_queues) { @@ -1887,6 +1898,14 @@ dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs) flow_ring_node = DHD_FLOW_RING(bus->dhd, flow_id); +#ifdef DHD_LOSSLESS_ROAMING + if ((dhdp->dequeue_prec_map & (1 << flow_ring_node->flow_info.tid)) == 0) { + DHD_INFO(("%s: tid %d is not in precedence map. block scheduling\n", + __FUNCTION__, flow_ring_node->flow_info.tid)); + return BCME_OK; + } +#endif /* DHD_LOSSLESS_ROAMING */ + { unsigned long flags; void *txp = NULL; @@ -3401,6 +3420,9 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) return BCME_OK; if (state) { + int idle_retry = 0; + int active; + bus->wait_for_d3_ack = 0; bus->suspended = TRUE; DHD_GENERAL_LOCK(bus->dhd, flags); @@ -3419,9 +3441,18 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) timeleft = dhd_os_d3ack_wait(bus->dhd, &bus->wait_for_d3_ack, &pending); dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); DHD_OS_WAKE_LOCK_RESTORE(bus->dhd); + + /* To allow threads that got pre-empted to complete. + */ + while ((active = dhd_os_check_wakelock_all(bus->dhd)) && + (idle_retry < MAX_WKLK_IDLE_CHECK)) { + msleep(1); + idle_retry++; + } + if (bus->wait_for_d3_ack) { /* Got D3 Ack. Suspend the bus */ - if (!bus->force_suspend && dhd_os_check_wakelock_all(bus->dhd)) { + if (!bus->force_suspend && active) { DHD_ERROR(("Suspend failed because of wakelock\n")); #ifdef DHD_USE_IDLECOUNT if (bus->host_suspend == TRUE) { @@ -3446,6 +3477,9 @@ dhdpcie_bus_suspend(struct dhd_bus *bus, bool state) #endif /* DHD_USE_IDLECOUNT */ } bus->dhd->d3ackcnt_timeout = 0; +#if defined(BCMPCIE_OOB_HOST_WAKE) + dhdpcie_oob_intr_set(bus, TRUE); +#endif /* BCMPCIE_OOB_HOST_WAKE */ } else if (timeleft == 0) { bus->dhd->d3ackcnt_timeout++; DHD_ERROR(("%s: resumed on timeout for D3 ACK d3_inform_cnt %d \n", diff --git a/drivers/net/wireless/bcmdhd4358/dhd_pcie_linux.c b/drivers/net/wireless/bcmdhd4358/dhd_pcie_linux.c index d631c9a0a64f..d5993e2ac9b5 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_pcie_linux.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_pcie_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_pcie_linux.c 531053 2015-02-02 07:23:56Z $ + * $Id: dhd_pcie_linux.c 545664 2015-04-01 09:11:26Z $ */ @@ -1122,6 +1122,7 @@ static irqreturn_t wlan_oob_irq(int irq, void *data) dhd_bus_t *bus; DHD_TRACE(("%s: IRQ Triggered\n", __FUNCTION__)); bus = (dhd_bus_t *)data; + dhdpcie_oob_intr_set(bus, FALSE); if (bus->dhd->up && bus->suspended) { DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(bus->dhd, OOB_WAKE_LOCK_TIMEOUT); } diff --git a/drivers/net/wireless/bcmdhd4358/dhd_sdio.c b/drivers/net/wireless/bcmdhd4358/dhd_sdio.c index ba2e201ec8b6..d3ac1317af84 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd4358/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 531053 2015-02-02 07:23:56Z $ + * $Id: dhd_sdio.c 547738 2015-04-09 09:22:30Z $ */ #include @@ -2225,6 +2225,9 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) osh = dhd->osh; tx_prec_map = ~bus->flowcontrol; +#ifdef DHD_LOSSLESS_ROAMING + tx_prec_map &= dhd->dequeue_prec_map; +#endif for (cnt = 0; (cnt < maxframes) && DATAOK(bus);) { int i; int num_pkt = 1; @@ -2238,7 +2241,7 @@ dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) } num_pkt = MIN(num_pkt, pktq_mlen(&bus->txq, tx_prec_map)); for (i = 0; i < num_pkt; i++) { - pkts[i] = pktq_mdeq(&bus->txq, ~bus->flowcontrol, &prec_out); + pkts[i] = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); if (!pkts[i]) { DHD_ERROR(("%s: pktq_mlen non-zero when no pkt\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcmdhd4358/dhd_sec_feature.h b/drivers/net/wireless/bcmdhd4358/dhd_sec_feature.h index 476a9c5dad1c..c5d49218b522 100644 --- a/drivers/net/wireless/bcmdhd4358/dhd_sec_feature.h +++ b/drivers/net/wireless/bcmdhd4358/dhd_sec_feature.h @@ -68,6 +68,10 @@ #define READ_MACADDR #endif /* CONFIG_WIFI_BROADCOM_COB */ +#if defined(CONFIG_WIFI_BROADCOM_COB) && defined(CONFIG_BCMDHD_PCIE) +#define OTP_WRITE_ON +#endif /* CONFIG_WIFI_BROADCOM_COB && CONFIG_BCMDHD_PCIE */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)) && (defined(CONFIG_BCM4334) || \ defined(CONFIG_BCM4334_MODULE)) #define RXFRAME_THREAD diff --git a/drivers/net/wireless/bcmdhd4358/document/ChangeHistory.txt b/drivers/net/wireless/bcmdhd4358/document/ChangeHistory.txt index ef6ed9514116..28c470f4d1b0 100644 --- a/drivers/net/wireless/bcmdhd4358/document/ChangeHistory.txt +++ b/drivers/net/wireless/bcmdhd4358/document/ChangeHistory.txt @@ -1,8 +1,46 @@ -BCM4358 DHD 1.47.23 for Android Lollipop Zero Project +BCM4358 DHD 1.47.30 for Android Lollipop Zero Project Notes: - Must sync up DHD and FW for additional message to eliminate spurious D0 interrupt. . additional message to eliminate spurious D0 interrupt is enabled from DHD 1.47.20 and FW 7.112.20.5/7.112.20.2(IBSS) +2015.5.13 - DHD 1.47.30 +Others + - CSP:906264 Added Private command for Preferred Band selection + - CSP:906786 OTP value updated for BCM4356G + - CSP:912978 Fixed P2P NOA wpa_cli private command + - CSP:916567 Fixed prevent null check issue + - CSP:916865 Added PCIe register dump code for further debugging + - CSP:917184 Added WAR for avoid P2P GO beacon delay issue + - Fixed Flow ring remained issue for IBSS mode + (This patch should be sync up with IBSS FW 7.112.17.7 or higher version) + + +2015.4.28 - DHD 1.47.29 +Others + - CSP:906786 Added Runtime OTP header writing and checking code for PCIE COB type module + - CSP:914492 Fixed Ch 12/13 AP connection failed issue with UA country code + (This patch should be sync up same FW patch - CSP:914492) + - CSP:914563 Fixed FT & CCKM roaming issues when Lossless Roaming in enabled + - Added Exceptional Kconfig for Galaxy Tab2 platform + + +2015.4.21 - DHD 1.47.27 +Kernel Panic + - CSP:805589 Prevent running wl_event_handler while HANG is occurred + +Others + - CSP:799948 Added Lossless Roaming feature + - CSP:888565, 897513 Added OOB intr wakelock handling on system suspend for DPM device timeout issue + - CSP:910874 Added Additional wl_event_handler terminate code + - CSP:911242 Fixed Prevent null check issue + - CSP:911733 Filter out Action Frame Rx Packet for IBSS mode + - Added BCM4356G Chip ID support code + - Enabled Power save for IBSS mode + - Fixed adding interworking IE to dongle on driver + - Fixed Coverity issue - Uninitialized scalar variable + - Fixed suspend failure issue due to wake lock + + 2015.3.19 - DHD 1.47.23 Kernel Panic - CSP:858385 Fixed synchronization problem when called the wl_cfg80211_remove_if() function diff --git a/drivers/net/wireless/bcmdhd4358/include/bcmdevs.h b/drivers/net/wireless/bcmdhd4358/include/bcmdevs.h index 5bc1620bf0b6..36d26abd6b8d 100644 --- a/drivers/net/wireless/bcmdhd4358/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd4358/include/bcmdevs.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmdevs.h 484136 2014-06-12 04:36:10Z $ + * $Id: bcmdevs.h 548451 2015-04-13 08:20:45Z $ */ #ifndef _BCMDEVS_H @@ -364,6 +364,7 @@ #define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */ #define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */ #define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */ +#define BCM43562_CHIP_ID 0xAA2A /* 43562 chipcommon chipid */ #define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */ #define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */ #define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */ diff --git a/drivers/net/wireless/bcmdhd4358/include/epivers.h b/drivers/net/wireless/bcmdhd4358/include/epivers.h index d234fa8734fc..7faa63c040fd 100644 --- a/drivers/net/wireless/bcmdhd4358/include/epivers.h +++ b/drivers/net/wireless/bcmdhd4358/include/epivers.h @@ -30,19 +30,19 @@ #define EPI_MINOR_VERSION 47 -#define EPI_RC_NUMBER 23 +#define EPI_RC_NUMBER 30 #define EPI_INCREMENTAL_NUMBER 0 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 1, 47, 23, 0 +#define EPI_VERSION 1, 47, 30, 0 -#define EPI_VERSION_NUM 0x012f1700 +#define EPI_VERSION_NUM 0x012f1e00 -#define EPI_VERSION_DEV 1.47.23 +#define EPI_VERSION_DEV 1.47.30 /* Driver Version String, ASCII, 32 chars max */ -#define EPI_VERSION_STR "1.47.23 (r_DPM)" +#define EPI_VERSION_STR "1.47.30 (r)" #endif /* _epivers_h_ */ diff --git a/drivers/net/wireless/bcmdhd4358/include/linux_osl.h b/drivers/net/wireless/bcmdhd4358/include/linux_osl.h index 66d2efbe0ae5..023bc0fa8c50 100644 --- a/drivers/net/wireless/bcmdhd4358/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd4358/include/linux_osl.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.h 539666 2015-03-09 07:22:56Z $ + * $Id: linux_osl.h 547511 2015-04-08 21:22:26Z $ */ #ifndef _linux_osl_h_ @@ -385,8 +385,9 @@ extern int osl_error(int bcmerror); #define PKTID(skb) ({BCM_REFERENCE(skb); 0;}) #define PKTSETID(skb, id) ({BCM_REFERENCE(skb); BCM_REFERENCE(id);}) #define PKTSHRINK(osh, m) ({BCM_REFERENCE(osh); m;}) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) -#define PKTORPHAN(skb) ({BCM_REFERENCE(skb); 0;}) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) && defined(TSQ_MULTIPLIER) +#define PKTORPHAN(skb) osl_pkt_orphan_partial(skb) +extern void osl_pkt_orphan_partial(struct sk_buff *skb); #else #define PKTORPHAN(skb) ({BCM_REFERENCE(skb); 0;}) #endif /* LINUX VERSION >= 3.6 */ diff --git a/drivers/net/wireless/bcmdhd4358/linux_osl.c b/drivers/net/wireless/bcmdhd4358/linux_osl.c index 856e542d4a22..c7cc78504217 100644 --- a/drivers/net/wireless/bcmdhd4358/linux_osl.c +++ b/drivers/net/wireless/bcmdhd4358/linux_osl.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.c 541343 2015-03-16 12:51:01Z $ + * $Id: linux_osl.c 551293 2015-04-22 22:58:36Z $ */ #define LINUX_PORT @@ -1624,3 +1624,38 @@ osl_is_flag_set(osl_t *osh, uint32 mask) { return (osh->flags & mask); } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) && defined(TSQ_MULTIPLIER) +#include +#include +void +osl_pkt_orphan_partial(struct sk_buff *skb) +{ + uint32 fraction; + static void *p_tcp_wfree = NULL; + + if (!skb->destructor || skb->destructor == sock_wfree) + return; + + if (unlikely(!p_tcp_wfree)) { + char sym[KSYM_SYMBOL_LEN]; + sprint_symbol(sym, (unsigned long)skb->destructor); + sym[9] = 0; + if (!strcmp(sym, "tcp_wfree")) + p_tcp_wfree = skb->destructor; + else + return; + } + + if (unlikely(skb->destructor != p_tcp_wfree || !skb->sk)) + return; + + /* abstract a certain portion of skb truesize from the socket + * sk_wmem_alloc to allow more skb can be allocated for this + * socket for better cusion meeting WiFi device requirement + */ + fraction = skb->truesize * (TSQ_MULTIPLIER - 1) / TSQ_MULTIPLIER; + skb->truesize -= fraction; + atomic_sub(fraction, &skb->sk->sk_wmem_alloc); + } +#endif /* LINUX_VERSION >= 3.6.0 && TSQ_MULTIPLIER */ diff --git a/drivers/net/wireless/bcmdhd4358/siutils.c b/drivers/net/wireless/bcmdhd4358/siutils.c index 0482c12026c8..d205bf80cc92 100644 --- a/drivers/net/wireless/bcmdhd4358/siutils.c +++ b/drivers/net/wireless/bcmdhd4358/siutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c 517572 2014-11-26 01:56:32Z $ + * $Id: siutils.c 548451 2015-04-13 08:20:45Z $ */ #include @@ -440,6 +440,7 @@ si_chipid_fixup(si_t *sih) ASSERT(sii->chipnew == 0); switch (sih->chip) { + case BCM43562_CHIP_ID: case BCM43570_CHIP_ID: case BCM4358_CHIP_ID: sii->chipnew = sih->chip; /* save it */ @@ -565,7 +566,7 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, if ((sih->chip == BCM4358_CHIP_ID) || (sih->chip == BCM43570_CHIP_ID) || - (sih->chip == BCM4358_CHIP_ID)) { + (sih->chip == BCM43562_CHIP_ID)) { si_chipid_fixup(sih); } diff --git a/drivers/net/wireless/bcmdhd4358/wl_android.c b/drivers/net/wireless/bcmdhd4358/wl_android.c index cf202a1963fe..cc3908fb0d5c 100644 --- a/drivers/net/wireless/bcmdhd4358/wl_android.c +++ b/drivers/net/wireless/bcmdhd4358/wl_android.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_android.c 530216 2015-01-29 12:54:42Z $ + * $Id: wl_android.c 554114 2015-05-04 12:45:04Z $ */ #include @@ -181,6 +181,7 @@ #define CMD_SETSCANNPROBES "SETSCANNPROBES" #define CMD_GETDFSSCANMODE "GETDFSSCANMODE" #define CMD_SETDFSSCANMODE "SETDFSSCANMODE" +#define CMD_SETJOINPREFER "SETJOINPREFER" #define CMD_SENDACTIONFRAME "SENDACTIONFRAME" #define CMD_REASSOC "REASSOC" @@ -1008,6 +1009,44 @@ int wl_android_set_scan_dfs_channel_mode(struct net_device *dev, char *command, return 0; } +#define JOINPREFFER_BUF_SIZE 12 + +static int +wl_android_set_join_prefer(struct net_device *dev, char *command, int total_len) +{ + int error = BCME_OK; + char smbuf[WLC_IOCTL_SMLEN]; + uint8 buf[JOINPREFFER_BUF_SIZE]; + char *pcmd; + int total_len_left; + int i; + char hex[2]; + + pcmd = command + strlen(CMD_SETJOINPREFER) + 1; + total_len_left = strlen(pcmd); + + memset(buf, 0, sizeof(buf)); + + if (total_len_left != JOINPREFFER_BUF_SIZE << 1) { + DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__)); + return BCME_ERROR; + } + + /* Store the MSB first, as required by join_pref */ + for (i = 0; i < JOINPREFFER_BUF_SIZE; i++) { + hex[0] = *pcmd++; + hex[1] = *pcmd++; + buf[i] = (uint8)simple_strtoul(hex, NULL, 16); + } + + prhex("join pref", (uint8 *)buf, JOINPREFFER_BUF_SIZE); + error = wldev_iovar_setbuf(dev, "join_pref", buf, JOINPREFFER_BUF_SIZE, + smbuf, sizeof(smbuf), NULL); + if (error) { + DHD_ERROR(("Failed to set join_pref, error = %d\n", error)); + } + return error; +} int wl_android_send_action_frame(struct net_device *dev, char *command, int total_len) { @@ -3623,6 +3662,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_android_set_scan_dfs_channel_mode(net, command, priv_cmd.total_len); } + else if (strnicmp(command, CMD_SETJOINPREFER, strlen(CMD_SETJOINPREFER)) == 0) { + bytes_written = wl_android_set_join_prefer(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_GETWESMODE, strlen(CMD_GETWESMODE)) == 0) { bytes_written = wl_android_get_wes_mode(net, command, priv_cmd.total_len); } diff --git a/drivers/net/wireless/bcmdhd4358/wl_cfg80211.c b/drivers/net/wireless/bcmdhd4358/wl_cfg80211.c index 254698fb3afd..cca3400fa4d3 100644 --- a/drivers/net/wireless/bcmdhd4358/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd4358/wl_cfg80211.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.c 541592 2015-03-17 06:43:29Z $ + * $Id: wl_cfg80211.c 556026 2015-05-12 06:55:40Z $ */ /* */ #include @@ -73,6 +73,10 @@ #include #endif +#ifdef BCMPCIE +#include +#endif + #ifdef WL11U #if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF) #error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \ @@ -482,6 +486,11 @@ static s32 wl_notify_gscan_event(struct bcm_cfg80211 *wl, bcm_struct_cfgdev *cfg #endif /* GSCAN_SUPPORT */ static s32 wl_notifier_change_state(struct bcm_cfg80211 *cfg, struct net_info *_net_info, enum wl_status state, bool set); +#ifdef DHD_LOSSLESS_ROAMING +static s32 wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, + bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data); +static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg); +#endif /* DHD_LOSSLESS_ROAMING */ #ifdef WLTDLS static s32 wl_tdls_event_handler(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, @@ -549,6 +558,8 @@ static int wl_cfg80211_get_rsn_capa(bcm_tlv_t *wpa2ie, u8* capa); bcm_tlv_t * wl_cfg80211_find_interworking_ie(u8 *parse, u32 len); static s32 +wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx); +static s32 wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, uint8 ie_id, uint8 *data, uint8 data_len); #endif /* WL11U */ @@ -2677,25 +2688,17 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, #ifdef WL11U if ((interworking_ie = wl_cfg80211_find_interworking_ie( (u8 *)request->ie, request->ie_len)) != NULL) { - err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, + if ((err = wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, VNDR_IE_CUSTOM_FLAG, interworking_ie->id, - interworking_ie->data, interworking_ie->len); - - if (unlikely(err)) { + interworking_ie->data, + interworking_ie->len)) != BCME_OK) { goto scan_out; } - } else if (cfg->iw_ie_len != 0) { + } else if (cfg->wl11u) { /* we have to clear IW IE and disable gratuitous APR */ - wl_cfg80211_add_iw_ie(cfg, ndev, bssidx, - VNDR_IE_CUSTOM_FLAG, - DOT11_MNG_INTERWORKING_ID, - 0, 0); - - wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, - bssidx); + wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx); + wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0, bssidx); cfg->wl11u = FALSE; - cfg->iw_ie_len = 0; - memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); /* we don't care about error */ } #endif /* WL11U */ @@ -3978,8 +3981,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) break; #endif default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR(("invalid akm suites ( 0x%x)\n", + sme->crypto.akm_suites[0])); return -EINVAL; } } else if (val & (WPA2_AUTH_PSK | @@ -4018,8 +4021,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) break; #endif default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR(("invalid akm suites ( 0x%x)\n", + sme->crypto.akm_suites[0])); return -EINVAL; } } @@ -4033,8 +4036,8 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) val = WAPI_AUTH_PSK; break; default: - WL_ERR(("invalid cipher group (%d)\n", - sme->crypto.cipher_group)); + WL_ERR(("invalid akm suites (0x%x)\n", + sme->crypto.akm_suites[0])); return -EINVAL; } } @@ -4562,6 +4565,15 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, act = true; } #endif /* ESCAN_RESULT_PATCH */ + +#ifdef CUSTOMER_HW4 + if ((wl_get_drv_status(cfg, CONNECTING, dev) || + wl_get_drv_status(cfg, CONNECTED, dev)) && act) { + WL_ERR(("Wait for complete of connecting \n")); + OSL_SLEEP(200); + } +#endif /* CUSTOMER_HW4 */ + if (act) { /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. @@ -7581,6 +7593,9 @@ wl_cfg80211_change_station( struct station_parameters *params) { int err; +#ifdef DHD_LOSSLESS_ROAMING + struct bcm_cfg80211 *cfg = wiphy_priv(wiphy); +#endif WL_DBG(("SCB_AUTHORIZE mac_addr:"MACDBG" sta_flags_mask:0x%x " "sta_flags_set:0x%x iface:%s \n", MAC2STRDBG(mac), @@ -7602,6 +7617,9 @@ wl_cfg80211_change_station( err = wldev_ioctl(dev, WLC_SCB_AUTHORIZE, mac, ETH_ALEN, true); if (err) WL_ERR(("WLC_SCB_AUTHORIZE error (%d)\n", err)); +#ifdef DHD_LOSSLESS_ROAMING + wl_del_roam_timeout(cfg); +#endif return err; } #endif /* WL_SUPPORT_BACKPORTED_KPATCHES || KERNEL_VER >= KERNEL_VERSION(3, 2, 0)) */ @@ -9107,17 +9125,30 @@ wl_notify_connect_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, wl_link_up(cfg); act = true; if (!wl_get_drv_status(cfg, DISCONNECTING, ndev)) { +#ifdef DHD_LOSSLESS_ROAMING + bool is_connected = wl_get_drv_status(cfg, CONNECTED, ndev); +#endif + printk("wl_bss_connect_done succeeded with " MACDBG "\n", MAC2STRDBG((u8*)(&e->addr))); wl_bss_connect_done(cfg, ndev, e, data, true); WL_DBG(("joined in BSS network \"%s\"\n", ((struct wlc_ssid *) wl_read_prof(cfg, ndev, WL_PROF_SSID))->SSID)); +#ifdef DHD_LOSSLESS_ROAMING + if (event == WLC_E_LINK && is_connected && + !cfg->roam_offload) { + wl_bss_roaming_done(cfg, ndev, e, data); + } +#endif /* DHD_LOSSLESS_ROAMING */ } wl_update_prof(cfg, ndev, e, &act, WL_PROF_ACT); wl_update_prof(cfg, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); } else if (wl_is_linkdown(cfg, e)) { +#ifdef DHD_LOSSLESS_ROAMING + wl_del_roam_timeout(cfg); +#endif if (cfg->scan_request) wl_notify_escan_complete(cfg, ndev, true, true); if (wl_get_drv_status(cfg, CONNECTED, ndev)) { @@ -9228,8 +9259,21 @@ wl_notify_aibss_txfail(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, { u32 evt = ntoh32(e->event_type); int ret = -1; - +#ifdef PCIE_FULL_DONGLE + dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); + u32 reason = ntoh32(e->reason); + int hostidx; + hostidx = dhd_ifidx2hostidx(dhd->info, e->ifidx); +#endif if (cfg->aibss_txfail_pid != 0) { +#ifdef PCIE_FULL_DONGLE + if (reason == AIBSS_PEER_FREE) { + WL_INFORM(("Peer freed. Flow rings delete for peer.\n")); + dhd_flow_rings_delete_for_peer(dhd, hostidx, + (void *)&e->addr.octet[0]); + return 0; + } +#endif ret = wl_netlink_send_msg(cfg->aibss_txfail_pid, AIBSS_EVENT_TXFAIL, cfg->aibss_txfail_seq++, (void *)&e->addr, ETHER_ADDR_LEN); } @@ -9273,6 +9317,9 @@ wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, s32 err = 0; u32 event = be32_to_cpu(e->event_type); u32 status = be32_to_cpu(e->status); +#ifdef DHD_LOSSLESS_ROAMING + struct wl_security *sec; +#endif WL_DBG(("Enter \n")); ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); @@ -9292,7 +9339,33 @@ wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, WL_INFORM(("BSSID already updated\n")); return err; } +#ifdef DHD_LOSSLESS_ROAMING + if (cfg->roam_offload) { + wl_bss_roaming_done(cfg, ndev, e, data); + wl_del_roam_timeout(cfg); + } + else { + sec = wl_read_prof(cfg, ndev, WL_PROF_SEC); + /* In order to reduce roaming delay, wl_bss_roaming_done is + * early called with WLC_E_LINK event. It is called from + * here only if WLC_E_LINK event is blocked for specific + * security type. + */ + if (IS_AKM_SUITE_FT(sec)) { + wl_bss_roaming_done(cfg, ndev, e, data); + } + /* Roam timer is deleted mostly from wl_cfg80211_change_station + * after roaming is finished successfully. We need to delete + * the timer from here only for some security types that aren't + * using wl_cfg80211_change_station to authorize SCB + */ + if (IS_AKM_SUITE_FT(sec) || IS_AKM_SUITE_CCKM(sec)) { + wl_del_roam_timeout(cfg); + } + } +#else wl_bss_roaming_done(cfg, ndev, e, data); +#endif /* DHD_LOSSLESS_ROAMING */ memcpy(&cfg->last_roamed_addr, (void *)&e->addr, ETHER_ADDR_LEN); } else { wl_bss_connect_done(cfg, ndev, e, data, true); @@ -9304,6 +9377,25 @@ wl_notify_roaming_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, return err; } +#ifdef DHD_LOSSLESS_ROAMING +static s32 +wl_notify_roam_prep_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, + const wl_event_msg_t *e, void *data) +{ + s32 err = 0; + + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + + dhdp->dequeue_prec_map = 1 << PRIO_8021D_NC; + /* Restore flow control */ + dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); + + mod_timer(&cfg->roam_timeout, jiffies + msecs_to_jiffies(WL_ROAM_TIMEOUT_MS)); + + return err; +} +#endif /* DHD_LOSSLESS_ROAMING */ + #ifdef QOS_MAP_SET /* up range from low to high with up value */ static bool @@ -10660,6 +10752,9 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg) cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status; #endif /* WL_NAN */ cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; +#ifdef DHD_LOSSLESS_ROAMING + cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status; +#endif } #if defined(STATIC_WL_PRIV_STRUCT) @@ -10839,6 +10934,15 @@ static void wl_destroy_event_handler(struct bcm_cfg80211 *cfg) PROC_STOP(&cfg->event_tsk); } +void wl_terminate_event_handler(void) +{ + struct bcm_cfg80211 *cfg = g_bcm_cfg; + + if (cfg) { + wl_destroy_event_handler(cfg); + } +} + static void wl_scan_timeout(unsigned long data) { wl_event_msg_t msg; @@ -10860,6 +10964,31 @@ static void wl_scan_timeout(unsigned long data) #endif /* CUSTOMER_HW4 && DHD_DEBUG */ } +#ifdef DHD_LOSSLESS_ROAMING +static void wl_del_roam_timeout(struct bcm_cfg80211 *cfg) +{ + dhd_pub_t *dhdp = (dhd_pub_t *)(cfg->pub); + + /* restore prec_map to ALLPRIO */ + dhdp->dequeue_prec_map = ALLPRIO; + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } + +} + +static void wl_roam_timeout(unsigned long data) +{ + struct bcm_cfg80211 *cfg = (struct bcm_cfg80211 *)data; + + WL_ERR(("roam timer expired\n")); + + /* restore prec_map to ALLPRIO */ + wl_del_roam_timeout(cfg); +} + +#endif /* DHD_LOSSLESS_ROAMING */ + static s32 wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, unsigned long state, @@ -11714,6 +11843,20 @@ static s32 wl_init_scan(struct bcm_cfg80211 *cfg) return err; } +#ifdef DHD_LOSSLESS_ROAMING +static s32 wl_init_roam_timeout(struct bcm_cfg80211 *cfg) +{ + int err = 0; + + /* Init roam timer */ + init_timer(&cfg->roam_timeout); + cfg->roam_timeout.data = (unsigned long) cfg; + cfg->roam_timeout.function = wl_roam_timeout; + + return err; +} +#endif /* DHD_LOSSLESS_ROAMING */ + static s32 wl_init_priv(struct bcm_cfg80211 *cfg) { struct wiphy *wiphy = bcmcfg_to_wiphy(cfg); @@ -11750,6 +11893,12 @@ static s32 wl_init_priv(struct bcm_cfg80211 *cfg) err = wl_init_scan(cfg); if (err) return err; +#ifdef DHD_LOSSLESS_ROAMING + err = wl_init_roam_timeout(cfg); + if (err) { + return err; + } +#endif /* DHD_LOSSLESS_ROAMING */ wl_init_conf(cfg->conf); wl_init_prof(cfg, ndev); wl_link_down(cfg); @@ -11765,6 +11914,9 @@ static void wl_deinit_priv(struct bcm_cfg80211 *cfg) wl_flush_eq(cfg); wl_link_down(cfg); del_timer_sync(&cfg->scan_timeout); +#ifdef DHD_LOSSLESS_ROAMING + del_timer_sync(&cfg->roam_timeout); +#endif wl_deinit_priv_mem(cfg); if (wl_cfg80211_netdev_notifier_registered) { wl_cfg80211_netdev_notifier_registered = FALSE; @@ -11992,6 +12144,11 @@ void wl_cfg80211_detach(void *para) if (timer_pending(&cfg->scan_timeout)) del_timer_sync(&cfg->scan_timeout); +#ifdef DHD_LOSSLESS_ROAMING + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } +#endif /* DHD_LOSSLESS_ROAMING */ #if defined(WL_CFG80211_P2P_DEV_IF) wl_cfgp2p_del_p2p_disc_if(cfg->p2p_wdev, cfg); @@ -12069,6 +12226,10 @@ static s32 wl_event_handler(void *data) #endif /* WL_CFG80211_P2P_DEV_IF */ } if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { + dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); + if (dhd->busstate == DHD_BUS_DOWN) { + WL_ERR((": BUS is DOWN.\n")); + } else cfg->evt_handler[e->etype] (cfg, cfgdev, &e->emsg, e->edata); } else { WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); @@ -12782,6 +12943,11 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) if (timer_pending(&cfg->scan_timeout)) { del_timer_sync(&cfg->scan_timeout); } +#ifdef DHD_LOSSLESS_ROAMING + if (timer_pending(&cfg->roam_timeout)) { + del_timer_sync(&cfg->roam_timeout); + } +#endif /* DHD_LOSSLESS_ROAMING */ if (cfg->ap_info) { kfree(cfg->ap_info->wpa_ie); @@ -12810,8 +12976,6 @@ static s32 __wl_cfg80211_down(struct bcm_cfg80211 *cfg) /* Clear interworking element. */ if (cfg->wl11u) { cfg->wl11u = FALSE; - cfg->iw_ie_len = 0; - memset(cfg->iw_ie, 0, IW_IES_MAX_BUF_LEN); } #endif /* WL11U */ @@ -13371,8 +13535,11 @@ wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, cfg = g_bcm_cfg; dhdp = (dhd_pub_t *)(cfg->pub); memset(&info, 0, sizeof(tdls_iovar_t)); - if (peer) + if (peer) { memcpy(&info.ea, peer, ETHER_ADDR_LEN); + } else { + return -1; + } switch (oper) { case NL80211_TDLS_DISCOVERY_REQ: /* If the discovery request is broadcast then we need to set @@ -13382,7 +13549,7 @@ wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, info.mode = TDLS_MANUAL_EP_WFD_TPQ; WL_ERR(("%s TDLS TUNNELED PRBOBE REQUEST\n", __FUNCTION__)); } else { - info.mode = TDLS_MANUAL_EP_DISCOVERY; + info.mode = TDLS_MANUAL_EP_DISCOVERY; } break; case NL80211_TDLS_SETUP: @@ -13391,7 +13558,7 @@ wl_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, tdls_auto_mode = false; ret = dhd_tdls_enable(dev, false, tdls_auto_mode, NULL); if (ret < 0) { - return ret; + return ret; } } else { tdls_auto_mode = true; @@ -14071,6 +14238,19 @@ wl_cfg80211_find_interworking_ie(u8 *parse, u32 len) return NULL; } +static s32 +wl_cfg80211_clear_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx) +{ + ie_setbuf_t ie_setbuf; + + WL_DBG(("clear interworking IE\n")); + + ie_setbuf.ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID; + ie_setbuf.ie_buffer.ie_list[0].ie_data.len = 0; + + return wldev_iovar_setbuf_bsscfg(ndev, "ie", &ie_setbuf, sizeof(ie_setbuf), + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); +} static s32 wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bssidx, s32 pktflag, @@ -14079,78 +14259,74 @@ wl_cfg80211_add_iw_ie(struct bcm_cfg80211 *cfg, struct net_device *ndev, s32 bss s32 err = BCME_OK; s32 buf_len; s32 iecount; - ie_setbuf_t *ie_setbuf; + ie_setbuf_t ie_setbuf; + ie_getbuf_t ie_getbufp; + char getbuf[WLC_IOCTL_SMLEN]; - if (ie_id != DOT11_MNG_INTERWORKING_ID) + if (ie_id != DOT11_MNG_INTERWORKING_ID) { + WL_ERR(("unsupported (id=%d)\n", ie_id)); return BCME_UNSUPPORTED; + } + + /* access network options (1 octet) is the mandatory field */ + if (!data || data_len == 0) { + WL_ERR(("wrong interworking IE (len=%d)\n", data_len)); + return BCME_BADARG; + } /* Validate the pktflag parameter */ if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG | VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG | VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG| VNDR_IE_CUSTOM_FLAG))) { - WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag)); - return -1; + WL_ERR(("invalid packet flag 0x%x\n", pktflag)); + return BCME_BADARG; } /* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */ pktflag = htod32(pktflag); buf_len = sizeof(ie_setbuf_t) + data_len - 1; - ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL); - if (!ie_setbuf) { - WL_ERR(("Error allocating buffer for IE\n")); - return -ENOMEM; + ie_getbufp.id = DOT11_MNG_INTERWORKING_ID; + if (wldev_iovar_getbuf_bsscfg(ndev, "ie", (void *)&ie_getbufp, + sizeof(ie_getbufp), getbuf, WLC_IOCTL_SMLEN, bssidx, &cfg->ioctl_buf_sync) + == BCME_OK) { + if (!memcmp(&getbuf[TLV_HDR_LEN], data, data_len)) { + WL_DBG(("skip to set interworking IE\n")); + return BCME_OK; } - - if (cfg->iw_ie_len == data_len && !memcmp(cfg->iw_ie, data, data_len)) { - WL_ERR(("Previous IW IE is equals to current IE\n")); - err = BCME_OK; - goto exit; } - strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1); - ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0'; + strncpy(ie_setbuf.cmd, "add", VNDR_IE_CMD_LEN - 1); + ie_setbuf.cmd[VNDR_IE_CMD_LEN - 1] = '\0'; /* Buffer contains only 1 IE */ iecount = htod32(1); - memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int)); - memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); + memcpy((void *)&ie_setbuf.ie_buffer.iecount, &iecount, sizeof(int)); + memcpy((void *)&ie_setbuf.ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32)); /* Now, add the IE to the buffer */ - ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id; + ie_setbuf.ie_buffer.ie_list[0].ie_data.id = DOT11_MNG_INTERWORKING_ID; /* if already set with previous values, delete it first */ - if (cfg->iw_ie_len != 0) { - WL_DBG(("Different IW_IE was already set. clear first\n")); - - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0; - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); - - if (err != BCME_OK) - goto exit; + if (cfg->wl11u) { + if ((err = wl_cfg80211_clear_iw_ie(cfg, ndev, bssidx)) != BCME_OK) { + return err; + } } - ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len; - memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len); - - err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len, - cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync); + ie_setbuf.ie_buffer.ie_list[0].ie_data.len = data_len; + memcpy((uchar *)&ie_setbuf.ie_buffer.ie_list[0].ie_data.data[0], data, data_len); - if (err == BCME_OK) { - memcpy(cfg->iw_ie, data, data_len); - cfg->iw_ie_len = data_len; + if ((err = wldev_iovar_setbuf_bsscfg(ndev, "ie", &ie_setbuf, buf_len, + cfg->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &cfg->ioctl_buf_sync)) + == BCME_OK) { + WL_DBG(("set interworking IE\n")); cfg->wl11u = TRUE; - err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx); } -exit: - if (ie_setbuf) - kfree(ie_setbuf); return err; } #endif /* WL11U */ diff --git a/drivers/net/wireless/bcmdhd4358/wl_cfg80211.h b/drivers/net/wireless/bcmdhd4358/wl_cfg80211.h index 78ff6b8f6b68..fe00c2d02cab 100644 --- a/drivers/net/wireless/bcmdhd4358/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd4358/wl_cfg80211.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfg80211.h 539956 2015-03-10 12:20:45Z $ + * $Id: wl_cfg80211.h 556026 2015-05-12 06:55:40Z $ */ /** @@ -182,6 +182,9 @@ do { \ #define WL_CHANNEL_SYNC_RETRY 5 #define WL_INVALID -1 +#ifdef DHD_LOSSLESS_ROAMING +#define WL_ROAM_TIMEOUT_MS 1000 /* Roam timeout */ +#endif /* Bring down SCB Timeout to 20secs from 60secs default */ #ifndef WL_SCB_TIMEOUT #define WL_SCB_TIMEOUT 20 @@ -198,6 +201,7 @@ do { \ #define AIBSS_INITIAL_MIN_BCN_DUR 500 #define AIBSS_MIN_BCN_DUR 5000 #define AIBSS_BCN_FLOOD_DUR 5000 +#define AIBSS_PEER_FREE 3 #endif /* WLAIBSS */ /* driver status */ @@ -613,8 +617,6 @@ struct bcm_cfg80211 { wlc_ssid_t hostapd_ssid; #ifdef WL11U bool wl11u; - u8 iw_ie[IW_IES_MAX_BUF_LEN]; - u32 iw_ie_len; #endif /* WL11U */ bool sched_scan_running; /* scheduled scan req status */ #ifdef WL_SCHED_SCAN @@ -664,6 +666,9 @@ struct bcm_cfg80211 { u32 tdls_mgmt_frame_len; s32 tdls_mgmt_freq; #endif /* WLTDLS */ +#ifdef DHD_LOSSLESS_ROAMING + struct timer_list roam_timeout; /* Timer for catch roam timeout */ +#endif }; @@ -934,6 +939,28 @@ wl_get_netinfo_by_netdev(struct bcm_cfg80211 *cfg, struct net_device *ndev) ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ (!_sme->crypto.n_ciphers_pairwise) && \ (!_sme->crypto.cipher_group)) + +#ifdef WLFBT +#if defined(WLAN_AKM_SUITE_FT_8021X) && defined(WLAN_AKM_SUITE_FT_PSK) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X || \ + sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) +#elif defined(WLAN_AKM_SUITE_FT_8021X) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_8021X) +#elif defined(WLAN_AKM_SUITE_FT_PSK) +#define IS_AKM_SUITE_FT(sec) (sec->wpa_auth == WLAN_AKM_SUITE_FT_PSK) +#else +#define IS_AKM_SUITE_FT(sec) false +#endif /* WLAN_AKM_SUITE_FT_8021X && WLAN_AKM_SUITE_FT_PSK */ +#else +#define IS_AKM_SUITE_FT(sec) false +#endif /* WLFBT */ + +#ifdef BCMCCX +#define IS_AKM_SUITE_CCKM(sec) (sec->wpa_auth == WLAN_AKM_SUITE_CCKM) +#else +#define IS_AKM_SUITE_CCKM(sec) false +#endif /* BCMCCX */ + extern s32 wl_cfg80211_attach(struct net_device *ndev, void *context); extern s32 wl_cfg80211_attach_post(struct net_device *ndev); extern void wl_cfg80211_detach(void *para); @@ -1006,6 +1033,7 @@ extern s32 wl_cfg80211_apply_eventbuffer(struct net_device *ndev, struct bcm_cfg80211 *cfg, wl_eventmsg_buf_t *ev); extern void get_primary_mac(struct bcm_cfg80211 *cfg, struct ether_addr *mac); extern void wl_cfg80211_update_power_mode(struct net_device *dev); +extern void wl_terminate_event_handler(void); #define SCAN_BUF_CNT 2 #define SCAN_BUF_NEXT 1 #define WL_SCANTYPE_LEGACY 0x1 diff --git a/drivers/net/wireless/bcmdhd4358/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd4358/wl_cfgp2p.c index 04a8b3fffd90..531c2e79a5f0 100644 --- a/drivers/net/wireless/bcmdhd4358/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd4358/wl_cfgp2p.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_cfgp2p.c 529169 2015-01-26 12:05:27Z $ + * $Id: wl_cfgp2p.c 552891 2015-04-28 08:36:40Z $ * */ #include @@ -2156,7 +2156,7 @@ wl_cfgp2p_set_p2p_noa(struct bcm_cfg80211 *cfg, struct net_device *ndev, char* b } else { /* Continuous NoA interval. */ - dongle_noa.action = WL_P2P_SCHED_ACTION_NONE; + dongle_noa.action = WL_P2P_SCHED_ACTION_DOZE; dongle_noa.type = WL_P2P_SCHED_TYPE_ABS; if ((cfg->p2p->noa.desc[0].interval == 102) || (cfg->p2p->noa.desc[0].interval == 100)) { diff --git a/drivers/nfc/sec_nfc.c b/drivers/nfc/sec_nfc.c index 803f44861bfa..1930ec408bf3 100644 --- a/drivers/nfc/sec_nfc.c +++ b/drivers/nfc/sec_nfc.c @@ -111,6 +111,11 @@ struct sec_nfc_info { #endif }; +#define FEATURE_SEC_NFC_TEST +#ifdef FEATURE_SEC_NFC_TEST +static struct sec_nfc_info *g_nfc_info; +static bool on_nfc_test; +#endif #ifdef CONFIG_SEC_NFC_IF_I2C static irqreturn_t sec_nfc_irq_thread_fn(int irq, void *dev_id) { @@ -119,6 +124,11 @@ static irqreturn_t sec_nfc_irq_thread_fn(int irq, void *dev_id) dev_dbg(info->dev, "[NFC] Read Interrupt is occurred!\n"); +#ifdef FEATURE_SEC_NFC_TEST + if (on_nfc_test) + return IRQ_HANDLED; +#endif + if(gpio_get_value(pdata->irq) == 0) { dev_err(info->dev, "[NFC] Warning,irq-gpio state is low!\n"); return IRQ_HANDLED; @@ -152,6 +162,11 @@ static ssize_t sec_nfc_read(struct file *file, char __user *buf, dev_dbg(info->dev, "%s: info: %p, count: %zu\n", __func__, info, count); +#ifdef FEATURE_SEC_NFC_TEST + if (on_nfc_test) + return 0; +#endif + mutex_lock(&info->mutex); if (info->mode == SEC_NFC_MODE_OFF) { @@ -225,6 +240,11 @@ static ssize_t sec_nfc_write(struct file *file, const char __user *buf, dev_dbg(info->dev, "%s: info: %p, count %d\n", __func__, info, (u32)count); +#ifdef FEATURE_SEC_NFC_TEST + if (on_nfc_test) + return 0; +#endif + mutex_lock(&info->mutex); if (info->mode == SEC_NFC_MODE_OFF) { @@ -749,12 +769,177 @@ static int sec_nfc_parse_dt(struct device *dev, return -ENODEV; } #endif + +#ifdef FEATURE_SEC_NFC_TEST +static int sec_nfc_i2c_read(char *buf, int count) +{ + struct sec_nfc_info *info = g_nfc_info; + int ret = 0; + + mutex_lock(&info->mutex); + + if (info->mode == SEC_NFC_MODE_OFF) { + pr_err("NFC_TEST: sec_nfc is not enabled\n"); + ret = -ENODEV; + goto out; + } + + /* i2c recv */ + if (count > info->i2c_info.buflen) + count = info->i2c_info.buflen; + + if (count > SEC_NFC_MSG_MAX_SIZE) { + pr_err("NFC_TEST: user required wrong size :%d\n", (u32)count); + ret = -EINVAL; + goto out; + } + + mutex_lock(&info->i2c_info.read_mutex); + memset(buf, 0, count); + ret = i2c_master_recv(info->i2c_info.i2c_dev, buf, (u32)count); + pr_info("NFC_TEST: recv size : %d\n", ret); + + if (ret == -EREMOTEIO) { + ret = -ERESTART; + goto read_error; + } else if (ret != count) { + pr_err("NFC_TEST: read failed: return: %d count: %d\n", + ret, (u32)count); + goto read_error; + } + + mutex_unlock(&info->i2c_info.read_mutex); + + goto out; + +read_error: + info->i2c_info.read_irq = SEC_NFC_NONE; + mutex_unlock(&info->i2c_info.read_mutex); +out: + mutex_unlock(&info->mutex); + + return ret; +} + +static int sec_nfc_i2c_write(char *buf, int count) +{ + struct sec_nfc_info *info = g_nfc_info; + int ret = 0; + + mutex_lock(&info->mutex); + + if (info->mode == SEC_NFC_MODE_OFF) { + pr_err("NFC_TEST: sec_nfc is not enabled\n"); + ret = -ENODEV; + goto out; + } + + if (count > info->i2c_info.buflen) + count = info->i2c_info.buflen; + + if (count > SEC_NFC_MSG_MAX_SIZE) { + pr_err("NFC_TEST: user required wrong size :%d\n", (u32)count); + ret = -EINVAL; + goto out; + } + + mutex_lock(&info->i2c_info.read_mutex); + ret = i2c_master_send(info->i2c_info.i2c_dev, buf, count); + mutex_unlock(&info->i2c_info.read_mutex); + + if (ret == -EREMOTEIO) { + pr_err("NFC_TEST: send failed: return: %d count: %d\n", + ret, (u32)count); + ret = -ERESTART; + goto out; + } + + if (ret != count) { + pr_err("NFC_TEST: send failed: return: %d count: %d\n", + ret, (u32)count); + ret = -EREMOTEIO; + } + +out: + mutex_unlock(&info->mutex); + + return ret; +} + +static ssize_t sec_nfc_test_show(struct class *class, + struct class_attribute *attr, + char *buf) +{ + char cmd[2][8] = { + {0x0, 0x1, 0x0, 0x0,}, /*bootloader fw check*/ + {0x20, 0x03, 0x02, 0x01, 0x00,} /*check status on ON*/ + }; + char *msg[2] = {"FW_VER", "ON :"}; + char cmd_len = 4; + int sel = 0; + enum sec_nfc_mode old_mode = g_nfc_info->mode; + int size; + int ret = 0; + + on_nfc_test = true; + pr_info("NFC_TEST: mode = %d\n", old_mode); + +#if 0/* TODO */ + if (old_mode == SEC_NFC_MODE_FIRMWARE) + { + sel = 0; + cmd_len = 4; + } + else +#endif + { + sec_nfc_set_mode(g_nfc_info, SEC_NFC_MODE_BOOTLOADER); + } + ret = sec_nfc_i2c_write(cmd[sel], cmd_len); + if (ret < 0) + { + pr_info("NFC_TEST: i2c write error %d\n", ret); + size = sprintf(buf, "NFC_TEST: i2c write error %d\n", ret); + goto exit; + } + msleep(10);/* need wait? */ + ret = sec_nfc_i2c_read(buf, 16); + if (ret < 0) + { + pr_info("NFC_TEST: i2c read error %d\n", ret); + size = sprintf(buf, "NFC_TEST: i2c read error %d\n", ret); + goto exit; + } + pr_info("NFC_TEST: %s: %02X %02X %02X %02X, mode: %d\n", msg[sel], buf[0], buf[1], + buf[2], buf[3], g_nfc_info->mode); + size = sprintf(buf, "%s: %02X.%02X.%02X.%02X\n", msg[sel], buf[0], buf[1], buf[2], + buf[3]); + +exit: + sec_nfc_set_mode(g_nfc_info, old_mode); + on_nfc_test = false; + + return size; +} +static ssize_t sec_nfc_test_store(struct class *dev, + struct class_attribute *attr, + const char *buf, size_t size) +{ + return size; +} + +static CLASS_ATTR(test, 0664, sec_nfc_test_show, sec_nfc_test_store); +#endif + static int __devinit __sec_nfc_probe(struct device *dev) { struct sec_nfc_info *info; struct sec_nfc_platform_data *pdata = NULL; int ret = 0; +#ifdef FEATURE_SEC_NFC_TEST + struct class *nfc_class; +#endif dev_dbg(dev, "[NFC]sec-nfc probe start \n"); if (dev->of_node) { pdata = devm_kzalloc(dev, @@ -837,6 +1022,18 @@ static int __devinit __sec_nfc_probe(struct device *dev) wake_lock_init(&info->nfc_wake_lock, WAKE_LOCK_SUSPEND, "nfc_wake_lock"); +#ifdef FEATURE_SEC_NFC_TEST + g_nfc_info = info; + nfc_class = class_create(THIS_MODULE, "nfc_test"); + if (IS_ERR(&nfc_class)) + pr_err("NFC: failed to create nfc class\n"); + else + { + ret = class_create_file(nfc_class, &class_attr_test); + if (ret) + pr_err("NFC: failed to create attr_test\n"); + } +#endif dev_dbg(dev, "%s: success info: %p, pdata %p\n", __func__, info, pdata); return 0; diff --git a/drivers/nfc/secnfc/sec_nfc.c b/drivers/nfc/secnfc/sec_nfc.c index ada46fd6002c..e714d98311f9 100644 --- a/drivers/nfc/secnfc/sec_nfc.c +++ b/drivers/nfc/secnfc/sec_nfc.c @@ -30,7 +30,7 @@ #include #include - +#include #ifdef CONFIG_SEC_NFC_I2C #include #include @@ -94,13 +94,13 @@ extern int poweroff_charging; static unsigned int tvdd_gpio = -1; #undef FEATURE_SET_DEFAULT_ANT_VAL -#define FEATURE_FELICA_IMPROVE_ANT_ON_CASE -#ifdef FEATURE_FELICA_IMPROVE_ANT_ON_CASE +#ifdef CONFIG_NFC_EDC_TUNING static unsigned char user_ant = 10; #endif static int felica_epc_ant_read(unsigned char *read_buff); static int felica_epc_ant_write(char ant); +int felica_epc_reset(void); /* * I2C device_id table @@ -168,7 +168,12 @@ static int bu80003gul_i2c_probe(struct i2c_client *client, return -EFAULT; } #endif -#ifdef FEATURE_FELICA_IMPROVE_ANT_ON_CASE +#ifdef CONFIG_NFC_EDC_TUNING + ret = felica_epc_reset(); + if (ret < 0) { + EPC_ERR("[MFDD] %s felica_epc_reset fail, ret=[%d]", + __func__, ret); + } ret = felica_epc_ant_read(&user_ant); if (ret < 0) { EPC_ERR("[MFDD] %s felica_epc_ant_read fail, ret=[%d]", @@ -458,7 +463,7 @@ static ssize_t felica_epc_write(struct file *file, const char __user *data, return -EFAULT; } -#ifdef FEATURE_FELICA_IMPROVE_ANT_ON_CASE +#ifdef CONFIG_NFC_EDC_TUNING user_ant = ant & 0x7F; #endif EPC_DEBUG("[MFDD] %s END\n", __func__); @@ -467,29 +472,33 @@ static ssize_t felica_epc_write(struct file *file, const char __user *data, } #endif /* BU80003GUL */ -#ifdef FEATURE_FELICA_IMPROVE_ANT_ON_CASE -int felica_ant_tuning(int parameter) +#ifdef CONFIG_NFC_EDC_TUNING +static int ant_tune_req = 0; +static void felica_ant_tuning_work(struct work_struct *work) { + int i, ret; char ant; - int ret; -#ifdef CONFIG_NFC_EDC_TUNING - if (parameter == 1) - ant = (user_ant > 10) ? (user_ant-10) : 1; - else - ant = user_ant; -#else - if (parameter == 1) - ant = 1; - else - ant = user_ant; -#endif - pr_info("%s : felica_ant : %d, event: %d\n", __func__, (int)ant, parameter); - ret = felica_epc_ant_write(ant); - if (ret < 0) { - EPC_ERR("[MFDD] %s ERROR(i2c_transfer), ret=[%d]", - __func__, ret); - return -EIO; + ant = user_ant; + for (i = 0; i < 10; i++) { + if (ant_tune_req != 1) + break; + ant = ant > 2 ? ant - 2 : 1; + ret = felica_epc_ant_write(ant); + pr_info("%s : felica_tune_work ant: %d\n", __func__, ant); + msleep(1000); + } + ret = felica_epc_ant_write(user_ant); + ant_tune_req = 0; +} +static DECLARE_DELAYED_WORK(felica_ant_work, felica_ant_tuning_work); +int felica_ant_tuning(int evt) +{ + pr_info("%s : felica_tune_req : %d, event: %d\n", __func__, ant_tune_req, evt); + + ant_tune_req = evt; + if (evt == 1) { + schedule_delayed_work(&felica_ant_work, 0); } return 1; @@ -842,6 +851,9 @@ static long sec_nfc_ioctl(struct file *file, unsigned int cmd, __func__, mode, firm); break; + case SEC_NFC_EDC_SWEEP: + felica_ant_tuning(1); + break; default: dev_err(info->dev, "Unknow ioctl 0x%x\n", cmd); @@ -1288,7 +1300,6 @@ static int sec_nfc_probe(struct platform_device *pdev) } */ #endif /* BU80003GUL */ - pr_info("%s: exit - sec-nfc probe finish\n", __func__); return 0; @@ -1333,14 +1344,12 @@ static void sec_nfc_lpm_set(struct device *dev) static void sec_nfc_shutdown(struct platform_device *pdev) { - int ret; struct device *dev = &pdev->dev; - ret = felica_epc_reset(); - if (ret < 0) { - EPC_ERR("[MFDD] %s ERROR(i2c_transfer), ret=[%d]", - __func__, ret); - } +#ifdef CONFIG_NFC_EDC_TUNING + ant_tune_req = 0; + flush_delayed_work(&felica_ant_work); +#endif sec_nfc_lpm_set(dev); gpio_set_value(tvdd_gpio, 0); } diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c index 24bfd61774e1..1d36af61a9c4 100644 --- a/drivers/pci/host/pci-exynos.c +++ b/drivers/pci/host/pci-exynos.c @@ -64,6 +64,7 @@ extern int sec_argos_register_notifier(struct notifier_block *n, char *label); extern int sec_argos_unregister_notifier(struct notifier_block *n, char *label); #ifdef CONFIG_ESOC extern int mdm_get_fatal_status(void); +extern void set_ap2mdm_errfatal(void); #endif static void exynos_pcie_notify_callback(struct pcie_port *pp, int event); #if defined(CONFIG_PCI_MSI) @@ -263,10 +264,6 @@ int exynos_pcie_reset(struct pcie_port *pp) if(mdm_get_fatal_status()) return -EPIPE; #endif - /* set #PERST Low */ - gpio_set_value(exynos_pcie->perst_gpio, 0); - msleep(15); - /* set RxElecIdle = 0 to access DBI area */ tmp0 = readl(phy_base + 0x4A*4); tmp1 = readl(phy_base + 0x5C*4); @@ -376,6 +373,9 @@ int exynos_pcie_reset(struct pcie_port *pp) writel(PCIE_ELBI_LTSSM_DISABLE, exynos_pcie->elbi_base + PCIE_APP_LTSSM_ENABLE); + if (soc_is_exynos7420() && exynos_pcie->ch_num == 0) + msleep(15); + goto retry; } else { #ifdef CONFIG_ESOC @@ -480,6 +480,15 @@ void exynos_pcie_work(struct work_struct *work) if (exynos_pcie->ch_num == 0) { exynos_pcie_register_dump(0); exynos_pcie_notify_callback(pp, EXYNOS_PCIE_EVENT_LINKDOWN); +#ifdef CONFIG_ESOC + if(mdm_get_fatal_status()) { + dev_info(pp->dev, "PCIe: mdm has fatal status\n"); + } else { + dev_info(pp->dev, "PCIe: link is downed, force cp crash\n"); + set_ap2mdm_errfatal(); + } +#endif + } else if (exynos_pcie->ch_num == 1) { #ifdef CONFIG_PCI_EXYNOS_TEST exynos_pcie_poweroff(exynos_pcie->ch_num); @@ -707,6 +716,8 @@ static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp) val = readl(elbi_base + PCIE_IRQ_SPECIAL); if (soc_is_exynos7420() && (val & (0x1 << 2))) { dev_info(pp->dev, "!!!PCIE LINK DOWN!!!\n"); + if (exynos_pcie->ch_num == 0) + exynos_pcie->state = STATE_LINK_DOWN_TRY; queue_work(exynos_pcie->pcie_wq, &exynos_pcie->work.work); } @@ -1108,22 +1119,6 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) if (ret) goto probe_fail; -#ifdef CONFIG_CPU_IDLE - exynos_pcie->lpa_nb.notifier_call = exynos_pci_lpa_event; - exynos_pcie->lpa_nb.next = NULL; - exynos_pcie->lpa_nb.priority = 0; - - if (soc_is_exynos5433()) - ret = raw_notifier_chain_register(&pci_lpa_nh, &exynos_pcie->lpa_nb); - else if (soc_is_exynos7420()) - ret = exynos_pm_register_notifier(&exynos_pcie->lpa_nb); - - if (ret) { - dev_err(&pdev->dev, "Failed to register lpa notifier\n"); - goto probe_fail; - } -#endif - platform_set_drvdata(pdev, exynos_pcie); if (exynos_pcie->ch_num == 1) { @@ -1319,14 +1314,22 @@ void exynos_pcie_enable_async_suspend(struct device *dev) } EXPORT_SYMBOL(exynos_pcie_enable_async_suspend); -void exynos_pcie_poweron(int ch_num) +int exynos_pcie_poweron(int ch_num) { struct pcie_port *pp = &g_pcie[ch_num].pp; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); u32 val, vendor_id, device_id; + int ret; dev_info(pp->dev, "%s, start of poweron, pcie state: %d\n", __func__, exynos_pcie->state); - if (exynos_pcie->state == STATE_LINK_DOWN) { + if (exynos_pcie->state == STATE_LINK_DOWN || ((exynos_pcie->ch_num == 0) && (exynos_pcie->state == STATE_LINK_DOWN_TRY))) { + + if (soc_is_exynos7420() && exynos_pcie->ch_num == 0) { + /* set #PERST Low */ + gpio_set_value(exynos_pcie->perst_gpio, 0); + msleep(15); + } + exynos_pcie_clock_enable(pp, 1); #ifndef CONFIG_SOC_EXYNOS5433 exynos_pcie_ref_clock_enable(pp, 1); @@ -1349,16 +1352,34 @@ void exynos_pcie_poweron(int ch_num) exynos_pcie->state = STATE_LINK_UP_TRY; if (!exynos_pcie->probe_ok) { +#ifdef CONFIG_CPU_IDLE + exynos_pcie->lpa_nb.notifier_call = exynos_pci_lpa_event; + exynos_pcie->lpa_nb.next = NULL; + exynos_pcie->lpa_nb.priority = 0; + + if (soc_is_exynos5433()) + ret = raw_notifier_chain_register(&pci_lpa_nh, &exynos_pcie->lpa_nb); + else if (soc_is_exynos7420()) + ret = exynos_pm_register_notifier(&exynos_pcie->lpa_nb); + + if (ret) { + dev_err(pp->dev, "Failed to register lpa notifier\n"); + goto poweron_fail; + } +#endif mutex_init(&exynos_pcie->lock); exynos_pcie->pcie_wq = create_freezable_workqueue("pcie_wq"); if (IS_ERR(exynos_pcie->pcie_wq)) { dev_err(pp->dev, "couldn't create workqueue\n"); - return; + goto mtx_fail; } INIT_DELAYED_WORK(&exynos_pcie->work, exynos_pcie_work); - exynos_pcie_establish_link(pp); + if (exynos_pcie_establish_link(pp)) { + dev_err(pp->dev, "pcie link up fail\n"); + goto wq_fail; + } exynos_pcie->state = STATE_LINK_UP; dw_pcie_scan(pp); @@ -1369,7 +1390,7 @@ void exynos_pcie_poweron(int ch_num) exynos_pcie->pci_dev = pci_get_device(vendor_id, device_id, NULL); if (!exynos_pcie->pci_dev) { dev_err(pp->dev, "Failed to get pci device\n"); - return; + goto wq_fail; } #ifdef CONFIG_PCI_MSI @@ -1380,13 +1401,9 @@ void exynos_pcie_poweron(int ch_num) exynos_pcie->pci_saved_configs = pci_store_saved_state(exynos_pcie->pci_dev); exynos_pcie->probe_ok = 1; } else if (exynos_pcie->probe_ok) { - if (soc_is_exynos7420() && exynos_pcie->ch_num == 0) { - if (exynos_pcie_reset(pp)) { - dev_err(pp->dev, "Failed exynos_pcie_reset\n"); - return; - } - } else { - exynos_pcie_reset(pp); + if (exynos_pcie_reset(pp)) { + dev_err(pp->dev, "pcie link up fail\n"); + goto poweron_fail; } exynos_pcie->state = STATE_LINK_UP; @@ -1399,6 +1416,26 @@ void exynos_pcie_poweron(int ch_num) } } dev_info(pp->dev, "%s, end of poweron, pcie state: %d\n", __func__, exynos_pcie->state); + + return 0; + +wq_fail: + destroy_workqueue(exynos_pcie->pcie_wq); +mtx_fail: + mutex_destroy(&exynos_pcie->lock); + +#ifdef CONFIG_CPU_IDLE + if (soc_is_exynos5433()) + raw_notifier_chain_unregister(&pci_lpa_nh, &exynos_pcie->lpa_nb); + else if (soc_is_exynos7420()) + exynos_pm_unregister_notifier(&exynos_pcie->lpa_nb); +#endif + +poweron_fail: + exynos_pcie->state = STATE_LINK_UP; + exynos_pcie_poweroff(exynos_pcie->ch_num); + + return -EPIPE; } EXPORT_SYMBOL(exynos_pcie_poweron); @@ -1409,7 +1446,7 @@ void exynos_pcie_poweroff(int ch_num) unsigned long flags; dev_info(pp->dev, "%s, start of poweroff, pcie state: %d\n", __func__, exynos_pcie->state); - if (exynos_pcie->state == STATE_LINK_UP) { + if (exynos_pcie->state == STATE_LINK_UP || ((exynos_pcie->ch_num == 0) && (exynos_pcie->state == STATE_LINK_DOWN_TRY))) { exynos_pcie->state = STATE_LINK_DOWN_TRY; while (exynos_pcie->lpc_checking) usleep_range(1000, 1100); @@ -1532,11 +1569,17 @@ int exynos_pcie_pm_suspend(int ch_num) { struct pcie_port *pp = &g_pcie[ch_num].pp; struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + unsigned long flags; if (exynos_pcie->state == STATE_LINK_DOWN) { dev_info(pp->dev, "RC%d already off\n", exynos_pcie->ch_num); return 0; } + + spin_lock_irqsave(&pp->conf_lock, flags); + exynos_pcie->state = STATE_LINK_DOWN_TRY; + spin_unlock_irqrestore(&pp->conf_lock, flags); + exynos_pcie_send_pme_turn_off(exynos_pcie); exynos_pcie_poweroff(ch_num); @@ -1546,9 +1589,7 @@ EXPORT_SYMBOL(exynos_pcie_pm_suspend); int exynos_pcie_pm_resume(int ch_num) { - exynos_pcie_poweron(ch_num); - - return 0; + return exynos_pcie_poweron(ch_num); } EXPORT_SYMBOL(exynos_pcie_pm_resume); @@ -1988,6 +2029,25 @@ int exynos_pcie_dump_link_down_status(int ch_num) } EXPORT_SYMBOL(exynos_pcie_dump_link_down_status); +void exynos_pcie_rxelecidle_toggle(int ch_num) +{ + struct pcie_port *pp = &g_pcie[ch_num].pp; + struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp); + void __iomem *phy_base = exynos_pcie->phy_base; + u32 tmp0, tmp1; + + tmp0 = readl(phy_base + 0x4A*4); + tmp1 = readl(phy_base + 0x5C*4); + writel(0xDF, phy_base + 0x4A*4); + writel(0x54, phy_base + 0x5C*4); + + udelay(10); + + writel(tmp1, phy_base + 0x5C*4); + writel(tmp0, phy_base + 0x4A*4); +} +EXPORT_SYMBOL(exynos_pcie_rxelecidle_toggle); + MODULE_AUTHOR("Jingoo Han "); MODULE_DESCRIPTION("Samsung PCIe host controller driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pci/host/pci-noti.h b/drivers/pci/host/pci-noti.h index 87b7ef432af3..157fcfb2a368 100644 --- a/drivers/pci/host/pci-noti.h +++ b/drivers/pci/host/pci-noti.h @@ -51,5 +51,5 @@ int exynos_pcie_restore_config(struct pci_dev *dev); int exynos_pcie_pm_suspend(int ch_num); int exynos_pcie_pm_resume(int ch_num); int exynos_pcie_disable_irq(int ch_num); - +void exynos_pcie_rxelecidle_toggle(int ch_num); #endif diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h index 3aa7af66c3b5..ef94a5011dc1 100644 --- a/drivers/pci/host/pcie-designware.h +++ b/drivers/pci/host/pcie-designware.h @@ -51,7 +51,7 @@ struct pcie_host_ops { }; extern unsigned long global_io_offset; -void exynos_pcie_poweron(int); +int exynos_pcie_poweron(int); void exynos_pcie_poweroff(int); int cfg_read(void *addr, int where, int size, u32 *val); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 411eab6a7129..541756c0ebca 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -227,6 +227,10 @@ config SEC_GPIO_DVS config MST_SECURE_GPIO bool "setting MST gpio as secure pin" +config SENSORS_FP_SPI_GPIO + depends on SENSORS_FINGERPRINT + string "Fingerprint spi gpio name" + source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/sh-pfc/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 03c48b46bc31..d229e8cdc7ef 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,6 +1,7 @@ # generic pinmux support ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG +ccflags-y += $(KBUILD_FP_SENSOR_CFLAGS) obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 603bef28fbe5..dbabc413b66d 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -1593,9 +1593,11 @@ struct samsung_pin_ctrl exynos7420_pin_ctrl[] = { .weint_fltcon = EXYNOS5430_WKUP_EFLTCON_OFFSET, .svc = EXYNOS_SVC_OFFSET, .gpio_type = EXYNOS_GPIO_TYPE_DRV_SEPARATE, +#ifndef ENABLE_SENSORS_FPRINT_SECURE .eint_gpio_init = exynos_eint_gpio_init, .suspend = exynos5430_pinctrl_suspend, .resume = exynos5430_pinctrl_resume, +#endif .label = "exynos7420-gpio-ctrl7", }, { /* pin-controller instance 8 FSYS0 data */ diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index ae1c6087c0be..2f9a9410bfce 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c @@ -444,6 +444,12 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base, ®, &pin_offset, &bank); + +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + return; +#endif + type = bank->type; mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; @@ -453,6 +459,12 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, reg += 4; } +#ifdef CONFIG_MST_SECURE_GPIO + if (!strncmp(bank->name, "gpj0", 4)) + return; + if (!strncmp(bank->name, "gpj1", 4)) + return; +#endif spin_lock_irqsave(&bank->slock, flags); con = readl(reg + type->reg_offset[PINCFG_TYPE_FUNC]); @@ -514,6 +526,12 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, unsigned long flags; bank = gc_to_pin_bank(range->gc); + +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + return 0; +#endif + type = bank->type; drvdata = pinctrl_dev_get_drvdata(pctldev); reg_ext_base = bank->eint_ext_offset ? @@ -531,6 +549,12 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, reg += 4; } +#ifdef CONFIG_MST_SECURE_GPIO + if (!strncmp(bank->name, "gpj0", 4)) + return 0; + if (!strncmp(bank->name, "gpj1", 4)) + return 0; +#endif spin_lock_irqsave(&bank->slock, flags); data = readl(reg); @@ -582,11 +606,23 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, drvdata = pinctrl_dev_get_drvdata(pctldev); pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, &pin_offset, &bank); + +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + return 0; +#endif + type = bank->type; if (cfg_type >= PINCFG_TYPE_NUM || !type->fld_width[cfg_type]) return -EINVAL; +#ifdef CONFIG_MST_SECURE_GPIO + if (!strncmp(bank->name, "gpj0", 4)) + return 0; + if (!strncmp(bank->name, "gpj1", 4)) + return 0; +#endif width = type->fld_width[cfg_type]; cfg_reg = type->reg_offset[cfg_type]; @@ -758,8 +794,19 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) bank->drvdata->virt_ext_base : bank->drvdata->virt_base; u32 data; +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + return; +#endif + reg = reg_ext_base + bank->pctl_offset; +#ifdef CONFIG_MST_SECURE_GPIO + if (!strncmp(bank->name, "gpj0", 4)) + return; + if (!strncmp(bank->name, "gpj1", 4)) + return; +#endif spin_lock_irqsave(&bank->slock, flags); data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); @@ -1373,6 +1420,11 @@ static void samsung_pinctrl_save_regs( if (!widths[PINCFG_TYPE_CON_PDN]) continue; +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + continue; +#endif + for (type = 0; type < PINCFG_TYPE_NUM; type++) if (widths[type]) bank->pm_save[type] = readl(reg + offs[type]); @@ -1413,6 +1465,11 @@ static void samsung_pinctrl_restore_regs( if (!widths[PINCFG_TYPE_CON_PDN]) continue; +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + continue; +#endif + if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) { /* Some banks have two config registers */ pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n", @@ -1466,6 +1523,11 @@ static void samsung_pinctrl_set_pdn_previos_state( if (!widths[PINCFG_TYPE_CON_PDN]) continue; +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) + continue; +#endif + /* set previous state */ writel(0xffffffff, reg + offs[PINCFG_TYPE_CON_PDN]); writel(bank->pm_save[PINCFG_TYPE_PUD], @@ -1711,6 +1773,13 @@ static void gpiodvs_check_init_gpio(struct samsung_pinctrl_drv_data *drvdata, pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, &pin_offset, &bank); +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) { + init_gpio_idx++; + goto out; + } +#endif + /* GPZ ports are AUD interface (I2S, UART, PCM, SB) that should not * access when AUD power is disabled */ @@ -1761,6 +1830,13 @@ static void gpiodvs_check_sleep_gpio(struct samsung_pinctrl_drv_data *drvdata, pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, &pin_offset, &bank); +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (!strncmp(bank->name, CONFIG_SENSORS_FP_SPI_GPIO, 4)) { + sleep_gpio_idx++; + goto out; + } +#endif + /* GPZ ports are AUD interface (I2S, UART, PCM, SB) that should not * access when AUD power is disabled */ diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index eea6414b73bc..eaae1d711469 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -107,6 +107,17 @@ static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; } +static int arizona_ldo1_hc_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, + unsigned int new_selector) +{ + /* if moving to 1.8v allow time for it to reach voltage */ + if (new_selector == rdev->desc->n_voltages - 1) + return 25; + else + return 0; +} + static struct regulator_ops arizona_ldo1_hc_ops = { .list_voltage = arizona_ldo1_hc_list_voltage, .map_voltage = arizona_ldo1_hc_map_voltage, @@ -114,6 +125,7 @@ static struct regulator_ops arizona_ldo1_hc_ops = { .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, .get_bypass = regulator_get_bypass_regmap, .set_bypass = regulator_set_bypass_regmap, + .set_voltage_time_sel = arizona_ldo1_hc_set_voltage_time_sel, }; static const struct regulator_desc arizona_ldo1_hc = { @@ -281,6 +293,9 @@ static int arizona_ldo1_probe(struct platform_device *pdev) arizona->external_dcvdd = true; ldo1->regulator = regulator_register(desc, &config); + + of_node_put(config.of_node); + if (IS_ERR(ldo1->regulator)) { ret = PTR_ERR(ldo1->regulator); dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", @@ -288,8 +303,6 @@ static int arizona_ldo1_probe(struct platform_device *pdev) return ret; } - of_node_put(config.of_node); - platform_set_drvdata(pdev, ldo1); return 0; diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index 362ec0d6ca94..933caa9139c0 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -106,10 +106,13 @@ static void arizona_micsupp_check_cp(struct work_struct *work) SND_SOC_DAPM_CLASS_RUNTIME); if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) == - ARIZONA_CPMIC_ENA) + ARIZONA_CPMIC_ENA) { snd_soc_dapm_force_enable_pin(dapm, "MICSUPP"); - else + arizona->micvdd_regulated = true; + } else { snd_soc_dapm_disable_pin(dapm, "MICSUPP"); + arizona->micvdd_regulated = false; + } mutex_unlock(&dapm->card->dapm_mutex); @@ -319,6 +322,9 @@ static int arizona_micsupp_probe(struct platform_device *pdev) ARIZONA_CPMIC_BYPASS, 0); micsupp->regulator = regulator_register(desc, &config); + + of_node_put(config.of_node); + if (IS_ERR(micsupp->regulator)) { ret = PTR_ERR(micsupp->regulator); dev_err(arizona->dev, "Failed to register mic supply: %d\n", @@ -326,8 +332,6 @@ static int arizona_micsupp_probe(struct platform_device *pdev) return ret; } - of_node_put(config.of_node); - platform_set_drvdata(pdev, micsupp); return 0; diff --git a/drivers/regulator/max77833.c b/drivers/regulator/max77833.c index d7ed7f8b01c0..b5e0d2c3cc02 100644 --- a/drivers/regulator/max77833.c +++ b/drivers/regulator/max77833.c @@ -160,8 +160,8 @@ static int max77833_get_enable_register(struct regulator_dev *rdev, switch (rid) { case MAX77833_SAFEOUT1...MAX77833_SAFEOUT2: *reg = MAX77833_PMIC_REG_SAFEOUT_CTRL; - *mask = 0x40 << (rid - MAX77833_SAFEOUT1); - *pattern = 0x40 << (rid - MAX77833_SAFEOUT1); + *mask = 0x80 << (rid - MAX77833_SAFEOUT1); + *pattern = 0x80 << (rid - MAX77833_SAFEOUT1); break; default: /* Not controllable or not exists */ @@ -180,7 +180,7 @@ static int max77833_get_disable_register(struct regulator_dev *rdev, switch (rid) { case MAX77833_SAFEOUT1...MAX77833_SAFEOUT2: *reg = MAX77833_PMIC_REG_SAFEOUT_CTRL; - *mask = 0x40 << (rid - MAX77833_SAFEOUT1); + *mask = 0x80 << (rid - MAX77833_SAFEOUT1); *pattern = 0x00; break; default: diff --git a/drivers/regulator/max77838-regulator.c b/drivers/regulator/max77838-regulator.c index cf1d5db1dd89..fffb6291f2e7 100644 --- a/drivers/regulator/max77838-regulator.c +++ b/drivers/regulator/max77838-regulator.c @@ -185,6 +185,32 @@ static int max77838_reg_set_active_discharge(struct max77838_reg *max77838_reg, return rc; } +struct max77838_reg *max77838_reg_global; + +int max77838_reg_set_diode_mode(bool on) +{ + int rc, reg, val; + + if (on) + val = 0x01<<6; + else + val = 0; + + if (max77838_reg_global) { + /* decide diode mode */ + reg = REG_GPIO_PD_CTRL; + rc = regmap_write(max77838_reg_global->regmap, reg, val); + pr_info ("MAX77838: set addr(0x%x) to 0x%x\n", reg, val); + } else { + pr_info ("MAX77838: device is not ready\n"); + return -1; + } + + return rc; +} + +EXPORT_SYMBOL(max77838_reg_set_diode_mode); + static int max77838_reg_hw_init(struct max77838_reg *max77838_reg, struct max77838_regulator_platform_data *pdata) { @@ -204,6 +230,11 @@ static int max77838_reg_hw_init(struct max77838_reg *max77838_reg, val = pdata->uvlo_fall_threshold<regmap, reg, val); + /* set diode mode */ + val = 0x01<<6; + reg = REG_GPIO_PD_CTRL; + rc = regmap_write(max77838_reg->regmap, reg, val); + return rc; } @@ -354,6 +385,8 @@ static int max77838_regulator_probe(struct i2c_client *client, goto abort; } + max77838_reg_global = max77838_reg; + pr_info("<%s> probe end\n", client->name); return 0; diff --git a/drivers/rtc/rtc-sec.c b/drivers/rtc/rtc-sec.c index 14b1e84f69ad..b49ea0311ff1 100644 --- a/drivers/rtc/rtc-sec.c +++ b/drivers/rtc/rtc-sec.c @@ -38,6 +38,11 @@ #ifdef CONFIG_EXYNOS_MBOX #include #endif + +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING +#include +#endif + struct s2m_rtc_info { struct device *dev; struct sec_pmic_dev *iodev; @@ -50,6 +55,9 @@ struct s2m_rtc_info { bool lpm_mode; bool alarm_irq_flag; struct wake_lock alarm_wake_lock; +#endif +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + bool dchg_check_rtc_set; #endif int smpl_irq; bool use_irq; @@ -83,6 +91,12 @@ enum S2M_RTC_OP { S2M_RTC_WRITE_ALARM, }; +#if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) +#define RTC_BWAKEUP_AMIN 2 +#define RTC_BWAKEUP_ALOOP_MIN 60 +static u8 rtc_balarm_min_for_dischg = 0; +#endif + static void s2m_data_to_tm(u8 *data, struct rtc_time *tm) { tm->tm_sec = data[RTC_SEC] & 0x7f; @@ -122,7 +136,7 @@ static int s2m_tm_to_data(struct rtc_time *tm, u8 *data) static int s2m_rtc_update(struct s2m_rtc_info *info, enum S2M_RTC_OP op) { - u8 data; + u8 data, rtc_update_reg; int ret; if (!info || !info->iodev) { @@ -161,6 +175,14 @@ static int s2m_rtc_update(struct s2m_rtc_info *info, else usleep_range(1000, 1000); + ret = sec_rtc_read(info->iodev, S2M_RTC_UPDATE, &rtc_update_reg); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to read update reg(%d)\n", __func__, ret); + } + + pr_info("%s: RTC_UPDATE_REGISTER check : 0x%02x\n", __func__, rtc_update_reg); + return ret; } @@ -379,6 +401,13 @@ static int s2m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret, i; mutex_lock(&info->lock); +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if (info->dchg_check_rtc_set) { + pr_err("[SDCHG][%s] already set discharging rtc for bootloader\n", __func__); + ret = -EPERM; + goto out; + } +#endif ret = s2m_tm_to_data(&alrm->time, data); if (ret < 0) goto out; @@ -540,7 +569,6 @@ static int s2m_rtc_set_alarm_boot(struct device *dev, { struct s2m_rtc_info *info = dev_get_drvdata(dev); u8 data[7]; - u8 rtcwake; int ret; mutex_lock(&info->lock); @@ -557,7 +585,7 @@ static int s2m_rtc_set_alarm_boot(struct device *dev, if (ret < 0) return ret; - ret = sec_rtc_read(info->iodev, S2M_RTC_UPDATE, &rtcwake); + ret = sec_rtc_read(info->iodev, S2M_RTC_UPDATE, &info->update_reg); if (ret < 0) { printk(KERN_INFO "%s: read fail \n", __func__); @@ -565,11 +593,11 @@ static int s2m_rtc_set_alarm_boot(struct device *dev, } if (alrm->enabled) - rtcwake |= RTC_WAKE_MASK; + info->update_reg |= RTC_WAKE_MASK; else - rtcwake &= ~RTC_WAKE_MASK; + info->update_reg &= ~RTC_WAKE_MASK; - ret = sec_rtc_write(info->iodev, S2M_RTC_UPDATE, (char)rtcwake); + ret = sec_rtc_write(info->iodev, S2M_RTC_UPDATE, (char)info->update_reg); if (ret < 0) { dev_err(info->dev, "%s: fail to write update reg(%d)\n", @@ -610,6 +638,244 @@ static int s2m_rtc_get_alarm_boot(struct device *dev, } #endif +#if defined(CONFIG_BATTERY_SWELLING_SELF_DISCHARGING) +static inline int s2m_rtc_update_reg_dischg(struct s2m_rtc_info *info, + enum S2M_RTC_OP op) +{ + int ret; + unsigned int data; + + ret = sec_rtc_read(info->iodev, S2M_RTC_UPDATE, &data); + if (ret < 0) + return ret; + + switch (op) { + case S2M_RTC_READ: + data |= RTC_RUDR_MASK; + break; + case S2M_RTC_WRITE_TIME: + data |= info->wudr_mask; + break; + case S2M_RTC_WRITE_ALARM: + data |= info->audr_mask; + break; + default: + dev_err(info->dev, "%s: invalid op(%d)\n", __func__, op); + return -EINVAL; + } + + ret = sec_rtc_write(info->iodev, S2M_RTC_UPDATE, (char)data); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + } else { + usleep_range(1000, 1000); + } + + return ret; +} + +static int s2m_rtc_stop_balarm_dischg(struct s2m_rtc_info *info) +{ + u8 data[7]; + int ret,i; + struct rtc_time tm; + + ret = sec_rtc_bulk_read(info->iodev, S2M_ALARM0_SEC, 7, data); + if (ret < 0) + return ret; + + s2m_data_to_tm(data, &tm); + + printk(KERN_INFO "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + for (i = 0; i < 7; i++) + data[i] &= ~ALARM_ENABLE_MASK; + + ret = sec_rtc_bulk_write(info->iodev, S2M_ALARM0_SEC, 7, data); + if (ret < 0) + return ret; + + ret = s2m_rtc_update_reg_dischg(info, S2M_RTC_WRITE_ALARM); + + return ret; +} + +static int s2m_rtc_start_balarm_dischg(struct s2m_rtc_info *info) +{ + int ret; + u8 data[7]; + struct rtc_time tm; + + ret = sec_rtc_bulk_read(info->iodev, S2M_ALARM0_SEC, 7, data); + if (ret < 0) + return ret; + + s2m_data_to_tm(data, &tm); + + printk(KERN_INFO "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + + //DISCHG Algorithm must run all the time + data[RTC_MIN] |= ALARM_ENABLE_MASK; + printk(KERN_INFO "%s data[RTC_MIN] = 0x%02x\n",__func__, data[RTC_MIN]); + + ret = sec_rtc_bulk_write(info->iodev, S2M_ALARM0_MIN, 1, &data[RTC_MIN]); + if (ret < 0) + return ret; + + ret = s2m_rtc_update_reg_dischg(info, S2M_RTC_WRITE_ALARM); + + ret = sec_rtc_bulk_read(info->iodev, S2M_ALARM0_SEC, 7, data); + if (ret < 0) + return ret; + + s2m_data_to_tm(data, &tm); + + printk(KERN_INFO "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, + 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + printk(KERN_INFO "%s data[RTC_MIN] = 0x%02x\n",__func__, data[RTC_MIN]); + + return ret; +} + +static int s2m_rtc_set_balarm_dischg_only(struct s2m_rtc_info *info) +{ + int ret; + u8 rtc_balarm_min; + u8 rtcwake; + u8 data[NR_RTC_CNT_REGS]; + +#if defined(CONFIG_RTC_ALARM_BOOT) + unsigned long alarm_time; + unsigned long rtc_time; + struct rtc_time temp_rtc_time; + u8 alarm1_time[NR_RTC_CNT_REGS]; +#endif + mutex_lock(&info->lock); + + ret = s2m_rtc_update(info, S2M_RTC_READ); + if (ret < 0) + dev_err(info->dev, "%s: fail to update RTC(%d)\n", __func__,ret); + + ret = sec_rtc_bulk_read(info->iodev, S2M_RTC_SEC, NR_RTC_CNT_REGS, data); + if (ret < 0) + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,ret); + + + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d(0x%02x)%s\n", + __func__, data[RTC_YEAR] + 2000, data[RTC_MONTH], + data[RTC_DATE], data[RTC_HOUR] & 0x1f, data[RTC_MIN], + data[RTC_SEC], data[RTC_WEEKDAY], + data[RTC_HOUR] & HOUR_PM_MASK ? "PM" : "AM"); + + +#if defined(CONFIG_RTC_ALARM_BOOT) + + ret = sec_rtc_bulk_read(info->iodev, S2M_ALARM1_SEC, 7, alarm1_time); + if (ret < 0) + dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,ret); + + s2m_data_to_tm(alarm1_time, &temp_rtc_time); + + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d(%d)\n", __func__, + temp_rtc_time.tm_year + 1900, temp_rtc_time.tm_mon + 1, + temp_rtc_time.tm_mday, temp_rtc_time.tm_hour, + temp_rtc_time.tm_min, temp_rtc_time.tm_sec, + temp_rtc_time.tm_wday); + + rtc_tm_to_time(&temp_rtc_time, &alarm_time); + + s2m_data_to_tm(data, &temp_rtc_time); + + dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d(%d)\n", __func__, + temp_rtc_time.tm_year + 1900, temp_rtc_time.tm_mon + 1, + temp_rtc_time.tm_mday, temp_rtc_time.tm_hour, + temp_rtc_time.tm_min, temp_rtc_time.tm_sec, + temp_rtc_time.tm_wday); + + rtc_tm_to_time(&temp_rtc_time, &rtc_time); + + alarm_time = alarm_time / 60; + rtc_time = rtc_time / 60; + + + if (alarm_time > rtc_time && alarm_time < rtc_time +5) { //if alarm_boot time is within 5min of current RTC + pr_info("[SDCHG][%s]alarm within 5min\n", __func__); + mutex_unlock(&info->lock); + return 0; //then do anything. System will boot by alarm_boot + } + +#endif + + rtc_balarm_min_for_dischg = data[RTC_MIN]; + rtc_balarm_min = rtc_balarm_min_for_dischg + RTC_BWAKEUP_AMIN; + + if(rtc_balarm_min >= RTC_BWAKEUP_ALOOP_MIN) + rtc_balarm_min = rtc_balarm_min -RTC_BWAKEUP_ALOOP_MIN; + + s2m_rtc_stop_balarm_dischg(info); + + ret = sec_rtc_read(info->iodev, S2M_RTC_UPDATE, &rtcwake); + + if (ret < 0) + { + printk(KERN_ERR "%s: read fail \n", __func__); + mutex_unlock(&info->lock); + return ret; + } + + printk(KERN_INFO "%s: rtcwake(before) = %d\n",__func__,rtcwake); + + rtcwake |= RTC_WAKE_MASK; + + printk(KERN_INFO "%s: rtcwake(after) = %d\n",__func__,rtcwake); + + ret = sec_rtc_write(info->iodev, S2M_RTC_UPDATE, (char)rtcwake); + + if (ret < 0) { + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + } else { + usleep_range(1000, 1000); + } + + ret = sec_rtc_bulk_write(info->iodev, S2M_ALARM0_MIN, 1, &rtc_balarm_min); + if (ret < 0){ + dev_err(info->dev, "%s: fail to write update reg(%d)\n", + __func__, ret); + } + + ret = s2m_rtc_update_reg_dischg(info, S2M_RTC_WRITE_ALARM); + if (ret < 0) + printk(KERN_ERR "%s: s2m_rtc_update_reg_dischg FAIL!!\n",__func__); + else + printk(KERN_INFO "%s: s2m_rtc_update_reg_dischg SUCCESS!!\n",__func__); + + ret = s2m_rtc_start_balarm_dischg(info); + if (ret < 0) + printk(KERN_ERR "%s: s2m_rtc_start_balarm_dischg FAIL!!\n",__func__); + else + printk(KERN_INFO "%s: s2m_rtc_start_balarm_dischg SUCCESS!!\n",__func__); + + ret = sec_rtc_bulk_read(info->iodev, S2M_ALARM0_SEC, NR_RTC_CNT_REGS, data); + if(ret < 0) + printk(KERN_ERR "%s: RTC_MIN read fail\n",__func__); + else + printk(KERN_INFO "%s: RTC_MIN = %d\n",__func__,data[RTC_MIN]); + + info->dchg_check_rtc_set = true; + mutex_unlock(&info->lock); + + return ret; +} +#endif + static int s2m_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { @@ -1250,6 +1516,9 @@ static int s2m_rtc_probe(struct platform_device *pdev) info->use_alarm_workaround = false; info->wudr_mask = RTC_WUDR_MASK; info->audr_mask = RTC_AUDR_MASK; +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + info->dchg_check_rtc_set = false; +#endif switch (iodev->device_type) { case S2MPU03X: @@ -1432,6 +1701,12 @@ static void s2m_rtc_shutdown(struct platform_device *pdev) struct s2m_rtc_info *info = platform_get_drvdata(pdev); struct sec_platform_data *pdata = dev_get_platdata(info->iodev->dev); +#ifdef CONFIG_BATTERY_SWELLING_SELF_DISCHARGING + if(sdchg_nochip_support && (s2m_rtc_set_balarm_dischg_only(info) < 0)) + printk(KERN_ERR "%s: Failed to set alarm reg. for boot self-dischg\n \n", + __func__); +#endif + if (info->wtsr_en || info->smpl_en) s2m_rtc_disable_wtsr_smpl(info, pdata); } diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 53b1ecb21aa2..83266a009699 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -87,7 +87,7 @@ config SCSI_UFS_EXYNOS config FIPS_FMP_UFS tristate "EXYNOS FMP UFS Test for FIPS" - depends on SCSI_UFSHCD && SCSI_UFSHCD_PLATFORM && FMP + depends on SCSI_UFSHCD && SCSI_UFSHCD_PLATFORM && FIPS_FMP ---help--- This selects EXYNOS FMP UFS Self-Test driver for FIPS. @@ -109,21 +109,3 @@ config UFS_BKOPS_NODE_GID Owner group ID of BKOPS sysfs node. Default is 0. Do not touch the value if unsure. -choice - prompt "Option for self-test failure" - depends on FIPS_FMP_UFS - default NODE_FOR_SELFTEST_FAIL - -config NODE_FOR_SELFTEST_FAIL - bool "Set fips fmp node when self-test fails" - depends on FIPS_FMP_UFS - help - This select that fips fmp node was set to zero when FMP self-test fails. - -config PANIC_FOR_SELFTEST_FAIL - bool "Panic when self-test fails" - depends on FIPS_FMP_UFS - help - This select that kernel panic occurs when FMP self-test fails. - -endchoice diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 70559163eb81..92300d22aa7b 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -3,8 +3,6 @@ obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o ufs_quirks.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o -obj-$(CONFIG_UFS_FMP_ECRYPT_FS) += fmp_derive_iv.o obj-$(CONFIG_FIPS_FMP_UFS) += fips-fmp-ufs.o -obj-$(CONFIG_FIPS_FMP_UFS) += first_file.o -obj-$(CONFIG_FIPS_FMP_UFS) += fips-fmp.o fips-fmp-integrity.o -obj-$(CONFIG_FIPS_FMP_UFS) += last_file.o + +ccflags-y := -Idrivers/crypto/fmp diff --git a/drivers/scsi/ufs/fips-fmp-ufs.c b/drivers/scsi/ufs/fips-fmp-ufs.c index 525d1e82acc4..7e4991360905 100644 --- a/drivers/scsi/ufs/fips-fmp-ufs.c +++ b/drivers/scsi/ufs/fips-fmp-ufs.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,14 +25,12 @@ #include "ufshcd.h" #include "../scsi_priv.h" -#include "fips-fmp.h" - #define byte2word(b0, b1, b2, b3) \ ((unsigned int)(b0) << 24) | ((unsigned int)(b1) << 16) | ((unsigned int)(b2) << 8) | (b3) #define get_word(x, c) byte2word(((unsigned char *)(x) + 4 * (c))[0], ((unsigned char *)(x) + 4 * (c))[1], \ ((unsigned char *)(x) + 4 * (c))[2], ((unsigned char *)(x) + 4 * (c))[3]) -#define SF_OFFSET (20 * 1024) +#define SF_BLK_OFFSET (5) #define MAX_SCAN_PART (50) struct ufs_fmp_work { @@ -45,14 +44,13 @@ struct ufs_fmp_work { struct ufshcd_sg_entry *prd_table; struct ufshcd_sg_entry *ucd_prdt_ptr_st; -static int ufs_fmp_init(struct platform_device *pdev, uint32_t mode) +static int ufs_fmp_init(struct device *dev, uint32_t mode) { - struct device *dev = &pdev->dev; struct ufs_hba *hba; struct ufs_fmp_work *work; struct Scsi_Host *host; - work = platform_get_drvdata(pdev); + work = dev_get_drvdata(dev); if (!work) { dev_err(dev, "Fail to get work from platform device\n"); return -ENODEV; @@ -70,15 +68,14 @@ static int ufs_fmp_init(struct platform_device *pdev, uint32_t mode) return 0; } -static int ufs_fmp_set_key(struct platform_device *pdev, uint32_t mode, uint8_t *key, uint32_t key_len) +static int ufs_fmp_set_key(struct device *dev, uint32_t mode, uint8_t *key, uint32_t key_len) { - struct device *dev = &pdev->dev; struct ufs_hba *hba; struct ufs_fmp_work *work; struct Scsi_Host *host; struct ufshcd_sg_entry *prd_table; - work = platform_get_drvdata(pdev); + work = dev_get_drvdata(dev); if (!work) { dev_err(dev, "Fail to get work from platform device\n"); return -ENODEV; @@ -204,18 +201,18 @@ static int ufs_fmp_set_key(struct platform_device *pdev, uint32_t mode, uint8_t return -EINVAL; } + dev_info(dev, "%s: ufs fmp key set is done.\n", __func__); return 0; } -static int ufs_fmp_set_iv(struct platform_device *pdev, uint32_t mode, uint8_t *iv, uint32_t iv_len) +static int ufs_fmp_set_iv(struct device *dev, uint32_t mode, uint8_t *iv, uint32_t iv_len) { - struct device *dev = &pdev->dev; struct ufs_hba *hba; struct ufs_fmp_work *work; struct Scsi_Host *host; struct ufshcd_sg_entry *prd_table; - work = platform_get_drvdata(pdev); + work = dev_get_drvdata(dev); if (!work) { dev_err(dev, "Fail to get work from platform device\n"); return -ENODEV; @@ -288,49 +285,39 @@ static dev_t find_devt_for_selftest(void) return (dev_t)0; } -static int ufs_fmp_run(struct platform_device *pdev, uint32_t mode, uint8_t *data, uint32_t len) +static int ufs_fmp_run(struct device *dev, uint32_t mode, uint8_t *data, + uint32_t len, uint32_t write) { - int write; struct ufs_hba *hba; struct ufs_fmp_work *work; struct Scsi_Host *host; - struct device *dev = &pdev->dev; static struct buffer_head *bh; - work = platform_get_drvdata(pdev); + work = dev_get_drvdata(dev); if (!work) { dev_err(dev, "Fail to get work from platform device\n"); return -ENODEV; } host = work->host; hba = shost_priv(host); + hba->self_test_mode = mode; - if ((mode == XTS_MODE) || (mode == CBC_MODE)) - write = 1; - else if (mode == BYPASS_MODE) - write = 0; - else { - dev_err(dev, "Fail to run FMP due to abnormal mode = %d\n", mode); - return -EINVAL; - } - hba->self_test = mode; - - bh = __getblk(work->bdev, work->sector, UFS_BLOCK_SIZE); + bh = __getblk(work->bdev, work->sector, FMP_BLK_SIZE); if (!bh) { dev_err(dev, "Fail to get block from bdev\n"); - hba->self_test = 0; return -ENODEV; } + hba->self_test_bh = bh; get_bh(bh); - if (write) { + if (write == WRITE_MODE) { memcpy(bh->b_data, data, len); bh->b_state &= ~(1 << BH_Uptodate); bh->b_state &= ~(1 << BH_Lock); ll_rw_block(WRITE_FLUSH_FUA, 1, &bh); wait_on_buffer(bh); - memset(bh->b_data, 0, UFS_BLOCK_SIZE); + memset(bh->b_data, 0, FMP_BLK_SIZE); } else { bh->b_state &= ~(1 << BH_Uptodate); bh->b_state &= ~(1 << BH_Lock); @@ -339,9 +326,11 @@ static int ufs_fmp_run(struct platform_device *pdev, uint32_t mode, uint8_t *dat memcpy(data, bh->b_data, len); } - hba->self_test = 0; put_bh(bh); + hba->self_test_mode = 0; + hba->self_test_bh = NULL; + return 0; } @@ -353,7 +342,7 @@ static int ufs_fmp_exit(void) return 0; } -struct fips_fmp_ops fips_fmp_ufs_ops = { +struct fips_fmp_ops fips_fmp_fops = { .init = ufs_fmp_init, .set_key = ufs_fmp_set_key, .set_iv = ufs_fmp_set_iv, @@ -361,15 +350,21 @@ struct fips_fmp_ops fips_fmp_ufs_ops = { .exit = ufs_fmp_exit, }; -int fips_fmp_init(struct platform_device *pdev) +int fips_fmp_init(struct device *dev) { - struct device *dev = &pdev->dev; struct ufs_fmp_work *work; struct device_node *dev_node; struct platform_device *pdev_ufs; + struct device *dev_ufs; struct ufs_hba *hba; struct Scsi_Host *host; + struct inode *inode; struct scsi_device *sdev; + struct super_block *sb; + unsigned long blocksize; + unsigned char blocksize_bits; + + sector_t self_test_block; fmode_t fmode = FMODE_WRITE | FMODE_READ; work = kmalloc(sizeof(*work), GFP_KERNEL); @@ -390,14 +385,15 @@ int fips_fmp_init(struct platform_device *pdev) goto out; } - hba = platform_get_drvdata(pdev_ufs); + dev_ufs = &pdev_ufs->dev; + hba = dev_get_drvdata(dev_ufs); if (!hba) { - dev_err(dev, "Fail to find hba from pdev,\n"); + dev_err(dev, "Fail to find hba from dev\n"); goto out; } host = hba->host; - sdev = to_scsi_device(&pdev_ufs->dev); + sdev = to_scsi_device(dev_ufs); work->host = host; work->sdev = sdev; @@ -412,9 +408,14 @@ int fips_fmp_init(struct platform_device *pdev) dev_err(dev, "Fail to open block device\n"); return -ENODEV; } - work->sector = (sector_t)((i_size_read(work->bdev->bd_inode) - SF_OFFSET) / UFS_BLOCK_SIZE); - - platform_set_drvdata(pdev, work); + inode = work->bdev->bd_inode; + sb = inode->i_sb; + blocksize = sb->s_blocksize; + blocksize_bits = sb->s_blocksize_bits; + self_test_block = (i_size_read(inode) - (blocksize * SF_BLK_OFFSET)) >> blocksize_bits; + work->sector = self_test_block; + + dev_set_drvdata(dev, work); return 0; diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c index 0fd35faf72b8..314255554f88 100644 --- a/drivers/scsi/ufs/ufs_quirks.c +++ b/drivers/scsi/ufs/ufs_quirks.c @@ -1,142 +1,148 @@ -/* - * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "ufshcd.h" -#include "ufs_quirks.h" - -#ifndef UFS_VENDOR_ID_SAMSUNG -#define UFS_VENDOR_ID_SAMSUNG 0x1ce -#endif - -#ifndef UFS_VENDOR_ID_TOSHIBA -#define UFS_VENDOR_ID_TOSHIBA 0x198 -#endif - -static struct ufs_card_fix ufs_fixups[] = { - /* UFS cards deviations table */ - UFS_FIX(UFS_VENDOR_ID_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_BROKEN_LINEREST), - END_FIX -}; - -int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data) -{ - int err; - u8 model_index; - u8 serial_num_index; - u8 serial_num_buf[6]; /* samsung spec : use only 6 bytes of serial number string descriptor */ - u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; - u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; - u8 health_buf[QUERY_DESC_HEALTH_MAX_SIZE]; - bool ascii_type; - - err = ufshcd_read_device_desc(hba, desc_buf, - QUERY_DESC_DEVICE_MAX_SIZE); - if (err) - goto out; - - err = ufshcd_read_health_desc(hba, health_buf, - QUERY_DESC_HEALTH_MAX_SIZE); - if (err) - printk("%s: DEVICE_HEALTH desc read fail, err = %d\n", __FUNCTION__, err); - - /* getting Life Time at Device Health DESC*/ - card_data->lifetime = health_buf[HEALTH_DEVICE_DESC_PARAM_LIFETIMEA]; - - /* - * getting vendor (manufacturerID) and Bank Index in big endian - * format - */ - card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | - desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; - - hba->manufacturer_id = card_data->wmanufacturerid; - hba->lifetime = card_data->lifetime; - - model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; - - memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); - err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, - QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); - if (err) - goto out; - - str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), - min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], - MAX_MODEL_LEN)); - /* Null terminate the model string */ - card_data->model[MAX_MODEL_LEN] = '\0'; - - /* make unique id with MANUFACTURE DATE & SERIAL NUMBER */ - serial_num_index = desc_buf[DEVICE_DESC_PARAM_SN]; - memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); - - /*Samsung device use UTF16*/ - if ((hba->manufacturer_id == UFS_VENDOR_ID_SAMSUNG) || (hba->manufacturer_id == UFS_VENDOR_ID_TOSHIBA)) - ascii_type = UTF16_STD; - else - ascii_type = ASCII_STD; - - err = ufshcd_read_string_desc(hba, serial_num_index, str_desc_buf, - QUERY_DESC_STRING_MAX_SIZE, ascii_type); - - if (err) - goto out; - str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; - - memset(serial_num_buf, 0, sizeof(serial_num_buf)); - memcpy(serial_num_buf, str_desc_buf + QUERY_DESC_HDR_SIZE, sizeof(serial_num_buf)); - - memset(hba->unique_number, 0, sizeof(hba->unique_number)); - sprintf(hba->unique_number, "%02x%02x%02x%02x%02x%02x%02x%02x", desc_buf[DEVICE_DESC_PARAM_MANF_DATE], desc_buf[DEVICE_DESC_PARAM_MANF_DATE+1], serial_num_buf[0], serial_num_buf[1], serial_num_buf[2], serial_num_buf[3], serial_num_buf[4], serial_num_buf[5]); - - /* Null terminate the unique number string */ - hba->unique_number[UFS_UNIQUE_NUMBER_LEN - 1] = '\0'; - - printk("%s: UNIQUE NUMBER = %s , Lifetime: 0x%02x \n", __FUNCTION__, hba->unique_number, health_buf[3]<<4|health_buf[4]); - -out: - return err; -} - -void ufs_advertise_fixup_device(struct ufs_hba *hba) -{ - int err; - struct ufs_card_fix *f; - struct ufs_card_info card_data; - - card_data.wmanufacturerid = 0; - card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); - if (!card_data.model) - goto out; - - /* get device data*/ - err = ufs_get_device_info(hba, &card_data); - if (err) { - dev_err(hba->dev, "%s: Failed getting device info\n", __func__); - goto out; - } - - for (f = ufs_fixups; f->quirk; f++) { - /* if same wmanufacturerid */ - if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || - (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && - /* and same model */ - (STR_PRFX_EQUAL(f->card.model, card_data.model) || - !strcmp(f->card.model, UFS_ANY_MODEL))) - /* update quirks */ - hba->dev_quirks |= f->quirk; - } -out: - kfree(card_data.model); -} +/* + * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "ufshcd.h" +#include "ufs_quirks.h" + +#ifndef UFS_VENDOR_ID_SAMSUNG +#define UFS_VENDOR_ID_SAMSUNG 0x1ce +#endif + +#ifndef UFS_VENDOR_ID_TOSHIBA +#define UFS_VENDOR_ID_TOSHIBA 0x198 +#endif + +#ifndef UFS_VENDOR_ID_HYNIX +#define UFS_VENDOR_ID_HYNIX 0x1ad +#endif + +static struct ufs_card_fix ufs_fixups[] = { + /* UFS cards deviations table */ + UFS_FIX(UFS_VENDOR_ID_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_BROKEN_LINEREST), + END_FIX +}; + +int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data) +{ + int err; + u8 model_index; + u8 serial_num_index; + u8 serial_num_buf[6]; /* samsung spec : use only 6 bytes of serial number string descriptor */ + u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; + u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; + u8 health_buf[QUERY_DESC_HEALTH_MAX_SIZE]; + bool ascii_type; + + err = ufshcd_read_device_desc(hba, desc_buf, + QUERY_DESC_DEVICE_MAX_SIZE); + if (err) + goto out; + + err = ufshcd_read_health_desc(hba, health_buf, + QUERY_DESC_HEALTH_MAX_SIZE); + if (err) + printk("%s: DEVICE_HEALTH desc read fail, err = %d\n", __FUNCTION__, err); + + /* getting Life Time at Device Health DESC*/ + card_data->lifetime = health_buf[HEALTH_DEVICE_DESC_PARAM_LIFETIMEA]; + + /* + * getting vendor (manufacturerID) and Bank Index in big endian + * format + */ + card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + + hba->manufacturer_id = card_data->wmanufacturerid; + hba->lifetime = card_data->lifetime; + + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + + memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); + err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, + QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); + if (err) + goto out; + + str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; + strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), + min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], + MAX_MODEL_LEN)); + /* Null terminate the model string */ + card_data->model[MAX_MODEL_LEN] = '\0'; + + /* make unique id with MANUFACTURE DATE & SERIAL NUMBER */ + serial_num_index = desc_buf[DEVICE_DESC_PARAM_SN]; + memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); + + /*Samsung device use UTF16*/ + if ((hba->manufacturer_id == UFS_VENDOR_ID_SAMSUNG) || + (hba->manufacturer_id == UFS_VENDOR_ID_TOSHIBA) || + (hba->manufacturer_id == UFS_VENDOR_ID_HYNIX)) + ascii_type = UTF16_STD; + else + ascii_type = ASCII_STD; + + err = ufshcd_read_string_desc(hba, serial_num_index, str_desc_buf, + QUERY_DESC_STRING_MAX_SIZE, ascii_type); + + if (err) + goto out; + str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; + + memset(serial_num_buf, 0, sizeof(serial_num_buf)); + memcpy(serial_num_buf, str_desc_buf + QUERY_DESC_HDR_SIZE, sizeof(serial_num_buf)); + + memset(hba->unique_number, 0, sizeof(hba->unique_number)); + sprintf(hba->unique_number, "%02x%02x%02x%02x%02x%02x%02x%02x", desc_buf[DEVICE_DESC_PARAM_MANF_DATE], desc_buf[DEVICE_DESC_PARAM_MANF_DATE+1], serial_num_buf[0], serial_num_buf[1], serial_num_buf[2], serial_num_buf[3], serial_num_buf[4], serial_num_buf[5]); + + /* Null terminate the unique number string */ + hba->unique_number[UFS_UNIQUE_NUMBER_LEN - 1] = '\0'; + + printk("%s: UNIQUE NUMBER = %s , Lifetime: 0x%02x \n", __FUNCTION__, hba->unique_number, health_buf[3]<<4|health_buf[4]); + +out: + return err; +} + +void ufs_advertise_fixup_device(struct ufs_hba *hba) +{ + int err; + struct ufs_card_fix *f; + struct ufs_card_info card_data; + + card_data.wmanufacturerid = 0; + card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); + if (!card_data.model) + goto out; + + /* get device data*/ + err = ufs_get_device_info(hba, &card_data); + if (err) { + dev_err(hba->dev, "%s: Failed getting device info\n", __func__); + goto out; + } + + for (f = ufs_fixups; f->quirk; f++) { + /* if same wmanufacturerid */ + if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || + (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && + /* and same model */ + (STR_PRFX_EQUAL(f->card.model, card_data.model) || + !strcmp(f->card.model, UFS_ANY_MODEL))) + /* update quirks */ + hba->dev_quirks |= f->quirk; + } +out: + kfree(card_data.model); +} diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0a2e2069266b..af134099dc30 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -43,6 +43,9 @@ #if defined(CONFIG_UFS_FMP_DM_CRYPT) #include #endif +#if defined(CONFIG_FIPS_FMP_UFS) +#include +#endif #include #include "ufshcd.h" @@ -50,12 +53,8 @@ #include "ufs-exynos.h" #include "ufs_quirks.h" -#if defined(CONFIG_FIPS_FMP_UFS) -#include "fips-fmp-info.h" -#endif - #if defined(CONFIG_UFS_FMP_ECRYPT_FS) -#include "fmp_derive_iv.h" +#include #endif #define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ @@ -1186,10 +1185,18 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) hba->transferred_sector += prd_table[i].size; #if defined(CONFIG_UFS_FMP_DM_CRYPT) || defined(CONFIG_UFS_FMP_ECRYPT_FS) #if defined(CONFIG_UFS_FMP_ECRYPT_FS) - if(test_bit(PG_sensitive_data, &sg_page(sg)->flags)) { - sector_key |= UFS_FILE_ENCRYPTION_SECTOR_BEGIN; - } else + if (!((unsigned long)(sg_page(sg)->mapping) & 0x1)) { + if (sg_page(sg)->mapping && sg_page(sg)->mapping->key) { + if ((unsigned int)(sg_page(sg)->index) >= 2) + sector_key |= UFS_FILE_ENCRYPTION_SECTOR_BEGIN; + else + sector_key &= ~UFS_FILE_ENCRYPTION_SECTOR_BEGIN; + } else { + sector_key &= ~UFS_FILE_ENCRYPTION_SECTOR_BEGIN; + } + } else { sector_key &= ~UFS_FILE_ENCRYPTION_SECTOR_BEGIN; + } #endif if (sector_key == UFS_BYPASS_SECTOR_BEGIN) { SET_DAS(&prd_table[i], CLEAR); @@ -1315,8 +1322,7 @@ static int ufshcd_map_sg_st(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) cmd = lrbp->cmd; if (cmd->request->bio) { - sector_key = (hba->self_test != BYPASS_MODE)? UFS_ENCRYPTION_SECTOR_BEGIN : UFS_BYPASS_SECTOR_BEGIN; - cmd->request->bio->bi_sensitive_data = 0; + sector_key = (hba->self_test_mode != BYPASS_MODE)? UFS_ENCRYPTION_SECTOR_BEGIN : UFS_BYPASS_SECTOR_BEGIN; sector = cmd->request->bio->bi_sector; } @@ -1349,9 +1355,9 @@ static int ufshcd_map_sg_st(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) } else { if (sector_key & UFS_ENCRYPTION_SECTOR_BEGIN) { /* disk encryption */ /* AES algorithm selector */ - if (hba->self_test == XTS_MODE) + if (hba->self_test_mode == XTS_MODE) SET_FAS(&prd_table[i], AES_XTS); - else if (hba->self_test == CBC_MODE) + else if (hba->self_test_mode == CBC_MODE) SET_FAS(&prd_table[i], AES_CBC); if (prd_table_st->size == 32) @@ -1672,6 +1678,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) unsigned long flags; int tag; int err = 0; +#if defined(CONFIG_FIPS_FMP_UFS) + uint64_t self_test_bh; +#endif hba = shost_priv(host); @@ -1731,10 +1740,15 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) /* form UPIU before issuing the command */ ufshcd_compose_upiu(hba, lrbp); #if defined(CONFIG_FIPS_FMP_UFS) - if (hba->self_test) - err = ufshcd_map_sg_st(hba, lrbp); - else + if (cmd->request->bio) { + self_test_bh = (uint64_t)cmd->request->bio->bi_private; + if ((uint64_t)hba->self_test_bh && (self_test_bh == (uint64_t)hba->self_test_bh)) + err = ufshcd_map_sg_st(hba, lrbp); + else + err = ufshcd_map_sg(hba, lrbp); + } else { err = ufshcd_map_sg(hba, lrbp); + } #else err = ufshcd_map_sg(hba, lrbp); #endif diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 69a6c0a32dd0..182f1b51bcb4 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -514,7 +514,8 @@ struct ufs_hba { struct device_attribute bkops_en_attr; struct device_attribute capabilities_attr; - u32 self_test; + struct buffer_head *self_test_bh; + uint32_t self_test_mode; struct ufshcd_sg_entry *ucd_prdt_ptr_st; /* UFSHCI doesn't support DWORD size in UTRD */ diff --git a/drivers/sensorhub/atmel/factory/accel_bmi058.c b/drivers/sensorhub/atmel/factory/accel_bmi058.c index 495e99546eee..54b31b840d3b 100644 --- a/drivers/sensorhub/atmel/factory/accel_bmi058.c +++ b/drivers/sensorhub/atmel/factory/accel_bmi058.c @@ -45,7 +45,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -198,7 +198,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/accel_lsm330.c b/drivers/sensorhub/atmel/factory/accel_lsm330.c index 5065fe646b23..a7e12a8fde15 100644 --- a/drivers/sensorhub/atmel/factory/accel_lsm330.c +++ b/drivers/sensorhub/atmel/factory/accel_lsm330.c @@ -45,7 +45,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -148,7 +148,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/accel_mpu6050.c b/drivers/sensorhub/atmel/factory/accel_mpu6050.c index 0ec1091f4414..d2440e3eedf8 100644 --- a/drivers/sensorhub/atmel/factory/accel_mpu6050.c +++ b/drivers/sensorhub/atmel/factory/accel_mpu6050.c @@ -45,7 +45,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -148,7 +148,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/accel_mpu6500.c b/drivers/sensorhub/atmel/factory/accel_mpu6500.c index e4d7632f78c5..7c8421deeb18 100644 --- a/drivers/sensorhub/atmel/factory/accel_mpu6500.c +++ b/drivers/sensorhub/atmel/factory/accel_mpu6500.c @@ -67,7 +67,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -231,7 +231,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/gyro_bmi058.c b/drivers/sensorhub/atmel/factory/gyro_bmi058.c index 62769c94d338..24ed196a39d4 100644 --- a/drivers/sensorhub/atmel/factory/gyro_bmi058.c +++ b/drivers/sensorhub/atmel/factory/gyro_bmi058.c @@ -59,7 +59,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -101,7 +101,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/gyro_lsm330.c b/drivers/sensorhub/atmel/factory/gyro_lsm330.c index bcde89e3b250..d327fe61af80 100644 --- a/drivers/sensorhub/atmel/factory/gyro_lsm330.c +++ b/drivers/sensorhub/atmel/factory/gyro_lsm330.c @@ -45,7 +45,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -87,7 +87,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/gyro_mpu6050.c b/drivers/sensorhub/atmel/factory/gyro_mpu6050.c index dfb50b8885fe..412bbeefbec1 100644 --- a/drivers/sensorhub/atmel/factory/gyro_mpu6050.c +++ b/drivers/sensorhub/atmel/factory/gyro_mpu6050.c @@ -55,7 +55,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -97,7 +97,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/gyro_mpu6500.c b/drivers/sensorhub/atmel/factory/gyro_mpu6500.c index b7744f954228..08a4112e3fa1 100644 --- a/drivers/sensorhub/atmel/factory/gyro_mpu6500.c +++ b/drivers/sensorhub/atmel/factory/gyro_mpu6500.c @@ -80,7 +80,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -134,7 +134,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/magnetic_yas532.c b/drivers/sensorhub/atmel/factory/magnetic_yas532.c index 5abe53afd7f5..96d64bc5673f 100644 --- a/drivers/sensorhub/atmel/factory/magnetic_yas532.c +++ b/drivers/sensorhub/atmel/factory/magnetic_yas532.c @@ -32,7 +32,7 @@ int mag_open_hwoffset(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP] %s: filp_open failed\n", __func__); set_fs(old_fs); @@ -81,7 +81,7 @@ int mag_store_hwoffset(struct ssp_data *data) set_fs(KERNEL_DS); cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open hw_offset file\n", __func__); diff --git a/drivers/sensorhub/atmel/factory/pressure_bmp182.c b/drivers/sensorhub/atmel/factory/pressure_bmp182.c index 796a344f6e91..f9339d937734 100644 --- a/drivers/sensorhub/atmel/factory/pressure_bmp182.c +++ b/drivers/sensorhub/atmel/factory/pressure_bmp182.c @@ -59,7 +59,7 @@ int pressure_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { iErr = PTR_ERR(cal_filp); if (iErr != -ENOENT) diff --git a/drivers/sensorhub/atmel/factory/pressure_lps25h.c b/drivers/sensorhub/atmel/factory/pressure_lps25h.c index 1a80b9f38e90..79e052435a1a 100644 --- a/drivers/sensorhub/atmel/factory/pressure_lps25h.c +++ b/drivers/sensorhub/atmel/factory/pressure_lps25h.c @@ -55,7 +55,7 @@ int pressure_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { iErr = PTR_ERR(cal_filp); if (iErr != -ENOENT) diff --git a/drivers/sensorhub/atmel/factory/prox_cm36651.c b/drivers/sensorhub/atmel/factory/prox_cm36651.c index 85d7ef192629..5472e27d13ff 100644 --- a/drivers/sensorhub/atmel/factory/prox_cm36651.c +++ b/drivers/sensorhub/atmel/factory/prox_cm36651.c @@ -106,7 +106,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -158,7 +158,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/prox_max88005.c b/drivers/sensorhub/atmel/factory/prox_max88005.c index 16547bc394d0..e68e20ce3462 100644 --- a/drivers/sensorhub/atmel/factory/prox_max88005.c +++ b/drivers/sensorhub/atmel/factory/prox_max88005.c @@ -147,7 +147,7 @@ int proximity_open_lcd_ldi(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -186,7 +186,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -240,7 +240,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/atmel/factory/prox_max88920.c b/drivers/sensorhub/atmel/factory/prox_max88920.c index e6cc05ea35e2..4de54655b57d 100644 --- a/drivers/sensorhub/atmel/factory/prox_max88920.c +++ b/drivers/sensorhub/atmel/factory/prox_max88920.c @@ -188,7 +188,7 @@ int proximity_open_lcd_ldi(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -227,7 +227,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -286,7 +286,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/Kconfig b/drivers/sensorhub/brcm/Kconfig index 15194fcd72c8..4a0511f85290 100644 --- a/drivers/sensorhub/brcm/Kconfig +++ b/drivers/sensorhub/brcm/Kconfig @@ -308,11 +308,89 @@ config SENSORS_SSP_SX9306 To compile this driver as a module, choose M here: the module will be called ssp. +config SENSORS_SSP_SX9306 + tristate "SX9306 Grip sensor" + default n + depends on SPI + help + sx9306 file for factory test in ssp driver. + If you say yes here you get sx9306 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SX9310 + depends on I2C + tristate "SX9310 driver" + default n + help + Say Y here if you use sx9310. + This option enables grip sensors using + SemTech sx9310 device driver. + Say N here if you do not use sx9310. + +config SENSORS_SX9310_INIT_TOUCH_THRESHOLD + int "SX9310 Grip sensor threshold for init touch" + depends on SENSORS_SX9310 + default "3000" + help + This value is the standard of init touch using + SemTech sx9310 device driver. + +config SENSORS_SX9310_NORMAL_TOUCH_THRESHOLD + int "SX9310 Grip sensor threshold for normal touch" + depends on SENSORS_SX9310 + default "17" + help + This value is the standard of normal touch using + SemTech sx9310 device driver. + +config SENSORS_SX9310_CP_LDO_CONTROL + depends on SENSORS_SX9310 + tristate "SX9310 driver" + default n + help + Say Y here if you control grip power in cp. + Say N here if you do not use grip power in cp. + config SENSORS_SSP_INTERRUPT_GYRO_SENSOR tristate "Sensors ssp interrpt gyro" default n depends on SPI help If you want to use interrupt gyro data, it should be set. - + +config SENSORS_SSP_VLTE + tristate "V Proejct" + default n + depends on SPI + help + Binary file for ssp driver. + If you say yes here you get V project support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_NOBLELTE + tristate "NOBLE Proejct" + default n + depends on SPI + help + Binary file for ssp driver. + If you say yes here you get NOBLE project support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_ZENLTE + tristate "ZEN Proejct" + default n + depends on SPI + help + Binary file for ssp driver. + If you say yes here you get ZEN project support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + source "drivers/sensorhub/brcm/max_notchfilter/Kconfig" diff --git a/drivers/sensorhub/brcm/Makefile b/drivers/sensorhub/brcm/Makefile index c61c5d265fbb..fdd6095f2de7 100644 --- a/drivers/sensorhub/brcm/Makefile +++ b/drivers/sensorhub/brcm/Makefile @@ -29,10 +29,11 @@ obj-$(CONFIG_SENSORS_SSP_MOBEAM) += factory/barcode_emul_tmg3992.o obj-$(CONFIG_SENSORS_SSP_SX9306) += factory/grip_sx9306.o obj-$(CONFIG_SENSORS_SSP_SENSORHUB) += ssp_sensorhub.o ssp_misc.o -obj-$(CONFIG_SENSORS_MAX86900) += max86900.o -obj-$(CONFIG_SENSORS_MAX86902) += max86902.o -obj-$(CONFIG_SENSORS_MAX_NOTCHFILTER) += max_notchfilter/ -obj-$(CONFIG_SENSORS_ADPD142) += adpd142.o +obj-$(CONFIG_SENSORS_MAX86900) += max86900.o +obj-$(CONFIG_SENSORS_MAX86902) += max86902.o +obj-$(CONFIG_SENSORS_MAX_NOTCHFILTER) += max_notchfilter/ +obj-$(CONFIG_SENSORS_ADPD142) += adpd142.o +obj-$(CONFIG_SENSORS_SX9310) += sx9310.o obj-$(CONFIG_SENSORS_SSP_BBD) += ssp_bbd.o factory/mcu_bcm4773.o obj-$(CONFIG_SENSORS_SSP_BBD) += bbdpl/ diff --git a/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file.h b/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file.h index 2863eb95046b..4fa22566ff9d 100644 --- a/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file.h +++ b/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file.h @@ -1,6 +1,6 @@ "\n" -"\n" -"\n" +"\n" +"\n" "\n" "\n" "\n" @@ -8,32 +8,32 @@ "\n" "\n" "\n" -"\n" diff --git a/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file_V.h b/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file_V.h new file mode 100644 index 000000000000..d7933af02b17 --- /dev/null +++ b/drivers/sensorhub/brcm/bbdpl/bbd_new_patch_file_V.h @@ -0,0 +1,12158 @@ +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"\n" diff --git a/drivers/sensorhub/brcm/bbdpl/bbd_patch.c b/drivers/sensorhub/brcm/bbdpl/bbd_patch.c index 1921216c76c5..b1ac260cdedc 100644 --- a/drivers/sensorhub/brcm/bbdpl/bbd_patch.c +++ b/drivers/sensorhub/brcm/bbdpl/bbd_patch.c @@ -28,11 +28,18 @@ static unsigned char bbd_patch[] = }; #ifdef SUPPORT_MCU_HOST_WAKE +#ifdef CONFIG_SENSORS_SSP_VLTE +static unsigned char bbd_new_patch[] = +{ +#include "bbd_new_patch_file_V.h" +}; +#else static unsigned char bbd_new_patch[] = { #include "bbd_new_patch_file.h" }; #endif +#endif void bbd_patch_init_vars(struct bbd_device *dev, int* result) { diff --git a/drivers/sensorhub/brcm/bbdpl/bbd_patch_file.h b/drivers/sensorhub/brcm/bbdpl/bbd_patch_file.h index 800821e053ca..4c225e31031f 100644 --- a/drivers/sensorhub/brcm/bbdpl/bbd_patch_file.h +++ b/drivers/sensorhub/brcm/bbdpl/bbd_patch_file.h @@ -1,6 +1,6 @@ "\n" -"\n" -"\n" +"\n" +"\n" "\n" "\n" "\n" @@ -8,32 +8,32 @@ "\n" "\n" "\n" -"\n" +"3F2405F5B910F6FF80DCF5FF0FF9FF1FFDFF2F03FDFF3F\n" +"04FDFF4F05FD7CDB05FE1601F10DF2063218D20A10FDFF\n" +"4009F1E1E8FDFF4009F5FF0EF9FF1EFDFF2E03FDFF3E04\n" +"FDFF4E05FD7DDB05FE3001311782903F8E02B554F00510\n" +"54BC850070BC853E1201346184F11734120234216AF212\n" +"023432F393215E8DD8079EFF74131007E9C282003BC382\n" +"001A0C1264043001F112000C12C80452F20C21E252F30C\n" +"1E202C522002F412E03D0C23800C30A00124000F717308\n" +"080BF0040A98C18500B4C1D02002A00C408C20431BB704\n" +"61028E062C5412CC20F20AE844F11400F04382003CC97B\n" +"78E818040000408200EFBEADDE>\n" diff --git a/drivers/sensorhub/brcm/bbdpl/bbd_sysfs.c b/drivers/sensorhub/brcm/bbdpl/bbd_sysfs.c index a4b1d3fad07b..894fa8b97b25 100644 --- a/drivers/sensorhub/brcm/bbdpl/bbd_sysfs.c +++ b/drivers/sensorhub/brcm/bbdpl/bbd_sysfs.c @@ -277,18 +277,18 @@ static ssize_t show_sysfs_bbd_ssi_trace(struct device *dev, p[10],p[11],p[12], p[13]); } -static DEVICE_ATTR(BBD, 0222, NULL, store_sysfs_BBD_control); -static DEVICE_ATTR(ESW, 0222, NULL, store_sysfs_ESW_control); -static DEVICE_ATTR(DEV, 0222, NULL, store_sysfs_DEV_control); -static DEVICE_ATTR(debug, 0666, show_sysfs_bbd_debug,store_sysfs_bbd_debug); -static DEVICE_ATTR(baud, 0666, show_sysfs_bbd_baud, store_sysfs_bbd_baud); -static DEVICE_ATTR(shmd, 0444, show_sysfs_bbd_shmd, NULL); -static DEVICE_ATTR(pl, 0444, show_sysfs_bbd_pl, NULL); -static DEVICE_ATTR(buf, 0444, show_sysfs_bbd_buf, NULL); -static DEVICE_ATTR(passthru,0444, show_sysfs_bbd_passthru, NULL); -static DEVICE_ATTR(ssi_xfer, 0444, show_sysfs_bbd_ssi_xfer, NULL); -static DEVICE_ATTR(ssi_count, 0444, show_sysfs_bbd_ssi_count, NULL); -static DEVICE_ATTR(ssi_trace, 0444, show_sysfs_bbd_ssi_trace, NULL); +static DEVICE_ATTR(BBD, 0220, NULL, store_sysfs_BBD_control); +static DEVICE_ATTR(ESW, 0220, NULL, store_sysfs_ESW_control); +static DEVICE_ATTR(DEV, 0220, NULL, store_sysfs_DEV_control); +static DEVICE_ATTR(debug, 0660, show_sysfs_bbd_debug,store_sysfs_bbd_debug); +static DEVICE_ATTR(baud, 0660, show_sysfs_bbd_baud, store_sysfs_bbd_baud); +static DEVICE_ATTR(shmd, 0440, show_sysfs_bbd_shmd, NULL); +static DEVICE_ATTR(pl, 0440, show_sysfs_bbd_pl, NULL); +static DEVICE_ATTR(buf, 0440, show_sysfs_bbd_buf, NULL); +static DEVICE_ATTR(passthru,0440, show_sysfs_bbd_passthru, NULL); +static DEVICE_ATTR(ssi_xfer, 0440, show_sysfs_bbd_ssi_xfer, NULL); +static DEVICE_ATTR(ssi_count, 0440, show_sysfs_bbd_ssi_count, NULL); +static DEVICE_ATTR(ssi_trace, 0440, show_sysfs_bbd_ssi_trace, NULL); static struct attribute *bbd_esw_attributes[] = { &dev_attr_BBD.attr, diff --git a/drivers/sensorhub/brcm/bbdpl/bcm_gps_spi.c b/drivers/sensorhub/brcm/bbdpl/bcm_gps_spi.c index 5ac389fab658..44ce6df34f85 100644 --- a/drivers/sensorhub/brcm/bbdpl/bcm_gps_spi.c +++ b/drivers/sensorhub/brcm/bbdpl/bcm_gps_spi.c @@ -1198,9 +1198,10 @@ static void bcm4773_rxtx_work( struct work_struct *work ) loop_count++; if (loop_count >= 100) { - if ((loop_count % 100) == 0) { + if ((loop_count % 300) == 0) { printk("[SSPBBD]: Warning! looping more than %d in a run. status = %d, pending = %d. Enforcing SSI dump \n", loop_count, status, pending); ssi_dbg = true; + break; } else ssi_dbg = false; diff --git a/drivers/sensorhub/brcm/factory/accel_bmi058.c b/drivers/sensorhub/brcm/factory/accel_bmi058.c index cdbbc0d52c96..9bb0a3bfad23 100644 --- a/drivers/sensorhub/brcm/factory/accel_bmi058.c +++ b/drivers/sensorhub/brcm/factory/accel_bmi058.c @@ -50,7 +50,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -196,7 +196,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/accel_icm20610.c b/drivers/sensorhub/brcm/factory/accel_icm20610.c index 3edabb6b1d08..0ada6d4678d5 100644 --- a/drivers/sensorhub/brcm/factory/accel_icm20610.c +++ b/drivers/sensorhub/brcm/factory/accel_icm20610.c @@ -51,7 +51,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -201,7 +201,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/accel_k330.c b/drivers/sensorhub/brcm/factory/accel_k330.c index 74a0fd7a2bd5..168a8d565350 100644 --- a/drivers/sensorhub/brcm/factory/accel_k330.c +++ b/drivers/sensorhub/brcm/factory/accel_k330.c @@ -50,7 +50,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -158,7 +158,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/accel_k6ds3tr.c b/drivers/sensorhub/brcm/factory/accel_k6ds3tr.c index 4ea573eca26d..a615f828c36a 100644 --- a/drivers/sensorhub/brcm/factory/accel_k6ds3tr.c +++ b/drivers/sensorhub/brcm/factory/accel_k6ds3tr.c @@ -51,7 +51,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -201,7 +201,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/accel_mpu6050.c b/drivers/sensorhub/brcm/factory/accel_mpu6050.c index 123fbae4f156..87657883f600 100644 --- a/drivers/sensorhub/brcm/factory/accel_mpu6050.c +++ b/drivers/sensorhub/brcm/factory/accel_mpu6050.c @@ -45,7 +45,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -148,7 +148,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/accel_mpu6500.c b/drivers/sensorhub/brcm/factory/accel_mpu6500.c index 745ad8529747..ed0a805d6ab6 100644 --- a/drivers/sensorhub/brcm/factory/accel_mpu6500.c +++ b/drivers/sensorhub/brcm/factory/accel_mpu6500.c @@ -65,7 +65,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -215,7 +215,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/grip_sx9306.c b/drivers/sensorhub/brcm/factory/grip_sx9306.c index 776183a93e97..a0f4ecbabacc 100644 --- a/drivers/sensorhub/brcm/factory/grip_sx9306.c +++ b/drivers/sensorhub/brcm/factory/grip_sx9306.c @@ -82,7 +82,7 @@ static int get_temp(void) old_fs = get_fs(); set_fs(KERNEL_DS); - filp = filp_open(TEMP_FILE_PATH, O_RDONLY, + filp = filp_open(TEMP_FILE_PATH, O_RDONLY | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(filp)) { ret = PTR_ERR(filp); @@ -220,7 +220,7 @@ void open_grip_caldata(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { ret = PTR_ERR(cal_filp); @@ -262,7 +262,7 @@ void open_grip_caldata(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(SLOPE_FILE_PATH, O_RDONLY, + cal_filp = filp_open(SLOPE_FILE_PATH, O_RDONLY | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { ret = PTR_ERR(cal_filp); @@ -298,7 +298,7 @@ void open_grip_caldata(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(TEMP_CAL_FILE_PATH, O_RDONLY, + cal_filp = filp_open(TEMP_CAL_FILE_PATH, O_RDONLY | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { ret = PTR_ERR(cal_filp); @@ -443,7 +443,7 @@ static int get_grip_calibration(struct ssp_data *data) set_fs(KERNEL_DS); cal_filp = filp_open(TEMP_CAL_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open temp_cal file\n", @@ -630,7 +630,7 @@ static int save_caldata(struct ssp_data *data) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", @@ -934,7 +934,7 @@ static ssize_t slope_store(struct device *dev, set_fs(KERNEL_DS); cal_filp = filp_open(SLOPE_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC | O_NOFOLLOW, S_IRUGO | S_IWUSR | S_IWGRP); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open slope file\n", diff --git a/drivers/sensorhub/brcm/factory/gyro_bmi058.c b/drivers/sensorhub/brcm/factory/gyro_bmi058.c index 63e55d228b98..25c6491e58da 100644 --- a/drivers/sensorhub/brcm/factory/gyro_bmi058.c +++ b/drivers/sensorhub/brcm/factory/gyro_bmi058.c @@ -59,7 +59,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -101,7 +101,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/gyro_icm20610.c b/drivers/sensorhub/brcm/factory/gyro_icm20610.c index 37126a0ccb34..9e52a99457e8 100644 --- a/drivers/sensorhub/brcm/factory/gyro_icm20610.c +++ b/drivers/sensorhub/brcm/factory/gyro_icm20610.c @@ -56,7 +56,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -98,7 +98,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/gyro_k330.c b/drivers/sensorhub/brcm/factory/gyro_k330.c index 77edbccbcc8b..0a094008350b 100644 --- a/drivers/sensorhub/brcm/factory/gyro_k330.c +++ b/drivers/sensorhub/brcm/factory/gyro_k330.c @@ -45,7 +45,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -87,7 +87,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/gyro_k6ds3tr.c b/drivers/sensorhub/brcm/factory/gyro_k6ds3tr.c index d042ae91c4ad..fcdfc3074ea7 100644 --- a/drivers/sensorhub/brcm/factory/gyro_k6ds3tr.c +++ b/drivers/sensorhub/brcm/factory/gyro_k6ds3tr.c @@ -39,6 +39,10 @@ #define DEF_SQRT_SCALE_FOR_RMS (100) #define GYRO_LIB_DL_FAIL 9990 +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) +#endif + static ssize_t gyro_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -60,7 +64,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -102,7 +106,7 @@ int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); @@ -299,7 +303,7 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, int i = 0, j = 0, total_count = 0, ret_val = 0, gyro_lib_dl_fail = 0; long avg[3] = {0,}, rms[3] = {0,}; int gyro_bias[3] = {0,}, gyro_rms[3] = {0,}; - s16 shift_ratio[3] = {0,}; + s16 shift_ratio[3] = {0,}; //self_diff value s16 iCalData[3] = {0,}; char a_name[3][2] = { "X", "Y", "Z" }; int iRet = 0; @@ -309,7 +313,11 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, int fifo_ret = 0; int cal_ret = 0; struct ssp_data *data = dev_get_drvdata(dev); - + s16 st_zro[3] = {0, }; + s16 st_bias[3] = {0, }; + int gyro_fifo_avg[3] = {0,}, gyro_self_zro[3] = {0,}; + int gyro_self_bias[3] = {0,}, gyro_self_diff[3] = {0,}; + struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); @@ -372,17 +380,51 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, (chTempBuf[34] << 16) + (chTempBuf[33] << 8) + chTempBuf[32]); + + st_zro[0] = (s16)((chTempBuf[25] << 8) + + chTempBuf[24]); + st_zro[1] = (s16)((chTempBuf[27] << 8) + + chTempBuf[26]); + st_zro[2] = (s16)((chTempBuf[29] << 8) + + chTempBuf[28]); + + st_bias[0] = (s16)((chTempBuf[31] << 8) + + chTempBuf[30]); + st_bias[1] = (s16)((chTempBuf[33] << 8) + + chTempBuf[32]); + st_bias[2] = (s16)((chTempBuf[35] << 8) + + chTempBuf[34]); + pr_info("[SSP] init: %d, total cnt: %d\n", initialized, total_count); pr_info("[SSP] hw_result: %d, %d, %d, %d\n", hw_result, shift_ratio[0], shift_ratio[1], shift_ratio[2]); pr_info("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]); pr_info("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]); - if (total_count == 0) { - pr_err("[SSP] %s, total_count is 0. goto exit\n", __func__); + //FIFO ZRO check pass / fail + gyro_fifo_avg[0] = avg[0] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_fifo_avg[1] = avg[1] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_fifo_avg[2] = avg[2] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + // ZRO self test + gyro_self_zro[0] = st_zro[0] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_zro[1] = st_zro[1] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_zro[2] = st_zro[2] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + //bias + gyro_self_bias[0] = st_bias[0] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_bias[1] = st_bias[1] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_bias[2] = st_bias[2] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + //diff = bias - ZRO + gyro_self_diff[0] = shift_ratio[0] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_diff[1] = shift_ratio[1] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + gyro_self_diff[2] = shift_ratio[2] * DEF_GYRO_SENS / DEF_SCALE_FOR_FLOAT; + + if (total_count != 128) { + pr_err("[SSP] %s, total_count is not 128. goto exit\n", __func__); ret_val = 2; goto exit; } + else + cal_ret = fifo_ret = 1; if (hw_result < 0) { pr_err("[SSP] %s - hw selftest fail(%d), sw selftest skip\n", @@ -393,6 +435,7 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, pr_err("[SSP] %s - gyro lib download fail\n", __func__); gyro_lib_dl_fail = 1; } else { +/* ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", __func__, shift_ratio[0] / 10, @@ -402,11 +445,18 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, shift_ratio[0] / 10, shift_ratio[1] / 10, shift_ratio[2] / 10); +*/ + ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", __func__, gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); + return sprintf(buf, "%d,%d,%d\n", gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); } } - //gyro_bias[0] = (avg[0] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; - //gyro_bias[1] = (avg[1] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; - //gyro_bias[2] = (avg[2] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS; + + // AVG value range test +/- 40 + if( (ABS(gyro_fifo_avg[0]) > 40) || (ABS(gyro_fifo_avg[1]) > 40) || (ABS(gyro_fifo_avg[2]) > 40) ) + { + ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", __func__, gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2]); + return sprintf(buf, "%d,%d,%d\n", gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2]); + } // STMICRO gyro_bias[0] = avg[0] * DEF_GYRO_SENS; @@ -447,16 +497,7 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, (long)rms[0] / total_count, (long)rms[1] / total_count, (long)rms[2] / total_count); } -/* - for (j = 0; j < 3; j++) { - if (unlikely(rms[j] / total_count > DEF_RMS_THRESH)) { - pr_err("[SSP] %s-Gyro rms (%ld) exceeded threshold " - "(threshold = %d LSB)\n", a_name[j], - rms[j] / total_count, DEF_RMS_THRESH); - ret_val |= 1 << (7 + j); - } - } -*/ + for (i = 0; i < 3; i++) { if (rms[i] > 10000) { temp = @@ -498,10 +539,6 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, data->gyrocal.y = 0; data->gyrocal.z = 0; } - - if(total_count == 128) - cal_ret = fifo_ret = 1; - exit: ssp_dbg("[SSP]: %s - " "%d,%d,%d," @@ -509,44 +546,26 @@ static ssize_t k6ds3tr_gyro_selftest(struct device *dev, "%d,%d,%d," "%d,%d,%d,%d,%d\n", __func__, - gyro_bias[0]/1000, - gyro_bias[1]/1000, - gyro_bias[2]/1000, - gyro_rms[0]/1000, - gyro_rms[1]/1000, - gyro_rms[2]/1000, - shift_ratio[0] / 10, - shift_ratio[1] / 10, - shift_ratio[2] / 10, - total_count, - total_count, - total_count, + gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2], + gyro_self_zro[0], gyro_self_zro[1], gyro_self_zro[2], + gyro_self_bias[0], gyro_self_bias[1], gyro_self_bias[2], + gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2], fifo_ret, cal_ret); - + + // Gyro Calibration pass / fail, buffer 1~6 values. if( (fifo_ret == 0) || (cal_ret == 0) ) - return sprintf(buf, "%d,%d,%d\n", - shift_ratio[0] / 10, - shift_ratio[1] / 10, - shift_ratio[2] / 10); - + return sprintf(buf, "%d,%d,%d\n", gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); + return sprintf(buf, "%d,%d,%d," "%d,%d,%d," "%d,%d,%d," "%d,%d,%d,%d,%d\n", - gyro_bias[0]/1000, - gyro_bias[1]/1000, - gyro_bias[2]/1000, - gyro_rms[0]/1000, - gyro_rms[1]/1000, - gyro_rms[2]/1000, - shift_ratio[0] / 10, - shift_ratio[1] / 10, - shift_ratio[2] / 10, - total_count, - total_count, - total_count, + gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2], + gyro_self_zro[0], gyro_self_zro[1], gyro_self_zro[2], + gyro_self_bias[0], gyro_self_bias[1], gyro_self_bias[2], + gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2], fifo_ret, cal_ret); } diff --git a/drivers/sensorhub/brcm/factory/gyro_mpu6050.c b/drivers/sensorhub/brcm/factory/gyro_mpu6050.c index 12695ab9daa6..cd33325f64ba 100644 --- a/drivers/sensorhub/brcm/factory/gyro_mpu6050.c +++ b/drivers/sensorhub/brcm/factory/gyro_mpu6050.c @@ -55,7 +55,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -97,7 +97,7 @@ static int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/gyro_mpu6500.c b/drivers/sensorhub/brcm/factory/gyro_mpu6500.c index ff90a08ff4af..f5481a744bc5 100644 --- a/drivers/sensorhub/brcm/factory/gyro_mpu6500.c +++ b/drivers/sensorhub/brcm/factory/gyro_mpu6500.c @@ -79,7 +79,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -121,7 +121,7 @@ int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/magnetic_ak09911.c b/drivers/sensorhub/brcm/factory/magnetic_ak09911.c index 21ef6cfa7e9d..0890aa1f6487 100644 --- a/drivers/sensorhub/brcm/factory/magnetic_ak09911.c +++ b/drivers/sensorhub/brcm/factory/magnetic_ak09911.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * Copyright (C) 2015, Samsung Electronics Co. Ltd. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,15 +18,11 @@ /* factory Sysfs */ /*************************************************************************/ -#define VENDOR_AK "AKM" -#define CHIP_ID_AK "AK09911C" -#define VENDOR_YAS "YAMAHA" -#define CHIP_ID_YAS "YAS532" +#define VENDOR "AKM" +#define CHIP_ID "AK09911C" -#define MAG_HW_OFFSET_FILE_PATH "/efs/FactoryApp/hw_offset" - -#define GM_DATA_SPEC_MIN -6500 -#define GM_DATA_SPEC_MAX 6500 +#define GM_DATA_SPEC_MIN -1600 +#define GM_DATA_SPEC_MAX 1600 #define GM_SELFTEST_X_SPEC_MIN -30 #define GM_SELFTEST_X_SPEC_MAX 30 @@ -35,215 +31,31 @@ #define GM_SELFTEST_Z_SPEC_MIN -400 #define GM_SELFTEST_Z_SPEC_MAX -50 -int mag_open_hwoffset(struct ssp_data *data) -{ - int iRet = 0; - mm_segment_t old_fs; - struct file *cal_filp = NULL; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0666); - if (IS_ERR(cal_filp)) { - pr_err("[SSP] %s: filp_open failed\n", __func__); - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - - data->magoffset.x = 0; - data->magoffset.y = 0; - data->magoffset.z = 0; - - return iRet; - } - - iRet = cal_filp->f_op->read(cal_filp, (char *)&data->magoffset, - 3 * sizeof(char), &cal_filp->f_pos); - if (iRet != 3 * sizeof(char)) { - pr_err("[SSP] %s: filp_open failed\n", __func__); - iRet = -EIO; - } - - filp_close(cal_filp, current->files); - set_fs(old_fs); - - ssp_dbg("[SSP]: %s: %d, %d, %d\n", __func__, - (s8)data->magoffset.x, - (s8)data->magoffset.y, - (s8)data->magoffset.z); - - if ((data->magoffset.x == 0) && (data->magoffset.y == 0) - && (data->magoffset.z == 0)) - return ERROR; - - return iRet; -} - -int mag_store_hwoffset(struct ssp_data *data) -{ - int iRet = 0; - struct file *cal_filp = NULL; - mm_segment_t old_fs; - - if (get_hw_offset(data) < 0) { - pr_err("[SSP]: %s - get_hw_offset failed\n", __func__); - return ERROR; - } else { - old_fs = get_fs(); - set_fs(KERNEL_DS); - - cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); - if (IS_ERR(cal_filp)) { - pr_err("[SSP]: %s - Can't open hw_offset file\n", - __func__); - set_fs(old_fs); - iRet = PTR_ERR(cal_filp); - return iRet; - } - iRet = cal_filp->f_op->write(cal_filp, - (char *)&data->magoffset, - 3 * sizeof(char), &cal_filp->f_pos); - if (iRet != 3 * sizeof(char)) { - pr_err("[SSP]: %s - Can't write the hw_offset" - " to file\n", __func__); - iRet = -EIO; - } - filp_close(cal_filp, current->files); - set_fs(old_fs); - return iRet; - } -} - -int set_hw_offset(struct ssp_data *data) -{ - int iRet = 0; - struct ssp_msg *msg; - - if (!(data->uSensorState & 0x04)) { - pr_info("[SSP]: %s - Skip this function!!!"\ - ", magnetic sensor is not connected(0x%x)\n", - __func__, data->uSensorState); - return iRet; - } - - msg = kzalloc(sizeof(*msg), GFP_KERNEL); - if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); - return -ENOMEM; - } - msg->cmd = MSG2SSP_AP_SET_MAGNETIC_HWOFFSET; - msg->length = 3; - msg->options = AP2HUB_WRITE; - msg->buffer = (char*) kzalloc(3, GFP_KERNEL); - msg->free_buffer = 1; - - msg->buffer[0] = data->magoffset.x; - msg->buffer[1] = data->magoffset.y; - msg->buffer[2] = data->magoffset.z; - - iRet = ssp_spi_async(data, msg); - - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); - iRet = ERROR; - } - - pr_info("[SSP]: %s: x: %d, y: %d, z: %d\n", __func__, - (s8)data->magoffset.x, (s8)data->magoffset.y, (s8)data->magoffset.z); - return iRet; -} - -int get_hw_offset(struct ssp_data *data) -{ - int iRet = 0; - char buffer[3] = { 0, }; - - struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); - if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); - return -ENOMEM; - } - msg->cmd = MSG2SSP_AP_GET_MAGNETIC_HWOFFSET; - msg->length = 3; - msg->options = AP2HUB_READ; - msg->buffer = buffer; - msg->free_buffer = 0; - - data->magoffset.x = 0; - data->magoffset.y = 0; - data->magoffset.z = 0; - - iRet = ssp_spi_sync(data, msg, 1000); - - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); - iRet = ERROR; - } - - data->magoffset.x = buffer[0]; - data->magoffset.y = buffer[1]; - data->magoffset.z = buffer[2]; - - pr_info("[SSP]: %s: x: %d, y: %d, z: %d\n", __func__, - (s8)data->magoffset.x, - (s8)data->magoffset.y, - (s8)data->magoffset.z); - return iRet; -} - -static ssize_t hw_offset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); - - mag_open_hwoffset(data); - - pr_info("[SSP] %s: %d %d %d\n", __func__, - (s8)data->magoffset.x, - (s8)data->magoffset.y, - (s8)data->magoffset.z); - - return sprintf(buf, "%d %d %d\n", - (s8)data->magoffset.x, - (s8)data->magoffset.y, - (s8)data->magoffset.z); -} static ssize_t magnetic_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ssp_data *data = dev_get_drvdata(dev); - - if (data->ap_rev >= 6) - return sprintf(buf, "%s\n", VENDOR_AK); - else - return sprintf(buf, "%s\n", VENDOR_YAS); + return sprintf(buf, "%s\n", VENDOR); } static ssize_t magnetic_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct ssp_data *data = dev_get_drvdata(dev); - - if (data->ap_rev >= 6) - return sprintf(buf, "%s\n", CHIP_ID_AK); - else - return sprintf(buf, "%s\n", CHIP_ID_YAS); + return sprintf(buf, "%s\n", CHIP_ID); } -static int check_data_spec(struct ssp_data *data) +static int check_data_spec(struct ssp_data *data, int sensortype) { - if ((data->buf[GEOMAGNETIC_RAW].x == 0) && - (data->buf[GEOMAGNETIC_RAW].y == 0) && - (data->buf[GEOMAGNETIC_RAW].z == 0)) + if ((data->buf[sensortype].x == 0) && + (data->buf[sensortype].y == 0) && + (data->buf[sensortype].z == 0)) return FAIL; - else if ((data->buf[GEOMAGNETIC_RAW].x > GM_DATA_SPEC_MAX) - || (data->buf[GEOMAGNETIC_RAW].x < GM_DATA_SPEC_MIN) - || (data->buf[GEOMAGNETIC_RAW].y > GM_DATA_SPEC_MAX) - || (data->buf[GEOMAGNETIC_RAW].y < GM_DATA_SPEC_MIN) - || (data->buf[GEOMAGNETIC_RAW].z > GM_DATA_SPEC_MAX) - || (data->buf[GEOMAGNETIC_RAW].z < GM_DATA_SPEC_MIN)) + else if ((data->buf[sensortype].x > GM_DATA_SPEC_MAX) + || (data->buf[sensortype].x < GM_DATA_SPEC_MIN) + || (data->buf[sensortype].y > GM_DATA_SPEC_MAX) + || (data->buf[sensortype].y < GM_DATA_SPEC_MIN) + || (data->buf[sensortype].z > GM_DATA_SPEC_MAX) + || (data->buf[sensortype].z < GM_DATA_SPEC_MIN)) return FAIL; else return SUCCESS; @@ -288,16 +100,16 @@ static ssize_t raw_data_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { char chTempbuf[4] = { 0 }; - int iRet; + int ret; int64_t dEnable; - int iRetries = 50; + int retries = 50; struct ssp_data *data = dev_get_drvdata(dev); s32 dMsDelay = 20; memcpy(&chTempbuf[0], &dMsDelay, 4); - iRet = kstrtoll(buf, 10, &dEnable); - if (iRet < 0) - return iRet; + ret = kstrtoll(buf, 10, &dEnable); + if (ret < 0) + return ret; if (dEnable) { data->buf[GEOMAGNETIC_RAW].x = 0; @@ -309,18 +121,17 @@ static ssize_t raw_data_store(struct device *dev, do { msleep(20); - if (check_data_spec(data) == SUCCESS) + if (check_data_spec(data, GEOMAGNETIC_RAW) == SUCCESS) break; - } while (--iRetries); + } while (--retries); - if (iRetries > 0) { - pr_info("[SSP] %s - success, %d\n", __func__, iRetries); - data->bGeomagneticRawEnabled = true; - } else { + if (retries > 0) + pr_info("[SSP] %s - success, %d\n", __func__, retries); + else pr_err("[SSP] %s - wait timeout, %d\n", __func__, - iRetries); - data->bGeomagneticRawEnabled = false; - } + retries); + + data->bGeomagneticRawEnabled = true; } else { send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_RAW, chTempbuf, 4); @@ -336,7 +147,7 @@ static ssize_t adc_data_read(struct device *dev, bool bSuccess = false; u8 chTempbuf[4] = { 0 }; s16 iSensorBuf[3] = {0, }; - int iRetries = 10; + int retries = 10; struct ssp_data *data = dev_get_drvdata(dev); s32 dMsDelay = 20; memcpy(&chTempbuf[0], &dMsDelay, 4); @@ -351,11 +162,11 @@ static ssize_t adc_data_read(struct device *dev, do { msleep(60); - if (check_data_spec(data) == SUCCESS) + if (check_data_spec(data, GEOMAGNETIC_SENSOR) == SUCCESS) break; - } while (--iRetries); + } while (--retries); - if (iRetries > 0) + if (retries > 0) bSuccess = true; iSensorBuf[0] = data->buf[GEOMAGNETIC_SENSOR].x; @@ -366,7 +177,7 @@ static ssize_t adc_data_read(struct device *dev, send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_SENSOR, chTempbuf, 4); - pr_info("[SSP]: %s - x = %d, y = %d, z = %d\n", __func__, + pr_info("[SSP] %s - x = %d, y = %d, z = %d\n", __func__, iSensorBuf[0], iSensorBuf[1], iSensorBuf[2]); return sprintf(buf, "%s,%d,%d,%d\n", (bSuccess ? "OK" : "NG"), @@ -401,119 +212,105 @@ static ssize_t magnetic_get_status(struct device *dev, return sprintf(buf, "%s,%u\n", (bSuccess ? "OK" : "NG"), bSuccess); } -static ssize_t yas_magnetic_get_selftest(struct ssp_data *data, char *buf) +static ssize_t magnetic_check_cntl(struct device *dev, + struct device_attribute *attr, char *strbuf) { + bool bSuccess = false; + int ret; char chTempBuf[22] = { 0, }; - int iRet = 0; - s8 id = 0, x = 0, y1 = 0, y2 = 0, dir = 0; - s16 sx = 0, sy = 0, ohx = 0, ohy = 0, ohz = 0; - s8 err[7] = {-1, }; + struct ssp_data *data = dev_get_drvdata(dev); + struct ssp_msg *msg; - struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); - if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); - goto exit; - } - msg->cmd = GEOMAGNETIC_FACTORY; - msg->length = 22; - msg->options = AP2HUB_READ; - msg->buffer = chTempBuf; - msg->free_buffer = 0; + if (!data->uMagCntlRegData) { + bSuccess = true; + } else { + pr_info("[SSP] %s - check cntl register before selftest", + __func__); + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", + __func__); + return -ENOMEM; + } + msg->cmd = GEOMAGNETIC_FACTORY; + msg->length = 22; + msg->options = AP2HUB_READ; + msg->buffer = chTempBuf; + msg->free_buffer = 0; - iRet = ssp_spi_sync(data, msg, 1000); + ret = ssp_spi_sync(data, msg, 1000); - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", __func__, iRet); - goto exit; + if (ret != SUCCESS) { + pr_err("[SSP] %s - spi sync failed due to Timeout!! %d\n", + __func__, ret); + } + + data->uMagCntlRegData = chTempBuf[21]; + bSuccess = !data->uMagCntlRegData; } - id = (s8)(chTempBuf[0]); - err[0] = (s8)(chTempBuf[1]); - err[1] = (s8)(chTempBuf[2]); - err[2] = (s8)(chTempBuf[3]); - x = (s8)(chTempBuf[4]); - y1 = (s8)(chTempBuf[5]); - y2 = (s8)(chTempBuf[6]); - err[3] = (s8)(chTempBuf[7]); - dir = (s8)(chTempBuf[8]); - err[4] = (s8)(chTempBuf[9]); - ohx = (s16)((chTempBuf[10] << 8) + chTempBuf[11]); - ohy = (s16)((chTempBuf[12] << 8) + chTempBuf[13]); - ohz = (s16)((chTempBuf[14] << 8) + chTempBuf[15]); - err[6] = (s8)(chTempBuf[16]); - sx = (s16)((chTempBuf[17] << 8) + chTempBuf[18]); - sy = (s16)((chTempBuf[19] << 8) + chTempBuf[20]); - err[5] = (s8)(chTempBuf[21]); - - if (unlikely(id != 0x2)) - err[0] = -1; - if (unlikely(x < -30 || x > 30)) - err[3] = -1; - if (unlikely(y1 < -30 || y1 > 30)) - err[3] = -1; - if (unlikely(y2 < -30 || y2 > 30)) - err[3] = -1; - if (unlikely(sx < 17 || sy < 22)) - err[5] = -1; - if (unlikely(ohx < -600 || ohx > 600)) - err[6] = -1; - if (unlikely(ohy < -600 || ohy > 600)) - err[6] = -1; - if (unlikely(ohz < -600 || ohz > 600)) - err[6] = -1; - - pr_info("[SSP] %s\n" - "[SSP] Test1 - err = %d, id = %d\n" - "[SSP] Test3 - err = %d\n" - "[SSP] Test4 - err = %d, offset = %d,%d,%d\n" - "[SSP] Test5 - err = %d, direction = %d\n" - "[SSP] Test6 - err = %d, sensitivity = %d,%d\n" - "[SSP] Test7 - err = %d, offset = %d,%d,%d\n" - "[SSP] Test2 - err = %d\n", - __func__, err[0], id, err[2], err[3], x, y1, y2, err[4], dir, - err[5], sx, sy, err[6], ohx, ohy, ohz, err[1]); + pr_info("[SSP] %s - CTRL : 0x%x\n", __func__, + data->uMagCntlRegData); -exit: - return sprintf(buf, - "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", - err[0], id, err[2], err[3], x, y1, y2, err[4], dir, - err[5], sx, sy, err[6], ohx, ohy, ohz, err[1]); + data->uMagCntlRegData = 1; /* reset the value */ + + return sprintf(strbuf, "%s,%d,%d,%d\n", + (bSuccess ? "OK" : "NG"), (bSuccess ? 1 : 0), 0, 0); } -static ssize_t ak_magnetic_get_selftest(struct ssp_data *data, char *buf) +static ssize_t magnetic_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) { - bool bSelftestPassed = false; - char chTempBuf[22] = { 0, }; + s8 iResult[4] = {-1, -1, -1, -1}; + char bufSelftset[22] = {0, }; + char bufAdc[4] = {0, }; s16 iSF_X = 0, iSF_Y = 0, iSF_Z = 0; - int /*iDelayCnt = 0,*/ iRet = 0,/* iTimeoutReties = 0,*/ iSpecOutReties = 0; + s16 iADC_X = 0, iADC_Y = 0, iADC_Z = 0; + s32 dMsDelay = 20; + int ret = 0, iSpecOutRetries = 0; + struct ssp_data *data = dev_get_drvdata(dev); struct ssp_msg *msg; -reties: + pr_info("[SSP] %s in\n", __func__); + + /* STATUS */ + if ((data->uFuseRomData[0] == 0) || + (data->uFuseRomData[0] == 0xff) || + (data->uFuseRomData[1] == 0) || + (data->uFuseRomData[1] == 0xff) || + (data->uFuseRomData[2] == 0) || + (data->uFuseRomData[2] == 0xff)) + iResult[0] = -1; + else + iResult[0] = 0; + +Retry_selftest: msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); + pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", + __func__); goto exit; } msg->cmd = GEOMAGNETIC_FACTORY; msg->length = 22; msg->options = AP2HUB_READ; - msg->buffer = chTempBuf; + msg->buffer = bufSelftset; msg->free_buffer = 0; - iRet = ssp_spi_sync(data, msg, 1000); - - if (iRet != SUCCESS) { - pr_err("[SSP]: %s - Magnetic Selftest Timeout!! %d\n", __func__, iRet); + ret = ssp_spi_sync(data, msg, 1000); + if (ret != SUCCESS) { + pr_err("[SSP] %s - Magnetic Selftest Timeout!! %d\n", + __func__, ret); goto exit; } /* read 6bytes data registers */ - iSF_X = (s16)((chTempBuf[13] << 8) + chTempBuf[14]); - iSF_Y = (s16)((chTempBuf[15] << 8) + chTempBuf[16]); - iSF_Z = (s16)((chTempBuf[17] << 8) + chTempBuf[18]); + iSF_X = (s16)((bufSelftset[13] << 8) + bufSelftset[14]); + iSF_Y = (s16)((bufSelftset[15] << 8) + bufSelftset[16]); + iSF_Z = (s16)((bufSelftset[17] << 8) + bufSelftset[18]); - /* Store Cntl Register value to check power down */ - data->uMagCntlRegData = chTempBuf[21]; + /* DAC (store Cntl Register value to check power down) */ + iResult[2] = bufSelftset[21]; iSF_X = (s16)(((iSF_X * data->uFuseRomData[0]) >> 7) + iSF_X); iSF_Y = (s16)(((iSF_Y * data->uFuseRomData[1]) >> 7) + iSF_Y); @@ -538,119 +335,115 @@ static ssize_t ak_magnetic_get_selftest(struct ssp_data *data, char *buf) else pr_info("[SSP] z failed self test, expect -400<=z<=-50\n"); + /* SELFTEST */ if ((iSF_X >= GM_SELFTEST_X_SPEC_MIN) && (iSF_X <= GM_SELFTEST_X_SPEC_MAX) && (iSF_Y >= GM_SELFTEST_Y_SPEC_MIN) && (iSF_Y <= GM_SELFTEST_Y_SPEC_MAX) && (iSF_Z >= GM_SELFTEST_Z_SPEC_MIN) && (iSF_Z <= GM_SELFTEST_Z_SPEC_MAX)) - bSelftestPassed = true; + iResult[1] = 0; + + if ((iResult[1] == -1) && (iSpecOutRetries++ < 5)) { + pr_err("[SSP] %s, selftest spec out. Retry = %d", __func__, + iSpecOutRetries); + goto Retry_selftest; + } - if ((bSelftestPassed == false) && (iSpecOutReties++ < 5)) - goto reties; + iSpecOutRetries = 10; -exit: - return sprintf(buf, "%u,%d,%d,%d\n", - bSelftestPassed, iSF_X, iSF_Y, iSF_Z); -} + /* ADC */ + memcpy(&bufAdc[0], &dMsDelay, 4); + data->buf[GEOMAGNETIC_RAW].x = 0; + data->buf[GEOMAGNETIC_RAW].y = 0; + data->buf[GEOMAGNETIC_RAW].z = 0; -static ssize_t magnetic_get_selftest(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ssp_data *data = dev_get_drvdata(dev); + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_RAW))) + send_instruction(data, ADD_SENSOR, GEOMAGNETIC_RAW, + bufAdc, 4); - if (data->ap_rev >= 6) - return ak_magnetic_get_selftest(data, buf); - else - return yas_magnetic_get_selftest(data, buf); -} + do { + msleep(60); + if (check_data_spec(data, GEOMAGNETIC_RAW) == SUCCESS) + break; + } while (--iSpecOutRetries); -static ssize_t magnetic_check_cntl(struct device *dev, - struct device_attribute *attr, char *strbuf) -{ - bool bSuccess = false; - int iRet; - char chTempBuf[22] = { 0, }; - struct ssp_data *data = dev_get_drvdata(dev); - struct ssp_msg *msg; + if (iSpecOutRetries > 0) + iResult[3] = 0; - if (!data->uMagCntlRegData) { - bSuccess = true; - } else { - pr_info("[SSP] %s - check cntl register before selftest\n", __func__); - msg = kzalloc(sizeof(*msg), GFP_KERNEL); - if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); - return -ENOMEM; - } - msg->cmd = GEOMAGNETIC_FACTORY; - msg->length = 22; - msg->options = AP2HUB_READ; - msg->buffer = chTempBuf; - msg->free_buffer = 0; + iADC_X = data->buf[GEOMAGNETIC_RAW].x; + iADC_Y = data->buf[GEOMAGNETIC_RAW].y; + iADC_Z = data->buf[GEOMAGNETIC_RAW].z; - iRet = ssp_spi_sync(data, msg, 1000); + if (!(atomic_read(&data->aSensorEnable) & (1 << GEOMAGNETIC_RAW))) + send_instruction(data, REMOVE_SENSOR, GEOMAGNETIC_RAW, + bufAdc, 4); - if (iRet != SUCCESS) { - pr_err("[SSP] %s - spi sync failed due to Timeout!! %d\n", - __func__, iRet); - } + pr_info("[SSP] %s -adc, x = %d, y = %d, z = %d, retry = %d\n", + __func__, iADC_X, iADC_Y, iADC_Z, iSpecOutRetries); - data->uMagCntlRegData = chTempBuf[21]; - bSuccess = !data->uMagCntlRegData; +exit: + pr_info("[SSP] %s out. Result = %d %d %d %d\n", + __func__, iResult[0], iResult[1], iResult[2], iResult[3]); + + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + iResult[0], iResult[1], iSF_X, iSF_Y, iSF_Z, + iResult[2], iResult[3], iADC_X, iADC_Y, iADC_Z); +} + +static int set_pdc_matrix(struct ssp_data *data) +{ + int ret = 0; + struct ssp_msg *msg; + + if (!(data->uSensorState & 0x04)) { + pr_info("[SSP] %s - Skip this function!!!"\ + ", magnetic sensor is not connected(0x%x)\n", + __func__, data->uSensorState); + return ret; } - pr_info("[SSP] %s - CTRL : 0x%x\n", __func__, - data->uMagCntlRegData); + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + pr_err("[SSP] %s, failed to alloc memory for ssp msg\n", + __func__); + return -ENOMEM; + } - data->uMagCntlRegData = 1; /* reset the value */ + msg->cmd = MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX; + msg->length = sizeof(data->pdc_matrix); + msg->options = AP2HUB_WRITE; + msg->buffer = kzalloc(sizeof(data->pdc_matrix), GFP_KERNEL); + if (msg->buffer == NULL) { + pr_err("[SSP] %s, failed to alloc memory\n", __func__); + kfree(msg); + return -ENOMEM; + } - return sprintf(strbuf, "%s,%d,%d,%d\n", - (bSuccess ? "OK" : "NG"), (bSuccess ? 1 : 0), 0, 0); -} + msg->free_buffer = 1; + memcpy(msg->buffer, data->pdc_matrix, sizeof(data->pdc_matrix)); -static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); -static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); -static DEVICE_ATTR(raw_data, S_IRUGO | S_IWUSR | S_IWGRP, - raw_data_show, raw_data_store); -static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); -static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); -static DEVICE_ATTR(hw_offset, S_IRUGO, hw_offset_show, NULL); -static DEVICE_ATTR(status, S_IRUGO, magnetic_get_status, NULL); -static DEVICE_ATTR(dac, S_IRUGO, magnetic_check_cntl, NULL); -static DEVICE_ATTR(ak09911_asa, S_IRUGO, magnetic_get_asa, NULL); + ret = ssp_spi_async(data, msg); + if (ret != SUCCESS) { + pr_err("[SSP] %s - i2c fail %d\n", __func__, ret); + ret = ERROR; + } -static struct device_attribute *mag_attrs[] = { - &dev_attr_name, - &dev_attr_vendor, - &dev_attr_adc, - &dev_attr_dac, - &dev_attr_raw_data, - &dev_attr_selftest, - &dev_attr_status, - &dev_attr_ak09911_asa, - NULL, -}; + pr_info("[SSP] %s: finished\n", __func__); -static struct device_attribute *mag_attrs_yas532[] = { - &dev_attr_name, - &dev_attr_vendor, - &dev_attr_adc, - &dev_attr_raw_data, - &dev_attr_selftest, - &dev_attr_hw_offset, - NULL, -}; + return ret; +} -static int get_fuserom_data(struct ssp_data *data) +int get_fuserom_data(struct ssp_data *data) { - int iRet = 0; + int ret = 0; char buffer[3] = { 0, }; struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { - pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); + pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", + __func__); return -ENOMEM; } msg->cmd = MSG2SSP_AP_FUSEROM; @@ -659,9 +452,9 @@ static int get_fuserom_data(struct ssp_data *data) msg->buffer = buffer; msg->free_buffer = 0; - iRet = ssp_spi_sync(data, msg, 1000); + ret = ssp_spi_sync(data, msg, 1000); - if (iRet) { + if (ret) { data->uFuseRomData[0] = buffer[0]; data->uFuseRomData[1] = buffer[1]; data->uFuseRomData[2] = buffer[2]; @@ -684,26 +477,96 @@ int initialize_magnetic_sensor(struct ssp_data *data) ret = get_fuserom_data(data); if (ret < 0) - pr_err("[SSP]: %s - get_fuserom_data failed %d\n", + pr_err("[SSP] %s - get_fuserom_data failed %d\n", __func__, ret); - return ret; + ret = set_pdc_matrix(data); + if (ret < 0) + pr_err("[SSP] %s - set_magnetic_pdc_matrix failed %d\n", + __func__, ret); + + return ret < 0 ? ret : SUCCESS; +} + +static ssize_t magnetic_logging_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char buffer[21] = {0, }; + int ret = 0; + int logging_data[8] = {0, }; + struct ssp_data *data = dev_get_drvdata(dev); + struct ssp_msg *msg; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", + __func__); + goto exit; + } + + msg->cmd = MSG2SSP_AP_GEOMAG_LOGGING; + msg->length = 21; + msg->options = AP2HUB_READ; + msg->buffer = buffer; + msg->free_buffer = 0; + + ret = ssp_spi_sync(data, msg, 1000); + if (ret != SUCCESS) { + pr_err("[SSP] %s - Magnetic logging data Timeout!! %d\n", + __func__, ret); + goto exit; + } + + logging_data[0] = buffer[0]; /* ST1 Reg */ + logging_data[1] = (short)((buffer[3] << 8) + buffer[2]); + logging_data[2] = (short)((buffer[5] << 8) + buffer[4]); + logging_data[3] = (short)((buffer[7] << 8) + buffer[6]); + logging_data[4] = buffer[1]; /* ST2 Reg */ + logging_data[5] = (short)((buffer[9] << 8) + buffer[8]); + logging_data[6] = (short)((buffer[11] << 8) + buffer[10]); + logging_data[7] = (short)((buffer[13] << 8) + buffer[12]); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + logging_data[0], logging_data[1], + logging_data[2], logging_data[3], + logging_data[4], logging_data[5], + logging_data[6], logging_data[7], + data->uFuseRomData[0], data->uFuseRomData[1], + data->uFuseRomData[2]); +exit: + return snprintf(buf, PAGE_SIZE, "-1,0,0,0,0,0,0,0,0,0,0\n"); } +static DEVICE_ATTR(name, S_IRUGO, magnetic_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, magnetic_vendor_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO | S_IWUSR | S_IWGRP, + raw_data_show, raw_data_store); +static DEVICE_ATTR(adc, S_IRUGO, adc_data_read, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, magnetic_get_selftest, NULL); +static DEVICE_ATTR(status, S_IRUGO, magnetic_get_status, NULL); +static DEVICE_ATTR(dac, S_IRUGO, magnetic_check_cntl, NULL); +static DEVICE_ATTR(ak09911_asa, S_IRUGO, magnetic_get_asa, NULL); +static DEVICE_ATTR(logging_data, S_IRUGO, magnetic_logging_show, NULL); + +static struct device_attribute *mag_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_adc, + &dev_attr_dac, + &dev_attr_raw_data, + &dev_attr_selftest, + &dev_attr_status, + &dev_attr_ak09911_asa, + &dev_attr_logging_data, + NULL, +}; + void initialize_magnetic_factorytest(struct ssp_data *data) { - if (data->ap_rev >= 6) - sensors_register(data->mag_device, data, - mag_attrs, "magnetic_sensor"); - else - sensors_register(data->mag_device, data, - mag_attrs_yas532, "magnetic_sensor"); + sensors_register(data->mag_device, data, mag_attrs, "magnetic_sensor"); } void remove_magnetic_factorytest(struct ssp_data *data) { - if (data->ap_rev >= 6) - sensors_unregister(data->mag_device, mag_attrs); - else - sensors_unregister(data->mag_device, mag_attrs_yas532); + sensors_unregister(data->mag_device, mag_attrs); } diff --git a/drivers/sensorhub/brcm/factory/magnetic_yas532.c b/drivers/sensorhub/brcm/factory/magnetic_yas532.c index 47f3172d30d7..d8e2b6bd5062 100644 --- a/drivers/sensorhub/brcm/factory/magnetic_yas532.c +++ b/drivers/sensorhub/brcm/factory/magnetic_yas532.c @@ -32,7 +32,7 @@ int mag_open_hwoffset(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP] %s: filp_open failed\n", __func__); set_fs(old_fs); @@ -81,7 +81,7 @@ int mag_store_hwoffset(struct ssp_data *data) set_fs(KERNEL_DS); cal_filp = filp_open(MAG_HW_OFFSET_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open hw_offset file\n", __func__); diff --git a/drivers/sensorhub/brcm/factory/pressure_bmp182.c b/drivers/sensorhub/brcm/factory/pressure_bmp182.c index 880f3d52c30d..7bc2cfda618b 100644 --- a/drivers/sensorhub/brcm/factory/pressure_bmp182.c +++ b/drivers/sensorhub/brcm/factory/pressure_bmp182.c @@ -56,7 +56,7 @@ int pressure_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { iErr = PTR_ERR(cal_filp); if (iErr != -ENOENT) diff --git a/drivers/sensorhub/brcm/factory/pressure_lps25h.c b/drivers/sensorhub/brcm/factory/pressure_lps25h.c index 822247fb5f1b..b80547df0e24 100644 --- a/drivers/sensorhub/brcm/factory/pressure_lps25h.c +++ b/drivers/sensorhub/brcm/factory/pressure_lps25h.c @@ -55,7 +55,7 @@ int pressure_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { iErr = PTR_ERR(cal_filp); if (iErr != -ENOENT) diff --git a/drivers/sensorhub/brcm/factory/prox_max88920.c b/drivers/sensorhub/brcm/factory/prox_max88920.c index b5c4d1ae034e..db12c0063903 100644 --- a/drivers/sensorhub/brcm/factory/prox_max88920.c +++ b/drivers/sensorhub/brcm/factory/prox_max88920.c @@ -133,7 +133,7 @@ static int proximity_open_lcd_ldi(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -202,7 +202,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -285,7 +285,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/factory/prox_tmg399x.c b/drivers/sensorhub/brcm/factory/prox_tmg399x.c index 1c817205eb69..d98293680576 100644 --- a/drivers/sensorhub/brcm/factory/prox_tmg399x.c +++ b/drivers/sensorhub/brcm/factory/prox_tmg399x.c @@ -139,7 +139,7 @@ static int proximity_open_lcd_ldi(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -208,7 +208,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -292,7 +292,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/brcm/max86902.c b/drivers/sensorhub/brcm/max86902.c index f87c384e6f27..24187aee726d 100644 --- a/drivers/sensorhub/brcm/max86902.c +++ b/drivers/sensorhub/brcm/max86902.c @@ -39,10 +39,12 @@ #define MAX86902_PART_ID2 0x15 #define MAX86902_REV_ID1 0xFE #define MAX86902_REV_ID2 0x03 +#define MAX86906_OTP_ID 0x15 #define MAX86900_DEFAULT_CURRENT 0x55 #define MAX86900A_DEFAULT_CURRENT 0xFF #define MAX86900C_DEFAULT_CURRENT 0x0F +#define MAX86906_DEFAULT_CURRENT 0x0F #define MAX86902_DEFAULT_CURRENT1 0x00 //RED #define MAX86902_DEFAULT_CURRENT2 0x60 //IR @@ -334,6 +336,31 @@ static int max86902_init_device(struct max86900_device_data *data) return 0; } +void max86900_pin_control(struct max86900_device_data *data, bool pin_set) +{ + int status = 0; + data->p->state = NULL; + if (pin_set) { + if (!IS_ERR(data->pins_idle)) { + status = pinctrl_select_state(data->p, + data->pins_idle); + if (status) + pr_err("%s: can't set pin default state\n", + __func__); + pr_debug("%s idle\n", __func__); + } + } else { + if (!IS_ERR(data->pins_sleep)) { + status = pinctrl_select_state(data->p, + data->pins_sleep); + if (status) + pr_err("%s: can't set pin sleep state\n", + __func__); + pr_debug("%s sleep\n", __func__); + } + } +} + static void irq_set_state(struct max86900_device_data *data, int irq_enable) { pr_info("%s - irq_enable : %d, irq_state : %d\n", @@ -1417,25 +1444,29 @@ static int max86900_eol_test_control(struct max86900_device_data *data) if (data->sample_cnt < data->hr_range2) { data->hr_range = 1; } else if (data->sample_cnt < (data->hr_range2 + 297)) { - /* Fake pulse */ - if (data->sample_cnt % 8 < 4) { - data->test_current_ir++; - data->test_current_red++; - } else { - data->test_current_ir--; - data->test_current_red--; - } + if ( data->eol_test_is_enable == 1 ) { + /* Fake pulse */ + if (data->sample_cnt % 8 < 4) { + data->test_current_ir++; + data->test_current_red++; + } else { + data->test_current_ir--; + data->test_current_red--; + } - led_current = (data->test_current_red << 4) - | data->test_current_ir; - err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, - led_current); - if (err != 0) { - pr_err("%s - error initializing MAX86900_LED_CONFIGURATION!\n", - __func__); - return -EIO; + led_current = (data->test_current_red << 4) + | data->test_current_ir; + err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, + led_current); + if (err != 0) { + pr_err("%s - error initializing MAX86900_LED_CONFIGURATION!\n", + __func__); + return -EIO; + } + data->hr_range = 2; + } else if (data->eol_test_is_enable == 2 ) { + data->sample_cnt = data->hr_range2 + 297 - 1; } - data->hr_range = 2; } else if (data->sample_cnt == (data->hr_range2 + 297)) { /* Measure */ err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, @@ -2899,7 +2930,7 @@ static void max86900_eol_test_onoff(struct max86900_device_data *data, int onoff if (onoff) { err = max86900_hrm_eol_test_enable(data); - data->eol_test_is_enable = 1; + data->eol_test_is_enable = onoff; if (err != 0) pr_err("max86900_hrm_eol_test_enable err : %d\n", err); } else { @@ -3227,6 +3258,42 @@ static int max86902_get_device_id(struct max86900_device_data *data, unsigned lo return 0; } +static int max86900_otp_id(struct max86900_device_data *data) +{ + u8 recvData; + int err; + + err = max86900_write_reg(data, 0xFF, 0x54); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST0!\n", + __func__); + return -EIO; + } + + err = max86900_write_reg(data, 0xFF, 0x4d); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST1!\n", + __func__); + return -EIO; + } + + recvData = 0x8B; + if ((err = max86900_read_reg(data, &recvData, 1)) != 0) { + pr_err("%s - max86900_read_reg err:%d, address:0x%02x\n", + __func__, err, recvData); + return -EIO; + } + + err = max86900_write_reg(data, 0xFF, 0x00); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST0!\n", + __func__); + return -EIO; + } + + return recvData; + +} static ssize_t max86900_hrm_name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3515,6 +3582,8 @@ static ssize_t eol_test_store(struct device *dev, if (sysfs_streq(buf, "1")) /* eol_test start */ test_onoff = 1; + else if (sysfs_streq(buf, "2")) /* eol_test for grip sensor */ + test_onoff = 2; else if (sysfs_streq(buf, "0")) /* eol_test stop */ test_onoff = 0; else { @@ -4603,6 +4672,28 @@ static int max86900_parse_dt(struct max86900_device_data *data, if (of_property_read_u32(dNode, "max86900,dual-hrm", &data->dual_hrm)) data->dual_hrm = 0; + data->p = pinctrl_get_select_default(dev); + if (IS_ERR(data->p)) { + pr_err("%s: failed pinctrl_get\n", __func__); + return -EINVAL; + } + + data->pins_sleep = pinctrl_lookup_state(data->p, PINCTRL_STATE_SLEEP); + if(IS_ERR(data->pins_sleep)) { + pr_err("%s : could not get pins sleep_state (%li)\n", + __func__, PTR_ERR(data->pins_sleep)); + pinctrl_put(data->p); + return -EINVAL; + } + + data->pins_idle = pinctrl_lookup_state(data->p, PINCTRL_STATE_IDLE); + if(IS_ERR(data->pins_idle)) { + pr_err("%s : could not get pins idle_state (%li)\n", + __func__, PTR_ERR(data->pins_idle)); + pinctrl_put(data->p); + return -EINVAL; + } + return 0; } @@ -4646,6 +4737,7 @@ static int max86900_setup_irq(struct max86900_device_data *data) } disable_irq(data->irq); + return errorno; } @@ -4746,8 +4838,13 @@ int max86900_probe(struct i2c_client *client, const struct i2c_device_id *id) data->default_current = MAX86900A_DEFAULT_CURRENT; break; case MAX86900C_REV_ID: - data->part_type = PART_TYPE_MAX86900C; - data->default_current = MAX86900C_DEFAULT_CURRENT; + if ( max86900_otp_id(data) == MAX86906_OTP_ID ) { + data->part_type = PART_TYPE_MAX86906; + data->default_current = MAX86906_DEFAULT_CURRENT; + } else { + data->part_type = PART_TYPE_MAX86900C; + data->default_current = MAX86900C_DEFAULT_CURRENT; + } break; default: pr_err("%s WHOAMI read error : REV ID : 0x%02x\n", @@ -5008,6 +5105,8 @@ static void max86900_shutdown(struct i2c_client *client) static int max86900_pm_suspend(struct device *dev) { struct max86900_device_data *data = dev_get_drvdata(dev); + + max86900_pin_control(data, false); if (data->part_type < PART_TYPE_MAX86902A) { if (atomic_read(&data->hrm_is_enable)) { max86900_hrm_mode_enable(data, HRM_LDO_OFF); @@ -5032,6 +5131,8 @@ static int max86900_pm_suspend(struct device *dev) static int max86900_pm_resume(struct device *dev) { struct max86900_device_data *data = dev_get_drvdata(dev); + + max86900_pin_control(data, true); if (data->part_type < PART_TYPE_MAX86902A) { if (atomic_read(&data->is_suspend) == 1) { max86900_hrm_mode_enable(data, HRM_LDO_ON); diff --git a/drivers/sensorhub/brcm/max86902.h b/drivers/sensorhub/brcm/max86902.h index 2fc35f4f2dc1..59045a2a0bb3 100644 --- a/drivers/sensorhub/brcm/max86902.h +++ b/drivers/sensorhub/brcm/max86902.h @@ -25,6 +25,9 @@ #include #include +#include +#include "../../pinctrl/core.h" + #define MAX86902_DEBUG #define MAX86900_SLAVE_ADDR 0x51 @@ -197,7 +200,8 @@ typedef enum _PART_TYPE PART_TYPE_MAX86900A, PART_TYPE_MAX86900B, PART_TYPE_MAX86900C, - PART_TYPE_MAX86902A, + PART_TYPE_MAX86906, + PART_TYPE_MAX86902A = 10, PART_TYPE_MAX86902B, } PART_TYPE; @@ -218,6 +222,9 @@ struct max86900_device_data struct mutex activelock; struct delayed_work uv_sr_work_queue; struct delayed_work reenable_work_queue; + struct pinctrl *p; + struct pinctrl_state *pins_sleep; + struct pinctrl_state *pins_idle; const char *led_3p3; const char *vdd_1p8; bool *bio_status; diff --git a/drivers/sensorhub/brcm/ssp.h b/drivers/sensorhub/brcm/ssp.h index 1f54f5720821..4a794e8a9cd3 100644 --- a/drivers/sensorhub/brcm/ssp.h +++ b/drivers/sensorhub/brcm/ssp.h @@ -199,6 +199,7 @@ enum { #define MSG2SSP_AP_MOBEAM_COUNT_SET 0x33 #define MSG2SSP_AP_MOBEAM_START 0x34 #define MSG2SSP_AP_MOBEAM_STOP 0x35 +#define MSG2SSP_AP_GEOMAG_LOGGING 0x36 #define MSG2SSP_AP_SENSOR_LPF 0x37 #define MSG2SSP_AP_IRDATA_SEND 0x38 @@ -239,8 +240,8 @@ enum { #if defined(CONFIG_SENSORS_SSP_TMG399x) #define DEFUALT_HIGH_THRESHOLD 130 #define DEFUALT_LOW_THRESHOLD 90 -#define DEFUALT_CAL_HIGH_THRESHOLD 120 -#define DEFUALT_CAL_LOW_THRESHOLD 55 +#define DEFUALT_CAL_HIGH_THRESHOLD 130 +#define DEFUALT_CAL_LOW_THRESHOLD 54 #else #define DEFUALT_HIGH_THRESHOLD 2000 #define DEFUALT_LOW_THRESHOLD 1400 @@ -257,6 +258,9 @@ enum { #define MAX_COMP_BUFF 60 +/* ak0911 magnetic pdc matrix size */ +#define PDC_SIZE 27 + /* temphumidity sensor*/ struct shtc1_buffer { u16 batt[MAX_COMP_BUFF]; @@ -291,8 +295,12 @@ enum { TEMPERATURE_HUMIDITY_SENSOR, LIGHT_SENSOR, PROXIMITY_RAW, +#ifdef CONFIG_SENSORS_SSP_SX9306 GRIP_SENSOR, ORIENTATION_SENSOR, +#else + ORIENTATION_SENSOR = 12, +#endif STEP_DETECTOR = 13, SIG_MOTION_SENSOR, GYRO_UNCALIB_SENSOR, @@ -307,7 +315,7 @@ enum { LIGHT_IR_SENSOR = 24, #endif #ifdef CONFIG_SENSORS_SSP_INTERRUPT_GYRO_SENSOR - INTERRUPT_GYRO_SENSOR, + INTERRUPT_GYRO_SENSOR = 25, #endif SENSOR_MAX, }; @@ -624,6 +632,7 @@ struct ssp_data { int mag_position; u8 mag_matrix_size; u8 *mag_matrix; + unsigned char pdc_matrix[PDC_SIZE]; #ifdef CONFIG_SENSORS_SSP_SHTC1 struct miscdevice shtc1_device; char *comp_engine_ver; diff --git a/drivers/sensorhub/brcm/ssp_data.c b/drivers/sensorhub/brcm/ssp_data.c index 8de92e0b2069..f437d0feaf0b 100644 --- a/drivers/sensorhub/brcm/ssp_data.c +++ b/drivers/sensorhub/brcm/ssp_data.c @@ -36,8 +36,12 @@ static void generate_data(struct ssp_data *data, u64 move_timestamp = data->lastTimestamp[iSensorData]; if ((iSensorData != PROXIMITY_SENSOR) && (iSensorData != GESTURE_SENSOR) && (iSensorData != STEP_DETECTOR) && (iSensorData != SIG_MOTION_SENSOR) - && (iSensorData != STEP_COUNTER) && (iSensorData != GRIP_SENSOR)) { - while ((move_timestamp * 10 + data->adDelayBuf[iSensorData] * 15) < (timestamp * 10)) { + && (iSensorData != STEP_COUNTER) +#ifdef CONFIG_SENSORS_SSP_SX9306 + && (iSensorData != GRIP_SENSOR) +#endif + ) { + while ((move_timestamp * 10 + data->adDelayBuf[iSensorData] * 13) < (timestamp * 10)) { move_timestamp += data->adDelayBuf[iSensorData]; sensorsdata->timestamp = move_timestamp; data->report_sensor_data[iSensorData](data, sensorsdata); @@ -63,7 +67,7 @@ static void get_timestamp(struct ssp_data *data, char *pchRcvDataFrame, sensorsdata->timestamp = data->timestamp; } } else { - if (((sensortime->irq_diff * 10) > (data->adDelayBuf[iSensorData] * 18)) + if (((sensortime->irq_diff * 10) > (data->adDelayBuf[iSensorData] * 13)) && ((sensortime->irq_diff * 10) < (data->adDelayBuf[iSensorData] * 100))) { generate_data(data, sensorsdata, iSensorData, data->timestamp); } @@ -181,12 +185,14 @@ static void get_proximity_rawdata(char *pchRcvDataFrame, int *iDataIdx, #endif } +#ifdef CONFIG_SENSORS_SSP_SX9306 static void get_grip_sensordata(char *pchRcvDataFrame, int *iDataIdx, struct sensor_value *sensorsdata) { memcpy(sensorsdata, pchRcvDataFrame + *iDataIdx, 9); *iDataIdx += 9; } +#endif static void get_temp_humidity_sensordata(char *pchRcvDataFrame, int *iDataIdx, struct sensor_value *sensorsdata) @@ -275,12 +281,12 @@ int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) else if (length > 2) time = data->adDelayBuf[iSensorData] * 50; else - time = data->adDelayBuf[iSensorData] * 100; + time = data->adDelayBuf[iSensorData] * 120; if ((sensortime.time_diff * 10) > time) { data->lastTimestamp[iSensorData] = data->timestamp - (data->adDelayBuf[iSensorData] * length); sensortime.time_diff = data->adDelayBuf[iSensorData]; } else { - time = data->adDelayBuf[iSensorData] * 18; + time = data->adDelayBuf[iSensorData] * 11; if ((sensortime.time_diff * 10) > time) sensortime.time_diff = data->adDelayBuf[iSensorData]; } @@ -299,7 +305,7 @@ int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) do { data->get_sensor_data[iSensorData](pchRcvDataFrame, &iDataIdx, &sensorsdata); get_timestamp(data, pchRcvDataFrame, &iDataIdx, &sensorsdata, &sensortime, iSensorData); - if (sensortime.irq_diff > 1000000) + if (sensortime.irq_diff > 2500000) data->report_sensor_data[iSensorData](data, &sensorsdata); else if ((iSensorData == PROXIMITY_SENSOR) || (iSensorData == PROXIMITY_RAW) || (iSensorData == GESTURE_SENSOR) || (iSensorData == SIG_MOTION_SENSOR)) @@ -344,7 +350,9 @@ int parse_dataframe(struct ssp_data *data, char *pchRcvDataFrame, int iLength) case MSG2AP_INST_GYRO_CAL: pr_err("Gyro caldata received from MCU\n"); memcpy(caldata, pchRcvDataFrame + iDataIdx, sizeof(caldata)); + wake_lock(&data->ssp_wake_lock); save_gyro_caldata(data, caldata); + wake_unlock(&data->ssp_wake_lock); iDataIdx += sizeof(caldata); break; } @@ -366,7 +374,9 @@ void initialize_function_pointer(struct ssp_data *data) data->get_sensor_data[GESTURE_SENSOR] = get_gesture_sensordata; data->get_sensor_data[PROXIMITY_SENSOR] = get_proximity_sensordata; data->get_sensor_data[PROXIMITY_RAW] = get_proximity_rawdata; +#ifdef CONFIG_SENSORS_SSP_SX9306 data->get_sensor_data[GRIP_SENSOR] = get_grip_sensordata; +#endif data->get_sensor_data[LIGHT_SENSOR] = get_light_sensordata; #ifdef CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA data->get_sensor_data[LIGHT_IR_SENSOR] = get_light_ir_sensordata; @@ -395,7 +405,9 @@ void initialize_function_pointer(struct ssp_data *data) data->report_sensor_data[GESTURE_SENSOR] = report_gesture_data; data->report_sensor_data[PROXIMITY_SENSOR] = report_prox_data; data->report_sensor_data[PROXIMITY_RAW] = report_prox_raw_data; +#ifdef CONFIG_SENSORS_SSP_SX9306 data->report_sensor_data[GRIP_SENSOR] = report_grip_data; +#endif data->report_sensor_data[LIGHT_SENSOR] = report_light_data; #ifdef CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA data->report_sensor_data[LIGHT_IR_SENSOR] = report_light_ir_data; diff --git a/drivers/sensorhub/brcm/ssp_dev.c b/drivers/sensorhub/brcm/ssp_dev.c index 155fece9afe5..f43a11a4f17a 100644 --- a/drivers/sensorhub/brcm/ssp_dev.c +++ b/drivers/sensorhub/brcm/ssp_dev.c @@ -288,8 +288,8 @@ static int ssp_parse_dt(struct device *dev,struct ssp_data *data) #endif return errorno; -dt_exit: #if defined(CONFIG_SENSORS_SSP_YAS532) || defined(CONFIG_SENSORS_SSP_YAS537) +dt_exit: if(data->static_matrix != NULL) kfree(data->static_matrix); #endif diff --git a/drivers/sensorhub/brcm/ssp_firmware.c b/drivers/sensorhub/brcm/ssp_firmware.c index 64c183167a73..14fd69e6aab5 100644 --- a/drivers/sensorhub/brcm/ssp_firmware.c +++ b/drivers/sensorhub/brcm/ssp_firmware.c @@ -1,26 +1,32 @@ /* - * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +* Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ #include "ssp.h" -#ifdef CONFIG_SENSORS_SSP_K6DS3TR -#define SSP_FIRMWARE_REVISION_BCM 15042700 +#ifdef CONFIG_SENSORS_SSP_NOBLELTE +#undef SSP_FIRMWARE_REVISION_BCM +#define SSP_FIRMWARE_REVISION_BCM 15051900 +#elif defined (CONFIG_SENSORS_SSP_ZENLTE) +#undef SSP_FIRMWARE_REVISION_BCM +#define SSP_FIRMWARE_REVISION_BCM 15051100 +#elif defined (CONFIG_SENSORS_SSP_K6DS3TR) +#define SSP_FIRMWARE_REVISION_BCM 15052100 #elif defined (CONFIG_SENSORS_SSP_VLTE) #undef SSP_FIRMWARE_REVISION_BCM -#define SSP_FIRMWARE_REVISION_BCM 15042000 +#define SSP_FIRMWARE_REVISION_BCM 15052000 #else // ZERO -#define SSP_FIRMWARE_REVISION_BCM 15042900 +#define SSP_FIRMWARE_REVISION_BCM 15050701 #endif unsigned int get_module_rev(struct ssp_data *data) { diff --git a/drivers/sensorhub/brcm/ssp_input.c b/drivers/sensorhub/brcm/ssp_input.c index 824cab943766..7f1d79233b1d 100644 --- a/drivers/sensorhub/brcm/ssp_input.c +++ b/drivers/sensorhub/brcm/ssp_input.c @@ -551,6 +551,7 @@ void report_prox_raw_data(struct ssp_data *data, data->buf[PROXIMITY_RAW].prox[0] = proxrawdata->prox[0]; } +#ifdef CONFIG_SENSORS_SSP_SX9306 void report_grip_data(struct ssp_data *data, struct sensor_value *gripdata) { pr_err("[SSP] grip = %d %d %d 0x%02x\n", @@ -580,6 +581,7 @@ void report_grip_data(struct ssp_data *data, struct sensor_value *gripdata) wake_lock_timeout(&data->ssp_wake_lock, 3 * HZ); } +#endif void report_step_det_data(struct ssp_data *data, struct sensor_value *stepdet_data) @@ -650,10 +652,11 @@ int initialize_event_symlink(struct ssp_data *data) if (iRet < 0) goto iRet_prox_sysfs_create_link; +#ifdef CONFIG_SENSORS_SSP_SX9306 iRet = sensors_create_symlink(data->grip_input_dev); if (iRet < 0) goto iRet_grip_sysfs_create_link; - +#endif iRet = sensors_create_symlink(data->temp_humi_input_dev); if (iRet < 0) goto iRet_temp_humi_sysfs_create_link; @@ -687,8 +690,10 @@ int initialize_event_symlink(struct ssp_data *data) iRet_sig_motion_sysfs_create_link: sensors_remove_symlink(data->temp_humi_input_dev); iRet_temp_humi_sysfs_create_link: +#ifdef CONFIG_SENSORS_SSP_SX9306 sensors_remove_symlink(data->grip_input_dev); iRet_grip_sysfs_create_link: +#endif sensors_remove_symlink(data->prox_input_dev); iRet_prox_sysfs_create_link: #ifdef CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA @@ -712,7 +717,9 @@ void remove_event_symlink(struct ssp_data *data) sensors_remove_symlink(data->light_ir_input_dev); #endif sensors_remove_symlink(data->prox_input_dev); +#ifdef CONFIG_SENSORS_SSP_SX9306 sensors_remove_symlink(data->grip_input_dev); +#endif sensors_remove_symlink(data->temp_humi_input_dev); sensors_remove_symlink(data->sig_motion_input_dev); sensors_remove_symlink(data->step_cnt_input_dev); @@ -1138,6 +1145,7 @@ int initialize_input_dev(struct ssp_data *data) } input_set_drvdata(data->prox_input_dev, data); +#ifdef CONFIG_SENSORS_SSP_SX9306 data->grip_input_dev = input_allocate_device(); if (data->grip_input_dev == NULL) goto err_initialize_grip_input_dev; @@ -1150,6 +1158,7 @@ int initialize_input_dev(struct ssp_data *data) goto err_initialize_grip_input_dev; } input_set_drvdata(data->grip_input_dev, data); +#endif data->temp_humi_input_dev = input_allocate_device(); if (data->temp_humi_input_dev == NULL) @@ -1296,9 +1305,11 @@ int initialize_input_dev(struct ssp_data *data) input_unregister_device(data->temp_humi_input_dev); err_initialize_temp_humi_input_dev: pr_err("[SSP]: %s - could not allocate temp_humi input device\n", __func__); +#ifdef CONFIG_SENSORS_SSP_SX9306 input_unregister_device(data->grip_input_dev); err_initialize_grip_input_dev: pr_err("[SSP]: %s - could not allocate grip input device\n", __func__); +#endif input_unregister_device(data->prox_input_dev); err_initialize_proximity_input_dev: pr_err("[SSP]: %s - could not allocate proximity input device\n", __func__); diff --git a/drivers/sensorhub/brcm/sx9310.c b/drivers/sensorhub/brcm/sx9310.c new file mode 100644 index 000000000000..4c13eb14ae64 --- /dev/null +++ b/drivers/sensorhub/brcm/sx9310.c @@ -0,0 +1,1608 @@ +/* + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sx9310_reg.h" + +#define VENDOR_NAME "SEMTECH" +#define MODEL_NAME "SX9310" +#define MODULE_NAME "grip_sensor" +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/grip_cal_data" + +#define I2C_M_WR 0 /* for i2c Write */ +#define I2c_M_RD 1 /* for i2c Read */ + +#define IDLE 0 +#define ACTIVE 1 + +#define CAL_RET_ERROR -1 +#define CAL_RET_NONE 0 +#define CAL_RET_EXIST 1 +#define CAL_RET_SUCCESS 2 + +#define INIT_TOUCH_MODE 0 +#define NORMAL_TOUCH_MODE 1 + +#define SX9310_MODE_SLEEP 0 +#define SX9310_MODE_NORMAL 1 +#define SX9310_IRQ_ENABLE 1 +#define SX9310_IRQ_DISABLE 0 + +#define MAIN_SENSOR 1 +#define REF_SENSOR 2 + +#define CSX_STATUS_REG SX9310_TCHCMPSTAT_TCHSTAT1_FLAG + +#define DEFAULT_THRESHOLD 0x8E + +#define LIMIT_PROXOFFSET 13500 /* 99.9pF */// 2550 /* 30pF */ +#define LIMIT_PROXUSEFUL_MIN -10000 +#define LIMIT_PROXUSEFUL_MAX 10000 +#define PROXUSEFUL_DELTA_SPEC 2000 +#define STANDARD_CAP_MAIN 1000000 + +#define TOUCH_CHECK_REF_AMB 0 // 44523 +#define TOUCH_CHECK_SLOPE 0 // 50 +#define TOUCH_CHECK_MAIN_AMB 0 // 151282 + +#define DEFENCE_CODE_FOR_DEVICE_DAMAGE +/* CS0, CS1, CS2, CS3 */ +#define ENABLE_CSX (1 << MAIN_SENSOR)/* | (1 << REF_SENSOR)) */ + +#define IRQ_PROCESS_CONDITION (SX9310_IRQSTAT_TOUCH_FLAG \ + | SX9310_IRQSTAT_RELEASE_FLAG \ + | SX9310_IRQSTAT_COMPDONE_FLAG) + +struct sx9310_p { + struct i2c_client *client; + struct input_dev *input; + struct device *factory_device; +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + struct delayed_work reinit_irq_work; +#else + struct delayed_work init_work; +#endif + struct delayed_work irq_work; + struct wake_lock grip_wake_lock; + struct mutex mode_mutex; + struct mutex read_mutex; + + bool cal_successed; + bool flag_dataskip; + u8 normal_th; + u8 normal_th_buf; + int init_th; + int cal_data[3]; + int touch_mode; + s32 capmain; + s16 useful; + s16 avg; + u16 offset; + u16 freq; + + int irq; + int irq_ldo; + int gpio_nirq; + int gpio_ldoen; + int state; + int irq_state; + + u8 sreg; + u8 rwreg_val; + u8 retry_cnt; + + atomic_t enable; +}; + +static int sx9310_get_nirq_state(struct sx9310_p *data) +{ + return gpio_get_value_cansleep(data->gpio_nirq); +} + +static int sx9310_get_nirqldo_state(struct sx9310_p *data) +{ + return gpio_get_value_cansleep(data->gpio_ldoen); +} + +static int sx9310_i2c_write(struct sx9310_p *data, u8 reg_addr, u8 buf) +{ + int ret; + struct i2c_msg msg; + unsigned char w_buf[2]; + + w_buf[0] = reg_addr; + w_buf[1] = buf; + + msg.addr = data->client->addr; + msg.flags = I2C_M_WR; + msg.len = 2; + msg.buf = (char *)w_buf; + + ret = i2c_transfer(data->client->adapter, &msg, 1); + if (ret < 0) + pr_err("[SX9310]: %s - i2c write error %d\n", __func__, ret); + + return 0; +} + +static int sx9310_i2c_read(struct sx9310_p *data, u8 reg_addr, u8 *buf) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = data->client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®_addr; + + msg[1].addr = data->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = buf; + + ret = i2c_transfer(data->client->adapter, msg, 2); + if (ret < 0) + pr_err("[SX9310]: %s - i2c read error %d\n", __func__, ret); + + return ret; +} + +static int sx9310_i2c_read_block(struct sx9310_p *data, u8 reg_addr, + u8 *buf, u8 buf_size) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = data->client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®_addr; + + msg[1].addr = data->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = buf_size; + msg[1].buf = buf; + + ret = i2c_transfer(data->client->adapter, msg, 2); + if (ret < 0) + pr_err("[SX9310]: %s - i2c read error %d\n", __func__, ret); + + return ret; +} + +static u8 sx9310_read_irqstate(struct sx9310_p *data) +{ + u8 val = 0; + + if (sx9310_i2c_read(data, SX9310_IRQSTAT_REG, &val) >= 0) + return (val & 0x00FF); + + return 0; +} + +static void sx9310_initialize_register(struct sx9310_p *data) +{ + u8 val = 0; + int idx; + + for (idx = 0; idx < (sizeof(setup_reg) >> 1); idx++) { + sx9310_i2c_write(data, setup_reg[idx].reg, setup_reg[idx].val); + pr_info("[SX9310]: %s - Write Reg: 0x%x Value: 0x%x\n", + __func__, setup_reg[idx].reg, setup_reg[idx].val); + + sx9310_i2c_read(data, setup_reg[idx].reg, &val); + pr_info("[SX9310]: %s - Read Reg: 0x%x Value: 0x%x\n\n", + __func__, setup_reg[idx].reg, val); + } +} + +static void sx9310_initialize_chip(struct sx9310_p *data) +{ + int cnt = 0; + + while ((sx9310_get_nirq_state(data) == 0) && (cnt++ < 10)) { + sx9310_read_irqstate(data); + msleep(20); + } + + if (cnt >= 10) + pr_err("[SX9310]: %s - s/w reset fail(%d)\n", + __func__, cnt); + + sx9310_initialize_register(data); +} + +static int sx9310_set_offset_calibration(struct sx9310_p *data) +{ + int ret = 0; + + ret = sx9310_i2c_write(data, SX9310_IRQSTAT_REG, 0xFF); + + return ret; +} + +static void send_event(struct sx9310_p *data, u8 state) +{ + data->normal_th = data->normal_th_buf; +#ifdef CONFIG_SENSORS_SX9310_DEFENCE_CODE_FOR_TA_NOISE + if (check_ta_state() > 1) { + data->normal_th = SX9310_NORMAL_TOUCH_CABLE_THRESHOLD; + pr_info("[SX9310]: %s - TA cable connected\n", __func__); + } +#endif + + if (state == ACTIVE) { + data->state = ACTIVE; +#if (MAIN_SENSOR == 1) + sx9310_i2c_write(data, SX9310_CPS_CTRL9_REG, data->normal_th); +#else + sx9310_i2c_write(data, SX9310_CPS_CTRL8_REG, data->normal_th); +#endif + pr_info("[SX9310]: %s - button touched\n", __func__); + } else { + data->touch_mode = NORMAL_TOUCH_MODE; + data->state = IDLE; +#if (MAIN_SENSOR == 1) + sx9310_i2c_write(data, SX9310_CPS_CTRL9_REG, data->normal_th); +#else + sx9310_i2c_write(data, SX9310_CPS_CTRL8_REG, data->normal_th); +#endif + pr_info("[SX9310]: %s - button released\n", __func__); + } + + if (data->flag_dataskip == true) + return; + + if (state == ACTIVE) + input_report_rel(data->input, REL_MISC, 1); + else + input_report_rel(data->input, REL_MISC, 2); + + input_sync(data->input); +} + +static void sx9310_display_data_reg(struct sx9310_p *data) +{ + u8 val, reg; + + sx9310_i2c_write(data, SX9310_REGSENSORSELECT, MAIN_SENSOR); + for (reg = SX9310_REGUSEMSB; reg <= SX9310_REGOFFSETLSB; reg++) { + sx9310_i2c_read(data, reg, &val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, reg, val); + } + } + +static s32 sx9310_get_init_threshold(struct sx9310_p *data) +{ + s32 threshold; + + /* Because the STANDARD_CAP_MAIN was 300,000 in the previous patch, + * the exception code is added. It will be removed later */ + if (data->cal_data[0] == 0) + threshold = STANDARD_CAP_MAIN + data->init_th; + else + threshold = data->init_th + data->cal_data[0]; + + return threshold; +} + +#define RAW_DATA_BLOCK_SIZE (SX9310_REGOFFSETLSB - SX9310_REGUSEMSB + 1) + +static void sx9310_get_data(struct sx9310_p *data) +{ + u8 ms_byte = 0; + u8 is_byte = 0; + u8 ls_byte = 0; + + u8 buf[RAW_DATA_BLOCK_SIZE]; + mutex_lock(&data->read_mutex); + + sx9310_i2c_write(data, SX9310_REGSENSORSELECT, MAIN_SENSOR); + sx9310_i2c_read_block(data, SX9310_REGUSEMSB, + &buf[0], RAW_DATA_BLOCK_SIZE); + + data->useful = (s16)((s32)buf[0] << 8) | ((s32)buf[1]); + data->avg = (s16)((s32)buf[2] << 8) | ((s32)buf[3]); + data->offset = ((u16)buf[6] << 8) | ((u16)buf[7]); + + ms_byte = (u8)(data->offset >> 13); + is_byte = (u8)((data->offset & 0x1fc0) >> 6); + ls_byte = (u8)(data->offset & 0x3f); + + data->capmain = (((s32)ms_byte * 234000) + ((s32)is_byte * 9000) + + ((s32)ls_byte * 450)) + (((s32)data->useful * 50000) / + (8 * 65536)); + + mutex_unlock(&data->read_mutex); + + pr_info("[SX9310]: %s - CapsMain: %d, Useful: %d, Offset: %u\n", + __func__, data->capmain, data->useful, data->offset); +} + +static void sx9310_touchCheckWithRefSensor(struct sx9310_p *data) +{ + s32 threshold; + + threshold = sx9310_get_init_threshold(data); + sx9310_get_data(data); + + if (data->state == IDLE) { + if (data->capmain >= threshold) + send_event(data, ACTIVE); + else + send_event(data, IDLE); + } else { + if (data->capmain < threshold) + send_event(data, IDLE); + else + send_event(data, ACTIVE); + } +} + +static int sx9310_save_caldata(struct sx9310_p *data) +{ + struct file *cal_filp = NULL; + mm_segment_t old_fs; + int ret = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, + S_IRUGO | S_IWUSR | S_IWGRP); + if (IS_ERR(cal_filp)) { + pr_err("[SX9310]: %s - Can't open calibration file\n", + __func__); + set_fs(old_fs); + ret = PTR_ERR(cal_filp); + return ret; + } + + ret = cal_filp->f_op->write(cal_filp, (char *)data->cal_data, + sizeof(int) * 3, &cal_filp->f_pos); + if (ret != (sizeof(int) * 3)) { + pr_err("[SX9310]: %s - Can't write the cal data to file\n", + __func__); + ret = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return ret; +} + +static void sx9310_open_caldata(struct sx9310_p *data) +{ + struct file *cal_filp = NULL; + mm_segment_t old_fs; + int ret; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, + S_IRUGO | S_IWUSR | S_IWGRP); + if (IS_ERR(cal_filp)) { + ret = PTR_ERR(cal_filp); + if (ret != -ENOENT) + pr_err("[SX9310]: %s - Can't open calibration file.\n", + __func__); + else { + pr_info("[SX9310]: %s - There is no calibration file\n", + __func__); + /* calibration status init */ + memset(data->cal_data, 0, sizeof(int) * 3); + } + set_fs(old_fs); + return; + } + + ret = cal_filp->f_op->read(cal_filp, (char *)data->cal_data, + sizeof(int) * 3, &cal_filp->f_pos); + if (ret != (sizeof(int) * 3)) + pr_err("[SX9310]: %s - Can't read the cal data from file\n", + __func__); + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + pr_info("[SX9310]: %s - (%d, %d, %d)\n", __func__, + data->cal_data[0], data->cal_data[1], data->cal_data[2]); +} + +static void irq_set_state(struct sx9310_p *data, int irq_enable) +{ + pr_info("%s - irq_enable : %d, irq_state : %d\n", + __func__, irq_enable, data->irq_state); + + if (irq_enable) { + if(!data->irq_state) { + enable_irq(data->irq); + enable_irq_wake(data->irq); + data->irq_state++; + } + } else { + if(data->irq_state) { + disable_irq(data->irq); + disable_irq_wake(data->irq); + data->irq_state--; + } + } +} + +static int sx9310_set_mode(struct sx9310_p *data, unsigned char mode) +{ + int ret = -EINVAL; + + mutex_lock(&data->mode_mutex); + if (mode == SX9310_MODE_SLEEP) { + ret = sx9310_i2c_write(data, SX9310_CPS_CTRL0_REG, + setup_reg[2].val); + irq_set_state(data, SX9310_IRQ_DISABLE); + } else if (mode == SX9310_MODE_NORMAL) { + ret = sx9310_i2c_write(data, SX9310_CPS_CTRL0_REG, + setup_reg[2].val | ENABLE_CSX); + msleep(20); + + sx9310_set_offset_calibration(data); + msleep(400); + + sx9310_touchCheckWithRefSensor(data); + irq_set_state(data, SX9310_IRQ_ENABLE); + } + + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + + pr_info("[SX9310]: %s - change the mode : %u\n", __func__, mode); + + mutex_unlock(&data->mode_mutex); + return ret; +} + +static int sx9310_do_calibrate(struct sx9310_p *data, bool do_calib) +{ + int ret = 0, useful_min = 32768, useful_max = -32767; + s32 useful_sum = 0; + u8 ms_byte = 0; + u8 is_byte = 0; + u8 ls_byte = 0; + int i = 0; + + if (do_calib == false) { + pr_info("[SX9310]: %s - Erase!\n", __func__); + goto cal_erase; + } + + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_NORMAL); + + sx9310_get_data(data); + data->cal_data[2] = data->offset; + if ((data->cal_data[2] >= LIMIT_PROXOFFSET) + || (data->cal_data[2] == 0)) { + pr_err("[SX9310]: %s - offset fail(%d)\n", __func__, + data->cal_data[2]); + goto cal_fail; + } + + for (i = 0; i < 8; i++) { + mdelay(90); + sx9310_get_data(data); + useful_sum += data->useful; + if (data->useful > useful_max) + useful_max = data->useful; + if (data->useful < useful_min) + useful_min = data->useful; + + pr_info("[SX9310]: %s - useful(%d)-offset(%u)\n", + __func__, data->useful, data->offset); + if (data->offset != data->cal_data[2]) { + data->cal_data[1] = data->useful; + pr_err("[SX9310]: %s - offset fail(%d)-(%d)\n", + __func__, data->cal_data[2], data->offset); + goto cal_fail; + } + } + + data->cal_data[1] = useful_sum >> 3; + if ((useful_max - useful_min) > PROXUSEFUL_DELTA_SPEC) { + pr_err("[SX9310]: %s - useful delta fail(min : %d, max : %d)\n", + __func__, useful_min, useful_max); + goto cal_fail; + } + + if (data->cal_data[1] <= LIMIT_PROXUSEFUL_MIN || + data->cal_data[1] >= LIMIT_PROXUSEFUL_MAX) { + pr_err("[SX9310]: %s - useful spec fail(%d)\n", __func__, + data->cal_data[1]); + goto cal_fail; + } + + ms_byte = (u8)(data->cal_data[2] >> 13); + is_byte = (u8)((data->cal_data[2] & 0x1fc0) >> 6); + ls_byte = (u8)(data->cal_data[2] & 0x3f); + + data->cal_data[0] = (((s32)ms_byte * 234000) + ((s32)is_byte*9000) + + ((s32)ls_byte * 450)) + (((s32)data->cal_data[1] + * 50000) / (8 * 65536)); + + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + + goto exit; + +cal_fail: + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + ret = -1; +cal_erase: + memset(data->cal_data, 0, sizeof(int) * 3); +exit: + pr_info("[SX9310]: %s - (%d, %d, %d)\n", __func__, + data->cal_data[0], data->cal_data[1], data->cal_data[2]); + return ret; +} + +static void sx9310_set_enable(struct sx9310_p *data, int enable) +{ + if (enable) { + data->touch_mode = INIT_TOUCH_MODE; + data->cal_successed = false; + + sx9310_open_caldata(data); + sx9310_set_mode(data, SX9310_MODE_NORMAL); + atomic_set(&data->enable, ON); + } else { + sx9310_set_mode(data, SX9310_MODE_SLEEP); + atomic_set(&data->enable, OFF); + } +} + +static ssize_t sx9310_get_offset_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + sx9310_i2c_read(data, SX9310_IRQSTAT_REG, &val); + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t sx9310_set_offset_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + if (val) + sx9310_set_offset_calibration(data); + + return count; +} + +static ssize_t sx9310_register_write_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int regist = 0, val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sscanf(buf, "%d,%d", ®ist, &val) != 2) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + + sx9310_i2c_write(data, (unsigned char)regist, (unsigned char)val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, regist, val); + + return count; +} + +static ssize_t sx9310_register_read_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int regist = 0; + unsigned char val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sscanf(buf, "%d", ®ist) != 1) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + + sx9310_i2c_read(data, (unsigned char)regist, &val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, regist, val); + + return count; +} + +static ssize_t sx9310_read_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + sx9310_display_data_reg(data); + + return snprintf(buf, PAGE_SIZE, "%d\n", 0); +} + +static ssize_t sx9310_sw_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + + ret = sx9310_i2c_write(data, SX9310_SOFTRESET_REG, SX9310_SOFTRESET); + msleep(300); + + sx9310_initialize_chip(data); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_NORMAL); + + return snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t sx9310_freq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return count; + } + + data->freq = (u16)val; + val = ((val << 3) | 0x05) & 0xff; + sx9310_i2c_write(data, SX9310_CPS_CTRL4_REG, (u8)val); + + pr_info("[SX9310]: %s - Freq : 0x%x\n", __func__, data->freq); + + return count; +} + +static ssize_t sx9310_freq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + pr_info("[SX9310]: %s - Freq : 0x%x\n", __func__, data->freq); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->freq); +} + +static ssize_t sx9310_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR_NAME); +} + +static ssize_t sx9310_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", MODEL_NAME); +} + +static ssize_t sx9310_touch_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->touch_mode); +} + +static ssize_t sx9310_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 proxdiff; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == OFF) + pr_err("[SX9310]: %s - SX9310 was not enabled\n", + __func__); + + sx9310_get_data(data); + proxdiff = (data->useful - data->avg) >> 4; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%u,%d\n", + data->capmain, data->useful, data->offset, proxdiff); +} + +static ssize_t sx9310_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + sx9310_get_init_threshold(data)); +} + +static ssize_t sx9310_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + pr_info("[SX9310]: %s - init threshold %lu\n", __func__, val); + data->init_th = (u8)val; + + return count; +} + +static ssize_t sx9310_normal_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + u16 thresh_temp = 0, hysteresis = 0; + u16 thresh_table[32] = {2, 4, 6, 8, 12, 16, 20, 24, 28, 32,\ + 40, 48, 56, 64, 72, 80, 88, 96, 112, 128,\ + 144, 160, 192, 224, 256, 320, 384, 512, 640, 768,\ + 1024, 1536}; + + thresh_temp = data->normal_th >> 3 & 0x1f; + thresh_temp = thresh_table[thresh_temp]; + + /* CTRL10 */ + hysteresis = setup_reg[11].val>>4 & 0x3; + + switch (hysteresis) { + case 0x01:/* 6% */ + hysteresis = thresh_temp >> 4; + break; + case 0x02:/* 12% */ + hysteresis = thresh_temp >> 3; + break; + case 0x03:/* 25% */ + hysteresis = thresh_temp >> 2; + break; + default: + /* None */ + break; + } + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", thresh_temp + hysteresis, thresh_temp - hysteresis); +} + +static ssize_t sx9310_normal_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + /* It's for normal touch */ + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + pr_info("[SX9310]: %s - normal threshold %lu\n", __func__, val); + data->normal_th_buf = data->normal_th = (u8)(val << 3); + + return count; +} + +static ssize_t sx9310_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", !data->flag_dataskip); +} + +static ssize_t sx9310_onoff_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u8 val; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &val); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + if (val == 0) + data->flag_dataskip = true; + else + data->flag_dataskip = false; + + pr_info("[SX9310]: %s -%u\n", __func__, val); + return count; +} + +static ssize_t sx9310_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + if ((data->cal_successed == false) && (data->cal_data[0] == 0)) + ret = CAL_RET_NONE; + else if ((data->cal_successed == false) && (data->cal_data[0] != 0)) + ret = CAL_RET_EXIST; + else if ((data->cal_successed == true) && (data->cal_data[0] != 0)) + ret = CAL_RET_SUCCESS; + else + ret = CAL_RET_ERROR; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", ret, + data->cal_data[1], data->cal_data[2]); +} + +static ssize_t sx9310_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + bool do_calib; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + do_calib = true; + else if (sysfs_streq(buf, "0")) + do_calib = false; + else { + pr_info("[SX9310]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ret = sx9310_do_calibrate(data, do_calib); + if (ret < 0) { + pr_err("[SX9310]: %s - sx9310_do_calibrate fail(%d)\n", + __func__, ret); + goto exit; + } + + ret = sx9310_save_caldata(data); + if (ret < 0) { + pr_err("[SX9310]: %s - sx9310_save_caldata fail(%d)\n", + __func__, ret); + memset(data->cal_data, 0, sizeof(int) * 3); + goto exit; + } + + pr_info("[SX9310]: %s - %u success!\n", __func__, do_calib); + +exit: + + if ((data->cal_data[0] != 0) && (ret >= 0)) + data->cal_successed = true; + else + data->cal_successed = false; + + return count; +} + +static ssize_t sx9310_select_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->sreg); +} + +static ssize_t sx9310_select_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->sreg = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x)\n", __func__, data->sreg); + + return count; +} + + +static ssize_t sx9310_rw_reg_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->rwreg_val = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x)\n", __func__, data->sreg); + sx9310_i2c_read(data, data->sreg, &data->rwreg_val); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->rwreg_val); +} + +static ssize_t sx9310_rw_reg_val_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->rwreg_val = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x), val(0x%2x)\n", + __func__, data->sreg, data->rwreg_val); + sx9310_i2c_write(data, data->sreg, data->rwreg_val); + + return count; +} +static DEVICE_ATTR(menual_calibrate, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_get_offset_calibration_show, + sx9310_set_offset_calibration_store); +static DEVICE_ATTR(register_write, S_IWUSR | S_IWGRP, + NULL, sx9310_register_write_store); +static DEVICE_ATTR(register_read, S_IWUSR | S_IWGRP, + NULL, sx9310_register_read_store); +static DEVICE_ATTR(readback, S_IRUGO, sx9310_read_data_show, NULL); +static DEVICE_ATTR(reset, S_IRUGO, sx9310_sw_reset_show, NULL); + +static DEVICE_ATTR(name, S_IRUGO, sx9310_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, sx9310_vendor_show, NULL); +static DEVICE_ATTR(mode, S_IRUGO, sx9310_touch_mode_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, sx9310_raw_data_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_calibration_show, sx9310_calibration_store); +static DEVICE_ATTR(onoff, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_onoff_show, sx9310_onoff_store); +static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_threshold_show, sx9310_threshold_store); +static DEVICE_ATTR(normal_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_normal_threshold_show, sx9310_normal_threshold_store); +static DEVICE_ATTR(select_reg, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_select_reg_show, sx9310_select_reg_store); +static DEVICE_ATTR(rw_reg_val, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_rw_reg_val_show, sx9310_rw_reg_val_store); +static DEVICE_ATTR(freq, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_freq_show, sx9310_freq_store); + +static struct device_attribute *sensor_attrs[] = { + &dev_attr_menual_calibrate, + &dev_attr_register_write, + &dev_attr_register_read, + &dev_attr_readback, + &dev_attr_reset, + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_mode, + &dev_attr_raw_data, + &dev_attr_threshold, + &dev_attr_normal_threshold, + &dev_attr_onoff, + &dev_attr_calibration, + &dev_attr_select_reg, + &dev_attr_rw_reg_val, + &dev_attr_freq, + NULL, +}; + +/*****************************************************************************/ +static ssize_t sx9310_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 enable; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &enable); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + pr_info("[SX9310]: %s - new_value = %u\n", __func__, enable); + if ((enable == 0) || (enable == 1)) + sx9310_set_enable(data, (int)enable); + + return size; +} + +static ssize_t sx9310_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&data->enable)); +} + +static ssize_t sx9310_flush_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 enable; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &enable); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + if (enable == 1) { + mutex_lock(&data->mode_mutex); + input_report_rel(data->input, REL_MAX, 1); + input_sync(data->input); + mutex_unlock(&data->mode_mutex); + } + + return size; +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_enable_show, sx9310_enable_store); +static DEVICE_ATTR(flush, S_IWUSR | S_IWGRP, + NULL, sx9310_flush_store); + +static struct attribute *sx9310_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_flush.attr, + NULL +}; + +static struct attribute_group sx9310_attribute_group = { + .attrs = sx9310_attributes +}; + +static void sx9310_touch_process(struct sx9310_p *data, u8 flag) +{ + u8 status = 0; + s32 threshold; + int cnt; + + threshold = sx9310_get_init_threshold(data); + sx9310_get_data(data); + + pr_info("[SX9310]: %s\n", __func__); + sx9310_i2c_read(data, SX9310_STAT0_REG, &status); + + if (flag & SX9310_IRQSTAT_COMPDONE_FLAG) { + if (data->state == IDLE) { + if (status & (CSX_STATUS_REG << MAIN_SENSOR)) + send_event(data, ACTIVE); + else if (data->capmain > threshold) + send_event(data, ACTIVE); + else + pr_info("[SX9310]: %s-already released.\n", + __func__); + } else { /* User released button */ + if (status & (CSX_STATUS_REG << MAIN_SENSOR)) + pr_info("[SX9310]: %s - still touched.\n", + __func__); + else if (data->capmain <= threshold + 300) + send_event(data, IDLE); + else + pr_info("[SX9310]: %s - still touched.\n", + __func__); + } + + return; + } + if (data->state == IDLE) { + if (status & (CSX_STATUS_REG << cnt)) { +#ifdef DEFENCE_CODE_FOR_DEVICE_DAMAGE + if ((data->cal_data[0] - 5000) > data->capmain) { + sx9310_set_offset_calibration(data); + msleep(400); + sx9310_touchCheckWithRefSensor(data); + pr_err("[SX9310]: %s - Defence code for" + " device damage\n", __func__); + return; + } +#endif + send_event(data, ACTIVE); + } else{ + pr_info("[SX9310]: %s - %d already released.\n", + __func__, cnt); + } + } else { /* User released button */ + if (!(status & (CSX_STATUS_REG << cnt))) { + if ((data->touch_mode == INIT_TOUCH_MODE) + && (data->capmain >= threshold)) + pr_info("[SX9310]: %s - IDLE SKIP\n", + __func__); + else + send_event(data , IDLE); + + } else { + pr_info("[SX9310]: %s - %d still touched\n", + __func__, cnt); + } + } +} + +static void sx9310_process_interrupt(struct sx9310_p *data) +{ + u8 flag = 0; + + /* since we are not in an interrupt don't need to disable irq. */ + flag = sx9310_read_irqstate(data); + + if (flag & IRQ_PROCESS_CONDITION) + sx9310_touch_process(data, flag); +} + +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL +static void sx9310_reinit_irq_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, reinit_irq_work); + + if(atomic_read(&data->enable)) { + pr_info("[SX9310]: %s - pre enable is EN. So disable irq\n", + __func__); + irq_set_state(data, SX9310_IRQ_DISABLE); + } + + if (sx9310_get_nirqldo_state(data) == 1) { + pr_info("[SX9310]: %s - init reg\n", __func__); + sx9310_initialize_chip(data); + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + } else + pr_err("[SX9310]: %s - nirq ldo read high %d\n", + __func__, sx9310_get_nirqldo_state(data)); +} + +static irqreturn_t sx9310_reinit_int_th(int irq, void *pdata) +{ + struct sx9310_p *data = pdata; + + if (sx9310_get_nirqldo_state(data) == 1) { + pr_info("[SX9310]: %s - happen irq ldo en\n", + __func__); + wake_lock_timeout(&data->grip_wake_lock, 3 * HZ); + schedule_delayed_work(&data->reinit_irq_work, msecs_to_jiffies(10)); + } else { + pr_err("[SX9310]: %s - nirq ldo read low\n", __func__); + } + + return IRQ_HANDLED; +} +#else +static void sx9310_init_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, init_work); + + int ret = 0; + pr_err("[SX9310]: %s - ldo en read high %d\n", + __func__, gpio_get_value_cansleep(data->gpio_ldoen)); + + if (gpio_get_value_cansleep(data->gpio_ldoen)) { + ret = sx9310_i2c_write(data, + SX9310_SOFTRESET_REG, SX9310_SOFTRESET); + if (ret < 0) { + pr_err("[SX9310]: %s - chip reset failed %d\n", + __func__, ret); + return; + } + msleep(400); + sx9310_initialize_chip(data); + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + } else { + if (data->retry_cnt < 10) { + data->retry_cnt++; + schedule_delayed_work(&data->init_work, + msecs_to_jiffies(500)); + } else { + pr_err("[SX9310]: %s - ldo retry fail\n", __func__); + sensors_remove_symlink(data->input); + } + } +} +#endif + +static void sx9310_irq_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, irq_work); + + if (sx9310_get_nirq_state(data) == 0) + sx9310_process_interrupt(data); + else + pr_err("[SX9310]: %s - nirq read high %d\n", + __func__, sx9310_get_nirq_state(data)); +} + +static irqreturn_t sx9310_interrupt_thread(int irq, void *pdata) +{ + struct sx9310_p *data = pdata; + + if (sx9310_get_nirq_state(data) == 1) { + pr_err("[SX9310]: %s - nirq read high\n", __func__); + } else { + wake_lock_timeout(&data->grip_wake_lock, 3 * HZ); + schedule_delayed_work(&data->irq_work, msecs_to_jiffies(100)); + } + + return IRQ_HANDLED; +} + +static int sx9310_input_init(struct sx9310_p *data) +{ + int ret = 0; + struct input_dev *dev = NULL; + + /* Create the input device */ + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->name = MODULE_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_REL, REL_MISC); + input_set_drvdata(dev, data); + + ret = input_register_device(dev); + if (ret < 0) { + input_free_device(dev); + return ret; + } + + ret = sensors_create_symlink(dev); + if (ret < 0) { + input_unregister_device(dev); + return ret; + } + + ret = sysfs_create_group(&dev->dev.kobj, &sx9310_attribute_group); + if (ret < 0) { + sensors_remove_symlink(dev); + input_unregister_device(dev); + return ret; + } + + /* save the input pointer and finish initialization */ + data->input = dev; + + return 0; +} + +static int sx9310_setup_pin(struct sx9310_p *data) +{ + int ret; + + ret = gpio_request(data->gpio_nirq, "SX9310_nIRQ"); + if (ret < 0) { + pr_err("[SX9310]: %s - gpio %d request failed (%d)\n", + __func__, data->gpio_nirq, ret); + return ret; + } + + ret = gpio_direction_input(data->gpio_nirq); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->gpio_nirq, ret); + gpio_free(data->gpio_nirq); + return ret; + } + + data->irq = gpio_to_irq(data->gpio_nirq); + + /* initailize interrupt reporting */ + ret = request_threaded_irq(data->irq, NULL, sx9310_interrupt_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT + , "sx9310_irq", data); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set request_threaded_irq %d" + " as returning (%d)\n", __func__, data->irq, ret); + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); + return ret; + } + + disable_irq(data->irq); + + ret = gpio_request(data->gpio_ldoen, "SX9310_nIRQ_ldo"); + if (ret < 0) { + pr_err("[SX9310]: %s - gpio %d request failed (%d)\n", + __func__, data->gpio_nirq, ret); + return ret; + } + + ret = gpio_direction_input(data->gpio_ldoen); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->gpio_ldoen, ret); + gpio_free(data->gpio_ldoen); + return ret; + } + + data->irq_ldo = gpio_to_irq(data->gpio_ldoen); + + /* initailize interrupt reporting */ + ret = request_threaded_irq(data->irq_ldo, NULL, sx9310_reinit_int_th, + IRQF_TRIGGER_RISING | IRQF_ONESHOT + , "sx9310_irq_ldo", data); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set sx9310_reinit_int_th %d" + " as returning (%d)\n", __func__, data->irq_ldo, ret); + free_irq(data->irq_ldo, data); + gpio_free(data->gpio_ldoen); + return ret; + } + + return 0; +} +static void sx9310_initialize_variable(struct sx9310_p *data) +{ + data->state= IDLE; + data->touch_mode = INIT_TOUCH_MODE; + data->flag_dataskip = false; + data->cal_successed = false; + data->freq = setup_reg[6].val >> 3; + memset(data->cal_data, 0, sizeof(int) * 3); + atomic_set(&data->enable, OFF); + data->init_th = (int)CONFIG_SENSORS_SX9310_INIT_TOUCH_THRESHOLD; + pr_info("[SX9310]: %s - Init Touch Threshold : %d\n", + __func__, data->init_th); + data->normal_th = (u8)CONFIG_SENSORS_SX9310_NORMAL_TOUCH_THRESHOLD; + data->normal_th_buf = data->normal_th; + pr_info("[SX9310]: %s - Normal Touch Threshold : %u\n", + __func__, data->normal_th); +} + +static int sx9310_parse_dt(struct sx9310_p *data, struct device *dev) +{ + struct device_node *dNode = dev->of_node; + enum of_gpio_flags flags; + + if (dNode == NULL) + return -ENODEV; + + data->gpio_nirq = of_get_named_gpio_flags(dNode, + "sx9310-i2c,nirq-gpio", 0, &flags); + if (data->gpio_nirq < 0) { + pr_err("[SX9310]: %s - get gpio_nirq error\n", __func__); + return -ENODEV; + } + + data->gpio_ldoen = of_get_named_gpio_flags(dNode, + "sx9310-i2c,ldo-en", 0, &flags); + if (data->gpio_ldoen < 0) { + pr_err("[SX9310]: %s - get gpio_ldoen error\n", __func__); + } + + return 0; +} + +static int sx9310_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = -ENODEV; + struct sx9310_p *data = NULL; + + pr_info("[SX9310]: %s - Probe Start!\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("[SX9310]: %s - i2c_check_functionality error\n", + __func__); + goto exit; + } + + /* create memory for main struct */ + data = kzalloc(sizeof(struct sx9310_p), GFP_KERNEL); + if (data == NULL) { + pr_err("[SX9310]: %s - kzalloc error\n", __func__); + ret = -ENOMEM; + goto exit_kzalloc; + } + + ret = sx9310_parse_dt(data, &client->dev); + if (ret < 0) { + pr_err("[SX9310]: %s - of_node error\n", __func__); + ret = -ENODEV; + goto exit_of_node; + } + + ret = sx9310_setup_pin(data); + if (ret) { + pr_err("[SX9310]: %s - could not setup pin\n", __func__); + goto exit_setup_pin; + } + + i2c_set_clientdata(client, data); + data->client = client; + data->factory_device = &client->dev; + data->retry_cnt = 0; + data->irq_state = 0; + + ret = sx9310_input_init(data); + if (ret < 0) + goto exit_input_init; + + wake_lock_init(&data->grip_wake_lock, + WAKE_LOCK_SUSPEND, "grip_wake_lock"); + + ret = sensors_register(data->factory_device, + data, sensor_attrs, MODULE_NAME); + + if (ret) { + pr_err("[SENSOR] %s - cound not register grip_sensor(%d).\n", + __func__, ret); + goto grip_sensor_register_failed; + } + + sx9310_initialize_variable(data); +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + INIT_DELAYED_WORK(&data->reinit_irq_work, sx9310_reinit_irq_work_func); +#else + INIT_DELAYED_WORK(&data->init_work, sx9310_init_work_func); + schedule_delayed_work(&data->init_work, msecs_to_jiffies(5000)); +#endif + INIT_DELAYED_WORK(&data->irq_work, sx9310_irq_work_func); + mutex_init(&data->mode_mutex); + mutex_init(&data->read_mutex); + + pr_info("[SX9310]: %s - Probe done!\n", __func__); + + return 0; +grip_sensor_register_failed: + input_unregister_device(data->input); +exit_input_init: + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); +exit_setup_pin: +exit_of_node: + kfree(data); +exit_kzalloc: +exit: + pr_err("[SX9310]: %s - Probe fail!\n", __func__); + return ret; +} + +static int sx9310_remove(struct i2c_client *client) +{ + struct sx9310_p *data = (struct sx9310_p *)i2c_get_clientdata(client); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + cancel_delayed_work_sync(&data->reinit_irq_work); +#else + cancel_delayed_work_sync(&data->init_work); +#endif + cancel_delayed_work_sync(&data->irq_work); + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); + free_irq(data->irq_ldo, data); + gpio_free(data->gpio_ldoen); + + wake_lock_destroy(&data->grip_wake_lock); + sensors_unregister(data->factory_device, sensor_attrs); + sensors_remove_symlink(data->input); + sysfs_remove_group(&data->input->dev.kobj, &sx9310_attribute_group); + input_unregister_device(data->input); + mutex_destroy(&data->mode_mutex); + mutex_destroy(&data->read_mutex); + + kfree(data); + + return 0; +} + +static int sx9310_suspend(struct device *dev) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + pr_info("[SX9310]: %s\n", __func__); + + return 0; +} + +static int sx9310_resume(struct device *dev) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + pr_info("[SX9310]: %s\n", __func__); + + return 0; +} + +static struct of_device_id sx9310_match_table[] = { + { .compatible = "sx9310-i2c",}, + {}, +}; + +static const struct i2c_device_id sx9310_id[] = { + { "sx9310_match_table", 0 }, + { } +}; + +static const struct dev_pm_ops sx9310_pm_ops = { + .suspend = sx9310_suspend, + .resume = sx9310_resume, +}; + +static struct i2c_driver sx9310_driver = { + .driver = { + .name = MODEL_NAME, + .owner = THIS_MODULE, + .of_match_table = sx9310_match_table, + .pm = &sx9310_pm_ops + }, + .probe = sx9310_probe, + .remove = sx9310_remove, + .id_table = sx9310_id, +}; + +static int __init sx9310_init(void) +{ + return i2c_add_driver(&sx9310_driver); +} + +static void __exit sx9310_exit(void) +{ + i2c_del_driver(&sx9310_driver); +} + +module_init(sx9310_init); +module_exit(sx9310_exit); + +MODULE_DESCRIPTION("Semtech Corp. SX9310 Capacitive Touch Controller Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/brcm/sx9310_reg.h b/drivers/sensorhub/brcm/sx9310_reg.h new file mode 100644 index 000000000000..6a1ad4b80759 --- /dev/null +++ b/drivers/sensorhub/brcm/sx9310_reg.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef _SX9310_I2C_REG_H_ +#define _SX9310_I2C_REG_H_ + +/* + * I2C Registers + */ +#define SX9310_IRQSTAT_REG 0x00 +#define SX9310_STAT0_REG 0x01 +#define SX9310_STAT1_REG 0x02 +#define SX9310_IRQ_ENABLE_REG 0x03 +#define SX9310_IRQFUNC_REG 0x04 +#define SX9310_CPS_CTRL0_REG 0x10 +#define SX9310_CPS_CTRL1_REG 0x11 +#define SX9310_CPS_CTRL2_REG 0x12 +#define SX9310_CPS_CTRL3_REG 0x13 +#define SX9310_CPS_CTRL4_REG 0x14 +#define SX9310_CPS_CTRL5_REG 0x15 +#define SX9310_CPS_CTRL6_REG 0x16 +#define SX9310_CPS_CTRL7_REG 0x17 +#define SX9310_CPS_CTRL8_REG 0x18 +#define SX9310_CPS_CTRL9_REG 0x19 +#define SX9310_CPS_CTRL10_REG 0x1A +#define SX9310_CPS_CTRL11_REG 0x1B +#define SX9310_CPS_CTRL12_REG 0x1C +#define SX9310_CPS_CTRL13_REG 0x1D +#define SX9310_CPS_CTRL14_REG 0x1E +#define SX9310_CPS_CTRL15_REG 0x1F +#define SX9310_CPS_CTRL16_REG 0x20 +#define SX9310_CPS_CTRL17_REG 0x21 +#define SX9310_CPS_CTRL18_REG 0x22 +#define SX9310_CPS_CTRL19_REG 0x23 +#define SX9310_SAR_CTRL0_REG 0x2A +#define SX9310_SAR_CTRL1_REG 0x2B +#define SX9310_SAR_CTRL2_REG 0x2C + +#define SX9310_SOFTRESET_REG 0x7F + +/* Sensor Readback */ +#define SX9310_REGSENSORSELECT 0x30 +#define SX9310_REGUSEMSB 0x31 +#define SX9310_REGUSELSB 0x32 +#define SX9310_REGAVGMSB 0x33 +#define SX9310_REGAVGLSB 0x34 +#define SX9310_REGDIFFMSB 0x35 +#define SX9310_REGDIFFLSB 0x36 +#define SX9310_REGOFFSETMSB 0x37 +#define SX9310_REGOFFSETLSB 0x38 +#define SX9310_SARMSB 0x39 +#define SX9310_SARLSB 0x3A + +/*Miscellaneous register */ +#define SX9310_I2CADDRSET_REG 0x40 + +/* IrqStat 0:Inactive 1:Active */ +#define SX9310_IRQSTAT_RESET_FLAG 0x80 +#define SX9310_IRQSTAT_TOUCH_FLAG 0x40 +#define SX9310_IRQSTAT_RELEASE_FLAG 0x20 +#define SX9310_IRQSTAT_COMPDONE_FLAG 0x10 +#define SX9310_IRQSTAT_CONV_FLAG 0x08 +#define SX9310_IRQSTAT_SMARTSAR_FLAG 0x01 + +/* CpsStat */ +#define SX9310_TCHCMPSTAT_TCHCOMB_FLAG 0x08 +#define SX9310_TCHCMPSTAT_TCHSTAT2_FLAG 0x04 +#define SX9310_TCHCMPSTAT_TCHSTAT1_FLAG 0x02 +#define SX9310_TCHCMPSTAT_TCHSTAT0_FLAG 0x01 + +/* SoftReset */ +#define SX9310_SOFTRESET 0xDE + + +// #define SX9310_CS2_GND +#define SX9310_CS0_GND + +struct smtc_reg_data { + unsigned char reg; + unsigned char val; +}; + +static const struct smtc_reg_data setup_reg[] = { + { + .reg = SX9310_IRQ_ENABLE_REG, + .val = 0x70, + }, + { + .reg = SX9310_IRQFUNC_REG, + .val = 0x00, + }, + { + .reg = SX9310_CPS_CTRL0_REG, + .val = 0x10, + }, + { + .reg = SX9310_CPS_CTRL1_REG, + .val = 0x00, + }, +#if defined(SX9310_CS2_GND) + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x06, + }, +#elif defined(SX9310_CS0_GND) + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x00, + }, +#else + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x00, + }, +#endif + { + .reg = SX9310_CPS_CTRL3_REG, + .val = 0x0F, + }, + { + .reg = SX9310_CPS_CTRL4_REG, + .val = 0x0D, + }, + { + .reg = SX9310_CPS_CTRL5_REG, + .val = 0xC3, + }, + { + .reg = SX9310_CPS_CTRL6_REG, + .val = 0x20, + }, + { + .reg = SX9310_CPS_CTRL7_REG, + .val = 0x4B, + }, + { + .reg = SX9310_CPS_CTRL8_REG, + .val = 0x7E, + }, + { + .reg = SX9310_CPS_CTRL9_REG, + .val = 0x7D, + }, + { + .reg = SX9310_CPS_CTRL10_REG, + .val = 0x10, + }, +#if defined(SX9310_CS2_GND) + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x00, + }, +#elif defined(SX9310_CS0_GND) + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x01, + }, +#else + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x00, + }, +#endif +}; + +enum { + OFF = 0, + ON = 1 +}; + +extern int sensors_create_symlink(struct input_dev *inputdev); +extern void sensors_remove_symlink(struct input_dev *inputdev); +extern int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name); +extern void sensors_unregister(struct device *dev, + struct device_attribute *attributes[]); + +#endif /* _SX9310_I2C_REG_H_*/ diff --git a/drivers/sensorhub/stm/Kconfig b/drivers/sensorhub/stm/Kconfig index 74a4f1184762..25991f893b0e 100644 --- a/drivers/sensorhub/stm/Kconfig +++ b/drivers/sensorhub/stm/Kconfig @@ -24,17 +24,6 @@ config SENSORS_SSP_STM To compile this driver as a module, choose M here: the module will be called ssp. -config SENSORS_SSP_AK09911 - tristate "Sensors ssp ak09911" - default n - depends on SPI - help - ak09911 file for factory test and doeplus in ssp driver. - If you say yes here you get ak09911 support for - factory test. - To compile this driver as a module, choose M here: the - module will be called ssp. - config SENSORS_MAX86900 tristate "MAXIM MAX86900 HRM Sensor" default n @@ -69,5 +58,57 @@ config SENSORS_SSP_IRDATA_FOR_CAMERA help If you want to use irdata, it should be set. +config SENSORS_SX9310 + depends on I2C + tristate "SX9310 driver" + default n + help + Say Y here if you use sx9310. + This option enables grip sensors using + SemTech sx9310 device driver. + Say N here if you do not use sx9310. + +config SENSORS_SX9310_INIT_TOUCH_THRESHOLD + int "SX9310 Grip sensor threshold for init touch" + depends on SENSORS_SX9310 + default "3000" + help + This value is the standard of init touch using + SemTech sx9310 device driver. + +config SENSORS_SX9310_NORMAL_TOUCH_THRESHOLD + int "SX9310 Grip sensor threshold for normal touch" + depends on SENSORS_SX9310 + default "17" + help + This value is the standard of normal touch using + SemTech sx9310 device driver. + +config SENSORS_SX9310_CP_LDO_CONTROL + depends on SENSORS_SX9310 + tristate "SX9310 driver" + default n + help + Say Y here if you control grip power in cp. + Say N here if you do not use grip power in cp. + +config SENSORS_SSP_NOBLELTE + tristate "Sensors ssp for noble project" + default n + help + If you want to use noble project, it should be set. + +config SENSORS_SSP_ZENLTE + tristate "Sensors ssp for zen project" + default n + help + If you want to use zen project, it should be set. + +config SENSORS_SSP_VLTE + tristate "Sensors ssp for v project" + default n + help + If you want to use v project, it should be set. + source "drivers/sensorhub/stm/factory/Kconfig" source "drivers/sensorhub/brcm/max_notchfilter/Kconfig" diff --git a/drivers/sensorhub/stm/Makefile b/drivers/sensorhub/stm/Makefile index 1267b7d2e719..891a0b007a3d 100644 --- a/drivers/sensorhub/stm/Makefile +++ b/drivers/sensorhub/stm/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_SENSORS_SSP) += sensors_core.o ssp_dev.o ssp_spi.o ssp_data.o ssp_sysfs.o \ ssp_iio.o ssp_firmware.o ssp_debug.o ssp_sensorhub.o \ ssp_misc.o factory/ - +obj-$(CONFIG_SENSORS_SX9310) += sx9310.o obj-$(CONFIG_SENSORS_MAX86900) += max86900.o obj-$(CONFIG_SENSORS_MAX86902) += max86902.o obj-$(CONFIG_SENSORS_MAX_NOTCHFILTER) += max_notchfilter/ diff --git a/drivers/sensorhub/stm/factory/Kconfig b/drivers/sensorhub/stm/factory/Kconfig index 49d8eca1ec59..dbbff7faf25b 100644 --- a/drivers/sensorhub/stm/factory/Kconfig +++ b/drivers/sensorhub/stm/factory/Kconfig @@ -24,6 +24,17 @@ config SENSORS_SSP_MPU6500 To compile this driver as a module, choose M here: the module will be called ssp. +config SENSORS_SSP_BMI168 + tristate "Sensors ssp bmi168" + default n + depends on SPI + help + bmi168 file for factory test in ssp driver. + If you say yes here you get bmi168 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + config SENSORS_SSP_BMP280 tristate "Sensors ssp bmp280" default n @@ -46,6 +57,28 @@ config SENSORS_SSP_TMD4903 To compile this driver as a module, choose M here: the module will be called ssp. +config SENSORS_SSP_TMG399X + tristate "Sensors ssp tmg399x" + default n + depends on SPI + help + tmg399x file for factory test in ssp driver. + If you say yes here you get tmg399x support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + +config SENSORS_SSP_AK09911 + tristate "Sensors ssp ak09911" + default n + depends on SPI + help + ak09911 file for factory test and doeplus in ssp driver. + If you say yes here you get ak09911 support for + factory test. + To compile this driver as a module, choose M here: the + module will be called ssp. + config SENSORS_SSP_MOBEAM tristate "Sensors ssp mobeam" default n diff --git a/drivers/sensorhub/stm/factory/Makefile b/drivers/sensorhub/stm/factory/Makefile index 5a546de6e219..9a5b1463d9db 100644 --- a/drivers/sensorhub/stm/factory/Makefile +++ b/drivers/sensorhub/stm/factory/Makefile @@ -4,7 +4,9 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SENSORS_SSP_MPU6500) += accel_mpu6500.o gyro_mpu6500.o +obj-$(CONFIG_SENSORS_SSP_BMI168) += accel_bmi168.o gyro_bmi168.o obj-$(CONFIG_SENSORS_SSP_TMD4903) += light_tmg399x.o prox_tmg399x.o gesture_tmg399x.o irled_tmd4903.o +obj-$(CONFIG_SENSORS_SSP_TMG399X) += light_tmg399x.o prox_tmg399x.o gesture_tmg399x.o obj-$(CONFIG_SENSORS_SSP_AK09911) += magnetic_ak09911.o obj-$(CONFIG_SENSORS_SSP_BMP280) += pressure_bmp280.o obj-$(CONFIG_SENSORS_SSP_ATUC128L5HAR) += mcu_atuc128l5har.o diff --git a/drivers/sensorhub/stm/factory/accel_bmi168.c b/drivers/sensorhub/stm/factory/accel_bmi168.c new file mode 100644 index 000000000000..63af23c1e68f --- /dev/null +++ b/drivers/sensorhub/stm/factory/accel_bmi168.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2015, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "BOSCH" +#define CHIP_ID "BMI168" + +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/calibration_data" +#define CALIBRATION_DATA_AMOUNT 20 + +#define MAX_ACCEL_1G 8192 +#define MAX_ACCEL_2G 16384 +#define MIN_ACCEL_2G -16383 +#define MAX_ACCEL_4G 32768 + +static ssize_t accel_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t accel_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int accel_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_infof("open accel calibration %d, %d, %d\n", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + if ((data->accelcal.x == 0) && (data->accelcal.y == 0) + && (data->accelcal.z == 0)) + return ERROR; + + return iRet; +} + +int set_accel_cal(struct ssp_data *data) +{ + int iRet = 0; + struct ssp_msg *msg; + s16 accel_cal[3]; + + if (!(data->uSensorState & (1 << ACCELEROMETER_SENSOR))) { + pr_info("[SSP]: %s - Skip this function!!!"\ + ", accel sensor is not connected(0x%x)\n", + __func__, data->uSensorState); + return iRet; + } + accel_cal[0] = data->accelcal.x; + accel_cal[1] = data->accelcal.y; + accel_cal[2] = data->accelcal.z; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = MSG2SSP_AP_MCU_SET_ACCEL_CAL; + msg->length = 6; + msg->options = AP2HUB_WRITE; + msg->buffer = (char*) kzalloc(6, GFP_KERNEL); + + msg->free_buffer = 1; + memcpy(msg->buffer, accel_cal, 6); + + iRet = ssp_spi_async(data, msg); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); + iRet = ERROR; + } + + pr_info("[SSP] Set accel cal data %d, %d, %d\n", accel_cal[0], accel_cal[1], accel_cal[2]); + return iRet; +} + +static int enable_accel_for_cal(struct ssp_data *data) +{ + u8 uBuf[9] = { 0, }; + s32 dMsDelay = get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]); + memcpy(&uBuf[0], &dMsDelay, 4); + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + if (get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]) != 10) { + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 9); + return SUCCESS; + } + } else { + send_instruction(data, ADD_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 9); + } + + return FAIL; +} + +static void disable_accel_for_cal(struct ssp_data *data, int iDelayChanged) +{ + u8 uBuf[9] = { 0, }; + s32 dMsDelay = get_msdelay(data->adDelayBuf[ACCELEROMETER_SENSOR]); + memcpy(&uBuf[0], &dMsDelay, 4); + + if (atomic_read(&data->aSensorEnable) & (1 << ACCELEROMETER_SENSOR)) { + if (iDelayChanged) + send_instruction(data, CHANGE_DELAY, + ACCELEROMETER_SENSOR, uBuf, 9); + } else { + send_instruction(data, REMOVE_SENSOR, + ACCELEROMETER_SENSOR, uBuf, 4); + } +} + +static int accel_do_calibrate(struct ssp_data *data, int iEnable) +{ + int iSum[3] = { 0, }; + int iRet = 0, iCount; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + if (iEnable) { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + set_accel_cal(data); + + iRet = enable_accel_for_cal(data); + msleep(300); + + for (iCount = 0; iCount < CALIBRATION_DATA_AMOUNT; iCount++) { + iSum[0] += data->buf[ACCELEROMETER_SENSOR].x; + iSum[1] += data->buf[ACCELEROMETER_SENSOR].y; + iSum[2] += data->buf[ACCELEROMETER_SENSOR].z; + mdelay(10); + } + disable_accel_for_cal(data, iRet); + + data->accelcal.x = (iSum[0] / CALIBRATION_DATA_AMOUNT); + data->accelcal.y = (iSum[1] / CALIBRATION_DATA_AMOUNT); + data->accelcal.z = (iSum[2] / CALIBRATION_DATA_AMOUNT); + + if (data->accelcal.z > 0) + data->accelcal.z -= MAX_ACCEL_1G; + else if (data->accelcal.z < 0) + data->accelcal.z += MAX_ACCEL_1G; + } else { + data->accelcal.x = 0; + data->accelcal.y = 0; + data->accelcal.z = 0; + } + + ssp_info("do accel calibrate %d, %d, %d", + data->accelcal.x, data->accelcal.y, data->accelcal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY, 0660); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return iRet; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->accelcal, + 3 * sizeof(int), &cal_filp->f_pos); + if (iRet != 3 * sizeof(int)) { + pr_err("[SSP]: %s - Can't write the accelcal to file\n", + __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + set_accel_cal(data); + return iRet; +} + +static ssize_t accel_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int iRet; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = accel_open_calibration(data); + if (iRet < 0) + pr_err("[SSP]: %s - calibration open failed(%d)\n", __func__, iRet); + + ssp_info("Cal data : %d %d %d - %d", + data->accelcal.x, data->accelcal.y, data->accelcal.z, iRet); + + return sprintf(buf, "%d %d %d %d\n", iRet, data->accelcal.x, + data->accelcal.y, data->accelcal.z); +} + +static ssize_t accel_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet; + int64_t dEnable; + struct ssp_data *data = dev_get_drvdata(dev); + + iRet = kstrtoll(buf, 10, &dEnable); + if (iRet < 0) + return iRet; + + iRet = accel_do_calibrate(data, (int)dEnable); + if (iRet < 0) + pr_err("[SSP]: %s - accel_do_calibrate() failed\n", __func__); + + return size; +} + +static ssize_t raw_data_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", + data->buf[ACCELEROMETER_SENSOR].x, + data->buf[ACCELEROMETER_SENSOR].y, + data->buf[ACCELEROMETER_SENSOR].z); +} + +static ssize_t accel_reactive_alert_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet = 0; + char chTempBuf = 1; + struct ssp_data *data = dev_get_drvdata(dev); + + struct ssp_msg *msg; + + if (sysfs_streq(buf, "1")) { + ssp_infof("on"); + } else if (sysfs_streq(buf, "0")) { + ssp_infof("off"); + } else if (sysfs_streq(buf, "2")) { + ssp_infof("factory"); + + data->bAccelAlert = 0; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = ACCELEROMETER_FACTORY; + msg->length = 1; + msg->options = AP2HUB_READ; + msg->data = chTempBuf; + msg->buffer = &chTempBuf; + msg->free_buffer = 0; + + iRet = ssp_spi_sync(data, msg, 3000); + data->bAccelAlert = chTempBuf; + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - accel Selftest Timeout!!\n", __func__); + goto exit; + } + + ssp_infof("factory test success!"); + } else { + pr_err("[SSP]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } +exit: + return size; +} + +static ssize_t accel_reactive_alert_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + bool bSuccess = false; + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->bAccelAlert == true) + bSuccess = true; + else + bSuccess = false; + + data->bAccelAlert = false; + return sprintf(buf, "%u\n", bSuccess); +} + +static ssize_t accel_hw_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + char chTempBuf[8] = { 2, 0, }; + s8 init_status = 0, result = -1; + u16 diff_axis[3] = { 0, }; + int iRet; + struct ssp_data *data = dev_get_drvdata(dev); + struct ssp_msg *msg; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = ACCELEROMETER_FACTORY; + msg->length = sizeof(chTempBuf); + msg->options = AP2HUB_READ; + msg->data = chTempBuf[0]; + msg->buffer = chTempBuf; + msg->free_buffer = 0; + + iRet = ssp_spi_sync(data, msg, 3000); + if (iRet != SUCCESS) { + pr_err("[SSP] %s - accel hw selftest Timeout!!\n", __func__); + return sprintf(buf, "%d,%d,%d,%d\n", -5, 0, 0, 0); + } + + init_status = chTempBuf[0]; + diff_axis[0] = (s16)((chTempBuf[2] << 8) + chTempBuf[1]); + diff_axis[1] = (s16)((chTempBuf[4] << 8) + chTempBuf[3]); + diff_axis[2] = (s16)((chTempBuf[6] << 8) + chTempBuf[5]); + result = chTempBuf[7]; + + pr_info("[SSP] %s - %d, %d, %d, %d, %d\n", __func__, + init_status, result, diff_axis[0], diff_axis[1], diff_axis[2]); + return sprintf(buf, "%d,%d,%d,%d\n", + result, diff_axis[0], diff_axis[1], diff_axis[2]); +} + +static ssize_t accel_lowpassfilter_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + int iRet = 0, new_enable = 1; + struct ssp_data *data = dev_get_drvdata(dev); + struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + pr_err("[SSP] %s, failed to alloc memory\n", __func__); + goto exit; + } + + if (sysfs_streq(buf, "1")) + new_enable = 1; + else if (sysfs_streq(buf, "0")) + new_enable = 0; + else + ssp_info(" invalid value!"); + + msg->cmd = MSG2SSP_AP_SENSOR_LPF; + msg->length = 1; + msg->options = AP2HUB_WRITE; + msg->buffer = (char*) kzalloc(1, GFP_KERNEL); + if (msg->buffer == NULL) { + pr_err("[SSP] %s, failed to alloc memory\n", __func__); + kfree(msg); + goto exit; + } + + *msg->buffer = new_enable; + msg->free_buffer = 1; + + iRet = ssp_spi_async(data, msg); + if (iRet != SUCCESS) + pr_err("[SSP] %s - fail %d\n", __func__, iRet); + else + pr_info("[SSP] %s - %d\n", __func__, new_enable); + +exit: + return size; +} + +static DEVICE_ATTR(name, S_IRUGO, accel_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, accel_vendor_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + accel_calibration_show, accel_calibration_store); +static DEVICE_ATTR(raw_data, S_IRUGO, raw_data_read, NULL); +static DEVICE_ATTR(reactive_alert, S_IRUGO | S_IWUSR | S_IWGRP, + accel_reactive_alert_show, accel_reactive_alert_store); +static DEVICE_ATTR(selftest, S_IRUGO, accel_hw_selftest_show, NULL); +static DEVICE_ATTR(lowpassfilter, S_IWUSR | S_IWGRP, + NULL, accel_lowpassfilter_store); + +static struct device_attribute *acc_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_calibration, + &dev_attr_raw_data, + &dev_attr_reactive_alert, + &dev_attr_selftest, + &dev_attr_lowpassfilter, + NULL, +}; + +void initialize_accel_factorytest(struct ssp_data *data) +{ + sensors_register(data->devices[ACCELEROMETER_SENSOR], data, acc_attrs, + data->name[ACCELEROMETER_SENSOR]); +} + +void remove_accel_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->devices[ACCELEROMETER_SENSOR], acc_attrs); +} diff --git a/drivers/sensorhub/stm/factory/accel_mpu6500.c b/drivers/sensorhub/stm/factory/accel_mpu6500.c index 0101685008d8..65423f50bd94 100644 --- a/drivers/sensorhub/stm/factory/accel_mpu6500.c +++ b/drivers/sensorhub/stm/factory/accel_mpu6500.c @@ -18,9 +18,14 @@ /* factory Sysfs */ /*************************************************************************/ +#define INV_ID 0 #define VENDOR "INVENSENSE" #define CHIP_ID "MPU6500" +#define STM_ID 1 +#define VENDOR_STM "STM" +#define CHIP_ID_STM "K6DS3TR" + #define CALIBRATION_FILE_PATH "/efs/FactoryApp/calibration_data" #define CALIBRATION_DATA_AMOUNT 20 @@ -32,13 +37,23 @@ static ssize_t accel_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", VENDOR); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", VENDOR_STM); + else + return sprintf(buf, "%s\n", VENDOR); } static ssize_t accel_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", CHIP_ID); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", CHIP_ID_STM); + else + return sprintf(buf, "%s\n", CHIP_ID); } int accel_open_calibration(struct ssp_data *data) @@ -50,7 +65,7 @@ int accel_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -197,7 +212,7 @@ static int accel_do_calibrate(struct ssp_data *data, int iEnable) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/stm/factory/gyro_bmi168.c b/drivers/sensorhub/stm/factory/gyro_bmi168.c new file mode 100644 index 000000000000..409457852e98 --- /dev/null +++ b/drivers/sensorhub/stm/factory/gyro_bmi168.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2012, Samsung Electronics Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include "../ssp.h" + +/*************************************************************************/ +/* factory Sysfs */ +/*************************************************************************/ + +#define VENDOR "BOSCH" +#define CHIP_ID "BMI168" + +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/gyro_cal_data" +#define CALIBRATION_DATA_AMOUNT 20 +#define SELFTEST_DATA_AMOUNT 64 +#define SELFTEST_LIMITATION_OF_ERROR 5250 + +static ssize_t gyro_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", VENDOR); +} + +static ssize_t gyro_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", CHIP_ID); +} + +int gyro_open_calibration(struct ssp_data *data) +{ + int iRet = 0; + mm_segment_t old_fs; + struct file *cal_filp = NULL; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); + if (IS_ERR(cal_filp)) { + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + + return iRet; + } + + iRet = cal_filp->f_op->read(cal_filp, (char *)&data->gyrocal, + sizeof(data->gyrocal), &cal_filp->f_pos); + if (iRet != sizeof(data->gyrocal)) + iRet = -EIO; + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + ssp_info("open gyro calibration %d, %d, %d", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + return iRet; +} + +int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) +{ + int iRet = 0; + struct file *cal_filp = NULL; + mm_segment_t old_fs; + + if (data->bSspShutdown) + return -EIO; + + data->gyrocal.x = iCalData[0]; + data->gyrocal.y = iCalData[1]; + data->gyrocal.z = iCalData[2]; + + ssp_info("do gyro calibrate %d, %d, %d", + data->gyrocal.x, data->gyrocal.y, data->gyrocal.z); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); + if (IS_ERR(cal_filp)) { + pr_err("[SSP]: %s - Can't open calibration file\n", __func__); + set_fs(old_fs); + iRet = PTR_ERR(cal_filp); + return -EIO; + } + + iRet = cal_filp->f_op->write(cal_filp, (char *)&data->gyrocal, + sizeof(data->gyrocal), &cal_filp->f_pos); + if (iRet != sizeof(data->gyrocal)) { + pr_err("[SSP]: %s - Can't write gyro cal to file\n", __func__); + iRet = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return iRet; +} + +int set_gyro_cal(struct ssp_data *data) +{ + int iRet = 0; + struct ssp_msg *msg; + s16 gyro_cal[3]; + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) { + pr_info("[SSP]: %s - Skip this function!!!"\ + ", gyro sensor is not connected(0x%x)\n", + __func__, data->uSensorState); + return iRet; + } + + gyro_cal[0] = data->gyrocal.x; + gyro_cal[1] = data->gyrocal.y; + gyro_cal[2] = data->gyrocal.z; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = MSG2SSP_AP_MCU_SET_GYRO_CAL; + msg->length = 6; + msg->options = AP2HUB_WRITE; + msg->buffer = (char*) kzalloc(6, GFP_KERNEL); + + msg->free_buffer = 1; + memcpy(msg->buffer, gyro_cal, 6); + + iRet = ssp_spi_async(data, msg); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - i2c fail %d\n", __func__, iRet); + iRet = ERROR; + } + + pr_info("[SSP] Set gyro cal data %d, %d, %d\n", gyro_cal[0], gyro_cal[1], gyro_cal[2]); + return iRet; +} + +static ssize_t gyro_power_off(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_infof(); + + return sprintf(buf, "%d\n", 1); +} + +static ssize_t gyro_power_on(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssp_infof(); + + return sprintf(buf, "%d\n", 1); +} + +short gyro_get_temp(struct ssp_data *data) +{ + char chTempBuf[2] = { 0}; + unsigned char reg[2]; + short temperature = 0; + int iRet = 0; + + struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = GYROSCOPE_TEMP_FACTORY; + msg->length = 2; + msg->options = AP2HUB_READ; + msg->buffer = chTempBuf; + msg->free_buffer = 0; + + iRet = ssp_spi_sync(data, msg, 3000); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Gyro Temp Timeout!!\n", __func__); + goto exit; + } + + reg[0] = chTempBuf[1]; + reg[1] = chTempBuf[0]; + temperature = (short) (((reg[0]) << 8) | reg[1]); + ssp_infof("%d", temperature); + + exit: + return temperature; +} + +static ssize_t gyro_temp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", gyro_get_temp(data)); +} + +static ssize_t gyro_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + char chTempBuf[19] = {0, }; + u8 bist=0, selftest = 0; + int datax_check = 0; + int datay_check = 0; + int dataz_check = 0; + s16 iCalData[3] = {0, }; + int iRet = 0; + + struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->cmd = GYROSCOPE_FACTORY; + msg->length = 19; + msg->options = AP2HUB_READ; + msg->buffer = chTempBuf; + msg->free_buffer = 0; + + iRet = ssp_spi_sync(data, msg, 3000); + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); + selftest = 1; + goto exit; + } + + pr_info("[SSP]: %s - %d %d %d %d %d %d %d %d %d %d %d %d %d\n", + __func__, chTempBuf[0], chTempBuf[1], chTempBuf[2], + chTempBuf[3], chTempBuf[4], chTempBuf[5], chTempBuf[6], + chTempBuf[7], chTempBuf[8], chTempBuf[9], chTempBuf[10], + chTempBuf[11], chTempBuf[12]); + + data->uTimeOutCnt = 0; + + /* 1: X axis fail, 2: X axis fail, 4: X axis fail, 8: Bist fail*/ + selftest = chTempBuf[0]; + if (selftest == 0) + bist = 1; + else + bist =0; + + datax_check = (int)((chTempBuf[4] << 24) + (chTempBuf[3] << 16) + +(chTempBuf[2] << 8) + chTempBuf[1]); + datay_check = (int)((chTempBuf[8] << 24) + (chTempBuf[7] << 16) + +(chTempBuf[6] << 8) + chTempBuf[5]); + dataz_check = (int)((chTempBuf[12] << 24) + (chTempBuf[11] << 16) + +(chTempBuf[10] << 8) + chTempBuf[9]); + + iCalData[0] = (s16)((chTempBuf[14] << 8) + chTempBuf[13]); + iCalData[1] = (s16)((chTempBuf[16] << 8) + chTempBuf[15]); + iCalData[2] = (s16)((chTempBuf[18] << 8) + chTempBuf[17]); + + pr_info("[SSP]: %s - bist: %d, selftest: %d\n", + __func__, bist, selftest); + pr_info("[SSP]: %s - X: %d, Y: %d, Z: %d\n", + __func__, datax_check, datay_check, dataz_check); + pr_info("[SSP]: %s - CalData X: %d, Y: %d, Z: %d\n", + __func__, iCalData[0], iCalData[1], iCalData[2]); + + if ((datax_check <= SELFTEST_LIMITATION_OF_ERROR) + && (datay_check <= SELFTEST_LIMITATION_OF_ERROR) + && (dataz_check <= SELFTEST_LIMITATION_OF_ERROR)) { + pr_info("[SSP]: %s - Gyro zero rate OK!- Gyro selftest Pass\n", + __func__); + /* save_gyro_caldata(data, iCalData); */ + } else { + pr_info("[SSP]: %s - Gyro zero rate NG!- Gyro selftest fail!\n", + __func__); + selftest |= 1; + } +exit: + pr_info("[SSP] %s - %d,%d,%d.%03d,%d.%03d,%d.%03d\n", __func__, + selftest ? 0 : 1, bist, + (datax_check / 1000), (int)abs(datax_check % 1000), + (datay_check / 1000), (int)abs(datay_check % 1000), + (dataz_check / 1000), (int)abs(dataz_check % 1000)); + + return sprintf(buf, "%d,%d,%d.%03d,%d.%03d,%d.%03d,"\ + "%d,%d,%d,%d,%d,%d,%d,%d" "\n", + selftest ? 0 : 1, bist, + (datax_check / 1000), (int)abs(datax_check % 1000), + (datay_check / 1000), (int)abs(datay_check % 1000), + (dataz_check / 1000), (int)abs(dataz_check % 1000), + iRet ,iRet ,iRet ,iRet ,iRet ,iRet ,iRet ,iRet); +} + +static ssize_t gyro_selftest_dps_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int iNewDps = 0; + int iRet = 0; + char chTempBuf = 0; + + struct ssp_data *data = dev_get_drvdata(dev); + + struct ssp_msg *msg; + + if (!(data->uSensorState & (1 << GYROSCOPE_SENSOR))) + goto exit; + + msg = kzalloc(sizeof(*msg), GFP_KERNEL); + msg->cmd = GYROSCOPE_DPS_FACTORY; + msg->length = 1; + msg->options = AP2HUB_READ; + msg->buffer = &chTempBuf; + msg->free_buffer = 0; + + sscanf(buf, "%d", &iNewDps); + + if (iNewDps == GYROSCOPE_DPS250) + msg->options |= 0 << SSP_GYRO_DPS; + else if (iNewDps == GYROSCOPE_DPS500) + msg->options |= 1 << SSP_GYRO_DPS; + else if (iNewDps == GYROSCOPE_DPS2000) + msg->options |= 2 << SSP_GYRO_DPS; + else { + msg->options |= 1 << SSP_GYRO_DPS; + iNewDps = GYROSCOPE_DPS500; + } + + iRet = ssp_spi_sync(data, msg, 3000); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest DPS Timeout!!\n", __func__); + goto exit; + } + + if (chTempBuf != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest DPS Error!!\n", __func__); + goto exit; + } + + data->buf[GYROSCOPE_SENSOR].gyro_dps = (unsigned int)iNewDps; + pr_err("[SSP]: %s - %u dps stored\n", __func__, + data->buf[GYROSCOPE_SENSOR].gyro_dps); +exit: + return count; +} + +static ssize_t gyro_selftest_dps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ssp_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", data->buf[GYROSCOPE_SENSOR].gyro_dps); +} + +static DEVICE_ATTR(name, S_IRUGO, gyro_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, gyro_vendor_show, NULL); +static DEVICE_ATTR(power_off, S_IRUGO, gyro_power_off, NULL); +static DEVICE_ATTR(power_on, S_IRUGO, gyro_power_on, NULL); +static DEVICE_ATTR(temperature, S_IRUGO, gyro_temp_show, NULL); +static DEVICE_ATTR(selftest, S_IRUGO, gyro_selftest_show, NULL); +static DEVICE_ATTR(selftest_dps, S_IRUGO | S_IWUSR | S_IWGRP, + gyro_selftest_dps_show, gyro_selftest_dps_store); + +static struct device_attribute *gyro_attrs[] = { + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_selftest, + &dev_attr_power_on, + &dev_attr_power_off, + &dev_attr_temperature, + &dev_attr_selftest_dps, + NULL, +}; + +void initialize_gyro_factorytest(struct ssp_data *data) +{ + sensors_register(data->devices[GYROSCOPE_SENSOR], data, gyro_attrs, + data->name[GYROSCOPE_SENSOR]); +} + +void remove_gyro_factorytest(struct ssp_data *data) +{ + sensors_unregister(data->devices[GYROSCOPE_SENSOR], gyro_attrs); +} diff --git a/drivers/sensorhub/stm/factory/gyro_mpu6500.c b/drivers/sensorhub/stm/factory/gyro_mpu6500.c index 62d6118ea223..34be7201230b 100644 --- a/drivers/sensorhub/stm/factory/gyro_mpu6500.c +++ b/drivers/sensorhub/stm/factory/gyro_mpu6500.c @@ -19,9 +19,14 @@ /* factory Sysfs */ /*************************************************************************/ +#define INV_ID 0 #define VENDOR "INVENSENSE" #define CHIP_ID "MPU6500" +#define STM_ID 1 +#define VENDOR_STM "STM" +#define CHIP_ID_STM "K6DS3TR" + #define CALIBRATION_FILE_PATH "/efs/FactoryApp/gyro_cal_data" #define VERBOSE_OUT 1 #define CALIBRATION_DATA_AMOUNT 20 @@ -36,16 +41,33 @@ #define DEF_SQRT_SCALE_FOR_RMS (100) #define GYRO_LIB_DL_FAIL 9990 +#define DEF_GYRO_SENS_STM (70) // 0.07 * 1000 +#define DEF_BIAS_LSB_THRESH_SELF_STM (40000 / DEF_GYRO_SENS_STM) + +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) +#endif + static ssize_t gyro_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", VENDOR); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", VENDOR_STM); + else + return sprintf(buf, "%s\n", VENDOR); } static ssize_t gyro_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", CHIP_ID); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", CHIP_ID_STM); + else + return sprintf(buf, "%s\n", CHIP_ID); } int gyro_open_calibration(struct ssp_data *data) @@ -57,7 +79,7 @@ int gyro_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { set_fs(old_fs); iRet = PTR_ERR(cal_filp); @@ -102,7 +124,7 @@ int save_gyro_caldata(struct ssp_data *data, s16 *iCalData) set_fs(KERNEL_DS); cal_filp = filp_open(CALIBRATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW, 0660); if (IS_ERR(cal_filp)) { pr_err("[SSP]: %s - Can't open calibration file\n", __func__); set_fs(old_fs); @@ -175,7 +197,7 @@ static ssize_t gyro_power_on(struct device *dev, return sprintf(buf, "%d\n", 1); } -short mpu6500_gyro_get_temp(struct ssp_data *data) +short do_gyro_get_temp(struct ssp_data *data) { char chTempBuf[2] = { 0}; unsigned char reg[2]; @@ -210,11 +232,11 @@ static ssize_t gyro_get_temp(struct device *dev, { short temperature = 0; struct ssp_data *data = dev_get_drvdata(dev); - temperature = mpu6500_gyro_get_temp(data); + temperature = do_gyro_get_temp(data); return sprintf(buf, "%d\n", temperature); } -u32 mpu6050_selftest_sqrt(u32 sqsum) +u32 selftest_sqrt(u32 sqsum) { u32 sq_rt; u32 g0, g1, g2, g3, g4; @@ -280,6 +302,280 @@ u32 mpu6050_selftest_sqrt(u32 sqsum) return sq_rt; } +static ssize_t k6ds3tr_gyro_selftest(char *buf, struct ssp_data *data) +{ + char chTempBuf[36] = { 0,}; + u8 initialized = 0; + s8 hw_result = 0; + int i = 0, j = 0, total_count = 0, ret_val = 0, gyro_lib_dl_fail = 0; + long avg[3] = {0,}, rms[3] = {0,}; + int gyro_bias[3] = {0,}, gyro_rms[3] = {0,}; + s16 shift_ratio[3] = {0,}; //self_diff value + s16 iCalData[3] = {0,}; + char a_name[3][2] = { "X", "Y", "Z" }; + int iRet = 0; + int dps_rms[3] = { 0, }; + u32 temp = 0; + int bias_thresh = DEF_BIAS_LSB_THRESH_SELF_STM; + int fifo_ret = 0; + int cal_ret = 0; + s16 st_zro[3] = {0, }; + s16 st_bias[3] = {0, }; + int gyro_fifo_avg[3] = {0,}, gyro_self_zro[3] = {0,}; + int gyro_self_bias[3] = {0,}, gyro_self_diff[3] = {0,}; + + struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL); + if (msg == NULL) { + pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__); + goto exit; + } + msg->cmd = GYROSCOPE_FACTORY; + msg->length = 36; + msg->options = AP2HUB_READ; + msg->buffer = chTempBuf; + msg->free_buffer = 0; + + iRet = ssp_spi_sync(data, msg, 7000); + + if (iRet != SUCCESS) { + pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__); + ret_val = 1; + goto exit; + } + + data->uTimeOutCnt = 0; + + pr_err("[SSP]%d %d %d %d %d %d %d %d %d %d %d %d\n", chTempBuf[0], + chTempBuf[1], chTempBuf[2], chTempBuf[3], chTempBuf[4], + chTempBuf[5], chTempBuf[6], chTempBuf[7], chTempBuf[8], + chTempBuf[9], chTempBuf[10], chTempBuf[11]); + + initialized = chTempBuf[0]; + shift_ratio[0] = (s16)((chTempBuf[2] << 8) + + chTempBuf[1]); + shift_ratio[1] = (s16)((chTempBuf[4] << 8) + + chTempBuf[3]); + shift_ratio[2] = (s16)((chTempBuf[6] << 8) + + chTempBuf[5]); + hw_result = (s8)chTempBuf[7]; + total_count = (int)((chTempBuf[11] << 24) + + (chTempBuf[10] << 16) + + (chTempBuf[9] << 8) + + chTempBuf[8]); + avg[0] = (long)((chTempBuf[15] << 24) + + (chTempBuf[14] << 16) + + (chTempBuf[13] << 8) + + chTempBuf[12]); + avg[1] = (long)((chTempBuf[19] << 24) + + (chTempBuf[18] << 16) + + (chTempBuf[17] << 8) + + chTempBuf[16]); + avg[2] = (long)((chTempBuf[23] << 24) + + (chTempBuf[22] << 16) + + (chTempBuf[21] << 8) + + chTempBuf[20]); + rms[0] = (long)((chTempBuf[27] << 24) + + (chTempBuf[26] << 16) + + (chTempBuf[25] << 8) + + chTempBuf[24]); + rms[1] = (long)((chTempBuf[31] << 24) + + (chTempBuf[30] << 16) + + (chTempBuf[29] << 8) + + chTempBuf[28]); + rms[2] = (long)((chTempBuf[35] << 24) + + (chTempBuf[34] << 16) + + (chTempBuf[33] << 8) + + chTempBuf[32]); + + st_zro[0] = (s16)((chTempBuf[25] << 8) + + chTempBuf[24]); + st_zro[1] = (s16)((chTempBuf[27] << 8) + + chTempBuf[26]); + st_zro[2] = (s16)((chTempBuf[29] << 8) + + chTempBuf[28]); + + st_bias[0] = (s16)((chTempBuf[31] << 8) + + chTempBuf[30]); + st_bias[1] = (s16)((chTempBuf[33] << 8) + + chTempBuf[32]); + st_bias[2] = (s16)((chTempBuf[35] << 8) + + chTempBuf[34]); + + pr_info("[SSP] init: %d, total cnt: %d\n", initialized, total_count); + pr_info("[SSP] hw_result: %d, %d, %d, %d\n", hw_result, + shift_ratio[0], shift_ratio[1], shift_ratio[2]); + pr_info("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]); + pr_info("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]); + + //FIFO ZRO check pass / fail + gyro_fifo_avg[0] = avg[0] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_fifo_avg[1] = avg[1] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_fifo_avg[2] = avg[2] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + // ZRO self test + gyro_self_zro[0] = st_zro[0] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_zro[1] = st_zro[1] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_zro[2] = st_zro[2] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + //bias + gyro_self_bias[0] = st_bias[0] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_bias[1] = st_bias[1] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_bias[2] = st_bias[2] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + //diff = bias - ZRO + gyro_self_diff[0] = shift_ratio[0] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_diff[1] = shift_ratio[1] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + gyro_self_diff[2] = shift_ratio[2] * DEF_GYRO_SENS_STM / DEF_SCALE_FOR_FLOAT; + + if (total_count != 128) { + pr_err("[SSP] %s, total_count is not 128. goto exit\n", __func__); + ret_val = 2; + goto exit; + } + else + cal_ret = fifo_ret = 1; + + if (hw_result < 0) { + pr_err("[SSP] %s - hw selftest fail(%d), sw selftest skip\n", + __func__, hw_result); + if (shift_ratio[0] == GYRO_LIB_DL_FAIL && + shift_ratio[1] == GYRO_LIB_DL_FAIL && + shift_ratio[2] == GYRO_LIB_DL_FAIL) { + pr_err("[SSP] %s - gyro lib download fail\n", __func__); + gyro_lib_dl_fail = 1; + } else { +/* + ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", + __func__, + shift_ratio[0] / 10, + shift_ratio[1] / 10, + shift_ratio[2] / 10); + return sprintf(buf, "%d,%d,%d\n", + shift_ratio[0] / 10, + shift_ratio[1] / 10, + shift_ratio[2] / 10); +*/ + ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", __func__, gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); + return sprintf(buf, "%d,%d,%d\n", gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); + } + } + + // AVG value range test +/- 40 + if( (ABS(gyro_fifo_avg[0]) > 40) || (ABS(gyro_fifo_avg[1]) > 40) || (ABS(gyro_fifo_avg[2]) > 40) ) + { + ssp_dbg("[SSP]: %s - %d,%d,%d fail.\n", __func__, gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2]); + return sprintf(buf, "%d,%d,%d\n", gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2]); + } + + // STMICRO + gyro_bias[0] = avg[0] * DEF_GYRO_SENS_STM; + gyro_bias[1] = avg[1] * DEF_GYRO_SENS_STM; + gyro_bias[2] = avg[2] * DEF_GYRO_SENS_STM; + iCalData[0] = (s16)avg[0]; + iCalData[1] = (s16)avg[1]; + iCalData[2] = (s16)avg[2]; + + if (VERBOSE_OUT) { + pr_info("[SSP] abs bias : %+8d.%03d %+8d.%03d %+8d.%03d (dps)\n", + (int)abs(gyro_bias[0]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[0]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[1]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[1]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[2]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_bias[2]) % DEF_SCALE_FOR_FLOAT); + } + + for (j = 0; j < 3; j++) { + if (unlikely(abs(avg[j]) > bias_thresh)) { + pr_err("[SSP] %s-Gyro bias (%ld) exceeded threshold " + "(threshold = %d LSB)\n", a_name[j], + avg[j], bias_thresh); + ret_val |= 1 << (3 + j); + } + } +// STMICRO + /* 3rd, check RMS for dead gyros + If any of the RMS noise value returns zero, + then we might have dead gyro or FIFO/register failure, + the part is sleeping, or the part is not responsive */ + //if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0) + //ret_val |= 1 << 6; + + if (VERBOSE_OUT) { + pr_info("[SSP] RMS ^ 2 : %+8ld %+8ld %+8ld\n", + (long)rms[0] / total_count, + (long)rms[1] / total_count, (long)rms[2] / total_count); + } + + for (i = 0; i < 3; i++) { + if (rms[i] > 10000) { + temp = + ((u32) (rms[i] / total_count)) * + DEF_RMS_SCALE_FOR_RMS; + } else { + temp = + ((u32) (rms[i] * DEF_RMS_SCALE_FOR_RMS)) / + total_count; + } + if (rms[i] < 0) + temp = 1 << 31; + + dps_rms[i] = selftest_sqrt(temp) / DEF_GYRO_SENS_STM; + + gyro_rms[i] = + dps_rms[i] * DEF_SCALE_FOR_FLOAT / DEF_SQRT_SCALE_FOR_RMS; + } + + pr_info("[SSP] RMS : %+8d.%03d %+8d.%03d %+8d.%03d (dps)\n", + (int)abs(gyro_rms[0]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[0]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[1]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[1]) % DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[2]) / DEF_SCALE_FOR_FLOAT, + (int)abs(gyro_rms[2]) % DEF_SCALE_FOR_FLOAT); + + if (gyro_lib_dl_fail) { + pr_err("[SSP] gyro_lib_dl_fail, Don't save cal data\n"); + ret_val = -1; + goto exit; + } + + if (likely(!ret_val)) { + save_gyro_caldata(data, iCalData); + } else { + pr_err("[SSP] ret_val != 0, gyrocal is 0 at all axis\n"); + data->gyrocal.x = 0; + data->gyrocal.y = 0; + data->gyrocal.z = 0; + } +exit: + ssp_dbg("[SSP]: %s - " + "%d,%d,%d," + "%d,%d,%d," + "%d,%d,%d," + "%d,%d,%d,%d,%d\n", + __func__, + gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2], + gyro_self_zro[0], gyro_self_zro[1], gyro_self_zro[2], + gyro_self_bias[0], gyro_self_bias[1], gyro_self_bias[2], + gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2], + fifo_ret, + cal_ret); + + // Gyro Calibration pass / fail, buffer 1~6 values. + if( (fifo_ret == 0) || (cal_ret == 0) ) + return sprintf(buf, "%d,%d,%d\n", gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2]); + + return sprintf(buf, + "%d,%d,%d," + "%d,%d,%d," + "%d,%d,%d," + "%d,%d,%d,%d,%d\n", + gyro_fifo_avg[0], gyro_fifo_avg[1], gyro_fifo_avg[2], + gyro_self_zro[0], gyro_self_zro[1], gyro_self_zro[2], + gyro_self_bias[0], gyro_self_bias[1], gyro_self_bias[2], + gyro_self_diff[0], gyro_self_diff[1], gyro_self_diff[2], + fifo_ret, + cal_ret); +} + ssize_t mpu6500_gyro_selftest(char *buf, struct ssp_data *data) { char chTempBuf[36] = { 0,}; @@ -439,7 +735,7 @@ ssize_t mpu6500_gyro_selftest(char *buf, struct ssp_data *data) if (rms[i] < 0) temp = 1 << 31; - dps_rms[i] = mpu6050_selftest_sqrt(temp) / DEF_GYRO_SENS; + dps_rms[i] = selftest_sqrt(temp) / DEF_GYRO_SENS; gyro_rms[i] = dps_rms[i] * DEF_SCALE_FOR_FLOAT / DEF_SQRT_SCALE_FOR_RMS; @@ -525,7 +821,11 @@ static ssize_t gyro_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ssp_data *data = dev_get_drvdata(dev); - return mpu6500_gyro_selftest(buf, data); + + if (data->acc_type == STM_ID) + return k6ds3tr_gyro_selftest(buf, data); + else + return mpu6500_gyro_selftest(buf, data); } static ssize_t gyro_selftest_dps_store(struct device *dev, diff --git a/drivers/sensorhub/stm/factory/irled_tmd4903.c b/drivers/sensorhub/stm/factory/irled_tmd4903.c index 871707b8ad5e..1d7a4b402704 100644 --- a/drivers/sensorhub/stm/factory/irled_tmd4903.c +++ b/drivers/sensorhub/stm/factory/irled_tmd4903.c @@ -27,7 +27,7 @@ static ssize_t irled_send_store(struct device *dev, unsigned int buf_len = 0; unsigned int iRet; - buf_len = strlen(buf)+1; + buf_len = (unsigned int)strlen(buf)+1; msg = kzalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { pr_err("[SSP]: %s - failed to allocate memory\n", __func__); diff --git a/drivers/sensorhub/stm/factory/pressure_bmp280.c b/drivers/sensorhub/stm/factory/pressure_bmp280.c index 18b82988d5bc..894493a026ad 100644 --- a/drivers/sensorhub/stm/factory/pressure_bmp280.c +++ b/drivers/sensorhub/stm/factory/pressure_bmp280.c @@ -14,9 +14,14 @@ */ #include "../ssp.h" +#define BOSCH_ID 0 #define VENDOR "BOSCH" #define CHIP_ID "BMP280" +#define STM_ID 1 +#define VENDOR_STM "STM" +#define CHIP_ID_STM "LPS25H" + #define CALIBRATION_FILE_PATH "/efs/FactoryApp/baro_delta" #define PR_ABS_MAX 8388607 /* 24 bit 2'compl */ @@ -53,7 +58,7 @@ int pressure_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0666); + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cal_filp)) { iErr = PTR_ERR(cal_filp); if (iErr != -ENOENT) @@ -149,13 +154,23 @@ static ssize_t eeprom_check_show(struct device *dev, static ssize_t pressure_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", VENDOR); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", VENDOR_STM); + else + return sprintf(buf, "%s\n", VENDOR); } static ssize_t pressure_name_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", CHIP_ID); + struct ssp_data *data = dev_get_drvdata(dev); + + if (data->acc_type == STM_ID) + return sprintf(buf, "%s\n", CHIP_ID_STM); + else + return sprintf(buf, "%s\n", CHIP_ID); } static DEVICE_ATTR(vendor, S_IRUGO, pressure_vendor_show, NULL); diff --git a/drivers/sensorhub/stm/factory/prox_tmg399x.c b/drivers/sensorhub/stm/factory/prox_tmg399x.c index 5a988318bdc3..a18c132c2c43 100644 --- a/drivers/sensorhub/stm/factory/prox_tmg399x.c +++ b/drivers/sensorhub/stm/factory/prox_tmg399x.c @@ -139,7 +139,7 @@ static int proximity_open_lcd_ldi(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(LCD_LDI_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -207,7 +207,7 @@ int proximity_open_calibration(struct ssp_data *data) old_fs = get_fs(); set_fs(KERNEL_DS); - cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0666); + cancel_filp = filp_open(CANCELATION_FILE_PATH, O_RDONLY, 0660); if (IS_ERR(cancel_filp)) { iRet = PTR_ERR(cancel_filp); if (iRet != -ENOENT) @@ -299,7 +299,7 @@ static int proximity_store_cancelation(struct ssp_data *data, int iCalCMD) set_fs(KERNEL_DS); cancel_filp = filp_open(CANCELATION_FILE_PATH, - O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0666); + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, 0660); if (IS_ERR(cancel_filp)) { pr_err("%s: Can't open cancelation file\n", __func__); set_fs(old_fs); diff --git a/drivers/sensorhub/stm/max86902.c b/drivers/sensorhub/stm/max86902.c index e08b9abdca32..013494a9585a 100644 --- a/drivers/sensorhub/stm/max86902.c +++ b/drivers/sensorhub/stm/max86902.c @@ -39,10 +39,12 @@ #define MAX86902_PART_ID2 0x15 #define MAX86902_REV_ID1 0xFE #define MAX86902_REV_ID2 0x03 +#define MAX86906_OTP_ID 0x15 #define MAX86900_DEFAULT_CURRENT 0x55 #define MAX86900A_DEFAULT_CURRENT 0xFF #define MAX86900C_DEFAULT_CURRENT 0x0F +#define MAX86906_DEFAULT_CURRENT 0x0F #define MAX86902_DEFAULT_CURRENT1 0x00 //RED #define MAX86902_DEFAULT_CURRENT2 0x60 //IR @@ -334,6 +336,31 @@ static int max86902_init_device(struct max86900_device_data *data) return 0; } +void max86900_pin_control(struct max86900_device_data *data, bool pin_set) +{ + int status = 0; + data->p->state = NULL; + if (pin_set) { + if (!IS_ERR(data->pins_idle)) { + status = pinctrl_select_state(data->p, + data->pins_idle); + if (status) + pr_err("%s: can't set pin default state\n", + __func__); + pr_debug("%s idle\n", __func__); + } + } else { + if (!IS_ERR(data->pins_sleep)) { + status = pinctrl_select_state(data->p, + data->pins_sleep); + if (status) + pr_err("%s: can't set pin sleep state\n", + __func__); + pr_debug("%s sleep\n", __func__); + } + } +} + static void irq_set_state(struct max86900_device_data *data, int irq_enable) { pr_info("%s - irq_enable : %d, irq_state : %d\n", @@ -1417,25 +1444,29 @@ static int max86900_eol_test_control(struct max86900_device_data *data) if (data->sample_cnt < data->hr_range2) { data->hr_range = 1; } else if (data->sample_cnt < (data->hr_range2 + 297)) { - /* Fake pulse */ - if (data->sample_cnt % 8 < 4) { - data->test_current_ir++; - data->test_current_red++; - } else { - data->test_current_ir--; - data->test_current_red--; - } + if ( data->eol_test_is_enable == 1 ) { + /* Fake pulse */ + if (data->sample_cnt % 8 < 4) { + data->test_current_ir++; + data->test_current_red++; + } else { + data->test_current_ir--; + data->test_current_red--; + } - led_current = (data->test_current_red << 4) - | data->test_current_ir; - err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, - led_current); - if (err != 0) { - pr_err("%s - error initializing MAX86900_LED_CONFIGURATION!\n", - __func__); - return -EIO; + led_current = (data->test_current_red << 4) + | data->test_current_ir; + err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, + led_current); + if (err != 0) { + pr_err("%s - error initializing MAX86900_LED_CONFIGURATION!\n", + __func__); + return -EIO; + } + data->hr_range = 2; + } else if (data->eol_test_is_enable == 2 ) { + data->sample_cnt = data->hr_range2 + 297 - 1; } - data->hr_range = 2; } else if (data->sample_cnt == (data->hr_range2 + 297)) { /* Measure */ err = max86900_write_reg(data, MAX86900_LED_CONFIGURATION, @@ -2899,7 +2930,7 @@ static void max86900_eol_test_onoff(struct max86900_device_data *data, int onoff if (onoff) { err = max86900_hrm_eol_test_enable(data); - data->eol_test_is_enable = 1; + data->eol_test_is_enable = onoff; if (err != 0) pr_err("max86900_hrm_eol_test_enable err : %d\n", err); } else { @@ -3227,6 +3258,42 @@ static int max86902_get_device_id(struct max86900_device_data *data, unsigned lo return 0; } +static int max86900_otp_id(struct max86900_device_data *data) +{ + u8 recvData; + int err; + + err = max86900_write_reg(data, 0xFF, 0x54); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST0!\n", + __func__); + return -EIO; + } + + err = max86900_write_reg(data, 0xFF, 0x4d); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST1!\n", + __func__); + return -EIO; + } + + recvData = 0x8B; + if ((err = max86900_read_reg(data, &recvData, 1)) != 0) { + pr_err("%s - max86900_read_reg err:%d, address:0x%02x\n", + __func__, err, recvData); + return -EIO; + } + + err = max86900_write_reg(data, 0xFF, 0x00); + if (err != 0) { + pr_err("%s - error initializing MAX86900_MODE_TEST0!\n", + __func__); + return -EIO; + } + + return recvData; + +} static ssize_t max86900_hrm_name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3515,6 +3582,8 @@ static ssize_t eol_test_store(struct device *dev, if (sysfs_streq(buf, "1")) /* eol_test start */ test_onoff = 1; + else if (sysfs_streq(buf, "2")) /* eol_test for grip sensor */ + test_onoff = 2; else if (sysfs_streq(buf, "0")) /* eol_test stop */ test_onoff = 0; else { @@ -4606,6 +4675,28 @@ static int max86900_parse_dt(struct max86900_device_data *data, if (of_property_read_u32(dNode, "max86900,dual-hrm", &data->dual_hrm)) data->dual_hrm = 0; + data->p = pinctrl_get_select_default(dev); + if (IS_ERR(data->p)) { + pr_err("%s: failed pinctrl_get\n", __func__); + return -EINVAL; + } + + data->pins_sleep = pinctrl_lookup_state(data->p, PINCTRL_STATE_SLEEP); + if(IS_ERR(data->pins_sleep)) { + pr_err("%s : could not get pins sleep_state (%li)\n", + __func__, PTR_ERR(data->pins_sleep)); + pinctrl_put(data->p); + return -EINVAL; + } + + data->pins_idle = pinctrl_lookup_state(data->p, PINCTRL_STATE_IDLE); + if(IS_ERR(data->pins_idle)) { + pr_err("%s : could not get pins idle_state (%li)\n", + __func__, PTR_ERR(data->pins_idle)); + pinctrl_put(data->p); + return -EINVAL; + } + return 0; } @@ -4649,6 +4740,7 @@ static int max86900_setup_irq(struct max86900_device_data *data) } disable_irq(data->irq); + return errorno; } @@ -4749,8 +4841,13 @@ int max86900_probe(struct i2c_client *client, const struct i2c_device_id *id) data->default_current = MAX86900A_DEFAULT_CURRENT; break; case MAX86900C_REV_ID: - data->part_type = PART_TYPE_MAX86900C; - data->default_current = MAX86900C_DEFAULT_CURRENT; + if ( max86900_otp_id(data) == MAX86906_OTP_ID ) { + data->part_type = PART_TYPE_MAX86906; + data->default_current = MAX86906_DEFAULT_CURRENT; + } else { + data->part_type = PART_TYPE_MAX86900C; + data->default_current = MAX86900C_DEFAULT_CURRENT; + } break; default: pr_err("%s WHOAMI read error : REV ID : 0x%02x\n", @@ -5011,6 +5108,8 @@ static void max86900_shutdown(struct i2c_client *client) static int max86900_pm_suspend(struct device *dev) { struct max86900_device_data *data = dev_get_drvdata(dev); + + max86900_pin_control(data, false); if (data->part_type < PART_TYPE_MAX86902A) { if (atomic_read(&data->hrm_is_enable)) { max86900_hrm_mode_enable(data, HRM_LDO_OFF); @@ -5035,6 +5134,8 @@ static int max86900_pm_suspend(struct device *dev) static int max86900_pm_resume(struct device *dev) { struct max86900_device_data *data = dev_get_drvdata(dev); + + max86900_pin_control(data, true); if (data->part_type < PART_TYPE_MAX86902A) { if (atomic_read(&data->is_suspend) == 1) { max86900_hrm_mode_enable(data, HRM_LDO_ON); diff --git a/drivers/sensorhub/stm/max86902.h b/drivers/sensorhub/stm/max86902.h index 33951c9014fb..289c2eca6e4f 100644 --- a/drivers/sensorhub/stm/max86902.h +++ b/drivers/sensorhub/stm/max86902.h @@ -25,6 +25,9 @@ #include #include +#include +#include "../../pinctrl/core.h" + #define MAX86902_DEBUG #define MAX86900_SLAVE_ADDR 0x51 @@ -197,7 +200,8 @@ typedef enum _PART_TYPE PART_TYPE_MAX86900A, PART_TYPE_MAX86900B, PART_TYPE_MAX86900C, - PART_TYPE_MAX86902A, + PART_TYPE_MAX86906, + PART_TYPE_MAX86902A = 10, PART_TYPE_MAX86902B, } PART_TYPE; @@ -218,6 +222,9 @@ struct max86900_device_data struct mutex activelock; struct delayed_work uv_sr_work_queue; struct delayed_work reenable_work_queue; + struct pinctrl *p; + struct pinctrl_state *pins_sleep; + struct pinctrl_state *pins_idle; const char *vdd_1p8; const char *led_3p3; int hrm_en; diff --git a/drivers/sensorhub/stm/ssp.h b/drivers/sensorhub/stm/ssp.h index e0a20f2ab278..48596f016519 100644 --- a/drivers/sensorhub/stm/ssp.h +++ b/drivers/sensorhub/stm/ssp.h @@ -446,6 +446,8 @@ struct ssp_data { #ifdef CONFIG_SENSORS_SSP_IRDATA_FOR_CAMERA int light_ir_log_cnt; #endif + int acc_type; + int pressure_type; }; struct ssp_big { diff --git a/drivers/sensorhub/stm/ssp_data.c b/drivers/sensorhub/stm/ssp_data.c index cf9c1bb49edc..5033f6ddcd5c 100644 --- a/drivers/sensorhub/stm/ssp_data.c +++ b/drivers/sensorhub/stm/ssp_data.c @@ -49,7 +49,7 @@ static void get_timestamp(struct ssp_data *data, char *dataframe, sensorsdata->timestamp = data->timestamp; } } else { - if (((sensortime->irq_diff * 10) > (data->adDelayBuf[sensor] * 18)) + if (((sensortime->irq_diff * 10) > (data->adDelayBuf[sensor] * 15)) && ((sensortime->irq_diff * 10) < (data->adDelayBuf[sensor] * 100))) { generate_data(data, sensorsdata, sensor, data->timestamp); } @@ -165,7 +165,7 @@ int parse_dataframe(struct ssp_data *data, char *dataframe, int frame_len) data->lastTimestamp[sensor] = data->timestamp - (data->adDelayBuf[sensor] * length); sensortime.time_diff = data->adDelayBuf[sensor]; } else { - time = data->adDelayBuf[sensor] * 18; + time = data->adDelayBuf[sensor] * 11; if ((sensortime.time_diff * 10) > time) sensortime.time_diff = data->adDelayBuf[sensor]; } diff --git a/drivers/sensorhub/stm/ssp_dev.c b/drivers/sensorhub/stm/ssp_dev.c index 47a381f2297c..5b062d13eaee 100644 --- a/drivers/sensorhub/stm/ssp_dev.c +++ b/drivers/sensorhub/stm/ssp_dev.c @@ -243,6 +243,18 @@ static int ssp_parse_dt(struct device *dev, data->glass_type = 0; #endif + /* acc type */ + if (of_property_read_u32(np, "ssp-acc-type", &data->acc_type)) + data->acc_type = 0; + + ssp_info("acc-type = %d", data->acc_type); + + /* pressure type */ + if (of_property_read_u32(np, "ssp-pressure-type", &data->pressure_type)) + data->pressure_type = 0; + + ssp_info("pressure-type = %d", data->pressure_type); + /* mag matrix */ if (of_property_read_u8_array(np, "ssp,mag-array", data->pdc_matrix, sizeof(data->pdc_matrix))) { @@ -298,7 +310,7 @@ static int ssp_suspend(struct device *dev) ssp_errf("MSG2SSP_AP_STATUS_SUSPEND failed"); data->bTimeSyncing = false; - disable_irq(data->iIrq); + disable_irq_nosync(data->iIrq); return 0; } diff --git a/drivers/sensorhub/stm/ssp_firmware.c b/drivers/sensorhub/stm/ssp_firmware.c index d8b4e9ec2f67..d3bf0dd0e964 100644 --- a/drivers/sensorhub/stm/ssp_firmware.c +++ b/drivers/sensorhub/stm/ssp_firmware.c @@ -167,7 +167,7 @@ static int stm32fwu_spi_write(struct spi_device *spi, struct spi_transfer t = { .tx_buf = buffer, .rx_buf = rx_buf, - .len = len, + .len = (unsigned int)len, .bits_per_word = 8, }; #endif @@ -323,28 +323,28 @@ static int load_ums_fw_bootmode(struct spi_device *spi, const char *pFn) uFSize = (unsigned int)fp->f_path.dentry->d_inode->i_size; ssp_info("ssp_load_ums firmware size: %u", uFSize); - buff = kzalloc((size_t)uFSize, GFP_KERNEL); + buff = kzalloc((size_t)STM_MAX_XFER_SIZE, GFP_KERNEL); if (!buff) { iRet = ERROR; ssp_err("fail to alloc buffer for fw"); goto err_alloc; } - uNRead = (unsigned int)vfs_read(fp, (char __user *)buff, - (unsigned int)uFSize, &fp->f_pos); - if (uNRead != uFSize) { - iRet = ERROR; - ssp_err("fail to read file %s (nread = %u)", fw_path, uNRead); - goto err_fw_size; - } remaining = uFSize; while (remaining > 0) { if (block > remaining) block = remaining; + uNRead = (unsigned int)vfs_read(fp, (char __user *)buff, + (unsigned int)block, &fp->f_pos); + if (uNRead != block) { + iRet = ERROR; + ssp_err("fail to read file %s (nread = %u)", fw_path, uNRead); + goto err_fw_size; + } while (retry_count < 3) { - iRet = fw_write_stm(spi, fw_addr, block, buff + uPos); + iRet = fw_write_stm(spi, fw_addr, block, buff); if (iRet < block) { ssp_err("Err writing to addr 0x%08X", fw_addr); if (iRet < 0) { @@ -495,10 +495,12 @@ static int change_to_bootmode(struct ssp_data *data) int iCnt; int ret; char syncb = BL_SPI_SOF; + int ncount = 5; struct stm32fwu_spi_cmd dummy_cmd; ssp_dbgf(); - dummy_cmd.timeout = DEF_ACKCMD_NUMBER; + /* dummy_cmd.timeout = DEF_ACKCMD_NUMBER; */ + dummy_cmd.timeout = ncount; gpio_set_value_cansleep(data->rst, 0); usleep_range(4000, 4400); @@ -517,15 +519,20 @@ static int change_to_bootmode(struct ssp_data *data) ssp_err("failed to setup spi mode for boot"); usleep_range(1000, 1100); - ret = stm32fwu_spi_write(data->spi, &syncb, 1); + msleep(30); + + while (ncount-- >= 0) { + ret = stm32fwu_spi_write(data->spi, &syncb, 1); #if SSP_STM_DEBUG - ssp_info("stm32fwu_spi_write(sync byte) returned %d", ret); + ssp_info("stm32fwu_spi_write(sync byte) returned %d", ret); #endif - - ret = stm32fwu_spi_wait_for_ack(data->spi, &dummy_cmd, BL_DUMMY); + ret = stm32fwu_spi_wait_for_ack(data->spi, &dummy_cmd, BL_DUMMY); #if SSP_STM_DEBUG - ssp_info("stm32fwu_spi_wait_for_ack returned %d (0x%x)", ret, ret); + ssp_info("stm32fwu_spi_wait_for_ack returned %d (0x%x)", ret, ret); #endif + if (ret == BL_ACK) + break; + } return ret; } diff --git a/drivers/sensorhub/stm/ssp_firmware.h b/drivers/sensorhub/stm/ssp_firmware.h index 97f45bcbe7d3..234008b008a2 100644 --- a/drivers/sensorhub/stm/ssp_firmware.h +++ b/drivers/sensorhub/stm/ssp_firmware.h @@ -18,8 +18,14 @@ #include "ssp.h" - -#define SSP_FIRMWARE_REVISION_STM 15042900 +#if defined (CONFIG_SENSORS_SSP_NOBLELTE) \ + || defined (CONFIG_SENSORS_SSP_ZENLTE) /* Noble or Zen */ +#define SSP_FIRMWARE_REVISION_STM 15051500 +#elif defined (CONFIG_SENSORS_SSP_VLTE) /* V */ +#define SSP_FIRMWARE_REVISION_STM 15051900 +#else /* Zero */ +#define SSP_FIRMWARE_REVISION_STM 15050700 +#endif #define SSP_INVALID_REVISION 99999 #define SSP_INVALID_REVISION2 0xFFFFFF @@ -28,7 +34,15 @@ #define NORM_SPI_HZ 4800000 /* Bootload mode cmd */ +#if defined (CONFIG_SENSORS_SSP_NOBLELTE) \ + || defined (CONFIG_SENSORS_SSP_ZENLTE) /* Noble or Zen */ +#define BL_FW_NAME "ssp_stm_noble.fw" +#elif defined (CONFIG_SENSORS_SSP_VLTE) /* V */ +#define BL_FW_NAME "ssp_stm_v.fw" +#else /* Zero */ #define BL_FW_NAME "ssp_stm.fw" +#endif + #define BL_UMS_FW_NAME "ssp_stm.bin" #define BL_CRASHED_FW_NAME "ssp_crashed.fw" diff --git a/drivers/sensorhub/stm/ssp_sensorlist.h b/drivers/sensorhub/stm/ssp_sensorlist.h index 4dfb2c85e722..c12e1a9339a0 100644 --- a/drivers/sensorhub/stm/ssp_sensorlist.h +++ b/drivers/sensorhub/stm/ssp_sensorlist.h @@ -76,6 +76,19 @@ 1, /* interrupt gyro */ \ 1, /* meta sensor */ } +#if defined(CONFIG_SENSORS_SSP_TMG399X) +/* byte unit - not including timestamp */ +#define SENSOR_DATA_LEN { \ + 6, 6, 12, 6, 7, 6, 20, 2, 5, 10, \ + 1, 0, 1, 1, 12, 17, 17, 4, 0, 0, \ + 0, 0, 1, 0, 12, 6, 8, } + +/* byte unit - not including timestamp */ +#define SENSOR_REPORT_LEN { \ + 6, 10, 12, 6, 7, 14, 20, 2, 5, 10, \ + 0, 0, 1, 1, 12, 17, 17, 12, 0, 0, \ + 0, 0, 1, 0, 12, 10, 8, } +#else /* byte unit - not including timestamp */ #define SENSOR_DATA_LEN { \ 6, 6, 12, 6, 7, 6, 20, 3, 5, 10, \ @@ -87,5 +100,6 @@ 6, 10, 12, 6, 7, 14, 20, 3, 5, 10, \ 0, 0, 1, 1, 12, 17, 17, 12, 0, 0, \ 0, 0, 1, 0, 12, 10, 8, } +#endif #endif diff --git a/drivers/sensorhub/stm/ssp_spi.c b/drivers/sensorhub/stm/ssp_spi.c index 0ce1a25cdead..cc138a955079 100644 --- a/drivers/sensorhub/stm/ssp_spi.c +++ b/drivers/sensorhub/stm/ssp_spi.c @@ -566,17 +566,26 @@ void set_proximity_threshold(struct ssp_data *data, return; } msg->cmd = MSG2SSP_AP_SENSOR_PROXTHRESHOLD; +#if defined(CONFIG_SENSORS_SSP_TMG399X) + msg->length = 2; +#else msg->length = 4; +#endif msg->options = AP2HUB_WRITE; msg->buffer = kzalloc(4, GFP_KERNEL); msg->free_buffer = 1; ssp_errf("SENSOR_PROXTHRESHOL"); +#if defined(CONFIG_SENSORS_SSP_TMG399X) + msg->buffer[0] = (char)uData1; + msg->buffer[1] = (char)uData2; +#else msg->buffer[0] = ((char) (uData1 >> 8) & 0xff); msg->buffer[1] = (char) uData1; msg->buffer[2] = ((char) (uData2 >> 8) & 0xff); msg->buffer[3] = (char) uData2; +#endif iRet = ssp_spi_async(data, msg); diff --git a/drivers/sensorhub/stm/sx9310.c b/drivers/sensorhub/stm/sx9310.c new file mode 100644 index 000000000000..4c13eb14ae64 --- /dev/null +++ b/drivers/sensorhub/stm/sx9310.c @@ -0,0 +1,1608 @@ +/* + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sx9310_reg.h" + +#define VENDOR_NAME "SEMTECH" +#define MODEL_NAME "SX9310" +#define MODULE_NAME "grip_sensor" +#define CALIBRATION_FILE_PATH "/efs/FactoryApp/grip_cal_data" + +#define I2C_M_WR 0 /* for i2c Write */ +#define I2c_M_RD 1 /* for i2c Read */ + +#define IDLE 0 +#define ACTIVE 1 + +#define CAL_RET_ERROR -1 +#define CAL_RET_NONE 0 +#define CAL_RET_EXIST 1 +#define CAL_RET_SUCCESS 2 + +#define INIT_TOUCH_MODE 0 +#define NORMAL_TOUCH_MODE 1 + +#define SX9310_MODE_SLEEP 0 +#define SX9310_MODE_NORMAL 1 +#define SX9310_IRQ_ENABLE 1 +#define SX9310_IRQ_DISABLE 0 + +#define MAIN_SENSOR 1 +#define REF_SENSOR 2 + +#define CSX_STATUS_REG SX9310_TCHCMPSTAT_TCHSTAT1_FLAG + +#define DEFAULT_THRESHOLD 0x8E + +#define LIMIT_PROXOFFSET 13500 /* 99.9pF */// 2550 /* 30pF */ +#define LIMIT_PROXUSEFUL_MIN -10000 +#define LIMIT_PROXUSEFUL_MAX 10000 +#define PROXUSEFUL_DELTA_SPEC 2000 +#define STANDARD_CAP_MAIN 1000000 + +#define TOUCH_CHECK_REF_AMB 0 // 44523 +#define TOUCH_CHECK_SLOPE 0 // 50 +#define TOUCH_CHECK_MAIN_AMB 0 // 151282 + +#define DEFENCE_CODE_FOR_DEVICE_DAMAGE +/* CS0, CS1, CS2, CS3 */ +#define ENABLE_CSX (1 << MAIN_SENSOR)/* | (1 << REF_SENSOR)) */ + +#define IRQ_PROCESS_CONDITION (SX9310_IRQSTAT_TOUCH_FLAG \ + | SX9310_IRQSTAT_RELEASE_FLAG \ + | SX9310_IRQSTAT_COMPDONE_FLAG) + +struct sx9310_p { + struct i2c_client *client; + struct input_dev *input; + struct device *factory_device; +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + struct delayed_work reinit_irq_work; +#else + struct delayed_work init_work; +#endif + struct delayed_work irq_work; + struct wake_lock grip_wake_lock; + struct mutex mode_mutex; + struct mutex read_mutex; + + bool cal_successed; + bool flag_dataskip; + u8 normal_th; + u8 normal_th_buf; + int init_th; + int cal_data[3]; + int touch_mode; + s32 capmain; + s16 useful; + s16 avg; + u16 offset; + u16 freq; + + int irq; + int irq_ldo; + int gpio_nirq; + int gpio_ldoen; + int state; + int irq_state; + + u8 sreg; + u8 rwreg_val; + u8 retry_cnt; + + atomic_t enable; +}; + +static int sx9310_get_nirq_state(struct sx9310_p *data) +{ + return gpio_get_value_cansleep(data->gpio_nirq); +} + +static int sx9310_get_nirqldo_state(struct sx9310_p *data) +{ + return gpio_get_value_cansleep(data->gpio_ldoen); +} + +static int sx9310_i2c_write(struct sx9310_p *data, u8 reg_addr, u8 buf) +{ + int ret; + struct i2c_msg msg; + unsigned char w_buf[2]; + + w_buf[0] = reg_addr; + w_buf[1] = buf; + + msg.addr = data->client->addr; + msg.flags = I2C_M_WR; + msg.len = 2; + msg.buf = (char *)w_buf; + + ret = i2c_transfer(data->client->adapter, &msg, 1); + if (ret < 0) + pr_err("[SX9310]: %s - i2c write error %d\n", __func__, ret); + + return 0; +} + +static int sx9310_i2c_read(struct sx9310_p *data, u8 reg_addr, u8 *buf) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = data->client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®_addr; + + msg[1].addr = data->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = buf; + + ret = i2c_transfer(data->client->adapter, msg, 2); + if (ret < 0) + pr_err("[SX9310]: %s - i2c read error %d\n", __func__, ret); + + return ret; +} + +static int sx9310_i2c_read_block(struct sx9310_p *data, u8 reg_addr, + u8 *buf, u8 buf_size) +{ + int ret; + struct i2c_msg msg[2]; + + msg[0].addr = data->client->addr; + msg[0].flags = I2C_M_WR; + msg[0].len = 1; + msg[0].buf = ®_addr; + + msg[1].addr = data->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = buf_size; + msg[1].buf = buf; + + ret = i2c_transfer(data->client->adapter, msg, 2); + if (ret < 0) + pr_err("[SX9310]: %s - i2c read error %d\n", __func__, ret); + + return ret; +} + +static u8 sx9310_read_irqstate(struct sx9310_p *data) +{ + u8 val = 0; + + if (sx9310_i2c_read(data, SX9310_IRQSTAT_REG, &val) >= 0) + return (val & 0x00FF); + + return 0; +} + +static void sx9310_initialize_register(struct sx9310_p *data) +{ + u8 val = 0; + int idx; + + for (idx = 0; idx < (sizeof(setup_reg) >> 1); idx++) { + sx9310_i2c_write(data, setup_reg[idx].reg, setup_reg[idx].val); + pr_info("[SX9310]: %s - Write Reg: 0x%x Value: 0x%x\n", + __func__, setup_reg[idx].reg, setup_reg[idx].val); + + sx9310_i2c_read(data, setup_reg[idx].reg, &val); + pr_info("[SX9310]: %s - Read Reg: 0x%x Value: 0x%x\n\n", + __func__, setup_reg[idx].reg, val); + } +} + +static void sx9310_initialize_chip(struct sx9310_p *data) +{ + int cnt = 0; + + while ((sx9310_get_nirq_state(data) == 0) && (cnt++ < 10)) { + sx9310_read_irqstate(data); + msleep(20); + } + + if (cnt >= 10) + pr_err("[SX9310]: %s - s/w reset fail(%d)\n", + __func__, cnt); + + sx9310_initialize_register(data); +} + +static int sx9310_set_offset_calibration(struct sx9310_p *data) +{ + int ret = 0; + + ret = sx9310_i2c_write(data, SX9310_IRQSTAT_REG, 0xFF); + + return ret; +} + +static void send_event(struct sx9310_p *data, u8 state) +{ + data->normal_th = data->normal_th_buf; +#ifdef CONFIG_SENSORS_SX9310_DEFENCE_CODE_FOR_TA_NOISE + if (check_ta_state() > 1) { + data->normal_th = SX9310_NORMAL_TOUCH_CABLE_THRESHOLD; + pr_info("[SX9310]: %s - TA cable connected\n", __func__); + } +#endif + + if (state == ACTIVE) { + data->state = ACTIVE; +#if (MAIN_SENSOR == 1) + sx9310_i2c_write(data, SX9310_CPS_CTRL9_REG, data->normal_th); +#else + sx9310_i2c_write(data, SX9310_CPS_CTRL8_REG, data->normal_th); +#endif + pr_info("[SX9310]: %s - button touched\n", __func__); + } else { + data->touch_mode = NORMAL_TOUCH_MODE; + data->state = IDLE; +#if (MAIN_SENSOR == 1) + sx9310_i2c_write(data, SX9310_CPS_CTRL9_REG, data->normal_th); +#else + sx9310_i2c_write(data, SX9310_CPS_CTRL8_REG, data->normal_th); +#endif + pr_info("[SX9310]: %s - button released\n", __func__); + } + + if (data->flag_dataskip == true) + return; + + if (state == ACTIVE) + input_report_rel(data->input, REL_MISC, 1); + else + input_report_rel(data->input, REL_MISC, 2); + + input_sync(data->input); +} + +static void sx9310_display_data_reg(struct sx9310_p *data) +{ + u8 val, reg; + + sx9310_i2c_write(data, SX9310_REGSENSORSELECT, MAIN_SENSOR); + for (reg = SX9310_REGUSEMSB; reg <= SX9310_REGOFFSETLSB; reg++) { + sx9310_i2c_read(data, reg, &val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, reg, val); + } + } + +static s32 sx9310_get_init_threshold(struct sx9310_p *data) +{ + s32 threshold; + + /* Because the STANDARD_CAP_MAIN was 300,000 in the previous patch, + * the exception code is added. It will be removed later */ + if (data->cal_data[0] == 0) + threshold = STANDARD_CAP_MAIN + data->init_th; + else + threshold = data->init_th + data->cal_data[0]; + + return threshold; +} + +#define RAW_DATA_BLOCK_SIZE (SX9310_REGOFFSETLSB - SX9310_REGUSEMSB + 1) + +static void sx9310_get_data(struct sx9310_p *data) +{ + u8 ms_byte = 0; + u8 is_byte = 0; + u8 ls_byte = 0; + + u8 buf[RAW_DATA_BLOCK_SIZE]; + mutex_lock(&data->read_mutex); + + sx9310_i2c_write(data, SX9310_REGSENSORSELECT, MAIN_SENSOR); + sx9310_i2c_read_block(data, SX9310_REGUSEMSB, + &buf[0], RAW_DATA_BLOCK_SIZE); + + data->useful = (s16)((s32)buf[0] << 8) | ((s32)buf[1]); + data->avg = (s16)((s32)buf[2] << 8) | ((s32)buf[3]); + data->offset = ((u16)buf[6] << 8) | ((u16)buf[7]); + + ms_byte = (u8)(data->offset >> 13); + is_byte = (u8)((data->offset & 0x1fc0) >> 6); + ls_byte = (u8)(data->offset & 0x3f); + + data->capmain = (((s32)ms_byte * 234000) + ((s32)is_byte * 9000) + + ((s32)ls_byte * 450)) + (((s32)data->useful * 50000) / + (8 * 65536)); + + mutex_unlock(&data->read_mutex); + + pr_info("[SX9310]: %s - CapsMain: %d, Useful: %d, Offset: %u\n", + __func__, data->capmain, data->useful, data->offset); +} + +static void sx9310_touchCheckWithRefSensor(struct sx9310_p *data) +{ + s32 threshold; + + threshold = sx9310_get_init_threshold(data); + sx9310_get_data(data); + + if (data->state == IDLE) { + if (data->capmain >= threshold) + send_event(data, ACTIVE); + else + send_event(data, IDLE); + } else { + if (data->capmain < threshold) + send_event(data, IDLE); + else + send_event(data, ACTIVE); + } +} + +static int sx9310_save_caldata(struct sx9310_p *data) +{ + struct file *cal_filp = NULL; + mm_segment_t old_fs; + int ret = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, + O_CREAT | O_TRUNC | O_WRONLY | O_SYNC, + S_IRUGO | S_IWUSR | S_IWGRP); + if (IS_ERR(cal_filp)) { + pr_err("[SX9310]: %s - Can't open calibration file\n", + __func__); + set_fs(old_fs); + ret = PTR_ERR(cal_filp); + return ret; + } + + ret = cal_filp->f_op->write(cal_filp, (char *)data->cal_data, + sizeof(int) * 3, &cal_filp->f_pos); + if (ret != (sizeof(int) * 3)) { + pr_err("[SX9310]: %s - Can't write the cal data to file\n", + __func__); + ret = -EIO; + } + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + return ret; +} + +static void sx9310_open_caldata(struct sx9310_p *data) +{ + struct file *cal_filp = NULL; + mm_segment_t old_fs; + int ret; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + cal_filp = filp_open(CALIBRATION_FILE_PATH, O_RDONLY, + S_IRUGO | S_IWUSR | S_IWGRP); + if (IS_ERR(cal_filp)) { + ret = PTR_ERR(cal_filp); + if (ret != -ENOENT) + pr_err("[SX9310]: %s - Can't open calibration file.\n", + __func__); + else { + pr_info("[SX9310]: %s - There is no calibration file\n", + __func__); + /* calibration status init */ + memset(data->cal_data, 0, sizeof(int) * 3); + } + set_fs(old_fs); + return; + } + + ret = cal_filp->f_op->read(cal_filp, (char *)data->cal_data, + sizeof(int) * 3, &cal_filp->f_pos); + if (ret != (sizeof(int) * 3)) + pr_err("[SX9310]: %s - Can't read the cal data from file\n", + __func__); + + filp_close(cal_filp, current->files); + set_fs(old_fs); + + pr_info("[SX9310]: %s - (%d, %d, %d)\n", __func__, + data->cal_data[0], data->cal_data[1], data->cal_data[2]); +} + +static void irq_set_state(struct sx9310_p *data, int irq_enable) +{ + pr_info("%s - irq_enable : %d, irq_state : %d\n", + __func__, irq_enable, data->irq_state); + + if (irq_enable) { + if(!data->irq_state) { + enable_irq(data->irq); + enable_irq_wake(data->irq); + data->irq_state++; + } + } else { + if(data->irq_state) { + disable_irq(data->irq); + disable_irq_wake(data->irq); + data->irq_state--; + } + } +} + +static int sx9310_set_mode(struct sx9310_p *data, unsigned char mode) +{ + int ret = -EINVAL; + + mutex_lock(&data->mode_mutex); + if (mode == SX9310_MODE_SLEEP) { + ret = sx9310_i2c_write(data, SX9310_CPS_CTRL0_REG, + setup_reg[2].val); + irq_set_state(data, SX9310_IRQ_DISABLE); + } else if (mode == SX9310_MODE_NORMAL) { + ret = sx9310_i2c_write(data, SX9310_CPS_CTRL0_REG, + setup_reg[2].val | ENABLE_CSX); + msleep(20); + + sx9310_set_offset_calibration(data); + msleep(400); + + sx9310_touchCheckWithRefSensor(data); + irq_set_state(data, SX9310_IRQ_ENABLE); + } + + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + + pr_info("[SX9310]: %s - change the mode : %u\n", __func__, mode); + + mutex_unlock(&data->mode_mutex); + return ret; +} + +static int sx9310_do_calibrate(struct sx9310_p *data, bool do_calib) +{ + int ret = 0, useful_min = 32768, useful_max = -32767; + s32 useful_sum = 0; + u8 ms_byte = 0; + u8 is_byte = 0; + u8 ls_byte = 0; + int i = 0; + + if (do_calib == false) { + pr_info("[SX9310]: %s - Erase!\n", __func__); + goto cal_erase; + } + + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_NORMAL); + + sx9310_get_data(data); + data->cal_data[2] = data->offset; + if ((data->cal_data[2] >= LIMIT_PROXOFFSET) + || (data->cal_data[2] == 0)) { + pr_err("[SX9310]: %s - offset fail(%d)\n", __func__, + data->cal_data[2]); + goto cal_fail; + } + + for (i = 0; i < 8; i++) { + mdelay(90); + sx9310_get_data(data); + useful_sum += data->useful; + if (data->useful > useful_max) + useful_max = data->useful; + if (data->useful < useful_min) + useful_min = data->useful; + + pr_info("[SX9310]: %s - useful(%d)-offset(%u)\n", + __func__, data->useful, data->offset); + if (data->offset != data->cal_data[2]) { + data->cal_data[1] = data->useful; + pr_err("[SX9310]: %s - offset fail(%d)-(%d)\n", + __func__, data->cal_data[2], data->offset); + goto cal_fail; + } + } + + data->cal_data[1] = useful_sum >> 3; + if ((useful_max - useful_min) > PROXUSEFUL_DELTA_SPEC) { + pr_err("[SX9310]: %s - useful delta fail(min : %d, max : %d)\n", + __func__, useful_min, useful_max); + goto cal_fail; + } + + if (data->cal_data[1] <= LIMIT_PROXUSEFUL_MIN || + data->cal_data[1] >= LIMIT_PROXUSEFUL_MAX) { + pr_err("[SX9310]: %s - useful spec fail(%d)\n", __func__, + data->cal_data[1]); + goto cal_fail; + } + + ms_byte = (u8)(data->cal_data[2] >> 13); + is_byte = (u8)((data->cal_data[2] & 0x1fc0) >> 6); + ls_byte = (u8)(data->cal_data[2] & 0x3f); + + data->cal_data[0] = (((s32)ms_byte * 234000) + ((s32)is_byte*9000) + + ((s32)ls_byte * 450)) + (((s32)data->cal_data[1] + * 50000) / (8 * 65536)); + + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + + goto exit; + +cal_fail: + if (atomic_read(&data->enable) == OFF) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + ret = -1; +cal_erase: + memset(data->cal_data, 0, sizeof(int) * 3); +exit: + pr_info("[SX9310]: %s - (%d, %d, %d)\n", __func__, + data->cal_data[0], data->cal_data[1], data->cal_data[2]); + return ret; +} + +static void sx9310_set_enable(struct sx9310_p *data, int enable) +{ + if (enable) { + data->touch_mode = INIT_TOUCH_MODE; + data->cal_successed = false; + + sx9310_open_caldata(data); + sx9310_set_mode(data, SX9310_MODE_NORMAL); + atomic_set(&data->enable, ON); + } else { + sx9310_set_mode(data, SX9310_MODE_SLEEP); + atomic_set(&data->enable, OFF); + } +} + +static ssize_t sx9310_get_offset_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + sx9310_i2c_read(data, SX9310_IRQSTAT_REG, &val); + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t sx9310_set_offset_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + if (val) + sx9310_set_offset_calibration(data); + + return count; +} + +static ssize_t sx9310_register_write_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int regist = 0, val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sscanf(buf, "%d,%d", ®ist, &val) != 2) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + + sx9310_i2c_write(data, (unsigned char)regist, (unsigned char)val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, regist, val); + + return count; +} + +static ssize_t sx9310_register_read_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int regist = 0; + unsigned char val = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sscanf(buf, "%d", ®ist) != 1) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + + sx9310_i2c_read(data, (unsigned char)regist, &val); + pr_info("[SX9310]: %s - Register(0x%2x) data(0x%2x)\n", + __func__, regist, val); + + return count; +} + +static ssize_t sx9310_read_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + sx9310_display_data_reg(data); + + return snprintf(buf, PAGE_SIZE, "%d\n", 0); +} + +static ssize_t sx9310_sw_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + + ret = sx9310_i2c_write(data, SX9310_SOFTRESET_REG, SX9310_SOFTRESET); + msleep(300); + + sx9310_initialize_chip(data); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_NORMAL); + + return snprintf(buf, PAGE_SIZE, "%d\n", ret); +} + +static ssize_t sx9310_freq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return count; + } + + data->freq = (u16)val; + val = ((val << 3) | 0x05) & 0xff; + sx9310_i2c_write(data, SX9310_CPS_CTRL4_REG, (u8)val); + + pr_info("[SX9310]: %s - Freq : 0x%x\n", __func__, data->freq); + + return count; +} + +static ssize_t sx9310_freq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + pr_info("[SX9310]: %s - Freq : 0x%x\n", __func__, data->freq); + + return snprintf(buf, PAGE_SIZE, "%u\n", data->freq); +} + +static ssize_t sx9310_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", VENDOR_NAME); +} + +static ssize_t sx9310_name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", MODEL_NAME); +} + +static ssize_t sx9310_touch_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->touch_mode); +} + +static ssize_t sx9310_raw_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 proxdiff; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == OFF) + pr_err("[SX9310]: %s - SX9310 was not enabled\n", + __func__); + + sx9310_get_data(data); + proxdiff = (data->useful - data->avg) >> 4; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%u,%d\n", + data->capmain, data->useful, data->offset, proxdiff); +} + +static ssize_t sx9310_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + sx9310_get_init_threshold(data)); +} + +static ssize_t sx9310_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + pr_info("[SX9310]: %s - init threshold %lu\n", __func__, val); + data->init_th = (u8)val; + + return count; +} + +static ssize_t sx9310_normal_threshold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + u16 thresh_temp = 0, hysteresis = 0; + u16 thresh_table[32] = {2, 4, 6, 8, 12, 16, 20, 24, 28, 32,\ + 40, 48, 56, 64, 72, 80, 88, 96, 112, 128,\ + 144, 160, 192, 224, 256, 320, 384, 512, 640, 768,\ + 1024, 1536}; + + thresh_temp = data->normal_th >> 3 & 0x1f; + thresh_temp = thresh_table[thresh_temp]; + + /* CTRL10 */ + hysteresis = setup_reg[11].val>>4 & 0x3; + + switch (hysteresis) { + case 0x01:/* 6% */ + hysteresis = thresh_temp >> 4; + break; + case 0x02:/* 12% */ + hysteresis = thresh_temp >> 3; + break; + case 0x03:/* 25% */ + hysteresis = thresh_temp >> 2; + break; + default: + /* None */ + break; + } + + return snprintf(buf, PAGE_SIZE, "%d,%d\n", thresh_temp + hysteresis, thresh_temp - hysteresis); +} + +static ssize_t sx9310_normal_threshold_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + /* It's for normal touch */ + if (kstrtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return -EINVAL; + } + + pr_info("[SX9310]: %s - normal threshold %lu\n", __func__, val); + data->normal_th_buf = data->normal_th = (u8)(val << 3); + + return count; +} + +static ssize_t sx9310_onoff_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", !data->flag_dataskip); +} + +static ssize_t sx9310_onoff_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u8 val; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &val); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + if (val == 0) + data->flag_dataskip = true; + else + data->flag_dataskip = false; + + pr_info("[SX9310]: %s -%u\n", __func__, val); + return count; +} + +static ssize_t sx9310_calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + if ((data->cal_successed == false) && (data->cal_data[0] == 0)) + ret = CAL_RET_NONE; + else if ((data->cal_successed == false) && (data->cal_data[0] != 0)) + ret = CAL_RET_EXIST; + else if ((data->cal_successed == true) && (data->cal_data[0] != 0)) + ret = CAL_RET_SUCCESS; + else + ret = CAL_RET_ERROR; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", ret, + data->cal_data[1], data->cal_data[2]); +} + +static ssize_t sx9310_calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + bool do_calib; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (sysfs_streq(buf, "1")) + do_calib = true; + else if (sysfs_streq(buf, "0")) + do_calib = false; + else { + pr_info("[SX9310]: %s - invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + ret = sx9310_do_calibrate(data, do_calib); + if (ret < 0) { + pr_err("[SX9310]: %s - sx9310_do_calibrate fail(%d)\n", + __func__, ret); + goto exit; + } + + ret = sx9310_save_caldata(data); + if (ret < 0) { + pr_err("[SX9310]: %s - sx9310_save_caldata fail(%d)\n", + __func__, ret); + memset(data->cal_data, 0, sizeof(int) * 3); + goto exit; + } + + pr_info("[SX9310]: %s - %u success!\n", __func__, do_calib); + +exit: + + if ((data->cal_data[0] != 0) && (ret >= 0)) + data->cal_successed = true; + else + data->cal_successed = false; + + return count; +} + +static ssize_t sx9310_select_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->sreg); +} + +static ssize_t sx9310_select_reg_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->sreg = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x)\n", __func__, data->sreg); + + return count; +} + + +static ssize_t sx9310_rw_reg_val_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->rwreg_val = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x)\n", __func__, data->sreg); + sx9310_i2c_read(data, data->sreg, &data->rwreg_val); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->rwreg_val); +} + +static ssize_t sx9310_rw_reg_val_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long val; + struct sx9310_p *data = dev_get_drvdata(dev); + + if (strict_strtoul(buf, 10, &val)) { + pr_err("[SX9310]: %s - The number of data are wrong\n", + __func__); + return -EINVAL; + } + data->rwreg_val = (u8)val; + pr_info("[SX9310]: %s - sreg(0x%2x), val(0x%2x)\n", + __func__, data->sreg, data->rwreg_val); + sx9310_i2c_write(data, data->sreg, data->rwreg_val); + + return count; +} +static DEVICE_ATTR(menual_calibrate, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_get_offset_calibration_show, + sx9310_set_offset_calibration_store); +static DEVICE_ATTR(register_write, S_IWUSR | S_IWGRP, + NULL, sx9310_register_write_store); +static DEVICE_ATTR(register_read, S_IWUSR | S_IWGRP, + NULL, sx9310_register_read_store); +static DEVICE_ATTR(readback, S_IRUGO, sx9310_read_data_show, NULL); +static DEVICE_ATTR(reset, S_IRUGO, sx9310_sw_reset_show, NULL); + +static DEVICE_ATTR(name, S_IRUGO, sx9310_name_show, NULL); +static DEVICE_ATTR(vendor, S_IRUGO, sx9310_vendor_show, NULL); +static DEVICE_ATTR(mode, S_IRUGO, sx9310_touch_mode_show, NULL); +static DEVICE_ATTR(raw_data, S_IRUGO, sx9310_raw_data_show, NULL); +static DEVICE_ATTR(calibration, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_calibration_show, sx9310_calibration_store); +static DEVICE_ATTR(onoff, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_onoff_show, sx9310_onoff_store); +static DEVICE_ATTR(threshold, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_threshold_show, sx9310_threshold_store); +static DEVICE_ATTR(normal_threshold, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_normal_threshold_show, sx9310_normal_threshold_store); +static DEVICE_ATTR(select_reg, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_select_reg_show, sx9310_select_reg_store); +static DEVICE_ATTR(rw_reg_val, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_rw_reg_val_show, sx9310_rw_reg_val_store); +static DEVICE_ATTR(freq, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_freq_show, sx9310_freq_store); + +static struct device_attribute *sensor_attrs[] = { + &dev_attr_menual_calibrate, + &dev_attr_register_write, + &dev_attr_register_read, + &dev_attr_readback, + &dev_attr_reset, + &dev_attr_name, + &dev_attr_vendor, + &dev_attr_mode, + &dev_attr_raw_data, + &dev_attr_threshold, + &dev_attr_normal_threshold, + &dev_attr_onoff, + &dev_attr_calibration, + &dev_attr_select_reg, + &dev_attr_rw_reg_val, + &dev_attr_freq, + NULL, +}; + +/*****************************************************************************/ +static ssize_t sx9310_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 enable; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &enable); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + pr_info("[SX9310]: %s - new_value = %u\n", __func__, enable); + if ((enable == 0) || (enable == 1)) + sx9310_set_enable(data, (int)enable); + + return size; +} + +static ssize_t sx9310_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&data->enable)); +} + +static ssize_t sx9310_flush_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + u8 enable; + int ret; + struct sx9310_p *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 2, &enable); + if (ret) { + pr_err("[SX9310]: %s - Invalid Argument\n", __func__); + return ret; + } + + if (enable == 1) { + mutex_lock(&data->mode_mutex); + input_report_rel(data->input, REL_MAX, 1); + input_sync(data->input); + mutex_unlock(&data->mode_mutex); + } + + return size; +} + +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR | S_IWGRP, + sx9310_enable_show, sx9310_enable_store); +static DEVICE_ATTR(flush, S_IWUSR | S_IWGRP, + NULL, sx9310_flush_store); + +static struct attribute *sx9310_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_flush.attr, + NULL +}; + +static struct attribute_group sx9310_attribute_group = { + .attrs = sx9310_attributes +}; + +static void sx9310_touch_process(struct sx9310_p *data, u8 flag) +{ + u8 status = 0; + s32 threshold; + int cnt; + + threshold = sx9310_get_init_threshold(data); + sx9310_get_data(data); + + pr_info("[SX9310]: %s\n", __func__); + sx9310_i2c_read(data, SX9310_STAT0_REG, &status); + + if (flag & SX9310_IRQSTAT_COMPDONE_FLAG) { + if (data->state == IDLE) { + if (status & (CSX_STATUS_REG << MAIN_SENSOR)) + send_event(data, ACTIVE); + else if (data->capmain > threshold) + send_event(data, ACTIVE); + else + pr_info("[SX9310]: %s-already released.\n", + __func__); + } else { /* User released button */ + if (status & (CSX_STATUS_REG << MAIN_SENSOR)) + pr_info("[SX9310]: %s - still touched.\n", + __func__); + else if (data->capmain <= threshold + 300) + send_event(data, IDLE); + else + pr_info("[SX9310]: %s - still touched.\n", + __func__); + } + + return; + } + if (data->state == IDLE) { + if (status & (CSX_STATUS_REG << cnt)) { +#ifdef DEFENCE_CODE_FOR_DEVICE_DAMAGE + if ((data->cal_data[0] - 5000) > data->capmain) { + sx9310_set_offset_calibration(data); + msleep(400); + sx9310_touchCheckWithRefSensor(data); + pr_err("[SX9310]: %s - Defence code for" + " device damage\n", __func__); + return; + } +#endif + send_event(data, ACTIVE); + } else{ + pr_info("[SX9310]: %s - %d already released.\n", + __func__, cnt); + } + } else { /* User released button */ + if (!(status & (CSX_STATUS_REG << cnt))) { + if ((data->touch_mode == INIT_TOUCH_MODE) + && (data->capmain >= threshold)) + pr_info("[SX9310]: %s - IDLE SKIP\n", + __func__); + else + send_event(data , IDLE); + + } else { + pr_info("[SX9310]: %s - %d still touched\n", + __func__, cnt); + } + } +} + +static void sx9310_process_interrupt(struct sx9310_p *data) +{ + u8 flag = 0; + + /* since we are not in an interrupt don't need to disable irq. */ + flag = sx9310_read_irqstate(data); + + if (flag & IRQ_PROCESS_CONDITION) + sx9310_touch_process(data, flag); +} + +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL +static void sx9310_reinit_irq_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, reinit_irq_work); + + if(atomic_read(&data->enable)) { + pr_info("[SX9310]: %s - pre enable is EN. So disable irq\n", + __func__); + irq_set_state(data, SX9310_IRQ_DISABLE); + } + + if (sx9310_get_nirqldo_state(data) == 1) { + pr_info("[SX9310]: %s - init reg\n", __func__); + sx9310_initialize_chip(data); + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + } else + pr_err("[SX9310]: %s - nirq ldo read high %d\n", + __func__, sx9310_get_nirqldo_state(data)); +} + +static irqreturn_t sx9310_reinit_int_th(int irq, void *pdata) +{ + struct sx9310_p *data = pdata; + + if (sx9310_get_nirqldo_state(data) == 1) { + pr_info("[SX9310]: %s - happen irq ldo en\n", + __func__); + wake_lock_timeout(&data->grip_wake_lock, 3 * HZ); + schedule_delayed_work(&data->reinit_irq_work, msecs_to_jiffies(10)); + } else { + pr_err("[SX9310]: %s - nirq ldo read low\n", __func__); + } + + return IRQ_HANDLED; +} +#else +static void sx9310_init_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, init_work); + + int ret = 0; + pr_err("[SX9310]: %s - ldo en read high %d\n", + __func__, gpio_get_value_cansleep(data->gpio_ldoen)); + + if (gpio_get_value_cansleep(data->gpio_ldoen)) { + ret = sx9310_i2c_write(data, + SX9310_SOFTRESET_REG, SX9310_SOFTRESET); + if (ret < 0) { + pr_err("[SX9310]: %s - chip reset failed %d\n", + __func__, ret); + return; + } + msleep(400); + sx9310_initialize_chip(data); + /* make sure no interrupts are pending since enabling irq + * will only work on next falling edge */ + sx9310_read_irqstate(data); + } else { + if (data->retry_cnt < 10) { + data->retry_cnt++; + schedule_delayed_work(&data->init_work, + msecs_to_jiffies(500)); + } else { + pr_err("[SX9310]: %s - ldo retry fail\n", __func__); + sensors_remove_symlink(data->input); + } + } +} +#endif + +static void sx9310_irq_work_func(struct work_struct *work) +{ + struct sx9310_p *data = container_of((struct delayed_work *)work, + struct sx9310_p, irq_work); + + if (sx9310_get_nirq_state(data) == 0) + sx9310_process_interrupt(data); + else + pr_err("[SX9310]: %s - nirq read high %d\n", + __func__, sx9310_get_nirq_state(data)); +} + +static irqreturn_t sx9310_interrupt_thread(int irq, void *pdata) +{ + struct sx9310_p *data = pdata; + + if (sx9310_get_nirq_state(data) == 1) { + pr_err("[SX9310]: %s - nirq read high\n", __func__); + } else { + wake_lock_timeout(&data->grip_wake_lock, 3 * HZ); + schedule_delayed_work(&data->irq_work, msecs_to_jiffies(100)); + } + + return IRQ_HANDLED; +} + +static int sx9310_input_init(struct sx9310_p *data) +{ + int ret = 0; + struct input_dev *dev = NULL; + + /* Create the input device */ + dev = input_allocate_device(); + if (!dev) + return -ENOMEM; + + dev->name = MODULE_NAME; + dev->id.bustype = BUS_I2C; + + input_set_capability(dev, EV_REL, REL_MISC); + input_set_drvdata(dev, data); + + ret = input_register_device(dev); + if (ret < 0) { + input_free_device(dev); + return ret; + } + + ret = sensors_create_symlink(dev); + if (ret < 0) { + input_unregister_device(dev); + return ret; + } + + ret = sysfs_create_group(&dev->dev.kobj, &sx9310_attribute_group); + if (ret < 0) { + sensors_remove_symlink(dev); + input_unregister_device(dev); + return ret; + } + + /* save the input pointer and finish initialization */ + data->input = dev; + + return 0; +} + +static int sx9310_setup_pin(struct sx9310_p *data) +{ + int ret; + + ret = gpio_request(data->gpio_nirq, "SX9310_nIRQ"); + if (ret < 0) { + pr_err("[SX9310]: %s - gpio %d request failed (%d)\n", + __func__, data->gpio_nirq, ret); + return ret; + } + + ret = gpio_direction_input(data->gpio_nirq); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->gpio_nirq, ret); + gpio_free(data->gpio_nirq); + return ret; + } + + data->irq = gpio_to_irq(data->gpio_nirq); + + /* initailize interrupt reporting */ + ret = request_threaded_irq(data->irq, NULL, sx9310_interrupt_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT + , "sx9310_irq", data); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set request_threaded_irq %d" + " as returning (%d)\n", __func__, data->irq, ret); + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); + return ret; + } + + disable_irq(data->irq); + + ret = gpio_request(data->gpio_ldoen, "SX9310_nIRQ_ldo"); + if (ret < 0) { + pr_err("[SX9310]: %s - gpio %d request failed (%d)\n", + __func__, data->gpio_nirq, ret); + return ret; + } + + ret = gpio_direction_input(data->gpio_ldoen); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set gpio %d as input (%d)\n", + __func__, data->gpio_ldoen, ret); + gpio_free(data->gpio_ldoen); + return ret; + } + + data->irq_ldo = gpio_to_irq(data->gpio_ldoen); + + /* initailize interrupt reporting */ + ret = request_threaded_irq(data->irq_ldo, NULL, sx9310_reinit_int_th, + IRQF_TRIGGER_RISING | IRQF_ONESHOT + , "sx9310_irq_ldo", data); + if (ret < 0) { + pr_err("[SX9310]: %s - failed to set sx9310_reinit_int_th %d" + " as returning (%d)\n", __func__, data->irq_ldo, ret); + free_irq(data->irq_ldo, data); + gpio_free(data->gpio_ldoen); + return ret; + } + + return 0; +} +static void sx9310_initialize_variable(struct sx9310_p *data) +{ + data->state= IDLE; + data->touch_mode = INIT_TOUCH_MODE; + data->flag_dataskip = false; + data->cal_successed = false; + data->freq = setup_reg[6].val >> 3; + memset(data->cal_data, 0, sizeof(int) * 3); + atomic_set(&data->enable, OFF); + data->init_th = (int)CONFIG_SENSORS_SX9310_INIT_TOUCH_THRESHOLD; + pr_info("[SX9310]: %s - Init Touch Threshold : %d\n", + __func__, data->init_th); + data->normal_th = (u8)CONFIG_SENSORS_SX9310_NORMAL_TOUCH_THRESHOLD; + data->normal_th_buf = data->normal_th; + pr_info("[SX9310]: %s - Normal Touch Threshold : %u\n", + __func__, data->normal_th); +} + +static int sx9310_parse_dt(struct sx9310_p *data, struct device *dev) +{ + struct device_node *dNode = dev->of_node; + enum of_gpio_flags flags; + + if (dNode == NULL) + return -ENODEV; + + data->gpio_nirq = of_get_named_gpio_flags(dNode, + "sx9310-i2c,nirq-gpio", 0, &flags); + if (data->gpio_nirq < 0) { + pr_err("[SX9310]: %s - get gpio_nirq error\n", __func__); + return -ENODEV; + } + + data->gpio_ldoen = of_get_named_gpio_flags(dNode, + "sx9310-i2c,ldo-en", 0, &flags); + if (data->gpio_ldoen < 0) { + pr_err("[SX9310]: %s - get gpio_ldoen error\n", __func__); + } + + return 0; +} + +static int sx9310_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = -ENODEV; + struct sx9310_p *data = NULL; + + pr_info("[SX9310]: %s - Probe Start!\n", __func__); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("[SX9310]: %s - i2c_check_functionality error\n", + __func__); + goto exit; + } + + /* create memory for main struct */ + data = kzalloc(sizeof(struct sx9310_p), GFP_KERNEL); + if (data == NULL) { + pr_err("[SX9310]: %s - kzalloc error\n", __func__); + ret = -ENOMEM; + goto exit_kzalloc; + } + + ret = sx9310_parse_dt(data, &client->dev); + if (ret < 0) { + pr_err("[SX9310]: %s - of_node error\n", __func__); + ret = -ENODEV; + goto exit_of_node; + } + + ret = sx9310_setup_pin(data); + if (ret) { + pr_err("[SX9310]: %s - could not setup pin\n", __func__); + goto exit_setup_pin; + } + + i2c_set_clientdata(client, data); + data->client = client; + data->factory_device = &client->dev; + data->retry_cnt = 0; + data->irq_state = 0; + + ret = sx9310_input_init(data); + if (ret < 0) + goto exit_input_init; + + wake_lock_init(&data->grip_wake_lock, + WAKE_LOCK_SUSPEND, "grip_wake_lock"); + + ret = sensors_register(data->factory_device, + data, sensor_attrs, MODULE_NAME); + + if (ret) { + pr_err("[SENSOR] %s - cound not register grip_sensor(%d).\n", + __func__, ret); + goto grip_sensor_register_failed; + } + + sx9310_initialize_variable(data); +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + INIT_DELAYED_WORK(&data->reinit_irq_work, sx9310_reinit_irq_work_func); +#else + INIT_DELAYED_WORK(&data->init_work, sx9310_init_work_func); + schedule_delayed_work(&data->init_work, msecs_to_jiffies(5000)); +#endif + INIT_DELAYED_WORK(&data->irq_work, sx9310_irq_work_func); + mutex_init(&data->mode_mutex); + mutex_init(&data->read_mutex); + + pr_info("[SX9310]: %s - Probe done!\n", __func__); + + return 0; +grip_sensor_register_failed: + input_unregister_device(data->input); +exit_input_init: + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); +exit_setup_pin: +exit_of_node: + kfree(data); +exit_kzalloc: +exit: + pr_err("[SX9310]: %s - Probe fail!\n", __func__); + return ret; +} + +static int sx9310_remove(struct i2c_client *client) +{ + struct sx9310_p *data = (struct sx9310_p *)i2c_get_clientdata(client); + + if (atomic_read(&data->enable) == ON) + sx9310_set_mode(data, SX9310_MODE_SLEEP); + +#ifdef CONFIG_SENSORS_SX9310_CP_LDO_CONTROL + cancel_delayed_work_sync(&data->reinit_irq_work); +#else + cancel_delayed_work_sync(&data->init_work); +#endif + cancel_delayed_work_sync(&data->irq_work); + free_irq(data->irq, data); + gpio_free(data->gpio_nirq); + free_irq(data->irq_ldo, data); + gpio_free(data->gpio_ldoen); + + wake_lock_destroy(&data->grip_wake_lock); + sensors_unregister(data->factory_device, sensor_attrs); + sensors_remove_symlink(data->input); + sysfs_remove_group(&data->input->dev.kobj, &sx9310_attribute_group); + input_unregister_device(data->input); + mutex_destroy(&data->mode_mutex); + mutex_destroy(&data->read_mutex); + + kfree(data); + + return 0; +} + +static int sx9310_suspend(struct device *dev) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + pr_info("[SX9310]: %s\n", __func__); + + return 0; +} + +static int sx9310_resume(struct device *dev) +{ + struct sx9310_p *data = dev_get_drvdata(dev); + + if (atomic_read(&data->enable) == ON) + pr_info("[SX9310]: %s\n", __func__); + + return 0; +} + +static struct of_device_id sx9310_match_table[] = { + { .compatible = "sx9310-i2c",}, + {}, +}; + +static const struct i2c_device_id sx9310_id[] = { + { "sx9310_match_table", 0 }, + { } +}; + +static const struct dev_pm_ops sx9310_pm_ops = { + .suspend = sx9310_suspend, + .resume = sx9310_resume, +}; + +static struct i2c_driver sx9310_driver = { + .driver = { + .name = MODEL_NAME, + .owner = THIS_MODULE, + .of_match_table = sx9310_match_table, + .pm = &sx9310_pm_ops + }, + .probe = sx9310_probe, + .remove = sx9310_remove, + .id_table = sx9310_id, +}; + +static int __init sx9310_init(void) +{ + return i2c_add_driver(&sx9310_driver); +} + +static void __exit sx9310_exit(void) +{ + i2c_del_driver(&sx9310_driver); +} + +module_init(sx9310_init); +module_exit(sx9310_exit); + +MODULE_DESCRIPTION("Semtech Corp. SX9310 Capacitive Touch Controller Driver"); +MODULE_AUTHOR("Samsung Electronics"); +MODULE_LICENSE("GPL"); diff --git a/drivers/sensorhub/stm/sx9310_reg.h b/drivers/sensorhub/stm/sx9310_reg.h new file mode 100644 index 000000000000..6a1ad4b80759 --- /dev/null +++ b/drivers/sensorhub/stm/sx9310_reg.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2013 Samsung Electronics. All rights reserved. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#ifndef _SX9310_I2C_REG_H_ +#define _SX9310_I2C_REG_H_ + +/* + * I2C Registers + */ +#define SX9310_IRQSTAT_REG 0x00 +#define SX9310_STAT0_REG 0x01 +#define SX9310_STAT1_REG 0x02 +#define SX9310_IRQ_ENABLE_REG 0x03 +#define SX9310_IRQFUNC_REG 0x04 +#define SX9310_CPS_CTRL0_REG 0x10 +#define SX9310_CPS_CTRL1_REG 0x11 +#define SX9310_CPS_CTRL2_REG 0x12 +#define SX9310_CPS_CTRL3_REG 0x13 +#define SX9310_CPS_CTRL4_REG 0x14 +#define SX9310_CPS_CTRL5_REG 0x15 +#define SX9310_CPS_CTRL6_REG 0x16 +#define SX9310_CPS_CTRL7_REG 0x17 +#define SX9310_CPS_CTRL8_REG 0x18 +#define SX9310_CPS_CTRL9_REG 0x19 +#define SX9310_CPS_CTRL10_REG 0x1A +#define SX9310_CPS_CTRL11_REG 0x1B +#define SX9310_CPS_CTRL12_REG 0x1C +#define SX9310_CPS_CTRL13_REG 0x1D +#define SX9310_CPS_CTRL14_REG 0x1E +#define SX9310_CPS_CTRL15_REG 0x1F +#define SX9310_CPS_CTRL16_REG 0x20 +#define SX9310_CPS_CTRL17_REG 0x21 +#define SX9310_CPS_CTRL18_REG 0x22 +#define SX9310_CPS_CTRL19_REG 0x23 +#define SX9310_SAR_CTRL0_REG 0x2A +#define SX9310_SAR_CTRL1_REG 0x2B +#define SX9310_SAR_CTRL2_REG 0x2C + +#define SX9310_SOFTRESET_REG 0x7F + +/* Sensor Readback */ +#define SX9310_REGSENSORSELECT 0x30 +#define SX9310_REGUSEMSB 0x31 +#define SX9310_REGUSELSB 0x32 +#define SX9310_REGAVGMSB 0x33 +#define SX9310_REGAVGLSB 0x34 +#define SX9310_REGDIFFMSB 0x35 +#define SX9310_REGDIFFLSB 0x36 +#define SX9310_REGOFFSETMSB 0x37 +#define SX9310_REGOFFSETLSB 0x38 +#define SX9310_SARMSB 0x39 +#define SX9310_SARLSB 0x3A + +/*Miscellaneous register */ +#define SX9310_I2CADDRSET_REG 0x40 + +/* IrqStat 0:Inactive 1:Active */ +#define SX9310_IRQSTAT_RESET_FLAG 0x80 +#define SX9310_IRQSTAT_TOUCH_FLAG 0x40 +#define SX9310_IRQSTAT_RELEASE_FLAG 0x20 +#define SX9310_IRQSTAT_COMPDONE_FLAG 0x10 +#define SX9310_IRQSTAT_CONV_FLAG 0x08 +#define SX9310_IRQSTAT_SMARTSAR_FLAG 0x01 + +/* CpsStat */ +#define SX9310_TCHCMPSTAT_TCHCOMB_FLAG 0x08 +#define SX9310_TCHCMPSTAT_TCHSTAT2_FLAG 0x04 +#define SX9310_TCHCMPSTAT_TCHSTAT1_FLAG 0x02 +#define SX9310_TCHCMPSTAT_TCHSTAT0_FLAG 0x01 + +/* SoftReset */ +#define SX9310_SOFTRESET 0xDE + + +// #define SX9310_CS2_GND +#define SX9310_CS0_GND + +struct smtc_reg_data { + unsigned char reg; + unsigned char val; +}; + +static const struct smtc_reg_data setup_reg[] = { + { + .reg = SX9310_IRQ_ENABLE_REG, + .val = 0x70, + }, + { + .reg = SX9310_IRQFUNC_REG, + .val = 0x00, + }, + { + .reg = SX9310_CPS_CTRL0_REG, + .val = 0x10, + }, + { + .reg = SX9310_CPS_CTRL1_REG, + .val = 0x00, + }, +#if defined(SX9310_CS2_GND) + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x06, + }, +#elif defined(SX9310_CS0_GND) + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x00, + }, +#else + { + .reg = SX9310_CPS_CTRL2_REG, + .val = 0x00, + }, +#endif + { + .reg = SX9310_CPS_CTRL3_REG, + .val = 0x0F, + }, + { + .reg = SX9310_CPS_CTRL4_REG, + .val = 0x0D, + }, + { + .reg = SX9310_CPS_CTRL5_REG, + .val = 0xC3, + }, + { + .reg = SX9310_CPS_CTRL6_REG, + .val = 0x20, + }, + { + .reg = SX9310_CPS_CTRL7_REG, + .val = 0x4B, + }, + { + .reg = SX9310_CPS_CTRL8_REG, + .val = 0x7E, + }, + { + .reg = SX9310_CPS_CTRL9_REG, + .val = 0x7D, + }, + { + .reg = SX9310_CPS_CTRL10_REG, + .val = 0x10, + }, +#if defined(SX9310_CS2_GND) + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x00, + }, +#elif defined(SX9310_CS0_GND) + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x01, + }, +#else + { + .reg = SX9310_SAR_CTRL0_REG, + .val = 0x00, + }, +#endif +}; + +enum { + OFF = 0, + ON = 1 +}; + +extern int sensors_create_symlink(struct input_dev *inputdev); +extern void sensors_remove_symlink(struct input_dev *inputdev); +extern int sensors_register(struct device *dev, void * drvdata, + struct device_attribute *attributes[], char *name); +extern void sensors_unregister(struct device *dev, + struct device_attribute *attributes[]); + +#endif /* _SX9310_I2C_REG_H_*/ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 92a9345d7a6b..fe6c659df704 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -531,6 +531,11 @@ config SPI_TLE62X0 sysfs interface, with each line presented as a kind of GPIO exposing both switch control and diagnostic feedback. +config SENSORS_FP_SPI_NUMBER + depends on SENSORS_FINGERPRINT + int "Fingerprint spi gpio number" + default 0 + # # Add new SPI protocol masters in alphabetical order above this line # diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 33f9c09561e7..bd2b98efcc1b 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -3,6 +3,7 @@ # ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG +ccflags-y += $(KBUILD_FP_SENSOR_CFLAGS) # small core, mostly translating board-specific # config declarations into driver model code diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 66cbc260b1bb..9b1d9b59232e 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -1242,6 +1242,11 @@ static int s3c64xx_spi_setup(struct spi_device *spi) return -ENODEV; } +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (sdd->port_id == CONFIG_SENSORS_FP_SPI_NUMBER) + return 0; +#endif + if (!spi_get_ctldata(spi)) { if(cs->line != 0) { err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH, @@ -1401,6 +1406,11 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) void __iomem *gpg4con, *gpg4dat; #endif +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (channel == CONFIG_SENSORS_FP_SPI_NUMBER) + return; +#endif + sdd->cur_speed = 0; writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); @@ -1804,9 +1814,16 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) goto err3; } +#ifdef ENABLE_SENSORS_FPRINT_SECURE + if (sdd->port_id != CONFIG_SENSORS_FP_SPI_NUMBER) + writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN | + S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, + sdd->regs + S3C64XX_SPI_INT_EN); +#else writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN | S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN, sdd->regs + S3C64XX_SPI_INT_EN); +#endif pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_sync(&pdev->dev); diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 2e593cc9797c..c8aa0a9d1667 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -2706,6 +2706,30 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } break; + + /* { System SW, SA_SAMP */ + // SAMP : Service Process Management + case BINDER_GET_PROC_BINDERSTATS: { + //get proc stats,(bc_transactions/br_transactions) + //used for the binded service + int transactions; + if (size != sizeof(int)) { + ret = -EINVAL; + goto err; + } + + //Only consider the called times now + transactions = proc->stats.br[_IOC_NR(BR_TRANSACTION)] /*+ proc->stats.bc[_IOC_NR(BC_TRANSACTION)] */; + + binder_debug(BINDER_DEBUG_READ_WRITE, + "-- BINDER_GET_PROC_BINDERSTATS transactions = %d\n", transactions); + if (put_user(transactions, (uint32_t __user *)ubuf)) { + ret = -EINVAL; + goto err; + } + break; + } + /* System SW, SA_SAMP } */ default: ret = -EINVAL; goto err; diff --git a/drivers/staging/android/ion/exynos/exynos_ion_v2.c b/drivers/staging/android/ion/exynos/exynos_ion_v2.c index 06fa8919c036..acfc3232d6cd 100644 --- a/drivers/staging/android/ion/exynos/exynos_ion_v2.c +++ b/drivers/staging/android/ion/exynos/exynos_ion_v2.c @@ -20,6 +20,7 @@ #include "../ion_priv.h" struct ion_device *ion_exynos; +static DEFINE_SPINLOCK(smc_lock); /* starting from index=1 regarding default index=0 for system heap */ static int nr_heaps = 1; @@ -67,6 +68,8 @@ static void __ion_secure_protect(struct exynos_ion_platform_heap *pdata) pdata->protected = true; + spin_lock(&smc_lock); + /* passing region info */ BUG_ON(exynos_smc(SMC_DRM_SECMEM_REGION_INFO, pdata->id - 1, pdata->rmem->base, pdata->rmem->size) != 0); @@ -75,6 +78,8 @@ static void __ion_secure_protect(struct exynos_ion_platform_heap *pdata) BUG_ON(exynos_smc(SMC_DRM_SECMEM_REGION_PROT, pdata->id - 1, SMC_PROTECTION_ENABLE, 0) != 0); + spin_unlock(&smc_lock); + pr_info("%s: protection enabled for heap %s\n", __func__, pdata->heap->name); } @@ -114,10 +119,13 @@ static void __ion_secure_unprotect(struct kref *kref) pr_info("%s: enter\n", __func__); + spin_lock(&smc_lock); + /* unprotection */ BUG_ON(exynos_smc(SMC_DRM_SECMEM_REGION_PROT, pdata->id - 1, SMC_PROTECTION_DISABLE, 0) != 0); + spin_unlock(&smc_lock); pdata->protected = false; pr_info("%s: protection disabled for heap %s\n", __func__, @@ -640,14 +648,56 @@ subsys_initcall(exynos_ion_init); #ifdef CONFIG_HIGHMEM #define exynos_sync_single_for_device(addr, size, dir) dmac_map_area(addr, size, dir) #define exynos_sync_single_for_cpu(addr, size, dir) dmac_unmap_area(addr, size, dir) -#define exynos_sync_sg_for_device(dev, sg, nents, dir) ion_device_sync(ion_exynos, sgl, nents, dir, dmac_map_area, false) -#define exynos_sync_sg_for_cpu(dev, sg, nents, dir) ion_device_sync(ion_exynos, sgl, nents, dir, dmac_unmap_area, false) +#define exynos_sync_sg_for_device(dev, size, sg, nents, dir) \ + ion_device_sync(ion_exynos, sgl, nents, dir, dmac_map_area, false) +#define exynos_sync_sg_for_cpu(dev, size, sg, nents, dir) \ + ion_device_sync(ion_exynos, sgl, nents, dir, dmac_unmap_area, false) #define exynos_sync_all flush_all_cpu_caches #else +static void __exynos_sync_sg_for_device(struct device *dev, size_t size, + struct scatterlist *sgl, int nelems, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sgl, sg, nelems, i) { + size_t sg_len = min(size, (size_t)sg->length); + + __dma_map_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg_len, dir); + if (size > sg->length) + size -= sg->length; + else + break; + } +} + +static void __exynos_sync_sg_for_cpu(struct device *dev, size_t size, + struct scatterlist *sgl, int nelems, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg(sgl, sg, nelems, i) { + size_t sg_len = min(size, (size_t)sg->length); + + __dma_unmap_area(phys_to_virt(dma_to_phys(dev, sg->dma_address)), + sg_len, dir); + if (size > sg->length) + size -= sg->length; + else + break; + } +} + #define exynos_sync_single_for_device(addr, size, dir) __dma_map_area(addr, size, dir) #define exynos_sync_single_for_cpu(addr, size, dir) __dma_unmap_area(addr, size, dir) -#define exynos_sync_sg_for_device(dev, sg, nents, dir) dma_sync_sg_for_device(dev, sg, nents, dir) -#define exynos_sync_sg_for_cpu(dev, sg, nents, dir) dma_sync_sg_for_cpu(dev, sg, nents, dir) +#define exynos_sync_sg_for_device(dev, size, sg, nents, dir) \ + __exynos_sync_sg_for_device(dev, size, sg, nents, dir) +#define exynos_sync_sg_for_cpu(dev, size, sg, nents, dir) \ + __exynos_sync_sg_for_cpu(dev, size, sg, nents, dir) #define exynos_sync_all flush_all_cpu_caches #endif @@ -673,13 +723,12 @@ void exynos_ion_sync_dmabuf_for_device(struct device *dev, trace_ion_sync_start(_RET_IP_, dev, dir, size, buffer->vaddr, 0, size >= ION_FLUSH_ALL_HIGHLIMIT); - if (ion_buffer_need_flush_all(buffer)) + if (size >= ION_FLUSH_ALL_HIGHLIMIT) exynos_sync_all(); else if (!IS_ERR_OR_NULL(buffer->vaddr)) - exynos_sync_single_for_device(buffer->vaddr, - buffer->size, dir); + exynos_sync_single_for_device(buffer->vaddr, size, dir); else - exynos_sync_sg_for_device(dev, buffer->sg_table->sgl, + exynos_sync_sg_for_device(dev, size, buffer->sg_table->sgl, buffer->sg_table->nents, dir); trace_ion_sync_end(_RET_IP_, dev, dir, size, @@ -724,7 +773,7 @@ void exynos_ion_sync_sg_for_device(struct device *dev, size_t size, if (size >= ION_FLUSH_ALL_HIGHLIMIT) exynos_sync_all(); else - exynos_sync_sg_for_device(dev, sgt->sgl, sgt->nents, dir); + exynos_sync_sg_for_device(dev, size, sgt->sgl, sgt->nents, dir); trace_ion_sync_end(_RET_IP_, dev, dir, size, 0, 0, size >= ION_FLUSH_ALL_HIGHLIMIT); @@ -756,12 +805,12 @@ void exynos_ion_sync_dmabuf_for_cpu(struct device *dev, trace_ion_sync_start(_RET_IP_, dev, dir, size, buffer->vaddr, 0, size >= ION_FLUSH_ALL_HIGHLIMIT); - if (ion_buffer_need_flush_all(buffer)) + if (size >= ION_FLUSH_ALL_HIGHLIMIT) exynos_sync_all(); else if (!IS_ERR_OR_NULL(buffer->vaddr)) exynos_sync_single_for_cpu(buffer->vaddr, size, dir); else - exynos_sync_sg_for_cpu(dev, buffer->sg_table->sgl, + exynos_sync_sg_for_cpu(dev, size, buffer->sg_table->sgl, buffer->sg_table->nents, dir); trace_ion_sync_end(_RET_IP_, dev, dir, size, @@ -812,7 +861,7 @@ void exynos_ion_sync_sg_for_cpu(struct device *dev, size_t size, if (size >= ION_FLUSH_ALL_HIGHLIMIT) exynos_sync_all(); else - exynos_sync_sg_for_cpu(dev, sgt->sgl, sgt->nents, dir); + exynos_sync_sg_for_cpu(dev, size, sgt->sgl, sgt->nents, dir); trace_ion_sync_end(_RET_IP_, dev, dir, size, 0, 0, size >= ION_FLUSH_ALL_HIGHLIMIT); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 25b8e4b5af9f..db1c593a8c37 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -922,6 +922,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) struct ion_client *client = s->private; struct rb_node *n; size_t sizes[ION_NUM_HEAP_IDS] = {0}; + size_t sizes_pss[ION_NUM_HEAP_IDS] = {0}; const char *names[ION_NUM_HEAP_IDS] = {NULL}; int i; @@ -940,24 +941,40 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) return -EINVAL; } + seq_printf(s, "%16.s %16.s %4.s %16.s %4.s %10.s %8.s %9.s\n", + "buffer", "task", "pid", "thread", "tid", "size", + "# procs", "flag"); + seq_printf(s, "----------------------------------------------" + "--------------------------------------------\n"); + mutex_lock(&client->lock); for (n = rb_first(&client->handles); n; n = rb_next(n)) { struct ion_handle *handle = rb_entry(n, struct ion_handle, node); - unsigned int id = handle->buffer->heap->id; + struct ion_buffer *buffer = handle->buffer; + unsigned int id = buffer->heap->id; if (!names[id]) - names[id] = handle->buffer->heap->name; - sizes[id] += handle->buffer->size; + names[id] = buffer->heap->name; + sizes[id] += buffer->size; + sizes_pss[id] += (buffer->size / buffer->handle_count); + seq_printf(s, "%16p %16.s %4u %16.s %4u %10zu %8d %9lx\n", + buffer, buffer->task_comm, buffer->pid, + buffer->thread_comm, buffer->tid, buffer->size, + buffer->handle_count, buffer->flags); } mutex_unlock(&client->lock); up_read(&g_idev->lock); - seq_printf(s, "%16.16s: %16.16s\n", "heap_name", "size_in_bytes"); + seq_printf(s, "----------------------------------------------" + "--------------------------------------------\n"); + seq_printf(s, "%16.16s: %16.16s %18.18s\n", "heap_name", + "size_in_bytes", "size_in_bytes(pss)"); for (i = 0; i < ION_NUM_HEAP_IDS; i++) { if (!names[i]) continue; - seq_printf(s, "%16.16s: %16zu\n", names[i], sizes[i]); + seq_printf(s, "%16.16s: %16zu %18zu\n", + names[i], sizes[i], sizes_pss[i]); } return 0; } @@ -1541,6 +1558,74 @@ static int ion_sync_for_device(struct ion_client *client, int fd) return 0; } +static int ion_sync_partial_for_device(struct ion_client *client, int fd, + off_t offset, size_t len) +{ + struct dma_buf *dmabuf; + struct ion_buffer *buffer; + struct scatterlist *sg, *sgl; + size_t remained = len; + int nelems; + int i; + + dmabuf = dma_buf_get(fd); + if (IS_ERR(dmabuf)) + return PTR_ERR(dmabuf); + + /* if this memory came from ion */ + if (dmabuf->ops != &dma_buf_ops) { + pr_err("%s: can not sync dmabuf from another exporter\n", + __func__); + dma_buf_put(dmabuf); + return -EINVAL; + } + buffer = dmabuf->priv; + + if (!ion_buffer_cached(buffer) || + ion_buffer_fault_user_mappings(buffer)) { + dma_buf_put(dmabuf); + return 0; + } + + trace_ion_sync_start(_RET_IP_, buffer->dev->dev.this_device, + DMA_BIDIRECTIONAL, buffer->size, + buffer->vaddr, 0, false); + + sgl = buffer->sg_table->sgl; + nelems = buffer->sg_table->nents; + + for_each_sg(sgl, sg, nelems, i) { + size_t len_to_flush; + if (offset >= sg->length) { + offset -= sg->length; + continue; + } + + len_to_flush = sg->length - offset; + if (remained < len_to_flush) { + len_to_flush = remained; + remained = 0; + } else { + remained -= len_to_flush; + } + + __dma_map_area(phys_to_virt(sg_phys(sg)) + offset, + len_to_flush, DMA_TO_DEVICE); + + if (remained == 0) + break; + offset = 0; + } + + trace_ion_sync_end(_RET_IP_, buffer->dev->dev.this_device, + DMA_BIDIRECTIONAL, buffer->size, + buffer->vaddr, 0, false); + + dma_buf_put(dmabuf); + + return 0; +} + static long ion_alloc_preload(struct ion_client *client, unsigned int heap_id_mask, unsigned int flags, @@ -1598,6 +1683,7 @@ static unsigned int ion_ioctl_dir(unsigned int cmd) { switch (cmd) { case ION_IOC_SYNC: + case ION_IOC_SYNC_PARTIAL: case ION_IOC_FREE: case ION_IOC_CUSTOM: return _IOC_WRITE; @@ -1616,6 +1702,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) union { struct ion_fd_data fd; + struct ion_fd_partial_data fd_partial; struct ion_allocation_data allocation; struct ion_handle_data handle; struct ion_custom_data custom; @@ -1689,6 +1776,12 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = ion_sync_for_device(client, data.fd.fd); break; } + case ION_IOC_SYNC_PARTIAL: + { + ret = ion_sync_partial_for_device(client, data.fd_partial.fd, + data.fd_partial.offset, data.fd_partial.len); + break; + } case ION_IOC_CUSTOM: { if (!dev->custom_ioctl) @@ -2489,8 +2582,12 @@ static struct ion_iovm_map *ion_buffer_iova_create(struct ion_buffer *buffer, iovm_map->region_id = id; iovm_map->dev = dev; + iovm_map->domain = get_domain_from_dev(dev); iovm_map->map_cnt = 1; + pr_debug("%s: new map added for dev %s, iova %pa, id %d\n", __func__, + dev_name(dev), &iovm_map->iova, id); + return iovm_map; } @@ -2501,13 +2598,24 @@ dma_addr_t ion_iovmm_map(struct dma_buf_attachment *attachment, struct dma_buf *dmabuf = attachment->dmabuf; struct ion_buffer *buffer = dmabuf->priv; struct ion_iovm_map *iovm_map; + struct iommu_domain *domain; BUG_ON(dmabuf->ops != &dma_buf_ops); + domain = get_domain_from_dev(attachment->dev); + if (!domain) { + pr_err("%s: invalid iommu device\n", __func__); + return -EINVAL; + } + mutex_lock(&buffer->lock); list_for_each_entry(iovm_map, &buffer->iovas, list) { - if ((attachment->dev == iovm_map->dev) && + if ((domain == iovm_map->domain) && (id == iovm_map->region_id)) { + pr_debug("%s: reusable map found for dev %s, " + "domain %p, id %d\n", __func__, + dev_name(iovm_map->dev), + iovm_map->domain, id); iovm_map->map_cnt++; mutex_unlock(&buffer->lock); return iovm_map->iova; @@ -2528,25 +2636,51 @@ dma_addr_t ion_iovmm_map(struct dma_buf_attachment *attachment, void ion_iovmm_unmap(struct dma_buf_attachment *attachment, dma_addr_t iova) { + struct ion_iovm_map *this_map = NULL; struct ion_iovm_map *iovm_map; struct dma_buf * dmabuf = attachment->dmabuf; struct device *dev = attachment->dev; struct ion_buffer *buffer = attachment->dmabuf->priv; + struct iommu_domain *domain; + bool found = false; BUG_ON(dmabuf->ops != &dma_buf_ops); + domain = get_domain_from_dev(attachment->dev); + if (!domain) { + pr_err("%s: invalid iommu device\n", __func__); + return; + } + mutex_lock(&buffer->lock); list_for_each_entry(iovm_map, &buffer->iovas, list) { - if ((dev == iovm_map->dev) && (iova == iovm_map->iova)) { - if (WARN_ON(iovm_map->map_cnt-- == 0)) - iovm_map->map_cnt = 0; - mutex_unlock(&buffer->lock); - return; + if (domain == iovm_map->domain) { + if (iova == iovm_map->iova) { + if (WARN_ON(iovm_map->map_cnt-- == 0)) + iovm_map->map_cnt = 0; + this_map = iovm_map; + } else { + found = true; + pr_debug("%s: found new map %pa for dev %s " + "in region %d\n", __func__, + &iovm_map->iova, + dev_name(iovm_map->dev), + iovm_map->region_id); + } } } - pr_warn("%s: IOVA %pa is not found for %s\n", - __func__, &iova, dev_name(dev)); + if (!this_map) { + pr_warn("%s: IOVA %pa is not found for %s\n", + __func__, &iova, dev_name(dev)); + } else if (found && !this_map->map_cnt) { + pr_debug("%s: unmap previous %pa for dev %s in region %d\n", + __func__, &this_map->iova, dev_name(this_map->dev), + this_map->region_id); + iovmm_unmap(this_map->dev, this_map->iova); + list_del(&this_map->list); + kfree(this_map); + } mutex_unlock(&buffer->lock); } diff --git a/drivers/staging/android/ion/ion_carveout_heap.c b/drivers/staging/android/ion/ion_carveout_heap.c index ff96a1e9b870..6c8c8e7cb2c7 100644 --- a/drivers/staging/android/ion/ion_carveout_heap.c +++ b/drivers/staging/android/ion/ion_carveout_heap.c @@ -149,11 +149,20 @@ static void ion_carveout_heap_free(struct ion_buffer *buffer) ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); #ifdef CONFIG_ARM64 - if (ion_buffer_cached(buffer)) - __flush_dcache_area(page_address(page), buffer->size); + if (ion_buffer_cached(buffer)) { + if (ion_buffer_need_flush_all(buffer)) + flush_all_cpu_caches(); + else + __flush_dcache_area(page_address(page), buffer->size); + } #else - if (ion_buffer_cached(buffer)) - dmac_flush_range(page_address(page), buffer->size, DMA_BIDIRECTIONAL); + if (ion_buffer_cached(buffer)) { + if (ion_buffer_need_flush_all(buffer)) + flush_all_cpu_caches(); + else + dmac_flush_range(page_address(page), buffer->size, + DMA_BIDIRECTIONAL); + } #endif ion_carveout_free(heap, paddr, buffer->size); sg_free_table(table); @@ -230,9 +239,15 @@ struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data) carveout_heap->heap.debug_show = carveout_heap_debug_show; #ifdef CONFIG_ARM64 - __flush_dcache_area(page_address(page), size); + if (size >= ION_FLUSH_ALL_HIGHLIMIT) + flush_all_cpu_caches(); + else + __flush_dcache_area(page_address(page), size); #else - dmac_flush_range(page_address(page), size, DMA_BIDIRECTIONAL); + if (size >= ION_FLUSH_ALL_HIGHLIMIT) + flush_all_cpu_caches(); + else + dmac_flush_range(page_address(page), size, DMA_BIDIRECTIONAL); #endif return &carveout_heap->heap; } diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index bd4df7223599..4d14a56e9749 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -111,13 +111,21 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, buffer->priv_virt = info; #ifdef CONFIG_ARM64 - if (!ion_buffer_cached(buffer) && !(buffer->flags & ION_FLAG_PROTECTED)) - __flush_dcache_area(page_address(sg_page(info->table->sgl)), + if (!ion_buffer_cached(buffer) && !(buffer->flags & ION_FLAG_PROTECTED)) { + if (ion_buffer_need_flush_all(buffer)) + flush_all_cpu_caches(); + else + __flush_dcache_area(page_address(sg_page(info->table->sgl)), len); + } #else - if (!ion_buffer_cached(buffer) && !(buffer->flags & ION_FLAG_PROTECTED)) - dmac_flush_range(page_address(sg_page(info->table->sgl), len, - DMA_BIDIRECTIONAL); + if (!ion_buffer_cached(buffer) && !(buffer->flags & ION_FLAG_PROTECTED)) { + if (ion_buffer_need_flush_all(buffer)) + flush_all_cpu_caches(); + else + dmac_flush_range(page_address(sg_page(info->table->sgl), + len, DMA_BIDIRECTIONAL)); + } #endif if (buffer->flags & ION_FLAG_PROTECTED) ion_secure_protect(heap); diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index a6d98a717acc..11f532eb85cc 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -103,27 +103,6 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, return 0; } -#ifdef CONFIG_ARM64 -static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents, - pgprot_t pgprot) -{ - struct scatterlist *sg; - int i; - - for_each_sg(sgl, sg, nents, i) { - struct page *p = sg_page(sg); - unsigned int len = sg->length; - - do { - clear_page(page_address(p)); - if (pgprot_writecombine(pgprot) == pgprot) - __flush_dcache_area(page_address(p), PAGE_SIZE); - } while (p++, len -= PAGE_SIZE, len > 0); - } - - return 0; -} -#else static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot) { void *addr = vm_map_ram(pages, num, -1, pgprot); @@ -158,7 +137,6 @@ static int ion_heap_sglist_zero(struct scatterlist *sgl, unsigned int nents, return ret; } -#endif int ion_heap_buffer_zero(struct ion_buffer *buffer) { diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index e0bac535eeaa..b0dbff36276a 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -40,6 +40,7 @@ struct ion_iovm_map { struct list_head list; unsigned int map_cnt; struct device *dev; + struct iommu_domain *domain; dma_addr_t iova; int region_id; }; @@ -155,7 +156,7 @@ struct ion_heap_ops { }; /* [INTERNAL USE ONLY] threshold value for whole cache flush */ -#define ION_FLUSH_ALL_HIGHLIMIT SZ_2G +#define ION_FLUSH_ALL_HIGHLIMIT SZ_8M /** * heap flags - flags between the heaps and core ion code @@ -227,6 +228,17 @@ struct ion_heap { int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); }; +/** + * ion_buffer_sync_force - check if ION_FLAG_SYNC_FORCE is set + * @buffer: buffer + * + * indicates whether this ion buffer should be cache clean after allocation + */ +static inline bool ion_buffer_sync_force(struct ion_buffer *buffer) +{ + return !!(buffer->flags & ION_FLAG_SYNC_FORCE); +} + /** * ion_buffer_cached - this ion buffer is cached * @buffer: buffer diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 3a8766163d1a..b415f28d92b7 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -133,6 +133,9 @@ static struct page *alloc_largest_available(struct ion_system_heap *heap, return NULL; } +#define should_flush_cache(page, buffer) (!ion_get_page_clean(page) && \ + (!ion_buffer_cached(buffer) || ion_buffer_sync_force(buffer))) + static int ion_system_heap_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long size, unsigned long align, @@ -180,11 +183,12 @@ static int ion_system_heap_allocate(struct ion_heap *heap, unsigned int len = PAGE_SIZE << compound_order(page); sg_set_page(sg, page, len, 0); sg = sg_next(sg); - if (!ion_buffer_cached(buffer) && !ion_get_page_clean(page)) { + if (should_flush_cache(page, buffer)) { all_pages_from_pool = false; if (!IS_ENABLED(CONFIG_HIGHMEM)) { __flush_dcache_area(page_address(page), len); - ion_set_page_clean(page); + if (!ion_buffer_cached(buffer)) + ion_set_page_clean(page); } } list_del(&page->lru); diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index d069c23f4e58..ed6b7de81a58 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -81,8 +81,10 @@ static unsigned long lowmem_deathpending_timeout; pr_info(x); \ } while (0) +#if defined(CONFIG_ZSWAP) extern u64 zswap_pool_pages; extern atomic_t zswap_stored_pages; +#endif static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) { @@ -158,12 +160,14 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) continue; } tasksize = get_mm_rss(p->mm); +#if defined(CONFIG_ZSWAP) if (atomic_read(&zswap_stored_pages)) { - lowmem_print(1, "shown tasksize : %d\n", tasksize); + lowmem_print(3, "shown tasksize : %d\n", tasksize); tasksize += (int)zswap_pool_pages * get_mm_counter(p->mm, MM_SWAPENTS) / atomic_read(&zswap_stored_pages); - lowmem_print(1, "real tasksize : %d\n", tasksize); + lowmem_print(3, "real tasksize : %d\n", tasksize); } +#endif task_unlock(p); if (tasksize <= 0) diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h index 4098c502fc36..561f49670ffc 100644 --- a/drivers/staging/android/uapi/binder.h +++ b/drivers/staging/android/uapi/binder.h @@ -103,6 +103,10 @@ struct binder_version { #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) +/* { System SW, SA_SAMP */ +// SAMP : Service Process Management +#define BINDER_GET_PROC_BINDERSTATS _IOWR('b', 10, int) +/* System SW, SA_SAMP } */ /* * NOTE: Two special error codes you should check for when calling diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h index 9cc0427a6165..277721ca67e8 100644 --- a/drivers/staging/android/uapi/ion.h +++ b/drivers/staging/android/uapi/ion.h @@ -72,6 +72,7 @@ enum ion_heap_type { world. if this is set, all cpu accesses are prohibited. */ +#define ION_FLAG_SYNC_FORCE 32 /* cache sync forcely at allocation */ /** * DOC: Ion Userspace API * @@ -114,6 +115,13 @@ struct ion_fd_data { int fd; }; +struct ion_fd_partial_data { + ion_user_handle_t handle; + int fd; + off_t offset; + size_t len; +}; + /** * struct ion_handle_data - a handle passed to/from the kernel * @handle: a handle @@ -213,6 +221,7 @@ struct ion_preload_data { * this will make the buffer in memory coherent. */ #define ION_IOC_SYNC _IOWR(ION_IOC_MAGIC, 7, struct ion_fd_data) +#define ION_IOC_SYNC_PARTIAL _IOWR(ION_IOC_MAGIC, 9, struct ion_fd_partial_data) /** * DOC: ION_IOC_PRELOAD_ALLOC - prefetches pages to page pool diff --git a/drivers/staging/samsung/sec_debug.c b/drivers/staging/samsung/sec_debug.c index 6e7dc8de759c..ed17ff0a5930 100644 --- a/drivers/staging/samsung/sec_debug.c +++ b/drivers/staging/samsung/sec_debug.c @@ -134,6 +134,7 @@ enum sec_debug_upload_cause_t { UPLOAD_CAUSE_CP_ERROR_FATAL = 0x000000CC, UPLOAD_CAUSE_USER_FAULT = 0x0000002F, UPLOAD_CAUSE_HSIC_DISCONNECTED = 0x000000DD, + UPLOAD_CAUSE_POWERKEY_LONG_PRESS = 0x00000085, }; static void sec_debug_set_upload_magic(unsigned magic, char *str) @@ -548,8 +549,14 @@ void sec_debug_check_crash_key(unsigned int code, int value) if (!sec_debug_level.en.kernel_fault) return; - if (code == KEY_POWER) + if (code == KEY_POWER) { pr_info("sec_debug: POWER-KEY(%d)\n", value); + if (value) { + sec_debug_set_upload_cause(UPLOAD_CAUSE_POWERKEY_LONG_PRESS); + } else { + sec_debug_set_upload_cause(UPLOAD_CAUSE_INIT); + } + } /* Enter Forced Upload * Hold volume down key first diff --git a/drivers/staging/samsung/sec_log.c b/drivers/staging/samsung/sec_log.c index 47d7fd3c2c4e..b8e85dbe9e36 100644 --- a/drivers/staging/samsung/sec_log.c +++ b/drivers/staging/samsung/sec_log.c @@ -475,64 +475,6 @@ late_initcall(sec_last_kmsg_late_init); #ifdef CONFIG_SEC_DEBUG_TIMA_LOG #ifdef CONFIG_TIMA_RKP -#ifdef CONFIG_SOC_EXYNOS5430 -#define TIMA_DEBUG_LOG_START 0x30300000 -#define TIMA_DEBUG_LOG_SIZE 1<<20 - -#define TIMA_SEC_LOG 0x2d800000 -#define TIMA_SEC_LOG_SIZE 1<<18 - -#define TIMA_PHYS_MAP 0x2d900000 -#define TIMA_PHYS_MAP_SIZE 6<<20 - -#define TIMA_SEC_TO_PGT 0x2e000000 -#define TIMA_SEC_TO_PGT_SIZE 1<<20 - -#define TIMA_DASHBOARD_START 0x2d700000 -#define TIMA_DASHBOARD_SIZE 0x1000 -#endif - -#ifdef CONFIG_SOC_EXYNOS7420 - -#define TIMA_VMM_START 0x52C00000 -#define TIMA_VMM_SIZE 2<<20 - -#define TIMA_DEBUG_LOG_START 0x52300000 -#define TIMA_DEBUG_LOG_SIZE 1<<20 - -#define TIMA_SEC_LOG 0x4d800000 -#define TIMA_SEC_LOG_SIZE 1<<18 - -#define TIMA_PHYS_MAP 0x4da00000 -#define TIMA_PHYS_MAP_SIZE 4<<20 - - -#define TIMA_DASHBOARD_START 0x4d700000 -#define TIMA_DASHBOARD_SIZE 0x1000 - -#define TIMA_ROBUF_START 0x52400000 -#define TIMA_ROBUF_SIZE 1<<23 - - -#endif /* CONFIG_SOC_EXYNOS7420 */ - -#ifdef CONFIG_SOC_EXYNOS5422 -#define TIMA_DEBUG_LOG_START 0x50300000 -#define TIMA_DEBUG_LOG_SIZE 1<<20 - -#define TIMA_SEC_LOG 0x4d800000 -#define TIMA_SEC_LOG_SIZE 1<<18 - -#define TIMA_PHYS_MAP 0x4d900000 -#define TIMA_PHYS_MAP_SIZE 6<<20 - -#define TIMA_SEC_TO_PGT 0x4e000000 -#define TIMA_SEC_TO_PGT_SIZE 1<<20 - - -#define TIMA_DASHBOARD_START 0x4d700000 -#define TIMA_DASHBOARD_SIZE 0x1000 -#endif static int tima_setup_rkp_mem(void){ #ifdef CONFIG_NO_BOOTMEM diff --git a/drivers/switch/switch-arizona.c b/drivers/switch/switch-arizona.c index 750ef872abb5..959753b7f93d 100644 --- a/drivers/switch/switch-arizona.c +++ b/drivers/switch/switch-arizona.c @@ -69,9 +69,21 @@ #define HP_LOW_IMPEDANCE_LIMIT 13 +struct arizona_hpdet_calibration_data { + int min; + int max; + s64 C0; /* value * 1000000 */ + s64 C1; /* value * 10000 */ + s64 C2; /* not multiplied */ + s64 C3; /* value * 1000000 */ + s64 C4_x_C3; /* value * 1000000 */ + s64 C5; /* value * 1000000 */ + s64 dacval_adjust; +}; + struct arizona_hpdet_d_trims { - int off; - int grad_x2; + int off_x4; + int grad_x4; }; struct arizona_extcon_info { @@ -114,6 +126,8 @@ struct arizona_extcon_info { int hpdet_ip; const struct arizona_hpdet_d_trims *hpdet_d_trims; + const struct arizona_hpdet_calibration_data *calib_data; + int calib_data_size; struct switch_dev edev; @@ -168,12 +182,12 @@ enum headset_state { static ssize_t arizona_extcon_show(struct device *dev, struct device_attribute *attr, char *buf); -DEVICE_ATTR(hp_impedance, S_IRUGO, arizona_extcon_show, NULL); +static DEVICE_ATTR(hp_impedance, S_IRUGO, arizona_extcon_show, NULL); static ssize_t arizona_extcon_mic_show(struct device *dev, struct device_attribute *attr, char *buf); -DEVICE_ATTR(mic_impedance, S_IRUGO, arizona_extcon_mic_show, NULL); +static DEVICE_ATTR(mic_impedance, S_IRUGO, arizona_extcon_mic_show, NULL); inline void arizona_extcon_report(struct arizona_extcon_info *info, int state) { @@ -270,6 +284,8 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, switch (arizona->type) { case WM5102: case WM8997: + case WM8998: + case WM1814: mask = ARIZONA_RMV_SHRT_HP1L; if (clamp) val = ARIZONA_RMV_SHRT_HP1L; @@ -297,6 +313,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, break; case WM8285: case WM1840: + case CS47L35: edre_reg = CLEARWATER_EDRE_MANUAL; mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI; @@ -389,17 +406,33 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) { - switch (info->micd_modes[0].bias) { - case 1: - return "MICBIAS1"; - case 2: - return "MICBIAS2"; - case 3: - return "MICBIAS3"; - case 4: - return "MICBIAS4"; + struct arizona *arizona = info->arizona; + + switch (arizona->type) { + case CS47L35: + switch (info->micd_modes[0].bias) { + case 1: + return "MICBIAS1A"; + case 2: + return "MICBIAS1B"; + case 3: + return "MICBIAS2A"; + default: + return "MICVDD"; + } default: - return "MICVDD"; + switch (info->micd_modes[0].bias) { + case 1: + return "MICBIAS1"; + case 2: + return "MICBIAS2"; + case 3: + return "MICBIAS3"; + case 4: + return "MICBIAS4"; + default: + return "MICVDD"; + } } } @@ -564,56 +597,45 @@ static struct { { 1000, 10000 }, }; -static const struct { - int min; - int max; - s64 C0; /* value * 1000000 */ - s64 C1; /* value * 10000 */ - s64 C2; /* not multiplied */ - s64 C3; /* value * 1000000 */ - s64 C4_x_C3; /* value * 1000000 */ - s64 C5; /* value * 1000000 */ -} arizona_hpdet_d_ranges[] = { - { 0, 30, 1007000, -7200, 4003, 69300000, 381150, 250000}, - { 8, 100, 1007000, -7200, 7975, 69600000, 382800, 250000}, - { 100, 1000, 9696000, -79500, 7300, 62900000, 345950, 250000}, - { 1000, 10000, 100684000, -949400, 7300, 63200000, 347600, 250000}, +static const struct arizona_hpdet_calibration_data arizona_hpdet_d_ranges[] = { + { 0, 30, 1007000, -7200, 4003, 69300000, 381150, 250000, 1500000}, + { 8, 100, 1007000, -7200, 7975, 69600000, 382800, 250000, 1500000}, + { 100, 1000, 9696000, -79500, 7300, 62900000, 345950, 250000, 1500000}, + { 1000, 10000, 100684000, -949400, 7300, 63200000, 347600, 250000, 1500000}, }; -#ifdef ARIZONA_HPDET_USE_DEFAULT_TRIMS -static struct arizona_hpdet_d_trims arizona_hpdet_d_trims_default[] = { - { -1, 5}, - { 0, 5 }, - { -2, 12 }, - { -3, 12 }, +static const struct arizona_hpdet_calibration_data arizona_hpdet_clearwater_ranges[] = { + { 4, 30, 1007000, -7200, 4003, 69300000, 55, 250000, 500000}, + { 8, 100, 1007000, -7200, 7975, 69600000, 55, 250000, 500000}, + { 100, 1000, 9696000, -79500, 7300, 62900000, 55, 250000, 500000}, + { 1000, 10000, 100684000, -949400, 7300, 63200000, 55, 250000, 500000}, }; -#endif static int arizona_hpdet_d_calibrate(const struct arizona_extcon_info *info, int dacval, int range) { - int gradx2 = info->hpdet_d_trims[range].grad_x2; - int off = info->hpdet_d_trims[range].off; + int grad_x4 = info->hpdet_d_trims[range].grad_x4; + int off_x4 = info->hpdet_d_trims[range].off_x4; s64 val = dacval; s64 n; dev_warn(info->arizona->dev, "hpdet_d calib range %d dac %d\n", range, dacval); - val = (val * 1000000) + 1500000; - val = div64_s64(val, arizona_hpdet_d_ranges[range].C2); + val = (val * 1000000) + info->calib_data[range].dacval_adjust; + val = div64_s64(val, info->calib_data[range].C2); - n = div_s64(1000000000000, arizona_hpdet_d_ranges[range].C3 + - ((arizona_hpdet_d_ranges[range].C4_x_C3 * gradx2) / 2)); + n = div_s64(1000000000000LL, info->calib_data[range].C3 + + ((info->calib_data[range].C4_x_C3 * grad_x4) / 4)); n = val - n; - if (n == 0) + if (n <= 0) return ARIZONA_HPDET_MAX; - val = arizona_hpdet_d_ranges[range].C0 + - (arizona_hpdet_d_ranges[range].C1 * off); + val = info->calib_data[range].C0 + + ((info->calib_data[range].C1 * off_x4) / 4); val *= 1000000; val = div_s64(val, n); - val -= arizona_hpdet_d_ranges[range].C5; + val -= info->calib_data[range].C5; /* Round up */ val += 500000; @@ -632,6 +654,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) struct arizona *arizona = info->arizona; unsigned int val, range; int ret; + unsigned int val_down; ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); if (ret != 0) { @@ -741,6 +764,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) break; case 3: + case 4: if (!(val & ARIZONA_HP_DONE_B)) { dev_err(arizona->dev, "HPDET did not complete: %x\n", val); @@ -752,16 +776,16 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, &range); - range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) - >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; + range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) >> + ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; /* Skip up a range, or report? */ - if (range < ARRAY_SIZE(arizona_hpdet_d_ranges) - 1 && - (val >= arizona_hpdet_d_ranges[range].max)) { + if (range < info->calib_data_size - 1 && + (val >= info->calib_data[range].max)) { range++; dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n", - arizona_hpdet_d_ranges[range].min, - arizona_hpdet_d_ranges[range].max); + info->calib_data[range].min, + info->calib_data[range].max); regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, ARIZONA_HP_IMPEDANCE_RANGE_MASK, @@ -778,9 +802,23 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) ret); return -EAGAIN; } - val = (val >> ARIZONA_HP_DACVAL_SHIFT) & ARIZONA_HP_DACVAL_MASK; + + if (info->hpdet_ip == 4) { + ret = regmap_read(arizona->regmap, + ARIZONA_HP_DACVAL, + &val_down); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read HP DACVAL value: %d\n", + ret); + return -EAGAIN; + } + val_down = (val_down >> ARIZONA_HP_DACVAL_DOWN_SHIFT) & + ARIZONA_HP_DACVAL_DOWN_MASK; + val = (val + val_down) / 2; + } val = arizona_hpdet_d_calibrate(info, val, range); + break; } @@ -908,8 +946,8 @@ static const struct reg_default clearwater_normal_impedance_patch[] = { { 0x483, 0x0023 }, }; -int arizona_wm5110_tune_headphone(struct arizona_extcon_info *info, - int reading) +static int arizona_wm5110_tune_headphone(struct arizona_extcon_info *info, + int reading) { struct arizona *arizona = info->arizona; const struct reg_default *patch; @@ -958,8 +996,8 @@ int arizona_wm5110_tune_headphone(struct arizona_extcon_info *info, return 0; } -int arizona_wm1814_tune_headphone(struct arizona_extcon_info *info, - int reading) +static int arizona_wm1814_tune_headphone(struct arizona_extcon_info *info, + int reading) { struct arizona *arizona = info->arizona; const struct reg_default *patch; @@ -999,8 +1037,8 @@ int arizona_wm1814_tune_headphone(struct arizona_extcon_info *info, return 0; } -int arizona_clearwater_tune_headphone(struct arizona_extcon_info *info, - int reading) +static int arizona_clearwater_tune_headphone(struct arizona_extcon_info *info, + int reading) { struct arizona *arizona = info->arizona; const struct reg_default *patch; @@ -1163,15 +1201,21 @@ static int arizona_hpdet_moisture_start(struct arizona_extcon_info *info) switch (arizona->type) { case WM5102: - case WM5110: case WM8997: + regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, + ARIZONA_HP_RATE, ARIZONA_HP_RATE); + break; + case WM5110: case WM8280: - case WM8998: - case WM1814: case WM1831: case CS47L24: regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, - ARIZONA_HP_RATE, ARIZONA_HP_RATE); + ARIZONA_HP_FAST_MODE, ARIZONA_HP_FAST_MODE); + break; + case WM8998: + case WM1814: + regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, + VEGAS_HP_FAST_MODE, VEGAS_HP_FAST_MODE); break; default: regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, @@ -1195,15 +1239,21 @@ static void arizona_hpdet_moisture_stop(struct arizona_extcon_info *info) switch (arizona->type) { case WM5102: - case WM5110: case WM8997: + regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, + ARIZONA_HP_RATE, 0); + break; + case WM5110: case WM8280: - case WM8998: - case WM1814: case WM1831: case CS47L24: regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, - ARIZONA_HP_RATE, 0); + ARIZONA_HP_FAST_MODE, 0); + break; + case WM8998: + case WM1814: + regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, + VEGAS_HP_FAST_MODE, 0); break; default: regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, @@ -1645,6 +1695,14 @@ static int arizona_antenna_add_micd_level(struct arizona_extcon_info *info, int int i, j, micd_lvl; int hp_imp_range_lo = -1, hp_imp_range_hi = -1, ret = 0; + /* check if additional impedance levels can be added */ + if (info->num_micd_ranges + 2 > ARIZONA_MAX_MICD_RANGE) { + dev_info(arizona->dev, "Cannot increase MICD ranges to: %d\n", + info->num_micd_ranges + 2); + ret = -EINVAL; + goto err_input; + } + /* check if impedance level is supported */ for (micd_lvl = 0; micd_lvl < ARIZONA_NUM_MICD_BUTTON_LEVELS; micd_lvl++) { if (arizona_micd_levels[micd_lvl] >= imp) @@ -1685,7 +1743,10 @@ static int arizona_antenna_add_micd_level(struct arizona_extcon_info *info, int } if (hp_imp_range_lo == hp_imp_range_hi) { - if (info->micd_ranges[i-1].max < arizona_micd_levels[hp_imp_range_hi - 1]) + if (i == 0) + hp_imp_range_lo = hp_imp_range_hi - 1; + else if (info->micd_ranges[i-1].max < + arizona_micd_levels[hp_imp_range_hi - 1]) hp_imp_range_lo = hp_imp_range_hi - 1; else { dev_info(arizona->dev, "MICD level range cannot be added %d\n", @@ -1701,7 +1762,10 @@ static int arizona_antenna_add_micd_level(struct arizona_extcon_info *info, int info->micd_ranges[j+2].key = info->micd_ranges[j].key; } info->micd_ranges[i].max = arizona_micd_levels[hp_imp_range_lo]; - info->micd_ranges[i].key = info->micd_ranges[i+2].key; + if (i == info->num_micd_ranges) + info->micd_ranges[i].key = info->micd_ranges[i-1].key; + else + info->micd_ranges[i].key = info->micd_ranges[i+2].key; info->micd_ranges[i+1].max =arizona_micd_levels[hp_imp_range_hi]; info->micd_ranges[i+1].key = -1; info->num_micd_ranges += 2; @@ -1750,6 +1814,8 @@ static int arizona_antenna_button_start(struct arizona_extcon_info *info) int i, micd_lvl; int hp_imp_range_hi = -1; + info->button_impedance = 0; + info->button_check = 0; info->wait_for_mic = false; /* check if impedance level is supported */ @@ -1831,7 +1897,7 @@ static int arizona_antenna_button_reading(struct arizona_extcon_info *info, int i; info->button_impedance = 0; - info->button_check = false; + info->button_check = 0; /* Clear any currently pressed buttons */ for (i = 0; i < info->num_micd_ranges; i++) @@ -2357,6 +2423,14 @@ const struct arizona_jd_state arizona_hpdet_moisture = { }; EXPORT_SYMBOL_GPL(arizona_hpdet_moisture); +const struct arizona_jd_state arizona_hpdet_moisture_r = { + .mode = ARIZONA_ACCDET_MODE_HPR, + .start = arizona_hpdet_moisture_start, + .reading = arizona_hpdet_moisture_reading, + .stop = arizona_hpdet_moisture_stop, +}; +EXPORT_SYMBOL_GPL(arizona_hpdet_moisture_r); + const struct arizona_jd_state arizona_hpdet_left = { .mode = ARIZONA_ACCDET_MODE_HPL, .start = arizona_hpdet_start, @@ -2423,6 +2497,14 @@ const struct arizona_jd_state arizona_antenna_moisture = { }; EXPORT_SYMBOL_GPL(arizona_antenna_moisture); +const struct arizona_jd_state arizona_antenna_moisture_r = { + .mode = ARIZONA_ACCDET_MODE_HPR, + .start = arizona_hpdet_moisture_start, + .reading = arizona_antenna_moisture_reading, + .stop = arizona_hpdet_moisture_stop, +}; +EXPORT_SYMBOL_GPL(arizona_antenna_moisture_r); + const struct arizona_jd_state arizona_antenna_mic_det = { .mode = ARIZONA_ACCDET_MODE_ADC, .start = arizona_micd_mic_start, @@ -2554,13 +2636,21 @@ static irqreturn_t arizona_jackdet(int irq, void *data) if (arizona->pdata.custom_jd) arizona_jds_set_state(info, arizona->pdata.custom_jd); - else if (arizona->pdata.antenna_supported) - arizona_jds_set_state(info, - &arizona_antenna_moisture); - else if (arizona->pdata.hpdet_moisture_imp) - arizona_jds_set_state(info, - &arizona_hpdet_moisture); - else if (arizona->pdata.micd_software_compare) + else if (arizona->pdata.antenna_supported) { + if (arizona->pdata.moisture_det_channel) + arizona_jds_set_state(info, + &arizona_antenna_moisture_r); + else + arizona_jds_set_state(info, + &arizona_antenna_moisture); + } else if (arizona->pdata.hpdet_moisture_imp) { + if (arizona->pdata.moisture_det_channel) + arizona_jds_set_state(info, + &arizona_hpdet_moisture_r); + else + arizona_jds_set_state(info, + &arizona_hpdet_moisture); + } else if (arizona->pdata.micd_software_compare) arizona_jds_set_state(info, &arizona_micd_adc_mic); else @@ -2714,38 +2804,38 @@ static int arizona_extcon_of_get_pdata(struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; - arizona_of_read_u32(arizona, "wlf,micd-detect-debounce", false, + arizona_of_read_s32(arizona, "wlf,micd-detect-debounce", false, &pdata->micd_detect_debounce); - arizona_of_read_u32(arizona, "wlf,micd-manual-debounce", false, + arizona_of_read_s32(arizona, "wlf,micd-manual-debounce", false, &pdata->micd_manual_debounce); - arizona_of_read_u32(arizona, "wlf,antenna-manual-debounce", false, + arizona_of_read_s32(arizona, "wlf,antenna-manual-debounce", false, &pdata->antenna_manual_debounce); - arizona_of_read_u32(arizona, "wlf,antenna-manual-db-plugout", false, + arizona_of_read_s32(arizona, "wlf,antenna-manual-db-plugout", false, &pdata->antenna_manual_db_plugout); - arizona_of_read_u32(arizona, "wlf,antenna-hp-imp-range-lo", false, + arizona_of_read_s32(arizona, "wlf,antenna-hp-imp-range-lo", false, &pdata->antenna_hp_imp_range_lo); - arizona_of_read_u32(arizona, "wlf,antenna-hp-imp-range-hi", false, + arizona_of_read_s32(arizona, "wlf,antenna-hp-imp-range-hi", false, &pdata->antenna_hp_imp_range_hi); pdata->micd_pol_gpio = arizona_of_get_named_gpio(arizona, "wlf,micd-pol-gpio", false); - arizona_of_read_u32(arizona, "wlf,micd-bias-start-time", false, + arizona_of_read_s32(arizona, "wlf,micd-bias-start-time", false, &pdata->micd_bias_start_time); - arizona_of_read_u32(arizona, "wlf,micd-rate", false, + arizona_of_read_s32(arizona, "wlf,micd-rate", false, &pdata->micd_rate); - arizona_of_read_u32(arizona, "wlf,micd-dbtime", false, + arizona_of_read_s32(arizona, "wlf,micd-dbtime", false, &pdata->micd_dbtime); - arizona_of_read_u32(arizona, "wlf,micd-timeout", false, + arizona_of_read_s32(arizona, "wlf,micd-timeout", false, &pdata->micd_timeout); pdata->micd_force_micbias = @@ -2777,25 +2867,28 @@ static int arizona_extcon_of_get_pdata(struct arizona *arizona) arizona_of_read_u32(arizona, "wlf,gpsw", false, &pdata->gpsw); - arizona_of_read_u32(arizona, "wlf,init-mic-delay", false, + arizona_of_read_s32(arizona, "wlf,init-mic-delay", false, &pdata->init_mic_delay); - arizona_of_read_u32(arizona, "wlf,fixed-hpdet-imp", false, + arizona_of_read_s32(arizona, "wlf,fixed-hpdet-imp", false, &pdata->fixed_hpdet_imp); - arizona_of_read_u32(arizona, "wlf,hpdet-moisture-imp", false, + arizona_of_read_s32(arizona, "wlf,hpdet-moisture-imp", false, &pdata->hpdet_moisture_imp); - arizona_of_read_u32(arizona, "wlf,hpdet-moisture-debounce", false, + arizona_of_read_s32(arizona, "wlf,hpdet-moisture-debounce", false, &pdata->hpdet_moisture_debounce); - arizona_of_read_u32(arizona, "wlf,hpdet-short-circuit-imp", false, + arizona_of_read_s32(arizona, "wlf,hpdet-short-circuit-imp", false, &pdata->hpdet_short_circuit_imp); - arizona_of_read_u32(arizona, "wlf,hpdet-channel", false, + arizona_of_read_s32(arizona, "wlf,hpdet-channel", false, &pdata->hpdet_channel); - arizona_of_read_u32(arizona, "wlf,jd-wake-time", false, + arizona_of_read_u32(arizona, "wlf,moisture-det-channel", false, + &pdata->moisture_det_channel); + + arizona_of_read_s32(arizona, "wlf,jd-wake-time", false, &pdata->jd_wake_time); arizona_of_read_u32(arizona, "wlf,micd-clamp-mode", false, @@ -2842,7 +2935,7 @@ static int arizona_micd_manual_reading(struct arizona_extcon_info *info, int val return val; } -const struct arizona_jd_state arizona_micd_manual = { +static const struct arizona_jd_state arizona_micd_manual = { .mode = ARIZONA_ACCDET_MODE_ADC, .start = arizona_micd_mic_start, .reading = arizona_micd_manual_reading, @@ -2894,10 +2987,6 @@ static int arizona_hpdet_d_read_calibration(struct arizona_extcon_info *info) unsigned int v1, v2; int ret = -EIO; -#ifdef ARIZONA_HPDET_USE_DEFAULT_TRIMS - info->hpdet_d_trims = arizona_hpdet_d_trims_default; -#endif - ret = regmap_read(arizona->regmap, 0x0087, &v1); if (ret >= 0) { ret = regmap_read(arizona->regmap, 0x0088, &v2); @@ -2939,26 +3028,120 @@ static int arizona_hpdet_d_read_calibration(struct arizona_extcon_info *info) grad_range3_2 = (v2 >> 7) & 0x7f; grad_range3_2 = arizona_hp_trim_signify(grad_range3_2, 0x3f); - trims[0].off = coeff_range0 + off_range1; - trims[1].off = off_range1; - trims[2].off = coeff_range2 + off_range1; - trims[3].off = coeff_range3 + off_range1; - trims[0].grad_x2 = grad_range1_0 * 2; - trims[1].grad_x2 = grad_range1_0 * 2; - trims[2].grad_x2 = grad_range3_2 * 2; - trims[3].grad_x2 = grad_range3_2 * 2; + trims[0].off_x4 = (coeff_range0 + off_range1) * 4; + trims[1].off_x4 = off_range1 * 4; + trims[2].off_x4 = (coeff_range2 + off_range1) * 4; + trims[3].off_x4 = (coeff_range3 + off_range1) * 4; + trims[0].grad_x4 = grad_range1_0 * 4; + trims[1].grad_x4 = grad_range1_0 * 4; + trims[2].grad_x4 = grad_range3_2 * 4; + trims[3].grad_x4 = grad_range3_2 * 4; info->hpdet_d_trims = trims; + info->calib_data = arizona_hpdet_d_ranges; + info->calib_data_size = ARRAY_SIZE(arizona_hpdet_d_ranges); dev_dbg(arizona->dev, "Set trims %d,%d %d,%d %d,%d %d,%d\n", - trims[0].off, - trims[0].grad_x2, - trims[1].off, - trims[1].grad_x2, - trims[2].off, - trims[2].grad_x2, - trims[3].off, - trims[3].grad_x2); + trims[0].off_x4, + trims[0].grad_x4, + trims[1].off_x4, + trims[1].grad_x4, + trims[2].off_x4, + trims[2].grad_x4, + trims[3].off_x4, + trims[3].grad_x4); + return 0; +} + +#define ARIZONA_HPDET_CLEARWATER_OTP_MID_VAL 128 +static inline int arizona_hpdet_clearwater_convert_otp(unsigned int otp_val) +{ + return (ARIZONA_HPDET_CLEARWATER_OTP_MID_VAL - (int)otp_val); +} + +static int arizona_hpdet_clearwater_read_calibration(struct arizona_extcon_info *info) +{ + struct arizona *arizona = info->arizona; + struct arizona_hpdet_d_trims *trims; + int ret = -EIO; + unsigned int offset, gradient, interim_val; + unsigned int otp_hpdet_calib_1, otp_hpdet_calib_2; + + switch (arizona->type) { + case CS47L35: + otp_hpdet_calib_1 = MARLEY_OTP_HPDET_CALIB_1; + otp_hpdet_calib_2 = MARLEY_OTP_HPDET_CALIB_2; + break; + default: + otp_hpdet_calib_1 = CLEARWATER_OTP_HPDET_CALIB_1; + otp_hpdet_calib_2 = CLEARWATER_OTP_HPDET_CALIB_2; + break; + } + + ret = regmap_read(arizona->regmap_32bit, + otp_hpdet_calib_1, + &offset); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read HP CALIB OFFSET value: %d\n", + ret); + return ret; + } + + ret = regmap_read(arizona->regmap_32bit, + otp_hpdet_calib_2, + &gradient); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read HP CALIB OFFSET value: %d\n", + ret); + return ret; + } + + if (((offset == 0) && (gradient == 0)) || + ((offset == 0xFFFFFFFF) && (gradient == 0xFFFFFFFF))) { + dev_warn(arizona->dev, "No HP trims\n"); + return 0; + } + + trims = devm_kzalloc(info->dev, + 4 * sizeof(struct arizona_hpdet_d_trims), + GFP_KERNEL); + if (!trims) { + dev_err(arizona->dev, "Failed to alloc hpdet trims\n"); + return -ENOMEM; + } + + interim_val = (offset & CLEARWATER_OTP_HPDET_CALIB_OFFSET_00_MASK) >> + CLEARWATER_OTP_HPDET_CALIB_OFFSET_00_SHIFT; + trims[0].off_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + interim_val = (gradient & CLEARWATER_OTP_HPDET_GRADIENT_0X_MASK) >> + CLEARWATER_OTP_HPDET_GRADIENT_0X_SHIFT; + trims[0].grad_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + interim_val = (offset & CLEARWATER_OTP_HPDET_CALIB_OFFSET_01_MASK) >> + CLEARWATER_OTP_HPDET_CALIB_OFFSET_01_SHIFT; + trims[1].off_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + trims[1].grad_x4 = trims[0].grad_x4; + + interim_val = (offset & CLEARWATER_OTP_HPDET_CALIB_OFFSET_10_MASK) >> + CLEARWATER_OTP_HPDET_CALIB_OFFSET_10_SHIFT; + trims[2].off_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + interim_val = (gradient & CLEARWATER_OTP_HPDET_GRADIENT_1X_MASK) >> + CLEARWATER_OTP_HPDET_GRADIENT_1X_SHIFT; + trims[2].grad_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + interim_val = (offset & CLEARWATER_OTP_HPDET_CALIB_OFFSET_11_MASK) >> + CLEARWATER_OTP_HPDET_CALIB_OFFSET_11_SHIFT; + trims[3].off_x4 = arizona_hpdet_clearwater_convert_otp(interim_val); + + trims[3].grad_x4 = trims[2].grad_x4; + + info->hpdet_d_trims = trims; + info->calib_data = arizona_hpdet_clearwater_ranges; + info->calib_data_size = ARRAY_SIZE(arizona_hpdet_clearwater_ranges); + return 0; } @@ -3139,6 +3322,14 @@ static int arizona_extcon_probe(struct platform_device *pdev) break; } break; + case CS47L35: + arizona->pdata.micd_force_micbias = true; + /* fall through to next case to set common properties */ + case WM8285: + case WM1840: + info->micd_clamp = true; + info->hpdet_ip = 4; + break; default: info->micd_clamp = true; info->hpdet_ip = 2; @@ -3291,10 +3482,25 @@ static int arizona_extcon_probe(struct platform_device *pdev) pm_runtime_idle(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - if (info->hpdet_ip == 3) { + switch (info->hpdet_ip) { + case 3: arizona_hpdet_d_read_calibration(info); if (!info->hpdet_d_trims) info->hpdet_ip = 2; + break; + case 4: + arizona_hpdet_clearwater_read_calibration(info); + if (!info->hpdet_d_trims) + info->hpdet_ip = 2; + else + /* as per the hardware steps - below bit needs to be set + * for clearwater for accurate HP impedance detection */ + regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, + ARIZONA_ACCDET_POLARITY_INV_ENA_MASK, + 1 << ARIZONA_ACCDET_POLARITY_INV_ENA_SHIFT); + break; + default: + break; } if (arizona->pdata.jd_gpio5) { diff --git a/drivers/thermal/exynos7420_thermal.c b/drivers/thermal/exynos7420_thermal.c index f31dcc03c017..348061a93395 100644 --- a/drivers/thermal/exynos7420_thermal.c +++ b/drivers/thermal/exynos7420_thermal.c @@ -839,6 +839,7 @@ static void exynos_tmu_get_efuse(struct platform_device *pdev, int id) struct exynos_tmu_data *data = platform_get_drvdata(pdev); struct exynos_tmu_platform_data *pdata = data->pdata; unsigned int trim_info, temp; + int retry_cnt = 0; mutex_lock(&data->lock); @@ -848,6 +849,21 @@ static void exynos_tmu_get_efuse(struct platform_device *pdev, int id) /* Save trimming info in order to perform calibration */ trim_info = readl(data->base[id] + EXYNOS_TMU_REG_TRIMINFO); + /* retry read TRIMINFO when 0, it could be happend cur_probe_sensor is changed after check */ + while (trim_info == 0) { + mdelay(1); + while (get_cur_probe_sensor(data, id) != SENSOR_P0) + usleep_range(1, 2); + + trim_info = readl(data->base[id] + EXYNOS_TMU_REG_TRIMINFO); + + retry_cnt++; + + if (retry_cnt == 10 && trim_info == 0) { + panic("TMU[%d] TRIMINFO READ FAIL\n", id); + } + } + if (trim_info & CALIB_SEL_MASK) pdata->cal_type = TYPE_TWO_POINT_TRIMMING; else diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7abe2a926f43..ee59998437af 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -114,13 +114,14 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, } /** - * n_tty_set__room - receive space + * n_tty_set_room - receive space * @tty: terminal * - * Called by the driver to find out how much data it is - * permitted to feed to the line discipline without any being lost - * and thus to manage flow control. Not serialized. Answers for the - * "instant". + * Sets tty->receive_room to reflect the currently available space + * in the input buffer, and re-schedules the flip buffer work if space + * just became available. + * + * Locks: Concurrent update is protected with read_lock */ static void n_tty_set_room(struct tty_struct *tty) @@ -132,7 +133,6 @@ static void n_tty_set_room(struct tty_struct *tty) raw_spin_lock_irqsave(&ldata->read_lock, flags); - /* ldata->read_cnt is not read locked ? */ if (I_PARMRK(tty)) { /* Multiply read_cnt by 3, since each byte might take up to * three times as many spaces when PARMRK is set (depending on @@ -1886,7 +1886,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, retval = -ERESTARTSYS; break; } - /* FIXME: does n_tty_set_room need locking ? */ n_tty_set_room(tty); timeout = schedule_timeout(timeout); continue; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 4930180cca82..6dc1e8c15342 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -37,7 +37,7 @@ #include #include -#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) /* This is just temporary features*/ +#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) || defined(CONFIG_BT_BCM4359) /* This is just temporary features*/ #define BT4339_LINE 4 #endif /* @@ -186,7 +186,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (tty_port_cts_enabled(port)) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) -#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) +#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) || defined(CONFIG_BT_BCM4359) if (uport->line != BT4339_LINE) tty->hw_stopped = 1; #else @@ -1313,7 +1313,7 @@ static void uart_set_termios(struct tty_struct *tty, else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { spin_lock_irqsave(&uport->lock, flags); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) { -#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) +#if defined(CONFIG_BT_BCM4339) || defined(CONFIG_BT_BCM4354) || defined(CONFIG_BT_BCM4358) || defined(CONFIG_BT_BCM4359) if (uport->line != BT4339_LINE) tty->hw_stopped = 1; #else diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index bd4b45a93e1a..42fd2e4d341f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -73,6 +73,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) urb->transfer_buffer_length); #if defined(CONFIG_MDM_HSIC_PM) ep0_timeout_cnt++; + set_ap2mdm_errfatal(); #endif } else retval = ctx.status; diff --git a/drivers/usb/gadget/f_mtp_samsung.c b/drivers/usb/gadget/f_mtp_samsung.c index c500d244b99e..5a46c129a21b 100644 --- a/drivers/usb/gadget/f_mtp_samsung.c +++ b/drivers/usb/gadget/f_mtp_samsung.c @@ -887,11 +887,6 @@ static void read_send_work(struct work_struct *work) break; } - if (!req) { - printk(KERN_ERR "[%s]Alloc has failed\n", __func__); - break; - } - if (count > MTPG_BULK_BUFFER_SIZE) xfer = MTPG_BULK_BUFFER_SIZE; else @@ -997,8 +992,12 @@ static long mtpg_ioctl(struct file *fd, unsigned int code, unsigned long arg) case MTP_WRITE_INT_DATA: printk(KERN_INFO "[%s]\t%d MTP intrpt_Write no slep\n", __func__, __LINE__); - if (copy_from_user(&event, (void __user *)arg, sizeof(event))) + if (copy_from_user(&event, (void __user *)arg, sizeof(event))){ status = -EFAULT; + printk(KERN_ERR "[%s]\t%d:copyfrmuser fail\n", + __func__, __LINE__); + break; + } ret_value = interrupt_write(fd, &event, MTP_MAX_PACKET_LEN_FROM_APP); if (ret_value < 0) { printk(KERN_ERR "[%s]\t%d interptFD failed\n", diff --git a/drivers/usb/gadget/u_ncm.c b/drivers/usb/gadget/u_ncm.c index 59eb16188678..4ad5e3e78406 100644 --- a/drivers/usb/gadget/u_ncm.c +++ b/drivers/usb/gadget/u_ncm.c @@ -19,11 +19,26 @@ */ #include "f_ncm.c" +#include /* Support dynamic tethering mode. * if ncm_connect is true, device is received vendor specific request * from head unit. */ + +struct ncm_dev { + struct work_struct work; +}; + + +static const char mirrorlink_shortname[] = "usb_ncm"; +/* Create misc driver for Mirror Link cmd */ +static struct miscdevice mirrorlink_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = mirrorlink_shortname, + //.fops = &mirrorlink_fops, +}; + static bool ncm_connect; /* terminal version using vendor specific request */ @@ -35,17 +50,58 @@ struct ncm_function_config { struct eth_dev *dev; }; +static struct ncm_dev *_ncm_dev; + +static void ncm_work(struct work_struct *data) +{ + char *ncm_start[2] = { "NCM_DEVICE=START", NULL }; + char *ncm_release[2] = { "NCM_DEVICE=RELEASE", NULL }; + char **uevent_envp = NULL; + + printk(KERN_DEBUG "usb: %s ncm_connect=%d\n", __func__, ncm_connect); + + if ( ncm_connect==true ) + uevent_envp = ncm_start; + else + uevent_envp = ncm_release; + + kobject_uevent_env(&mirrorlink_device.this_device->kobj, KOBJ_CHANGE, uevent_envp); +} + static int ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *cdev) { + struct ncm_dev *dev; + int ret=0; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL); + + if (!f->config) + { + kfree(dev); + return -ENOMEM; + } + INIT_WORK(&dev->work, ncm_work); + + _ncm_dev = dev; + + ret = misc_register(&mirrorlink_device); + if (ret) + printk("usb: %s - usb_ncm misc driver fail \n",__func__); return 0; } static void ncm_function_cleanup(struct android_usb_function *f) { + misc_deregister(&mirrorlink_device); + kfree(_ncm_dev); kfree(f->config); f->config = NULL; + _ncm_dev = NULL; } @@ -152,8 +208,12 @@ void set_ncm_device_descriptor(struct usb_device_descriptor *desc) void set_ncm_ready(bool ready) { if (ready != ncm_connect) + { printk(KERN_DEBUG "usb: %s old status=%d, new status=%d\n", __func__, ncm_connect, ready); + schedule_work(&_ncm_dev->work); + } + ncm_connect = ready; if (ready == false) { terminal_mode_version = 0; diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 9b4609fd0ffc..6269e3f37d8a 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -583,6 +583,10 @@ static int s5p_ehci_probe(struct platform_device *pdev) } else if (s5p_ehci->pdata->phy_exit) { s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); } + + /* clear Host */ + if (s5p_ehci->otg) + s5p_ehci->otg->host = NULL; fail_io: s5p_ehci_clk_disable_unprepare(s5p_ehci); fail_clk: diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 2bab2e5251bf..6c4607b18ea7 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -368,6 +368,10 @@ static int exynos_ohci_probe(struct platform_device *pdev) if (exynos_ohci->phy) pm_runtime_put_sync(exynos_ohci->phy->dev); exynos_ohci_phy_disable(exynos_ohci); + + /* clear Host */ + if (exynos_ohci->otg) + exynos_ohci->otg->host = NULL; fail_io: clk_disable_unprepare(exynos_ohci->clk); fail_clk: @@ -394,6 +398,10 @@ static int exynos_ohci_remove(struct platform_device *pdev) exynos_ohci_phy_disable(exynos_ohci); + /* clear Host */ + if (exynos_ohci->otg) + exynos_ohci->otg->host = NULL; + clk_disable_unprepare(exynos_ohci->clk); usb_put_hcd(hcd); diff --git a/drivers/usb/phy/phy-samsung-usb3-cal.c b/drivers/usb/phy/phy-samsung-usb3-cal.c index 76f6d05769c6..81274bb336e5 100644 --- a/drivers/usb/phy/phy-samsung-usb3-cal.c +++ b/drivers/usb/phy/phy-samsung-usb3-cal.c @@ -19,6 +19,7 @@ #include "phy-samsung-usb-cal.h" #include "phy-samsung-usb3-cal.h" +#include /* for struct device_node */ void samsung_exynos5_cal_usb3phy_enable(void __iomem *regs_base, u32 refclkfreq) @@ -227,6 +228,7 @@ void samsung_exynos5_cal_usb3phy_tune_dev(void __iomem *regs_base) u32 phyparam1; u32 phyparam2; u32 phypcsval; + struct device_node *np_usb3phy; /* Set the LINK Version Control and Frame Adjust Value */ linksystem = readl(regs_base + EXYNOS5_DRD_LINKSYSTEM); @@ -240,13 +242,22 @@ void samsung_exynos5_cal_usb3phy_tune_dev(void __iomem *regs_base) phypipe |= PHY_CLOCK_SEL; writel(phypipe, regs_base + EXYNOS5_DRD_PHYPIPE); - /* Tuning the USB3 HS Pre-empasis and TXVREFTUNE */ phyparam0 = readl(regs_base + EXYNOS5_DRD_PHYPARAM0); - phyparam0 &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; - phyparam0 |= PHYPARAM0_TXPREEMPAMPTUNE(0x3); - phyparam0 &= ~PHYPARAM0_TXVREFTUNE_MASK; - phyparam0 |= PHYPARAM0_TXVREFTUNE(0xe); - writel(phyparam0, regs_base + EXYNOS5_DRD_PHYPARAM0); + + /* Tuning the USB3 HS Pre-empasis and TXVREFTUNE */ + np_usb3phy = of_find_node_by_name(NULL, "dwc3_phy"); + if(!np_usb3phy){ + phyparam0 = readl(regs_base + EXYNOS5_DRD_PHYPARAM0); + phyparam0 &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK; + phyparam0 |= PHYPARAM0_TXPREEMPAMPTUNE(0x3); + phyparam0 &= ~PHYPARAM0_TXVREFTUNE_MASK; + phyparam0 |= PHYPARAM0_TXVREFTUNE(0xe); + writel(phyparam0, regs_base + EXYNOS5_DRD_PHYPARAM0); + } else { + if(!of_property_read_u32(np_usb3phy, "dwc3,usb3phy-tune", &phyparam0)){ + writel(phyparam0, regs_base + EXYNOS5_DRD_PHYPARAM0); + } + } /* Set the PHY Signal Quality Tuning Value */ phyparam1 = readl(regs_base + EXYNOS5_DRD_PHYPARAM1); diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile index 0d490282ad0e..c8ce656b9ed6 100644 --- a/drivers/video/exynos/Makefile +++ b/drivers/video/exynos/Makefile @@ -10,4 +10,5 @@ obj-$(CONFIG_EXYNOS_DECON_DISPLAY) += decon_display/ obj-$(CONFIG_EXYNOS_DECON_TV_DISPLAY) += decon_tv_display/ obj-y += panels/ obj-$(CONFIG_EXYNOS_DECON) += decon/ +obj-$(CONFIG_EXYNOS_DUAL_DECON) += dual_decon/ obj-$(CONFIG_EXYNOS_DECON_EXYNOS7580) += decon_7580/ \ No newline at end of file diff --git a/drivers/video/exynos/decon/decon.h b/drivers/video/exynos/decon/decon.h index b7dc6d9de4fe..efa5be33e998 100644 --- a/drivers/video/exynos/decon/decon.h +++ b/drivers/video/exynos/decon/decon.h @@ -394,6 +394,8 @@ struct decon_win_config { struct vpp_params vpp_parm; /* no read area of IDMA */ struct decon_win_rect block_area; + struct decon_win_rect transparent_area; + struct decon_win_rect opaque_area; /* source framebuffer coordinates */ struct decon_frame src; }; @@ -569,6 +571,8 @@ struct disp_log_vpp { u32 id; u32 start_cnt; u32 done_cnt; + u32 cur_int; + u32 cur_bw; }; /* Related with frame count */ diff --git a/drivers/video/exynos/decon/decon_core.c b/drivers/video/exynos/decon/decon_core.c index 9809c4f01088..b65cff81f8a7 100644 --- a/drivers/video/exynos/decon/decon_core.c +++ b/drivers/video/exynos/decon/decon_core.c @@ -1177,17 +1177,23 @@ static void decon_free_dma_buf(struct decon_device *decon, ion_free(decon->ion_client, dma->ion_handle); memset(dma, 0, sizeof(struct decon_dma_buf_data)); } +#if defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) + unsigned char esd_support; +#endif + static void decon_esd_enable_interrupt(struct decon_device *decon) { struct esd_protect *esd = &decon->esd; if (esd) { if (esd->pcd_irq){ - //disable_irq_nosync(esd->pcd_irq); enable_irq(esd->pcd_irq); } if (esd->err_irq) { - //disable_irq_nosync(esd->err_irq); +#if defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) + if(esd_support == 0) // because pre panel don't support esd recovery + return; +#endif enable_irq(esd->err_irq); } } @@ -1215,11 +1221,11 @@ int decon_enable(struct decon_device *decon) struct decon_init_param p; int state = decon->state; int ret = 0; + unsigned int te_pending = 0; #ifdef CONFIG_LCD_ALPM int alpm = 0; struct dsim_device *dsim = NULL; #endif - unsigned int te_pending = 0; decon_dbg("enable decon-%s\n", decon->id ? "ext" : "int"); exynos_ss_printk("%s:state %d: active %d:+\n", __func__, @@ -1232,7 +1238,6 @@ int decon_enable(struct decon_device *decon) decon_info("decon-%s: alpm(%d)\n", decon->id ? "ext" : "int", alpm); } #endif - if (decon->state != DECON_STATE_LPD_EXIT_REQ) mutex_lock(&decon->output_lock); @@ -1466,10 +1471,13 @@ int decon_disable(struct decon_device *decon) decon_reg_stop(decon->id, decon->pdata->dsi_mode, &psr); decon_reg_clear_int(decon->id); - /* DMA protection disable must be happen on vpp domain is alive */ - decon_set_protected_content(decon, NULL); - decon->vpp_usage_bitmask = 0; - decon_vpp_stop(decon, true); + if (decon->out_type != DECON_OUT_WB) { + /* DMA protection disable must be happen on vpp domain is alive */ + decon_set_protected_content(decon, NULL); + decon->vpp_usage_bitmask = 0; + decon_vpp_stop(decon, true); + } + iovmm_deactivate(decon->dev); /* Synchronize the decon->state with irq_handler */ @@ -1811,16 +1819,20 @@ static int decon_get_plane_cnt(enum decon_pixel_format format) } -inline static u32 get_vpp_src_format_opaque(u32 format) +static inline u32 get_vpp_src_format_opaque(int id, u32 format) { switch (format) { case DECON_PIXEL_FORMAT_BGRA_8888: + decon_info("vpp(%d), format(0x%x)\n", id, format); return DECON_PIXEL_FORMAT_BGRX_8888; case DECON_PIXEL_FORMAT_RGBA_8888: + decon_info("vpp(%d), format(0x%x)\n", id, format); return DECON_PIXEL_FORMAT_RGBX_8888; case DECON_PIXEL_FORMAT_ABGR_8888: + decon_info("vpp(%d), format(0x%x)\n", id, format); return DECON_PIXEL_FORMAT_XBGR_8888; case DECON_PIXEL_FORMAT_ARGB_8888: + decon_info("vpp(%d), format(0x%x)\n", id, format); return DECON_PIXEL_FORMAT_XRGB_8888; default: return format; @@ -1832,7 +1844,7 @@ static u32 get_vpp_src_format(u32 format, int id) switch (id) { case IDMA_VG0: case IDMA_VG1: - format = get_vpp_src_format_opaque(format); + format = get_vpp_src_format_opaque(id, format); break; default: break; @@ -3085,6 +3097,8 @@ static void decon_update_regs(struct decon_device *decon, struct decon_reg_data } else { decon->frame_done_cnt_cur++; atomic_set(&decon->wb_done, STATE_IDLE); + decon->vpp_usage_bitmask = 0; + decon_set_protected_content(decon, NULL); } } else { decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC); @@ -4172,11 +4186,16 @@ static void decon_parse_pdata(struct decon_device *decon, struct device *dev) static int decon_esd_panel_reset(struct decon_device *decon) { - int ret; + int ret = 0; struct esd_protect *esd = &decon->esd; decon_info("++ %s\n", __func__); + if (decon->state == DECON_STATE_OFF) { + decon_warn("decon%d status is inactive\n", decon->id); + return ret; + } + flush_workqueue(decon->lpd_wq); decon_lpd_block_exit(decon); @@ -4216,7 +4235,7 @@ static int decon_esd_panel_reset(struct decon_device *decon) decon->update_win.w = decon->lcd_info->xres; decon->update_win.h = decon->lcd_info->yres; decon->force_fullupdate = 1; - +#if 0 if (decon->pdata->trig_mode == DECON_HW_TRIG) decon_reg_set_trigger(decon->id, decon->pdata->dsi_mode, decon->pdata->trig_mode, DECON_TRIG_ENABLE); @@ -4230,8 +4249,8 @@ static int decon_esd_panel_reset(struct decon_device *decon) if (decon->pdata->trig_mode == DECON_HW_TRIG) decon_reg_set_trigger(decon->id, decon->pdata->dsi_mode, decon->pdata->trig_mode, DECON_TRIG_DISABLE); - reset_exit: +#endif mutex_unlock(&decon->output_lock); decon_lpd_unblock(decon); diff --git a/drivers/video/exynos/decon/decon_helper.c b/drivers/video/exynos/decon/decon_helper.c index df7afd6e735e..857cf8b18e22 100644 --- a/drivers/video/exynos/decon/decon_helper.c +++ b/drivers/video/exynos/decon/decon_helper.c @@ -227,6 +227,8 @@ static inline void disp_ss_event_log_vpp log->data.vpp.id = vpp->id; log->data.vpp.start_cnt = vpp->start_count; log->data.vpp.done_cnt = vpp->done_count; + log->data.vpp.cur_int = vpp->cur_int; + log->data.vpp.cur_bw = vpp->cur_bw; break; default: log->data.vpp.id = vpp->id; @@ -322,7 +324,7 @@ void DISP_SS_EVENT_LOG(disp_ss_event_t type, struct v4l2_subdev *sd, ktime_t tim case DISP_EVT_WIN_CONFIG: disp_ss_event_log_decon(type, sd, time); break; - + case DISP_EVT_DSIM_SUSPEND: case DISP_EVT_DSIM_RESUME: disp_ss_event_log_dsim(type, sd, time); @@ -614,12 +616,15 @@ void DISP_SS_EVENT_SHOW(struct seq_file *s, struct decon_device *decon) void DISP_SS_EVENT_SIZE_ERR_LOG(struct v4l2_subdev *sd, struct disp_ss_size_info *info) { struct decon_device *decon = container_of(sd, struct decon_device, sd); - int idx = (decon->disp_ss_size_log_idx++) % DISP_EVENT_SIZE_ERR_MAX; - struct disp_ss_size_err_info *log = &decon->disp_ss_size_log[idx]; + int idx; + struct disp_ss_size_err_info *log; if (!decon) return; + idx = (decon->disp_ss_size_log_idx++) % DISP_EVENT_SIZE_ERR_MAX; + log = &decon->disp_ss_size_log[idx]; + log->time = ktime_get(); memcpy(&log->info, info, sizeof(struct disp_ss_size_info)); } diff --git a/drivers/video/exynos/decon/decon_mdnie.c b/drivers/video/exynos/decon/decon_mdnie.c index 07de4a403e01..e00af57ec24b 100644 --- a/drivers/video/exynos/decon/decon_mdnie.c +++ b/drivers/video/exynos/decon/decon_mdnie.c @@ -20,7 +20,7 @@ #include "./panels/mdnie.h" #include "mdnie_reg.h" -#if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) || defined(CONFIG_PANEL_S6E3HF2_DYNAMIC) +#if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) || defined(CONFIG_PANEL_S6E3HF2_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) #include "decon-mdnie_table_zero.h" #endif #if defined(CONFIG_TDMB) diff --git a/drivers/video/exynos/decon/dsim.h b/drivers/video/exynos/decon/dsim.h index cf48aadcf777..4632533fc743 100644 --- a/drivers/video/exynos/decon/dsim.h +++ b/drivers/video/exynos/decon/dsim.h @@ -99,7 +99,8 @@ struct panel_private { unsigned char id[3]; unsigned char code[5]; unsigned char elvss_set[22]; - unsigned char tset[8]; + unsigned char tset[30]; // HA3 is 30 + unsigned char aid[16]; int temperature; unsigned int coordinate[2]; unsigned char date[4]; @@ -118,6 +119,7 @@ struct panel_private { void *dim_info; unsigned int *br_tbl; unsigned int *hbm_inter_br_tbl; + unsigned int *gallery_br_tbl; unsigned char **hbm_tbl; unsigned char **acl_cutoff_tbl; unsigned char **acl_opr_tbl; @@ -196,7 +198,8 @@ struct dsim_device { unsigned int enabled; struct decon_lcd lcd_info; struct dphy_timing_value timing; - int pktgo; + int pktgo; + int glide_display_size; int id; u32 data_lane_cnt; diff --git a/drivers/video/exynos/decon/dsim_drv.c b/drivers/video/exynos/decon/dsim_drv.c index 8e2f6faa9551..72550aeca5f9 100644 --- a/drivers/video/exynos/decon/dsim_drv.c +++ b/drivers/video/exynos/decon/dsim_drv.c @@ -405,10 +405,10 @@ static int dsim_partial_area_command(struct dsim_device *dsim, void *arg) /* w is right & h is bottom */ data_2a[0] = MIPI_DCS_SET_COLUMN_ADDRESS; - data_2a[1] = (win_rect->x >> 8) & 0xff; - data_2a[2] = win_rect->x & 0xff; - data_2a[3] = (win_rect->w >> 8) & 0xff; - data_2a[4] = win_rect->w & 0xff; + data_2a[1] = ((win_rect->x +dsim->glide_display_size) >> 8) & 0xff; + data_2a[2] = (win_rect->x +dsim->glide_display_size) & 0xff; + data_2a[3] = ((win_rect->w +dsim->glide_display_size) >> 8) & 0xff; + data_2a[4] = (win_rect->w +dsim->glide_display_size) & 0xff; data_2b[0] = MIPI_DCS_SET_PAGE_ADDRESS; data_2b[1] = (win_rect->y >> 8) & 0xff; diff --git a/drivers/video/exynos/decon/panels/Kconfig b/drivers/video/exynos/decon/panels/Kconfig index b7c6c74e0a30..0e5e103a52f8 100644 --- a/drivers/video/exynos/decon/panels/Kconfig +++ b/drivers/video/exynos/decon/panels/Kconfig @@ -27,6 +27,11 @@ config LCD_ALPM tristate "Support ALPM display" default n +config LCD_HBM_INTERPOLATION + depends on EXYNOS_DECON_LCD + tristate "Support HBM brightness table" + default n + config PANEL_AID_DIMMING depends on EXYNOS_DECON_LCD tristate "Support AID Dimming" @@ -56,6 +61,14 @@ config PANEL_S6E3HA2_DYNAMIC depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSI tristate "S6E3HA2 AMOLED SUPPORT BOTE S6E3HA0 and S6E3HA2 (1440 x 2560)" +config PANEL_S6E3HA3_DYNAMIC + depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSI + tristate "S6E3HA3 AMOLED SUPPORT BOTH S6E3HA2 and S6E3HA3 (1440 x 2560)" + +config PANEL_S6E3HF3_DYNAMIC + depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSI + tristate "S6E3HF3 AMOLED SUPPORT BOTH S6E3HA2 and S6E3HF3 (1440 x 2560)" + config EXYNOS_DECON_LCD_S6E3FA0 depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSI tristate "S6E3FA0 AMOLED FHD LCD driver(1080 x 1920)" diff --git a/drivers/video/exynos/decon/panels/Makefile b/drivers/video/exynos/decon/panels/Makefile index 7a436558d2f5..36448c1e46e6 100644 --- a/drivers/video/exynos/decon/panels/Makefile +++ b/drivers/video/exynos/decon/panels/Makefile @@ -1,12 +1,8 @@ -obj-$(CONFIG_EXYNOS_DECON_LCD) += dsim_panel.o dsim_backlight.o +obj-$(CONFIG_EXYNOS_DECON_LCD) += dsim_panel.o obj-$(CONFIG_PANEL_AID_DIMMING) += dimming_core.o obj-$(CONFIG_EXYNOS_DECON_MDNIE_LITE) += mdnie_lite.o mdnie_tuning.o obj-$(CONFIG_EXYNOS_DECON_LCD_SYSFS) += lcd_sysfs.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA0) += s6e3ha0k_mipi_lcd.o s6e3ha0k_lcd_ctrl.o dynamic_aid.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K) += s6e3ha2k_mipi_lcd.o s6e3ha2k_lcd_ctrl.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HF2) += s6e3hf2_mipi_lcd.o s6e3hf2_lcd_ctrl.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HF2_WQHD) += s6e3hf2_wqhd_mipi_lcd.o s6e3hf2_wqhd_lcd_ctrl.o s6e3hf2_wqhd_dimming.o -obj-$(CONFIG_PANEL_S6E3HF2_DYNAMIC) += s6e3hf2_wqhd_lcd_ctrl.o -obj-$(CONFIG_PANEL_S6E3HA2_DYNAMIC) += s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3FA0) += s6e3fa0_mipi_lcd.o s6e3fa0_lcd_ctrl.o -obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3FA2) += s6e3fa2_mipi_lcd.o s6e3fa2_lcd_ctrl.o +obj-$(CONFIG_PANEL_S6E3HF2_DYNAMIC) += s6e3hf2_wqhd_lcd_ctrl.o dsim_backlight.o +obj-$(CONFIG_PANEL_S6E3HA2_DYNAMIC) += s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.o dsim_backlight.o +obj-$(CONFIG_PANEL_S6E3HA3_DYNAMIC) += s6e3ha3_s6e3ha2_wqhd_lcd_ctrl.o dsim_backlight_dynamic.o +obj-$(CONFIG_PANEL_S6E3HF3_DYNAMIC) += s6e3ha3_s6e3ha2_wqhd_lcd_ctrl.o dsim_backlight_dynamic.o \ No newline at end of file diff --git a/drivers/video/exynos/decon/panels/aid_dimming.h b/drivers/video/exynos/decon/panels/aid_dimming.h index 9e05c5b69a83..0894c161fecc 100644 --- a/drivers/video/exynos/decon/panels/aid_dimming.h +++ b/drivers/video/exynos/decon/panels/aid_dimming.h @@ -15,6 +15,10 @@ #if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) #include "s6e3ha2_wqhd_dimming.h" +#elif defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) +#include "s6e3ha3_wqhd_dimming.h" +#elif defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) +#include "s6e3ha3_wqhd_dimming.h" #elif defined(CONFIG_PANEL_S6E3HF2_DYNAMIC) #include "s6e3hf2_wqhd_dimming.h" #else @@ -51,11 +55,11 @@ struct SmtDimInfo { unsigned int br; unsigned int refBr; const unsigned int *cGma; - const signed char *rTbl; - const signed char *cTbl; - const unsigned char *aid; - const unsigned char *elvCaps; - const unsigned char *elv; + signed char *rTbl; + signed char *cTbl; + unsigned char *aid; + unsigned char *elvCaps; + unsigned char *elv; unsigned char gamma[OLED_CMD_GAMMA_CNT]; unsigned int way; }; diff --git a/drivers/video/exynos/decon/panels/dsim_backlight.c b/drivers/video/exynos/decon/panels/dsim_backlight.c index b86ab193224f..7b043c7f17e1 100644 --- a/drivers/video/exynos/decon/panels/dsim_backlight.c +++ b/drivers/video/exynos/decon/panels/dsim_backlight.c @@ -21,6 +21,10 @@ #include "aid_dimming.h" #endif +#ifndef USE_PANEL_PARAMETER_MAX_SIZE +#define ELVSS_LEN_MAX ELVSS_LEN +#define TSET_LEN_MAX TSET_LEN +#endif #ifdef CONFIG_PANEL_AID_DIMMING @@ -119,11 +123,17 @@ static char dsim_panel_get_elvssoffset(struct dsim_device *dsim) char retVal = 0x00; unsigned char panelline; struct panel_private* panel = &(dsim->priv); - + bool bIsHbm = (LEVEL_IS_HBM(panel->auto_brightness) && (panel->bd->props.brightness == panel->bd->props.max_brightness)); + nit = panel->br_tbl[panel->bd->props.brightness]; - if (panel->interpolation) { - retVal = -panel->hbm_elvss_comp; + if((!bIsHbm) && (panel->interpolation)) { + if(panel->weakness_hbm_comp == HBM_COLORBLIND_ON) + retVal = -panel->hbm_elvss_comp; + else if(panel->weakness_hbm_comp == HBM_GALLERY_ON) + retVal = -HBM_INTER_22TH_OFFSET[panel->br_index - 65]; + else + pr_info("%s invaid weakness_hbm_comp:%d\n", __func__, panel->weakness_hbm_comp); goto exit_get_elvss; } @@ -139,15 +149,15 @@ static char dsim_panel_get_elvssoffset(struct dsim_device *dsim) retVal = panel->a3_elvss_temp_0[nit - 2]; else retVal = 0x00; - + goto exit_get_elvss; } - + #endif if(UNDER_MINUS_20(panel->temperature)) { switch(nit) { -#if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) // flat +#if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) // flat case 2: retVal = 0x00; break; @@ -224,8 +234,11 @@ static void dsim_panel_aid_ctrl(struct dsim_device *dsim) static void dsim_panel_set_elvss(struct dsim_device *dsim) { u8 *elvss = NULL; - unsigned char SEQ_ELVSS[ELVSS_LEN] = {ELVSS_REG, }; + unsigned char SEQ_ELVSS[ELVSS_LEN_MAX] = {0, }; + struct panel_private *panel = &dsim->priv; + bool bIsHbm = (LEVEL_IS_HBM(panel->auto_brightness) && (panel->bd->props.brightness == panel->bd->props.max_brightness)); + SEQ_ELVSS[0] = ELVSS_REG; elvss = get_elvss_from_index(dsim, dsim->priv.br_index, dsim->priv.caps_enable); if (elvss == NULL) { dsim_err("%s : failed to get elvss value\n", __func__); @@ -235,7 +248,9 @@ static void dsim_panel_set_elvss(struct dsim_device *dsim) memcpy(SEQ_ELVSS, elvss, ELVSS_CMD_CNT); SEQ_ELVSS[ELVSS_LEN - 1] += dsim_panel_get_elvssoffset(dsim); - + if(bIsHbm || + ((panel->interpolation) && (panel->weakness_hbm_comp == HBM_COLORBLIND_ON))) + SEQ_ELVSS[2] = 0x0A; if (dsim_write_hl_data(dsim, SEQ_ELVSS, ELVSS_LEN) < 0) dsim_err("%s : failed to write elvss \n", __func__); } @@ -281,8 +296,9 @@ static int dsim_panel_set_tset(struct dsim_device *dsim, int force) { int ret = 0; int tset = 0; - unsigned char SEQ_TSET[TSET_LEN] = {TSET_REG, }; + unsigned char SEQ_TSET[TSET_LEN_MAX] = {0, }; + SEQ_TSET[0] = TSET_REG; tset = (dsim->priv.temperature < 0) ? BIT(7) | abs(dsim->priv.temperature) : dsim->priv.temperature; if(force || dsim->priv.tset[TSET_LEN - 2] != tset) { @@ -455,6 +471,7 @@ int dsim_panel_set_brightness(struct dsim_device *dsim, int force) int acutal_br = 0; int real_br = 0; int prev_index = panel->br_index; + bool bIsHbm = (LEVEL_IS_HBM(panel->auto_brightness) && (p_br == panel->bd->props.max_brightness)); #ifdef CONFIG_LCD_HMT if(panel->hmt_on == HMT_ON) { pr_info("%s hmt is enabled, plz set hmt brightness \n", __func__); @@ -467,16 +484,18 @@ int dsim_panel_set_brightness(struct dsim_device *dsim, int force) dsim_info("%s : this panel does not support dimming\n", __func__); return ret; } - if (panel->weakness_hbm_comp) + if (panel->weakness_hbm_comp == 1) acutal_br = panel->hbm_inter_br_tbl[p_br]; + else if(panel->weakness_hbm_comp == 2) + acutal_br = panel->gallery_br_tbl[p_br]; else acutal_br = panel->br_tbl[p_br]; panel->br_index = get_acutal_br_index(dsim, acutal_br); real_br = get_actual_br_value(dsim, panel->br_index); - panel->acl_enable = ACL_IS_ON(real_br); panel->caps_enable = CAPS_IS_ON(real_br); + panel->acl_enable = ACL_IS_ON(real_br); - if (LEVEL_IS_HBM(panel->auto_brightness) && (p_br == panel->bd->props.max_brightness)) { + if(bIsHbm) { panel->br_index = panel->hbm_index; panel->acl_enable = 1; // hbm is acl on panel->caps_enable = 1; // hbm is caps on @@ -484,12 +503,16 @@ int dsim_panel_set_brightness(struct dsim_device *dsim, int force) if(panel->siop_enable) // check auto acl panel->acl_enable = 1; - if (acutal_br > MAX_BRIGHTNESS) { + if (real_br > MAX_BRIGHTNESS) { panel->interpolation = 1; - panel->acl_enable = 0; } else { panel->interpolation = 0; } + if (panel->weakness_hbm_comp) { + panel->acl_enable = 1; + if((!bIsHbm) && (p_br == 255)) + panel->acl_enable = 0; + } if (panel->state != PANEL_STATE_RESUMED) { dsim_info("%s : panel is not active state..\n", __func__); goto set_br_exit; @@ -606,8 +629,9 @@ static void dsim_panel_aid_ctrl_for_hmt(struct dsim_device *dsim) static void dsim_panel_set_elvss_for_hmt(struct dsim_device *dsim) { u8 *elvss = NULL; - unsigned char SEQ_ELVSS[ELVSS_LEN] = {ELVSS_REG, }; + unsigned char SEQ_ELVSS[ELVSS_LEN_MAX] = {ELVSS_REG, }; + SEQ_ELVSS[0] = ELVSS_REG; elvss = get_elvss_from_index_for_hmt(dsim, dsim->priv.hmt_br_index, dsim->priv.acl_enable); if (elvss == NULL) { dsim_err("%s : failed to get elvss value\n", __func__); diff --git a/drivers/video/exynos/decon/panels/dsim_backlight_dynamic.c b/drivers/video/exynos/decon/panels/dsim_backlight_dynamic.c new file mode 100644 index 000000000000..26e439df45df --- /dev/null +++ b/drivers/video/exynos/decon/panels/dsim_backlight_dynamic.c @@ -0,0 +1,745 @@ +/* linux/drivers/video/exynos_decon/panel/dsim_backlight.c + * + * Header file for Samsung MIPI-DSI Backlight driver. + * + * Copyright (c) 2013 Samsung Electronics + * Minwoo Kim + * + * 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. +*/ + + +#include + +#include "../dsim.h" +#include "dsim_backlight.h" +#include "panel_info.h" + +#ifdef CONFIG_PANEL_AID_DIMMING +#include "aid_dimming.h" +#endif + +struct aid_dimming_dynamic_var aid_dimming_dynamic; +unsigned dynamic_lcd_type; + +#ifdef CONFIG_PANEL_AID_DIMMING + +static unsigned int get_actual_br_value(struct dsim_device *dsim, int index) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_br_err; + } + + if (index > MAX_BR_INFO) + index = MAX_BR_INFO; + + return dimming_info[index].br; + +get_br_err: + return 0; +} +static unsigned char *get_gamma_from_index(struct dsim_device *dsim, int index) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_gamma_err; + } + + if (index > MAX_BR_INFO) + index = MAX_BR_INFO; + + return (unsigned char *)dimming_info[index].gamma; + +get_gamma_err: + return NULL; +} + +static unsigned char *get_aid_from_index(struct dsim_device *dsim, int index) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_aid_err; + } + + if (index > MAX_BR_INFO) + index = MAX_BR_INFO; + + return (u8 *)dimming_info[index].aid; + +get_aid_err: + return NULL; +} + +static unsigned char *get_elvss_from_index(struct dsim_device *dsim, int index, int caps) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_elvess_err; + } + + if(caps) + return (unsigned char *)dimming_info[index].elvCaps; + else + return (unsigned char *)dimming_info[index].elv; + +get_elvess_err: + return NULL; +} + + +static void dsim_panel_gamma_ctrl(struct dsim_device *dsim) +{ + u8 *gamma = NULL; + gamma = get_gamma_from_index(dsim, dsim->priv.br_index); + if (gamma == NULL) { + dsim_err("%s :faied to get gamma\n", __func__); + return; + } + + if (dsim_write_hl_data(dsim, gamma, GAMMA_CMD_CNT) < 0) + dsim_err("%s : failed to write gamma \n", __func__); +} + +static char dsim_panel_get_elvssoffset(struct dsim_device *dsim) +{ + int nit = 0; + char retVal = 0x00; + struct panel_private* panel = &(dsim->priv); + + nit = panel->br_tbl[panel->bd->props.brightness]; + if(nit > 6) + nit = 6; + if (panel->interpolation) { + retVal = -panel->hbm_elvss_comp; + goto exit_get_elvss; + } + + if(UNDER_MINUS_20(panel->temperature)) { + retVal = aid_dimming_dynamic.elvss_minus_offset[2][nit - 2]; + } else if(UNDER_0(panel->temperature)) { + retVal = aid_dimming_dynamic.elvss_minus_offset[1][nit - 2]; + } else { + retVal = aid_dimming_dynamic.elvss_minus_offset[0][nit - 2]; + } + +exit_get_elvss: + pr_info("%s %d\n", __func__, retVal); + return retVal; +} + + + +static void dsim_panel_aid_ctrl(struct dsim_device *dsim) + { + u8 *aid = NULL; + unsigned char SEQ_AID[AID_CMD_CNT_MAX] = {0, }; + + aid = get_aid_from_index(dsim, dsim->priv.br_index); + if (aid == NULL) { + dsim_err("%s : failed to get elvss value\n", __func__); + return; + } + SEQ_AID[0] = aid[0]; + memcpy(&SEQ_AID[1], dsim->priv.aid, aid_dimming_dynamic.aid_cmd_cnt - 1); // HA2/HF3 not read. but no danger + memcpy(&SEQ_AID[aid_dimming_dynamic.aid_reg_offset], aid+1, aid_dimming_dynamic.aid_cmd_cnt -aid_dimming_dynamic.aid_reg_offset +1 ); + + if (dsim_write_hl_data(dsim, SEQ_AID, aid_dimming_dynamic.aid_cmd_cnt) < 0) + dsim_err("%s : failed to write aid \n", __func__); + +} + +static int dsim_panel_set_tset(struct dsim_device *dsim, int force) +{ + int ret = 0; + int tset = 0; + unsigned char SEQ_TSET[TSET_LEN_MAX] = {0, }; + + SEQ_TSET[0] = aid_dimming_dynamic.tset_reg; + tset = (dsim->priv.temperature < 0) ? BIT(7) | abs(dsim->priv.temperature) : dsim->priv.temperature; + + if(force || dsim->priv.tset[aid_dimming_dynamic.tset_len - 2] != tset) { + memcpy(&SEQ_TSET[1], dsim->priv.tset, aid_dimming_dynamic.tset_len - 1); + dsim->priv.tset[aid_dimming_dynamic.tset_len - 2] = SEQ_TSET[aid_dimming_dynamic.tset_len - 1] = tset; + if ((ret = dsim_write_hl_data(dsim, SEQ_TSET, ARRAY_SIZE(SEQ_TSET))) < 0) { + dsim_err("fail to write tset command.\n"); + ret = -EPERM; + } + dsim_info("%s temperature: %d, tset: %d\n", + __func__, dsim->priv.temperature, SEQ_TSET[aid_dimming_dynamic.tset_len - 1]); + } + return ret; +} + +static void dsim_panel_set_elvss(struct dsim_device *dsim) +{ + u8 *elvss = NULL; + unsigned char SEQ_ELVSS[ELVSS_LEN_MAX] = {0, }; + + SEQ_ELVSS[0] = aid_dimming_dynamic.elvss_reg; + elvss = get_elvss_from_index(dsim, dsim->priv.br_index, dsim->priv.caps_enable); + if (elvss == NULL) { + dsim_err("%s : failed to get elvss value\n", __func__); + return; + } + memcpy(&SEQ_ELVSS[1], dsim->priv.elvss_set, aid_dimming_dynamic.elvss_len - 1); + memcpy(SEQ_ELVSS, elvss, aid_dimming_dynamic.elvss_cmd_cnt); + + SEQ_ELVSS[aid_dimming_dynamic.elvss_len - 1] += dsim_panel_get_elvssoffset(dsim); + if(dynamic_lcd_type == LCD_TYPE_S6E3HA2_WQHD) { + dsim_info("%s elvss ha2\n", __func__); + if (dsim_write_hl_data(dsim, SEQ_ELVSS, aid_dimming_dynamic.elvss_len) < 0) + dsim_err("%s : failed to write elvss \n", __func__); + } else { + dsim_info("%s elvss ha3/hf3\n", __func__); + memcpy(dsim->priv.tset, &SEQ_ELVSS[1], aid_dimming_dynamic.elvss_len - 1); + dsim_panel_set_tset(dsim, 1); + } +} + + +static int dsim_panel_set_acl(struct dsim_device *dsim, int force) +{ + int ret = 0, level = ACL_STATUS_8P; + struct panel_private *panel = &dsim->priv; + + if (panel == NULL) { + dsim_err("%s : panel is NULL\n", __func__); + goto exit; + } + + if (dsim->priv.siop_enable || LEVEL_IS_HBM(dsim->priv.auto_brightness)) // auto acl or hbm is acl on + goto acl_update; + + if (!dsim->priv.acl_enable) + level = ACL_STATUS_0P; + +acl_update: + if(force || dsim->priv.current_acl != panel->acl_cutoff_tbl[level][1]) { + if((ret = dsim_write_hl_data(dsim, panel->acl_opr_tbl[level], 2)) < 0) { + dsim_err("fail to write acl opr command.\n"); + goto exit; + } + if((ret = dsim_write_hl_data(dsim, panel->acl_cutoff_tbl[level], 2)) < 0) { + dsim_err("fail to write acl command.\n"); + goto exit; + } + dsim->priv.current_acl = panel->acl_cutoff_tbl[level][1]; + dsim_info("acl: %d, auto_brightness: %d\n", dsim->priv.current_acl, dsim->priv.auto_brightness); + } +exit: + if (!ret) + ret = -EPERM; + return ret; +} + +static int dsim_panel_set_vint(struct dsim_device *dsim, int force) +{ + int ret = 0; + int nit = 0; + int i, level = 0; + int arraySize = ARRAY_SIZE(VINT_DIM_TABLE); + struct panel_private* panel = &(dsim->priv); + unsigned char SEQ_VINT[VINT_LEN] = {VINT_REG, 0x8B, 0x21}; + unsigned char *vint_tbl = aid_dimming_dynamic.vint_dim_offset; + + level = arraySize - 1; + + SEQ_VINT[1] = aid_dimming_dynamic.vint_reg2; + + if(UNDER_MINUS_20(panel->temperature)) + goto set_vint; +#ifdef CONFIG_LCD_HMT + if(panel->hmt_on == HMT_ON) + goto set_vint; +#endif + nit = get_actual_br_value(dsim, panel->br_index); + + for (i = 0; i < arraySize; i++) { + if (nit <= VINT_DIM_TABLE[i]) { + level = i; + goto set_vint; + } + } +set_vint: + if(force || panel->current_vint != vint_tbl[level]) { + SEQ_VINT[VINT_LEN - 1] = vint_tbl[level]; + if ((ret = dsim_write_hl_data(dsim, SEQ_VINT, ARRAY_SIZE(SEQ_VINT))) < 0) { + dsim_err("fail to write vint command.\n"); + ret = -EPERM; + } + panel->current_vint = vint_tbl[level]; + dsim_info("vint: %02x\n", panel->current_vint); + } + return ret; +} + +static int dsim_panel_set_hbm(struct dsim_device *dsim, int force) +{ + int ret = 0, level = LEVEL_IS_HBM(dsim->priv.auto_brightness); + struct panel_private *panel = &dsim->priv; + + if (panel == NULL) { + dsim_err("%s : panel is NULL\n", __func__); + goto exit; + } + + if(force || dsim->priv.current_hbm != panel->hbm_tbl[level][1]) { + dsim->priv.current_hbm = panel->hbm_tbl[level][1]; + if((ret = dsim_write_hl_data(dsim, panel->hbm_tbl[level], ARRAY_SIZE(SEQ_HBM_OFF))) < 0) { + dsim_err("fail to write hbm command.\n"); + ret = -EPERM; + } + dsim_info("hbm: %d, auto_brightness: %d\n", dsim->priv.current_hbm, dsim->priv.auto_brightness); + } +exit: + return ret; +} + +static int low_level_set_brightness(struct dsim_device *dsim ,int force) +{ + + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_ON_F0, ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_ON_FC, ARRAY_SIZE(SEQ_TEST_KEY_ON_FC)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + + dsim_panel_gamma_ctrl(dsim); + + dsim_panel_aid_ctrl(dsim); + + dsim_panel_set_elvss(dsim); + + dsim_panel_set_vint(dsim, force); + + if (dsim_write_hl_data(dsim, SEQ_GAMMA_UPDATE, ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0) + dsim_err("%s : failed to write gamma \n", __func__); + if (dsim_write_hl_data(dsim, SEQ_GAMMA_UPDATE_L, ARRAY_SIZE(SEQ_GAMMA_UPDATE_L)) < 0) + dsim_err("%s : failed to write gamma \n", __func__); + + dsim_panel_set_acl(dsim, force); + if(dynamic_lcd_type == LCD_TYPE_S6E3HA2_WQHD) + dsim_panel_set_tset(dsim, force); + +#ifdef CONFIG_LCD_ALPM + if (!(dsim->priv.current_alpm && dsim->priv.alpm)) +#endif + dsim_panel_set_hbm(dsim, force); + + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_OFF_FC, ARRAY_SIZE(SEQ_TEST_KEY_OFF_FC)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_OFF_F0, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0) + dsim_err("%s : fail to write F0 on command\n", __func__); + + return 0; +} + +static int get_acutal_br_index(struct dsim_device *dsim, int br) +{ + int i; + int min; + int gap; + int index = 0; + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = panel->dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming_info is NULL\n", __func__); + return 0; + } + + min = MAX_BRIGHTNESS; + + for (i = 0; i < MAX_BR_INFO; i++) { + if (br > dimming_info[i].br) + gap = br - dimming_info[i].br; + else + gap = dimming_info[i].br - br; + + if (gap == 0) { + index = i; + break; + } + + if (gap < min) { + min = gap; + index = i; + } + } + return index; +} + +#endif + +int dsim_panel_set_brightness(struct dsim_device *dsim, int force) +{ + int ret = 0; +#ifndef CONFIG_PANEL_AID_DIMMING + dsim_info("%s:this panel does not support dimming \n", __func__); +#else + struct dim_data *dimming; + struct panel_private *panel = &dsim->priv; + int p_br = panel->bd->props.brightness; + int acutal_br = 0; + int real_br = 0; + int prev_index = panel->br_index; +#ifdef CONFIG_LCD_HMT + if(panel->hmt_on == HMT_ON) { + pr_info("%s hmt is enabled, plz set hmt brightness \n", __func__); + goto set_br_exit; + } +#endif + + dimming = (struct dim_data *)panel->dim_data; + if ((dimming == NULL) || (panel->br_tbl == NULL)) { + dsim_info("%s : this panel does not support dimming\n", __func__); + return ret; + } + if (panel->weakness_hbm_comp) + acutal_br = panel->hbm_inter_br_tbl[p_br]; + else + acutal_br = panel->br_tbl[p_br]; + panel->br_index = get_acutal_br_index(dsim, acutal_br); + real_br = get_actual_br_value(dsim, panel->br_index); + panel->acl_enable = ACL_IS_ON(real_br); + panel->caps_enable = CAPS_IS_ON(real_br); + + if (LEVEL_IS_HBM(panel->auto_brightness) && (p_br == panel->bd->props.max_brightness)) { + panel->br_index = panel->hbm_index; + panel->acl_enable = 1; // hbm is acl on + panel->caps_enable = 1; // hbm is caps on + } + if(panel->siop_enable) // check auto acl + panel->acl_enable = 1; + + if (acutal_br > MAX_BRIGHTNESS) { + panel->interpolation = 1; + panel->acl_enable = 0; + } else { + panel->interpolation = 0; + } + if (panel->state != PANEL_STATE_RESUMED) { + dsim_info("%s : panel is not active state..\n", __func__); + goto set_br_exit; + } + + dsim_info("%s : platform : %d, : mapping : %d, real : %d, index : %d, interpolation : %d\n", + __func__, p_br, acutal_br, real_br, panel->br_index, panel->interpolation); + + if (!force && panel->br_index == prev_index) + goto set_br_exit; + + if ((acutal_br == 0) || (real_br == 0)) + goto set_br_exit; + + mutex_lock(&panel->lock); + + ret = low_level_set_brightness(dsim, force); + if (ret) { + dsim_err("%s failed to set brightness : %d\n", __func__, acutal_br); + } + mutex_unlock(&panel->lock); + +set_br_exit: +#endif + return ret; +} + +#ifdef CONFIG_LCD_HMT +#ifdef CONFIG_PANEL_AID_DIMMING +static unsigned char *get_gamma_from_index_for_hmt(struct dsim_device *dsim, int index) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->hmt_dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_gamma_err; + } + + if (index > HMT_MAX_BR_INFO - 1) + index = HMT_MAX_BR_INFO - 1; + + return (unsigned char *)dimming_info[index].gamma; + +get_gamma_err: + return NULL; +} + +static unsigned char *get_aid_from_index_for_hmt(struct dsim_device *dsim, int index) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->hmt_dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_aid_err; + } + + if (index > HMT_MAX_BR_INFO - 1) + index = HMT_MAX_BR_INFO - 1; + + return (u8 *)dimming_info[index].aid; + +get_aid_err: + return NULL; +} + +static unsigned char *get_elvss_from_index_for_hmt(struct dsim_device *dsim, int index, int caps) +{ + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = (struct SmtDimInfo *)panel->hmt_dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming info is NULL\n", __func__); + goto get_elvess_err; + } + + if(caps) + return (unsigned char *)dimming_info[index].elvCaps; + else + return (unsigned char *)dimming_info[index].elv; + +get_elvess_err: + return NULL; +} + + +static void dsim_panel_gamma_ctrl_for_hmt(struct dsim_device *dsim) +{ + u8 *gamma = NULL; + gamma = get_gamma_from_index_for_hmt(dsim, dsim->priv.hmt_br_index); + if (gamma == NULL) { + dsim_err("%s :faied to get gamma\n", __func__); + return; + } + + if (dsim_write_hl_data(dsim, gamma, GAMMA_CMD_CNT) < 0) + dsim_err("%s : failed to write hmt gamma \n", __func__); +} + + +static void dsim_panel_aid_ctrl_for_hmt(struct dsim_device *dsim) +{ + u8 *aid = NULL; + aid = get_aid_from_index_for_hmt(dsim, dsim->priv.hmt_br_index); + if (aid == NULL) { + dsim_err("%s : faield to get aid value\n", __func__); + return; + } + if (dsim_write_hl_data(dsim, aid, aid_dimming_dynamic.aid_cmd_cnt + 1) < 0) + dsim_err("%s : failed to write hmt aid \n", __func__); +} + +static void dsim_panel_set_elvss_for_hmt(struct dsim_device *dsim) +{ + u8 *elvss = NULL; + unsigned char SEQ_ELVSS[ELVSS_LEN_MAX] = {aid_dimming_dynamic.elvss_reg, }; + + SEQ_ELVSS[0] = aid_dimming_dynamic.elvss_reg; + elvss = get_elvss_from_index_for_hmt(dsim, dsim->priv.hmt_br_index, dsim->priv.acl_enable); + if (elvss == NULL) { + dsim_err("%s : failed to get elvss value\n", __func__); + return; + } + memcpy(&SEQ_ELVSS[1], dsim->priv.elvss_set, aid_dimming_dynamic.elvss_len - 1); + memcpy(SEQ_ELVSS, elvss, aid_dimming_dynamic.elvss_cmd_cnt); + + if(UNDER_MINUS_20(dsim->priv.temperature)) // tset + SEQ_ELVSS[aid_dimming_dynamic.elvss_len - 1] -= aid_dimming_dynamic.tset_minus_offset; + + if (dsim_write_hl_data(dsim, SEQ_ELVSS, aid_dimming_dynamic.elvss_len) < 0) + dsim_err("%s : failed to write elvss \n", __func__); +} + +static int low_level_set_brightness_for_hmt(struct dsim_device *dsim ,int force) +{ + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_ON_F0, ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_ON_FC, ARRAY_SIZE(SEQ_TEST_KEY_ON_FC)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + + dsim_panel_gamma_ctrl_for_hmt(dsim); + + dsim_panel_aid_ctrl_for_hmt(dsim); + + dsim_panel_set_elvss_for_hmt(dsim); + + dsim_panel_set_vint(dsim, force); + + if (dsim_write_hl_data(dsim, SEQ_GAMMA_UPDATE, ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0) + dsim_err("%s : failed to write gamma \n", __func__); + if (dsim_write_hl_data(dsim, SEQ_GAMMA_UPDATE_L, ARRAY_SIZE(SEQ_GAMMA_UPDATE_L)) < 0) + dsim_err("%s : failed to write gamma \n", __func__); + + dsim_panel_set_acl(dsim, force); + + dsim_panel_set_tset(dsim, force); + + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_OFF_FC, ARRAY_SIZE(SEQ_TEST_KEY_OFF_FC)) < 0) + dsim_err("%s : fail to write F0 on command.\n", __func__); + if (dsim_write_hl_data(dsim, SEQ_TEST_KEY_OFF_F0, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0) + dsim_err("%s : fail to write F0 on command\n", __func__); + + return 0; +} + +static int get_acutal_br_index_for_hmt(struct dsim_device *dsim, int br) +{ + int i; + int min; + int gap; + int index = 0; + struct panel_private *panel = &dsim->priv; + struct SmtDimInfo *dimming_info = panel->hmt_dim_info; + + if (dimming_info == NULL) { + dsim_err("%s : dimming_info is NULL\n", __func__); + return 0; + } + + min = HMT_MAX_BRIGHTNESS; + + for (i = 0; i < MAX_BR_INFO; i++) { + if (br > dimming_info[i].br) + gap = br - dimming_info[i].br; + else + gap = dimming_info[i].br - br; + + if (gap == 0) { + index = i; + break; + } + + if (gap < min) { + min = gap; + index = i; + } + } + return index; +} + +#endif +int dsim_panel_set_brightness_for_hmt(struct dsim_device *dsim, int force) +{ + int ret = 0; +#ifndef CONFIG_PANEL_AID_DIMMING + dsim_info("%s:this panel does not support dimming \n", __func__); +#else + struct dim_data *dimming; + struct panel_private *panel = &dsim->priv; + int p_br = panel->hmt_brightness; + int acutal_br = 0; + int prev_index = panel->hmt_br_index; + + dimming = (struct dim_data *)panel->hmt_dim_data; + if ((dimming == NULL) || (panel->hmt_br_tbl == NULL)) { + dsim_info("%s : this panel does not support dimming\n", __func__); + return ret; + } + + acutal_br = panel->hmt_br_tbl[p_br]; + panel->acl_enable = 0; + panel->hmt_br_index = get_acutal_br_index_for_hmt(dsim, acutal_br); + if(panel->siop_enable) // check auto acl + panel->acl_enable = 1; + if (panel->state != PANEL_STATE_RESUMED) { + dsim_info("%s : panel is not active state..\n", __func__); + goto set_br_exit; + } + if (!force && panel->hmt_br_index == prev_index) + goto set_br_exit; + + dsim_info("%s : req : %d : nit : %d index : %d\n", + __func__, p_br, acutal_br, panel->hmt_br_index); + + if (acutal_br == 0) + goto set_br_exit; + + mutex_lock(&panel->lock); + + ret = low_level_set_brightness_for_hmt(dsim, force); + if (ret) { + dsim_err("%s failed to hmt set brightness : %d\n", __func__, acutal_br); + } + mutex_unlock(&panel->lock); + +set_br_exit: +#endif + return ret; +} +#endif + +static int panel_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + + +static int panel_set_brightness(struct backlight_device *bd) +{ + int ret = 0; + int brightness = bd->props.brightness; + struct panel_private *priv = bl_get_data(bd); + struct dsim_device *dsim; + + dsim = container_of(priv, struct dsim_device, priv); + + if (brightness < UI_MIN_BRIGHTNESS || brightness > UI_MAX_BRIGHTNESS) { + printk(KERN_ALERT "Brightness should be in the range of 0 ~ 255\n"); + ret = -EINVAL; + goto exit_set; + } + + ret = dsim_panel_set_brightness(dsim, 0); + if (ret) { + dsim_err("%s : fail to set brightness\n", __func__); + goto exit_set; + } +exit_set: + return ret; + +} + +static const struct backlight_ops panel_backlight_ops = { + .get_brightness = panel_get_brightness, + .update_status = panel_set_brightness, +}; + + +int dsim_backlight_probe(struct dsim_device *dsim) +{ + int ret = 0; + struct panel_private *panel = &dsim->priv; + + panel->bd = backlight_device_register("panel", dsim->dev, &dsim->priv, + &panel_backlight_ops, NULL); + if (IS_ERR(panel->bd)) { + dsim_err("%s:failed register backlight\n", __func__); + ret = PTR_ERR(panel->bd); + } + + panel->bd->props.max_brightness = UI_MAX_BRIGHTNESS; + panel->bd->props.brightness = UI_DEFAULT_BRIGHTNESS; + +#ifdef CONFIG_LCD_HMT + panel->hmt_on = HMT_OFF; + panel->hmt_brightness = DEFAULT_HMT_BRIGHTNESS; + panel->hmt_br_index = 0; +#endif + return ret; +} diff --git a/drivers/video/exynos/decon/panels/dsim_panel.c b/drivers/video/exynos/decon/panels/dsim_panel.c index 1ada7738ffdb..2100c677079d 100644 --- a/drivers/video/exynos/decon/panels/dsim_panel.c +++ b/drivers/video/exynos/decon/panels/dsim_panel.c @@ -123,6 +123,7 @@ static int dsim_panel_probe(struct dsim_device *dsim) panel->current_vint = 0; panel->weakness_hbm_comp = 0; + dsim->glide_display_size = 0; mutex_init(&panel->lock); #ifdef CONFIG_EXYNOS_DECON_LCD_MCD diff --git a/drivers/video/exynos/decon/panels/lcd_sysfs.c b/drivers/video/exynos/decon/panels/lcd_sysfs.c index 5ac10b380cc5..a844c21c5912 100644 --- a/drivers/video/exynos/decon/panels/lcd_sysfs.c +++ b/drivers/video/exynos/decon/panels/lcd_sysfs.c @@ -127,7 +127,27 @@ static struct lcd_seq_info SEQ_HMT_OFF_SET[] = { {(u8 *)SEQ_HMT_OFF1, ARRAY_SIZE(SEQ_HMT_OFF1), 0}, {(u8 *)SEQ_HMT_OFF2, ARRAY_SIZE(SEQ_HMT_OFF2), 0}, }; +#elif defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) +static struct lcd_seq_info SEQ_HMT_AID_FORWARD_SET[] = { + {(u8 *)SEQ_HMT_AID_FORWARD1, ARRAY_SIZE(SEQ_HMT_AID_FORWARD1), 0}, + {(u8 *)SEQ_HMT_AID_FORWARD2, ARRAY_SIZE(SEQ_HMT_AID_FORWARD2), 0}, +}; +static struct lcd_seq_info SEQ_HMT_REVERSE_SET[] = { + {(u8 *)SEQ_HMT_AID_REVERSE1, ARRAY_SIZE(SEQ_HMT_AID_REVERSE1), 0}, + {(u8 *)SEQ_HMT_AID_REVERSE2, ARRAY_SIZE(SEQ_HMT_AID_REVERSE2), 0}, +}; + +static struct lcd_seq_info SEQ_HMT_ON_SET[] = { + {(u8 *)SEQ_HMT_ON1, ARRAY_SIZE(SEQ_HMT_ON1), 0}, + {(u8 *)SEQ_HMT_ON2, ARRAY_SIZE(SEQ_HMT_ON2), 0}, + {(u8 *)SEQ_HMT_ON3, ARRAY_SIZE(SEQ_HMT_ON3), 0}, +}; + +static struct lcd_seq_info SEQ_HMT_OFF_SET[] = { + {(u8 *)SEQ_HMT_OFF1, ARRAY_SIZE(SEQ_HMT_OFF1), 0}, + {(u8 *)SEQ_HMT_OFF2, ARRAY_SIZE(SEQ_HMT_OFF2), 0}, +}; #endif @@ -280,7 +300,6 @@ static DEVICE_ATTR(hmt_on, 0664, hmt_on_show, hmt_on_store); #endif #ifdef CONFIG_LCD_ALPM - int alpm_set_mode(struct dsim_device *dsim, int enable) { struct panel_private *priv = &(dsim->priv); @@ -690,6 +709,27 @@ static ssize_t manufacture_code_show(struct device *dev, return strlen(buf); } +#ifdef CONFIG_LCD_HBM_INTERPOLATION +static int find_hbm_table(struct dsim_device *dsim, int nit, int mode) +{ + int retVal = 0; + int i; + int current_gap; + int minVal = 20000; + for(i = 0; i < 256; i++) { + if(mode == 1) // setting + current_gap = nit - dsim->priv.hbm_inter_br_tbl[i]; + else // gallery + current_gap = nit - dsim->priv.gallery_br_tbl[i]; + if(current_gap < 0) + current_gap *= -1; + if(minVal > current_gap) { + minVal = current_gap; + retVal = i; + } + } + return retVal; +} static ssize_t weakness_hbm_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -704,7 +744,10 @@ static ssize_t weakness_hbm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int rc; - int value; + int value, i; + int hbm_nit, origin_nit, p_br, gap_nit; + int index_array[6]; + int nFlagForInter = 0; struct dsim_device *dsim; struct panel_private *priv = dev_get_drvdata(dev); @@ -714,14 +757,50 @@ static ssize_t weakness_hbm_store(struct device *dev, if (rc < 0) return rc; else { - if (priv->weakness_hbm_comp != value) { - dev_info(dev, "%s: %d, %d\n", __func__, priv->weakness_hbm_comp, value); - priv->weakness_hbm_comp = value; + if (priv->weakness_hbm_comp != value){ + if((priv->weakness_hbm_comp == 1) && (value == 2)) { + pr_info("%s don't support color blind -> gallery\n", __func__); + return size; + } + p_br = priv->bd->props.brightness; + if((priv->weakness_hbm_comp == 1) || (value == 1)) { + hbm_nit = priv->hbm_inter_br_tbl[p_br]; + nFlagForInter = 1; + } + else if((priv->weakness_hbm_comp == 2) || (value == 2)) { + hbm_nit = priv->gallery_br_tbl[p_br]; + nFlagForInter = 2; + } + origin_nit = priv->br_tbl[p_br]; + gap_nit = (hbm_nit - origin_nit) / 5; + index_array[5] = priv->bd->props.brightness; + for(i = 0; i < 5; i++) { + index_array[i] = find_hbm_table(dsim, origin_nit, nFlagForInter); + origin_nit += gap_nit; + } + if(value) + priv->weakness_hbm_comp = value; + for(i = 1; i < 5; i++) { + if(value) + priv->bd->props.brightness = index_array[i]; + else + priv->bd->props.brightness = index_array[5 - i]; + dsim_panel_set_brightness(dsim, 0); + msleep(20); + } + if(!value) + priv->weakness_hbm_comp = value; + priv->bd->props.brightness = index_array[5]; dsim_panel_set_brightness(dsim, 0); + + dev_info(dev, "%s: %d, %d\n", __func__, priv->weakness_hbm_comp, value); } } return size; } +static DEVICE_ATTR(weakness_hbm_comp, 0664, weakness_hbm_show, weakness_hbm_store); +#endif + static DEVICE_ATTR(lcd_type, 0444, lcd_type_show, NULL); static DEVICE_ATTR(window_type, 0444, window_type_show, NULL); static DEVICE_ATTR(manufacture_code, 0444, manufacture_code_show, NULL); @@ -732,11 +811,10 @@ static DEVICE_ATTR(temperature, 0664, temperature_show, temperature_store); static DEVICE_ATTR(color_coordinate, 0444, color_coordinate_show, NULL); static DEVICE_ATTR(manufacture_date, 0444, manufacture_date_show, NULL); static DEVICE_ATTR(read_mtp, 0664, read_mtp_show, read_mtp_store); + #ifdef CONFIG_PANEL_AID_DIMMING static DEVICE_ATTR(aid_log, 0444, aid_log_show, NULL); #endif -static DEVICE_ATTR(weakness_hbm_comp, 0664, weakness_hbm_show, weakness_hbm_store); - void lcd_init_sysfs(struct dsim_device *dsim) { @@ -809,9 +887,12 @@ void lcd_init_sysfs(struct dsim_device *dsim) if (ret < 0) dev_err(&dsim->lcd->dev, "failed to add sysfs entries, %d\n", __LINE__); #endif + +#ifdef CONFIG_LCD_HBM_INTERPOLATION ret = device_create_file(&dsim->priv.bd->dev ,&dev_attr_weakness_hbm_comp); if (ret < 0) dev_err(&dsim->lcd->dev, "failed to add sysfs entries, %d\n", __LINE__); +#endif } diff --git a/drivers/video/exynos/decon/panels/mdnie.h b/drivers/video/exynos/decon/panels/mdnie.h index 48ab0221e6f7..887c3169a564 100644 --- a/drivers/video/exynos/decon/panels/mdnie.h +++ b/drivers/video/exynos/decon/panels/mdnie.h @@ -49,9 +49,14 @@ enum ACCESSIBILITY { SCREEN_CURTAIN, GRAYSCALE, GRAYSCALE_NEGATIVE, + COLOR_BLIND_HBM, ACCESSIBILITY_MAX }; +#define MDNIE_COLOR_BLIND_TUNE_CNT 9 +#define MDNIE_COLOR_BLIND_HBM_TUNE_CNT 12 + + enum HBM { HBM_OFF, HBM_ON, diff --git a/drivers/video/exynos/decon/panels/mdnie_lite.c b/drivers/video/exynos/decon/panels/mdnie_lite.c index 8bea5703147d..82ca0018f7e2 100644 --- a/drivers/video/exynos/decon/panels/mdnie_lite.c +++ b/drivers/video/exynos/decon/panels/mdnie_lite.c @@ -33,6 +33,10 @@ #include "mdnie_lite_table_zero.h" #elif defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) #include "mdnie_lite_table_zerof.h" +#elif defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) +#include "mdnie_lite_table_noble.h" +#elif defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) +#include "mdnie_lite_table_zen.h" #endif #if defined(CONFIG_TDMB) #include "mdnie_lite_table_dmb.h" @@ -395,15 +399,16 @@ static ssize_t accessibility_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct mdnie_info *mdnie = dev_get_drvdata(dev); - unsigned int value, s[9], i = 0; + int value; + unsigned int s[12] = {0, }, i = 0; int ret; mdnie_t *wbuf; - ret = sscanf(buf, "%d %x %x %x %x %x %x %x %x %x", + ret = sscanf(buf, "%d %x %x %x %x %x %x %x %x %x %x %x %x", &value, &s[0], &s[1], &s[2], &s[3], - &s[4], &s[5], &s[6], &s[7], &s[8]); + &s[4], &s[5], &s[6], &s[7], &s[8], &s[9], &s[10], &s[11]); - dev_info(dev, "%s: value=%d\n", __func__, value); + dev_info(dev, "%s: value=%d param cnt : %d\n", __func__, value, ret); if (ret < 0) return ret; @@ -414,17 +419,28 @@ static ssize_t accessibility_store(struct device *dev, mutex_lock(&mdnie->lock); mdnie->accessibility = value; if (value == COLOR_BLIND) { - if (ret != 10) { + if (ret != MDNIE_COLOR_BLIND_TUNE_CNT + 1) { mutex_unlock(&mdnie->lock); return -EINVAL; } wbuf = &accessibility_table[COLOR_BLIND].tune[MDNIE_CMD1].sequence[MDNIE_COLOR_BLIND_OFFSET]; - while (i < ARRAY_SIZE(s)) { + while (i < MDNIE_COLOR_BLIND_TUNE_CNT) { + wbuf[i * 2 + 0] = GET_LSB_8BIT(s[i]); + wbuf[i * 2 + 1] = GET_MSB_8BIT(s[i]); + i++; + } + dev_info(dev, "%s: %s\n", __func__, buf); + } else if (value == COLOR_BLIND_HBM) { + if (ret != MDNIE_COLOR_BLIND_HBM_TUNE_CNT + 1) { + mutex_unlock(&mdnie->lock); + return -EINVAL; + } + wbuf = &accessibility_table[COLOR_BLIND_HBM].tune[MDNIE_CMD1].sequence[MDNIE_COLOR_BLIND_OFFSET]; + while (i < MDNIE_COLOR_BLIND_HBM_TUNE_CNT) { wbuf[i * 2 + 0] = GET_LSB_8BIT(s[i]); wbuf[i * 2 + 1] = GET_MSB_8BIT(s[i]); i++; } - dev_info(dev, "%s: %s\n", __func__, buf); } mutex_unlock(&mdnie->lock); diff --git a/drivers/video/exynos/decon/panels/mdnie_lite_table_dmb.h b/drivers/video/exynos/decon/panels/mdnie_lite_table_dmb.h index 40139fbfa573..afa30e00d230 100644 --- a/drivers/video/exynos/decon/panels/mdnie_lite_table_dmb.h +++ b/drivers/video/exynos/decon/panels/mdnie_lite_table_dmb.h @@ -1569,7 +1569,7 @@ static unsigned char AUTO_DMB_1[] = { }; #elif defined(CONFIG_DECON_LCD_S6E3HA2) || defined(CONFIG_DECON_LCD_S6E3HF2)\ - || defined(CONFIG_EXYNOS_DECON_LCD_S6E3HF2_WQHD) || defined(CONFIG_PANEL_S6E3HA2_DYNAMIC)\ + || defined(CONFIG_EXYNOS_DECON_LCD_S6E3HF2_WQHD) || defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) || defined(CONFIG_PANEL_S6E3HA3_DYNAMIC)\ || defined(CONFIG_PANEL_S6E3HF2_DYNAMIC) /* Bypass */ static unsigned char STANDARD_DMB_2[] = { diff --git a/drivers/video/exynos/decon/panels/mdnie_lite_table_noble.h b/drivers/video/exynos/decon/panels/mdnie_lite_table_noble.h new file mode 100644 index 000000000000..8ed31044a9f6 --- /dev/null +++ b/drivers/video/exynos/decon/panels/mdnie_lite_table_noble.h @@ -0,0 +1,9303 @@ +#ifndef __MDNIE_TABLE_H__ +#define __MDNIE_TABLE_H__ + +/* 2015.03.21 */ + +/* SCR Position can be different each panel */ +#define MDNIE_RED_R 133 /* ASCR_WIDE_CR[7:0] */ +#define MDNIE_RED_G 135 /* ASCR_WIDE_CG[7:0] */ +#define MDNIE_RED_B 137 /* ASCR_WIDE_CB[7:0] */ +#define MDNIE_BLUE_R 139 /* ASCR_WIDE_MR[7:0] */ +#define MDNIE_BLUE_G 141 /* ASCR_WIDE_MG[7:0] */ +#define MDNIE_BLUE_B 143 /* ASCR_WIDE_MB[7:0] */ +#define MDNIE_GREEN_R 145 /* ASCR_WIDE_YR[7:0] */ +#define MDNIE_GREEN_G 147 /* ASCR_WIDE_YG[7:0] */ +#define MDNIE_GREEN_B 149 /* ASCR_WIDE_YB[7:0] */ +#define MDNIE_WHITE_R 151 /* ASCR_WIDE_WR[7:0] */ +#define MDNIE_WHITE_G 153 /* ASCR_WIDE_WG[7:0] */ +#define MDNIE_WHITE_B 155 /* ASCR_WIDE_WB[7:0] */ + +#define MDNIE_COLOR_BLIND_OFFSET MDNIE_RED_R + +#define COLOR_OFFSET_F1(x, y) (((y << 10) - (((x << 10) * 353) / 326) + (30 << 10)) >> 10) +#define COLOR_OFFSET_F2(x, y) (((y << 10) - (((x << 10) * 20) / 19) - (14 << 10)) >> 10) +#define COLOR_OFFSET_F3(x, y) (((y << 10) + (((x << 10) * 185) / 42) - (16412 << 10)) >> 10) +#define COLOR_OFFSET_F4(x, y) (((y << 10) + (((x << 10) * 337) / 106) - (12601 << 10)) >> 10) + +/* color coordination order is WR, WG, WB */ +static unsigned char coordinate_data_1[][3] = { + {0xff, 0xff, 0xff}, /* dummy */ + {0xff, 0xf9, 0xfb}, /* Tune_1 */ + {0xff, 0xfa, 0xff}, /* Tune_2 */ + {0xfb, 0xf7, 0xff}, /* Tune_3 */ + {0xff, 0xfb, 0xfb}, /* Tune_4 */ + {0xff, 0xfd, 0xff}, /* Tune_5 */ + {0xfb, 0xfa, 0xff}, /* Tune_6 */ + {0xff, 0xfe, 0xfc}, /* Tune_7 */ + {0xff, 0xff, 0xff}, /* Tune_8 */ + {0xfb, 0xfd, 0xff}, /* Tune_9 */ +}; + +static unsigned char coordinate_data_2[][3] = { + {0xff, 0xff, 0xff}, /* dummy */ + {0xff, 0xf3, 0xeb}, /* Tune_1 */ + {0xff, 0xf4, 0xef}, /* Tune_2 */ + {0xff, 0xf5, 0xf3}, /* Tune_3 */ + {0xff, 0xf6, 0xec}, /* Tune_4 */ + {0xff, 0xf7, 0xef}, /* Tune_5 */ + {0xff, 0xf8, 0xf3}, /* Tune_6 */ + {0xff, 0xf9, 0xec}, /* Tune_7 */ + {0xff, 0xfa, 0xef}, /* Tune_8 */ + {0xff, 0xfb, 0xf3}, /* Tune_9 */ +}; + +static unsigned char (*coordinate_data[MODE_MAX])[3] = { + coordinate_data_1, + coordinate_data_2, + coordinate_data_2, + coordinate_data_1, + coordinate_data_1, +}; + + +static unsigned char GRAYSCALE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char GRAYSCALE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0xb3, //ascr_Cr + 0x4c, //ascr_Rr + 0xb3, //ascr_Cg + 0x4c, //ascr_Rg + 0xb3, //ascr_Cb + 0x4c, //ascr_Rb + 0x69, //ascr_Mr + 0x96, //ascr_Gr + 0x69, //ascr_Mg + 0x96, //ascr_Gg + 0x69, //ascr_Mb + 0x96, //ascr_Gb + 0xe2, //ascr_Yr + 0x1d, //ascr_Br + 0xe2, //ascr_Yg + 0x1d, //ascr_Bg + 0xe2, //ascr_Yb + 0x1d, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char GRAYSCALE_NEGATIVE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char GRAYSCALE_NEGATIVE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x4c, //ascr_Cr + 0xb3, //ascr_Rr + 0x4c, //ascr_Cg + 0xb3, //ascr_Rg + 0x4c, //ascr_Cb + 0xb3, //ascr_Rb + 0x96, //ascr_Mr + 0x69, //ascr_Gr + 0x96, //ascr_Mg + 0x69, //ascr_Gg + 0x96, //ascr_Mb + 0x69, //ascr_Gb + 0x1d, //ascr_Yr + 0xe2, //ascr_Br + 0x1d, //ascr_Yg + 0xe2, //ascr_Bg + 0x1d, //ascr_Yb + 0xe2, //ascr_Bb + 0x00, //ascr_Wr + 0xff, //ascr_Kr + 0x00, //ascr_Wg + 0xff, //ascr_Kg + 0x00, //ascr_Wb + 0xff, //ascr_Kb + /* end */ +}; + +////////////////// UI /// ///////////////////// +static unsigned char SCREEN_CURTAIN_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char SCREEN_CURTAIN_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0x00, //ascr_Rr + 0x00, //ascr_Cg + 0x00, //ascr_Rg + 0x00, //ascr_Cb + 0x00, //ascr_Rb + 0x00, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0x00, //ascr_Gg + 0x00, //ascr_Mb + 0x00, //ascr_Gb + 0x00, //ascr_Yr + 0x00, //ascr_Br + 0x00, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0x00, //ascr_Bb + 0x00, //ascr_Wr + 0x00, //ascr_Kr + 0x00, //ascr_Wg + 0x00, //ascr_Kg + 0x00, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char STANDARD_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x60, + 0x3f, //fa_pcl_ppi 14 + 0xff, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x5c, //ascr_skin_Rg + 0x68, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf8, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// GALLERY ///////////////////// +static unsigned char STANDARD_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0xa0, + 0x00, //de_maxminus 11 + 0xa0, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0c, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x6a, //ascr_skin_cb + 0x9a, //ascr_skin_cr + 0x25, //ascr_dist_up + 0x1a, //ascr_dist_down + 0x16, //ascr_dist_right + 0x2a, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x37, + 0x5a, + 0x00, //ascr_div_down + 0x4e, + 0xc5, + 0x00, //ascr_div_right + 0x5d, + 0x17, + 0x00, //ascr_div_left + 0x30, + 0xc3, + 0xff, //ascr_skin_Rr + 0x48, //ascr_skin_Rg + 0x48, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf0, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xd8, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xd9, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xe0, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xf6, //ascr_Cb + 0x00, //ascr_Rb + 0xd8, //ascr_Mr + 0x3b, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xd9, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x14, //ascr_Br + 0xf9, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// VIDEO ///////////////////// +static unsigned char STANDARD_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x05, //fa_pcl_ppi 14 + 0x86, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x14, //curve_1_a + 0x00, //curve_2_b + 0x14, //curve_2_a + 0x00, //curve_3_b + 0x14, //curve_3_a + 0x00, //curve_4_b + 0x14, //curve_4_a + 0x03, //curve_5_b + 0x9a, //curve_5_a + 0x03, //curve_6_b + 0x9a, //curve_6_a + 0x03, //curve_7_b + 0x9a, //curve_7_a + 0x03, //curve_8_b + 0x9a, //curve_8_a + 0x07, //curve_9_b + 0x9e, //curve_9_a + 0x07, //curve10_b + 0x9e, //curve10_a + 0x07, //curve11_b + 0x9e, //curve11_a + 0x07, //curve12_b + 0x9e, //curve12_a + 0x0a, //curve13_b + 0xa0, //curve13_a + 0x0a, //curve14_b + 0xa0, //curve14_a + 0x0a, //curve15_b + 0xa0, //curve15_a + 0x0a, //curve16_b + 0xa0, //curve16_a + 0x16, //curve17_b + 0xa6, //curve17_a + 0x16, //curve18_b + 0xa6, //curve18_a + 0x16, //curve19_b + 0xa6, //curve19_a + 0x16, //curve20_b + 0xa6, //curve20_a + 0x05, //curve21_b + 0x21, //curve21_a + 0x0b, //curve22_b + 0x20, //curve22_a + 0x87, //curve23_b + 0x0f, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0f, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x14, //curve_1_a + 0x00, //curve_2_b + 0x14, //curve_2_a + 0x00, //curve_3_b + 0x14, //curve_3_a + 0x00, //curve_4_b + 0x14, //curve_4_a + 0x03, //curve_5_b + 0x9a, //curve_5_a + 0x03, //curve_6_b + 0x9a, //curve_6_a + 0x03, //curve_7_b + 0x9a, //curve_7_a + 0x03, //curve_8_b + 0x9a, //curve_8_a + 0x07, //curve_9_b + 0x9e, //curve_9_a + 0x07, //curve10_b + 0x9e, //curve10_a + 0x07, //curve11_b + 0x9e, //curve11_a + 0x07, //curve12_b + 0x9e, //curve12_a + 0x0a, //curve13_b + 0xa0, //curve13_a + 0x0a, //curve14_b + 0xa0, //curve14_a + 0x0a, //curve15_b + 0xa0, //curve15_a + 0x0a, //curve16_b + 0xa0, //curve16_a + 0x16, //curve17_b + 0xa6, //curve17_a + 0x16, //curve18_b + 0xa6, //curve18_a + 0x16, //curve19_b + 0xa6, //curve19_a + 0x16, //curve20_b + 0xa6, //curve20_a + 0x05, //curve21_b + 0x21, //curve21_a + 0x0b, //curve22_b + 0x20, //curve22_a + 0x87, //curve23_b + 0x0f, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// VT ///////////////////// +static unsigned char STANDARD_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0xa0, + 0x00, //de_maxminus 11 + 0xa0, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char BYPASS_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x00, //ascr algo lce 10 10 10 +}; + +static unsigned char BYPASS_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0c, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// CAMERA ///////////////////// +static unsigned char CAMERA_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char CAMERA_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_CAMERA_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_CAMERA_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0xb0, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0xb0, + 0x3f, //fa_pcl_ppi 14 + 0xff, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x6a, //ascr_skin_cb + 0x9a, //ascr_skin_cr + 0x25, //ascr_dist_up + 0x1a, //ascr_dist_down + 0x16, //ascr_dist_right + 0x2a, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x37, + 0x5a, + 0x00, //ascr_div_down + 0x4e, + 0xc5, + 0x00, //ascr_div_right + 0x5d, + 0x17, + 0x00, //ascr_div_left + 0x30, + 0xc3, + 0xff, //ascr_skin_Rr + 0x48, //ascr_skin_Rg + 0x48, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf0, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xd8, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xd9, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xe0, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xf6, //ascr_Cb + 0x00, //ascr_Rb + 0xd8, //ascr_Mr + 0x3b, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xd9, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x14, //ascr_Br + 0xf9, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#if 0 +static unsigned char CAMERA_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char CAMERA_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char COLD_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char COLD_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char COLD_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char COLD_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char WARM_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char WARM_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char WARM_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char WARM_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; +#endif + +static unsigned char NEGATIVE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char NEGATIVE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0xff, //ascr_Cr + 0x00, //ascr_Rr + 0x00, //ascr_Cg + 0xff, //ascr_Rg + 0x00, //ascr_Cb + 0xff, //ascr_Rb + 0x00, //ascr_Mr + 0xff, //ascr_Gr + 0xff, //ascr_Mg + 0x00, //ascr_Gg + 0x00, //ascr_Mb + 0xff, //ascr_Gb + 0x00, //ascr_Yr + 0xff, //ascr_Br + 0x00, //ascr_Yg + 0xff, //ascr_Bg + 0xff, //ascr_Yb + 0x00, //ascr_Bb + 0x00, //ascr_Wr + 0xff, //ascr_Kr + 0x00, //ascr_Wg + 0xff, //ascr_Kg + 0x00, //ascr_Wb + 0xff, //ascr_Kb + /* end */ +}; + +#if 0 +static unsigned char OUTDOOR_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char OUTDOOR_VIDEO_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; +#endif + +static unsigned char COLOR_BLIND_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char COLOR_BLIND_HBM_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_HBM_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// BROWSER ///////////////////// +static unsigned char STANDARD_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x5c, //ascr_skin_Rg + 0x68, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf8, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// eBOOK ///////////////////// +static unsigned char AUTO_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf5, //ascr_Wg + 0x00, //ascr_Kg + 0xe3, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char STANDARD_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf6, //ascr_Wg + 0x00, //ascr_Kg + 0xea, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_EMAIL_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_EMAIL_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf9, //ascr_Wg + 0x00, //ascr_Kg + 0xed, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_GRAY_8_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char HMT_GRAY_8_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char HMT_GRAY_16_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char HMT_GRAY_16_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char LOCAL_CE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3f, //ascr algo lce 10 10 10 +}; + +static unsigned char LOCAL_CE_1[] = { + 0xEC, + 0x86, //lce_gain 00 0000 + 0x30, //lce_color_gain 00 0000 + 0x00, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0x90, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0xbf, + 0x00, //lce_ref_gain 9 + 0xb0, + 0x77, //lce_block_size h v 0000 0000 + 0xfa, //lce_bright_th + 0x7f, //lce_bin_size_ratio + 0x00, //lce_dark_th 000 + 0x40, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x6b, //curve_1_a + 0x03, //curve_2_b + 0x48, //curve_2_a + 0x08, //curve_3_b + 0x32, //curve_3_a + 0x08, //curve_4_b + 0x32, //curve_4_a + 0x08, //curve_5_b + 0x32, //curve_5_a + 0x08, //curve_6_b + 0x32, //curve_6_a + 0x08, //curve_7_b + 0x32, //curve_7_a + 0x10, //curve_8_b + 0x28, //curve_8_a + 0x10, //curve_9_b + 0x28, //curve_9_a + 0x10, //curve10_b + 0x28, //curve10_a + 0x10, //curve11_b + 0x28, //curve11_a + 0x10, //curve12_b + 0x28, //curve12_a + 0x19, //curve13_b + 0x22, //curve13_a + 0x19, //curve14_b + 0x22, //curve14_a + 0x19, //curve15_b + 0x22, //curve15_a + 0x19, //curve16_b + 0x22, //curve16_a + 0x19, //curve17_b + 0x22, //curve17_a + 0x19, //curve18_b + 0x22, //curve18_a + 0x23, //curve19_b + 0x1e, //curve19_a + 0x2e, //curve20_b + 0x1b, //curve20_a + 0x33, //curve21_b + 0x1a, //curve21_a + 0x40, //curve22_b + 0x18, //curve22_a + 0x48, //curve23_b + 0x17, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x30, //ascr_skin_Rg + 0x30, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char LOCAL_CE_TEXT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3f, //ascr algo lce 10 10 10 +}; + +static unsigned char LOCAL_CE_TEXT_1[] = { + 0xEC, + 0x86, //lce_gain 00 0000 + 0x30, //lce_color_gain 00 0000 + 0x00, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0x90, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0xbf, + 0x00, //lce_ref_gain 9 + 0xb0, + 0x77, //lce_block_size h v 0000 0000 + 0xfa, //lce_bright_th + 0x7f, //lce_bin_size_ratio + 0x00, //lce_dark_th 000 + 0x40, //lce_min_ref_offset + 0x06, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x7b, //curve_1_a + 0x03, //curve_2_b + 0x48, //curve_2_a + 0x08, //curve_3_b + 0x32, //curve_3_a + 0x08, //curve_4_b + 0x32, //curve_4_a + 0x08, //curve_5_b + 0x32, //curve_5_a + 0x08, //curve_6_b + 0x32, //curve_6_a + 0x08, //curve_7_b + 0x32, //curve_7_a + 0x10, //curve_8_b + 0x28, //curve_8_a + 0x10, //curve_9_b + 0x28, //curve_9_a + 0x10, //curve10_b + 0x28, //curve10_a + 0x10, //curve11_b + 0x28, //curve11_a + 0x10, //curve12_b + 0x28, //curve12_a + 0x19, //curve13_b + 0x22, //curve13_a + 0x70, //curve14_b + 0xf7, //curve14_a + 0x70, //curve15_b + 0xf7, //curve15_a + 0x70, //curve16_b + 0xf7, //curve16_a + 0x70, //curve17_b + 0xf7, //curve17_a + 0x66, //curve18_b + 0x1a, //curve18_a + 0x76, //curve19_b + 0x14, //curve19_a + 0x82, //curve20_b + 0x11, //curve20_a + 0x92, //curve21_b + 0x0e, //curve21_a + 0x98, //curve22_b + 0x0d, //curve22_a + 0x9f, //curve23_b + 0x0c, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x56, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x67, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x17, + 0xd0, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x13, + 0xe2, + 0xff, //ascr_skin_Rr + 0xa0, //ascr_skin_Rg + 0xa0, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0x90, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#ifdef CONFIG_LCD_HMT +static unsigned char HMT_3000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_3000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xc8, //ascr_Wg + 0x00, //ascr_Kg + 0x80, //ascr_Wb + 0x00, //ascr_Kb + /*end*/ +}; + +static unsigned char HMT_4000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_4000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xde, //ascr_Wg + 0x00, //ascr_Kg + 0xac, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_5000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_5000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xeb, //ascr_Wg + 0x00, //ascr_Kg + 0xc8, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_6500K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_6500K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#endif + +static unsigned char LEVEL1_UNLOCK[] = { + 0xF0, + 0x5A, 0x5A +}; + +static unsigned char LEVEL1_LOCK[] = { + 0xF0, + 0xA5, 0xA5 +}; + +struct mdnie_table bypass_table[BYPASS_MAX] = { + [BYPASS_ON] = MDNIE_SET(BYPASS) +}; + +struct mdnie_table accessibility_table[ACCESSIBILITY_MAX] = { + [NEGATIVE] = MDNIE_SET(NEGATIVE), + MDNIE_SET(COLOR_BLIND), + MDNIE_SET(SCREEN_CURTAIN), + MDNIE_SET(GRAYSCALE), + MDNIE_SET(GRAYSCALE_NEGATIVE), + MDNIE_SET(COLOR_BLIND_HBM), +}; + +struct mdnie_table hbm_table[HBM_MAX] = { + [HBM_ON] = MDNIE_SET(LOCAL_CE), + MDNIE_SET(LOCAL_CE_TEXT) +}; +#ifdef CONFIG_LCD_HMT +struct mdnie_table hmt_table[HMT_MDNIE_MAX] = { + [HMT_MDNIE_ON] = MDNIE_SET(HMT_3000K), + MDNIE_SET(HMT_4000K), + MDNIE_SET(HMT_5000K), + MDNIE_SET(HMT_6500K) +}; +#endif +struct mdnie_table tuning_table[SCENARIO_MAX][MODE_MAX] = { + { + MDNIE_SET(DYNAMIC_UI), + MDNIE_SET(STANDARD_UI), + MDNIE_SET(NATURAL_UI), + MDNIE_SET(MOVIE_UI), + MDNIE_SET(AUTO_UI) + }, { + MDNIE_SET(DYNAMIC_VIDEO), + MDNIE_SET(STANDARD_VIDEO), + MDNIE_SET(NATURAL_VIDEO), + MDNIE_SET(MOVIE_VIDEO), + MDNIE_SET(AUTO_VIDEO) + }, + [CAMERA_MODE] = { + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(AUTO_CAMERA) + }, + [GALLERY_MODE] = { + MDNIE_SET(DYNAMIC_GALLERY), + MDNIE_SET(STANDARD_GALLERY), + MDNIE_SET(NATURAL_GALLERY), + MDNIE_SET(MOVIE_GALLERY), + MDNIE_SET(AUTO_GALLERY) + }, { + MDNIE_SET(DYNAMIC_VT), + MDNIE_SET(STANDARD_VT), + MDNIE_SET(NATURAL_VT), + MDNIE_SET(MOVIE_VT), + MDNIE_SET(AUTO_VT) + }, { + MDNIE_SET(DYNAMIC_BROWSER), + MDNIE_SET(STANDARD_BROWSER), + MDNIE_SET(NATURAL_BROWSER), + MDNIE_SET(MOVIE_BROWSER), + MDNIE_SET(AUTO_BROWSER) + }, { + MDNIE_SET(DYNAMIC_EBOOK), + MDNIE_SET(STANDARD_EBOOK), + MDNIE_SET(NATURAL_EBOOK), + MDNIE_SET(MOVIE_EBOOK), + MDNIE_SET(AUTO_EBOOK) + }, { + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL) + }, { + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8) + }, { + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16) + } +}; +#endif diff --git a/drivers/video/exynos/decon/panels/mdnie_lite_table_zen.h b/drivers/video/exynos/decon/panels/mdnie_lite_table_zen.h new file mode 100644 index 000000000000..8ed31044a9f6 --- /dev/null +++ b/drivers/video/exynos/decon/panels/mdnie_lite_table_zen.h @@ -0,0 +1,9303 @@ +#ifndef __MDNIE_TABLE_H__ +#define __MDNIE_TABLE_H__ + +/* 2015.03.21 */ + +/* SCR Position can be different each panel */ +#define MDNIE_RED_R 133 /* ASCR_WIDE_CR[7:0] */ +#define MDNIE_RED_G 135 /* ASCR_WIDE_CG[7:0] */ +#define MDNIE_RED_B 137 /* ASCR_WIDE_CB[7:0] */ +#define MDNIE_BLUE_R 139 /* ASCR_WIDE_MR[7:0] */ +#define MDNIE_BLUE_G 141 /* ASCR_WIDE_MG[7:0] */ +#define MDNIE_BLUE_B 143 /* ASCR_WIDE_MB[7:0] */ +#define MDNIE_GREEN_R 145 /* ASCR_WIDE_YR[7:0] */ +#define MDNIE_GREEN_G 147 /* ASCR_WIDE_YG[7:0] */ +#define MDNIE_GREEN_B 149 /* ASCR_WIDE_YB[7:0] */ +#define MDNIE_WHITE_R 151 /* ASCR_WIDE_WR[7:0] */ +#define MDNIE_WHITE_G 153 /* ASCR_WIDE_WG[7:0] */ +#define MDNIE_WHITE_B 155 /* ASCR_WIDE_WB[7:0] */ + +#define MDNIE_COLOR_BLIND_OFFSET MDNIE_RED_R + +#define COLOR_OFFSET_F1(x, y) (((y << 10) - (((x << 10) * 353) / 326) + (30 << 10)) >> 10) +#define COLOR_OFFSET_F2(x, y) (((y << 10) - (((x << 10) * 20) / 19) - (14 << 10)) >> 10) +#define COLOR_OFFSET_F3(x, y) (((y << 10) + (((x << 10) * 185) / 42) - (16412 << 10)) >> 10) +#define COLOR_OFFSET_F4(x, y) (((y << 10) + (((x << 10) * 337) / 106) - (12601 << 10)) >> 10) + +/* color coordination order is WR, WG, WB */ +static unsigned char coordinate_data_1[][3] = { + {0xff, 0xff, 0xff}, /* dummy */ + {0xff, 0xf9, 0xfb}, /* Tune_1 */ + {0xff, 0xfa, 0xff}, /* Tune_2 */ + {0xfb, 0xf7, 0xff}, /* Tune_3 */ + {0xff, 0xfb, 0xfb}, /* Tune_4 */ + {0xff, 0xfd, 0xff}, /* Tune_5 */ + {0xfb, 0xfa, 0xff}, /* Tune_6 */ + {0xff, 0xfe, 0xfc}, /* Tune_7 */ + {0xff, 0xff, 0xff}, /* Tune_8 */ + {0xfb, 0xfd, 0xff}, /* Tune_9 */ +}; + +static unsigned char coordinate_data_2[][3] = { + {0xff, 0xff, 0xff}, /* dummy */ + {0xff, 0xf3, 0xeb}, /* Tune_1 */ + {0xff, 0xf4, 0xef}, /* Tune_2 */ + {0xff, 0xf5, 0xf3}, /* Tune_3 */ + {0xff, 0xf6, 0xec}, /* Tune_4 */ + {0xff, 0xf7, 0xef}, /* Tune_5 */ + {0xff, 0xf8, 0xf3}, /* Tune_6 */ + {0xff, 0xf9, 0xec}, /* Tune_7 */ + {0xff, 0xfa, 0xef}, /* Tune_8 */ + {0xff, 0xfb, 0xf3}, /* Tune_9 */ +}; + +static unsigned char (*coordinate_data[MODE_MAX])[3] = { + coordinate_data_1, + coordinate_data_2, + coordinate_data_2, + coordinate_data_1, + coordinate_data_1, +}; + + +static unsigned char GRAYSCALE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char GRAYSCALE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0xb3, //ascr_Cr + 0x4c, //ascr_Rr + 0xb3, //ascr_Cg + 0x4c, //ascr_Rg + 0xb3, //ascr_Cb + 0x4c, //ascr_Rb + 0x69, //ascr_Mr + 0x96, //ascr_Gr + 0x69, //ascr_Mg + 0x96, //ascr_Gg + 0x69, //ascr_Mb + 0x96, //ascr_Gb + 0xe2, //ascr_Yr + 0x1d, //ascr_Br + 0xe2, //ascr_Yg + 0x1d, //ascr_Bg + 0xe2, //ascr_Yb + 0x1d, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char GRAYSCALE_NEGATIVE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char GRAYSCALE_NEGATIVE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x4c, //ascr_Cr + 0xb3, //ascr_Rr + 0x4c, //ascr_Cg + 0xb3, //ascr_Rg + 0x4c, //ascr_Cb + 0xb3, //ascr_Rb + 0x96, //ascr_Mr + 0x69, //ascr_Gr + 0x96, //ascr_Mg + 0x69, //ascr_Gg + 0x96, //ascr_Mb + 0x69, //ascr_Gb + 0x1d, //ascr_Yr + 0xe2, //ascr_Br + 0x1d, //ascr_Yg + 0xe2, //ascr_Bg + 0x1d, //ascr_Yb + 0xe2, //ascr_Bb + 0x00, //ascr_Wr + 0xff, //ascr_Kr + 0x00, //ascr_Wg + 0xff, //ascr_Kg + 0x00, //ascr_Wb + 0xff, //ascr_Kb + /* end */ +}; + +////////////////// UI /// ///////////////////// +static unsigned char SCREEN_CURTAIN_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char SCREEN_CURTAIN_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0x00, //ascr_Rr + 0x00, //ascr_Cg + 0x00, //ascr_Rg + 0x00, //ascr_Cb + 0x00, //ascr_Rb + 0x00, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0x00, //ascr_Gg + 0x00, //ascr_Mb + 0x00, //ascr_Gb + 0x00, //ascr_Yr + 0x00, //ascr_Br + 0x00, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0x00, //ascr_Bb + 0x00, //ascr_Wr + 0x00, //ascr_Kr + 0x00, //ascr_Wg + 0x00, //ascr_Kg + 0x00, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char STANDARD_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_UI_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_UI_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x60, + 0x3f, //fa_pcl_ppi 14 + 0xff, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x5c, //ascr_skin_Rg + 0x68, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf8, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// GALLERY ///////////////////// +static unsigned char STANDARD_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0xa0, + 0x00, //de_maxminus 11 + 0xa0, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_GALLERY_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_GALLERY_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0c, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x6a, //ascr_skin_cb + 0x9a, //ascr_skin_cr + 0x25, //ascr_dist_up + 0x1a, //ascr_dist_down + 0x16, //ascr_dist_right + 0x2a, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x37, + 0x5a, + 0x00, //ascr_div_down + 0x4e, + 0xc5, + 0x00, //ascr_div_right + 0x5d, + 0x17, + 0x00, //ascr_div_left + 0x30, + 0xc3, + 0xff, //ascr_skin_Rr + 0x48, //ascr_skin_Rg + 0x48, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf0, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xd8, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xd9, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xe0, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xf6, //ascr_Cb + 0x00, //ascr_Rb + 0xd8, //ascr_Mr + 0x3b, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xd9, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x14, //ascr_Br + 0xf9, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// VIDEO ///////////////////// +static unsigned char STANDARD_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x05, //fa_pcl_ppi 14 + 0x86, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x14, //curve_1_a + 0x00, //curve_2_b + 0x14, //curve_2_a + 0x00, //curve_3_b + 0x14, //curve_3_a + 0x00, //curve_4_b + 0x14, //curve_4_a + 0x03, //curve_5_b + 0x9a, //curve_5_a + 0x03, //curve_6_b + 0x9a, //curve_6_a + 0x03, //curve_7_b + 0x9a, //curve_7_a + 0x03, //curve_8_b + 0x9a, //curve_8_a + 0x07, //curve_9_b + 0x9e, //curve_9_a + 0x07, //curve10_b + 0x9e, //curve10_a + 0x07, //curve11_b + 0x9e, //curve11_a + 0x07, //curve12_b + 0x9e, //curve12_a + 0x0a, //curve13_b + 0xa0, //curve13_a + 0x0a, //curve14_b + 0xa0, //curve14_a + 0x0a, //curve15_b + 0xa0, //curve15_a + 0x0a, //curve16_b + 0xa0, //curve16_a + 0x16, //curve17_b + 0xa6, //curve17_a + 0x16, //curve18_b + 0xa6, //curve18_a + 0x16, //curve19_b + 0xa6, //curve19_a + 0x16, //curve20_b + 0xa6, //curve20_a + 0x05, //curve21_b + 0x21, //curve21_a + 0x0b, //curve22_b + 0x20, //curve22_a + 0x87, //curve23_b + 0x0f, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_VIDEO_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0f, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x00, //de_maxplus 11 + 0x40, + 0x00, //de_maxminus 11 + 0x40, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x14, //curve_1_a + 0x00, //curve_2_b + 0x14, //curve_2_a + 0x00, //curve_3_b + 0x14, //curve_3_a + 0x00, //curve_4_b + 0x14, //curve_4_a + 0x03, //curve_5_b + 0x9a, //curve_5_a + 0x03, //curve_6_b + 0x9a, //curve_6_a + 0x03, //curve_7_b + 0x9a, //curve_7_a + 0x03, //curve_8_b + 0x9a, //curve_8_a + 0x07, //curve_9_b + 0x9e, //curve_9_a + 0x07, //curve10_b + 0x9e, //curve10_a + 0x07, //curve11_b + 0x9e, //curve11_a + 0x07, //curve12_b + 0x9e, //curve12_a + 0x0a, //curve13_b + 0xa0, //curve13_a + 0x0a, //curve14_b + 0xa0, //curve14_a + 0x0a, //curve15_b + 0xa0, //curve15_a + 0x0a, //curve16_b + 0xa0, //curve16_a + 0x16, //curve17_b + 0xa6, //curve17_a + 0x16, //curve18_b + 0xa6, //curve18_a + 0x16, //curve19_b + 0xa6, //curve19_a + 0x16, //curve20_b + 0xa6, //curve20_a + 0x05, //curve21_b + 0x21, //curve21_a + 0x0b, //curve22_b + 0x20, //curve22_a + 0x87, //curve23_b + 0x0f, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// VT ///////////////////// +static unsigned char STANDARD_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x04, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x10, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x40, + 0x00, //de_maxplus 11 + 0xa0, + 0x00, //de_maxminus 11 + 0xa0, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char BYPASS_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x00, //ascr algo lce 10 10 10 +}; + +static unsigned char BYPASS_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_VT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_VT_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x0c, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x70, + 0x02, //de_maxplus 11 + 0x00, + 0x02, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0x70, + 0x01, //fa_pcl_ppi 14 + 0xc0, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// CAMERA ///////////////////// +static unsigned char CAMERA_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char CAMERA_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_CAMERA_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_CAMERA_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0xb0, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x01, + 0x00, //fa_step_n 13 + 0x01, + 0x00, //fa_max_de_gain 13 + 0xb0, + 0x3f, //fa_pcl_ppi 14 + 0xff, + 0xa9, //fa_skin_cr + 0x67, //fa_skin_cb + 0x27, //fa_dist_left + 0x19, //fa_dist_right + 0x29, //fa_dist_down + 0x17, //fa_dist_up + 0x01, //fa_div_dist_left + 0xa4, + 0x02, //fa_div_dist_right + 0x8f, + 0x01, //fa_div_dist_down + 0x90, + 0x02, //fa_div_dist_up + 0xc8, + 0x20, //fa_px_min_weight + 0x20, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x28, //fa_os_cnt_10_co + 0x3c, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x6a, //ascr_skin_cb + 0x9a, //ascr_skin_cr + 0x25, //ascr_dist_up + 0x1a, //ascr_dist_down + 0x16, //ascr_dist_right + 0x2a, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x37, + 0x5a, + 0x00, //ascr_div_down + 0x4e, + 0xc5, + 0x00, //ascr_div_right + 0x5d, + 0x17, + 0x00, //ascr_div_left + 0x30, + 0xc3, + 0xff, //ascr_skin_Rr + 0x48, //ascr_skin_Rg + 0x48, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf0, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xd8, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xd9, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xe0, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xf6, //ascr_Cb + 0x00, //ascr_Rb + 0xd8, //ascr_Mr + 0x3b, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xd9, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x14, //ascr_Br + 0xf9, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#if 0 +static unsigned char CAMERA_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char CAMERA_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char COLD_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char COLD_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char COLD_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char COLD_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char WARM_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char WARM_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char WARM_OUTDOOR_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char WARM_OUTDOOR_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; +#endif + +static unsigned char NEGATIVE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char NEGATIVE_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0xff, //ascr_Cr + 0x00, //ascr_Rr + 0x00, //ascr_Cg + 0xff, //ascr_Rg + 0x00, //ascr_Cb + 0xff, //ascr_Rb + 0x00, //ascr_Mr + 0xff, //ascr_Gr + 0xff, //ascr_Mg + 0x00, //ascr_Gg + 0x00, //ascr_Mb + 0xff, //ascr_Gb + 0x00, //ascr_Yr + 0xff, //ascr_Br + 0x00, //ascr_Yg + 0xff, //ascr_Bg + 0xff, //ascr_Yb + 0x00, //ascr_Bb + 0x00, //ascr_Wr + 0xff, //ascr_Kr + 0x00, //ascr_Wg + 0xff, //ascr_Kg + 0x00, //ascr_Wb + 0xff, //ascr_Kb + /* end */ +}; + +#if 0 +static unsigned char OUTDOOR_VIDEO_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char OUTDOOR_VIDEO_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; +#endif + +static unsigned char COLOR_BLIND_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char COLOR_BLIND_HBM_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_HBM_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// BROWSER ///////////////////// +static unsigned char STANDARD_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x20, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x7a, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x2b, //ascr_Rg + 0xf1, //ascr_Cb + 0x2d, //ascr_Rb + 0xff, //ascr_Mr + 0x68, //ascr_Gr + 0x15, //ascr_Mg + 0xff, //ascr_Gg + 0xfa, //ascr_Mb + 0x31, //ascr_Gb + 0xf8, //ascr_Yr + 0x34, //ascr_Br + 0xff, //ascr_Yg + 0x20, //ascr_Bg + 0x4b, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xef, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_BROWSER_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_BROWSER_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x5c, //ascr_skin_Rg + 0x68, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf8, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +////////////////// eBOOK ///////////////////// +static unsigned char AUTO_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf5, //ascr_Wg + 0x00, //ascr_Kg + 0xe3, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char DYNAMIC_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char DYNAMIC_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x03, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x20, + 0x00, // curve_1_b + 0x14, // curve_1_a + 0x00, // curve_2_b + 0x14, // curve_2_a + 0x00, // curve_3_b + 0x14, // curve_3_a + 0x00, // curve_4_b + 0x14, // curve_4_a + 0x03, // curve_5_b + 0x9a, // curve_5_a + 0x03, // curve_6_b + 0x9a, // curve_6_a + 0x03, // curve_7_b + 0x9a, // curve_7_a + 0x03, // curve_8_b + 0x9a, // curve_8_a + 0x07, // curve_9_b + 0x9e, // curve_9_a + 0x07, // curve10_b + 0x9e, // curve10_a + 0x07, // curve11_b + 0x9e, // curve11_a + 0x07, // curve12_b + 0x9e, // curve12_a + 0x0a, // curve13_b + 0xa0, // curve13_a + 0x0a, // curve14_b + 0xa0, // curve14_a + 0x0a, // curve15_b + 0xa0, // curve15_a + 0x0a, // curve16_b + 0xa0, // curve16_a + 0x16, // curve17_b + 0xa6, // curve17_a + 0x16, // curve18_b + 0xa6, // curve18_a + 0x16, // curve19_b + 0xa6, // curve19_a + 0x16, // curve20_b + 0xa6, // curve20_a + 0x05, // curve21_b + 0x21, // curve21_a + 0x0b, // curve22_b + 0x20, // curve22_a + 0x87, // curve23_b + 0x0f, // curve23_a + 0x00, // curve24_b + 0xFF, // curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x37, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x47, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x25, + 0x3d, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x1c, + 0xd8, + 0xff, //ascr_skin_Rr + 0x62, //ascr_skin_Rg + 0x6c, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf4, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char STANDARD_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char STANDARD_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xf7, //ascr_Rr + 0xe7, //ascr_Cg + 0x27, //ascr_Rg + 0xe8, //ascr_Cb + 0x2f, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x42, //ascr_Mg + 0xd9, //ascr_Gg + 0xe5, //ascr_Mb + 0x31, //ascr_Gb + 0xf4, //ascr_Yr + 0x30, //ascr_Br + 0xe9, //ascr_Yg + 0x30, //ascr_Bg + 0x45, //ascr_Yb + 0xde, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char NATURAL_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char NATURAL_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x50, //ascr_skin_Rg + 0x60, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x90, //ascr_Cr + 0xd5, //ascr_Rr + 0xef, //ascr_Cg + 0x22, //ascr_Rg + 0xe9, //ascr_Cb + 0x27, //ascr_Rb + 0xdf, //ascr_Mr + 0x87, //ascr_Gr + 0x3c, //ascr_Mg + 0xe2, //ascr_Gg + 0xde, //ascr_Mb + 0x4e, //ascr_Gb + 0xf5, //ascr_Yr + 0x30, //ascr_Br + 0xea, //ascr_Yg + 0x2f, //ascr_Bg + 0x57, //ascr_Yb + 0xda, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf7, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char MOVIE_EBOOK_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char MOVIE_EBOOK_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf6, //ascr_Wg + 0x00, //ascr_Kg + 0xea, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char AUTO_EMAIL_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char AUTO_EMAIL_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf9, //ascr_Wg + 0x00, //ascr_Kg + 0xed, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_GRAY_8_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char HMT_GRAY_8_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char HMT_GRAY_16_2[] = { + /* start */ + 0xEB, + 0x01, /* mdnie_en */ + 0x00, /* data_width mask 00 0000 */ + 0x00, /* ascr algo lce 10 10 10 */ +}; + +static unsigned char HMT_GRAY_16_1[] = { + 0xEC, + 0x98, /* lce_on gain 0 00 0000 */ + 0x24, /* lce_color_gain 00 0000 */ + 0x10, /* lce_scene_change_on scene_trans 0 0000 */ + 0x14, /* lce_min_diff */ + 0xb3, /* lce_illum_gain */ + 0x01, /* lce_ref_offset 9 */ + 0x0e, + 0x01, /* lce_ref_gain 9 */ + 0x00, + 0x66, /* lce_block_size h v 000 000 */ + 0xfa, /* lce_bright_th */ + 0x2d, /* lce_bin_size_ratio */ + 0x03, /* lce_dark_th 000 */ + 0x96, /* lce_min_ref_offset */ + 0x00, /* nr fa de cs gamma 0 0000 */ + 0xff, /* nr_mask_th */ + 0x00, /* de_gain 10 */ + 0x00, + 0x07, /* de_maxplus 11 */ + 0xff, + 0x07, /* de_maxminus 11 */ + 0xff, + 0x14, /* fa_edge_th */ + 0x00, /* fa_step_p 13 */ + 0x0a, + 0x00, /* fa_step_n 13 */ + 0x32, + 0x01, /* fa_max_de_gain 13 */ + 0xf4, + 0x0b, /* fa_pcl_ppi 14 */ + 0x8a, + 0x6e, /* fa_skin_cr */ + 0x99, /* fa_skin_cb */ + 0x1b, /* fa_dist_left */ + 0x17, /* fa_dist_right */ + 0x14, /* fa_dist_down */ + 0x1e, /* fa_dist_up */ + 0x02, /* fa_div_dist_left */ + 0x5f, + 0x02, /* fa_div_dist_right */ + 0xc8, + 0x03, /* fa_div_dist_down */ + 0x33, + 0x02, /* fa_div_dist_up */ + 0x22, + 0x10, /* fa_px_min_weight */ + 0x10, /* fa_fr_min_weight */ + 0x07, /* fa_skin_zone_w */ + 0x07, /* fa_skin_zone_h */ + 0x20, /* fa_os_cnt_10_co */ + 0x2d, /* fa_os_cnt_20_co */ + 0x01, /* cs_gain 10 */ + 0x00, + 0x00, /* curve_1_b */ + 0x20, /* curve_1_a */ + 0x00, /* curve_2_b */ + 0x20, /* curve_2_a */ + 0x00, /* curve_3_b */ + 0x20, /* curve_3_a */ + 0x00, /* curve_4_b */ + 0x20, /* curve_4_a */ + 0x02, /* curve_5_b */ + 0x1b, /* curve_5_a */ + 0x02, /* curve_6_b */ + 0x1b, /* curve_6_a */ + 0x02, /* curve_7_b */ + 0x1b, /* curve_7_a */ + 0x02, /* curve_8_b */ + 0x1b, /* curve_8_a */ + 0x09, /* curve_9_b */ + 0xa6, /* curve_9_a */ + 0x09, /* curve10_b */ + 0xa6, /* curve10_a */ + 0x09, /* curve11_b */ + 0xa6, /* curve11_a */ + 0x09, /* curve12_b */ + 0xa6, /* curve12_a */ + 0x00, /* curve13_b */ + 0x20, /* curve13_a */ + 0x00, /* curve14_b */ + 0x20, /* curve14_a */ + 0x00, /* curve15_b */ + 0x20, /* curve15_a */ + 0x00, /* curve16_b */ + 0x20, /* curve16_a */ + 0x00, /* curve17_b */ + 0x20, /* curve17_a */ + 0x00, /* curve18_b */ + 0x20, /* curve18_a */ + 0x00, /* curve19_b */ + 0x20, /* curve19_a */ + 0x00, /* curve20_b */ + 0x20, /* curve20_a */ + 0x00, /* curve21_b */ + 0x20, /* curve21_a */ + 0x00, /* curve22_b */ + 0x20, /* curve22_a */ + 0x00, /* curve23_b */ + 0x20, /* curve23_a */ + 0x00, /* curve24_b */ + 0xFF, /* curve24_a */ + 0x70, /* ascr_skin_on linear_on strength 0 0 00000 */ + 0x67, /* ascr_skin_cb */ + 0xa9, /* ascr_skin_cr */ + 0x0c, /* ascr_dist_up */ + 0x0c, /* ascr_dist_down */ + 0x0c, /* ascr_dist_right */ + 0x0c, /* ascr_dist_left */ + 0x00, /* ascr_div_up 20 */ + 0xaa, + 0xab, + 0x00, /* ascr_div_down */ + 0xaa, + 0xab, + 0x00, /* ascr_div_right */ + 0xaa, + 0xab, + 0x00, /* ascr_div_left */ + 0xaa, + 0xab, + 0xd5, /* ascr_skin_Rr */ + 0x2c, /* ascr_skin_Rg */ + 0x2a, /* ascr_skin_Rb */ + 0xff, /* ascr_skin_Yr */ + 0xf5, /* ascr_skin_Yg */ + 0x63, /* ascr_skin_Yb */ + 0xfe, /* ascr_skin_Mr */ + 0x4a, /* ascr_skin_Mg */ + 0xff, /* ascr_skin_Mb */ + 0xff, /* ascr_skin_Wr */ + 0xf9, /* ascr_skin_Wg */ + 0xf8, /* ascr_skin_Wb */ + 0x00, /* ascr_Cr */ + 0xff, /* ascr_Rr */ + 0xff, /* ascr_Cg */ + 0x00, /* ascr_Rg */ + 0xff, /* ascr_Cb */ + 0x00, /* ascr_Rb */ + 0xff, /* ascr_Mr */ + 0x00, /* ascr_Gr */ + 0x00, /* ascr_Mg */ + 0xff, /* ascr_Gg */ + 0xff, /* ascr_Mb */ + 0x00, /* ascr_Gb */ + 0xff, /* ascr_Yr */ + 0x00, /* ascr_Br */ + 0xff, /* ascr_Yg */ + 0x00, /* ascr_Bg */ + 0x00, /* ascr_Yb */ + 0xff, /* ascr_Bb */ + 0xff, /* ascr_Wr */ + 0x00, /* ascr_Kr */ + 0xff, /* ascr_Wg */ + 0x00, /* ascr_Kg */ + 0xff, /* ascr_Wb */ + 0x00, /* ascr_Kb */ + /* end */ +}; + +static unsigned char LOCAL_CE_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3f, //ascr algo lce 10 10 10 +}; + +static unsigned char LOCAL_CE_1[] = { + 0xEC, + 0x86, //lce_gain 00 0000 + 0x30, //lce_color_gain 00 0000 + 0x00, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0x90, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0xbf, + 0x00, //lce_ref_gain 9 + 0xb0, + 0x77, //lce_block_size h v 0000 0000 + 0xfa, //lce_bright_th + 0x7f, //lce_bin_size_ratio + 0x00, //lce_dark_th 000 + 0x40, //lce_min_ref_offset + 0x07, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x6b, //curve_1_a + 0x03, //curve_2_b + 0x48, //curve_2_a + 0x08, //curve_3_b + 0x32, //curve_3_a + 0x08, //curve_4_b + 0x32, //curve_4_a + 0x08, //curve_5_b + 0x32, //curve_5_a + 0x08, //curve_6_b + 0x32, //curve_6_a + 0x08, //curve_7_b + 0x32, //curve_7_a + 0x10, //curve_8_b + 0x28, //curve_8_a + 0x10, //curve_9_b + 0x28, //curve_9_a + 0x10, //curve10_b + 0x28, //curve10_a + 0x10, //curve11_b + 0x28, //curve11_a + 0x10, //curve12_b + 0x28, //curve12_a + 0x19, //curve13_b + 0x22, //curve13_a + 0x19, //curve14_b + 0x22, //curve14_a + 0x19, //curve15_b + 0x22, //curve15_a + 0x19, //curve16_b + 0x22, //curve16_a + 0x19, //curve17_b + 0x22, //curve17_a + 0x19, //curve18_b + 0x22, //curve18_a + 0x23, //curve19_b + 0x1e, //curve19_a + 0x2e, //curve20_b + 0x1b, //curve20_a + 0x33, //curve21_b + 0x1a, //curve21_a + 0x40, //curve22_b + 0x18, //curve22_a + 0x48, //curve23_b + 0x17, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x17, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x27, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x59, + 0x0b, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x34, + 0x83, + 0xff, //ascr_skin_Rr + 0x30, //ascr_skin_Rg + 0x30, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xff, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char LOCAL_CE_TEXT_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3f, //ascr algo lce 10 10 10 +}; + +static unsigned char LOCAL_CE_TEXT_1[] = { + 0xEC, + 0x86, //lce_gain 00 0000 + 0x30, //lce_color_gain 00 0000 + 0x00, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0x90, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0xbf, + 0x00, //lce_ref_gain 9 + 0xb0, + 0x77, //lce_block_size h v 0000 0000 + 0xfa, //lce_bright_th + 0x7f, //lce_bin_size_ratio + 0x00, //lce_dark_th 000 + 0x40, //lce_min_ref_offset + 0x06, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x60, + 0x01, //de_maxplus 11 + 0x00, + 0x01, //de_maxminus 11 + 0x00, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x7b, //curve_1_a + 0x03, //curve_2_b + 0x48, //curve_2_a + 0x08, //curve_3_b + 0x32, //curve_3_a + 0x08, //curve_4_b + 0x32, //curve_4_a + 0x08, //curve_5_b + 0x32, //curve_5_a + 0x08, //curve_6_b + 0x32, //curve_6_a + 0x08, //curve_7_b + 0x32, //curve_7_a + 0x10, //curve_8_b + 0x28, //curve_8_a + 0x10, //curve_9_b + 0x28, //curve_9_a + 0x10, //curve10_b + 0x28, //curve10_a + 0x10, //curve11_b + 0x28, //curve11_a + 0x10, //curve12_b + 0x28, //curve12_a + 0x19, //curve13_b + 0x22, //curve13_a + 0x70, //curve14_b + 0xf7, //curve14_a + 0x70, //curve15_b + 0xf7, //curve15_a + 0x70, //curve16_b + 0xf7, //curve16_a + 0x70, //curve17_b + 0xf7, //curve17_a + 0x66, //curve18_b + 0x1a, //curve18_a + 0x76, //curve19_b + 0x14, //curve19_a + 0x82, //curve20_b + 0x11, //curve20_a + 0x92, //curve21_b + 0x0e, //curve21_a + 0x98, //curve22_b + 0x0d, //curve22_a + 0x9f, //curve23_b + 0x0c, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x30, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x56, //ascr_dist_up + 0x29, //ascr_dist_down + 0x19, //ascr_dist_right + 0x67, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0x17, + 0xd0, + 0x00, //ascr_div_down + 0x31, + 0xf4, + 0x00, //ascr_div_right + 0x51, + 0xec, + 0x00, //ascr_div_left + 0x13, + 0xe2, + 0xff, //ascr_skin_Rr + 0xa0, //ascr_skin_Rg + 0xa0, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0x90, //ascr_skin_Yg + 0x00, //ascr_skin_Yb + 0xff, //ascr_skin_Mr + 0x00, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xff, //ascr_skin_Wg + 0xff, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#ifdef CONFIG_LCD_HMT +static unsigned char HMT_3000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_3000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xc8, //ascr_Wg + 0x00, //ascr_Kg + 0x80, //ascr_Wb + 0x00, //ascr_Kb + /*end*/ +}; + +static unsigned char HMT_4000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_4000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x40, //ascr_skin_on linear_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xde, //ascr_Wg + 0x00, //ascr_Kg + 0xac, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_5000K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_5000K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xeb, //ascr_Wg + 0x00, //ascr_Kg + 0xc8, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +static unsigned char HMT_6500K_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x3c, //ascr algo lce 10 10 10 +}; + +static unsigned char HMT_6500K_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x02, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x40, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xf8, //ascr_Wg + 0x00, //ascr_Kg + 0xee, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + +#endif + +static unsigned char LEVEL1_UNLOCK[] = { + 0xF0, + 0x5A, 0x5A +}; + +static unsigned char LEVEL1_LOCK[] = { + 0xF0, + 0xA5, 0xA5 +}; + +struct mdnie_table bypass_table[BYPASS_MAX] = { + [BYPASS_ON] = MDNIE_SET(BYPASS) +}; + +struct mdnie_table accessibility_table[ACCESSIBILITY_MAX] = { + [NEGATIVE] = MDNIE_SET(NEGATIVE), + MDNIE_SET(COLOR_BLIND), + MDNIE_SET(SCREEN_CURTAIN), + MDNIE_SET(GRAYSCALE), + MDNIE_SET(GRAYSCALE_NEGATIVE), + MDNIE_SET(COLOR_BLIND_HBM), +}; + +struct mdnie_table hbm_table[HBM_MAX] = { + [HBM_ON] = MDNIE_SET(LOCAL_CE), + MDNIE_SET(LOCAL_CE_TEXT) +}; +#ifdef CONFIG_LCD_HMT +struct mdnie_table hmt_table[HMT_MDNIE_MAX] = { + [HMT_MDNIE_ON] = MDNIE_SET(HMT_3000K), + MDNIE_SET(HMT_4000K), + MDNIE_SET(HMT_5000K), + MDNIE_SET(HMT_6500K) +}; +#endif +struct mdnie_table tuning_table[SCENARIO_MAX][MODE_MAX] = { + { + MDNIE_SET(DYNAMIC_UI), + MDNIE_SET(STANDARD_UI), + MDNIE_SET(NATURAL_UI), + MDNIE_SET(MOVIE_UI), + MDNIE_SET(AUTO_UI) + }, { + MDNIE_SET(DYNAMIC_VIDEO), + MDNIE_SET(STANDARD_VIDEO), + MDNIE_SET(NATURAL_VIDEO), + MDNIE_SET(MOVIE_VIDEO), + MDNIE_SET(AUTO_VIDEO) + }, + [CAMERA_MODE] = { + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(CAMERA), + MDNIE_SET(AUTO_CAMERA) + }, + [GALLERY_MODE] = { + MDNIE_SET(DYNAMIC_GALLERY), + MDNIE_SET(STANDARD_GALLERY), + MDNIE_SET(NATURAL_GALLERY), + MDNIE_SET(MOVIE_GALLERY), + MDNIE_SET(AUTO_GALLERY) + }, { + MDNIE_SET(DYNAMIC_VT), + MDNIE_SET(STANDARD_VT), + MDNIE_SET(NATURAL_VT), + MDNIE_SET(MOVIE_VT), + MDNIE_SET(AUTO_VT) + }, { + MDNIE_SET(DYNAMIC_BROWSER), + MDNIE_SET(STANDARD_BROWSER), + MDNIE_SET(NATURAL_BROWSER), + MDNIE_SET(MOVIE_BROWSER), + MDNIE_SET(AUTO_BROWSER) + }, { + MDNIE_SET(DYNAMIC_EBOOK), + MDNIE_SET(STANDARD_EBOOK), + MDNIE_SET(NATURAL_EBOOK), + MDNIE_SET(MOVIE_EBOOK), + MDNIE_SET(AUTO_EBOOK) + }, { + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL), + MDNIE_SET(AUTO_EMAIL) + }, { + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8), + MDNIE_SET(HMT_GRAY_8) + }, { + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16), + MDNIE_SET(HMT_GRAY_16) + } +}; +#endif diff --git a/drivers/video/exynos/decon/panels/mdnie_lite_table_zero.h b/drivers/video/exynos/decon/panels/mdnie_lite_table_zero.h index 05600fcb69bf..14cdc80db870 100644 --- a/drivers/video/exynos/decon/panels/mdnie_lite_table_zero.h +++ b/drivers/video/exynos/decon/panels/mdnie_lite_table_zero.h @@ -5815,6 +5815,175 @@ static unsigned char COLOR_BLIND_1[] = { /* end */ }; +static unsigned char COLOR_BLIND_HBM_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_HBM_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + ////////////////// BROWSER ///////////////////// static unsigned char STANDARD_BROWSER_2[] = { /* start */ @@ -9050,7 +9219,8 @@ struct mdnie_table accessibility_table[ACCESSIBILITY_MAX] = { MDNIE_SET(COLOR_BLIND), MDNIE_SET(SCREEN_CURTAIN), MDNIE_SET(GRAYSCALE), - MDNIE_SET(GRAYSCALE_NEGATIVE) + MDNIE_SET(GRAYSCALE_NEGATIVE), + MDNIE_SET(COLOR_BLIND_HBM), }; struct mdnie_table hbm_table[HBM_MAX] = { diff --git a/drivers/video/exynos/decon/panels/mdnie_lite_table_zerof.h b/drivers/video/exynos/decon/panels/mdnie_lite_table_zerof.h index 3fb1d6803737..8ed31044a9f6 100644 --- a/drivers/video/exynos/decon/panels/mdnie_lite_table_zerof.h +++ b/drivers/video/exynos/decon/panels/mdnie_lite_table_zerof.h @@ -5815,6 +5815,175 @@ static unsigned char COLOR_BLIND_1[] = { /* end */ }; +static unsigned char COLOR_BLIND_HBM_2[] = { + /* start */ + 0xEB, + 0x01, //mdnie_en + 0x00, //data_width mask 00 0000 + 0x30, //ascr algo lce 10 10 10 +}; + +static unsigned char COLOR_BLIND_HBM_1[] = { + 0xEC, + 0x98, //lce_on gain 0 00 0000 + 0x24, //lce_color_gain 00 0000 + 0x10, //lce_scene_change_on scene_trans 0 0000 + 0x14, //lce_min_diff + 0xb3, //lce_illum_gain + 0x01, //lce_ref_offset 9 + 0x0e, + 0x01, //lce_ref_gain 9 + 0x00, + 0x66, //lce_block_size h v 000 000 + 0xfa, //lce_bright_th + 0x2d, //lce_bin_size_ratio + 0x03, //lce_dark_th 000 + 0x96, //lce_min_ref_offset + 0x00, //nr fa de cs gamma 0 0000 + 0xff, //nr_mask_th + 0x00, //de_gain 10 + 0x00, + 0x07, //de_maxplus 11 + 0xff, + 0x07, //de_maxminus 11 + 0xff, + 0x14, //fa_edge_th + 0x00, //fa_step_p 13 + 0x0a, + 0x00, //fa_step_n 13 + 0x32, + 0x01, //fa_max_de_gain 13 + 0xf4, + 0x0b, //fa_pcl_ppi 14 + 0x8a, + 0x6e, //fa_skin_cr + 0x99, //fa_skin_cb + 0x1b, //fa_dist_left + 0x17, //fa_dist_right + 0x14, //fa_dist_down + 0x1e, //fa_dist_up + 0x02, //fa_div_dist_left + 0x5f, + 0x02, //fa_div_dist_right + 0xc8, + 0x03, //fa_div_dist_down + 0x33, + 0x02, //fa_div_dist_up + 0x22, + 0x10, //fa_px_min_weight + 0x10, //fa_fr_min_weight + 0x07, //fa_skin_zone_w + 0x07, //fa_skin_zone_h + 0x20, //fa_os_cnt_10_co + 0x2d, //fa_os_cnt_20_co + 0x01, //cs_gain 10 + 0x00, + 0x00, //curve_1_b + 0x20, //curve_1_a + 0x00, //curve_2_b + 0x20, //curve_2_a + 0x00, //curve_3_b + 0x20, //curve_3_a + 0x00, //curve_4_b + 0x20, //curve_4_a + 0x02, //curve_5_b + 0x1b, //curve_5_a + 0x02, //curve_6_b + 0x1b, //curve_6_a + 0x02, //curve_7_b + 0x1b, //curve_7_a + 0x02, //curve_8_b + 0x1b, //curve_8_a + 0x09, //curve_9_b + 0xa6, //curve_9_a + 0x09, //curve10_b + 0xa6, //curve10_a + 0x09, //curve11_b + 0xa6, //curve11_a + 0x09, //curve12_b + 0xa6, //curve12_a + 0x00, //curve13_b + 0x20, //curve13_a + 0x00, //curve14_b + 0x20, //curve14_a + 0x00, //curve15_b + 0x20, //curve15_a + 0x00, //curve16_b + 0x20, //curve16_a + 0x00, //curve17_b + 0x20, //curve17_a + 0x00, //curve18_b + 0x20, //curve18_a + 0x00, //curve19_b + 0x20, //curve19_a + 0x00, //curve20_b + 0x20, //curve20_a + 0x00, //curve21_b + 0x20, //curve21_a + 0x00, //curve22_b + 0x20, //curve22_a + 0x00, //curve23_b + 0x20, //curve23_a + 0x00, //curve24_b + 0xFF, //curve24_a + 0x00, //linear_on ascr_skin_on strength 0 0 00000 + 0x67, //ascr_skin_cb + 0xa9, //ascr_skin_cr + 0x0c, //ascr_dist_up + 0x0c, //ascr_dist_down + 0x0c, //ascr_dist_right + 0x0c, //ascr_dist_left + 0x00, //ascr_div_up 20 + 0xaa, + 0xab, + 0x00, //ascr_div_down + 0xaa, + 0xab, + 0x00, //ascr_div_right + 0xaa, + 0xab, + 0x00, //ascr_div_left + 0xaa, + 0xab, + 0xd5, //ascr_skin_Rr + 0x2c, //ascr_skin_Rg + 0x2a, //ascr_skin_Rb + 0xff, //ascr_skin_Yr + 0xf5, //ascr_skin_Yg + 0x63, //ascr_skin_Yb + 0xfe, //ascr_skin_Mr + 0x4a, //ascr_skin_Mg + 0xff, //ascr_skin_Mb + 0xff, //ascr_skin_Wr + 0xf9, //ascr_skin_Wg + 0xf8, //ascr_skin_Wb + 0x00, //ascr_Cr + 0xff, //ascr_Rr + 0xff, //ascr_Cg + 0x00, //ascr_Rg + 0xff, //ascr_Cb + 0x00, //ascr_Rb + 0xff, //ascr_Mr + 0x00, //ascr_Gr + 0x00, //ascr_Mg + 0xff, //ascr_Gg + 0xff, //ascr_Mb + 0x00, //ascr_Gb + 0xff, //ascr_Yr + 0x00, //ascr_Br + 0xff, //ascr_Yg + 0x00, //ascr_Bg + 0x00, //ascr_Yb + 0xff, //ascr_Bb + 0xff, //ascr_Wr + 0x00, //ascr_Kr + 0xff, //ascr_Wg + 0x00, //ascr_Kg + 0xff, //ascr_Wb + 0x00, //ascr_Kb + /* end */ +}; + ////////////////// BROWSER ///////////////////// static unsigned char STANDARD_BROWSER_2[] = { /* start */ @@ -9050,7 +9219,8 @@ struct mdnie_table accessibility_table[ACCESSIBILITY_MAX] = { MDNIE_SET(COLOR_BLIND), MDNIE_SET(SCREEN_CURTAIN), MDNIE_SET(GRAYSCALE), - MDNIE_SET(GRAYSCALE_NEGATIVE) + MDNIE_SET(GRAYSCALE_NEGATIVE), + MDNIE_SET(COLOR_BLIND_HBM), }; struct mdnie_table hbm_table[HBM_MAX] = { diff --git a/drivers/video/exynos/decon/panels/panel_info.h b/drivers/video/exynos/decon/panels/panel_info.h index 6e35b9236b5e..74ad3277bce4 100644 --- a/drivers/video/exynos/decon/panels/panel_info.h +++ b/drivers/video/exynos/decon/panels/panel_info.h @@ -4,9 +4,15 @@ #if defined(CONFIG_PANEL_S6E3HA2_DYNAMIC) #include "s6e3ha2_s6e3ha0_wqhd_param.h" +#elif defined(CONFIG_PANEL_S6E3HA3_DYNAMIC) +#include "s6e3ha3_s6e3ha2_wqhd_param.h" + #elif defined(CONFIG_PANEL_S6E3HF2_DYNAMIC) #include "s6e3hf2_wqhd_param.h" +#elif defined(CONFIG_PANEL_S6E3HF3_DYNAMIC) +#include "s6e3ha3_s6e3ha2_wqhd_param.h" + #else #error "ERROR !! Check LCD Panel Header File" #endif diff --git a/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.c b/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.c index 60200a4a236d..56fe9bac1fea 100644 --- a/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.c +++ b/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_lcd_ctrl.c @@ -321,6 +321,29 @@ static const unsigned int hbm_interpolation_br_tbl[256] = { 527, 529, 531, 534, 536, 539, 541, 543, 546, 548, 550, 553, 555, 557, 560, 562, 565, 567, 569, 572, 574, 576, 579, 581, 583, 586, 588, 591, 593, 595, 598, 600 }; + +static const unsigned gallery_br_tbl[256] = { + 2, 2, 2, 3, 5, 6, 8, 10, 11, 13, 15, 16, 18, 20, 21, 23, + 25, 26, 28, 29, 32, 33, 34, 36, 38, 39, 41, 43, 44, 46, 48, 50, + 51, 53, 55, 56, 57, 60, 61, 62, 64, 66, 68, 69, 71, 73, 74, 76, + 78, 79, 81, 83, 84, 86, 88, 89, 91, 92, 94, 96, 97, 99, 101, 102, + 104, 106, 107, 109, 111, 112, 114, 116, 117, 119, 120, 123, 124, 125, 127, 129, + 130, 132, 134, 135, 137, 139, 141, 142, 144, 146, 147, 148, 151, 152, 153, 155, + 157, 159, 160, 162, 164, 165, 167, 169, 170, 172, 174, 175, 177, 179, 180, 182, + 183, 185, 187, 188, 190, 192, 193, 195, 197, 198, 200, 202, 203, 205, 207, 208, + 210, 211, 214, 215, 216, 218, 220, 221, 223, 225, 226, 228, 230, 232, 233, 235, + 237, 238, 239, 242, 243, 244, 246, 248, 250, 251, 253, 255, 256, 258, 260, 261, + 263, 265, 266, 268, 270, 271, 273, 274, 276, 278, 279, 281, 283, 284, 286, 288, + 289, 291, 293, 294, 296, 298, 299, 301, 302, 305, 306, 307, 309, 311, 312, 314, + 316, 317, 319, 321, 323, 324, 326, 328, 329, 330, 333, 334, 335, 337, 339, 341, + 342, 344, 346, 347, 349, 351, 352, 354, 356, 357, 359, 361, 362, 364, 365, 367, + 369, 370, 372, 374, 375, 377, 379, 380, 382, 384, 385, 387, 389, 390, 392, 393, + 396, 397, 398, 400, 402, 403, 405, 407, 408, 410, 412, 414, 415, 417, 419, 430, +}; + + + + static const short center_gamma[NUM_VREF][CI_MAX] = { {0x000, 0x000, 0x000}, {0x080, 0x080, 0x080}, @@ -404,13 +427,13 @@ struct SmtDimInfo dimming_info_RC[MAX_BR_INFO] = { // add hbm array /*hbm interpolation */ {.br = 382, .refBr = 382, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on {.br = 407, .refBr = 407, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 433, .refBr = 433, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 461, .refBr = 461, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 491, .refBr = 491, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 517, .refBr = 517, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 545, .refBr = 545, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on + {.br = 433, .refBr = 433, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps14, .elv = elv14, .way = W3}, // hbm is acl on + {.br = 461, .refBr = 461, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps15, .elv = elv15, .way = W3}, // hbm is acl on + {.br = 491, .refBr = 491, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps16, .elv = elv16, .way = W3}, // hbm is acl on + {.br = 517, .refBr = 517, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps17, .elv = elv17, .way = W3}, // hbm is acl on + {.br = 545, .refBr = 545, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps18, .elv = elv18, .way = W3}, // hbm is acl on /* hbm */ - {.br = 600, .refBr = 600, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W4}, // hbm is acl on + {.br = 600, .refBr = 600, .cGma = gma2p20, .rTbl = RCrtbl360nit, .cTbl = RCctbl360nit, .aid = aid1005, .elvCaps = elvCaps19, .elv = elv19, .way = W4}, // hbm is acl on }; @@ -487,13 +510,13 @@ struct SmtDimInfo dimming_info_RE[MAX_BR_INFO] = { // add hbm array /*hbm interpolation */ {.br = 382, .refBr = 382, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on {.br = 407, .refBr = 407, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 433, .refBr = 433, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 461, .refBr = 461, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 491, .refBr = 491, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 517, .refBr = 517, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on - {.br = 545, .refBr = 545, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W3}, // hbm is acl on + {.br = 433, .refBr = 433, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps14, .elv = elv14, .way = W3}, // hbm is acl on + {.br = 461, .refBr = 461, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps15, .elv = elv15, .way = W3}, // hbm is acl on + {.br = 491, .refBr = 491, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps16, .elv = elv16, .way = W3}, // hbm is acl on + {.br = 517, .refBr = 517, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps17, .elv = elv17, .way = W3}, // hbm is acl on + {.br = 545, .refBr = 545, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps18, .elv = elv18, .way = W3}, // hbm is acl on /* hbm */ - {.br = 600, .refBr = 600, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps13, .elv = elv13, .way = W4}, // hbm is acl on + {.br = 600, .refBr = 600, .cGma = gma2p20, .rTbl = RErtbl360nit, .cTbl = REctbl360nit, .aid = aid1005, .elvCaps = elvCaps19, .elv = elv19, .way = W4}, // hbm is acl on }; @@ -522,12 +545,56 @@ static int set_gamma_to_center(struct SmtDimInfo *brInfo) return ret; } +static int gammaToVolt255(int gamma) +{ + int ret; + + if (gamma > vreg_element_max[V255]) { + dsim_err("%s : gamma overflow : %d\n", __FUNCTION__, gamma); + gamma = vreg_element_max[V255]; + } + if (gamma < 0) { + dsim_err("%s : gamma undeflow : %d\n", __FUNCTION__, gamma); + gamma = 0; + } + + ret = (int)v255_trans_volt[gamma]; + + return ret; +} + +static int voltToGamma(int hbm_volt_table[][3], int* vt, int tp, int color) +{ + int ret; + int t1, t2; + unsigned long temp; + + if(tp == V3) + { + t1 = DOUBLE_MULTIPLE_VREGOUT - hbm_volt_table[V3][color]; + t2 = DOUBLE_MULTIPLE_VREGOUT - hbm_volt_table[V11][color]; + } + else + { + t1 = vt[color] - hbm_volt_table[tp][color]; + t2 = vt[color] - hbm_volt_table[tp + 1][color]; + } + + temp = ((unsigned long)t1 * (unsigned long)fix_const[tp].de) / (unsigned long)t2; + ret = temp - fix_const[tp].nu; -static int set_gamma_to_hbm(struct SmtDimInfo *brInfo, u8 *hbm) + return ret; + +} + +static int set_gamma_to_hbm(struct SmtDimInfo *brInfo, struct dim_data *dimData, u8 *hbm) { int ret = 0; unsigned int index = 0; unsigned char *result = brInfo->gamma; + int i, j, idx; + int temp = 0; + int voltTableHbm[NUM_VREF][CI_MAX]; memset(result, 0, OLED_CMD_GAMMA_CNT); @@ -535,6 +602,45 @@ static int set_gamma_to_hbm(struct SmtDimInfo *brInfo, u8 *hbm) memcpy(result+1, hbm, S6E3HA2_HBMGAMMA_LEN); + + memcpy(voltTableHbm[V0], dimData->volt[0], sizeof(voltTableHbm[V0])); + memcpy(voltTableHbm[V3], dimData->volt[1], sizeof(voltTableHbm[V3])); + memcpy(voltTableHbm[V11], dimData->volt[10], sizeof(voltTableHbm[V11])); + memcpy(voltTableHbm[V23], dimData->volt[26], sizeof(voltTableHbm[V23])); + memcpy(voltTableHbm[V35], dimData->volt[40], sizeof(voltTableHbm[V35])); + memcpy(voltTableHbm[V51], dimData->volt[56], sizeof(voltTableHbm[V51])); + memcpy(voltTableHbm[V87], dimData->volt[100], sizeof(voltTableHbm[V87])); + memcpy(voltTableHbm[V151], dimData->volt[173], sizeof(voltTableHbm[V151])); + memcpy(voltTableHbm[V203], dimData->volt[233], sizeof(voltTableHbm[V203])); + + + idx = 0; + for(i = CI_RED; i < CI_MAX; i++, idx += 2) { + temp = (hbm[idx] << 8) | (hbm[idx + 1]); + voltTableHbm[V255][i] = gammaToVolt255(temp + dimData->mtp[V255][i]); + } + + idx = 1; + for (i = V255; i >= V0; i--) { + for (j = 0; j < CI_MAX; j++) { + if (i == V255) { + idx += 2; + } else if(i == V0) { + idx++; + } else { + temp = voltToGamma(voltTableHbm, dimData->volt_vt, i, j) - dimData->mtp[i][j]; + if(temp <= 0) + temp = 0; + result[idx] = temp; + idx ++; + } + } + } + + dsim_info("============ TUNE HBM GAMMA ========== : \n"); + for (i= 0; i < S6E3HA2_HBMGAMMA_LEN; i ++) { + dsim_info("HBM GAMMA[%d] : %x\n", i, result[i]); + } return ret; } @@ -662,6 +768,7 @@ static int init_dimming(struct dsim_device *dsim, u8 *mtp, u8 *hbm) panel->dim_info = (void *)diminfo; panel->br_tbl = (unsigned int *)br_tbl; panel->hbm_inter_br_tbl = (unsigned int *)hbm_interpolation_br_tbl; + panel->gallery_br_tbl = (unsigned int*)gallery_br_tbl; panel->hbm_tbl = (unsigned char **)HBM_TABLE; panel->acl_cutoff_tbl = (unsigned char **)ACL_CUTOFF_TABLE; panel->acl_opr_tbl = (unsigned char **)ACL_OPR_TABLE; @@ -725,7 +832,7 @@ static int init_dimming(struct dsim_device *dsim, u8 *mtp, u8 *hbm) } } else if (method == DIMMING_METHOD_FILL_HBM) { - ret = set_gamma_to_hbm(&diminfo[i], hbm); + ret = set_gamma_to_hbm(&diminfo[i], dimming, hbm); if (ret) { dsim_err("%s : failed to get hbm gamma\n", __func__); goto error; @@ -1235,8 +1342,9 @@ static int s6e3ha2_wqhd_init(struct dsim_device *dsim) dsim_err("%s : fail to write CMD : SEQ_SINGLE_DSI_2\n", __func__); goto init_exit; } - +#ifdef CONFIG_LCD_HMT if(dsim->priv.hmt_on != HMT_ON) +#endif msleep(120); /* Common Setting */ diff --git a/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_param.h b/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_param.h index 7391f7734be6..4d3e343bc400 100644 --- a/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_param.h +++ b/drivers/video/exynos/decon/panels/s6e3ha2_s6e3ha0_wqhd_param.h @@ -437,7 +437,6 @@ enum { ACL_OPR_MAX }; - #ifdef CONFIG_LCD_HMT #define DEFAULT_HMT_BRIGHTNESS 162 #define HMT_OFF 0 @@ -502,4 +501,16 @@ static const unsigned char SEQ_HMT_AID_REVERSE2[] = { /* G.Param */ #endif +enum { + HBM_INTER_OFF = 0, + HBM_COLORBLIND_ON, + HBM_GALLERY_ON, +}; + +// 384 ~ 550 +static const char HBM_INTER_22TH_OFFSET[] = { + 0x02, 0x04, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 +}; + + #endif /* __S6E3HA0_PARAM_H__ */ diff --git a/drivers/video/exynos/decon/panels/s6e3ha2_wqhd_aid_dimming.h b/drivers/video/exynos/decon/panels/s6e3ha2_wqhd_aid_dimming.h index 11600f346e23..d50c49b9962e 100644 --- a/drivers/video/exynos/decon/panels/s6e3ha2_wqhd_aid_dimming.h +++ b/drivers/video/exynos/decon/panels/s6e3ha2_wqhd_aid_dimming.h @@ -14,534 +14,573 @@ #define __S6E3HA2_WQHD_AID_DIMMING_H__ // start of aid sheet in rev.C opmanual -static const signed char RCrtbl2nit[10] = {0, 28, 27, 28, 24, 20, 15, 12, 8, 0}; -static const signed char RCrtbl3nit[10] = {0, 27, 28, 27, 23, 20, 16, 13, 7, 0}; -static const signed char RCrtbl4nit[10] = {0, 27, 25, 23, 19, 17, 15, 11, 7, 0}; -static const signed char RCrtbl5nit[10] = {0, 25, 25, 22, 18, 16, 14, 11, 8, 0}; -static const signed char RCrtbl6nit[10] = {0, 25, 24, 21, 17, 16, 14, 11, 7, 0}; -static const signed char RCrtbl7nit[10] = {0, 25, 23, 20, 17, 15, 13, 10, 7, 0}; -static const signed char RCrtbl8nit[10] = {0, 24, 22, 19, 16, 14, 12, 10, 7, 0}; -static const signed char RCrtbl9nit[10] = {0, 23, 22, 19, 15, 14, 12, 9, 6, 0}; -static const signed char RCrtbl10nit[10] = {0, 23, 21, 18, 14, 13, 12, 9, 6, 0}; -static const signed char RCrtbl11nit[10] = {0, 20, 21, 17, 14, 13, 11, 9, 6, 0}; -static const signed char RCrtbl12nit[10] = {0, 19, 19, 16, 13, 12, 10, 8, 6, 0}; -static const signed char RCrtbl13nit[10] = {0, 19, 19, 16, 12, 12, 10, 8, 6, 0}; -static const signed char RCrtbl14nit[10] = {0, 19, 18, 15, 12, 12, 9, 8, 6, 0}; -static const signed char RCrtbl15nit[10] = {0, 19, 18, 15, 11, 11, 9, 8, 6, 0}; -static const signed char RCrtbl16nit[10] = {0, 16, 18, 15, 11, 11, 9, 7, 6, 0}; -static const signed char RCrtbl17nit[10] = {0, 16, 17, 14, 11, 11, 9, 7, 6, 0}; -static const signed char RCrtbl19nit[10] = {0, 16, 16, 13, 10, 10, 8, 7, 6, 0}; -static const signed char RCrtbl20nit[10] = {0, 16, 15, 13, 10, 9, 8, 7, 6, 0}; -static const signed char RCrtbl21nit[10] = {0, 15, 15, 12, 9, 9, 7, 7, 6, 0}; -static const signed char RCrtbl22nit[10] = {0, 15, 15, 12, 9, 8, 7, 7, 6, 0}; -static const signed char RCrtbl24nit[10] = {0, 14, 14, 11, 8, 8, 7, 6, 5, 0}; -static const signed char RCrtbl25nit[10] = {0, 13, 14, 11, 8, 8, 7, 6, 5, 0}; -static const signed char RCrtbl27nit[10] = {0, 13, 13, 10, 7, 7, 7, 6, 5, 0}; -static const signed char RCrtbl29nit[10] = {0, 12, 13, 10, 8, 7, 6, 6, 5, 0}; -static const signed char RCrtbl30nit[10] = {0, 12, 13, 10, 7, 7, 6, 5, 5, 0}; -static const signed char RCrtbl32nit[10] = {0, 12, 13, 10, 7, 7, 5, 5, 5, 0}; -static const signed char RCrtbl34nit[10] = {0, 10, 12, 9, 7, 6, 5, 5, 5, 0}; -static const signed char RCrtbl37nit[10] = {0, 10, 11, 8, 6, 7, 5, 5, 5, 0}; -static const signed char RCrtbl39nit[10] = {0, 9, 11, 8, 6, 6, 5, 5, 5, 0}; -static const signed char RCrtbl41nit[10] = {0, 11, 10, 8, 6, 5, 5, 5, 5, 0}; -static const signed char RCrtbl44nit[10] = {0, 9, 10, 7, 5, 5, 4, 5, 5, 0}; -static const signed char RCrtbl47nit[10] = {0, 10, 9, 7, 5, 5, 4, 5, 5, 0}; -static const signed char RCrtbl50nit[10] = {0, 8, 9, 7, 5, 5, 4, 5, 5, 0}; -static const signed char RCrtbl53nit[10] = {0, 9, 8, 6, 4, 4, 4, 5, 5, 0}; -static const signed char RCrtbl56nit[10] = {0, 8, 8, 6, 4, 4, 4, 5, 4, 0}; -static const signed char RCrtbl60nit[10] = {0, 8, 7, 5, 4, 4, 4, 5, 5, 0}; -static const signed char RCrtbl64nit[10] = {0, 9, 6, 5, 3, 3, 3, 4, 4, 0}; -static const signed char RCrtbl68nit[10] = {0, 9, 6, 4, 3, 3, 3, 4, 4, 0}; -static const signed char RCrtbl72nit[10] = {0, 7, 6, 5, 3, 3, 3, 4, 4, 0}; -static const signed char RCrtbl77nit[10] = {0, 8, 5, 4, 3, 3, 2, 3, 2, 0}; -static const signed char RCrtbl82nit[10] = {0, 4, 6, 4, 3, 3, 3, 4, 3, 0}; -static const signed char RCrtbl87nit[10] = {0, 4, 5, 3, 2, 2, 3, 5, 3, 0}; -static const signed char RCrtbl93nit[10] = {0, 5, 4, 3, 3, 2, 3, 4, 2, 0}; -static const signed char RCrtbl98nit[10] = {0, 6, 4, 3, 2, 2, 4, 4, 1, 0}; -static const signed char RCrtbl105nit[10] = {0, 5, 5, 3, 3, 2, 3, 5, 2, 0}; -static const signed char RCrtbl111nit[10] = {0, 5, 4, 3, 2, 1, 3, 2, 0, 0}; -static const signed char RCrtbl119nit[10] = {0, 4, 4, 2, 1, 2, 4, 4, 0, 0}; -static const signed char RCrtbl126nit[10] = {0, 6, 3, 2, 2, 3, 2, 4, 0, 0}; -static const signed char RCrtbl134nit[10] = {0, 5, 3, 2, 1, 3, 3, 3, 0, 0}; -static const signed char RCrtbl143nit[10] = {0, 4, 3, 2, 2, 3, 3, 5, 2, 0}; -static const signed char RCrtbl152nit[10] = {0, 4, 3, 2, 2, 2, 3, 3, 1, 0}; -static const signed char RCrtbl162nit[10] = {0, 1, 2, 1, 1, 1, 3, 3, 0, 0}; -static const signed char RCrtbl172nit[10] = {0, 3, 2, 2, 1, 1, 2, 3, 1, 0}; -static const signed char RCrtbl183nit[10] = {0, 0, 3, 1, 0, 0, 1, 2, 0, 0}; -static const signed char RCrtbl195nit[10] = {0, 2, 2, 1, 0, 0, 2, 2, 0, 0}; -static const signed char RCrtbl207nit[10] = {0, 4, 1, 1, 0, 0, 1, 2, 0, 0}; -static const signed char RCrtbl220nit[10] = {0, 3, 1, 1, 0, 0, 1, 2, 0, 0}; -static const signed char RCrtbl234nit[10] = {0, 3, 2, 1, 1, 1, 2, 1, 0, 0}; -static const signed char RCrtbl249nit[10] = {0, 1, 1, 1, 0, 1, 1, 2, 0, 0}; -static const signed char RCrtbl265nit[10] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0}; -static const signed char RCrtbl282nit[10] = {0, 3, 0, 1, 1, 1, 1, 1, -1, 0}; -static const signed char RCrtbl300nit[10] = {0, 3, 0, 0, 0, 1, 0, 0, -1, 0}; -static const signed char RCrtbl316nit[10] = {0, 2, 0, 0, 0, 0, 0, 0, -1, 0}; -static const signed char RCrtbl333nit[10] = {0, 0, 1, 0, -1, 0, -1, -1, -1, 0}; -static const signed char RCrtbl360nit[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCrtbl2nit[10] = {0, 28, 27, 28, 24, 20, 15, 12, 8, 0}; +static signed char RCrtbl3nit[10] = {0, 27, 28, 27, 23, 20, 16, 13, 7, 0}; +static signed char RCrtbl4nit[10] = {0, 27, 25, 23, 19, 17, 15, 11, 7, 0}; +static signed char RCrtbl5nit[10] = {0, 25, 25, 22, 18, 16, 14, 11, 8, 0}; +static signed char RCrtbl6nit[10] = {0, 25, 24, 21, 17, 16, 14, 11, 7, 0}; +static signed char RCrtbl7nit[10] = {0, 25, 23, 20, 17, 15, 13, 10, 7, 0}; +static signed char RCrtbl8nit[10] = {0, 24, 22, 19, 16, 14, 12, 10, 7, 0}; +static signed char RCrtbl9nit[10] = {0, 23, 22, 19, 15, 14, 12, 9, 6, 0}; +static signed char RCrtbl10nit[10] = {0, 23, 21, 18, 14, 13, 12, 9, 6, 0}; +static signed char RCrtbl11nit[10] = {0, 20, 21, 17, 14, 13, 11, 9, 6, 0}; +static signed char RCrtbl12nit[10] = {0, 19, 19, 16, 13, 12, 10, 8, 6, 0}; +static signed char RCrtbl13nit[10] = {0, 19, 19, 16, 12, 12, 10, 8, 6, 0}; +static signed char RCrtbl14nit[10] = {0, 19, 18, 15, 12, 12, 9, 8, 6, 0}; +static signed char RCrtbl15nit[10] = {0, 19, 18, 15, 11, 11, 9, 8, 6, 0}; +static signed char RCrtbl16nit[10] = {0, 16, 18, 15, 11, 11, 9, 7, 6, 0}; +static signed char RCrtbl17nit[10] = {0, 16, 17, 14, 11, 11, 9, 7, 6, 0}; +static signed char RCrtbl19nit[10] = {0, 16, 16, 13, 10, 10, 8, 7, 6, 0}; +static signed char RCrtbl20nit[10] = {0, 16, 15, 13, 10, 9, 8, 7, 6, 0}; +static signed char RCrtbl21nit[10] = {0, 15, 15, 12, 9, 9, 7, 7, 6, 0}; +static signed char RCrtbl22nit[10] = {0, 15, 15, 12, 9, 8, 7, 7, 6, 0}; +static signed char RCrtbl24nit[10] = {0, 14, 14, 11, 8, 8, 7, 6, 5, 0}; +static signed char RCrtbl25nit[10] = {0, 13, 14, 11, 8, 8, 7, 6, 5, 0}; +static signed char RCrtbl27nit[10] = {0, 13, 13, 10, 7, 7, 7, 6, 5, 0}; +static signed char RCrtbl29nit[10] = {0, 12, 13, 10, 8, 7, 6, 6, 5, 0}; +static signed char RCrtbl30nit[10] = {0, 12, 13, 10, 7, 7, 6, 5, 5, 0}; +static signed char RCrtbl32nit[10] = {0, 12, 13, 10, 7, 7, 5, 5, 5, 0}; +static signed char RCrtbl34nit[10] = {0, 10, 12, 9, 7, 6, 5, 5, 5, 0}; +static signed char RCrtbl37nit[10] = {0, 10, 11, 8, 6, 7, 5, 5, 5, 0}; +static signed char RCrtbl39nit[10] = {0, 9, 11, 8, 6, 6, 5, 5, 5, 0}; +static signed char RCrtbl41nit[10] = {0, 11, 10, 8, 6, 5, 5, 5, 5, 0}; +static signed char RCrtbl44nit[10] = {0, 9, 10, 7, 5, 5, 4, 5, 5, 0}; +static signed char RCrtbl47nit[10] = {0, 10, 9, 7, 5, 5, 4, 5, 5, 0}; +static signed char RCrtbl50nit[10] = {0, 8, 9, 7, 5, 5, 4, 5, 5, 0}; +static signed char RCrtbl53nit[10] = {0, 9, 8, 6, 4, 4, 4, 5, 5, 0}; +static signed char RCrtbl56nit[10] = {0, 8, 8, 6, 4, 4, 4, 5, 4, 0}; +static signed char RCrtbl60nit[10] = {0, 8, 7, 5, 4, 4, 4, 5, 5, 0}; +static signed char RCrtbl64nit[10] = {0, 9, 6, 5, 3, 3, 3, 4, 4, 0}; +static signed char RCrtbl68nit[10] = {0, 9, 6, 4, 3, 3, 3, 4, 4, 0}; +static signed char RCrtbl72nit[10] = {0, 7, 6, 5, 3, 3, 3, 4, 4, 0}; +static signed char RCrtbl77nit[10] = {0, 8, 5, 4, 3, 3, 2, 3, 2, 0}; +static signed char RCrtbl82nit[10] = {0, 4, 6, 4, 3, 3, 3, 4, 3, 0}; +static signed char RCrtbl87nit[10] = {0, 4, 5, 3, 2, 2, 3, 5, 3, 0}; +static signed char RCrtbl93nit[10] = {0, 5, 4, 3, 3, 2, 3, 4, 2, 0}; +static signed char RCrtbl98nit[10] = {0, 6, 4, 3, 2, 2, 4, 4, 1, 0}; +static signed char RCrtbl105nit[10] = {0, 5, 5, 3, 3, 2, 3, 5, 2, 0}; +static signed char RCrtbl111nit[10] = {0, 5, 4, 3, 2, 1, 3, 2, 0, 0}; +static signed char RCrtbl119nit[10] = {0, 4, 4, 2, 1, 2, 4, 4, 0, 0}; +static signed char RCrtbl126nit[10] = {0, 6, 3, 2, 2, 3, 2, 4, 0, 0}; +static signed char RCrtbl134nit[10] = {0, 5, 3, 2, 1, 3, 3, 3, 0, 0}; +static signed char RCrtbl143nit[10] = {0, 4, 3, 2, 2, 3, 3, 5, 2, 0}; +static signed char RCrtbl152nit[10] = {0, 4, 3, 2, 2, 2, 3, 3, 1, 0}; +static signed char RCrtbl162nit[10] = {0, 1, 2, 1, 1, 1, 3, 3, 0, 0}; +static signed char RCrtbl172nit[10] = {0, 3, 2, 2, 1, 1, 2, 3, 1, 0}; +static signed char RCrtbl183nit[10] = {0, 0, 3, 1, 0, 0, 1, 2, 0, 0}; +static signed char RCrtbl195nit[10] = {0, 2, 2, 1, 0, 0, 2, 2, 0, 0}; +static signed char RCrtbl207nit[10] = {0, 4, 1, 1, 0, 0, 1, 2, 0, 0}; +static signed char RCrtbl220nit[10] = {0, 3, 1, 1, 0, 0, 1, 2, 0, 0}; +static signed char RCrtbl234nit[10] = {0, 3, 2, 1, 1, 1, 2, 1, 0, 0}; +static signed char RCrtbl249nit[10] = {0, 1, 1, 1, 0, 1, 1, 2, 0, 0}; +static signed char RCrtbl265nit[10] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0}; +static signed char RCrtbl282nit[10] = {0, 3, 0, 1, 1, 1, 1, 1, -1, 0}; +static signed char RCrtbl300nit[10] = {0, 3, 0, 0, 0, 1, 0, 0, -1, 0}; +static signed char RCrtbl316nit[10] = {0, 2, 0, 0, 0, 0, 0, 0, -1, 0}; +static signed char RCrtbl333nit[10] = {0, 0, 1, 0, -1, 0, -1, -1, -1, 0}; +static signed char RCrtbl360nit[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl2nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, -4, 0, 1, -3, -4, 2, -5, -1, 1, -3, -1, 0, -2, -1, 0, -1, -9, 1, -9}; -static const signed char RCctbl3nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, -4, -2, 1, -5, -3, 1, -5, -3, 1, -4, -2, 0, -3, -2, 0, -2, -7, 1, -7}; -static const signed char RCctbl4nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, -1, 0, -5, -1, 1, -4, -3, 1, -6, -2, 0, -4, -1, 0, -2, -2, 0, -2, -6, 1, -6}; -static const signed char RCctbl5nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, -1, 0, -5, 0, 2, -2, -1, 2, -6, -3, 1, -4, -1, 0, -2, -2, 0, -1, -5, 1, -5}; -static const signed char RCctbl6nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, -1, 0, -5, 0, 2, -3, -1, 2, -6, -3, 1, -3, -1, 0, -2, -1, 0, -2, -5, 1, -5}; -static const signed char RCctbl7nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -2, 0, 1, -5, -2, 0, -4, -1, 2, -7, -3, 0, -4, -1, 0, -1, -1, 0, -2, -4, 1, -4}; -static const signed char RCctbl8nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, 0, 2, -4, -2, 0, -5, 0, 2, -6, -3, 0, -3, -1, 0, -2, -1, 0, -1, -5, 0, -5}; -static const signed char RCctbl9nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -5, -2, 0, -5, 0, 1, -5, -1, 2, -5, -3, 1, -3, -1, 0, -2, -1, 0, -1, -4, 0, -4}; -static const signed char RCctbl10nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -5, -1, 0, -6, -1, 1, -4, -1, 2, -6, -3, 1, -3, 0, 0, -1, -1, 0, -1, -4, 0, -4}; -static const signed char RCctbl11nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, -5, 0, 2, -5, -1, 1, -5, -2, 1, -6, -2, 1, -3, 0, 0, -1, -1, 0, -1, -4, 0, -3}; -static const signed char RCctbl12nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -4, -1, 2, -5, 0, 1, -5, -1, 2, -4, -2, 0, -4, 0, 0, -1, -1, 0, -1, -4, 0, -3}; -static const signed char RCctbl13nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 2, -4, -1, 2, -6, -2, 1, -5, -2, 0, -4, 0, 0, -1, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl14nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -6, 0, 2, -4, 0, 2, -6, -2, 1, -5, -2, 0, -2, 0, 0, -1, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl15nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, 0, 1, -5, -2, 1, -6, -2, 1, -6, -1, 0, -1, 0, 0, -1, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl16nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, 0, 1, -4, 0, 1, -6, -2, 1, -5, -3, 0, -3, 0, 0, 0, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl17nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -6, -1, 1, -6, -1, 0, -6, -2, 1, -4, -2, 0, -3, 0, 0, 0, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl19nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, 0, 1, -6, -1, 1, -5, -2, 1, -6, -2, 0, -2, 0, 0, 0, -1, 0, -1, -3, 0, -2}; -static const signed char RCctbl20nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -9, -1, 1, -5, 0, 1, -4, -3, 1, -5, -2, 0, -2, 0, 0, -1, 0, 0, 0, -3, 0, -2}; -static const signed char RCctbl21nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 1, -6, -1, 1, -5, -2, 1, -4, -2, 0, -2, 0, 0, -1, 0, 0, 0, -3, 0, -2}; -static const signed char RCctbl22nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 1, -6, -2, 1, -4, -2, 1, -5, -1, 0, -2, 0, 0, 0, -1, 0, -1, -2, 0, -1}; -static const signed char RCctbl24nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -1, 1, -6, -2, 1, -5, -2, 1, -5, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; -static const signed char RCctbl25nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -8, -2, 0, -7, -2, 1, -5, -2, 0, -5, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; -static const signed char RCctbl27nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -9, -2, 1, -6, -2, 1, -4, -1, 0, -4, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; -static const signed char RCctbl29nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -2, 1, -7, -2, 1, -4, -2, 0, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl30nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -3, 0, -7, -2, 0, -4, -2, 0, -5, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl32nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, -9, -3, 0, -7, -2, 0, -4, -2, 0, -4, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl34nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -7, -2, 1, -7, -2, 0, -3, -3, 0, -5, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl37nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -2, 1, -6, -2, 0, -2, -1, 0, -4, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl39nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -9, -2, 1, -6, -2, 0, -3, -2, 0, -4, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; -static const signed char RCctbl41nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -12, -1, 1, -6, -1, 0, -3, -1, 0, -4, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, 0}; -static const signed char RCctbl44nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 1, -7, -3, 0, -2, -2, 0, -5, 0, 0, 0, 0, 0, -1, -1, 0, 0, -2, 0, 0}; -static const signed char RCctbl47nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -10, -1, 1, -5, -3, 0, -3, -2, 0, -4, 0, 0, 0, 0, 0, 0, -1, 0, -1, -2, 0, 0}; -static const signed char RCctbl50nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 1, -5, -2, 0, -2, -2, 0, -4, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0}; -static const signed char RCctbl53nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -10, -1, 1, -5, -2, 1, -3, -1, 0, -3, -1, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0}; -static const signed char RCctbl56nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -2, 1, -5, -2, 0, -3, -1, 0, -3, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; -static const signed char RCctbl60nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -8, -2, 1, -6, -3, 0, -3, 0, 0, -2, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0}; -static const signed char RCctbl64nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -10, -2, 1, -4, -1, 1, -1, -1, 0, -3, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0}; -static const signed char RCctbl68nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -2, 1, -6, -2, 0, -1, 0, 0, -3, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; -static const signed char RCctbl72nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 0, -5, -2, 0, -2, 0, 0, -2, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0}; -static const signed char RCctbl77nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -9, -3, 0, -5, -1, 0, -2, 0, 0, -2, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl82nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -8, -1, 1, -3, -1, 0, -2, 1, 0, -2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0}; -static const signed char RCctbl87nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -7, -2, 0, -5, -1, 0, -1, 1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl93nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -7, -2, 1, -3, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0}; -static const signed char RCctbl98nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -8, -2, 1, -3, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl105nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -8, -2, 0, -3, 0, 0, -2, 0, 0, -1, 1, 0, 1, 0, 0, 0, -2, 0, 0, 0, 0, 0}; -static const signed char RCctbl111nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -7, -2, 0, -3, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}; -static const signed char RCctbl119nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, -2, 1, -4, 0, 0, -1, 0, 0, -2, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl126nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, -2, 1, -4, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl134nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -8, -1, 0, -2, 0, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl143nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -7, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl152nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -6, -2, 0, -2, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0}; -static const signed char RCctbl162nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -5, -1, 0, -2, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char RCctbl172nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl183nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl195nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl207nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -5, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl220nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl234nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl249nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl265nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl282nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl300nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl316nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl333nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char RCctbl360nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl2nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, -4, 0, 1, -3, -4, 2, -5, -1, 1, -3, -1, 0, -2, -1, 0, -1, -9, 1, -9}; +static signed char RCctbl3nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, -4, -2, 1, -5, -3, 1, -5, -3, 1, -4, -2, 0, -3, -2, 0, -2, -7, 1, -7}; +static signed char RCctbl4nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, -1, 0, -5, -1, 1, -4, -3, 1, -6, -2, 0, -4, -1, 0, -2, -2, 0, -2, -6, 1, -6}; +static signed char RCctbl5nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, -1, 0, -5, 0, 2, -2, -1, 2, -6, -3, 1, -4, -1, 0, -2, -2, 0, -1, -5, 1, -5}; +static signed char RCctbl6nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, -1, 0, -5, 0, 2, -3, -1, 2, -6, -3, 1, -3, -1, 0, -2, -1, 0, -2, -5, 1, -5}; +static signed char RCctbl7nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -2, 0, 1, -5, -2, 0, -4, -1, 2, -7, -3, 0, -4, -1, 0, -1, -1, 0, -2, -4, 1, -4}; +static signed char RCctbl8nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -3, 0, 2, -4, -2, 0, -5, 0, 2, -6, -3, 0, -3, -1, 0, -2, -1, 0, -1, -5, 0, -5}; +static signed char RCctbl9nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -5, -2, 0, -5, 0, 1, -5, -1, 2, -5, -3, 1, -3, -1, 0, -2, -1, 0, -1, -4, 0, -4}; +static signed char RCctbl10nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -5, -1, 0, -6, -1, 1, -4, -1, 2, -6, -3, 1, -3, 0, 0, -1, -1, 0, -1, -4, 0, -4}; +static signed char RCctbl11nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, -5, 0, 2, -5, -1, 1, -5, -2, 1, -6, -2, 1, -3, 0, 0, -1, -1, 0, -1, -4, 0, -3}; +static signed char RCctbl12nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -4, -1, 2, -5, 0, 1, -5, -1, 2, -4, -2, 0, -4, 0, 0, -1, -1, 0, -1, -4, 0, -3}; +static signed char RCctbl13nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 2, -4, -1, 2, -6, -2, 1, -5, -2, 0, -4, 0, 0, -1, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl14nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -6, 0, 2, -4, 0, 2, -6, -2, 1, -5, -2, 0, -2, 0, 0, -1, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl15nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, 0, 1, -5, -2, 1, -6, -2, 1, -6, -1, 0, -1, 0, 0, -1, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl16nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, 0, 1, -4, 0, 1, -6, -2, 1, -5, -3, 0, -3, 0, 0, 0, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl17nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -6, -1, 1, -6, -1, 0, -6, -2, 1, -4, -2, 0, -3, 0, 0, 0, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl19nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, 0, 1, -6, -1, 1, -5, -2, 1, -6, -2, 0, -2, 0, 0, 0, -1, 0, -1, -3, 0, -2}; +static signed char RCctbl20nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -9, -1, 1, -5, 0, 1, -4, -3, 1, -5, -2, 0, -2, 0, 0, -1, 0, 0, 0, -3, 0, -2}; +static signed char RCctbl21nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 1, -6, -1, 1, -5, -2, 1, -4, -2, 0, -2, 0, 0, -1, 0, 0, 0, -3, 0, -2}; +static signed char RCctbl22nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -7, -1, 1, -6, -2, 1, -4, -2, 1, -5, -1, 0, -2, 0, 0, 0, -1, 0, -1, -2, 0, -1}; +static signed char RCctbl24nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -1, 1, -6, -2, 1, -5, -2, 1, -5, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; +static signed char RCctbl25nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -8, -2, 0, -7, -2, 1, -5, -2, 0, -5, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; +static signed char RCctbl27nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -9, -2, 1, -6, -2, 1, -4, -1, 0, -4, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, -1}; +static signed char RCctbl29nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -2, 1, -7, -2, 1, -4, -2, 0, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl30nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -3, 0, -7, -2, 0, -4, -2, 0, -5, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl32nit[30] = {0, 0, 0, 0, 0, 0,-1, 0, -9, -3, 0, -7, -2, 0, -4, -2, 0, -4, -1, 0, -1, -1, 0, -1, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl34nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -7, -2, 1, -7, -2, 0, -3, -3, 0, -5, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl37nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -9, -2, 1, -6, -2, 0, -2, -1, 0, -4, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl39nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -9, -2, 1, -6, -2, 0, -3, -2, 0, -4, -1, 0, 0, 0, 0, -1, 0, 0, 0, -2, 0, -1}; +static signed char RCctbl41nit[30] = {0, 0, 0, 0, 0, 0,0, 1, -12, -1, 1, -6, -1, 0, -3, -1, 0, -4, 0, 0, -1, 0, 0, 0, -1, 0, -1, -2, 0, 0}; +static signed char RCctbl44nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 1, -7, -3, 0, -2, -2, 0, -5, 0, 0, 0, 0, 0, -1, -1, 0, 0, -2, 0, 0}; +static signed char RCctbl47nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -10, -1, 1, -5, -3, 0, -3, -2, 0, -4, 0, 0, 0, 0, 0, 0, -1, 0, -1, -2, 0, 0}; +static signed char RCctbl50nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 1, -5, -2, 0, -2, -2, 0, -4, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0}; +static signed char RCctbl53nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -10, -1, 1, -5, -2, 1, -3, -1, 0, -3, -1, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0}; +static signed char RCctbl56nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -2, 1, -5, -2, 0, -3, -1, 0, -3, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; +static signed char RCctbl60nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -8, -2, 1, -6, -3, 0, -3, 0, 0, -2, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0}; +static signed char RCctbl64nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -10, -2, 1, -4, -1, 1, -1, -1, 0, -3, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0}; +static signed char RCctbl68nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -2, 1, -6, -2, 0, -1, 0, 0, -3, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; +static signed char RCctbl72nit[30] = {0, 0, 0, 0, 0, 0,0, 2, -9, -3, 0, -5, -2, 0, -2, 0, 0, -2, 0, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0}; +static signed char RCctbl77nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -9, -3, 0, -5, -1, 0, -2, 0, 0, -2, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl82nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -8, -1, 1, -3, -1, 0, -2, 1, 0, -2, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0}; +static signed char RCctbl87nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -7, -2, 0, -5, -1, 0, -1, 1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl93nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -7, -2, 1, -3, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, 0}; +static signed char RCctbl98nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -8, -2, 1, -3, 0, 0, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl105nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -8, -2, 0, -3, 0, 0, -2, 0, 0, -1, 1, 0, 1, 0, 0, 0, -2, 0, 0, 0, 0, 0}; +static signed char RCctbl111nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -7, -2, 0, -3, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}; +static signed char RCctbl119nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, -2, 1, -4, 0, 0, -1, 0, 0, -2, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl126nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -6, -2, 1, -4, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl134nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -8, -1, 0, -2, 0, 0, 0, 1, 0, -1, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl143nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -7, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl152nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -6, -2, 0, -2, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, -1, 0, 0, 0}; +static signed char RCctbl162nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -5, -1, 0, -2, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char RCctbl172nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl183nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl195nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -5, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl207nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -5, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl220nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl234nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl249nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl265nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl282nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl300nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl316nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl333nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RCctbl360nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char aid9821[3] = {0xB2, 0xE2, 0x90}; -static const signed char aid9717[3] = {0xB2, 0xC6, 0x90}; -static const signed char aid9639[3] = {0xB2, 0xB3, 0x90}; -static const signed char aid9538[3] = {0xB2, 0x96, 0x90}; -static const signed char aid9433[3] = {0xB2, 0x83, 0x90}; -static const signed char aid9387[3] = {0xB2, 0x67, 0x90}; -static const signed char aid9309[3] = {0xB2, 0x53, 0x90}; -static const signed char aid9216[3] = {0xB2, 0x3D, 0x90}; -static const signed char aid9123[3] = {0xB2, 0x27, 0x90}; -static const signed char aid9037[3] = {0xB2, 0x14, 0x90}; -static const signed char aid8998[3] = {0xB2, 0x00, 0x90}; -static const signed char aid8909[3] = {0xB2, 0xE7, 0x80}; -static const signed char aid8816[3] = {0xB2, 0xD4, 0x80}; -static const signed char aid8738[3] = {0xB2, 0xC5, 0x80}; -static const signed char aid8661[3] = {0xB2, 0xB1, 0x80}; -static const signed char aid8587[3] = {0xB2, 0x92, 0x80}; -static const signed char aid8412[3] = {0xB2, 0x68, 0x80}; -static const signed char aid8331[3] = {0xB2, 0x53, 0x80}; -static const signed char aid8245[3] = {0xB2, 0x3C, 0x80}; -static const signed char aid8160[3] = {0xB2, 0x27, 0x80}; -static const signed char aid7985[3] = {0xB2, 0xF7, 0x70}; -static const signed char aid7908[3] = {0xB2, 0xE2, 0x70}; -static const signed char aid7729[3] = {0xB2, 0xB6, 0x70}; -static const signed char aid7550[3] = {0xB2, 0x85, 0x70}; -static const signed char aid7473[3] = {0xB2, 0x71, 0x70}; -static const signed char aid7294[3] = {0xB2, 0x46, 0x70}; -static const signed char aid7116[3] = {0xB2, 0x17, 0x70}; -static const signed char aid6825[3] = {0xB2, 0xD2, 0x60}; -static const signed char aid6669[3] = {0xB2, 0xA7, 0x60}; -static const signed char aid6495[3] = {0xB2, 0x75, 0x60}; -static const signed char aid6234[3] = {0xB2, 0x32, 0x60}; -static const signed char aid5974[3] = {0xB2, 0xE8, 0x50}; -static const signed char aid5683[3] = {0xB2, 0xAB, 0x50}; -static const signed char aid5388[3] = {0xB2, 0x64, 0x50}; -static const signed char aid5155[3] = {0xB2, 0x1E, 0x50}; -static const signed char aid4767[3] = {0xB2, 0xC3, 0x40}; -static const signed char aid4379[3] = {0xB2, 0x5C, 0x40}; -static const signed char aid3998[3] = {0xB2, 0x02, 0x40}; -static const signed char aid3630[3] = {0xB2, 0xA1, 0x30}; -static const signed char aid3141[3] = {0xB2, 0x1D, 0x30}; -static const signed char aid2663[3] = {0xB2, 0xA5, 0x20}; -static const signed char aid2120[3] = {0xB2, 0x18, 0x20}; -static const signed char aid1518[3] = {0xB2, 0x87, 0x10}; -static const signed char aid1005[3] = {0xB2, 0x03, 0x10}; +static signed char aid9821[3] = {0xB2, 0xE2, 0x90}; +static signed char aid9717[3] = {0xB2, 0xC6, 0x90}; +static signed char aid9639[3] = {0xB2, 0xB3, 0x90}; +static signed char aid9538[3] = {0xB2, 0x96, 0x90}; +static signed char aid9433[3] = {0xB2, 0x83, 0x90}; +static signed char aid9387[3] = {0xB2, 0x67, 0x90}; +static signed char aid9309[3] = {0xB2, 0x53, 0x90}; +static signed char aid9216[3] = {0xB2, 0x3D, 0x90}; +static signed char aid9123[3] = {0xB2, 0x27, 0x90}; +static signed char aid9037[3] = {0xB2, 0x14, 0x90}; +static signed char aid8998[3] = {0xB2, 0x00, 0x90}; +static signed char aid8909[3] = {0xB2, 0xE7, 0x80}; +static signed char aid8816[3] = {0xB2, 0xD4, 0x80}; +static signed char aid8738[3] = {0xB2, 0xC5, 0x80}; +static signed char aid8661[3] = {0xB2, 0xB1, 0x80}; +static signed char aid8587[3] = {0xB2, 0x92, 0x80}; +static signed char aid8412[3] = {0xB2, 0x68, 0x80}; +static signed char aid8331[3] = {0xB2, 0x53, 0x80}; +static signed char aid8245[3] = {0xB2, 0x3C, 0x80}; +static signed char aid8160[3] = {0xB2, 0x27, 0x80}; +static signed char aid7985[3] = {0xB2, 0xF7, 0x70}; +static signed char aid7908[3] = {0xB2, 0xE2, 0x70}; +static signed char aid7729[3] = {0xB2, 0xB6, 0x70}; +static signed char aid7550[3] = {0xB2, 0x85, 0x70}; +static signed char aid7473[3] = {0xB2, 0x71, 0x70}; +static signed char aid7294[3] = {0xB2, 0x46, 0x70}; +static signed char aid7116[3] = {0xB2, 0x17, 0x70}; +static signed char aid6825[3] = {0xB2, 0xD2, 0x60}; +static signed char aid6669[3] = {0xB2, 0xA7, 0x60}; +static signed char aid6495[3] = {0xB2, 0x75, 0x60}; +static signed char aid6234[3] = {0xB2, 0x32, 0x60}; +static signed char aid5974[3] = {0xB2, 0xE8, 0x50}; +static signed char aid5683[3] = {0xB2, 0xAB, 0x50}; +static signed char aid5388[3] = {0xB2, 0x64, 0x50}; +static signed char aid5155[3] = {0xB2, 0x1E, 0x50}; +static signed char aid4767[3] = {0xB2, 0xC3, 0x40}; +static signed char aid4379[3] = {0xB2, 0x5C, 0x40}; +static signed char aid3998[3] = {0xB2, 0x02, 0x40}; +static signed char aid3630[3] = {0xB2, 0xA1, 0x30}; +static signed char aid3141[3] = {0xB2, 0x1D, 0x30}; +static signed char aid2663[3] = {0xB2, 0xA5, 0x20}; +static signed char aid2120[3] = {0xB2, 0x18, 0x20}; +static signed char aid1518[3] = {0xB2, 0x87, 0x10}; +static signed char aid1005[3] = {0xB2, 0x03, 0x10}; // end of aid sheet in rev.C opmanual // start of aid sheet in rev.E opmanual -static const signed char RErtbl2nit[10] = {0, 29, 27, 26, 21, 18, 14, 11, 7, 0}; -static const signed char RErtbl3nit[10] = {0, 27, 26, 24, 20, 17, 14, 11, 7, 0}; -static const signed char RErtbl4nit[10] = {0, 31, 24, 21, 17, 15, 14, 11, 7, 0}; -static const signed char RErtbl5nit[10] = {0, 28, 24, 20, 17, 15, 14, 11, 7, 0}; -static const signed char RErtbl6nit[10] = {0, 25, 23, 20, 16, 15, 14, 11, 7, 0}; -static const signed char RErtbl7nit[10] = {0, 25, 23, 19, 15, 14, 12, 11, 7, 0}; -static const signed char RErtbl8nit[10] = {0, 25, 21, 18, 13, 13, 12, 10, 7, 0}; -static const signed char RErtbl9nit[10] = {0, 22, 21, 17, 13, 12, 12, 10, 7, 0}; -static const signed char RErtbl10nit[10] = {0, 22, 20, 16, 12, 11, 11, 9, 7, 0}; -static const signed char RErtbl11nit[10] = {0, 22, 19, 15, 11, 11, 10, 9, 6, 0}; -static const signed char RErtbl12nit[10] = {0, 17, 19, 15, 11, 10, 10, 8, 6, 0}; -static const signed char RErtbl13nit[10] = {0, 17, 18, 14, 10, 10, 9, 7, 6, 0}; -static const signed char RErtbl14nit[10] = {0, 17, 17, 14, 10, 10, 9, 8, 6, 0}; -static const signed char RErtbl15nit[10] = {0, 17, 17, 14, 10, 10, 8, 8, 6, 0}; -static const signed char RErtbl16nit[10] = {0, 17, 16, 12, 10, 9, 8, 8, 6, 0}; -static const signed char RErtbl17nit[10] = {0, 17, 16, 12, 9, 9, 8, 7, 6, 0}; -static const signed char RErtbl19nit[10] = {0, 14, 15, 11, 8, 8, 7, 7, 6, 0}; -static const signed char RErtbl20nit[10] = {0, 14, 14, 11, 8, 8, 7, 7, 6, 0}; -static const signed char RErtbl21nit[10] = {0, 14, 14, 10, 8, 8, 7, 7, 6, 0}; -static const signed char RErtbl22nit[10] = {0, 14, 14, 10, 8, 8, 7, 7, 6, 0}; -static const signed char RErtbl24nit[10] = {0, 14, 13, 9, 7, 7, 7, 7, 6, 0}; -static const signed char RErtbl25nit[10] = {0, 14, 13, 8, 6, 6, 6, 7, 6, 0}; -static const signed char RErtbl27nit[10] = {0, 14, 12, 8, 6, 6, 6, 7, 6, 0}; -static const signed char RErtbl29nit[10] = {0, 11, 12, 8, 6, 6, 7, 7, 6, 0}; -static const signed char RErtbl30nit[10] = {0, 11, 12, 8, 6, 6, 6, 7, 6, 0}; -static const signed char RErtbl32nit[10] = {0, 10, 11, 8, 6, 6, 6, 6, 5, 0}; -static const signed char RErtbl34nit[10] = {0, 10, 11, 7, 5, 5, 5, 6, 5, 0}; -static const signed char RErtbl37nit[10] = {0, 10, 10, 7, 5, 5, 5, 6, 5, 0}; -static const signed char RErtbl39nit[10] = {0, 10, 10, 7, 5, 5, 5, 6, 5, 0}; -static const signed char RErtbl41nit[10] = {0, 10, 9, 7, 5, 5, 5, 5, 5, 0}; -static const signed char RErtbl44nit[10] = {0, 9, 9, 6, 4, 4, 5, 5, 5, 0}; -static const signed char RErtbl47nit[10] = {0, 7, 8, 6, 4, 4, 5, 5, 5, 0}; -static const signed char RErtbl50nit[10] = {0, 6, 8, 6, 4, 4, 5, 5, 5, 0}; -static const signed char RErtbl53nit[10] = {0, 6, 8, 5, 3, 4, 5, 5, 5, 0}; -static const signed char RErtbl56nit[10] = {0, 6, 7, 5, 3, 4, 4, 6, 5, 0}; -static const signed char RErtbl60nit[10] = {0, 4, 7, 5, 3, 4, 5, 5, 5, 0}; -static const signed char RErtbl64nit[10] = {0, 4, 7, 5, 3, 3, 4, 6, 5, 0}; -static const signed char RErtbl68nit[10] = {0, 4, 6, 5, 3, 3, 4, 5, 5, 0}; -static const signed char RErtbl72nit[10] = {0, 3, 6, 4, 2, 3, 4, 5, 4, 0}; -static const signed char RErtbl77nit[10] = {0, 3, 5, 3, 3, 2, 3, 6, 4, 0}; -static const signed char RErtbl82nit[10] = {0, 1, 6, 4, 3, 3, 4, 5, 3, 0}; -static const signed char RErtbl87nit[10] = {0, 3, 5, 4, 3, 3, 4, 4, 3, 0}; -static const signed char RErtbl93nit[10] = {0, 2, 7, 5, 4, 4, 5, 5, 2, 0}; -static const signed char RErtbl98nit[10] = {0, 1, 5, 3, 2, 2, 4, 5, 3, 0}; -static const signed char RErtbl105nit[10] = {0, 2, 5, 3, 3, 3, 4, 5, 2, 0}; -static const signed char RErtbl111nit[10] = {0, 2, 5, 3, 2, 3, 4, 4, 2, 0}; -static const signed char RErtbl119nit[10] = {0, 2, 4, 2, 2, 2, 4, 5, 0, 0}; -static const signed char RErtbl126nit[10] = {0, 3, 3, 3, 2, 2, 3, 5, 0, 0}; -static const signed char RErtbl134nit[10] = {0, 2, 4, 2, 2, 2, 3, 5, 1, 0}; -static const signed char RErtbl143nit[10] = {0, 3, 6, 3, 2, 4, 4, 5, 1, 0}; -static const signed char RErtbl152nit[10] = {0, 1, 3, 2, 2, 2, 5, 5, 1, 0}; -static const signed char RErtbl162nit[10] = {0, 1, 2, 1, 2, 2, 3, 3, 1, 0}; -static const signed char RErtbl172nit[10] = {0, 0, 3, 2, 2, 3, 4, 4, 2, 0}; -static const signed char RErtbl183nit[10] = {0, 3, 3, 1, 1, 2, 4, 4, 1, 0}; -static const signed char RErtbl195nit[10] = {0, 4, 2, 2, 1, 1, 4, 3, 0, 0}; -static const signed char RErtbl207nit[10] = {0, 0, 2, 1, 1, 1, 2, 2, 0, 0}; -static const signed char RErtbl220nit[10] = {0, 0, 2, 1, 1, 1, 2, 2, 0, 0}; -static const signed char RErtbl234nit[10] = {0, 2, 1, 1, 1, 1, 2, 2, 0, 0}; -static const signed char RErtbl249nit[10] = {0, 0, 1, 1, 0, 1, 2, 1, -1, 0}; -static const signed char RErtbl265nit[10] = {0, 0, 1, 1, 1, 0, 1, 1, 0, 0}; -static const signed char RErtbl282nit[10] = {0, 0, 0, 0, 0, 1, 0, 0, -1, 0}; -static const signed char RErtbl300nit[10] = {0, 0, 0, 0, 0, 1, 1, 0, 0, 0}; -static const signed char RErtbl316nit[10] = {0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; -static const signed char RErtbl333nit[10] = {0, 0, 1, -1, -1, 0, 0, 0, 0, 0}; -static const signed char RErtbl360nit[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char RErtbl2nit[10] = {0, 29, 27, 26, 21, 18, 14, 11, 7, 0}; +static signed char RErtbl3nit[10] = {0, 27, 26, 24, 20, 17, 14, 11, 7, 0}; +static signed char RErtbl4nit[10] = {0, 31, 24, 21, 17, 15, 14, 11, 7, 0}; +static signed char RErtbl5nit[10] = {0, 28, 24, 20, 17, 15, 14, 11, 7, 0}; +static signed char RErtbl6nit[10] = {0, 25, 23, 20, 16, 15, 14, 11, 7, 0}; +static signed char RErtbl7nit[10] = {0, 25, 23, 19, 15, 14, 12, 11, 7, 0}; +static signed char RErtbl8nit[10] = {0, 25, 21, 18, 13, 13, 12, 10, 7, 0}; +static signed char RErtbl9nit[10] = {0, 22, 21, 17, 13, 12, 12, 10, 7, 0}; +static signed char RErtbl10nit[10] = {0, 22, 20, 16, 12, 11, 11, 9, 7, 0}; +static signed char RErtbl11nit[10] = {0, 22, 19, 15, 11, 11, 10, 9, 6, 0}; +static signed char RErtbl12nit[10] = {0, 17, 19, 15, 11, 10, 10, 8, 6, 0}; +static signed char RErtbl13nit[10] = {0, 17, 18, 14, 10, 10, 9, 7, 6, 0}; +static signed char RErtbl14nit[10] = {0, 17, 17, 14, 10, 10, 9, 8, 6, 0}; +static signed char RErtbl15nit[10] = {0, 17, 17, 14, 10, 10, 8, 8, 6, 0}; +static signed char RErtbl16nit[10] = {0, 17, 16, 12, 10, 9, 8, 8, 6, 0}; +static signed char RErtbl17nit[10] = {0, 17, 16, 12, 9, 9, 8, 7, 6, 0}; +static signed char RErtbl19nit[10] = {0, 14, 15, 11, 8, 8, 7, 7, 6, 0}; +static signed char RErtbl20nit[10] = {0, 14, 14, 11, 8, 8, 7, 7, 6, 0}; +static signed char RErtbl21nit[10] = {0, 14, 14, 10, 8, 8, 7, 7, 6, 0}; +static signed char RErtbl22nit[10] = {0, 14, 14, 10, 8, 8, 7, 7, 6, 0}; +static signed char RErtbl24nit[10] = {0, 14, 13, 9, 7, 7, 7, 7, 6, 0}; +static signed char RErtbl25nit[10] = {0, 14, 13, 8, 6, 6, 6, 7, 6, 0}; +static signed char RErtbl27nit[10] = {0, 14, 12, 8, 6, 6, 6, 7, 6, 0}; +static signed char RErtbl29nit[10] = {0, 11, 12, 8, 6, 6, 7, 7, 6, 0}; +static signed char RErtbl30nit[10] = {0, 11, 12, 8, 6, 6, 6, 7, 6, 0}; +static signed char RErtbl32nit[10] = {0, 10, 11, 8, 6, 6, 6, 6, 5, 0}; +static signed char RErtbl34nit[10] = {0, 10, 11, 7, 5, 5, 5, 6, 5, 0}; +static signed char RErtbl37nit[10] = {0, 10, 10, 7, 5, 5, 5, 6, 5, 0}; +static signed char RErtbl39nit[10] = {0, 10, 10, 7, 5, 5, 5, 6, 5, 0}; +static signed char RErtbl41nit[10] = {0, 10, 9, 7, 5, 5, 5, 5, 5, 0}; +static signed char RErtbl44nit[10] = {0, 9, 9, 6, 4, 4, 5, 5, 5, 0}; +static signed char RErtbl47nit[10] = {0, 7, 8, 6, 4, 4, 5, 5, 5, 0}; +static signed char RErtbl50nit[10] = {0, 6, 8, 6, 4, 4, 5, 5, 5, 0}; +static signed char RErtbl53nit[10] = {0, 6, 8, 5, 3, 4, 5, 5, 5, 0}; +static signed char RErtbl56nit[10] = {0, 6, 7, 5, 3, 4, 4, 6, 5, 0}; +static signed char RErtbl60nit[10] = {0, 4, 7, 5, 3, 4, 5, 5, 5, 0}; +static signed char RErtbl64nit[10] = {0, 4, 7, 5, 3, 3, 4, 6, 5, 0}; +static signed char RErtbl68nit[10] = {0, 4, 6, 5, 3, 3, 4, 5, 5, 0}; +static signed char RErtbl72nit[10] = {0, 3, 6, 4, 2, 3, 4, 5, 4, 0}; +static signed char RErtbl77nit[10] = {0, 3, 5, 3, 3, 2, 3, 6, 4, 0}; +static signed char RErtbl82nit[10] = {0, 1, 6, 4, 3, 3, 4, 5, 3, 0}; +static signed char RErtbl87nit[10] = {0, 3, 5, 4, 3, 3, 4, 4, 3, 0}; +static signed char RErtbl93nit[10] = {0, 2, 7, 5, 4, 4, 5, 5, 2, 0}; +static signed char RErtbl98nit[10] = {0, 1, 5, 3, 2, 2, 4, 5, 3, 0}; +static signed char RErtbl105nit[10] = {0, 2, 5, 3, 3, 3, 4, 5, 2, 0}; +static signed char RErtbl111nit[10] = {0, 2, 5, 3, 2, 3, 4, 4, 2, 0}; +static signed char RErtbl119nit[10] = {0, 2, 4, 2, 2, 2, 4, 5, 0, 0}; +static signed char RErtbl126nit[10] = {0, 3, 3, 3, 2, 2, 3, 5, 0, 0}; +static signed char RErtbl134nit[10] = {0, 2, 4, 2, 2, 2, 3, 5, 1, 0}; +static signed char RErtbl143nit[10] = {0, 3, 6, 3, 2, 4, 4, 5, 1, 0}; +static signed char RErtbl152nit[10] = {0, 1, 3, 2, 2, 2, 5, 5, 1, 0}; +static signed char RErtbl162nit[10] = {0, 1, 2, 1, 2, 2, 3, 3, 1, 0}; +static signed char RErtbl172nit[10] = {0, 0, 3, 2, 2, 3, 4, 4, 2, 0}; +static signed char RErtbl183nit[10] = {0, 3, 3, 1, 1, 2, 4, 4, 1, 0}; +static signed char RErtbl195nit[10] = {0, 4, 2, 2, 1, 1, 4, 3, 0, 0}; +static signed char RErtbl207nit[10] = {0, 0, 2, 1, 1, 1, 2, 2, 0, 0}; +static signed char RErtbl220nit[10] = {0, 0, 2, 1, 1, 1, 2, 2, 0, 0}; +static signed char RErtbl234nit[10] = {0, 2, 1, 1, 1, 1, 2, 2, 0, 0}; +static signed char RErtbl249nit[10] = {0, 0, 1, 1, 0, 1, 2, 1, -1, 0}; +static signed char RErtbl265nit[10] = {0, 0, 1, 1, 1, 0, 1, 1, 0, 0}; +static signed char RErtbl282nit[10] = {0, 0, 0, 0, 0, 1, 0, 0, -1, 0}; +static signed char RErtbl300nit[10] = {0, 0, 0, 0, 0, 1, 1, 0, 0, 0}; +static signed char RErtbl316nit[10] = {0, 0, 0, 0, -1, 0, 0, -1, 0, 0}; +static signed char RErtbl333nit[10] = {0, 0, 1, -1, -1, 0, 0, 0, 0, 0}; +static signed char RErtbl360nit[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl2nit[30] = {0, 0, 0, 0, 0, 0,-4, 0, 0, -4, 0, -4, -6, 1, -5, -9, 1, -4, -4, 0, -3, -3, 0, -1, -1, 0, -1, -7, 0, -6}; -static const signed char REctbl3nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -2, -5, 0, -5, -6, 0, -6, -7, 1, -5, -5, 0, -3, -2, 0, -2, -2, 0, -1, -5, 0, -5}; -static const signed char REctbl4nit[30] = {0, 0, 0, 0, 0, 0,-4, 0, -5, -5, 0, -4, -7, 1, -6, -6, 1, -5, -3, 0, -2, -2, 0, -1, -2, 0, -1, -4, 0, -5}; -static const signed char REctbl5nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, -6, -6, 1, -8, -7, 0, -5, -5, 1, -5, -3, 0, -2, -2, 0, -2, -1, 0, -1, -4, 0, -5}; -static const signed char REctbl6nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -7, -5, 1, -5, -5, 1, -5, -4, 1, -5, -3, 0, -3, -2, 0, -1, -1, 0, -1, -3, 0, -4}; -static const signed char REctbl7nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -6, -5, 0, -7, -5, 1, -5, -5, 1, -6, -3, 1, -3, -1, 0, -1, -1, 0, 0, -3, 0, -3}; -static const signed char REctbl8nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -9, -4, 1, -5, -5, 1, -6, -5, 1, -6, -2, 1, -2, -2, 0, -1, -1, 0, -1, -3, 0, -3}; -static const signed char REctbl9nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -7, -5, 1, -7, -5, 1, -5, -4, 1, -6, -3, 0, -3, -1, 0, -1, -1, 0, 0, -2, 0, -3}; -static const signed char REctbl10nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -8, -4, 1, -7, -3, 1, -4, -5, 1, -6, -2, 0, -2, -2, 0, -1, 0, 0, -1, -2, 0, -2}; -static const signed char REctbl11nit[30] = {0, 0, 0, 0, 0, 0,-7, 1, -10, -3, 1, -6, -5, 1, -7, -4, 1, -5, -3, 0, -3, -1, 0, 0, 0, 0, -1, -2, 0, -2}; -static const signed char REctbl12nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -8, -3, 1, -5, -3, 1, -5, -3, 1, -5, -3, 0, -2, -1, 0, -1, -1, 0, 0, -1, 0, -2}; -static const signed char REctbl13nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -7, -4, 1, -7, -4, 1, -7, -3, 1, -4, -2, 0, -2, -1, 0, 0, -1, 0, 0, -1, 0, -1}; -static const signed char REctbl14nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -9, -3, 1, -5, -5, 1, -7, -3, 1, -4, -3, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; -static const signed char REctbl15nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -9, -3, 1, -5, -5, 1, -7, -3, 1, -4, -3, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; -static const signed char REctbl16nit[30] = {0, 0, 0, 0, 0, 0,-5, 2, -9, -4, 1, -8, -3, 1, -6, -4, 1, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; -static const signed char REctbl17nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -10, -4, 1, -7, -3, 1, -7, -4, 1, -4, -3, 0, -2, -1, 0, 0, 0, 0, 0, -1, 0, -1}; -static const signed char REctbl19nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -10, -3, 1, -6, -2, 1, -5, -4, 0, -4, -1, 0, -2, -1, 0, 0, 0, 0, 0, -1, 0, -1}; -static const signed char REctbl20nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -2, 1, -5, -3, 1, -5, -3, 0, -4, -1, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl21nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -4, 1, -8, -3, 1, -5, -4, 0, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl22nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -9, -4, 1, -7, -2, 1, -4, -3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl24nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -5, 1, -8, -2, 1, -4, -3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl25nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -7, -4, 1, -7, -2, 1, -4, -2, 1, -2, -1, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl27nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -11, -4, 1, -7, -2, 1, -4, -2, 0, -3, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl29nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -6, -3, 0, -4, -3, 1, -3, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1}; -static const signed char REctbl30nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -5, -3, 0, -4, -3, 0, -3, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl32nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -4, -2, 0, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl34nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -7, -3, 0, -3, -3, 0, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl37nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -10, -3, 1, -6, -2, 0, -2, -3, 0, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl39nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -11, -3, 0, -6, -3, 0, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl41nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -12, -4, 0, -6, -2, 0, -2, -2, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl44nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -9, -3, 0, -4, -2, 0, -2, -2, 0, -3, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl47nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -12, -3, 0, -4, -2, 0, -2, -1, 0, -2, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl50nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -3, 0, -3, -2, 0, -2, -2, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl53nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 0, -5, -2, 0, -2, -2, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl56nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -11, -4, 0, -5, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl60nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 0, -4, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl64nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -9, -3, 0, -4, 0, 0, -1, -1, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl68nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -10, -2, 0, -3, -1, 0, -2, 0, 0, -1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl72nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -10, -2, 0, -3, -1, 0, -2, 0, 0, -2, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl77nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -9, -3, 0, -4, 0, 0, -1, -1, 0, -2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl82nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -8, -2, 0, -2, -2, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl87nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -10, -3, 0, -3, -1, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl93nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -10, -2, 0, -4, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl98nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -7, -2, 0, -2, -1, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl105nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -8, -2, 0, -2, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl111nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -7, -2, 0, -2, -1, 0, -1, -1, 0, -1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl119nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -6, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl126nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -7, -1, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl134nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -5, -1, 0, -1, -1, 0, 0, 0, 0, -1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl143nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -7, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl152nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -6, -1, 0, -2, 0, 0, 0, 0, 0, -1, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl162nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -6, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl172nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -5, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl183nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0}; -static const signed char REctbl195nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl207nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl220nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl234nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl249nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl265nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl282nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl300nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl316nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl333nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char REctbl360nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl2nit[30] = {0, 0, 0, 0, 0, 0,-4, 0, 0, -4, 0, -4, -6, 1, -5, -9, 1, -4, -4, 0, -3, -3, 0, -1, -1, 0, -1, -7, 0, -6}; +static signed char REctbl3nit[30] = {0, 0, 0, 0, 0, 0,0, 0, -2, -5, 0, -5, -6, 0, -6, -7, 1, -5, -5, 0, -3, -2, 0, -2, -2, 0, -1, -5, 0, -5}; +static signed char REctbl4nit[30] = {0, 0, 0, 0, 0, 0,-4, 0, -5, -5, 0, -4, -7, 1, -6, -6, 1, -5, -3, 0, -2, -2, 0, -1, -2, 0, -1, -4, 0, -5}; +static signed char REctbl5nit[30] = {0, 0, 0, 0, 0, 0,-5, 0, -6, -6, 1, -8, -7, 0, -5, -5, 1, -5, -3, 0, -2, -2, 0, -2, -1, 0, -1, -4, 0, -5}; +static signed char REctbl6nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -7, -5, 1, -5, -5, 1, -5, -4, 1, -5, -3, 0, -3, -2, 0, -1, -1, 0, -1, -3, 0, -4}; +static signed char REctbl7nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -6, -5, 0, -7, -5, 1, -5, -5, 1, -6, -3, 1, -3, -1, 0, -1, -1, 0, 0, -3, 0, -3}; +static signed char REctbl8nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -9, -4, 1, -5, -5, 1, -6, -5, 1, -6, -2, 1, -2, -2, 0, -1, -1, 0, -1, -3, 0, -3}; +static signed char REctbl9nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -7, -5, 1, -7, -5, 1, -5, -4, 1, -6, -3, 0, -3, -1, 0, -1, -1, 0, 0, -2, 0, -3}; +static signed char REctbl10nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -8, -4, 1, -7, -3, 1, -4, -5, 1, -6, -2, 0, -2, -2, 0, -1, 0, 0, -1, -2, 0, -2}; +static signed char REctbl11nit[30] = {0, 0, 0, 0, 0, 0,-7, 1, -10, -3, 1, -6, -5, 1, -7, -4, 1, -5, -3, 0, -3, -1, 0, 0, 0, 0, -1, -2, 0, -2}; +static signed char REctbl12nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -8, -3, 1, -5, -3, 1, -5, -3, 1, -5, -3, 0, -2, -1, 0, -1, -1, 0, 0, -1, 0, -2}; +static signed char REctbl13nit[30] = {0, 0, 0, 0, 0, 0,-6, 1, -7, -4, 1, -7, -4, 1, -7, -3, 1, -4, -2, 0, -2, -1, 0, 0, -1, 0, 0, -1, 0, -1}; +static signed char REctbl14nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -9, -3, 1, -5, -5, 1, -7, -3, 1, -4, -3, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; +static signed char REctbl15nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -9, -3, 1, -5, -5, 1, -7, -3, 1, -4, -3, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; +static signed char REctbl16nit[30] = {0, 0, 0, 0, 0, 0,-5, 2, -9, -4, 1, -8, -3, 1, -6, -4, 1, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, -1, 0, -1}; +static signed char REctbl17nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -10, -4, 1, -7, -3, 1, -7, -4, 1, -4, -3, 0, -2, -1, 0, 0, 0, 0, 0, -1, 0, -1}; +static signed char REctbl19nit[30] = {0, 0, 0, 0, 0, 0,-5, 1, -10, -3, 1, -6, -2, 1, -5, -4, 0, -4, -1, 0, -2, -1, 0, 0, 0, 0, 0, -1, 0, -1}; +static signed char REctbl20nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -2, 1, -5, -3, 1, -5, -3, 0, -4, -1, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl21nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -4, 1, -8, -3, 1, -5, -4, 0, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl22nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -9, -4, 1, -7, -2, 1, -4, -3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl24nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -5, 1, -8, -2, 1, -4, -3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl25nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -7, -4, 1, -7, -2, 1, -4, -2, 1, -2, -1, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl27nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -11, -4, 1, -7, -2, 1, -4, -2, 0, -3, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl29nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -6, -3, 0, -4, -3, 1, -3, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1}; +static signed char REctbl30nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -5, -3, 0, -4, -3, 0, -3, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl32nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -4, -2, 0, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl34nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 1, -7, -3, 0, -3, -3, 0, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl37nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -10, -3, 1, -6, -2, 0, -2, -3, 0, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl39nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -11, -3, 0, -6, -3, 0, -3, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl41nit[30] = {0, 0, 0, 0, 0, 0,-1, 2, -12, -4, 0, -6, -2, 0, -2, -2, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl44nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -9, -3, 0, -4, -2, 0, -2, -2, 0, -3, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl47nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -12, -3, 0, -4, -2, 0, -2, -1, 0, -2, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl50nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -10, -3, 0, -3, -2, 0, -2, -2, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl53nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 0, -5, -2, 0, -2, -2, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl56nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -11, -4, 0, -5, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl60nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -10, -3, 0, -4, -2, 0, -2, -1, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl64nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -9, -3, 0, -4, 0, 0, -1, -1, 0, -2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl68nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -10, -2, 0, -3, -1, 0, -2, 0, 0, -1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl72nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -10, -2, 0, -3, -1, 0, -2, 0, 0, -2, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl77nit[30] = {0, 0, 0, 0, 0, 0,-2, 2, -9, -3, 0, -4, 0, 0, -1, -1, 0, -2, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl82nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -8, -2, 0, -2, -2, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl87nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -10, -3, 0, -3, -1, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl93nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -10, -2, 0, -4, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl98nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -7, -2, 0, -2, -1, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0}; +static signed char REctbl105nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -8, -2, 0, -2, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl111nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -7, -2, 0, -2, -1, 0, -1, -1, 0, -1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl119nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -6, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl126nit[30] = {0, 0, 0, 0, 0, 0,-3, 2, -7, -1, 0, -1, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl134nit[30] = {0, 0, 0, 0, 0, 0,-2, 1, -5, -1, 0, -1, -1, 0, 0, 0, 0, -1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0}; +static signed char REctbl143nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -7, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl152nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -6, -1, 0, -2, 0, 0, 0, 0, 0, -1, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl162nit[30] = {0, 0, 0, 0, 0, 0,-4, 1, -6, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl172nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -5, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl183nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -3, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0}; +static signed char REctbl195nit[30] = {0, 0, 0, 0, 0, 0,-3, 1, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl207nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl220nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl234nit[30] = {0, 0, 0, 0, 0, 0,-1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl249nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl265nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl282nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl300nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl316nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl333nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char REctbl360nit[30] = {0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char aid9825[3] = {0xB2, 0xE3, 0x90}; -static const signed char aid9713[3] = {0xB2, 0xC6, 0x90}; -static const signed char aid9635[3] = {0xB2, 0xB2, 0x90}; -static const signed char aid9523[3] = {0xB2, 0x95, 0x90}; -static const signed char aid9445[3] = {0xB2, 0x81, 0x90}; -static const signed char aid9344[3] = {0xB2, 0x67, 0x90}; -static const signed char aid9270[3] = {0xB2, 0x54, 0x90}; -static const signed char aid9200[3] = {0xB2, 0x42, 0x90}; -static const signed char aid9130[3] = {0xB2, 0x30, 0x90}; -static const signed char aid9030[3] = {0xB2, 0x16, 0x90}; -static const signed char aid8964[3] = {0xB2, 0x05, 0x90}; -static const signed char aid8894[3] = {0xB2, 0xF3, 0x80}; -static const signed char aid8832[3] = {0xB2, 0xE3, 0x80}; -static const signed char aid8723[3] = {0xB2, 0xC7, 0x80}; -static const signed char aid8653[3] = {0xB2, 0xB5, 0x80}; -static const signed char aid8575[3] = {0xB2, 0xA1, 0x80}; -static const signed char aid8393[3] = {0xB2, 0x72, 0x80}; -static const signed char aid8284[3] = {0xB2, 0x56, 0x80}; -static const signed char aid8218[3] = {0xB2, 0x45, 0x80}; -static const signed char aid8148[3] = {0xB2, 0x33, 0x80}; -static const signed char aid7974[3] = {0xB2, 0x06, 0x80}; -static const signed char aid7896[3] = {0xB2, 0xF2, 0x70}; -static const signed char aid7717[3] = {0xB2, 0xC4, 0x70}; -static const signed char aid7535[3] = {0xB2, 0x95, 0x70}; -static const signed char aid7469[3] = {0xB2, 0x84, 0x70}; -static const signed char aid7290[3] = {0xB2, 0x56, 0x70}; -static const signed char aid7104[3] = {0xB2, 0x26, 0x70}; -static const signed char aid6848[3] = {0xB2, 0xE4, 0x60}; -// static const signed char aid6669[3] = {0xB2, 0xB6, 0x60}; defined in rev.C area -static const signed char aid6491[3] = {0xB2, 0x88, 0x60}; -static const signed char aid6231[3] = {0xB2, 0x45, 0x60}; -static const signed char aid5947[3] = {0xB2, 0xFC, 0x50}; -static const signed char aid5675[3] = {0xB2, 0xB6, 0x50}; -static const signed char aid5419[3] = {0xB2, 0x74, 0x50}; -static const signed char aid5140[3] = {0xB2, 0x2C, 0x50}; -static const signed char aid4752[3] = {0xB2, 0xC8, 0x40}; -static const signed char aid4383[3] = {0xB2, 0x69, 0x40}; -static const signed char aid4006[3] = {0xB2, 0x08, 0x40}; -static const signed char aid3622[3] = {0xB2, 0xA5, 0x30}; -static const signed char aid3133[3] = {0xB2, 0x27, 0x30}; -static const signed char aid2620[3] = {0xB2, 0xA3, 0x20}; -static const signed char aid2158[3] = {0xB2, 0x2C, 0x20}; -static const signed char aid1611[3] = {0xB2, 0x9F, 0x10}; -// static const signed char aid1005[3] = {0xB2, 0x03, 0x10}; defined in rev.C area +static signed char aid9825[3] = {0xB2, 0xE3, 0x90}; +static signed char aid9713[3] = {0xB2, 0xC6, 0x90}; +static signed char aid9635[3] = {0xB2, 0xB2, 0x90}; +static signed char aid9523[3] = {0xB2, 0x95, 0x90}; +static signed char aid9445[3] = {0xB2, 0x81, 0x90}; +static signed char aid9344[3] = {0xB2, 0x67, 0x90}; +static signed char aid9270[3] = {0xB2, 0x54, 0x90}; +static signed char aid9200[3] = {0xB2, 0x42, 0x90}; +static signed char aid9130[3] = {0xB2, 0x30, 0x90}; +static signed char aid9030[3] = {0xB2, 0x16, 0x90}; +static signed char aid8964[3] = {0xB2, 0x05, 0x90}; +static signed char aid8894[3] = {0xB2, 0xF3, 0x80}; +static signed char aid8832[3] = {0xB2, 0xE3, 0x80}; +static signed char aid8723[3] = {0xB2, 0xC7, 0x80}; +static signed char aid8653[3] = {0xB2, 0xB5, 0x80}; +static signed char aid8575[3] = {0xB2, 0xA1, 0x80}; +static signed char aid8393[3] = {0xB2, 0x72, 0x80}; +static signed char aid8284[3] = {0xB2, 0x56, 0x80}; +static signed char aid8218[3] = {0xB2, 0x45, 0x80}; +static signed char aid8148[3] = {0xB2, 0x33, 0x80}; +static signed char aid7974[3] = {0xB2, 0x06, 0x80}; +static signed char aid7896[3] = {0xB2, 0xF2, 0x70}; +static signed char aid7717[3] = {0xB2, 0xC4, 0x70}; +static signed char aid7535[3] = {0xB2, 0x95, 0x70}; +static signed char aid7469[3] = {0xB2, 0x84, 0x70}; +static signed char aid7290[3] = {0xB2, 0x56, 0x70}; +static signed char aid7104[3] = {0xB2, 0x26, 0x70}; +static signed char aid6848[3] = {0xB2, 0xE4, 0x60}; +// static signed char aid6669[3] = {0xB2, 0xB6, 0x60}; defined in rev.C area +static signed char aid6491[3] = {0xB2, 0x88, 0x60}; +static signed char aid6231[3] = {0xB2, 0x45, 0x60}; +static signed char aid5947[3] = {0xB2, 0xFC, 0x50}; +static signed char aid5675[3] = {0xB2, 0xB6, 0x50}; +static signed char aid5419[3] = {0xB2, 0x74, 0x50}; +static signed char aid5140[3] = {0xB2, 0x2C, 0x50}; +static signed char aid4752[3] = {0xB2, 0xC8, 0x40}; +static signed char aid4383[3] = {0xB2, 0x69, 0x40}; +static signed char aid4006[3] = {0xB2, 0x08, 0x40}; +static signed char aid3622[3] = {0xB2, 0xA5, 0x30}; +static signed char aid3133[3] = {0xB2, 0x27, 0x30}; +static signed char aid2620[3] = {0xB2, 0xA3, 0x20}; +static signed char aid2158[3] = {0xB2, 0x2C, 0x20}; +static signed char aid1611[3] = {0xB2, 0x9F, 0x10}; +// static signed char aid1005[3] = {0xB2, 0x03, 0x10}; defined in rev.C area // end of aid sheet in rev.E opmanual -static const unsigned char elv1[3] = { +static unsigned char elv1[3] = { 0xB6, 0x8C, 0x16 }; -static const unsigned char elv2[3] = { +static unsigned char elv2[3] = { 0xB6, 0x8C, 0x15 }; -static const unsigned char elv3[3] = { +static unsigned char elv3[3] = { 0xB6, 0x8C, 0x14 }; -static const unsigned char elv4[3] = { +static unsigned char elv4[3] = { 0xB6, 0x8C, 0x13 }; -static const unsigned char elv5[3] = { +static unsigned char elv5[3] = { 0xB6, 0x8C, 0x12 }; -static const unsigned char elv6[3] = { +static unsigned char elv6[3] = { 0xB6, 0x8C, 0x11 }; -static const unsigned char elv7[3] = { +static unsigned char elv7[3] = { 0xB6, 0x8C, 0x10 }; -static const unsigned char elv8[3] = { +static unsigned char elv8[3] = { 0xB6, 0x8C, 0x0F }; -static const unsigned char elv9[3] = { +static unsigned char elv9[3] = { 0xB6, 0x8C, 0x0E }; -static const unsigned char elv10[3] = { +static unsigned char elv10[3] = { 0xB6, 0x8C, 0x0D }; -static const unsigned char elv11[3] = { +static unsigned char elv11[3] = { 0xB6, 0x8C, 0x0C }; -static const unsigned char elv12[3] = { +static unsigned char elv12[3] = { 0xB6, 0x8C, 0x0B }; -static const unsigned char elv13[3] = { +static unsigned char elv13[3] = { 0xB6, 0x8C, 0x0A }; +// hbm interpolation +static unsigned char elv14[3] = { + 0xB6, 0x8C, 0x09 +}; +static unsigned char elv15[3] = { + 0xB6, 0x8C, 0x08 +}; +static unsigned char elv16[3] = { + 0xB6, 0x8C, 0x06 +}; +static unsigned char elv17[3] = { + 0xB6, 0x8C, 0x04 +}; +static unsigned char elv18[3] = { + 0xB6, 0x8C, 0x02 +}; +static unsigned char elv19[3] = { + 0xB6, 0x8C, 0x00 +}; -static const unsigned char elvCaps1[3] = { +static unsigned char elvCaps1[3] = { 0xB6, 0x9C, 0x16 }; -static const unsigned char elvCaps2[3] = { +static unsigned char elvCaps2[3] = { 0xB6, 0x9C, 0x15 }; -static const unsigned char elvCaps3[3] = { +static unsigned char elvCaps3[3] = { 0xB6, 0x9C, 0x14 }; -static const unsigned char elvCaps4[3] = { +static unsigned char elvCaps4[3] = { 0xB6, 0x9C, 0x13 }; -static const unsigned char elvCaps5[3] = { +static unsigned char elvCaps5[3] = { 0xB6, 0x9C, 0x12 }; -static const unsigned char elvCaps6[3] = { +static unsigned char elvCaps6[3] = { 0xB6, 0x9C, 0x11 }; -static const unsigned char elvCaps7[3] = { +static unsigned char elvCaps7[3] = { 0xB6, 0x9C, 0x10 }; -static const unsigned char elvCaps8[3] = { +static unsigned char elvCaps8[3] = { 0xB6, 0x9C, 0x0F }; -static const unsigned char elvCaps9[3] = { +static unsigned char elvCaps9[3] = { 0xB6, 0x9C, 0x0E }; -static const unsigned char elvCaps10[3] = { +static unsigned char elvCaps10[3] = { 0xB6, 0x9C, 0x0D }; -static const unsigned char elvCaps11[3] = { +static unsigned char elvCaps11[3] = { 0xB6, 0x9C, 0x0C }; -static const unsigned char elvCaps12[3] = { +static unsigned char elvCaps12[3] = { 0xB6, 0x9C, 0x0B }; -static const unsigned char elvCaps13[3] = { +static unsigned char elvCaps13[3] = { 0xB6, 0x9C, 0x0A }; +// hbm interpolation +static unsigned char elvCaps14[3] = { + 0xB6, 0x9C, 0x09 +}; +static unsigned char elvCaps15[3] = { + 0xB6, 0x9C, 0x08 +}; +static unsigned char elvCaps16[3] = { + 0xB6, 0x9C, 0x06 +}; +static unsigned char elvCaps17[3] = { + 0xB6, 0x9C, 0x04 +}; +static unsigned char elvCaps18[3] = { + 0xB6, 0x9C, 0x02 +}; +static unsigned char elvCaps19[3] = { + 0xB6, 0x9C, 0x00 +}; + #ifdef CONFIG_LCD_HMT -static const signed char HMTrtbl10nit[10] = {0, 8, 10, 8, 6, 4, 2, 2, 1, 0}; -static const signed char HMTrtbl11nit[10] = {0, 13, 9, 7, 5, 4, 2, 2, 0, 0}; -static const signed char HMTrtbl12nit[10] = {0, 11, 9, 7, 5, 4, 2, 2, 0, 0}; -static const signed char HMTrtbl13nit[10] = {0, 11, 9, 7, 5, 3, 2, 3, 0, 0}; -static const signed char HMTrtbl14nit[10] = {0, 13, 9, 7, 5, 4, 3, 3, 1, 0}; -static const signed char HMTrtbl15nit[10] = {0, 9, 10, 7, 6, 4, 4, 4, 1, 0}; -static const signed char HMTrtbl16nit[10] = {0, 10, 10, 7, 5, 5, 3, 3, 1, 0}; -static const signed char HMTrtbl17nit[10] = {0, 8, 9, 7, 5, 4, 3, 3, 1, 0}; -static const signed char HMTrtbl19nit[10] = {0, 11, 9, 7, 5, 4, 3, 3, 2, 0}; -static const signed char HMTrtbl20nit[10] = {0, 10, 9, 7, 5, 5, 4, 3, 2, 0}; -static const signed char HMTrtbl21nit[10] = {0, 9, 9, 7, 5, 4, 4, 4, 3, 0}; -static const signed char HMTrtbl22nit[10] = {0, 9, 9, 6, 5, 4, 3, 3, 4, 0}; -static const signed char HMTrtbl23nit[10] = {0, 9, 9, 6, 5, 4, 3, 3, 3, 0}; -static const signed char HMTrtbl25nit[10] = {0, 12, 9, 7, 5, 5, 4, 4, 4, 0}; -static const signed char HMTrtbl27nit[10] = {0, 7, 9, 6, 5, 4, 5, 4, 3, 0}; -static const signed char HMTrtbl29nit[10] = {0, 10, 9, 7, 5, 5, 5, 7, 5, 0}; -static const signed char HMTrtbl31nit[10] = {0, 8, 9, 7, 5, 5, 5, 5, 4, 0}; -static const signed char HMTrtbl33nit[10] = {0, 10, 9, 6, 6, 5, 6, 7, 4, 0}; -static const signed char HMTrtbl35nit[10] = {0, 11, 9, 7, 6, 6, 6, 6, 4, 0}; -static const signed char HMTrtbl37nit[10] = {0, 6, 9, 6, 5, 5, 6, 6, 2, 0}; -static const signed char HMTrtbl39nit[10] = {0, 6, 9, 6, 5, 5, 6, 5, 2, 0}; -static const signed char HMTrtbl41nit[10] = {0, 11, 9, 7, 6, 6, 6, 6, 3, 0}; -static const signed char HMTrtbl44nit[10] = {0, 6, 10, 7, 6, 5, 5, 5, 1, 0}; -static const signed char HMTrtbl47nit[10] = {0, 8, 10, 7, 5, 5, 5, 5, 1, 0}; -static const signed char HMTrtbl50nit[10] = {0, 8, 10, 7, 6, 6, 6, 5, 0, 0}; -static const signed char HMTrtbl53nit[10] = {0, 9, 9, 7, 6, 6, 6, 6, 0, 0}; -static const signed char HMTrtbl56nit[10] = {0, 11, 9, 7, 5, 6, 6, 6, 2, 0}; -static const signed char HMTrtbl60nit[10] = {0, 11, 9, 7, 5, 6, 6, 5, 1, 0}; -static const signed char HMTrtbl64nit[10] = {0, 7, 10, 7, 6, 6, 6, 5, 1, 0}; -static const signed char HMTrtbl68nit[10] = {0, 7, 9, 7, 6, 5, 5, 5, 1, 0}; -static const signed char HMTrtbl72nit[10] = {0, 7, 9, 6, 5, 5, 5, 6, 2, 0}; -static const signed char HMTrtbl77nit[10] = {0, 6, 5, 4, 3, 3, 3, 4, -1, 0}; -static const signed char HMTrtbl82nit[10] = {0, 3, 6, 4, 3, 3, 5, 5, 0, 0}; -static const signed char HMTrtbl87nit[10] = {0, 1, 6, 4, 3, 2, 4, 5, 0, 0}; -static const signed char HMTrtbl93nit[10] = {0, 3, 5, 3, 2, 3, 5, 4, 2, 0}; -static const signed char HMTrtbl99nit[10] = {0, 3, 5, 3, 3, 3, 4, 4, 1, 0}; -static const signed char HMTrtbl105nit[10] = {0, 6, 5, 3, 3, 3, 4, 4, 1, 0}; +static signed char HMTrtbl10nit[10] = {0, 8, 10, 8, 6, 4, 2, 2, 1, 0}; +static signed char HMTrtbl11nit[10] = {0, 13, 9, 7, 5, 4, 2, 2, 0, 0}; +static signed char HMTrtbl12nit[10] = {0, 11, 9, 7, 5, 4, 2, 2, 0, 0}; +static signed char HMTrtbl13nit[10] = {0, 11, 9, 7, 5, 3, 2, 3, 0, 0}; +static signed char HMTrtbl14nit[10] = {0, 13, 9, 7, 5, 4, 3, 3, 1, 0}; +static signed char HMTrtbl15nit[10] = {0, 9, 10, 7, 6, 4, 4, 4, 1, 0}; +static signed char HMTrtbl16nit[10] = {0, 10, 10, 7, 5, 5, 3, 3, 1, 0}; +static signed char HMTrtbl17nit[10] = {0, 8, 9, 7, 5, 4, 3, 3, 1, 0}; +static signed char HMTrtbl19nit[10] = {0, 11, 9, 7, 5, 4, 3, 3, 2, 0}; +static signed char HMTrtbl20nit[10] = {0, 10, 9, 7, 5, 5, 4, 3, 2, 0}; +static signed char HMTrtbl21nit[10] = {0, 9, 9, 7, 5, 4, 4, 4, 3, 0}; +static signed char HMTrtbl22nit[10] = {0, 9, 9, 6, 5, 4, 3, 3, 4, 0}; +static signed char HMTrtbl23nit[10] = {0, 9, 9, 6, 5, 4, 3, 3, 3, 0}; +static signed char HMTrtbl25nit[10] = {0, 12, 9, 7, 5, 5, 4, 4, 4, 0}; +static signed char HMTrtbl27nit[10] = {0, 7, 9, 6, 5, 4, 5, 4, 3, 0}; +static signed char HMTrtbl29nit[10] = {0, 10, 9, 7, 5, 5, 5, 7, 5, 0}; +static signed char HMTrtbl31nit[10] = {0, 8, 9, 7, 5, 5, 5, 5, 4, 0}; +static signed char HMTrtbl33nit[10] = {0, 10, 9, 6, 6, 5, 6, 7, 4, 0}; +static signed char HMTrtbl35nit[10] = {0, 11, 9, 7, 6, 6, 6, 6, 4, 0}; +static signed char HMTrtbl37nit[10] = {0, 6, 9, 6, 5, 5, 6, 6, 2, 0}; +static signed char HMTrtbl39nit[10] = {0, 6, 9, 6, 5, 5, 6, 5, 2, 0}; +static signed char HMTrtbl41nit[10] = {0, 11, 9, 7, 6, 6, 6, 6, 3, 0}; +static signed char HMTrtbl44nit[10] = {0, 6, 10, 7, 6, 5, 5, 5, 1, 0}; +static signed char HMTrtbl47nit[10] = {0, 8, 10, 7, 5, 5, 5, 5, 1, 0}; +static signed char HMTrtbl50nit[10] = {0, 8, 10, 7, 6, 6, 6, 5, 0, 0}; +static signed char HMTrtbl53nit[10] = {0, 9, 9, 7, 6, 6, 6, 6, 0, 0}; +static signed char HMTrtbl56nit[10] = {0, 11, 9, 7, 5, 6, 6, 6, 2, 0}; +static signed char HMTrtbl60nit[10] = {0, 11, 9, 7, 5, 6, 6, 5, 1, 0}; +static signed char HMTrtbl64nit[10] = {0, 7, 10, 7, 6, 6, 6, 5, 1, 0}; +static signed char HMTrtbl68nit[10] = {0, 7, 9, 7, 6, 5, 5, 5, 1, 0}; +static signed char HMTrtbl72nit[10] = {0, 7, 9, 6, 5, 5, 5, 6, 2, 0}; +static signed char HMTrtbl77nit[10] = {0, 6, 5, 4, 3, 3, 3, 4, -1, 0}; +static signed char HMTrtbl82nit[10] = {0, 3, 6, 4, 3, 3, 5, 5, 0, 0}; +static signed char HMTrtbl87nit[10] = {0, 1, 6, 4, 3, 2, 4, 5, 0, 0}; +static signed char HMTrtbl93nit[10] = {0, 3, 5, 3, 2, 3, 5, 4, 2, 0}; +static signed char HMTrtbl99nit[10] = {0, 3, 5, 3, 3, 3, 4, 4, 1, 0}; +static signed char HMTrtbl105nit[10] = {0, 6, 5, 3, 3, 3, 4, 4, 1, 0}; -static const signed char HMTctbl10nit[30] = {0, 0, 0, 0, 0, 0,-3, 3, -6, -3, 3, -7, -3, 2, -5, -4, 2, -5, -1, 2, -4, -1, 0, -2, -1, 0, 0, 0, 0, -1}; -static const signed char HMTctbl11nit[30] = {0, 0, 0, 0, 0, 0,-6, 2, -6, -3, 3, -7, -4, 2, -6, -3, 2, -5, -2, 1, -4, -2, 0, -2, 0, 0, -1, 0, 0, 0}; -static const signed char HMTctbl12nit[30] = {0, 0, 0, 0, 0, 0,-8, 3, -6, -4, 3, -7, -3, 3, -6, -3, 2, -4, -1, 1, -3, -1, 0, -2, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl13nit[30] = {0, 0, 0, 0, 0, 0,-7, 2, -6, -3, 4, -9, -3, 2, -4, -2, 2, -5, -1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl14nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -8, -2, 3, -6, -3, 2, -5, -2, 2, -5, -1, 1, -3, -1, 0, -1, 0, 0, -1, 0, 0, 0}; -static const signed char HMTctbl15nit[30] = {0, 0, 0, 0, 0, 0,-7, 3, -7, -5, 3, -8, -2, 2, -4, -2, 2, -4, -1, 1, -4, -2, 0, -2, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl16nit[30] = {0, 0, 0, 0, 0, 0,-6, 2, -6, -3, 3, -8, -4, 2, -5, -3, 2, -5, -1, 1, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl17nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -6, -3, 3, -7, -4, 2, -5, -2, 2, -5, 0, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl19nit[30] = {0, 0, 0, 0, 0, 0,-7, 3, -8, -2, 3, -8, -5, 1, -4, -3, 2, -5, 0, 1, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl20nit[30] = {0, 0, 0, 0, 0, 0,-6, 3, -8, -4, 3, -8, -3, 2, -4, -2, 2, -4, -1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl21nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -8, -3, 3, -8, -4, 2, -4, -2, 2, -5, -1, 1, -3, 0, 0, 0, -1, 0, 0, 0, 0, 0}; -static const signed char HMTctbl22nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -8, -5, 3, -8, -2, 2, -4, -1, 2, -4, -2, 1, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl23nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -8, -4, 3, -8, -3, 2, -4, -1, 2, -4, -2, 1, -2, 0, 0, -1, 0, 0, 0, 1, 0, 0}; -static const signed char HMTctbl25nit[30] = {0, 0, 0, 0, 0, 0,-8, 4, -10, -4, 3, -7, -3, 1, -4, 0, 2, -4, -2, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -static const signed char HMTctbl27nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -8, -4, 3, -7, -4, 1, -4, -1, 1, -4, -1, 1, -2, -1, 0, 0, -1, 0, 0, 1, 0, 0}; -static const signed char HMTctbl29nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -10, -3, 2, -6, -4, 1, -4, 0, 2, -4, -2, 0, -2, 0, 0, 0, -1, 0, 0, 1, 0, 0}; -static const signed char HMTctbl31nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -9, -3, 3, -6, -3, 1, -4, -1, 2, -4, -1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl33nit[30] = {0, 0, 0, 0, 0, 0,-4, 3, -8, -3, 3, -7, -2, 1, -3, -1, 1, -4, -1, 1, -2, 0, 0, 0, 0, 0, 0, 1, 0, 0}; -static const signed char HMTctbl35nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -10, -4, 3, -6, -2, 1, -3, -1, 1, -4, -2, 0, -2, -1, 0, 0, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl37nit[30] = {0, 0, 0, 0, 0, 0,-3, 3, -8, -3, 3, -6, -4, 1, -4, -2, 1, -4, -1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0}; -static const signed char HMTctbl39nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -9, -4, 2, -6, -3, 1, -4, -1, 1, -3, -1, 0, -2, -1, 0, -1, 0, 0, 0, 2, 0, 2}; -static const signed char HMTctbl41nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -10, -3, 3, -6, -3, 1, -4, -2, 1, -4, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl44nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -9, -4, 2, -6, -3, 1, -4, 0, 1, -3, -1, 0, -2, 0, 0, -1, 0, 0, 0, 2, 0, 2}; -static const signed char HMTctbl47nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -9, -4, 2, -6, -2, 1, -4, -3, 1, -4, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl50nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -5, 2, -6, -2, 2, -4, -1, 1, -3, -1, 0, -2, -1, 0, -1, 0, 0, 0, 2, 0, 2}; -static const signed char HMTctbl53nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -9, -4, 2, -6, -3, 1, -4, 0, 1, -2, -1, 0, -1, -1, 0, -1, 0, 0, 0, 2, 0, 1}; -static const signed char HMTctbl56nit[30] = {0, 0, 0, 0, 0, 0,-4, 5, -10, -2, 1, -4, -2, 2, -4, -2, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 1}; -static const signed char HMTctbl60nit[30] = {0, 0, 0, 0, 0, 0,-4, 5, -10, -2, 2, -5, -2, 1, -4, -1, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 0}; -static const signed char HMTctbl64nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -3, 2, -5, -2, 1, -4, -1, 0, -2, -1, 0, -2, 0, 0, 0, -1, 0, 0, 1, 0, 1}; -static const signed char HMTctbl68nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -9, -1, 2, -4, -2, 1, -4, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0}; -static const signed char HMTctbl72nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -2, 2, -4, -1, 1, -4, -2, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl77nit[30] = {0, 0, 0, 0, 0, 0,-1, 4, -9, -2, 1, -4, -2, 0, -2, 0, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2}; -static const signed char HMTctbl82nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -2, 1, -3, 0, 0, -2, -1, 0, -1, 0, 0, -1, 0, 0, 1, 1, 0, 1}; -static const signed char HMTctbl87nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -1, 1, -3, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}; -static const signed char HMTctbl93nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -1, 1, -2, -1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}; -static const signed char HMTctbl99nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -7, -2, 1, -4, 0, 1, -3, 0, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2}; -static const signed char HMTctbl105nit[30] = {0, 0, 0, 0, 0, 0,-1, 4, -8, -4, 1, -4, 0, 1, -3, -1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3}; +static signed char HMTctbl10nit[30] = {0, 0, 0, 0, 0, 0,-3, 3, -6, -3, 3, -7, -3, 2, -5, -4, 2, -5, -1, 2, -4, -1, 0, -2, -1, 0, 0, 0, 0, -1}; +static signed char HMTctbl11nit[30] = {0, 0, 0, 0, 0, 0,-6, 2, -6, -3, 3, -7, -4, 2, -6, -3, 2, -5, -2, 1, -4, -2, 0, -2, 0, 0, -1, 0, 0, 0}; +static signed char HMTctbl12nit[30] = {0, 0, 0, 0, 0, 0,-8, 3, -6, -4, 3, -7, -3, 3, -6, -3, 2, -4, -1, 1, -3, -1, 0, -2, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl13nit[30] = {0, 0, 0, 0, 0, 0,-7, 2, -6, -3, 4, -9, -3, 2, -4, -2, 2, -5, -1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl14nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -8, -2, 3, -6, -3, 2, -5, -2, 2, -5, -1, 1, -3, -1, 0, -1, 0, 0, -1, 0, 0, 0}; +static signed char HMTctbl15nit[30] = {0, 0, 0, 0, 0, 0,-7, 3, -7, -5, 3, -8, -2, 2, -4, -2, 2, -4, -1, 1, -4, -2, 0, -2, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl16nit[30] = {0, 0, 0, 0, 0, 0,-6, 2, -6, -3, 3, -8, -4, 2, -5, -3, 2, -5, -1, 1, -4, -1, 0, -1, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl17nit[30] = {0, 0, 0, 0, 0, 0,-4, 2, -6, -3, 3, -7, -4, 2, -5, -2, 2, -5, 0, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl19nit[30] = {0, 0, 0, 0, 0, 0,-7, 3, -8, -2, 3, -8, -5, 1, -4, -3, 2, -5, 0, 1, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl20nit[30] = {0, 0, 0, 0, 0, 0,-6, 3, -8, -4, 3, -8, -3, 2, -4, -2, 2, -4, -1, 1, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl21nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -8, -3, 3, -8, -4, 2, -4, -2, 2, -5, -1, 1, -3, 0, 0, 0, -1, 0, 0, 0, 0, 0}; +static signed char HMTctbl22nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -8, -5, 3, -8, -2, 2, -4, -1, 2, -4, -2, 1, -2, -1, 0, -1, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl23nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -8, -4, 3, -8, -3, 2, -4, -1, 2, -4, -2, 1, -2, 0, 0, -1, 0, 0, 0, 1, 0, 0}; +static signed char HMTctbl25nit[30] = {0, 0, 0, 0, 0, 0,-8, 4, -10, -4, 3, -7, -3, 1, -4, 0, 2, -4, -2, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static signed char HMTctbl27nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -8, -4, 3, -7, -4, 1, -4, -1, 1, -4, -1, 1, -2, -1, 0, 0, -1, 0, 0, 1, 0, 0}; +static signed char HMTctbl29nit[30] = {0, 0, 0, 0, 0, 0,-6, 4, -10, -3, 2, -6, -4, 1, -4, 0, 2, -4, -2, 0, -2, 0, 0, 0, -1, 0, 0, 1, 0, 0}; +static signed char HMTctbl31nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -9, -3, 3, -6, -3, 1, -4, -1, 2, -4, -1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl33nit[30] = {0, 0, 0, 0, 0, 0,-4, 3, -8, -3, 3, -7, -2, 1, -3, -1, 1, -4, -1, 1, -2, 0, 0, 0, 0, 0, 0, 1, 0, 0}; +static signed char HMTctbl35nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -10, -4, 3, -6, -2, 1, -3, -1, 1, -4, -2, 0, -2, -1, 0, 0, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl37nit[30] = {0, 0, 0, 0, 0, 0,-3, 3, -8, -3, 3, -6, -4, 1, -4, -2, 1, -4, -1, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0}; +static signed char HMTctbl39nit[30] = {0, 0, 0, 0, 0, 0,-5, 4, -9, -4, 2, -6, -3, 1, -4, -1, 1, -3, -1, 0, -2, -1, 0, -1, 0, 0, 0, 2, 0, 2}; +static signed char HMTctbl41nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -10, -3, 3, -6, -3, 1, -4, -2, 1, -4, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl44nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -9, -4, 2, -6, -3, 1, -4, 0, 1, -3, -1, 0, -2, 0, 0, -1, 0, 0, 0, 2, 0, 2}; +static signed char HMTctbl47nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -9, -4, 2, -6, -2, 1, -4, -3, 1, -4, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl50nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -5, 2, -6, -2, 2, -4, -1, 1, -3, -1, 0, -2, -1, 0, -1, 0, 0, 0, 2, 0, 2}; +static signed char HMTctbl53nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -9, -4, 2, -6, -3, 1, -4, 0, 1, -2, -1, 0, -1, -1, 0, -1, 0, 0, 0, 2, 0, 1}; +static signed char HMTctbl56nit[30] = {0, 0, 0, 0, 0, 0,-4, 5, -10, -2, 1, -4, -2, 2, -4, -2, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 1}; +static signed char HMTctbl60nit[30] = {0, 0, 0, 0, 0, 0,-4, 5, -10, -2, 2, -5, -2, 1, -4, -1, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 0}; +static signed char HMTctbl64nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -3, 2, -5, -2, 1, -4, -1, 0, -2, -1, 0, -2, 0, 0, 0, -1, 0, 0, 1, 0, 1}; +static signed char HMTctbl68nit[30] = {0, 0, 0, 0, 0, 0,-4, 4, -9, -1, 2, -4, -2, 1, -4, -1, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0}; +static signed char HMTctbl72nit[30] = {0, 0, 0, 0, 0, 0,-3, 4, -8, -2, 2, -4, -1, 1, -4, -2, 1, -2, -1, 0, -2, 0, 0, -1, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl77nit[30] = {0, 0, 0, 0, 0, 0,-1, 4, -9, -2, 1, -4, -2, 0, -2, 0, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2}; +static signed char HMTctbl82nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -2, 1, -3, 0, 0, -2, -1, 0, -1, 0, 0, -1, 0, 0, 1, 1, 0, 1}; +static signed char HMTctbl87nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -1, 1, -3, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1}; +static signed char HMTctbl93nit[30] = {0, 0, 0, 0, 0, 0,-1, 3, -8, -2, 2, -4, -1, 1, -2, -1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}; +static signed char HMTctbl99nit[30] = {0, 0, 0, 0, 0, 0,0, 3, -7, -2, 1, -4, 0, 1, -3, 0, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2}; +static signed char HMTctbl105nit[30] = {0, 0, 0, 0, 0, 0,-1, 4, -8, -4, 1, -4, 0, 1, -3, -1, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3}; -static const unsigned char HMTaid8001[4] = { +static unsigned char HMTaid8001[4] = { 0xB2, 0x03, 0x12, 0x03 }; -static const unsigned char HMTaid7003[4] = { +static unsigned char HMTaid7003[4] = { 0xB2, 0x03, 0x13, 0x04 }; diff --git a/drivers/video/exynos/decon/panels/s6e3ha3_s6e3ha2_wqhd_lcd_ctrl.c b/drivers/video/exynos/decon/panels/s6e3ha3_s6e3ha2_wqhd_lcd_ctrl.c new file mode 100644 index 000000000000..e62250426aac --- /dev/null +++ b/drivers/video/exynos/decon/panels/s6e3ha3_s6e3ha2_wqhd_lcd_ctrl.c @@ -0,0 +1,2429 @@ +/* + * drivers/video/decon/panels/S6E3HA0_lcd_ctrl.c + * + * Samsung SoC MIPI LCD CONTROL functions + * + * Copyright (c) 2014 Samsung Electronics + * + * Jiun Yu, + * + * 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. +*/ + +#ifdef CONFIG_PANEL_AID_DIMMING +#include "aid_dimming.h" +#include "dimming_core.h" +#include "s6e3ha3_wqhd_aid_dimming.h" +#endif +#include "s6e3ha3_s6e3ha2_wqhd_param.h" +#include "../dsim.h" +#include