Merge "[SCSI] ufs: use devres functions for ufshcd"
diff --git a/AndroidKernel.mk b/AndroidKernel.mk
index 3684a3f..d97d3c3 100644
--- a/AndroidKernel.mk
+++ b/AndroidKernel.mk
@@ -5,7 +5,11 @@
KERNEL_OUT := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ
KERNEL_CONFIG := $(KERNEL_OUT)/.config
+ifeq ($(TARGET_KERNEL_APPEND_DTB), true)
+TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage-dtb
+else
TARGET_PREBUILT_INT_KERNEL := $(KERNEL_OUT)/arch/arm/boot/zImage
+endif
KERNEL_HEADERS_INSTALL := $(KERNEL_OUT)/usr
KERNEL_MODULES_INSTALL := system
KERNEL_MODULES_OUT := $(TARGET_OUT)/lib/modules
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
index a979c56..26102c8 100644
--- a/Documentation/devicetree/bindings/dma/sps/sps.txt
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -7,7 +7,11 @@
- compatible: should be "qcom,msm_sps"
Optional properties:
- - reg: offset and size of the register set in the memory map
+ - reg: offset and size for the memory mapping, including maps for
+ BAM DMA BAM, BAM DMA peripheral, pipe memory and reserved memory.
+ - reg-names: indicates various resources passed to driver (via reg
+ property) by name. "reg-names" examples are "bam_mem", "core_mem"
+ , "pipe_mem" and "res_mem".
- interrupts: IRQ line
- qcom,device-type: specify the device configuration of BAM DMA and
pipe memory. Can be one of
diff --git a/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
new file mode 100644
index 0000000..aa50140
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/stk-stk3x1x.txt
@@ -0,0 +1,46 @@
+Sensortek stk301x, stk321x and stk331x ambient light/proximity 3-in-1 sensor
+
+Required properties:
+
+ - compatible : Should be "stk,stk3x1x".
+ - reg : i2c slave address of the device.
+ - interrupt-parent : Parent of interrupt.
+ - interrupts : Sensor will issue interrupt when preset condition is met,
+ typically when proximity sensor detect a change on near/far state.
+ - vdd-supply : Main power supply to power sensor.
+ - vio-supply : Power supply required to pullup I2C bus.
+ - stk,irq-gpio : irq gpio which is to provide interrupts to host, same as
+ "interrupts" node.
+ - stk,transmittance : Transmittance rate of glass above the ambient light
+ detection window. The value may not be equal to real transmittance
+ but just a relative value.
+ - stk,state-reg : The default setting of state register.
+ - stk,psctrl-reg : The default setting for proximity sensor.
+ - stk,alsctrl-reg : The default setting for ambient light sensor.
+ - stk,ledctrl-reg : The default setting for IR LED.
+ - stk,wait-reg : The default setting for wait time.
+ - stk,ps-thdh : High threshold for proximity sensor, sensor will report
+ "near" if the proximity sensor reading is larger or equal to this
+ value.
+ - stk,ps-thdl : Low threshold for proximity sensor, sensor will report
+ "far" if the proximity sensor reading is larger than this value.
+
+Example:
+ i2c@f9925000 {
+ stk@48 {
+ compatible = "stk,stk3x1x";
+ reg = <0x48>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <80 0x2>;
+ vdd-supply = <&pm8110_l19>;
+ vio-supply = <&pm8110_l14>;
+ stk,irq-gpio = <&msmgpio 80 0x02>;
+ stk,transmittance = <500>;
+ stk,state-reg = <0x00>;
+ stk,psctrl-reg = <0x71>;
+ stk,alsctrl-reg = <0x38>;
+ stk,ledctrl-reg = <0xFF>;
+ stk,wait-reg = <0x07>;
+ stk,ps-thdh = <1700>;
+ stk,ps-thdl = <1500>;
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp.txt b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
index b60760e..9524360 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp.txt
@@ -47,6 +47,7 @@
- qcom,default-state: default state of the led, should be "on" or "off"
- qcom,torch-enable: set flash led to torch mode
- flash_boost-supply: SMBB regulator for LED flash mode
+- torch_boost-supply: SMBB regulator for LED torch mode
RGB Led is a tri-colored led, Red, Blue & Green.
@@ -222,6 +223,7 @@
compatible = "qcom,leds-qpnp";
status = "okay";
flash_boost-supply = <&pm8941_chg_boost>;
+ torch_boost-supply = <&pm8941_boost>;
qcom,flash_0 {
qcom,max-current = <1000>;
qcom,default-state = "off";
diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
index 72b32be..d848baf 100644
--- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt
@@ -13,6 +13,10 @@
- qcom,flash-source : Should contain array of phandles to flash source nodes.
- pm8941_flash0 pm8941_flash1
+Optional properties:
+-qcom,torch-source : Should contain phandle to torch source node.
+ -pm8941_torch
+
Example:
qcom,camera-led-flash {
@@ -20,4 +24,5 @@
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
qcom,flash-source = <&pm8941_flash0 &pm8941_flash1>;
+ qcom,torch-source = <&pm8941_torch>;
};
diff --git a/Documentation/devicetree/bindings/media/video/msm-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cci.txt
index b8156c3..c60441f 100644
--- a/Documentation/devicetree/bindings/media/video/msm-cci.txt
+++ b/Documentation/devicetree/bindings/media/video/msm-cci.txt
@@ -49,6 +49,7 @@
Required properties:
- compatible : should be manufacturer name followed by sensor name
- "qcom,s5k3l1yx"
+ - "qcom,imx135"
- "shinetech,gc0339"
- "shinetech,hi256"
- "shinetech,s5k4e1"
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a3a3807..527c50c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -42,6 +42,7 @@
samsung Samsung Semiconductor
sbs Smart Battery System
schindler Schindler
+stk Sensortek Technology Corporation.(formerly Sitronix Technology Co., Ltd.)
shinetech Shine Tech Corporation, Ltd.
sil Silicon Image
simtek
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8226e43..69b2cd2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2015,6 +2015,21 @@
help
Include support for flattened device tree machine descriptions.
+config BUILD_ARM_APPENDED_DTB_IMAGE
+ bool "Build a concatenated zImage/dtb by default"
+ depends on OF
+ help
+ Enabling this option will cause a concatenated zImage and list of
+ DTBs to be built by default (instead of a standalone zImage.)
+ The image will built in arch/arm/boot/zImage-dtb
+
+config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES
+ string "Default dtb names"
+ depends on BUILD_ARM_APPENDED_DTB_IMAGE
+ help
+ Space separated list of names of dtbs to append when
+ building a concatenated zImage-dtb.
+
# Compressed boot loader in ROM. Yes, we really want to ask about
# TEXT and BSS so we preserve their values in the config files.
config ZBOOT_ROM_TEXT
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2f2603f..d43e69bf 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -261,6 +261,8 @@
# Default target when executing plain make
ifeq ($(CONFIG_XIP_KERNEL),y)
KBUILD_IMAGE := xipImage
+else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y)
+KBUILD_IMAGE := zImage-dtb
else
KBUILD_IMAGE := zImage
endif
@@ -292,6 +294,9 @@
dtbs: scripts
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+zImage-dtb: vmlinux scripts
+ $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $(boot)/$@
+
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
@@ -306,7 +311,7 @@
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
echo '* xipImage - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
echo ' uImage - U-Boot wrapped zImage'
- echo ' bootpImage - Combined zImage and initial RAM disk'
+ echo ' bootpImage - Combined zImage and initial RAM disk'
echo ' (supply initrd image via make variable INITRD=<path>)'
echo '* dtbs - Build device tree blobs for enabled boards'
echo ' install - Install uncompressed kernel'
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
index 3c79f85..ad7a025 100644
--- a/arch/arm/boot/.gitignore
+++ b/arch/arm/boot/.gitignore
@@ -4,3 +4,4 @@
bootpImage
uImage
*.dtb
+zImage-dtb
\ No newline at end of file
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index c877087..bc8ee6c 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -27,6 +27,14 @@
targets := Image zImage xipImage bootpImage uImage
+DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
+ifneq ($(DTB_NAMES),)
+DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
+else
+DTB_LIST := $(dtb-y)
+endif
+DTB_OBJS := $(addprefix $(obj)/,$(DTB_LIST))
+
ifeq ($(CONFIG_XIP_KERNEL),y)
$(obj)/xipImage: vmlinux FORCE
@@ -55,15 +63,19 @@
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
+$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS) FORCE
+ $(call if_changed,cat)
+ @echo ' Kernel: $@ is ready'
+
endif
-targets += $(dtb-y)
+targets += $(DTB_LIST)
# Rule to build device tree blobs
$(obj)/%.dtb: $(src)/dts/%.dts FORCE
$(call if_changed_dep,dtc)
-$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+$(obj)/dtbs: $(DTB_OBJS)
clean-files := *.dtb
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index b89c676..7900ddf 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -20,3 +20,10 @@
compatible = "qcom,apq8026-mtp", "qcom,apq8026", "qcom,mtp";
qcom,msm-id = <199 8 0>;
};
+
+&cci {
+ /* Rotate rear camera to 0 degrees */
+ qcom,camera@6f {
+ qcom,mount-angle = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/apq8084-coresight.dtsi b/arch/arm/boot/dts/apq8084-coresight.dtsi
index 6cd238a..22c260f 100644
--- a/arch/arm/boot/dts/apq8084-coresight.dtsi
+++ b/arch/arm/boot/dts/apq8084-coresight.dtsi
@@ -348,4 +348,29 @@
coresight-name = "coresight-cti-cpu3";
coresight-nr-inports = <0>;
};
+
+ hwevent: hwevent@fd828018 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0xfd828018 0x80>,
+ <0xf9011080 0x80>,
+ <0xfd4ab160 0x80>,
+ <0xfc401600 0x80>;
+ reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux";
+
+ coresight-id = <29>;
+ coresight-name = "coresight-hwevent";
+ coresight-nr-inports = <0>;
+
+ qcom,hwevent-clks = "core_mmss_clk";
+ };
+
+ fuse: fuse@fc4be024 {
+ compatible = "arm,coresight-fuse";
+ reg = <0xfc4be024 0x8>;
+ reg-names = "fuse-base";
+
+ coresight-id = <30>;
+ coresight-name = "coresight-fuse";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
new file mode 100644
index 0000000..5b7cc79
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -0,0 +1,275 @@
+/* Copyright (c) 2013, 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.
+ */
+
+/*---------------------------------------------------------------------------
+ * This file is autogenerated file using gcdb parser. Please do not edit it.
+ * Update input XML file to add a new entry or update variable in this file
+ * VERSION = "1.0"
+ *---------------------------------------------------------------------------*/
+&soc {
+ qcom,mdss_dsi_nt35521_720p_video {
+ compatible = "qcom,mdss-dsi-panel";
+ status = "disable";
+ qcom,mdss-dsi-panel-name = "nt35521 720p video mode dsi panel";
+ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+ qcom,mdss-dsi-panel-destination = "display_1";
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-panel-width = <720>;
+ qcom,mdss-dsi-panel-height = <1280>;
+ qcom,mdss-dsi-h-front-porch = <44>;
+ qcom,mdss-dsi-h-back-porch = <55>;
+ qcom,mdss-dsi-h-pulse-width = <11>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <15>;
+ qcom,mdss-dsi-v-front-porch = <14>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = <0>;
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-pixel-packing = <0>;
+ qcom,mdss-dsi-on-command = [29 01 00 00 00 00 06 F0 55 AA 52 08 00
+ 29 01 00 00 00 00 03 B1 68 21
+ 23 01 00 00 00 00 02 B5 C8
+ 29 01 00 00 00 00 02 B6 0F
+ 29 01 00 00 00 00 05 B8 00 00 0A 00
+ 23 01 00 00 00 00 02 B9 00
+ 23 01 00 00 00 00 02 BA 02
+ 29 01 00 00 00 00 03 BB 63 63
+ 29 01 00 00 00 00 03 BC 00 00
+ 29 01 00 00 00 00 06 BD 02 7F 0D 0B 00
+ 29 01 00 00 00 00 11 CC 41 36 87 54 46 65 10 12 14 10 12 14 40 08 15 05
+ 23 01 00 00 00 00 02 D0 00
+ 29 01 00 00 00 00 11 D1 00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
+ 23 01 00 00 00 00 02 D3 00
+ 29 01 00 00 00 00 03 D6 44 44
+ 29 01 00 00 00 00 0D D7 00 00 00 00 00 00 00 00 00 00 00 00
+ 29 01 00 00 00 00 0E D8 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 29 01 00 00 00 00 03 D9 00 28
+ 29 01 00 00 00 00 03 E5 00 FF
+ 29 01 00 00 00 00 05 E6 F3 EC E7 DF
+ 29 01 00 00 00 00 0B E7 F3 D9 CC CD B3 A6 99 99 99 95
+ 29 01 00 00 00 00 0B E8 F3 D9 CC CD B3 A6 99 99 99 95
+ 29 01 00 00 00 00 03 E9 00 04
+ 23 01 00 00 00 00 02 EA 00
+ 29 01 00 00 00 00 05 EE 87 78 00 00
+ 29 01 00 00 00 00 03 EF 07 FF
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 01
+ 29 01 00 00 00 00 03 B0 0D 0D
+ 29 01 00 00 00 00 03 B1 0D 0D
+ 29 01 00 00 00 00 03 B3 2D 2D
+ 29 01 00 00 00 00 03 B4 19 19
+ 29 01 00 00 00 00 03 B5 06 06
+ 29 01 00 00 00 00 03 B6 05 05
+ 29 01 00 00 00 00 03 B7 05 05
+ 29 01 00 00 00 00 03 B8 05 05
+ 29 01 00 00 00 00 03 B9 44 44
+ 29 01 00 00 00 00 03 BA 36 36
+ 29 01 00 00 00 00 03 BC 50 00
+ 29 01 00 00 00 00 03 BD 50 00
+ 23 01 00 00 00 00 02 BE 39
+ 23 01 00 00 00 00 02 BF 39
+ 23 01 00 00 00 00 02 C0 0C
+ 23 01 00 00 00 00 02 C1 00
+ 29 01 00 00 00 00 03 C2 19 19
+ 29 01 00 00 00 00 03 C3 0A 0A
+ 29 01 00 00 00 00 03 C4 23 23
+ 29 01 00 00 00 00 04 C7 00 80 00
+ 29 01 00 00 00 00 07 C9 00 00 00 00 00 00
+ 23 01 00 00 00 00 02 CA 01
+ 29 01 00 00 00 00 03 CB 0B 53
+ 23 01 00 00 00 00 02 CC 00
+ 29 01 00 00 00 00 04 CD 0B 52 53
+ 23 01 00 00 00 00 02 CE 44
+ 29 01 00 00 00 00 04 CF 00 50 50
+ 29 01 00 00 00 00 03 D0 50 50
+ 29 01 00 00 00 00 03 D1 50 50
+ 23 01 00 00 00 00 02 D2 39
+ 23 01 00 00 00 00 02 D3 39
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 02
+ 29 01 00 00 00 00 11 B0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 B1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 B2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 B3 03 CC 03 CC
+ 29 01 00 00 00 00 11 B4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 B5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 B6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 B7 03 CC 03 CC
+ 29 01 00 00 00 00 11 B8 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 B9 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 BA 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 BB 03 CC 03 CC
+ 29 01 00 00 00 00 11 BC 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 BD 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 BE 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 BF 03 CC 03 CC
+ 29 01 00 00 00 00 11 C0 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 C1 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 C2 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 C3 03 CC 03 CC
+ 29 01 00 00 00 00 11 C4 00 AC 00 BA 00 D9 00 ED 01 01 01 1E 01 3A 01 62
+ 29 01 00 00 00 00 11 C5 01 85 01 B8 01 E4 02 27 02 5B 02 5D 02 8C 02 BE
+ 29 01 00 00 00 00 11 C6 02 DF 03 0C 03 2A 03 51 03 6D 03 8D 03 A4 03 BE
+ 29 01 00 00 00 00 05 C7 03 CC 03 CC
+ 23 01 00 00 00 00 02 EE 00
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 03
+ 29 01 00 00 00 00 03 B0 00 00
+ 29 01 00 00 00 00 03 B1 00 00
+ 29 01 00 00 00 00 06 B2 03 00 00 00 00
+ 29 01 00 00 00 00 06 B3 03 00 00 00 00
+ 29 01 00 00 00 00 06 B4 03 00 00 00 00
+ 29 01 00 00 00 00 06 B5 03 00 00 00 00
+ 29 01 00 00 00 00 06 B6 03 00 00 00 00
+ 29 01 00 00 00 00 06 B7 03 00 00 00 00
+ 29 01 00 00 00 00 06 B8 03 00 00 00 00
+ 29 01 00 00 00 00 06 B9 03 00 00 00 00
+ 29 01 00 00 00 00 06 BA 35 10 00 00 00
+ 29 01 00 00 00 00 06 BB 35 10 00 00 00
+ 29 01 00 00 00 00 06 BC 35 10 00 00 00
+ 29 01 00 00 00 00 06 BD 35 10 00 00 00
+ 29 01 00 00 00 00 05 C0 00 34 00 00
+ 29 01 00 00 00 00 05 C1 00 34 00 00
+ 29 01 00 00 00 00 05 C2 00 34 00 00
+ 29 01 00 00 00 00 05 C3 00 34 00 00
+ 23 01 00 00 00 00 02 C4 40
+ 23 01 00 00 00 00 02 C5 40
+ 23 01 00 00 00 00 02 C6 40
+ 23 01 00 00 00 00 02 C7 40
+ 23 01 00 00 00 00 02 EF 00
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 05
+ 29 01 00 00 00 00 03 B0 1B 10
+ 29 01 00 00 00 00 03 B1 1B 10
+ 29 01 00 00 00 00 03 B2 1B 10
+ 29 01 00 00 00 00 03 B3 1B 10
+ 29 01 00 00 00 00 03 B4 1B 10
+ 29 01 00 00 00 00 03 B5 1B 10
+ 29 01 00 00 00 00 03 B6 1B 10
+ 29 01 00 00 00 00 03 B7 1B 10
+ 23 01 00 00 00 00 02 B8 00
+ 23 01 00 00 00 00 02 B9 00
+ 23 01 00 00 00 00 02 BA 00
+ 23 01 00 00 00 00 02 BB 00
+ 23 01 00 00 00 00 02 BC 00
+ 29 01 00 00 00 00 06 BD 03 03 03 00 01
+ 23 01 00 00 00 00 02 C0 03
+ 23 01 00 00 00 00 02 C1 05
+ 23 01 00 00 00 00 02 C2 03
+ 23 01 00 00 00 00 02 C3 05
+ 23 01 00 00 00 00 02 C4 80
+ 23 01 00 00 00 00 02 C5 A2
+ 23 01 00 00 00 00 02 C6 80
+ 23 01 00 00 00 00 02 C7 A2
+ 29 01 00 00 00 00 03 C8 01 20
+ 29 01 00 00 00 00 03 C9 00 20
+ 29 01 00 00 00 00 03 CA 01 00
+ 29 01 00 00 00 00 03 CB 00 00
+ 29 01 00 00 00 00 04 CC 00 00 01
+ 29 01 00 00 00 00 04 CD 00 00 01
+ 29 01 00 00 00 00 04 CE 00 00 01
+ 29 01 00 00 00 00 04 CF 00 00 01
+ 23 01 00 00 00 00 02 D0 00
+ 29 01 00 00 00 00 06 D1 03 00 00 07 10
+ 29 01 00 00 00 00 06 D2 13 00 00 07 11
+ 29 01 00 00 00 00 06 D3 23 00 00 07 10
+ 29 01 00 00 00 00 06 D4 33 00 00 07 11
+ 23 01 00 00 00 00 02 E5 06
+ 23 01 00 00 00 00 02 E6 06
+ 23 01 00 00 00 00 02 E7 06
+ 23 01 00 00 00 00 02 E8 06
+ 23 01 00 00 00 00 02 E9 06
+ 23 01 00 00 00 00 02 EA 06
+ 23 01 00 00 00 00 02 EB 06
+ 23 01 00 00 00 00 02 EC 06
+ 23 01 00 00 00 00 02 ED 31
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 06
+ 29 01 00 00 00 00 03 B0 10 11
+ 29 01 00 00 00 00 03 B1 12 13
+ 29 01 00 00 00 00 03 B2 08 00
+ 29 01 00 00 00 00 03 B3 2D 2D
+ 29 01 00 00 00 00 03 B4 2D 34
+ 29 01 00 00 00 00 03 B5 34 2D
+ 29 01 00 00 00 00 03 B6 2D 34
+ 29 01 00 00 00 00 03 B7 34 34
+ 29 01 00 00 00 00 03 B8 02 0A
+ 29 01 00 00 00 00 03 B9 00 08
+ 29 01 00 00 00 00 03 BA 09 01
+ 29 01 00 00 00 00 03 BB 0B 03
+ 29 01 00 00 00 00 03 BC 34 34
+ 29 01 00 00 00 00 03 BD 34 2D
+ 29 01 00 00 00 00 03 BE 2D 34
+ 29 01 00 00 00 00 03 BF 34 2D
+ 29 01 00 00 00 00 03 C0 2D 2D
+ 29 01 00 00 00 00 03 C1 01 09
+ 29 01 00 00 00 00 03 C2 19 18
+ 29 01 00 00 00 00 03 C3 17 16
+ 29 01 00 00 00 00 03 C4 19 18
+ 29 01 00 00 00 00 03 C5 17 16
+ 29 01 00 00 00 00 03 C6 01 09
+ 29 01 00 00 00 00 03 C7 2D 2D
+ 29 01 00 00 00 00 03 C8 2D 34
+ 29 01 00 00 00 00 03 C9 34 2D
+ 29 01 00 00 00 00 03 CA 2D 34
+ 29 01 00 00 00 00 03 CB 34 34
+ 29 01 00 00 00 00 03 CC 0B 03
+ 29 01 00 00 00 00 03 CD 09 01
+ 29 01 00 00 00 00 03 CE 00 08
+ 29 01 00 00 00 00 03 CF 02 0A
+ 29 01 00 00 00 00 03 D0 34 34
+ 29 01 00 00 00 00 03 D1 34 2D
+ 29 01 00 00 00 00 03 D2 2D 34
+ 29 01 00 00 00 00 03 D3 34 2D
+ 29 01 00 00 00 00 03 D4 2D 2D
+ 29 01 00 00 00 00 03 D5 08 00
+ 29 01 00 00 00 00 03 D6 10 11
+ 29 01 00 00 00 00 03 D7 12 13
+ 29 01 00 00 00 00 06 D8 55 55 55 55 55
+ 29 01 00 00 00 00 06 D9 55 55 55 55 55
+ 29 01 00 00 00 00 03 E5 34 34
+ 29 01 00 00 00 00 03 E6 34 34
+ 23 01 00 00 00 00 02 E7 05
+ 29 01 00 00 00 00 06 F0 55 AA 52 00 00
+ 05 01 00 00 32 00 02 11 00
+ 05 01 00 00 96 00 02 29 00
+ 29 01 00 00 00 00 06 F0 55 AA 52 08 01
+ 29 01 00 00 00 00 06 F0 55 AA 52 00 00
+ 29 01 00 00 00 00 02 53 2C];
+ qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00
+ 05 01 00 00 78 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-h-sync-pulse = <1>;
+ qcom,mdss-dsi-traffic-mode = <2>;
+ qcom,mdss-dsi-lane-map = <0>;
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [93 1F 17 00 2F 2E 1C 21 26 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x20>;
+ qcom,mdss-dsi-t-clk-pre = <0x2D>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <255>;
+ qcom,mdss-dsi-dma-trigger = <4>;
+ qcom,mdss-dsi-mdp-trigger = <0>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
index 1abaf55..3ba2fbc 100644
--- a/arch/arm/boot/dts/mpq8092-rumi.dts
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -18,7 +18,7 @@
/ {
model = "Qualcomm MPQ8092 RUMI";
compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
- qcom,msm-id = <146 16 0>;
+ qcom,msm-id = <146 15 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/mpq8092-sim.dts b/arch/arm/boot/dts/mpq8092-sim.dts
index 676ef3b..2384a45 100644
--- a/arch/arm/boot/dts/mpq8092-sim.dts
+++ b/arch/arm/boot/dts/mpq8092-sim.dts
@@ -17,7 +17,7 @@
/ {
model = "Qualcomm MPQ8092 Simulator";
compatible = "qcom,mpq8092-sim", "qcom,mpq8092", "qcom,sim";
- qcom,msm-id = <126 16 0>;
+ qcom,msm-id = <146 16 0>;
};
&soc {
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 2f67f3e..9a37316 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -229,6 +229,15 @@
qcom,current-limit = <800>;
};
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>;
+ reg-names = "bam_mem", "core_mem";
+ interrupts = <0 94 0>;
+ qcom,pipe-attr-ee;
+ };
+
sata: sata@fc580000 {
compatible = "qcom,msm-ahci";
reg = <0xfc580000 0x17c>;
@@ -308,5 +317,9 @@
status = "ok";
};
+&gdsc_vcap {
+ status = "ok";
+};
+
/include/ "msm-pma8084.dtsi"
/include/ "mpq8092-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm-gdsc.dtsi b/arch/arm/boot/dts/msm-gdsc.dtsi
index 495f65a..2f732a4 100644
--- a/arch/arm/boot/dts/msm-gdsc.dtsi
+++ b/arch/arm/boot/dts/msm-gdsc.dtsi
@@ -109,4 +109,11 @@
reg = <0xfc401ec0 0x4>;
status = "disabled";
};
+
+ gdsc_vcap: qcom,gdsc@fd8c1804 {
+ compatible = "qcom,gdsc";
+ regulator-name = "gdsc_vcap";
+ reg = <0xfd8c1804 0x4>;
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/msm-pm8941.dtsi b/arch/arm/boot/dts/msm-pm8941.dtsi
index 12af463..0c2b02b 100644
--- a/arch/arm/boot/dts/msm-pm8941.dtsi
+++ b/arch/arm/boot/dts/msm-pm8941.dtsi
@@ -1252,6 +1252,7 @@
reg = <0xd300 0x100>;
label = "flash";
flash_boost-supply = <&pm8941_chg_boost>;
+ torch_boost-supply = <&pm8941_boost>;
};
qcom,leds@d400 {
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index d4b605b..f807814 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -68,6 +68,47 @@
qcom,cci-master = <0>;
};
+ qcom,camera@20 {
+ compatible = "qcom,imx135";
+ reg = <0x20>;
+ qcom,slave-id = <0x20 0x0016 0x0135>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <90>;
+ qcom,sensor-name = "imx135";
+ cam_vdig-supply = <&pm8226_l5>;
+ cam_vana-supply = <&pm8226_l19>;
+ cam_vio-supply = <&pm8226_lvs1>;
+ cam_vaf-supply = <&pm8226_l15>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-type = <0 1 0 0>;
+ qcom,cam-vreg-min-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2850000 2800000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 26 0>,
+ <&msmgpio 37 0>,
+ <&msmgpio 36 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1",
+ "CAM_STANDBY";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 30000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x1F>;
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,sensor-type = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
qcom,camera@6d {
compatible = "qcom,ov9724";
reg = <0x6d>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 53860ac..56e8a09 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -38,7 +38,7 @@
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <90>;
qcom,sensor-name = "ov8825";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 2405646..1da94b3 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -12,7 +12,6 @@
/dts-v1/;
/include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
/ {
model = "Qualcomm MSM 8226 Simulator";
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index b1d46b1..6f03dca 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -23,3 +23,10 @@
<198 8 0>,
<205 8 0>;
};
+
+&cci {
+ /* Rotate rear camera to 0 degrees */
+ qcom,camera@6f {
+ qcom,mount-angle = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 936f87f..3e0e4e4 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8226-v1.dtsi"
/include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35521-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226 QRD";
@@ -26,9 +26,9 @@
};
&soc {
- qcom,mdss_dsi_nt35590_720p_video {
+ qcom,mdss_dsi_nt35521_720p_video {
status = "ok";
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+ qcom,cont-splash-enabled;
};
sound {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index b34fb94..0a4657d 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -13,7 +13,7 @@
/dts-v1/;
/include/ "msm8226-v2.dtsi"
/include/ "msm8226-qrd.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "dsi-panel-nt35521-720p-video.dtsi"
/ {
model = "Qualcomm MSM 8226v2 QRD";
@@ -27,9 +27,9 @@
};
&soc {
- qcom,mdss_dsi_nt35590_720p_video {
+ qcom,mdss_dsi_nt35521_720p_video {
status = "ok";
- qcom,mdss-pan-bl-ctrl = "bl_ctrl_dcs";
+ qcom,cont-splash-enabled;
};
sound {
diff --git a/arch/arm/boot/dts/msm8226-v2.dtsi b/arch/arm/boot/dts/msm8226-v2.dtsi
index 1dab78a..2b3b7c2 100644
--- a/arch/arm/boot/dts/msm8226-v2.dtsi
+++ b/arch/arm/boot/dts/msm8226-v2.dtsi
@@ -17,7 +17,6 @@
*/
/include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
&pm8226_l3 {
regulator-min-microvolt = <750000>;
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index f46b714..013da90a 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -17,7 +17,6 @@
*/
/include/ "msm8226.dtsi"
-/include/ "msm8226-camera.dtsi"
/ {
model = "Qualcomm MSM 8926";
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index fa57244..9badf6d 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -271,11 +271,11 @@
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
+ qcom,boost-curr-lim = <5>;
qcom,cp-sel = <0>;
qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
+ qcom,num-strings = <3>;
qcom,id = <0>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 3d20f7c..9c2509a 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -269,11 +269,11 @@
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
+ qcom,boost-curr-lim = <5>;
qcom,cp-sel = <0>;
qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
+ qcom,num-strings = <3>;
qcom,id = <0>;
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index c1a8792..6955597 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -210,11 +210,11 @@
qcom,default-state = "on";
qcom,max-current = <25>;
qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
+ qcom,boost-curr-lim = <5>;
qcom,cp-sel = <0>;
qcom,switch-freq = <11>;
qcom,ovp-val = <2>;
- qcom,num-strings = <1>;
+ qcom,num-strings = <3>;
qcom,id = <0>;
};
};
diff --git a/arch/arm/boot/dts/msmsamarium-regulator.dtsi b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
new file mode 100644
index 0000000..ae4dc8d
--- /dev/null
+++ b/arch/arm/boot/dts/msmsamarium-regulator.dtsi
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+/* QPNP controlled regulators: */
+
+&spmi_bus {
+ qcom,pma8084@1 {
+ pma8084_s1: regulator@1400 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ /* PMA8084 S2 + S12 = 2 phase VDD_CX supply */
+ pma8084_s2: regulator@1700 {
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s3: regulator@1a00 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s4: regulator@1d00 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ /* Output of PMA8084 S5 and L25 is tied together. */
+ pma8084_s5: regulator@2000 {
+ regulator-min-microvolt = <2150000>;
+ regulator-max-microvolt = <2150000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_s6: regulator@2300 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_s7: regulator@2600 {
+ regulator-min-microvolt = <815000>;
+ regulator-max-microvolt = <900000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_s8: regulator@2900 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s9: regulator@2c00 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s10: regulator@2f00 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_s11: regulator@3200 {
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,enable-time = <500>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <100000>;
+ status = "okay";
+ };
+
+ pma8084_l1: regulator@4000 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ regulator-always-on;
+ qcom,system-load = <10000>;
+ status = "okay";
+ };
+
+ pma8084_l2: regulator@4100 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1175000>;
+ regulator-max-microvolt = <1175000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l3: regulator@4200 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l4: regulator@4300 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l6: regulator@4500 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l8: regulator@4700 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l9: regulator@4800 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l10: regulator@4900 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l11: regulator@4a00 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l12: regulator@4b00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l13: regulator@4c00 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l14: regulator@4d00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l15: regulator@4e00 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l16: regulator@4f00 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l17: regulator@5000 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l18: regulator@5100 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l19: regulator@5200 {
+ regulator-min-microvolt = <2900000>;
+ regulator-max-microvolt = <2900000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l20: regulator@5300 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l21: regulator@5400 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l22: regulator@5500 {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l23: regulator@5600 {
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l24: regulator@5700 {
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l26: regulator@5900 {
+ parent-supply = <&pma8084_s5>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_l27: regulator@5a00 {
+ parent-supply = <&pma8084_s3>;
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs1: regulator@8000 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs2: regulator@8100 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs3: regulator@8200 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_lvs4: regulator@8300 {
+ parent-supply = <&pma8084_s4>;
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+
+ pma8084_mvs1: regulator@8400 {
+ qcom,enable-time = <200>;
+ qcom,pull-down-enable = <1>;
+ status = "okay";
+ };
+ };
+};
+
+&soc {
+ pma8084_s2_corner: s2_corner_vreg {
+ compatible = "qcom,stub-regulator";
+ regulator-name = "8084_s2_corner";
+ regulator-min-microvolt = <1>;
+ regulator-max-microvolt = <7>;
+ qcom,hpm-min-load = <100000>;
+ qcom,consumer-supplies = "vdd_dig", "";
+ };
+};
diff --git a/arch/arm/boot/dts/msmsamarium.dtsi b/arch/arm/boot/dts/msmsamarium.dtsi
index 20954f9..a492561 100644
--- a/arch/arm/boot/dts/msmsamarium.dtsi
+++ b/arch/arm/boot/dts/msmsamarium.dtsi
@@ -242,6 +242,19 @@
cell-index = <0>;
qcom,not-wakeup; /* Needed until MPM is fully configured. */
};
+
+ tsens: tsens@fc4a8000 {
+ compatible = "qcom,msm-tsens";
+ reg = <0xfc4a8000 0x2000>,
+ <0xfc4bc000 0x1000>;
+ reg-names = "tsens_physical", "tsens_eeprom_physical";
+ interrupts = <0 184 0>;
+ qcom,sensors = <11>;
+ qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 3200
+ 3200 3200>;
+ qcom,calib-mode = "fuse_map1";
+ };
};
/include/ "msm-pma8084.dtsi"
+/include/ "msmsamarium-regulator.dtsi"
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index 4315d3f..f4ad0c4 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -402,9 +402,11 @@
CONFIG_CRYPTO_DEV_QCEDEV=m
CONFIG_CRC_CCITT=y
CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_FUSE=y
CONFIG_CORESIGHT_TMC=y
CONFIG_CORESIGHT_FUNNEL=y
CONFIG_CORESIGHT_REPLICATOR=y
CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
CONFIG_CORESIGHT_ETM=y
CONFIG_USB_BAM=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 0db08db..b9d37b8 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -391,3 +391,4 @@
CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y
CONFIG_SENSORS_STK3X1X=y
CONFIG_SENSORS_MMA8X5X=y
+CONFIG_LOGCAT_SIZE=64
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index f2f6558..7901e93 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -480,3 +480,4 @@
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 71742a5..8520f23 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -514,3 +514,4 @@
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c
index ad9dfb2..bb97140 100644
--- a/arch/arm/kernel/sched_clock.c
+++ b/arch/arm/kernel/sched_clock.c
@@ -68,7 +68,9 @@
smp_rmb();
} while (epoch_cyc != cd.epoch_cyc_copy);
- return epoch_ns + cyc_to_ns((cyc - epoch_cyc) & mask, cd.mult, cd.shift);
+ cyc = read_sched_clock();
+ cyc = (cyc - epoch_cyc) & sched_clock_mask;
+ return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
}
/*
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cd71104..e4a647f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -24,7 +24,7 @@
obj-y += acpuclock.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_trace_counters.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += acpuclock-krait.o clock-krait.o
ifdef CONFIG_ARCH_MSM_KRAIT
obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
endif
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 1460f94..820bcf9 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -1583,6 +1583,12 @@
{
int ret = 0;
+ if (in_global_reset) {
+ DMUX_LOG_KERR("%s: modem timeout: already in SSR\n",
+ __func__);
+ return 1;
+ }
+
DMUX_LOG_KERR("%s: modem timeout: BAM DMUX disabled for SSR\n",
__func__);
in_global_reset = 1;
@@ -1755,11 +1761,15 @@
unsigned long flags;
unsigned long time_remaining;
- time_remaining = wait_for_completion_timeout(&shutdown_completion,
- msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
- if (time_remaining == 0) {
- pr_err("%s: shutdown completion timed out\n", __func__);
- ssrestart_check();
+ if (!in_global_reset) {
+ time_remaining = wait_for_completion_timeout(
+ &shutdown_completion,
+ msecs_to_jiffies(SHUTDOWN_TIMEOUT_MS));
+ if (time_remaining == 0) {
+ DMUX_LOG_KERR("%s: shutdown completion timed out\n",
+ __func__);
+ ssrestart_check();
+ }
}
bam_connection_is_active = 0;
@@ -2226,6 +2236,11 @@
{
static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
+ if (in_global_reset) {
+ BAM_DMUX_LOG("%s: skipped due to SSR\n", __func__);
+ return;
+ }
+
BAM_DMUX_LOG("%s: apps ack %d->%d\n", __func__,
clear_bit & 0x1, ~clear_bit & 0x1);
smsm_change_state(SMSM_APPS_STATE,
diff --git a/arch/arm/mach-msm/board-samarium.c b/arch/arm/mach-msm/board-samarium.c
index 6133983..52a947b 100644
--- a/arch/arm/mach-msm/board-samarium.c
+++ b/arch/arm/mach-msm/board-samarium.c
@@ -16,6 +16,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/memory.h>
+#include <linux/msm_tsens.h>
#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -35,6 +36,10 @@
#include "modem_notifier.h"
static struct clk_lookup msm_clocks_dummy[] = {
+ CLK_DUMMY("xo", CXO_CLK, "fc880000.qcom,mss", OFF),
+ CLK_DUMMY("bus_clk", MSS_BIMC_Q6_CLK, "fc880000.qcom,mss", OFF),
+ CLK_DUMMY("iface_clk", MSS_CFG_AHB_CLK, "fc880000.qcom,mss", OFF),
+ CLK_DUMMY("mem_clk", BOOT_ROM_AHB_CLK, "fc880000.qcom,mss", OFF),
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
@@ -109,6 +114,7 @@
msm_init_modem_notifier_list();
msm_smd_init();
msm_clock_init(&msm_dummy_clock_init_data);
+ tsens_tm_init_driver();
}
static void __init msmsamarium_map_io(void)
diff --git a/arch/arm/mach-msm/clock-8084.c b/arch/arm/mach-msm/clock-8084.c
index ffd33a8..939a637 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -415,6 +415,7 @@
CLK_DUMMY("core_clk", qdss_clk.c, "fc342000.cti", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc343000.cti", OFF),
CLK_DUMMY("core_clk", qdss_clk.c, "fc344000.cti", OFF),
+ CLK_DUMMY("core_clk", qdss_clk.c, "fd828018.hwevent", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc326000.tmc", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc324000.replicator", OFF),
@@ -444,6 +445,13 @@
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc342000.cti", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc343000.cti", OFF),
CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fc344000.cti", OFF),
+ CLK_DUMMY("core_a_clk", qdss_a_clk.c, "fd828018.hwevent", OFF),
+
+ CLK_DUMMY("core_mmss_clk", mmss_misc_ahb_clk.c, "fd828018.hwevent",
+ OFF),
+
+ CLK_DUMMY("iface_clk", gcc_prng_ahb_clk.c,
+ "f9bff000.qcom,msm-rng", OFF),
};
struct clock_init_data msm8084_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 383af54..8a79687 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -3389,11 +3389,13 @@
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6d.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6a.qcom,camera"),
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "20.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6f.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "90.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6d.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6a.qcom,camera"),
CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "6c.qcom,camera"),
+ CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "20.qcom,camera"),
/* eeprom clocks */
CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6c.qcom,eeprom"),
diff --git a/arch/arm/mach-msm/clock-krait.c b/arch/arm/mach-msm/clock-krait.c
new file mode 100644
index 0000000..b96ba62
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2013, 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+
+#include <linux/clk.h>
+#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
+#include <mach/msm-krait-l2-accessors.h>
+#include "clock-krait.h"
+#include "avs.h"
+
+static DEFINE_SPINLOCK(kpss_clock_reg_lock);
+
+static void __kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+ unsigned long flags;
+ u32 regval;
+
+ spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+ regval = get_l2_indirect_reg(mux->offset);
+ regval &= ~(mux->mask << mux->shift);
+ regval |= (sel & mux->mask) << mux->shift;
+ set_l2_indirect_reg(mux->offset, regval);
+ spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+ /* Wait for switch to complete. */
+ mb();
+ udelay(1);
+}
+static int kpss_mux_set_sel(struct mux_clk *mux, int sel)
+{
+ mux->en_mask = sel;
+ if (mux->c.count)
+ __kpss_mux_set_sel(mux, sel);
+ return 0;
+}
+
+static int kpss_mux_get_sel(struct mux_clk *mux)
+{
+ u32 sel;
+
+ sel = get_l2_indirect_reg(mux->offset);
+ sel >>= mux->shift;
+ sel &= mux->mask;
+ mux->en_mask = sel;
+
+ return sel;
+}
+
+static int kpss_mux_enable(struct mux_clk *mux)
+{
+ __kpss_mux_set_sel(mux, mux->en_mask);
+ return 0;
+}
+
+static void kpss_mux_disable(struct mux_clk *mux)
+{
+ __kpss_mux_set_sel(mux, mux->safe_sel);
+}
+
+struct clk_mux_ops clk_mux_ops_kpss = {
+ .enable = kpss_mux_enable,
+ .disable = kpss_mux_disable,
+ .set_mux_sel = kpss_mux_set_sel,
+ .get_mux_sel = kpss_mux_get_sel,
+};
+
+/*
+ * The divider can divide by 2, 4, 6 and 8. But we only really need div-2. So
+ * force it to div-2 during handoff and treat it like a fixed div-2 clock.
+ */
+static int kpss_div2_get_div(struct div_clk *div)
+{
+ unsigned long flags;
+ u32 regval;
+ int val;
+
+ spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+ regval = get_l2_indirect_reg(div->offset);
+ val = (regval >> div->shift) && div->mask;
+ regval &= ~(div->mask << div->shift);
+ set_l2_indirect_reg(div->offset, regval);
+ spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+
+ val = (val + 1) * 2;
+ WARN(val != 2, "Divider %s was configured to div-%d instead of 2!\n",
+ div->c.dbg_name, val);
+
+ return 2;
+}
+
+struct clk_div_ops clk_div_ops_kpss_div2 = {
+ .get_div = kpss_div2_get_div,
+};
+
+#define LOCK_BIT BIT(16)
+
+/* Initialize a HFPLL at a given rate and enable it. */
+static void __hfpll_clk_init_once(struct clk *c)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+
+ if (likely(h->init_done))
+ return;
+
+ /* Configure PLL parameters for integer mode. */
+ writel_relaxed(hd->config_val, h->base + hd->config_offset);
+ writel_relaxed(0, h->base + hd->m_offset);
+ writel_relaxed(1, h->base + hd->n_offset);
+
+ if (hd->user_offset) {
+ u32 regval = hd->user_val;
+ unsigned long rate;
+
+ rate = readl_relaxed(h->base + hd->l_offset) * h->src_rate;
+
+ /* Pick the right VCO. */
+ if (rate > hd->low_vco_max_rate)
+ regval |= hd->user_vco_mask;
+ writel_relaxed(regval, h->base + hd->user_offset);
+ }
+
+ if (hd->droop_offset)
+ writel_relaxed(hd->droop_val, h->base + hd->droop_offset);
+
+ h->init_done = true;
+}
+
+/* Enable an already-configured HFPLL. */
+static int hfpll_clk_enable(struct clk *c)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+
+ if (!h->base)
+ return -ENODEV;
+
+ __hfpll_clk_init_once(c);
+
+ /* Disable PLL bypass mode. */
+ writel_relaxed(0x2, h->base + hd->mode_offset);
+
+ /*
+ * H/W requires a 5us delay between disabling the bypass and
+ * de-asserting the reset. Delay 10us just to be safe.
+ */
+ mb();
+ udelay(10);
+
+ /* De-assert active-low PLL reset. */
+ writel_relaxed(0x6, h->base + hd->mode_offset);
+
+ /* Wait for PLL to lock. */
+ if (hd->status_offset) {
+ while (!(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT))
+ ;
+ } else {
+ mb();
+ udelay(60);
+ }
+
+ /* Enable PLL output. */
+ writel_relaxed(0x7, h->base + hd->mode_offset);
+
+ /* Make sure the enable is done before returning. */
+ mb();
+
+ return 0;
+}
+
+static void hfpll_clk_disable(struct clk *c)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+
+ /*
+ * Disable the PLL output, disable test mode, enable the bypass mode,
+ * and assert the reset.
+ */
+ writel_relaxed(0, h->base + hd->mode_offset);
+}
+
+static long hfpll_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+ unsigned long rrate;
+
+ if (!h->src_rate)
+ return 0;
+
+ rate = max(rate, hd->min_rate);
+ rate = min(rate, hd->max_rate);
+
+ rrate = DIV_ROUND_UP(rate, h->src_rate) * h->src_rate;
+ if (rrate > hd->max_rate)
+ rrate -= h->src_rate;
+
+ return rrate;
+}
+
+/*
+ * For optimization reasons, assumes no downstream clocks are actively using
+ * it.
+ */
+static int hfpll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+ unsigned long flags;
+ u32 l_val;
+
+ if (!h->base)
+ return -ENODEV;
+
+ if (rate != hfpll_clk_round_rate(c, rate))
+ return -EINVAL;
+
+ l_val = rate / h->src_rate;
+
+ spin_lock_irqsave(&c->lock, flags);
+
+ if (c->count)
+ hfpll_clk_disable(c);
+
+ /* Pick the right VCO. */
+ if (hd->user_offset) {
+ u32 regval;
+ regval = readl_relaxed(h->base + hd->user_offset);
+ if (rate <= hd->low_vco_max_rate)
+ regval &= ~hd->user_vco_mask;
+ else
+ regval |= hd->user_vco_mask;
+ writel_relaxed(regval, h->base + hd->user_offset);
+ }
+
+ writel_relaxed(l_val, h->base + hd->l_offset);
+
+ if (c->count)
+ hfpll_clk_enable(c);
+
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ return 0;
+}
+
+static enum handoff hfpll_clk_handoff(struct clk *c)
+{
+ struct hfpll_clk *h = to_hfpll_clk(c);
+ struct hfpll_data const *hd = h->d;
+ u32 l_val, mode;
+
+ if (!hd)
+ return HANDOFF_DISABLED_CLK;
+
+ if (!h->base)
+ return HANDOFF_DISABLED_CLK;
+
+ /* Assume parent rate doesn't change and cache it. */
+ h->src_rate = clk_get_rate(c->parent);
+ l_val = readl_relaxed(h->base + hd->l_offset);
+ c->rate = l_val * h->src_rate;
+
+ mode = readl_relaxed(h->base + hd->mode_offset) & 0x7;
+ if (mode != 0x7) {
+ __hfpll_clk_init_once(c);
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ if (hd->status_offset &&
+ !(readl_relaxed(h->base + hd->status_offset) & LOCK_BIT)) {
+ WARN(1, "HFPLL %s is ON, but not locked!\n", c->dbg_name);
+ hfpll_clk_disable(c);
+ __hfpll_clk_init_once(c);
+ return HANDOFF_DISABLED_CLK;
+ }
+
+ WARN(c->rate < hd->min_rate || c->rate > hd->max_rate,
+ "HFPLL %s rate %lu outside spec!\n", c->dbg_name, c->rate);
+
+ return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_hfpll = {
+ .enable = hfpll_clk_enable,
+ .disable = hfpll_clk_disable,
+ .round_rate = hfpll_clk_round_rate,
+ .set_rate = hfpll_clk_set_rate,
+ .handoff = hfpll_clk_handoff,
+};
+
+struct cpu_hwcg_action {
+ bool read;
+ bool enable;
+};
+
+static void cpu_hwcg_rw(void *info)
+{
+ struct cpu_hwcg_action *action = info;
+
+ u32 val;
+ asm volatile ("mrc p15, 7, %[cpmr0], c15, c0, 5\n\t"
+ : [cpmr0]"=r" (val));
+
+ if (action->read) {
+ action->enable = !(val & BIT(0));
+ return;
+ }
+
+ if (action->enable)
+ val &= ~BIT(0);
+ else
+ val |= BIT(0);
+
+ asm volatile ("mcr p15, 7, %[cpmr0], c15, c0, 5\n\t"
+ : : [cpmr0]"r" (val));
+}
+
+static void kpss_cpu_enable_hwcg(struct clk *c)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+ struct cpu_hwcg_action action = { .enable = true };
+
+ smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static void kpss_cpu_disable_hwcg(struct clk *c)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+ struct cpu_hwcg_action action = { .enable = false };
+
+ smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+}
+
+static int kpss_cpu_in_hwcg_mode(struct clk *c)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+ struct cpu_hwcg_action action = { .read = true };
+
+ smp_call_function_single(cpu->id, cpu_hwcg_rw, &action, 1);
+ return action.enable;
+}
+
+static enum handoff kpss_cpu_handoff(struct clk *c)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+
+ c->rate = clk_get_rate(c->parent);
+
+ /*
+ * Don't unnecessarily turn on the parents for an offline CPU and
+ * then have them turned off at late init.
+ */
+ return (cpu_online(cpu->id) ?
+ HANDOFF_ENABLED_CLK : HANDOFF_DISABLED_CLK);
+}
+
+u32 find_dscr(struct avs_data *t, unsigned long rate)
+{
+ int i;
+
+ if (!t)
+ return 0;
+
+ for (i = 0; i < t->num; i++) {
+ if (t->rate[i] == rate)
+ return t->dscr[i];
+ }
+
+ return 0;
+}
+
+static int kpss_cpu_pre_set_rate(struct clk *c, unsigned long new_rate)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+ u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+ if (!c->prepare_count)
+ return -ENODEV;
+
+ if (dscr)
+ AVS_DISABLE(cpu->id);
+ return 0;
+}
+
+static long kpss_core_round_rate(struct clk *c, unsigned long rate)
+{
+ if (c->fmax && c->num_fmax)
+ rate = min(rate, c->fmax[c->num_fmax-1]);
+
+ return clk_round_rate(c->parent, rate);
+}
+
+static int kpss_core_set_rate(struct clk *c, unsigned long rate)
+{
+ if (!c->prepare_count)
+ return -ENODEV;
+
+ return clk_set_rate(c->parent, rate);
+}
+
+static void kpss_cpu_post_set_rate(struct clk *c, unsigned long old_rate)
+{
+ struct kpss_core_clk *cpu = to_kpss_core_clk(c);
+ u32 dscr = find_dscr(cpu->avs_tbl, c->rate);
+
+ /*
+ * FIXME: If AVS enable/disable needs to be done in the
+ * enable/disable op to correctly handle power collapse, then might
+ * need to grab the spinlock here.
+ */
+ if (dscr)
+ AVS_ENABLE(cpu->id, dscr);
+}
+
+static unsigned long kpss_core_get_rate(struct clk *c)
+{
+ return clk_get_rate(c->parent);
+}
+
+static long kpss_core_list_rate(struct clk *c, unsigned n)
+{
+ if (!c->fmax || c->num_fmax <= n)
+ return -ENXIO;
+
+ return c->fmax[n];
+}
+
+struct clk_ops clk_ops_kpss_cpu = {
+ .enable_hwcg = kpss_cpu_enable_hwcg,
+ .disable_hwcg = kpss_cpu_disable_hwcg,
+ .in_hwcg_mode = kpss_cpu_in_hwcg_mode,
+ .pre_set_rate = kpss_cpu_pre_set_rate,
+ .round_rate = kpss_core_round_rate,
+ .set_rate = kpss_core_set_rate,
+ .post_set_rate = kpss_cpu_post_set_rate,
+ .get_rate = kpss_core_get_rate,
+ .list_rate = kpss_core_list_rate,
+ .handoff = kpss_cpu_handoff,
+};
+
+#define SLPDLY_SHIFT 10
+#define SLPDLY_MASK 0x3
+static void kpss_l2_enable_hwcg(struct clk *c)
+{
+ struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+ u32 regval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+ regval = get_l2_indirect_reg(l2->cp15_iaddr);
+ regval &= ~(SLPDLY_MASK << SLPDLY_SHIFT);
+ regval |= l2->l2_slp_delay;
+ set_l2_indirect_reg(l2->cp15_iaddr, regval);
+ spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static void kpss_l2_disable_hwcg(struct clk *c)
+{
+ struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+ u32 regval;
+ unsigned long flags;
+
+ /*
+ * NOTE: Should not be called when HW clock gating is already
+ * disabled.
+ */
+ spin_lock_irqsave(&kpss_clock_reg_lock, flags);
+ regval = get_l2_indirect_reg(l2->cp15_iaddr);
+ l2->l2_slp_delay = regval & (SLPDLY_MASK << SLPDLY_SHIFT);
+ regval |= (SLPDLY_MASK << SLPDLY_SHIFT);
+ set_l2_indirect_reg(l2->cp15_iaddr, regval);
+ spin_unlock_irqrestore(&kpss_clock_reg_lock, flags);
+}
+
+static int kpss_l2_in_hwcg_mode(struct clk *c)
+{
+ struct kpss_core_clk *l2 = to_kpss_core_clk(c);
+ u32 regval;
+
+ regval = get_l2_indirect_reg(l2->cp15_iaddr);
+ regval >>= SLPDLY_SHIFT;
+ regval &= SLPDLY_MASK;
+ return (regval != SLPDLY_MASK);
+}
+
+static enum handoff kpss_l2_handoff(struct clk *c)
+{
+ c->rate = clk_get_rate(c->parent);
+ return HANDOFF_ENABLED_CLK;
+}
+
+struct clk_ops clk_ops_kpss_l2 = {
+ .enable_hwcg = kpss_l2_enable_hwcg,
+ .disable_hwcg = kpss_l2_disable_hwcg,
+ .in_hwcg_mode = kpss_l2_in_hwcg_mode,
+ .round_rate = kpss_core_round_rate,
+ .set_rate = kpss_core_set_rate,
+ .get_rate = kpss_core_get_rate,
+ .list_rate = kpss_core_list_rate,
+ .handoff = kpss_l2_handoff,
+};
diff --git a/arch/arm/mach-msm/clock-krait.h b/arch/arm/mach-msm/clock-krait.h
new file mode 100644
index 0000000..2691a8c
--- /dev/null
+++ b/arch/arm/mach-msm/clock-krait.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+#define __ARCH_ARM_MACH_MSM_CLOCK_KRAIT_H
+
+#include <mach/clk-provider.h>
+#include <mach/clock-generic.h>
+
+extern struct clk_mux_ops clk_mux_ops_kpss;
+extern struct clk_div_ops clk_div_ops_kpss_div2;
+
+#define DEFINE_KPSS_DIV2_CLK(clk_name, _parent, _offset) \
+static struct div_clk clk_name = { \
+ .div = 2, \
+ .min_div = 2, \
+ .max_div = 2, \
+ .ops = &clk_div_ops_kpss_div2, \
+ .offset = _offset, \
+ .mask = 0x3, \
+ .shift = 6, \
+ .c = { \
+ .parent = _parent, \
+ .dbg_name = #clk_name, \
+ .ops = &clk_ops_div, \
+ .flags = CLKFLAG_NO_RATE_CACHE, \
+ CLK_INIT(clk_name.c), \
+ } \
+}
+
+struct hfpll_data {
+ const u32 mode_offset;
+ const u32 l_offset;
+ const u32 m_offset;
+ const u32 n_offset;
+ const u32 user_offset;
+ const u32 droop_offset;
+ const u32 config_offset;
+ const u32 status_offset;
+
+ const u32 droop_val;
+ const u32 config_val;
+ const u32 user_val;
+ const u32 user_vco_mask;
+ unsigned long low_vco_max_rate;
+
+ unsigned long min_rate;
+ unsigned long max_rate;
+};
+
+struct hfpll_clk {
+ void * __iomem base;
+ struct hfpll_data const *d;
+ unsigned long src_rate;
+ int init_done;
+
+ struct clk c;
+};
+
+static inline struct hfpll_clk *to_hfpll_clk(struct clk *c)
+{
+ return container_of(c, struct hfpll_clk, c);
+}
+
+extern struct clk_ops clk_ops_hfpll;
+
+struct avs_data {
+ unsigned long *rate;
+ u32 *dscr;
+ int num;
+};
+
+struct kpss_core_clk {
+ int id;
+ u32 cp15_iaddr;
+ u32 l2_slp_delay;
+ struct avs_data *avs_tbl;
+ struct clk c;
+};
+
+static inline struct kpss_core_clk *to_kpss_core_clk(struct clk *c)
+{
+ return container_of(c, struct kpss_core_clk, c);
+}
+
+extern struct clk_ops clk_ops_kpss_cpu;
+extern struct clk_ops clk_ops_kpss_l2;
+
+#endif
diff --git a/arch/arm/mach-msm/clock-krypton.c b/arch/arm/mach-msm/clock-krypton.c
index 0b615cc..176dc32 100644
--- a/arch/arm/mach-msm/clock-krypton.c
+++ b/arch/arm/mach-msm/clock-krypton.c
@@ -18,12 +18,12 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/clk.h>
-#include <linux/iopoll.h>
#include <linux/regulator/consumer.h>
+#include <linux/iopoll.h>
+#include <mach/clk.h>
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
-#include <mach/rpm-smd.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -31,97 +31,2051 @@
#include "clock-voter.h"
#include "clock.h"
-static struct clk_lookup msm_clocks_dummy[] = {
- CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
- CLK_DUMMY("core_clk", SPI_CLK, "f9928000.spi", OFF),
- CLK_DUMMY("iface_clk", SPI_P_CLK, "f9928000.spi", OFF),
-
- CLK_DUMMY("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc", OFF),
- CLK_DUMMY("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc", OFF),
- CLK_DUMMY("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc", OFF),
- CLK_DUMMY("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc", OFF),
- CLK_DUMMY("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc", OFF),
- CLK_DUMMY("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc", OFF),
- CLK_DUMMY("mem_clk", bimc_msmbus_clk.c, "msm_bimc", OFF),
- CLK_DUMMY("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc", OFF),
- CLK_DUMMY("mem_clk", bimc_acpu_a_clk.c, "", OFF),
- CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
- CLK_DUMMY("dma_bam_pclk", DMA_BAM_P_CLK, "msm_sps", OFF),
-
- CLK_DUMMY("clktype", gcc_imem_axi_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_imem_cfg_ahb_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_mss_cfg_ahb_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_mss_q6_bimc_axi_clk , "drivername", OFF),
- CLK_DUMMY("mem_clk", gcc_usb30_master_clk , "drivername", OFF),
- CLK_DUMMY("sleep_clk", gcc_usb30_sleep_clk , "drivername", OFF),
- CLK_DUMMY("utmi_clk", gcc_usb30_mock_utmi_clk , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_usb_hsic_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_usb_hsic_system_clk , "drivername", OFF),
- CLK_DUMMY("phyclk", gcc_usb_hsic_clk , "drivername", OFF),
- CLK_DUMMY("cal_clk", gcc_usb_hsic_io_cal_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_usb_hs_system_clk , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_usb_hs_ahb_clk , "drivername", OFF),
- CLK_DUMMY("sleep_a_clk", gcc_usb2a_phy_sleep_clk , "drivername", OFF),
- CLK_DUMMY("sleep_b_clk", gcc_usb2b_phy_sleep_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_sdcc2_apps_clk , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_sdcc2_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_sdcc3_apps_clk , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_sdcc3_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", sdcc3_apps_clk_src , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup1_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup1_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart1_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup2_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup2_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart2_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup3_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart3_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup4_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup4_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart4_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup5_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup5_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart5_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup6_spi_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_qup6_i2c_apps_clk, "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_blsp1_uart6_apps_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", blsp1_uart6_apps_clk_src , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_pdm_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_pdm2_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_prng_ahb_clk , "drivername", OFF),
- CLK_DUMMY("dma_bam_pclk", gcc_bam_dma_ahb_clk , "drivername", OFF),
- CLK_DUMMY("mem_clk", gcc_boot_rom_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_ce1_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_ce1_axi_clk , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_ce1_ahb_clk , "drivername", OFF),
- CLK_DUMMY("core_clk_src", ce1_clk_src , "drivername", OFF),
- CLK_DUMMY("bus_clk", gcc_lpass_q6_axi_clk , "drivername", OFF),
- CLK_DUMMY("clktype", pcie_pipe_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_gp1_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gp1_clk_src , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_gp2_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gp2_clk_src , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_gp3_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gp3_clk_src , "drivername", OFF),
- CLK_DUMMY("core_clk", gcc_ipa_clk , "drivername", OFF),
- CLK_DUMMY("iface_clk", gcc_ipa_cnoc_clk , "drivername", OFF),
- CLK_DUMMY("inactivity_clk", gcc_ipa_sleep_clk , "drivername", OFF),
- CLK_DUMMY("core_clk_src", ipa_clk_src , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_dcs_clk , "drivername", OFF),
- CLK_DUMMY("clktype", dcs_clk_src , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_pcie_cfg_ahb_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_pcie_pipe_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_pcie_axi_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_pcie_sleep_clk , "drivername", OFF),
- CLK_DUMMY("clktype", gcc_pcie_axi_mstr_clk , "drivername", OFF),
- CLK_DUMMY("clktype", pcie_pipe_clk_src , "drivername", OFF),
- CLK_DUMMY("clktype", pcie_aux_clk_src , "drivername", OFF),
+enum {
+ GCC_BASE,
+ LPASS_BASE,
+ APCS_GLB_BASE,
+ APCS_GCC_BASE,
+ APCS_ACC_BASE,
+ N_BASES,
};
+static void __iomem *virt_bases[N_BASES];
+
+#define GCC_REG_BASE(x) (void __iomem *)(virt_bases[GCC_BASE] + (x))
+#define APCS_GCC_BASE(x) (void __iomem *)(virt_bases[APCS_GCC_BASE] + (x))
+
+/* Mux source select values */
+#define xo_source_val 0
+#define gpll0_source_val 1
+#define gpll1_source_val 4
+#define gnd_source_val 5
+
+#define usb3_pipe_clk_source_val 2
+#define pcie_pipe_clk_source_val 2
+
+/* Prevent a divider of -1 */
+#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
+
+#define F(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_clk = &s.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define F_EXT_SRC(f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(FIXDIV(div))) \
+ | BVAL(10, 8, s##_source_val), \
+ }
+
+#define VDD_DIG_FMAX_MAP1(l1, f1) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP2(l1, f1, l2, f2) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+#define VDD_DIG_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \
+ .vdd_class = &vdd_dig, \
+ .fmax = (unsigned long[VDD_DIG_NUM]) { \
+ [VDD_DIG_##l1] = (f1), \
+ [VDD_DIG_##l2] = (f2), \
+ [VDD_DIG_##l3] = (f3), \
+ }, \
+ .num_fmax = VDD_DIG_NUM
+
+enum vdd_dig_levels {
+ VDD_DIG_NONE,
+ VDD_DIG_LOW,
+ VDD_DIG_NOMINAL,
+ VDD_DIG_HIGH,
+ VDD_DIG_NUM
+};
+
+static int vdd_corner[] = {
+ RPM_REGULATOR_CORNER_NONE, /* VDD_DIG_NONE */
+ RPM_REGULATOR_CORNER_SVS_SOC, /* VDD_DIG_LOW */
+ RPM_REGULATOR_CORNER_NORMAL, /* VDD_DIG_NOMINAL */
+ RPM_REGULATOR_CORNER_SUPER_TURBO, /* VDD_DIG_HIGH */
+};
+
+static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
+
+#define RPM_MISC_CLK_TYPE 0x306b6c63
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+#define RPM_QPIC_CLK_TYPE 0x63697071
+
+#define RPM_SMD_KEY_ENABLE 0x62616E45
+
+#define CXO_ID 0x0
+#define QDSS_ID 0x1
+
+#define PNOC_ID 0x0
+#define SNOC_ID 0x1
+#define CNOC_ID 0x2
+
+#define BIMC_ID 0x0
+#define QPIC_ID 0x0
+
+#define D0_ID 1
+#define D1_ID 2
+#define A0_ID 3
+#define A1_ID 4
+#define A2_ID 5
+
+#define APCS_CLK_DIAG (0x001C)
+#define GPLL0_MODE (0x0000)
+#define GPLL1_MODE (0x0040)
+#define SYS_NOC_USB3_AXI_CBCR (0x0108)
+#define MSS_CFG_AHB_CBCR (0x0280)
+#define MSS_Q6_BIMC_AXI_CBCR (0x0284)
+#define USB_30_BCR (0x03C0)
+#define USB30_MASTER_CBCR (0x03C8)
+#define USB30_SLEEP_CBCR (0x03CC)
+#define USB30_MOCK_UTMI_CBCR (0x03D0)
+#define USB30_MASTER_CMD_RCGR (0x03D4)
+#define USB30_MOCK_UTMI_CMD_RCGR (0x03E8)
+#define USB3_PIPE_CBCR (0x1B90)
+#define USB3_AUX_CBCR (0x1B94)
+#define USB3_PIPE_CMD_RCGR (0x1B98)
+#define USB3_AUX_CMD_RCGR (0x1BC0)
+#define USB_HS_HSIC_BCR (0x0400)
+#define USB_HSIC_AHB_CBCR (0x0408)
+#define USB_HSIC_SYSTEM_CMD_RCGR (0x041C)
+#define USB_HSIC_SYSTEM_CBCR (0x040C)
+#define USB_HSIC_CMD_RCGR (0x0440)
+#define USB_HSIC_CBCR (0x0410)
+#define USB_HSIC_IO_CAL_CMD_RCGR (0x0458)
+#define USB_HSIC_IO_CAL_CBCR (0x0414)
+#define USB_HSIC_IO_CAL_SLEEP_CBCR (0x0418)
+#define USB_HSIC_XCVR_FS_CMD_RCGR (0x0424)
+#define USB_HSIC_XCVR_FS_CBCR (0x042C)
+#define USB_HS_BCR (0x0480)
+#define USB_HS_SYSTEM_CBCR (0x0484)
+#define USB_HS_AHB_CBCR (0x0488)
+#define USB_HS_SYSTEM_CMD_RCGR (0x0490)
+#define SDCC2_APPS_CMD_RCGR (0x0510)
+#define SDCC2_APPS_CBCR (0x0504)
+#define SDCC2_AHB_CBCR (0x0508)
+#define SDCC3_APPS_CMD_RCGR (0x0550)
+#define SDCC3_APPS_CBCR (0x0544)
+#define SDCC3_AHB_CBCR (0x0548)
+#define BLSP1_AHB_CBCR (0x05C4)
+#define BLSP1_QUP1_SPI_APPS_CBCR (0x0644)
+#define BLSP1_QUP1_I2C_APPS_CBCR (0x0648)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR (0x0660)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR (0x06E0)
+#define BLSP1_QUP3_I2C_APPS_CMD_RCGR (0x0760)
+#define BLSP1_QUP4_I2C_APPS_CMD_RCGR (0x07E0)
+#define BLSP1_QUP5_I2C_APPS_CMD_RCGR (0x0860)
+#define BLSP1_QUP6_I2C_APPS_CMD_RCGR (0x08E0)
+#define BLSP1_QUP1_SPI_APPS_CMD_RCGR (0x064C)
+#define BLSP1_UART1_APPS_CBCR (0x0684)
+#define BLSP1_UART1_APPS_CMD_RCGR (0x068C)
+#define BLSP1_QUP2_SPI_APPS_CBCR (0x06C4)
+#define BLSP1_QUP2_I2C_APPS_CBCR (0x06C8)
+#define BLSP1_QUP2_SPI_APPS_CMD_RCGR (0x06CC)
+#define BLSP1_UART2_APPS_CBCR (0x0704)
+#define BLSP1_UART2_APPS_CMD_RCGR (0x070C)
+#define BLSP1_QUP3_SPI_APPS_CBCR (0x0744)
+#define BLSP1_QUP3_I2C_APPS_CBCR (0x0748)
+#define BLSP1_QUP3_SPI_APPS_CMD_RCGR (0x074C)
+#define BLSP1_UART3_APPS_CBCR (0x0784)
+#define BLSP1_UART3_APPS_CMD_RCGR (0x078C)
+#define BLSP1_QUP4_SPI_APPS_CBCR (0x07C4)
+#define BLSP1_QUP4_I2C_APPS_CBCR (0x07C8)
+#define BLSP1_QUP4_SPI_APPS_CMD_RCGR (0x07CC)
+#define BLSP1_UART4_APPS_CBCR (0x0804)
+#define BLSP1_UART4_APPS_CMD_RCGR (0x080C)
+#define BLSP1_QUP5_SPI_APPS_CBCR (0x0844)
+#define BLSP1_QUP5_I2C_APPS_CBCR (0x0848)
+#define BLSP1_QUP5_SPI_APPS_CMD_RCGR (0x084C)
+#define BLSP1_UART5_APPS_CBCR (0x0884)
+#define BLSP1_UART5_APPS_CMD_RCGR (0x088C)
+#define BLSP1_QUP6_SPI_APPS_CBCR (0x08C4)
+#define BLSP1_QUP6_I2C_APPS_CBCR (0x08C8)
+#define BLSP1_QUP6_SPI_APPS_CMD_RCGR (0x08CC)
+#define BLSP1_UART6_APPS_CBCR (0x0904)
+#define BLSP1_UART6_APPS_CMD_RCGR (0x090C)
+#define PDM_AHB_CBCR (0x0CC4)
+#define PDM2_CBCR (0x0CCC)
+#define PDM2_CMD_RCGR (0x0CD0)
+#define PRNG_AHB_CBCR (0x0D04)
+#define BAM_DMA_AHB_CBCR (0x0D44)
+#define BAM_DMA_INACTIVITY_TIMERS_CBCR (0x0D48)
+#define BOOT_ROM_AHB_CBCR (0x0E04)
+#define RPM_MISC (0x0F24)
+#define CE1_CMD_RCGR (0x1050)
+#define CE1_CBCR (0x1044)
+#define CE1_AXI_CBCR (0x1048)
+#define CE1_AHB_CBCR (0x104C)
+#define GCC_XO_DIV4_CBCR (0x10C8)
+#define LPASS_Q6_AXI_CBCR (0x11C0)
+#define APCS_GPLL_ENA_VOTE (0x1480)
+#define APCS_CLOCK_BRANCH_ENA_VOTE (0x1484)
+#define GCC_DEBUG_CLK_CTL (0x1880)
+#define CLOCK_FRQ_MEASURE_CTL (0x1884)
+#define CLOCK_FRQ_MEASURE_STATUS (0x1888)
+#define PLLTEST_PAD_CFG (0x188C)
+#define PCIE_CFG_AHB_CBCR (0x1C04)
+#define PCIE_PIPE_CBCR (0x1C08)
+#define PCIE_AXI_CBCR (0x1C0C)
+#define PCIE_SLEEP_CBCR (0x1C10)
+#define PCIE_AXI_MSTR_CBCR (0x1C2C)
+#define PCIE_PIPE_CMD_RCGR (0x1C14)
+#define PCIE_AUX_CMD_RCGR (0x1E00)
+#define Q6SS_AHB_LFABIF_CBCR (0x22000)
+#define Q6SS_AHBM_CBCR (0x22004)
+
+DEFINE_CLK_RPM_SMD_BRANCH(xo, xo_a_clk, RPM_MISC_CLK_TYPE, CXO_ID, 19200000);
+
+static unsigned int soft_vote_gpll0;
+
+static struct pll_vote_clk gpll0 = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(31),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .rate = 600000000,
+ .parent = &xo.c,
+ .dbg_name = "gpll0",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0.c),
+ },
+};
+
+/* Don't vote for xo if using this clock to allow xo shutdown */
+static struct pll_vote_clk gpll0_ao = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(0),
+ .status_reg = (void __iomem *)GPLL0_MODE,
+ .status_mask = BIT(31),
+ .soft_vote = &soft_vote_gpll0,
+ .soft_vote_mask = PLL_SOFT_VOTE_ACPU,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .rate = 600000000,
+ .dbg_name = "gpll0_ao",
+ .ops = &clk_ops_pll_acpu_vote,
+ CLK_INIT(gpll0_ao.c),
+ },
+};
+
+static struct pll_vote_clk gpll1 = {
+ .en_reg = (void __iomem *)APCS_GPLL_ENA_VOTE,
+ .en_mask = BIT(1),
+ .status_reg = (void __iomem *)GPLL1_MODE,
+ .status_mask = BIT(31),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .rate = 480000000,
+ .parent = &xo.c,
+ .dbg_name = "gpll1",
+ .ops = &clk_ops_pll_vote,
+ CLK_INIT(gpll1.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
+ F( 125000000, gpll0, 1, 5, 24),
+ F_END
+};
+
+static struct rcg_clk usb30_master_clk_src = {
+ .cmd_rcgr_reg = USB30_MASTER_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_usb30_master_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb30_master_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 125000000),
+ CLK_INIT(usb30_master_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_i2c_apps_clk[] = {
+ F( 19200000, xo, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup1_i2c_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_6_spi_apps_clk[] = {
+ F( 960000, xo, 10, 1, 2),
+ F( 4800000, xo, 4, 0, 0),
+ F( 9600000, xo, 2, 0, 0),
+ F( 15000000, gpll0, 10, 1, 4),
+ F( 19200000, xo, 1, 0, 0),
+ F( 25000000, gpll0, 12, 1, 2),
+ F( 50000000, gpll0, 12, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_qup1_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP1_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup1_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup1_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup2_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup2_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP2_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup2_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup2_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup3_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup3_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup3_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup3_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup4_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup4_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup4_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup4_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup5_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup5_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup5_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup5_spi_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_i2c_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_I2C_APPS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_i2c_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_i2c_apps_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 19200000),
+ CLK_INIT(blsp1_qup6_i2c_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_QUP6_SPI_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_qup1_6_spi_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_qup6_spi_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 25000000, NOMINAL, 50000000),
+ CLK_INIT(blsp1_qup6_spi_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_uart1_6_apps_clk[] = {
+ F( 3686400, gpll0, 1, 96, 15625),
+ F( 7372800, gpll0, 1, 192, 15625),
+ F( 14745600, gpll0, 1, 384, 15625),
+ F( 16000000, gpll0, 5, 2, 15),
+ F( 19200000, xo, 1, 0, 0),
+ F( 24000000, gpll0, 5, 1, 5),
+ F( 32000000, gpll0, 1, 4, 75),
+ F( 40000000, gpll0, 15, 0, 0),
+ F( 46400000, gpll0, 1, 29, 375),
+ F( 48000000, gpll0, 12.5, 0, 0),
+ F( 51200000, gpll0, 1, 32, 375),
+ F( 56000000, gpll0, 1, 7, 75),
+ F( 58982400, gpll0, 1, 1536, 15625),
+ F( 60000000, gpll0, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk blsp1_uart1_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART1_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart1_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart1_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart2_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart2_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart3_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART3_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart3_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart3_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart4_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART4_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart4_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart4_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart5_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART5_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart5_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart5_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk blsp1_uart6_apps_clk_src = {
+ .cmd_rcgr_reg = BLSP1_UART6_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_blsp1_uart1_6_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "blsp1_uart6_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 31580000, NOMINAL, 63160000),
+ CLK_INIT(blsp1_uart6_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_ce1_clk[] = {
+ F( 50000000, gpll0, 12, 0, 0),
+ F( 85710000, gpll0, 7, 0, 0),
+ F( 100000000, gpll0, 6, 0, 0),
+ F( 171430000, gpll0, 3.5, 0, 0),
+ F( 200000000, gpll0, 3, 0, 0),
+ F_END
+};
+
+static struct rcg_clk ce1_clk_src = {
+ .cmd_rcgr_reg = CE1_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_ce1_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "ce1_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOW, 85710000, NOMINAL, 171430000, HIGH,
+ 200000000),
+ CLK_INIT(ce1_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_sleep_clk[] = {
+ F( 1000000, xo, 1, 5, 96),
+ F_END
+};
+
+static struct rcg_clk pcie_aux_clk_src = {
+ .cmd_rcgr_reg = PCIE_AUX_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_pcie_sleep_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pcie_aux_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 1000000),
+ CLK_INIT(pcie_aux_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_pcie_pipe_clk[] = {
+ F_EXT_SRC( 62500000, pcie_pipe_clk, 2, 0, 0),
+ F_EXT_SRC( 125000000, pcie_pipe_clk, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pcie_pipe_clk_src = {
+ .cmd_rcgr_reg = PCIE_PIPE_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_pcie_pipe_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pcie_pipe_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
+ CLK_INIT(pcie_pipe_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_pdm2_clk[] = {
+ F( 60000000, gpll0, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk pdm2_clk_src = {
+ .cmd_rcgr_reg = PDM2_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_pdm2_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "pdm2_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 60000000),
+ CLK_INIT(pdm2_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_sdcc2_3_apps_clk[] = {
+ F( 144000, xo, 16, 3, 25),
+ F( 400000, xo, 12, 1, 4),
+ F( 20000000, gpll0, 15, 1, 2),
+ F( 25000000, gpll0, 12, 1, 2),
+ F( 50000000, gpll0, 12, 0, 0),
+ F( 100000000, gpll0, 6, 0, 0),
+ F( 200000000, gpll0, 3, 0, 0),
+ F_END
+};
+
+static struct rcg_clk sdcc2_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC2_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc2_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 100000000, NOMINAL, 200000000),
+ CLK_INIT(sdcc2_apps_clk_src.c),
+ },
+};
+
+static struct rcg_clk sdcc3_apps_clk_src = {
+ .cmd_rcgr_reg = SDCC3_APPS_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_sdcc2_3_apps_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "sdcc3_apps_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP2(LOW, 50000000, NOMINAL, 100000000),
+ CLK_INIT(sdcc3_apps_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_aux_clk[] = {
+ F( 1000000, xo, 1, 5, 96),
+ F_END
+};
+
+static struct rcg_clk usb3_aux_clk_src = {
+ .cmd_rcgr_reg = USB3_AUX_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_gcc_usb3_aux_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb3_aux_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP1(LOW, 1000000),
+ CLK_INIT(usb3_aux_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb3_pipe_clk[] = {
+ F_EXT_SRC( 125000000, usb3_pipe_clk, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb3_pipe_clk_src = {
+ .cmd_rcgr_reg = USB3_PIPE_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb3_pipe_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb3_pipe_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 125000000),
+ CLK_INIT(usb3_pipe_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb30_mock_utmi_clk[] = {
+ F( 60000000, gpll0, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb30_mock_utmi_clk_src = {
+ .cmd_rcgr_reg = USB30_MOCK_UTMI_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb30_mock_utmi_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb30_mock_utmi_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 60000000),
+ CLK_INIT(usb30_mock_utmi_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hs_system_clk[] = {
+ F( 60000000, gpll0, 10, 0, 0),
+ F( 75000000, gpll0, 8, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hs_system_clk_src = {
+ .cmd_rcgr_reg = USB_HS_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hs_system_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hs_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+ CLK_INIT(usb_hs_system_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_clk[] = {
+ F( 480000000, gpll1, 1, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hsic_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 480000000),
+ CLK_INIT(usb_hsic_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_io_cal_clk[] = {
+ F( 9600000, xo, 2, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_io_cal_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_IO_CAL_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hsic_io_cal_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_io_cal_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 9600000),
+ CLK_INIT(usb_hsic_io_cal_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_system_clk[] = {
+ F( 60000000, gpll0, 10, 0, 0),
+ F( 75000000, gpll0, 8, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_system_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_SYSTEM_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hsic_system_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_system_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP2(LOW, 60000000, NOMINAL, 75000000),
+ CLK_INIT(usb_hsic_system_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_gcc_usb_hsic_xcvr_fs_clk[] = {
+ F( 60000000, gpll0, 10, 0, 0),
+ F_END
+};
+
+static struct rcg_clk usb_hsic_xcvr_fs_clk_src = {
+ .cmd_rcgr_reg = USB_HSIC_XCVR_FS_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_gcc_usb_hsic_xcvr_fs_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "usb_hsic_xcvr_fs_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 60000000),
+ CLK_INIT(usb_hsic_xcvr_fs_clk_src.c),
+ },
+};
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD_QDSS(qdss_clk, qdss_a_clk, RPM_MISC_CLK_TYPE, QDSS_ID);
+
+DEFINE_CLK_RPM_SMD(qpic_clk, qpic_a_clk, RPM_QPIC_CLK_TYPE, QPIC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+
+static struct local_vote_clk gcc_bam_dma_ahb_clk = {
+ .cbcr_reg = BAM_DMA_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(12),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_bam_dma_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_bam_dma_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_bam_dma_inactivity_timers_clk = {
+ .cbcr_reg = BAM_DMA_INACTIVITY_TIMERS_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_bam_dma_inactivity_timers_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_bam_dma_inactivity_timers_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_blsp1_ahb_clk = {
+ .cbcr_reg = BLSP1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(17),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_blsp1_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_i2c_apps_clk",
+ .parent = &blsp1_qup1_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup1_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP1_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup1_spi_apps_clk",
+ .parent = &blsp1_qup1_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup1_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_i2c_apps_clk",
+ .parent = &blsp1_qup2_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup2_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP2_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup2_spi_apps_clk",
+ .parent = &blsp1_qup2_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup2_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_i2c_apps_clk",
+ .parent = &blsp1_qup3_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP3_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+ .parent = &blsp1_qup3_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup3_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_i2c_apps_clk",
+ .parent = &blsp1_qup4_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP4_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+ .parent = &blsp1_qup4_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup4_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_i2c_apps_clk",
+ .parent = &blsp1_qup5_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP5_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+ .parent = &blsp1_qup5_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup5_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_i2c_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_I2C_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_i2c_apps_clk",
+ .parent = &blsp1_qup6_i2c_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_i2c_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_qup6_spi_apps_clk = {
+ .cbcr_reg = BLSP1_QUP6_SPI_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_qup6_spi_apps_clk",
+ .parent = &blsp1_qup6_spi_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_qup6_spi_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart1_apps_clk = {
+ .cbcr_reg = BLSP1_UART1_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart1_apps_clk",
+ .parent = &blsp1_uart1_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart1_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart2_apps_clk = {
+ .cbcr_reg = BLSP1_UART2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart2_apps_clk",
+ .parent = &blsp1_uart2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart3_apps_clk = {
+ .cbcr_reg = BLSP1_UART3_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart3_apps_clk",
+ .parent = &blsp1_uart3_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart3_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart4_apps_clk = {
+ .cbcr_reg = BLSP1_UART4_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart4_apps_clk",
+ .parent = &blsp1_uart4_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart4_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart5_apps_clk = {
+ .cbcr_reg = BLSP1_UART5_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart5_apps_clk",
+ .parent = &blsp1_uart5_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart5_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_blsp1_uart6_apps_clk = {
+ .cbcr_reg = BLSP1_UART6_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_blsp1_uart6_apps_clk",
+ .parent = &blsp1_uart6_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_blsp1_uart6_apps_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_ahb_clk = {
+ .cbcr_reg = CE1_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(3),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_axi_clk = {
+ .cbcr_reg = CE1_AXI_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(4),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_axi_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_axi_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_ce1_clk = {
+ .cbcr_reg = CE1_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(5),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_ce1_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_ce1_clk.c),
+ },
+};
+
+static struct branch_clk gcc_lpass_q6_axi_clk = {
+ .cbcr_reg = LPASS_Q6_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_lpass_q6_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_lpass_q6_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_mss_q6_bimc_axi_clk = {
+ .cbcr_reg = MSS_Q6_BIMC_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_q6_bimc_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_q6_bimc_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_axi_clk = {
+ .cbcr_reg = PCIE_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pcie_axi_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_axi_mstr_clk = {
+ .cbcr_reg = PCIE_AXI_MSTR_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pcie_axi_mstr_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_axi_mstr_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_cfg_ahb_clk = {
+ .cbcr_reg = PCIE_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pcie_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_cfg_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_pipe_clk = {
+ .cbcr_reg = PCIE_PIPE_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pcie_pipe_clk",
+ .parent = &pcie_pipe_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_pipe_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pcie_sleep_clk = {
+ .cbcr_reg = PCIE_SLEEP_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pcie_sleep_clk",
+ .parent = &pcie_aux_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pcie_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm2_clk = {
+ .cbcr_reg = PDM2_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm2_clk",
+ .parent = &pdm2_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm2_clk.c),
+ },
+};
+
+static struct branch_clk gcc_pdm_ahb_clk = {
+ .cbcr_reg = PDM_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_pdm_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_pdm_ahb_clk.c),
+ },
+};
+
+static struct local_vote_clk gcc_prng_ahb_clk = {
+ .cbcr_reg = PRNG_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(13),
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_prng_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_prng_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_ahb_clk = {
+ .cbcr_reg = SDCC2_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc2_apps_clk = {
+ .cbcr_reg = SDCC2_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc2_apps_clk",
+ .parent = &sdcc2_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc2_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc3_ahb_clk = {
+ .cbcr_reg = SDCC3_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc3_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc3_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sdcc3_apps_clk = {
+ .cbcr_reg = SDCC3_APPS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sdcc3_apps_clk",
+ .parent = &sdcc3_apps_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sdcc3_apps_clk.c),
+ },
+};
+
+static struct branch_clk gcc_sys_noc_usb3_axi_clk = {
+ .cbcr_reg = SYS_NOC_USB3_AXI_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_sys_noc_usb3_axi_clk",
+ .parent = &usb30_master_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_sys_noc_usb3_axi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb3_aux_clk = {
+ .cbcr_reg = USB3_AUX_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb3_aux_clk",
+ .parent = &usb3_aux_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb3_aux_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb3_pipe_clk = {
+ .cbcr_reg = USB3_PIPE_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb3_pipe_clk",
+ .parent = &usb3_pipe_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb3_pipe_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb30_master_clk = {
+ .cbcr_reg = USB30_MASTER_CBCR,
+ .bcr_reg = USB_30_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb30_master_clk",
+ .parent = &usb30_master_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_master_clk.c),
+ .depends = &gcc_sys_noc_usb3_axi_clk.c,
+ },
+};
+
+static struct branch_clk gcc_usb30_mock_utmi_clk = {
+ .cbcr_reg = USB30_MOCK_UTMI_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb30_mock_utmi_clk",
+ .parent = &usb30_mock_utmi_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_mock_utmi_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb30_sleep_clk = {
+ .cbcr_reg = USB30_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb30_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb30_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_ahb_clk = {
+ .cbcr_reg = USB_HS_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hs_system_clk = {
+ .cbcr_reg = USB_HS_SYSTEM_CBCR,
+ .has_sibling = 0,
+ .bcr_reg = USB_HS_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hs_system_clk",
+ .parent = &usb_hs_system_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hs_system_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_ahb_clk = {
+ .cbcr_reg = USB_HSIC_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_ahb_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_clk = {
+ .cbcr_reg = USB_HSIC_CBCR,
+ .has_sibling = 0,
+ .bcr_reg = USB_HS_HSIC_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_clk",
+ .parent = &usb_hsic_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_clk = {
+ .cbcr_reg = USB_HSIC_IO_CAL_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_io_cal_clk",
+ .parent = &usb_hsic_io_cal_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_io_cal_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_io_cal_sleep_clk = {
+ .cbcr_reg = USB_HSIC_IO_CAL_SLEEP_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_io_cal_sleep_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_io_cal_sleep_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_system_clk = {
+ .cbcr_reg = USB_HSIC_SYSTEM_CBCR,
+ .has_sibling = 0,
+ .bcr_reg = USB_HS_HSIC_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_system_clk",
+ .parent = &usb_hsic_system_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_system_clk.c),
+ },
+};
+
+static struct branch_clk gcc_usb_hsic_xcvr_fs_clk = {
+ .cbcr_reg = USB_HSIC_XCVR_FS_CBCR,
+ .has_sibling = 0,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_usb_hsic_xcvr_fs_clk",
+ .parent = &usb_hsic_xcvr_fs_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_usb_hsic_xcvr_fs_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+ .cbcr_reg = Q6SS_AHB_LFABIF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahb_lfabif_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahb_lfabif_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_ahbm_clk = {
+ .cbcr_reg = Q6SS_AHBM_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahbm_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahbm_clk.c),
+ },
+};
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sdcc2_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_sdcc3_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(pnoc_sps_clk, &pnoc_clk.c, LONG_MAX);
+
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
+static DEFINE_CLK_BRANCH_VOTER(cxo_pil_mss_clk, &xo.c);
+
+static DEFINE_CLK_MEASURE(a7_m_clk);
+
+#ifdef CONFIG_DEBUG_FS
+
+struct measure_mux_entry {
+ struct clk *c;
+ int base;
+ u32 debug_mux;
+};
+
+struct measure_mux_entry measure_mux[] = {
+ {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
+ {&gcc_mss_q6_bimc_axi_clk.c, GCC_BASE, 0x0031},
+ {&gcc_usb30_master_clk.c, GCC_BASE, 0x0050},
+ {&gcc_usb30_sleep_clk.c, GCC_BASE, 0x0051},
+ {&gcc_usb30_mock_utmi_clk.c, GCC_BASE, 0x0052},
+ {&gcc_usb3_pipe_clk.c, GCC_BASE, 0x0054},
+ {&gcc_usb3_aux_clk.c, GCC_BASE, 0x0055},
+ {&gcc_usb_hsic_ahb_clk.c, GCC_BASE, 0x0058},
+ {&gcc_usb_hsic_system_clk.c, GCC_BASE, 0x0059},
+ {&gcc_usb_hsic_clk.c, GCC_BASE, 0x005a},
+ {&gcc_usb_hsic_io_cal_clk.c, GCC_BASE, 0x005b},
+ {&gcc_usb_hsic_io_cal_sleep_clk.c, GCC_BASE, 0x005c},
+ {&gcc_usb_hsic_xcvr_fs_clk.c, GCC_BASE, 0x005d},
+ {&gcc_usb_hs_system_clk.c, GCC_BASE, 0x0060},
+ {&gcc_usb_hs_ahb_clk.c, GCC_BASE, 0x0061},
+ {&gcc_sdcc2_apps_clk.c, GCC_BASE, 0x0070},
+ {&gcc_sdcc2_ahb_clk.c, GCC_BASE, 0x0071},
+ {&gcc_sdcc3_apps_clk.c, GCC_BASE, 0x0078},
+ {&gcc_sdcc3_ahb_clk.c, GCC_BASE, 0x0079},
+ {&gcc_blsp1_ahb_clk.c, GCC_BASE, 0x0088},
+ {&gcc_blsp1_qup1_spi_apps_clk.c, GCC_BASE, 0x008a},
+ {&gcc_blsp1_qup1_i2c_apps_clk.c, GCC_BASE, 0x008b},
+ {&gcc_blsp1_uart1_apps_clk.c, GCC_BASE, 0x008c},
+ {&gcc_blsp1_qup2_spi_apps_clk.c, GCC_BASE, 0x008e},
+ {&gcc_blsp1_qup2_i2c_apps_clk.c, GCC_BASE, 0x0090},
+ {&gcc_blsp1_uart2_apps_clk.c, GCC_BASE, 0x0091},
+ {&gcc_blsp1_qup3_spi_apps_clk.c, GCC_BASE, 0x0093},
+ {&gcc_blsp1_qup3_i2c_apps_clk.c, GCC_BASE, 0x0094},
+ {&gcc_blsp1_uart3_apps_clk.c, GCC_BASE, 0x0095},
+ {&gcc_blsp1_qup4_spi_apps_clk.c, GCC_BASE, 0x0098},
+ {&gcc_blsp1_qup4_i2c_apps_clk.c, GCC_BASE, 0x0099},
+ {&gcc_blsp1_uart4_apps_clk.c, GCC_BASE, 0x009a},
+ {&gcc_blsp1_qup5_spi_apps_clk.c, GCC_BASE, 0x009c},
+ {&gcc_blsp1_qup5_i2c_apps_clk.c, GCC_BASE, 0x009d},
+ {&gcc_blsp1_uart5_apps_clk.c, GCC_BASE, 0x009e},
+ {&gcc_blsp1_qup6_spi_apps_clk.c, GCC_BASE, 0x00a1},
+ {&gcc_blsp1_qup6_i2c_apps_clk.c, GCC_BASE, 0x00a2},
+ {&gcc_blsp1_uart6_apps_clk.c, GCC_BASE, 0x00a3},
+ {&gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d0},
+ {&gcc_pdm2_clk.c, GCC_BASE, 0x00d2},
+ {&gcc_prng_ahb_clk.c, GCC_BASE, 0x00d8},
+ {&gcc_bam_dma_ahb_clk.c, GCC_BASE, 0x00e0},
+ {&gcc_bam_dma_inactivity_timers_clk.c, GCC_BASE, 0x00e1},
+ {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x00f8},
+ {&gcc_ce1_clk.c, GCC_BASE, 0x0138},
+ {&gcc_ce1_axi_clk.c, GCC_BASE, 0x0139},
+ {&gcc_ce1_ahb_clk.c, GCC_BASE, 0x013a},
+ {&gcc_lpass_q6_axi_clk.c, GCC_BASE, 0x0160},
+ {&gcc_pcie_cfg_ahb_clk.c, GCC_BASE, 0x01f0},
+ {&gcc_pcie_pipe_clk.c, GCC_BASE, 0x01f1},
+ {&gcc_pcie_axi_clk.c, GCC_BASE, 0x01f2},
+ {&gcc_pcie_sleep_clk.c, GCC_BASE, 0x01f3},
+ {&gcc_pcie_axi_mstr_clk.c, GCC_BASE, 0x01f4},
+
+ {&bimc_clk.c, GCC_BASE, 0x0155},
+ {&cnoc_clk.c, GCC_BASE, 0x0008},
+ {&pnoc_clk.c, GCC_BASE, 0x0010},
+ {&snoc_clk.c, GCC_BASE, 0x0000},
+
+ {&q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
+ {&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+
+ {&a7_m_clk, APCS_GCC_BASE, 0x3},
+ {&dummy_clk, N_BASES, 0x0000},
+};
+
+static int measure_clk_set_parent(struct clk *c, struct clk *parent)
+{
+ struct measure_clk *clk = to_measure_clk(c);
+ unsigned long flags;
+ u32 regval, clk_sel, i;
+
+ if (!parent)
+ return -EINVAL;
+
+ for (i = 0; i < (ARRAY_SIZE(measure_mux) - 1); i++)
+ if (measure_mux[i].c == parent)
+ break;
+
+ if (measure_mux[i].c == &dummy_clk)
+ return -EINVAL;
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ /*
+ * Program the test vector, measurement period (sample_ticks)
+ * and scaling multiplier.
+ */
+ clk->sample_ticks = 0x10000;
+ clk->multiplier = 1;
+
+ writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ switch (measure_mux[i].base) {
+
+ case GCC_BASE:
+ clk_sel = measure_mux[i].debug_mux;
+ break;
+
+ case APCS_GCC_BASE:
+ clk_sel = 0x16A;
+ regval = BVAL(5, 3, measure_mux[i].debug_mux);
+ writel_relaxed(regval, APCS_GCC_BASE(APCS_CLK_DIAG));
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* Set debug mux clock index */
+ regval = BVAL(9, 0, clk_sel);
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ /* Activate debug clock output */
+ regval |= BIT(16);
+ writel_relaxed(regval, GCC_REG_BASE(GCC_DEBUG_CLK_CTL));
+
+ /* Make sure test vector is set before starting measurements. */
+ mb();
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return 0;
+}
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned ticks)
+{
+ /* Stop counters and set the XO4 counter start value. */
+ writel_relaxed(ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+
+ /* Wait for timer to become ready. */
+ while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BIT(25)) != 0)
+ cpu_relax();
+
+ /* Run measurement and wait for completion. */
+ writel_relaxed(BIT(20)|ticks, GCC_REG_BASE(CLOCK_FRQ_MEASURE_CTL));
+ while ((readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BIT(25)) == 0)
+ cpu_relax();
+
+ /* Return measured ticks. */
+ return readl_relaxed(GCC_REG_BASE(CLOCK_FRQ_MEASURE_STATUS)) &
+ BM(24, 0);
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long measure_clk_get_rate(struct clk *c)
+{
+ unsigned long flags;
+ u32 gcc_xo4_reg_backup;
+ u64 raw_count_short, raw_count_full;
+ struct measure_clk *clk = to_measure_clk(c);
+ unsigned ret;
+
+ ret = clk_prepare_enable(&xo.c);
+ if (ret) {
+ pr_warning("CXO clock failed to enable. Can't measure\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+
+ /* Enable CXO/4 and RINGOSC branch. */
+ gcc_xo4_reg_backup = readl_relaxed(GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+ writel_relaxed(0x1, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+ /*
+ * The ring oscillator counter will not reset if the measured clock
+ * is not running. To detect this, run a short measurement before
+ * the full measurement. If the raw results of the two are the same
+ * then the clock must be off.
+ */
+
+ /* Run a short measurement. (~1 ms) */
+ raw_count_short = run_measurement(0x1000);
+ /* Run a full measurement. (~14 ms) */
+ raw_count_full = run_measurement(clk->sample_ticks);
+
+ writel_relaxed(gcc_xo4_reg_backup, GCC_REG_BASE(GCC_XO_DIV4_CBCR));
+
+ /* Return 0 if the clock is off. */
+ if (raw_count_full == raw_count_short) {
+ ret = 0;
+ } else {
+ /* Compute rate in Hz. */
+ raw_count_full = ((raw_count_full * 10) + 15) * 4800000;
+ do_div(raw_count_full, ((clk->sample_ticks * 10) + 35));
+ ret = (raw_count_full * clk->multiplier);
+ }
+
+ writel_relaxed(0x51A00, GCC_REG_BASE(PLLTEST_PAD_CFG));
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ clk_disable_unprepare(&xo.c);
+
+ return ret;
+}
+#else /* !CONFIG_DEBUG_FS */
+static int measure_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ return -EINVAL;
+}
+
+static unsigned long measure_clk_get_rate(struct clk *clk)
+{
+ return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static struct clk_ops clk_ops_measure = {
+ .set_parent = measure_clk_set_parent,
+ .get_rate = measure_clk_get_rate,
+};
+
+static struct measure_clk measure_clk = {
+ .c = {
+ .dbg_name = "measure_clk",
+ .ops = &clk_ops_measure,
+ CLK_INIT(measure_clk.c),
+ },
+ .multiplier = 1,
+};
+
+static struct clk_lookup msm_clocks_krypton[] = {
+ CLK_LOOKUP("xo", xo.c, ""),
+ CLK_LOOKUP("measure", measure_clk.c, "debug"),
+
+ /* PLLS */
+ CLK_LOOKUP("", gpll0.c, ""),
+ CLK_LOOKUP("", gpll1.c, ""),
+ CLK_LOOKUP("", gpll0_ao.c, ""),
+
+ /* PIL-LPASS */
+ CLK_LOOKUP("xo", cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("core_clk", cxo_pil_lpass_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
+ CLK_LOOKUP("reg_clk", q6ss_ahbm_clk.c, "fe200000.qcom,lpass"),
+
+ /* PIL-MODEM */
+ CLK_LOOKUP("xo", cxo_pil_mss_clk.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
+
+ /* SPS */
+ CLK_LOOKUP("dma_bam_pclk", gcc_bam_dma_ahb_clk.c, "msm_sps"),
+ CLK_LOOKUP("inactivity_clk", gcc_bam_dma_inactivity_timers_clk.c,
+ "msm_sps"),
+ CLK_LOOKUP("dfab_clk", pnoc_sps_clk.c, "msm_sps"),
+
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991f000.serial"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart3_apps_clk.c, "f991f000.serial"),
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9928000.spi"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, "f9928000.spi"),
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c"),
+
+ CLK_LOOKUP("iface_clk", gcc_blsp1_ahb_clk.c, "f991d000.uart"),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart1_apps_clk.c, "f991d000.uart"),
+
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup1_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup2_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup3_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup4_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup4_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup5_spi_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_i2c_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_qup6_spi_apps_clk.c, ""),
+
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart2_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart4_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart5_apps_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_blsp1_uart6_apps_clk.c, ""),
+
+ CLK_LOOKUP("iface_clk", gcc_prng_ahb_clk.c, "f9bff000.qcom,msm-rng"),
+
+ CLK_LOOKUP("core_clk", gcc_pdm2_clk.c, ""),
+ CLK_LOOKUP("iface_clk", gcc_pdm_ahb_clk.c, ""),
+
+ CLK_LOOKUP("iface_clk", gcc_sdcc2_ahb_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("core_clk", gcc_sdcc2_apps_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc2_clk.c, "msm_sdcc.2"),
+ CLK_LOOKUP("iface_clk", gcc_sdcc3_ahb_clk.c, "msm_sdcc.3"),
+ CLK_LOOKUP("core_clk", gcc_sdcc3_apps_clk.c, "msm_sdcc.3"),
+ CLK_LOOKUP("bus_clk", pnoc_sdcc3_clk.c, "msm_sdcc.3"),
+
+ CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "f9a55000.usb"),
+ CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "f9a55000.usb"),
+ CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("alt_core_clk", gcc_usb_hsic_xcvr_fs_clk.c, ""),
+ CLK_LOOKUP("inactivity_clk", gcc_usb_hsic_io_cal_sleep_clk.c,
+ "msm_hsic_host"),
+
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcedev"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcedev"),
+
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "fd400000.qcom,qcrypto"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd400000.qcom,qcrypto"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd400000.qcom,qcrypto"),
+ CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd400000.qcom,qcrypto"),
+
+ /* RPM and voter clocks */
+ CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+
+ CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
+ CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
+
+ CLK_LOOKUP("a7_m_clk", a7_m_clk, ""),
+
+ /* CoreSight clocks */
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.etm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "fc333000.cti"),
+ CLK_LOOKUP("core_clk", qdss_clk.c, "f9011038.hwevent"),
+
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc322000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc318000.tpiu"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31c000.replicator"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc307000.tmc"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31b000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc319000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc31a000.funnel"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc321000.stm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.etm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc332000.jtagmm"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc308000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc309000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30a000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30b000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30c000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30d000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30e000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc30f000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc310000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "fc333000.cti"),
+ CLK_LOOKUP("core_a_clk", qdss_a_clk.c, "f9011038.hwevent"),
+
+ /* Misc rcgs without clients */
+ CLK_LOOKUP("", usb30_master_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup1_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup1_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup2_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup2_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup3_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup3_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup4_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup4_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup5_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup5_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup6_i2c_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_qup6_spi_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart1_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart2_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart3_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart4_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart5_apps_clk_src.c, ""),
+ CLK_LOOKUP("", blsp1_uart6_apps_clk_src.c, ""),
+ CLK_LOOKUP("", pcie_aux_clk_src.c, ""),
+ CLK_LOOKUP("", pcie_pipe_clk_src.c, ""),
+ CLK_LOOKUP("", pdm2_clk_src.c, ""),
+ CLK_LOOKUP("", sdcc2_apps_clk_src.c, ""),
+ CLK_LOOKUP("", sdcc3_apps_clk_src.c, ""),
+ CLK_LOOKUP("", usb3_aux_clk_src.c, ""),
+ CLK_LOOKUP("", usb3_pipe_clk_src.c, ""),
+ CLK_LOOKUP("", usb30_mock_utmi_clk_src.c, ""),
+ CLK_LOOKUP("", usb_hs_system_clk_src.c, ""),
+ CLK_LOOKUP("", usb_hsic_clk_src.c, ""),
+ CLK_LOOKUP("", usb_hsic_io_cal_clk_src.c, ""),
+ CLK_LOOKUP("", usb_hsic_system_clk_src.c, ""),
+ CLK_LOOKUP("", usb_hsic_xcvr_fs_clk_src.c, ""),
+
+ CLK_LOOKUP("", gcc_pcie_axi_clk.c, ""),
+ CLK_LOOKUP("", gcc_pcie_axi_mstr_clk.c, ""),
+ CLK_LOOKUP("", gcc_pcie_cfg_ahb_clk.c, ""),
+ CLK_LOOKUP("", gcc_pcie_pipe_clk.c, ""),
+ CLK_LOOKUP("", gcc_pcie_sleep_clk.c, ""),
+ CLK_LOOKUP("", gcc_sys_noc_usb3_axi_clk.c, ""),
+ CLK_LOOKUP("", gcc_usb3_aux_clk.c, ""),
+ CLK_LOOKUP("", gcc_usb3_pipe_clk.c, ""),
+ CLK_LOOKUP("", gcc_usb30_master_clk.c, ""),
+ CLK_LOOKUP("", gcc_usb30_mock_utmi_clk.c, ""),
+ CLK_LOOKUP("", gcc_usb30_sleep_clk.c, ""),
+};
+
+static void __init reg_init(void)
+{
+ u32 regval;
+
+ /* Vote for GPLL0 to turn on. Needed by acpuclock. */
+ regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+ regval |= BIT(0);
+ writel_relaxed(regval, GCC_REG_BASE(APCS_GPLL_ENA_VOTE));
+}
+
+static void __init msmkrypton_clock_post_init(void)
+{
+ /*
+ * Hold an active set vote for CXO; this is because CXO is expected
+ * to remain on whenever CPUs aren't power collapsed.
+ */
+ clk_prepare_enable(&xo_a_clk.c);
+}
+
+#define GCC_CC_PHYS 0xFC400000
+#define GCC_CC_SIZE SZ_8K
+
+#define LPASS_CC_PHYS 0xFE000000
+#define LPASS_CC_SIZE SZ_256K
+
+#define APCS_GLB_PHYS 0xF9010000
+#define APCS_GLB_SIZE 0x38
+
+#define APCS_GCC_PHYS 0xF9011000
+#define APCS_GCC_SIZE 0x1C
+
+#define APCS_ACC_PHYS 0xF9008000
+#define APCS_ACC_SIZE 0x40
+
+static void __init msmkrypton_clock_pre_init(void)
+{
+ virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
+ if (!virt_bases[GCC_BASE])
+ panic("clock-krypton: Unable to ioremap GCC memory!");
+
+ virt_bases[LPASS_BASE] = ioremap(LPASS_CC_PHYS, LPASS_CC_SIZE);
+ if (!virt_bases[LPASS_BASE])
+ panic("clock-8226: Unable to ioremap LPASS_CC memory!");
+
+ virt_bases[APCS_GLB_BASE] = ioremap(APCS_GLB_PHYS, APCS_GLB_SIZE);
+ if (!virt_bases[APCS_GLB_BASE])
+ panic("clock-krypton: Unable to ioremap APCS_GLB memory!");
+
+ virt_bases[APCS_GCC_BASE] = ioremap(APCS_GCC_PHYS, APCS_GCC_SIZE);
+ if (!virt_bases[APCS_GCC_BASE])
+ panic("clock-krypton: Unable to ioremap APCS_GCC memory!");
+
+ virt_bases[APCS_ACC_BASE] = ioremap(APCS_ACC_PHYS, APCS_ACC_SIZE);
+ if (!virt_bases[APCS_ACC_BASE])
+ panic("clock-krypton: Unable to ioremap APCS_PLL memory!");
+
+ vdd_dig.regulator[0] = regulator_get(NULL, "vdd_dig");
+ if (IS_ERR(vdd_dig.regulator[0]))
+ panic("clock-krypton: Unable to get the vdd_dig regulator!");
+
+ enable_rpm_scaling();
+
+ reg_init();
+}
+
struct clock_init_data msmkrypton_clock_init_data __initdata = {
- .table = msm_clocks_dummy,
- .size = ARRAY_SIZE(msm_clocks_dummy),
+ .table = msm_clocks_krypton,
+ .size = ARRAY_SIZE(msm_clocks_krypton),
+ .pre_init = msmkrypton_clock_pre_init,
+ .post_init = msmkrypton_clock_post_init,
};
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index a4021d4..688dea0 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -46,8 +46,12 @@
QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
QSEOS_APP_REGION_NOTIFICATION,
QSEOS_REGISTER_LOG_BUF_COMMAND,
- QSEE_RPMB_PROVISION_KEY_COMMAND,
- QSEE_RPMB_ERASE_COMMAND,
+ QSEOS_RPMB_PROVISION_KEY_COMMAND,
+ QSEOS_RPMB_ERASE_COMMAND,
+ QSEOS_GENERATE_KEY = 0x11,
+ QSEOS_DELETE_KEY,
+ QSEOS_MAX_KEY_COUNT,
+ QSEOS_SET_KEY,
QSEOS_CMD_MAX = 0xEFFFFFFF
};
@@ -57,15 +61,6 @@
QSEOS_RESULT_FAILURE = 0xFFFFFFFF
};
-/* Key Management requests */
-enum qseecom_qceos_key_gen_cmd_id {
- QSEOS_GENERATE_KEY = 0x11,
- QSEOS_DELETE_KEY,
- QSEOS_MAX_KEY_COUNT,
- QSEOS_SET_KEY,
- QSEOS_KEY_CMD_MAX = 0xEFFFFFFF
-};
-
enum qseecom_pipe_type {
QSEOS_PIPE_ENC = 0x1,
QSEOS_PIPE_ENC_XTS = 0x2,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 64986d0..863a2d7 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -98,6 +98,7 @@
#define IPC_ROUTER_LOG_EVENT_ERROR 0x00
#define IPC_ROUTER_LOG_EVENT_TX 0x01
#define IPC_ROUTER_LOG_EVENT_RX 0x02
+#define IPC_ROUTER_DUMMY_DEST_NODE 0xFFFFFFFF
static LIST_HEAD(control_ports);
static DECLARE_RWSEM(control_ports_lock_lha5);
@@ -926,7 +927,8 @@
static int msm_ipc_router_send_control_msg(
struct msm_ipc_router_xprt_info *xprt_info,
- union rr_control_msg *msg)
+ union rr_control_msg *msg,
+ uint32_t dst_node_id)
{
struct rr_packet *pkt;
struct sk_buff *ipc_rtr_pkt;
@@ -986,7 +988,10 @@
hdr->src_port_id = IPC_ROUTER_ADDRESS;
hdr->confirm_rx = 0;
hdr->size = sizeof(*msg);
- hdr->dst_node_id = xprt_info->remote_node_id;
+ if (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)
+ hdr->dst_node_id = dst_node_id;
+ else
+ hdr->dst_node_id = xprt_info->remote_node_id;
hdr->dst_port_id = IPC_ROUTER_ADDRESS;
skb_queue_tail(pkt_fragment_q, ipc_rtr_pkt);
pkt->pkt_fragment_q = pkt_fragment_q;
@@ -1031,7 +1036,7 @@
ctl.srv.port_id =
server_port->server_addr.port_id;
msm_ipc_router_send_control_msg(xprt_info,
- &ctl);
+ &ctl, IPC_ROUTER_DUMMY_DEST_NODE);
}
}
}
@@ -1132,7 +1137,8 @@
down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(xprt_info, &xprt_info_list, list) {
- msm_ipc_router_send_control_msg(xprt_info, ctl);
+ msm_ipc_router_send_control_msg(xprt_info, ctl,
+ IPC_ROUTER_DUMMY_DEST_NODE);
}
up_read(&xprt_info_list_lock_lha5);
@@ -1150,7 +1156,8 @@
down_read(&xprt_info_list_lock_lha5);
list_for_each_entry(fwd_xprt_info, &xprt_info_list, list) {
if (xprt_info->xprt->link_id != fwd_xprt_info->xprt->link_id)
- msm_ipc_router_send_control_msg(fwd_xprt_info, ctl);
+ msm_ipc_router_send_control_msg(fwd_xprt_info, ctl,
+ IPC_ROUTER_DUMMY_DEST_NODE);
}
up_read(&xprt_info_list_lock_lha5);
@@ -1252,7 +1259,8 @@
list_for_each_entry(tmp_xprt_info, &xprt_info_list, list) {
if (tmp_xprt_info != xprt_info)
continue;
- msm_ipc_router_send_control_msg(tmp_xprt_info, &msg);
+ msm_ipc_router_send_control_msg(tmp_xprt_info, &msg,
+ IPC_ROUTER_DUMMY_DEST_NODE);
break;
}
up_read(&xprt_info_list_lock_lha5);
@@ -1498,7 +1506,8 @@
/* Send a reply HELLO message */
memset(&ctl, 0, sizeof(ctl));
ctl.cmd = IPC_ROUTER_CTRL_CMD_HELLO;
- rc = msm_ipc_router_send_control_msg(xprt_info, &ctl);
+ rc = msm_ipc_router_send_control_msg(xprt_info, &ctl,
+ IPC_ROUTER_DUMMY_DEST_NODE);
if (rc < 0) {
pr_err("%s: Error sending reply HELLO message\n", __func__);
return rc;
@@ -1751,7 +1760,6 @@
struct msm_ipc_port *port_ptr;
struct sk_buff *head_skb;
struct msm_ipc_router_remote_port *rport_ptr;
- uint32_t resume_tx, resume_tx_node_id, resume_tx_port_id;
struct msm_ipc_router_xprt_info *xprt_info =
container_of(work,
@@ -1814,10 +1822,6 @@
#endif
#endif
- resume_tx = hdr->confirm_rx;
- resume_tx_node_id = hdr->dst_node_id;
- resume_tx_port_id = hdr->dst_port_id;
-
down_read(&local_ports_lock_lha2);
port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
if (!port_ptr) {
@@ -1825,7 +1829,7 @@
hdr->dst_port_id);
up_read(&local_ports_lock_lha2);
release_pkt(pkt);
- goto process_done;
+ return;
}
down_read(&routing_table_lock_lha3);
@@ -1841,26 +1845,13 @@
hdr->src_port_id);
up_read(&routing_table_lock_lha3);
up_read(&local_ports_lock_lha2);
- goto process_done;
+ release_pkt(pkt);
+ return;
}
}
up_read(&routing_table_lock_lha3);
post_pkt_to_port(port_ptr, pkt, 0);
up_read(&local_ports_lock_lha2);
-
-process_done:
- if (resume_tx) {
- union rr_control_msg msg;
- memset(&msg, 0, sizeof(msg));
- msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
- msg.cli.node_id = resume_tx_node_id;
- msg.cli.port_id = resume_tx_port_id;
-
- RR("x RESUME_TX id=%d:%08x\n",
- msg.cli.node_id, msg.cli.port_id);
- msm_ipc_router_send_control_msg(xprt_info, &msg);
- }
-
}
return;
@@ -2239,11 +2230,56 @@
return 0;
}
+/**
+ * msm_ipc_router_send_resume_tx() - Send Resume_Tx message
+ * @data: Pointer to received data packet that has confirm_rx bit set
+ *
+ * @return: On success, number of bytes transferred is returned, else
+ * standard linux error code is returned.
+ *
+ * This function sends the Resume_Tx event to the remote node that
+ * sent the data with confirm_rx field set. In case of a multi-hop
+ * scenario also, this function makes sure that the destination node_id
+ * to which the resume_tx event should reach is right.
+ */
+static int msm_ipc_router_send_resume_tx(void *data)
+{
+ union rr_control_msg msg;
+ struct rr_header *hdr = (struct rr_header *)data;
+ struct msm_ipc_routing_table_entry *rt_entry;
+ int ret;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = IPC_ROUTER_CTRL_CMD_RESUME_TX;
+ msg.cli.node_id = hdr->dst_node_id;
+ msg.cli.port_id = hdr->dst_port_id;
+ down_read(&routing_table_lock_lha3);
+ rt_entry = lookup_routing_table(hdr->src_node_id);
+ if (!rt_entry) {
+ pr_err("%s: %d Node is not present",
+ __func__, hdr->src_node_id);
+ up_read(&routing_table_lock_lha3);
+ return -ENODEV;
+ }
+ RR("x RESUME_TX id=%d:%08x\n",
+ msg.cli.node_id, msg.cli.port_id);
+ ret = msm_ipc_router_send_control_msg(rt_entry->xprt_info, &msg,
+ hdr->src_node_id);
+ up_read(&routing_table_lock_lha3);
+ if (ret < 0)
+ pr_err("%s: Send Resume_Tx Failed SRC_NODE: %d SRC_PORT: %d DEST_NODE: %d",
+ __func__, hdr->dst_node_id, hdr->dst_port_id,
+ hdr->src_node_id);
+
+ return ret;
+}
+
int msm_ipc_router_read(struct msm_ipc_port *port_ptr,
struct sk_buff_head **data,
size_t buf_len)
{
struct rr_packet *pkt;
+ struct sk_buff *head_skb;
int ret;
if (!port_ptr || !data)
@@ -2265,8 +2301,15 @@
wake_unlock(&port_ptr->port_rx_wake_lock);
*data = pkt->pkt_fragment_q;
ret = pkt->length;
- kfree(pkt);
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
+ kfree(pkt);
+ head_skb = skb_peek(*data);
+ if (!head_skb) {
+ pr_err("%s: Socket Buffer not found", __func__);
+ return -EFAULT;
+ }
+ if (((struct rr_header *)(head_skb->data))->confirm_rx)
+ msm_ipc_router_send_resume_tx((void *)(head_skb->data));
return ret;
}
diff --git a/drivers/coresight/coresight-csr.c b/drivers/coresight/coresight-csr.c
index 6efab5b..16338a9 100644
--- a/drivers/coresight/coresight-csr.c
+++ b/drivers/coresight/coresight-csr.c
@@ -136,7 +136,7 @@
}
EXPORT_SYMBOL(msm_qdss_csr_disable_flush);
-int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val)
+int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val)
{
struct csr_drvdata *drvdata = csrdrvdata;
int ret = 0;
diff --git a/drivers/coresight/coresight-cti.c b/drivers/coresight/coresight-cti.c
index d139583..2a06f0a 100644
--- a/drivers/coresight/coresight-cti.c
+++ b/drivers/coresight/coresight-cti.c
@@ -387,11 +387,77 @@
}
static DEVICE_ATTR(unmap_trigout, S_IWUSR, NULL, cti_store_unmap_trigout);
+static ssize_t cti_show_trigin(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long trig, ch;
+ uint32_t ctien;
+ ssize_t size = 0;
+
+ for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+ ctien = cti_readl(drvdata, CTIINEN(trig));
+ for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+ if (ctien & (1 << ch)) {
+ /* Ensure we do not write more than PAGE_SIZE
+ * bytes of data including \n character and null
+ * terminator
+ */
+ size += scnprintf(&buf[size], PAGE_SIZE - size -
+ 1, " %#lx %#lx,", trig, ch);
+ if (size >= PAGE_SIZE - 2) {
+ dev_err(dev, "show buffer full\n");
+ goto err;
+ }
+
+ }
+ }
+ }
+err:
+ size += scnprintf(&buf[size], 2, "\n");
+ return size;
+}
+static DEVICE_ATTR(show_trigin, S_IRUGO, cti_show_trigin, NULL);
+
+static ssize_t cti_show_trigout(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cti_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long trig, ch;
+ uint32_t ctien;
+ ssize_t size = 0;
+
+ for (trig = 0; trig < CTI_MAX_TRIGGERS; trig++) {
+ ctien = cti_readl(drvdata, CTIOUTEN(trig));
+ for (ch = 0; ch < CTI_MAX_CHANNELS; ch++) {
+ if (ctien & (1 << ch)) {
+ /* Ensure we do not write more than PAGE_SIZE
+ * bytes of data including \n character and null
+ * terminator
+ */
+ size += scnprintf(&buf[size], PAGE_SIZE - size -
+ 1, " %#lx %#lx,", trig, ch);
+ if (size >= PAGE_SIZE - 2) {
+ dev_err(dev, "show buffer full\n");
+ goto err;
+ }
+
+ }
+ }
+ }
+err:
+ size += scnprintf(&buf[size], 2, "\n");
+ return size;
+}
+static DEVICE_ATTR(show_trigout, S_IRUGO, cti_show_trigout, NULL);
+
static struct attribute *cti_attrs[] = {
&dev_attr_map_trigin.attr,
&dev_attr_map_trigout.attr,
&dev_attr_unmap_trigin.attr,
&dev_attr_unmap_trigout.attr,
+ &dev_attr_show_trigin.attr,
+ &dev_attr_show_trigout.attr,
NULL,
};
diff --git a/drivers/coresight/coresight-hwevent.c b/drivers/coresight/coresight-hwevent.c
index 269d56e..4f75bcd 100644
--- a/drivers/coresight/coresight-hwevent.c
+++ b/drivers/coresight/coresight-hwevent.c
@@ -130,11 +130,11 @@
{
struct hwevent_drvdata *drvdata = dev_get_drvdata(dev->parent);
void *hwereg;
- phys_addr_t addr;
- uint32_t val;
+ unsigned long long addr;
+ unsigned long val;
int ret, i;
- if (sscanf(buf, "%x %x", &addr, &val) != 2)
+ if (sscanf(buf, "%llx %lx", &addr, &val) != 2)
return -EINVAL;
mutex_lock(&drvdata->mutex);
@@ -153,7 +153,7 @@
drvdata->hmux[i].end -
drvdata->hmux[i].start);
if (!hwereg) {
- dev_err(dev, "unable to map address 0x%x\n",
+ dev_err(dev, "unable to map address 0x%llx\n",
addr);
ret = -ENOMEM;
goto err;
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 3ad1f34..fae1232 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -47,13 +47,13 @@
extern void msm_qdss_csr_enable_bam_to_usb(void);
extern void msm_qdss_csr_disable_bam_to_usb(void);
extern void msm_qdss_csr_disable_flush(void);
-extern int coresight_csr_hwctrl_set(phys_addr_t addr, uint32_t val);
+extern int coresight_csr_hwctrl_set(uint64_t addr, uint32_t val);
extern void coresight_csr_set_byte_cntr(uint32_t);
#else
static inline void msm_qdss_csr_enable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_bam_to_usb(void) {}
static inline void msm_qdss_csr_disable_flush(void) {}
-static inline int coresight_csr_hwctrl_set(phys_addr_t addr,
+static inline int coresight_csr_hwctrl_set(uint64_t addr,
uint32_t val) { return -ENOSYS; }
static inline void coresight_csr_set_byte_cntr(uint32_t val) {}
#endif
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a052bd3..aaa2fc8 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -692,4 +692,16 @@
default "0"
help
this provide the sensor position setting , value is between 0~7
+
+config SENSORS_STK3X1X
+ tristate "STK3X1X device driver"
+ depends on I2C
+ default n
+ help
+ Say Y here you want to enable for the sitronix stk3x1x
+ light and proximity sensors driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stk3x1x.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 4f29e05..445fba0 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -64,3 +64,4 @@
obj-$(CONFIG_BMP18X) += bmp18x-core.o
obj-$(CONFIG_BMP18X_I2C) += bmp18x-i2c.o
obj-$(CONFIG_SENSORS_MMA8X5X) += mma8x5x.o
+obj-$(CONFIG_SENSORS_STK3X1X) += stk3x1x.o
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index 6e6b9ea..61f3530 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -43,6 +43,10 @@
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
@@ -169,6 +173,12 @@
#define ALS_NAME "lightsensor-level"
#define PS_NAME "proximity"
+/* POWER SUPPLY VOLTAGE RANGE */
+#define STK3X1X_VDD_MIN_UV 2000000
+#define STK3X1X_VDD_MAX_UV 3300000
+#define STK3X1X_VIO_MIN_UV 1750000
+#define STK3X1X_VIO_MAX_UV 1950000
+
struct stk3x1x_data {
struct i2c_client *client;
#if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
@@ -205,6 +215,9 @@
struct work_struct stk_als_work;
struct workqueue_struct *stk_als_wq;
#endif
+ struct regulator *vdd;
+ struct regulator *vio;
+ bool power_enabled;
};
#if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
@@ -1412,15 +1425,14 @@
return size;
}
-
static struct device_attribute als_enable_attribute = __ATTR(enable,0664,stk_als_enable_show,stk_als_enable_store);
static struct device_attribute als_lux_attribute = __ATTR(lux,0664,stk_als_lux_show,stk_als_lux_store);
static struct device_attribute als_code_attribute = __ATTR(code, 0444, stk_als_code_show, NULL);
static struct device_attribute als_transmittance_attribute = __ATTR(transmittance,0664,stk_als_transmittance_show,stk_als_transmittance_store);
-static struct device_attribute als_poll_delay_attribute = __ATTR(delay,0664,stk_als_delay_show,stk_als_delay_store);
+static struct device_attribute als_poll_delay_attribute =
+ __ATTR(poll_delay, 0664, stk_als_delay_show, stk_als_delay_store);
static struct device_attribute als_ir_code_attribute = __ATTR(ircode,0444,stk_als_ir_code_show,NULL);
-
static struct attribute *stk_als_attrs [] =
{
&als_enable_attribute.attr,
@@ -1433,7 +1445,6 @@
};
static struct attribute_group stk_als_attribute_group = {
- .name = "driver",
.attrs = stk_als_attrs,
};
@@ -1465,7 +1476,6 @@
};
static struct attribute_group stk_ps_attribute_group = {
- .name = "driver",
.attrs = stk_ps_attrs,
};
@@ -1793,6 +1803,205 @@
}
#endif //#ifdef CONFIG_HAS_EARLYSUSPEND
+static int stk3x1x_power_on(struct stk3x1x_data *data, bool on)
+{
+ int ret = 0;
+
+ if (!on && data->power_enabled) {
+ ret = regulator_disable(data->vdd);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator vdd disable failed ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_disable(data->vio);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator vio disable failed ret=%d\n", ret);
+ regulator_enable(data->vdd);
+ }
+ } else if (on && !data->power_enabled) {
+
+ ret = regulator_enable(data->vdd);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator vdd enable failed ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_enable(data->vio);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator vio enable failed ret=%d\n", ret);
+ regulator_disable(data->vdd);
+ }
+ } else {
+ dev_warn(&data->client->dev,
+ "Power on=%d. enabled=%d\n",
+ on, data->power_enabled);
+ }
+
+ return ret;
+}
+
+static int stk3x1x_power_init(struct stk3x1x_data *data, bool on)
+{
+ int ret;
+
+ if (!on) {
+ if (regulator_count_voltages(data->vdd) > 0)
+ regulator_set_voltage(data->vdd,
+ 0, STK3X1X_VDD_MAX_UV);
+
+ regulator_put(data->vdd);
+
+ if (regulator_count_voltages(data->vio) > 0)
+ regulator_set_voltage(data->vio,
+ 0, STK3X1X_VIO_MAX_UV);
+
+ regulator_put(data->vio);
+ } else {
+ data->vdd = regulator_get(&data->client->dev, "vdd");
+ if (IS_ERR(data->vdd)) {
+ ret = PTR_ERR(data->vdd);
+ dev_err(&data->client->dev,
+ "Regulator get failed vdd ret=%d\n", ret);
+ return ret;
+ }
+
+ if (regulator_count_voltages(data->vdd) > 0) {
+ ret = regulator_set_voltage(data->vdd,
+ STK3X1X_VDD_MIN_UV,
+ STK3X1X_VDD_MAX_UV);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator set failed vdd ret=%d\n",
+ ret);
+ goto reg_vdd_put;
+ }
+ }
+
+ data->vio = regulator_get(&data->client->dev, "vio");
+ if (IS_ERR(data->vio)) {
+ ret = PTR_ERR(data->vio);
+ dev_err(&data->client->dev,
+ "Regulator get failed vio ret=%d\n", ret);
+ goto reg_vdd_set;
+ }
+
+ if (regulator_count_voltages(data->vio) > 0) {
+ ret = regulator_set_voltage(data->vio,
+ STK3X1X_VIO_MIN_UV,
+ STK3X1X_VIO_MAX_UV);
+ if (ret) {
+ dev_err(&data->client->dev,
+ "Regulator set failed vio ret=%d\n", ret);
+ goto reg_vio_put;
+ }
+ }
+ }
+
+ return 0;
+
+reg_vio_put:
+ regulator_put(data->vio);
+reg_vdd_set:
+ if (regulator_count_voltages(data->vdd) > 0)
+ regulator_set_voltage(data->vdd, 0, STK3X1X_VDD_MAX_UV);
+reg_vdd_put:
+ regulator_put(data->vdd);
+ return ret;
+}
+
+#ifdef CONFIG_OF
+static int stk3x1x_parse_dt(struct device *dev,
+ struct stk3x1x_platform_data *pdata)
+{
+ int rc;
+ struct device_node *np = dev->of_node;
+ u32 temp_val;
+
+ pdata->int_pin = of_get_named_gpio_flags(np, "stk,irq-gpio",
+ 0, &pdata->int_flags);
+ if (pdata->int_pin < 0) {
+ dev_err(dev, "Unable to read irq-gpio\n");
+ return pdata->int_pin;
+ }
+
+ rc = of_property_read_u32(np, "stk,transmittance", &temp_val);
+ if (!rc)
+ pdata->transmittance = temp_val;
+ else {
+ dev_err(dev, "Unable to read transmittance\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,state-reg", &temp_val);
+ if (!rc)
+ pdata->state_reg = temp_val;
+ else {
+ dev_err(dev, "Unable to read state-reg\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,psctrl-reg", &temp_val);
+ if (!rc)
+ pdata->psctrl_reg = (u8)temp_val;
+ else {
+ dev_err(dev, "Unable to read psctrl-reg\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,alsctrl-reg", &temp_val);
+ if (!rc)
+ pdata->alsctrl_reg = (u8)temp_val;
+ else {
+ dev_err(dev, "Unable to read alsctrl-reg\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,ledctrl-reg", &temp_val);
+ if (!rc)
+ pdata->ledctrl_reg = (u8)temp_val;
+ else {
+ dev_err(dev, "Unable to read ledctrl-reg\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,wait-reg", &temp_val);
+ if (!rc)
+ pdata->wait_reg = (u8)temp_val;
+ else {
+ dev_err(dev, "Unable to read wait-reg\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,ps-thdh", &temp_val);
+ if (!rc)
+ pdata->ps_thd_h = (u16)temp_val;
+ else {
+ dev_err(dev, "Unable to read ps-thdh\n");
+ return rc;
+ }
+
+ rc = of_property_read_u32(np, "stk,ps-thdl", &temp_val);
+ if (!rc)
+ pdata->ps_thd_l = (u16)temp_val;
+ else {
+ dev_err(dev, "Unable to read ps-thdl\n");
+ return rc;
+ }
+
+ return 0;
+}
+#else
+static int stk3x1x_parse_dt(struct device *dev,
+ struct stk3x1x_platform_data *pdata)
+{
+ return -ENODEV;
+}
+#endif /* !CONFIG_OF */
static int stk3x1x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -1827,20 +2036,33 @@
#ifdef STK_POLL_PS
wake_lock_init(&ps_data->ps_nosuspend_wl,WAKE_LOCK_SUSPEND, "stk_nosuspend_wakelock");
#endif
- if(client->dev.platform_data != NULL)
- {
- plat_data = client->dev.platform_data;
- ps_data->als_transmittance = plat_data->transmittance;
- ps_data->int_pin = plat_data->int_pin;
- if(ps_data->als_transmittance == 0)
- {
- printk(KERN_ERR "%s: Please set als_transmittance in platform data\n", __func__);
- goto err_als_input_allocate;
+ if (client->dev.of_node) {
+ plat_data = devm_kzalloc(&client->dev,
+ sizeof(struct stk3x1x_platform_data), GFP_KERNEL);
+ if (!plat_data) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
}
+
+ err = stk3x1x_parse_dt(&client->dev, plat_data);
+ dev_err(&client->dev,
+ "%s: stk3x1x_parse_dt ret=%d\n", __func__, err);
+ if (err)
+ return err;
+ } else
+ plat_data = client->dev.platform_data;
+
+ if (!plat_data) {
+ dev_err(&client->dev,
+ "%s: no stk3x1x platform data!\n", __func__);
+ goto err_als_input_allocate;
}
- else
- {
- printk(KERN_ERR "%s: no stk3x1x platform data!\n", __func__);
+ ps_data->als_transmittance = plat_data->transmittance;
+ ps_data->int_pin = plat_data->int_pin;
+
+ if (ps_data->als_transmittance == 0) {
+ dev_err(&client->dev,
+ "%s: Please set als_transmittance\n", __func__);
goto err_als_input_allocate;
}
@@ -1913,6 +2135,14 @@
goto err_stk3x1x_setup_irq;
#endif
+ err = stk3x1x_power_init(ps_data, true);
+ if (err)
+ goto err_power_init;
+
+ err = stk3x1x_power_on(ps_data, true);
+ if (err)
+ goto err_power_on;
+
err = stk3x1x_init_all_setting(client, plat_data);
if(err < 0)
goto err_init_all_setting;
@@ -1926,6 +2156,10 @@
return 0;
err_init_all_setting:
+ stk3x1x_power_on(ps_data, false);
+err_power_on:
+ stk3x1x_power_init(ps_data, false);
+err_power_init:
#ifndef STK_POLL_PS
free_irq(ps_data->irq, ps_data);
gpio_free(plat_data->int_pin);
@@ -2001,11 +2235,17 @@
};
MODULE_DEVICE_TABLE(i2c, stk_ps_id);
+static struct of_device_id stk_match_table[] = {
+ { .compatible = "stk,stk3x1x", },
+ { },
+};
+
static struct i2c_driver stk_ps_driver =
{
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
+ .of_match_table = stk_match_table,
},
.probe = stk3x1x_probe,
.remove = stk3x1x_remove,
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
new file mode 100644
index 0000000..3dfe4e1
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -0,0 +1,615 @@
+/* drivers/input/touchscreen/goodix_tool.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version:1.6
+ * V1.0:2012/05/01,create file.
+ * V1.2:2012/06/08,modify some warning.
+ * V1.4:2012/08/28,modified to support GT9XX
+ * V1.6:new proc name
+ */
+
+#include "gt9xx.h"
+
+#define DATA_LENGTH_UINT 512
+#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8*))
+static char procname[20] = {0};
+
+#define UPDATE_FUNCTIONS
+
+#ifdef UPDATE_FUNCTIONS
+extern s32 gup_enter_update_mode(struct i2c_client *client);
+extern void gup_leave_update_mode(void);
+extern s32 gup_update_proc(void *dir);
+#endif
+
+extern void gtp_irq_disable(struct goodix_ts_data *);
+extern void gtp_irq_enable(struct goodix_ts_data *);
+
+#pragma pack(1)
+typedef struct{
+ u8 wr; //write read flag£¬0:R 1:W 2:PID 3:
+ u8 flag; //0:no need flag/int 1: need flag 2:need int
+ u8 flag_addr[2]; //flag address
+ u8 flag_val; //flag val
+ u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:<
+ u16 circle; //polling cycle
+ u8 times; //plling times
+ u8 retry; //I2C retry times
+ u16 delay; //delay befor read or after write
+ u16 data_len; //data length
+ u8 addr_len; //address length
+ u8 addr[2]; //address
+ u8 res[3]; //reserved
+ u8* data; //data pointer
+}st_cmd_head;
+#pragma pack()
+st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client = NULL;
+
+static struct proc_dir_entry *goodix_proc_entry;
+
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data);
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data );
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+#if GTP_ESD_PROTECT
+extern void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+s32 DATA_LENGTH = 0;
+s8 IC_TYPE[16] = {0};
+
+static void tool_set_proc_name(char * procname)
+{
+ char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+ char date[20] = {0};
+ char month[4] = {0};
+ int i = 0, n_month = 1, n_day = 0, n_year = 0;
+
+ sprintf(date, "%s", __DATE__);
+
+ //GTP_DEBUG("compile date: %s", date);
+
+ sscanf(date, "%s %d %d", month, &n_day, &n_year);
+
+ for (i = 0; i < 12; ++i)
+ {
+ if (!memcmp(months[i], month, 3))
+ {
+ n_month = i+1;
+ break;
+ }
+ }
+
+ sprintf(procname, "gmnode%04d%02d%02d", n_year, n_month, n_day);
+
+ //GTP_DEBUG("procname = %s", procname);
+}
+
+
+static s32 tool_i2c_read_no_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msgs[2];
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = gt_client->addr;
+ msgs[0].len = cmd_head.addr_len;
+ msgs[0].buf = &buf[0];
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = gt_client->addr;
+ msgs[1].len = len;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+
+ for (i = 0; i < cmd_head.retry; i++)
+ {
+ ret=i2c_transfer(gt_client->adapter, msgs, 2);
+ if (ret > 0)
+ {
+ break;
+ }
+ }
+ return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct i2c_msg msg;
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = gt_client->addr;
+ msg.len = len;
+ msg.buf = buf;
+
+ for (i = 0; i < cmd_head.retry; i++)
+ {
+ ret=i2c_transfer(gt_client->adapter, &msg, 1);
+ if (ret > 0)
+ {
+ break;
+ }
+ }
+ return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_read_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8* buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_write_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static void register_i2c_func(void)
+{
+// if (!strncmp(IC_TYPE, "GT818", 5) || !strncmp(IC_TYPE, "GT816", 5)
+// || !strncmp(IC_TYPE, "GT811", 5) || !strncmp(IC_TYPE, "GT818F", 6)
+// || !strncmp(IC_TYPE, "GT827", 5) || !strncmp(IC_TYPE,"GT828", 5)
+// || !strncmp(IC_TYPE, "GT813", 5))
+ if (strncmp(IC_TYPE, "GT8110", 6) && strncmp(IC_TYPE, "GT8105", 6)
+ && strncmp(IC_TYPE, "GT801", 5) && strncmp(IC_TYPE, "GT800", 5)
+ && strncmp(IC_TYPE, "GT801PLUS", 9) && strncmp(IC_TYPE, "GT811", 5)
+ && strncmp(IC_TYPE, "GTxxx", 5))
+ {
+ tool_i2c_read = tool_i2c_read_with_extra;
+ tool_i2c_write = tool_i2c_write_with_extra;
+ GTP_DEBUG("I2C function: with pre and end cmd!");
+ }
+ else
+ {
+ tool_i2c_read = tool_i2c_read_no_extra;
+ tool_i2c_write = tool_i2c_write_no_extra;
+ GTP_INFO("I2C function: without pre and end cmd!");
+ }
+}
+
+static void unregister_i2c_func(void)
+{
+ tool_i2c_read = NULL;
+ tool_i2c_write = NULL;
+ GTP_INFO("I2C function: unregister i2c transfer function!");
+}
+
+
+s32 init_wr_node(struct i2c_client *client)
+{
+ s32 i;
+
+ gt_client = client;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 5;
+ while ((!cmd_head.data) && i)
+ {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (NULL != cmd_head.data)
+ {
+ break;
+ }
+ i--;
+ }
+ if (i)
+ {
+ DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
+ GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ }
+ else
+ {
+ GTP_ERROR("Apply for memory failed.");
+ return FAIL;
+ }
+
+ cmd_head.addr_len = 2;
+ cmd_head.retry = 5;
+
+ register_i2c_func();
+
+ tool_set_proc_name(procname);
+ goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ if (goodix_proc_entry == NULL)
+ {
+ GTP_ERROR("Couldn't create proc entry!");
+ return FAIL;
+ }
+ else
+ {
+ GTP_INFO("Create proc entry success!");
+ goodix_proc_entry->write_proc = goodix_tool_write;
+ goodix_proc_entry->read_proc = goodix_tool_read;
+ }
+
+ return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ unregister_i2c_func();
+ remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+ u8 ret = 0;
+
+ switch (rlt)
+ {
+ case 0:
+ ret = (src != dst) ? true : false;
+ break;
+
+ case 1:
+ ret = (src == dst) ? true : false;
+ GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32)ret);
+ break;
+
+ case 2:
+ ret = (src > dst) ? true : false;
+ break;
+
+ case 3:
+ ret = (src < dst) ? true : false;
+ break;
+
+ case 4:
+ ret = (src & dst) ? true : false;
+ break;
+
+ case 5:
+ ret = (!(src | dst)) ? true : false;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Comfirm function.
+Input:
+ None.
+Output:
+ Return write length.
+********************************************************/
+static u8 comfirm(void)
+{
+ s32 i = 0;
+ u8 buf[32];
+
+// memcpy(&buf[GTP_ADDR_LENGTH - cmd_head.addr_len], &cmd_head.flag_addr, cmd_head.addr_len);
+// memcpy(buf, &cmd_head.flag_addr, cmd_head.addr_len);//Modified by Scott, 2012-02-17
+ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+ for (i = 0; i < cmd_head.times; i++)
+ {
+ if (tool_i2c_read(buf, 1) <= 0)
+ {
+ GTP_ERROR("Read flag data failed!");
+ return FAIL;
+ }
+ if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation))
+ {
+ GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);
+ GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
+ break;
+ }
+
+ msleep(cmd_head.circle);
+ }
+
+ if (i >= cmd_head.times)
+ {
+ GTP_ERROR("Didn't get the flag to continue!");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+/*******************************************************
+Function:
+ Goodix tool write function.
+Input:
+ standard proc write function param.
+Output:
+ Return write length.
+********************************************************/
+static s32 goodix_tool_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
+{
+ s32 ret = 0;
+ GTP_DEBUG_FUNC();
+ GTP_DEBUG_ARRAY((u8*)buff, len);
+
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+
+ GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
+ GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
+ GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
+ GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
+ GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
+ GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
+ GTP_DEBUG("times :%d.", (s32)cmd_head.times);
+ GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
+ GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
+ GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
+ GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
+ GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+ GTP_DEBUG("len:%d.", (s32)len);
+ GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+
+ if (1 == cmd_head.wr)
+ {
+ // copy_from_user(&cmd_head.data[cmd_head.addr_len], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + cmd_head.addr_len);
+ GTP_DEBUG_ARRAY((u8*)&buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+
+ if (1 == cmd_head.flag)
+ {
+ if (FAIL == comfirm())
+ {
+ GTP_ERROR("[WRITE]Comfirm fail!");
+ return FAIL;
+ }
+ }
+ else if (2 == cmd_head.flag)
+ {
+ //Need interrupt!
+ }
+ if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len) <= 0)
+ {
+ GTP_ERROR("[WRITE]Write data failed!");
+ return FAIL;
+ }
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],cmd_head.data_len + cmd_head.addr_len);
+ if (cmd_head.delay)
+ {
+ msleep(cmd_head.delay);
+ }
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (3 == cmd_head.wr) //Write ic type
+ {
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_ERROR("copy_from_user failed.");
+ }
+ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ register_i2c_func();
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (5 == cmd_head.wr)
+ {
+ //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ return cmd_head.data_len + CMD_HEAD_LENGTH;
+ }
+ else if (7 == cmd_head.wr)//disable irq!
+ {
+ gtp_irq_disable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_OFF);
+ #endif
+ return CMD_HEAD_LENGTH;
+ }
+ else if (9 == cmd_head.wr) //enable irq!
+ {
+ gtp_irq_enable(i2c_get_clientdata(gt_client));
+
+ #if GTP_ESD_PROTECT
+ gtp_esd_switch(gt_client, SWITCH_ON);
+ #endif
+ return CMD_HEAD_LENGTH;
+ }
+ else if(17 == cmd_head.wr)
+ {
+ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+ if(ret)
+ {
+ GTP_DEBUG("copy_from_user failed.");
+ }
+ if(cmd_head.data[GTP_ADDR_LENGTH])
+ {
+ GTP_DEBUG("gtp enter rawdiff.");
+ ts->gtp_rawdiff_mode = true;
+ }
+ else
+ {
+ ts->gtp_rawdiff_mode = false;
+ GTP_DEBUG("gtp leave rawdiff.");
+ }
+ return CMD_HEAD_LENGTH;
+ }
+#ifdef UPDATE_FUNCTIONS
+ else if (11 == cmd_head.wr)//Enter update mode!
+ {
+ if (FAIL == gup_enter_update_mode(gt_client))
+ {
+ return FAIL;
+ }
+ }
+ else if (13 == cmd_head.wr)//Leave update mode!
+ {
+ gup_leave_update_mode();
+ }
+ else if (15 == cmd_head.wr) //Update firmware!
+ {
+ show_len = 0;
+ total_len = 0;
+ memset(cmd_head.data, 0, cmd_head.data_len + 1);
+ memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
+
+ if (FAIL == gup_update_proc((void*)cmd_head.data))
+ {
+ return FAIL;
+ }
+ }
+#endif
+
+ return CMD_HEAD_LENGTH;
+}
+
+/*******************************************************
+Function:
+ Goodix tool read function.
+Input:
+ standard proc read function param.
+Output:
+ Return read length.
+********************************************************/
+static s32 goodix_tool_read( char *page, char **start, off_t off, int count, int *eof, void *data )
+{
+ GTP_DEBUG_FUNC();
+
+ if (cmd_head.wr % 2)
+ {
+ return FAIL;
+ }
+ else if (!cmd_head.wr)
+ {
+ u16 len = 0;
+ s16 data_len = 0;
+ u16 loc = 0;
+
+ if (1 == cmd_head.flag)
+ {
+ if (FAIL == comfirm())
+ {
+ GTP_ERROR("[READ]Comfirm fail!");
+ return FAIL;
+ }
+ }
+ else if (2 == cmd_head.flag)
+ {
+ //Need interrupt!
+ }
+
+ memcpy(cmd_head.data, cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG("[CMD HEAD DATA] ADDR:0x%02x%02x.", cmd_head.data[0], cmd_head.data[1]);
+ GTP_DEBUG("[CMD HEAD ADDR] ADDR:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
+
+ if (cmd_head.delay)
+ {
+ msleep(cmd_head.delay);
+ }
+
+ data_len = cmd_head.data_len;
+ while(data_len > 0)
+ {
+ if (data_len > DATA_LENGTH)
+ {
+ len = DATA_LENGTH;
+ }
+ else
+ {
+ len = data_len;
+ }
+ data_len -= DATA_LENGTH;
+
+ if (tool_i2c_read(cmd_head.data, len) <= 0)
+ {
+ GTP_ERROR("[READ]Read data failed!");
+ return FAIL;
+ }
+ memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);
+ loc += len;
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
+ GTP_DEBUG_ARRAY(page, len);
+ }
+ }
+ else if (2 == cmd_head.wr)
+ {
+ // memcpy(page, "gt8", cmd_head.data_len);
+ // memcpy(page, "GT818", 5);
+ // page[5] = 0;
+
+ GTP_DEBUG("Return ic type:%s len:%d.", page, (s32)cmd_head.data_len);
+ return cmd_head.data_len;
+ //return sizeof(IC_TYPE_NAME);
+ }
+ else if (4 == cmd_head.wr)
+ {
+ page[0] = show_len >> 8;
+ page[1] = show_len & 0xff;
+ page[2] = total_len >> 8;
+ page[3] = total_len & 0xff;
+
+ return cmd_head.data_len;
+ }
+ else if (6 == cmd_head.wr)
+ {
+ //Read error code!
+ }
+ else if (8 == cmd_head.wr) //Read driver version
+ {
+ // memcpy(page, GTP_DRIVER_VERSION, strlen(GTP_DRIVER_VERSION));
+ s32 tmp_len;
+ tmp_len = strlen(GTP_DRIVER_VERSION);
+ memcpy(page, GTP_DRIVER_VERSION, tmp_len);
+ page[tmp_len] = 0;
+ }
+
+ return cmd_head.data_len;
+}
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
new file mode 100644
index 0000000..b1dc08b
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -0,0 +1,1810 @@
+/* drivers/input/touchscreen/gt9xx.c
+ *
+ * 2010 - 2013 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version: 1.8
+ * Authors: andrew@goodix.com, meta@goodix.com
+ * Release Date: 2013/04/25
+ * Revision record:
+ * V1.0:
+ * first Release. By Andrew, 2012/08/31
+ * V1.2:
+ * modify gtp_reset_guitar,slot report,tracking_id & 0x0F. By Andrew, 2012/10/15
+ * V1.4:
+ * modify gt9xx_update.c. By Andrew, 2012/12/12
+ * V1.6:
+ * 1. new heartbeat/esd_protect mechanism(add external watchdog)
+ * 2. doze mode, sliding wakeup
+ * 3. 3 more cfg_group(GT9 Sensor_ID: 0~5)
+ * 3. config length verification
+ * 4. names & comments
+ * By Meta, 2013/03/11
+ * V1.8:
+ * 1. pen/stylus identification
+ * 2. read double check & fixed config support
+ * 2. new esd & slide wakeup optimization
+ * By Meta, 2013/06/08
+ */
+
+#include <linux/irq.h>
+#include "gt9xx.h"
+
+#if GTP_ICS_SLOT_REPORT
+ #include <linux/input/mt.h>
+#endif
+
+static const char *goodix_ts_name = "Goodix Capacitive TouchScreen";
+static struct workqueue_struct *goodix_wq;
+struct i2c_client * i2c_connect_client = NULL;
+u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]
+ = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+
+#if GTP_HAVE_TOUCH_KEY
+ static const u16 touch_key_array[] = GTP_KEY_TAB;
+ #define GTP_MAX_KEY_NUM (sizeof(touch_key_array)/sizeof(touch_key_array[0]))
+
+#if GTP_DEBUG_ON
+ static const int key_codes[] = {KEY_HOME, KEY_BACK, KEY_MENU, KEY_SEARCH};
+ static const char *key_names[] = {"Key_Home", "Key_Back", "Key_Menu", "Key_Search"};
+#endif
+
+#endif
+
+static s8 gtp_i2c_test(struct i2c_client *client);
+void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+void gtp_int_sync(s32 ms);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void goodix_ts_early_suspend(struct early_suspend *h);
+static void goodix_ts_late_resume(struct early_suspend *h);
+#endif
+
+#if GTP_CREATE_WR_NODE
+extern s32 init_wr_node(struct i2c_client*);
+extern void uninit_wr_node(void);
+#endif
+
+#if GTP_AUTO_UPDATE
+extern u8 gup_init_update_proc(struct goodix_ts_data *);
+#endif
+
+#if GTP_ESD_PROTECT
+static struct delayed_work gtp_esd_check_work;
+static struct workqueue_struct * gtp_esd_check_workqueue = NULL;
+static void gtp_esd_check_func(struct work_struct *);
+static s32 gtp_init_ext_watchdog(struct i2c_client *client);
+void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+
+
+#if GTP_SLIDE_WAKEUP
+typedef enum
+{
+ DOZE_DISABLED = 0,
+ DOZE_ENABLED = 1,
+ DOZE_WAKEUP = 2,
+}DOZE_T;
+static DOZE_T doze_status = DOZE_DISABLED;
+static s8 gtp_enter_doze(struct goodix_ts_data *ts);
+#endif
+
+static u8 chip_gt9xxs = 0; // true if ic is gt9xxs, like gt915s
+u8 grp_cfg_version = 0;
+
+/*******************************************************
+Function:
+ Read data from the i2c slave device.
+Input:
+ client: i2c device.
+ buf[0~1]: read start address.
+ buf[2~len-1]: read data buffer.
+ len: GTP_ADDR_LENGTH + read bytes count
+Output:
+ numbers of i2c_msgs to transfer:
+ 2: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+ struct i2c_msg msgs[2];
+ s32 ret=-1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = client->addr;
+ msgs[0].len = GTP_ADDR_LENGTH;
+ msgs[0].buf = &buf[0];
+ //msgs[0].scl_rate = 300 * 1000; // for Rockchip
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = client->addr;
+ msgs[1].len = len - GTP_ADDR_LENGTH;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+ //msgs[1].scl_rate = 300 * 1000;
+
+ while(retries < 5)
+ {
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if(ret == 2)break;
+ retries++;
+ }
+ if((retries >= 5))
+ {
+ #if GTP_SLIDE_WAKEUP
+ // reset chip would quit doze mode
+ if (DOZE_ENABLED == doze_status)
+ {
+ return ret;
+ }
+ #endif
+ GTP_DEBUG("I2C communication timeout, resetting chip...");
+ gtp_reset_guitar(client, 10);
+ }
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Write data to the i2c slave device.
+Input:
+ client: i2c device.
+ buf[0~1]: write start address.
+ buf[2~len-1]: data buffer
+ len: GTP_ADDR_LENGTH + write bytes count
+Output:
+ numbers of i2c_msgs to transfer:
+ 1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+ struct i2c_msg msg;
+ s32 ret = -1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = buf;
+ //msg.scl_rate = 300 * 1000; // for Rockchip
+
+ while(retries < 5)
+ {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)break;
+ retries++;
+ }
+ if((retries >= 5))
+ {
+ #if GTP_SLIDE_WAKEUP
+ if (DOZE_ENABLED == doze_status)
+ {
+ return ret;
+ }
+ #endif
+ GTP_DEBUG("I2C communication timeout, resetting chip...");
+ gtp_reset_guitar(client, 10);
+ }
+ return ret;
+}
+/*******************************************************
+Function:
+ i2c read twice, compare the results
+Input:
+ client: i2c device
+ addr: operate address
+ rxbuf: read data to store, if compare successful
+ len: bytes to read
+Output:
+ FAIL: read failed
+ SUCCESS: read successful
+*********************************************************/
+s32 gtp_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *rxbuf, int len)
+{
+ u8 buf[16] = {0};
+ u8 confirm_buf[16] = {0};
+ u8 retry = 0;
+
+ while (retry++ < 3)
+ {
+ memset(buf, 0xAA, 16);
+ buf[0] = (u8)(addr >> 8);
+ buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, buf, len + 2);
+
+ memset(confirm_buf, 0xAB, 16);
+ confirm_buf[0] = (u8)(addr >> 8);
+ confirm_buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, confirm_buf, len + 2);
+
+ if (!memcmp(buf, confirm_buf, len+2))
+ {
+ break;
+ }
+ }
+ if (retry < 3)
+ {
+ memcpy(rxbuf, confirm_buf+2, len);
+ return SUCCESS;
+ }
+ else
+ {
+ GTP_ERROR("i2c read 0x%04X, %d bytes, double check failed!", addr, len);
+ return FAIL;
+ }
+}
+
+/*******************************************************
+Function:
+ Send config.
+Input:
+ client: i2c device.
+Output:
+ result of i2c write operation.
+ 1: succeed, otherwise: failed
+*********************************************************/
+s32 gtp_send_cfg(struct i2c_client *client)
+{
+ s32 ret = 2;
+
+#if GTP_DRIVER_SEND_CFG
+ s32 retry = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->fixed_cfg)
+ {
+ GTP_INFO("Ic fixed config, no config sent!");
+ return 2;
+ }
+ GTP_INFO("driver send config");
+ for (retry = 0; retry < 5; retry++)
+ {
+ ret = gtp_i2c_write(client, config , GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+ if (ret > 0)
+ {
+ break;
+ }
+ }
+#endif
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Disable irq function
+Input:
+ ts: goodix i2c_client private data
+Output:
+ None.
+*********************************************************/
+void gtp_irq_disable(struct goodix_ts_data *ts)
+{
+ unsigned long irqflags;
+
+ GTP_DEBUG_FUNC();
+
+ spin_lock_irqsave(&ts->irq_lock, irqflags);
+ if (!ts->irq_is_disable)
+ {
+ ts->irq_is_disable = 1;
+ disable_irq_nosync(ts->client->irq);
+ }
+ spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+/*******************************************************
+Function:
+ Enable irq function
+Input:
+ ts: goodix i2c_client private data
+Output:
+ None.
+*********************************************************/
+void gtp_irq_enable(struct goodix_ts_data *ts)
+{
+ unsigned long irqflags = 0;
+
+ GTP_DEBUG_FUNC();
+
+ spin_lock_irqsave(&ts->irq_lock, irqflags);
+ if (ts->irq_is_disable)
+ {
+ enable_irq(ts->client->irq);
+ ts->irq_is_disable = 0;
+ }
+ spin_unlock_irqrestore(&ts->irq_lock, irqflags);
+}
+
+
+/*******************************************************
+Function:
+ Report touch point event
+Input:
+ ts: goodix i2c_client private data
+ id: trackId
+ x: input x coordinate
+ y: input y coordinate
+ w: input pressure
+Output:
+ None.
+*********************************************************/
+static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
+{
+#if GTP_CHANGE_X2Y
+ GTP_SWAP(x, y);
+#endif
+
+#if GTP_ICS_SLOT_REPORT
+ input_mt_slot(ts->input_dev, id);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+#else
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
+ input_mt_sync(ts->input_dev);
+#endif
+
+ GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
+}
+
+/*******************************************************
+Function:
+ Report touch release event
+Input:
+ ts: goodix i2c_client private data
+Output:
+ None.
+*********************************************************/
+static void gtp_touch_up(struct goodix_ts_data* ts, s32 id)
+{
+#if GTP_ICS_SLOT_REPORT
+ input_mt_slot(ts->input_dev, id);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ GTP_DEBUG("Touch id[%2d] release!", id);
+#else
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(ts->input_dev);
+#endif
+}
+
+
+/*******************************************************
+Function:
+ Goodix touchscreen work function
+Input:
+ work: work struct of goodix_workqueue
+Output:
+ None.
+*********************************************************/
+static void goodix_ts_work_func(struct work_struct *work)
+{
+ u8 end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
+ u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
+ u8 touch_num = 0;
+ u8 finger = 0;
+ static u16 pre_touch = 0;
+ static u8 pre_key = 0;
+#if GTP_WITH_PEN
+ static u8 pre_pen = 0;
+#endif
+ u8 key_value = 0;
+ u8* coor_data = NULL;
+ s32 input_x = 0;
+ s32 input_y = 0;
+ s32 input_w = 0;
+ s32 id = 0;
+ s32 i = 0;
+ s32 ret = -1;
+ struct goodix_ts_data *ts = NULL;
+
+#if GTP_SLIDE_WAKEUP
+ u8 doze_buf[3] = {0x81, 0x4B};
+#endif
+
+ GTP_DEBUG_FUNC();
+ ts = container_of(work, struct goodix_ts_data, work);
+ if (ts->enter_update)
+ {
+ return;
+ }
+#if GTP_SLIDE_WAKEUP
+ if (DOZE_ENABLED == doze_status)
+ {
+ ret = gtp_i2c_read(i2c_connect_client, doze_buf, 3);
+ GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
+ if (ret > 0)
+ {
+ if (doze_buf[2] == 0xAA)
+ {
+ GTP_INFO("Slide(0xAA) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ // clear 0x814B
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+ }
+ else if (doze_buf[2] == 0xBB)
+ {
+ GTP_INFO("Slide(0xBB) To Light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ // clear 0x814B
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+ }
+ else if (0xC0 == (doze_buf[2] & 0xC0))
+ {
+ GTP_INFO("double click to light up the screen!");
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ // clear 0x814B
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(i2c_connect_client, doze_buf, 3);
+ }
+ else
+ {
+ gtp_enter_doze(ts);
+ }
+ }
+ if (ts->use_irq)
+ {
+ gtp_irq_enable(ts);
+ }
+ return;
+ }
+#endif
+
+ ret = gtp_i2c_read(ts->client, point_data, 12);
+ if (ret < 0)
+ {
+ GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
+ goto exit_work_func;
+ }
+
+ finger = point_data[GTP_ADDR_LENGTH];
+ if((finger & 0x80) == 0)
+ {
+ goto exit_work_func;
+ }
+
+ touch_num = finger & 0x0f;
+ if (touch_num > GTP_MAX_TOUCH)
+ {
+ goto exit_work_func;
+ }
+
+ if (touch_num > 1)
+ {
+ u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};
+
+ ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
+ memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+ }
+
+#if GTP_HAVE_TOUCH_KEY
+ key_value = point_data[3 + 8 * touch_num];
+
+ if(key_value || pre_key)
+ {
+ for (i = 0; i < GTP_MAX_KEY_NUM; i++)
+ {
+ #if GTP_DEBUG_ON
+ for (ret = 0; ret < 4; ++ret)
+ {
+ if (key_codes[ret] == touch_key_array[i])
+ {
+ GTP_DEBUG("Key: %s %s", key_names[ret], (key_value & (0x01 << i)) ? "Down" : "Up");
+ break;
+ }
+ }
+ #endif
+ input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i));
+ }
+ touch_num = 0;
+ pre_touch = 0;
+ }
+#endif
+ pre_key = key_value;
+
+ GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
+
+#if GTP_ICS_SLOT_REPORT
+
+#if GTP_WITH_PEN
+ if (pre_pen && (touch_num == 0))
+ {
+ GTP_DEBUG("Pen touch UP(Slot)!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
+ pre_pen = 0;
+ }
+#endif
+ if (pre_touch || touch_num)
+ {
+ s32 pos = 0;
+ u16 touch_index = 0;
+
+ coor_data = &point_data[3];
+
+ if(touch_num)
+ {
+ id = coor_data[pos] & 0x0F;
+
+ #if GTP_WITH_PEN
+ id = coor_data[pos];
+ if ((id == 128))
+ {
+ GTP_DEBUG("Pen touch DOWN(Slot)!");
+ input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
+ input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
+ input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
+ input_mt_slot(ts->input_dev, 5);
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 5);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
+ GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]", input_x, input_y, input_w);
+ pre_pen = 1;
+ pre_touch = 0;
+ }
+ #endif
+
+ touch_index |= (0x01<<id);
+ }
+
+ GTP_DEBUG("id = %d,touch_index = 0x%x, pre_touch = 0x%x\n",id, touch_index,pre_touch);
+ for (i = 0; i < GTP_MAX_TOUCH; i++)
+ {
+ #if GTP_WITH_PEN
+ if (pre_pen == 1)
+ {
+ break;
+ }
+ #endif
+
+ if (touch_index & (0x01<<i))
+ {
+ input_x = coor_data[pos + 1] | (coor_data[pos + 2] << 8);
+ input_y = coor_data[pos + 3] | (coor_data[pos + 4] << 8);
+ input_w = coor_data[pos + 5] | (coor_data[pos + 6] << 8);
+
+ gtp_touch_down(ts, id, input_x, input_y, input_w);
+ pre_touch |= 0x01 << i;
+
+ pos += 8;
+ id = coor_data[pos] & 0x0F;
+ touch_index |= (0x01<<id);
+ }
+ else
+ {
+ gtp_touch_up(ts, i);
+ pre_touch &= ~(0x01 << i);
+ }
+ }
+ }
+#else
+ input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
+ if (touch_num)
+ {
+ for (i = 0; i < touch_num; i++)
+ {
+ coor_data = &point_data[i * 8 + 3];
+
+ id = coor_data[0]; // & 0x0F;
+ input_x = coor_data[1] | (coor_data[2] << 8);
+ input_y = coor_data[3] | (coor_data[4] << 8);
+ input_w = coor_data[5] | (coor_data[6] << 8);
+
+ #if GTP_WITH_PEN
+ if (id == 128)
+ {
+ GTP_DEBUG("Pen touch DOWN!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 1);
+ pre_pen = 1;
+ id = 0;
+ }
+ #endif
+
+ gtp_touch_down(ts, id, input_x, input_y, input_w);
+ }
+ }
+ else if (pre_touch)
+ {
+
+ #if GTP_WITH_PEN
+ if (pre_pen == 1)
+ {
+ GTP_DEBUG("Pen touch UP!");
+ input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
+ pre_pen = 0;
+ }
+ #endif
+
+ GTP_DEBUG("Touch Release!");
+ gtp_touch_up(ts, 0);
+ }
+
+ pre_touch = touch_num;
+#endif
+
+ input_sync(ts->input_dev);
+
+exit_work_func:
+ if(!ts->gtp_rawdiff_mode)
+ {
+ ret = gtp_i2c_write(ts->client, end_cmd, 3);
+ if (ret < 0)
+ {
+ GTP_INFO("I2C write end_cmd error!");
+ }
+ }
+ if (ts->use_irq)
+ {
+ gtp_irq_enable(ts);
+ }
+}
+
+/*******************************************************
+Function:
+ Timer interrupt service routine for polling mode.
+Input:
+ timer: timer struct pointer
+Output:
+ Timer work mode.
+ HRTIMER_NORESTART: no restart mode
+*********************************************************/
+static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
+{
+ struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
+
+ GTP_DEBUG_FUNC();
+
+ queue_work(goodix_wq, &ts->work);
+ hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
+ return HRTIMER_NORESTART;
+}
+
+/*******************************************************
+Function:
+ External interrupt service routine for interrupt mode.
+Input:
+ irq: interrupt number.
+ dev_id: private data pointer
+Output:
+ Handle Result.
+ IRQ_HANDLED: interrupt handled successfully
+*********************************************************/
+static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
+{
+ struct goodix_ts_data *ts = dev_id;
+
+ GTP_DEBUG_FUNC();
+
+ gtp_irq_disable(ts);
+
+ queue_work(goodix_wq, &ts->work);
+
+ return IRQ_HANDLED;
+}
+/*******************************************************
+Function:
+ Synchronization.
+Input:
+ ms: synchronization time in millisecond.
+Output:
+ None.
+*******************************************************/
+void gtp_int_sync(s32 ms)
+{
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+ msleep(ms);
+ GTP_GPIO_AS_INT(GTP_INT_PORT);
+}
+
+/*******************************************************
+Function:
+ Reset chip.
+Input:
+ ms: reset time in millisecond
+Output:
+ None.
+*******************************************************/
+void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+{
+ GTP_DEBUG_FUNC();
+
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 0); // begin select I2C slave addr
+ msleep(ms); // T2: > 10ms
+ // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);
+
+ msleep(2); // T3: > 100us
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+ msleep(6); // T4: > 5ms
+
+ GTP_GPIO_AS_INPUT(GTP_RST_PORT); // end select I2C slave addr
+
+ gtp_int_sync(50);
+
+#if GTP_ESD_PROTECT
+ gtp_init_ext_watchdog(client);
+#endif
+}
+
+#if GTP_SLIDE_WAKEUP
+/*******************************************************
+Function:
+ Enter doze mode for sliding wakeup.
+Input:
+ ts: goodix tp private data
+Output:
+ 1: succeed, otherwise failed
+*******************************************************/
+static s8 gtp_enter_doze(struct goodix_ts_data *ts)
+{
+ s8 ret = -1;
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 8};
+
+ GTP_DEBUG_FUNC();
+
+#if GTP_DBL_CLK_WAKEUP
+ i2c_control_buf[2] = 0x09;
+#endif
+
+ gtp_irq_disable(ts);
+
+ GTP_DEBUG("entering doze mode...");
+ while(retry++ < 5)
+ {
+ i2c_control_buf[0] = 0x80;
+ i2c_control_buf[1] = 0x46;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret < 0)
+ {
+ GTP_DEBUG("failed to set doze flag into 0x8046, %d", retry);
+ continue;
+ }
+ i2c_control_buf[0] = 0x80;
+ i2c_control_buf[1] = 0x40;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0)
+ {
+ doze_status = DOZE_ENABLED;
+ GTP_INFO("GTP has been working in doze mode!");
+ gtp_irq_enable(ts);
+ return ret;
+ }
+ msleep(10);
+ }
+ GTP_ERROR("GTP send doze cmd failed.");
+ gtp_irq_enable(ts);
+ return ret;
+}
+#else
+/*******************************************************
+Function:
+ Enter sleep mode.
+Input:
+ ts: private data.
+Output:
+ Executive outcomes.
+ 1: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_enter_sleep(struct goodix_ts_data * ts)
+{
+ s8 ret = -1;
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = {(u8)(GTP_REG_SLEEP >> 8), (u8)GTP_REG_SLEEP, 5};
+
+ GTP_DEBUG_FUNC();
+
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, 0);
+ msleep(5);
+
+ while(retry++ < 5)
+ {
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0)
+ {
+ GTP_INFO("GTP enter sleep!");
+
+ return ret;
+ }
+ msleep(10);
+ }
+ GTP_ERROR("GTP send sleep cmd failed.");
+ return ret;
+}
+#endif
+/*******************************************************
+Function:
+ Wakeup from sleep.
+Input:
+ ts: private data.
+Output:
+ Executive outcomes.
+ >0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_wakeup_sleep(struct goodix_ts_data * ts)
+{
+ u8 retry = 0;
+ s8 ret = -1;
+
+ GTP_DEBUG_FUNC();
+
+#if GTP_POWER_CTRL_SLEEP
+ while(retry++ < 5)
+ {
+ gtp_reset_guitar(ts->client, 20);
+
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ {
+ GTP_INFO("Wakeup sleep send config failed!");
+ continue;
+ }
+ GTP_INFO("GTP wakeup sleep");
+ return 1;
+ }
+#else
+ while(retry++ < 10)
+ {
+ #if GTP_SLIDE_WAKEUP
+ if (DOZE_WAKEUP != doze_status) // wakeup not by slide
+ {
+ gtp_reset_guitar(ts->client, 10);
+ }
+ else // wakeup by slide
+ {
+ doze_status = DOZE_DISABLED;
+ }
+ #else
+ if (chip_gt9xxs == 1)
+ {
+ gtp_reset_guitar(ts->client, 10);
+ }
+ else
+ {
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, 1);
+ msleep(5);
+ }
+ #endif
+ ret = gtp_i2c_test(ts->client);
+ if (ret > 0)
+ {
+ GTP_INFO("GTP wakeup sleep.");
+
+ #if (!GTP_SLIDE_WAKEUP)
+ if (chip_gt9xxs == 0)
+ {
+ gtp_int_sync(25);
+ msleep(20);
+ #if GTP_ESD_PROTECT
+ gtp_init_ext_watchdog(ts->client);
+ #endif
+ }
+ #endif
+ return ret;
+ }
+ gtp_reset_guitar(ts->client, 20);
+ }
+#endif
+
+ GTP_ERROR("GTP wakeup sleep failed.");
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Initialize gtp.
+Input:
+ ts: goodix private data
+Output:
+ Executive outcomes.
+ 0: succeed, otherwise: failed
+*******************************************************/
+static s32 gtp_init_panel(struct goodix_ts_data *ts)
+{
+ s32 ret = -1;
+
+#if GTP_DRIVER_SEND_CFG
+ s32 i;
+ u8 check_sum = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
+
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+ u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+ u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+ cfg_info_group4, cfg_info_group5, cfg_info_group6};
+ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5),
+ CFG_GROUP_LEN(cfg_info_group6)};
+
+ GTP_DEBUG("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+ cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], cfg_info_len[3],
+ cfg_info_len[4], cfg_info_len[5]);
+
+ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+ if (SUCCESS == ret)
+ {
+ if (opr_buf[0] != 0xBE)
+ {
+ ts->fw_error = 1;
+ GTP_ERROR("Firmware error, no config sent!");
+ return -1;
+ }
+ }
+
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+ (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+ (!cfg_info_len[5]))
+ {
+ sensor_id = 0;
+ }
+ else
+ {
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
+ if (SUCCESS == ret)
+ {
+ if (sensor_id >= 0x06)
+ {
+ GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
+ return -1;
+ }
+ }
+ else
+ {
+ GTP_ERROR("Failed to get sensor_id, No config sent!");
+ return -1;
+ }
+ }
+ GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+ ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+ if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
+ {
+ GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
+ return -1;
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
+
+ if (ret == SUCCESS)
+ {
+ GTP_DEBUG("CFG_GROUP%d Config Version: %d, 0x%02X; IC Config Version: %d, 0x%02X", sensor_id+1,
+ send_cfg_buf[sensor_id][0], send_cfg_buf[sensor_id][0], opr_buf[0], opr_buf[0]);
+
+ if (opr_buf[0] < 90)
+ {
+ grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version
+ send_cfg_buf[sensor_id][0] = 0x00;
+ ts->fixed_cfg = 0;
+ }
+ else // treated as fixed config, not send config
+ {
+ GTP_INFO("Ic fixed config with config version(%d, 0x%02X)", opr_buf[0], opr_buf[0]);
+ ts->fixed_cfg = 1;
+ }
+ }
+ else
+ {
+ GTP_ERROR("Failed to get ic config version!No config sent!");
+ return -1;
+ }
+
+ memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+
+#if GTP_CUSTOM_CFG
+ config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
+ config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+ config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+ config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+ if (GTP_INT_TRIGGER == 0) //RISING
+ {
+ config[TRIGGER_LOC] &= 0xfe;
+ }
+ else if (GTP_INT_TRIGGER == 1) //FALLING
+ {
+ config[TRIGGER_LOC] |= 0x01;
+ }
+#endif // GTP_CUSTOM_CFG
+
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ {
+ check_sum += config[i];
+ }
+ config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+#else // DRIVER NOT SEND CONFIG
+ ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
+ ret = gtp_i2c_read(ts->client, config, ts->gtp_cfg_len + GTP_ADDR_LENGTH);
+ if (ret < 0)
+ {
+ GTP_ERROR("Read Config Failed, Using Default Resolution & INT Trigger!");
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
+#endif // GTP_DRIVER_SEND_CFG
+
+ GTP_DEBUG_FUNC();
+ if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0))
+ {
+ ts->abs_x_max = (config[RESOLUTION_LOC + 1] << 8) + config[RESOLUTION_LOC];
+ ts->abs_y_max = (config[RESOLUTION_LOC + 3] << 8) + config[RESOLUTION_LOC + 2];
+ ts->int_trigger_type = (config[TRIGGER_LOC]) & 0x03;
+ }
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ {
+ GTP_ERROR("Send config error.");
+ }
+ GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+ ts->abs_x_max,ts->abs_y_max,ts->int_trigger_type);
+
+ msleep(10);
+ return 0;
+}
+
+/*******************************************************
+Function:
+ Read chip version.
+Input:
+ client: i2c device
+ version: buffer to keep ic firmware version
+Output:
+ read operation return.
+ 2: succeed, otherwise: failed
+*******************************************************/
+s32 gtp_read_version(struct i2c_client *client, u16* version)
+{
+ s32 ret = -1;
+ u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+
+ GTP_DEBUG_FUNC();
+
+ ret = gtp_i2c_read(client, buf, sizeof(buf));
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP read version failed");
+ return ret;
+ }
+
+ if (version)
+ {
+ *version = (buf[7] << 8) | buf[6];
+ }
+
+ if (buf[5] == 0x00)
+ {
+ GTP_INFO("IC Version: %c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[7], buf[6]);
+ }
+ else
+ {
+ if (buf[5] == 'S' || buf[5] == 's')
+ {
+ chip_gt9xxs = 1;
+ }
+ GTP_INFO("IC Version: %c%c%c%c_%02x%02x", buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
+ }
+ return ret;
+}
+
+/*******************************************************
+Function:
+ I2c test Function.
+Input:
+ client:i2c client.
+Output:
+ Executive outcomes.
+ 2: succeed, otherwise failed.
+*******************************************************/
+static s8 gtp_i2c_test(struct i2c_client *client)
+{
+ u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+ u8 retry = 0;
+ s8 ret = -1;
+
+ GTP_DEBUG_FUNC();
+
+ while(retry++ < 5)
+ {
+ ret = gtp_i2c_read(client, test, 3);
+ if (ret > 0)
+ {
+ return ret;
+ }
+ GTP_ERROR("GTP i2c test failed time %d.",retry);
+ msleep(10);
+ }
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Request gpio(INT & RST) ports.
+Input:
+ ts: private data.
+Output:
+ Executive outcomes.
+ >= 0: succeed, < 0: failed
+*******************************************************/
+static s8 gtp_request_io_port(struct goodix_ts_data *ts)
+{
+ s32 ret = 0;
+
+ ret = GTP_GPIO_REQUEST(GTP_INT_PORT, "GTP_INT_IRQ");
+ if (ret < 0)
+ {
+ GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d", (s32)GTP_INT_PORT, ret);
+ ret = -ENODEV;
+ }
+ else
+ {
+ GTP_GPIO_AS_INT(GTP_INT_PORT);
+ ts->client->irq = GTP_INT_IRQ;
+ }
+
+ ret = GTP_GPIO_REQUEST(GTP_RST_PORT, "GTP_RST_PORT");
+ if (ret < 0)
+ {
+ GTP_ERROR("Failed to request GPIO:%d, ERRNO:%d",(s32)GTP_RST_PORT,ret);
+ ret = -ENODEV;
+ }
+
+ GTP_GPIO_AS_INPUT(GTP_RST_PORT);
+ gtp_reset_guitar(ts->client, 20);
+
+
+ if(ret < 0)
+ {
+ GTP_GPIO_FREE(GTP_RST_PORT);
+ GTP_GPIO_FREE(GTP_INT_PORT);
+ }
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Request interrupt.
+Input:
+ ts: private data.
+Output:
+ Executive outcomes.
+ 0: succeed, -1: failed.
+*******************************************************/
+static s8 gtp_request_irq(struct goodix_ts_data *ts)
+{
+ s32 ret = -1;
+ const u8 irq_table[] = GTP_IRQ_TAB;
+
+ GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);
+
+ ret = request_irq(ts->client->irq,
+ goodix_ts_irq_handler,
+ irq_table[ts->int_trigger_type],
+ ts->client->name,
+ ts);
+ if (ret)
+ {
+ GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
+ GTP_GPIO_AS_INPUT(GTP_INT_PORT);
+ GTP_GPIO_FREE(GTP_INT_PORT);
+
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->timer.function = goodix_ts_timer_handler;
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ return -1;
+ }
+ else
+ {
+ gtp_irq_disable(ts);
+ ts->use_irq = 1;
+ return 0;
+ }
+}
+
+/*******************************************************
+Function:
+ Request input device Function.
+Input:
+ ts:private data.
+Output:
+ Executive outcomes.
+ 0: succeed, otherwise: failed.
+*******************************************************/
+static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+ s8 ret = -1;
+ s8 phys[32];
+#if GTP_HAVE_TOUCH_KEY
+ u8 index = 0;
+#endif
+
+ GTP_DEBUG_FUNC();
+
+ ts->input_dev = input_allocate_device();
+ if (ts->input_dev == NULL)
+ {
+ GTP_ERROR("Failed to allocate input device.");
+ return -ENOMEM;
+ }
+
+ ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
+#if GTP_ICS_SLOT_REPORT
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ input_mt_init_slots(ts->input_dev, 10); // in case of "out of memory"
+#else
+ ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+#endif
+
+#if GTP_HAVE_TOUCH_KEY
+ for (index = 0; index < GTP_MAX_KEY_NUM; index++)
+ {
+ input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]);
+ }
+#endif
+
+#if GTP_SLIDE_WAKEUP
+ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+#endif
+
+#if GTP_WITH_PEN
+ // pen support
+ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ __set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
+#endif
+
+#if GTP_CHANGE_X2Y
+ GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
+#endif
+
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);
+
+ sprintf(phys, "input/ts");
+ ts->input_dev->name = goodix_ts_name;
+ ts->input_dev->phys = phys;
+ ts->input_dev->id.bustype = BUS_I2C;
+ ts->input_dev->id.vendor = 0xDEAD;
+ ts->input_dev->id.product = 0xBEEF;
+ ts->input_dev->id.version = 10427;
+
+ ret = input_register_device(ts->input_dev);
+ if (ret)
+ {
+ GTP_ERROR("Register %s input device failed", ts->input_dev->name);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = goodix_ts_early_suspend;
+ ts->early_suspend.resume = goodix_ts_late_resume;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+ return 0;
+}
+
+/*******************************************************
+Function:
+ I2c probe.
+Input:
+ client: i2c device struct.
+ id: device id.
+Output:
+ Executive outcomes.
+ 0: succeed.
+*******************************************************/
+static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ s32 ret = -1;
+ struct goodix_ts_data *ts;
+ u16 version_info;
+
+ GTP_DEBUG_FUNC();
+
+ //do NOT remove these logs
+ GTP_INFO("GTP Driver Version: %s", GTP_DRIVER_VERSION);
+ GTP_INFO("GTP Driver Built@%s, %s", __TIME__, __DATE__);
+ GTP_INFO("GTP I2C Address: 0x%02x", client->addr);
+
+ i2c_connect_client = client;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ {
+ GTP_ERROR("I2C check functionality failed.");
+ return -ENODEV;
+ }
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts == NULL)
+ {
+ GTP_ERROR("Alloc GFP_KERNEL memory failed.");
+ return -ENOMEM;
+ }
+
+ memset(ts, 0, sizeof(*ts));
+ INIT_WORK(&ts->work, goodix_ts_work_func);
+ ts->client = client;
+ spin_lock_init(&ts->irq_lock); // 2.6.39 later
+ // ts->irq_lock = SPIN_LOCK_UNLOCKED; // 2.6.39 & before
+ i2c_set_clientdata(client, ts);
+
+ ts->gtp_rawdiff_mode = 0;
+
+ ret = gtp_request_io_port(ts);
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP request IO port failed.");
+ kfree(ts);
+ return ret;
+ }
+
+ ret = gtp_i2c_test(client);
+ if (ret < 0)
+ {
+ GTP_ERROR("I2C communication ERROR!");
+ }
+
+#if GTP_AUTO_UPDATE
+ ret = gup_init_update_proc(ts);
+ if (ret < 0)
+ {
+ GTP_ERROR("Create update thread error.");
+ }
+#endif
+
+ ret = gtp_init_panel(ts);
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP init panel failed.");
+ ts->abs_x_max = GTP_MAX_WIDTH;
+ ts->abs_y_max = GTP_MAX_HEIGHT;
+ ts->int_trigger_type = GTP_INT_TRIGGER;
+ }
+
+ ret = gtp_request_input_dev(ts);
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP request input dev failed");
+ }
+
+ ret = gtp_request_irq(ts);
+ if (ret < 0)
+ {
+ GTP_INFO("GTP works in polling mode.");
+ }
+ else
+ {
+ GTP_INFO("GTP works in interrupt mode.");
+ }
+
+ ret = gtp_read_version(client, &version_info);
+ if (ret < 0)
+ {
+ GTP_ERROR("Read version failed.");
+ }
+ if (ts->use_irq)
+ {
+ gtp_irq_enable(ts);
+ }
+
+#if GTP_CREATE_WR_NODE
+ init_wr_node(client);
+#endif
+
+#if GTP_ESD_PROTECT
+ gtp_esd_switch(client, SWITCH_ON);
+#endif
+ return 0;
+}
+
+
+/*******************************************************
+Function:
+ Goodix touchscreen driver release function.
+Input:
+ client: i2c device struct.
+Output:
+ Executive outcomes. 0---succeed.
+*******************************************************/
+static int goodix_ts_remove(struct i2c_client *client)
+{
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ GTP_DEBUG_FUNC();
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&ts->early_suspend);
+#endif
+
+#if GTP_CREATE_WR_NODE
+ uninit_wr_node();
+#endif
+
+#if GTP_ESD_PROTECT
+ destroy_workqueue(gtp_esd_check_workqueue);
+#endif
+
+ if (ts)
+ {
+ if (ts->use_irq)
+ {
+ GTP_GPIO_AS_INPUT(GTP_INT_PORT);
+ GTP_GPIO_FREE(GTP_INT_PORT);
+ free_irq(client->irq, ts);
+ }
+ else
+ {
+ hrtimer_cancel(&ts->timer);
+ }
+ }
+
+ GTP_INFO("GTP driver removing...");
+ i2c_set_clientdata(client, NULL);
+ input_unregister_device(ts->input_dev);
+ kfree(ts);
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+/*******************************************************
+Function:
+ Early suspend function.
+Input:
+ h: early_suspend struct.
+Output:
+ None.
+*******************************************************/
+static void goodix_ts_early_suspend(struct early_suspend *h)
+{
+ struct goodix_ts_data *ts;
+ s8 ret = -1;
+ ts = container_of(h, struct goodix_ts_data, early_suspend);
+
+ GTP_DEBUG_FUNC();
+
+#if GTP_ESD_PROTECT
+ ts->gtp_is_suspend = 1;
+ gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+
+#if GTP_SLIDE_WAKEUP
+ ret = gtp_enter_doze(ts);
+#else
+ if (ts->use_irq)
+ {
+ gtp_irq_disable(ts);
+ }
+ else
+ {
+ hrtimer_cancel(&ts->timer);
+ }
+ ret = gtp_enter_sleep(ts);
+#endif
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP early suspend failed.");
+ }
+ // to avoid waking up while not sleeping
+ // delay 48 + 10ms to ensure reliability
+ msleep(58);
+}
+
+/*******************************************************
+Function:
+ Late resume function.
+Input:
+ h: early_suspend struct.
+Output:
+ None.
+*******************************************************/
+static void goodix_ts_late_resume(struct early_suspend *h)
+{
+ struct goodix_ts_data *ts;
+ s8 ret = -1;
+ ts = container_of(h, struct goodix_ts_data, early_suspend);
+
+ GTP_DEBUG_FUNC();
+
+ ret = gtp_wakeup_sleep(ts);
+
+#if GTP_SLIDE_WAKEUP
+ doze_status = DOZE_DISABLED;
+#endif
+
+ if (ret < 0)
+ {
+ GTP_ERROR("GTP later resume failed.");
+ }
+
+ if (ts->use_irq)
+ {
+ gtp_irq_enable(ts);
+ }
+ else
+ {
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ }
+
+#if GTP_ESD_PROTECT
+ ts->gtp_is_suspend = 0;
+ gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+}
+#endif
+
+#if GTP_ESD_PROTECT
+/*******************************************************
+Function:
+ switch on & off esd delayed work
+Input:
+ client: i2c device
+ on: SWITCH_ON / SWITCH_OFF
+Output:
+ void
+*********************************************************/
+void gtp_esd_switch(struct i2c_client *client, s32 on)
+{
+ struct goodix_ts_data *ts;
+
+ ts = i2c_get_clientdata(client);
+ if (SWITCH_ON == on) // switch on esd
+ {
+ if (!ts->esd_running)
+ {
+ ts->esd_running = 1;
+ GTP_INFO("Esd started");
+ queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+ }
+ }
+ else // switch off esd
+ {
+ if (ts->esd_running)
+ {
+ ts->esd_running = 0;
+ GTP_INFO("Esd cancelled");
+ cancel_delayed_work_sync(>p_esd_check_work);
+ }
+ }
+}
+
+/*******************************************************
+Function:
+ Initialize external watchdog for esd protect
+Input:
+ client: i2c device.
+Output:
+ result of i2c write operation.
+ 1: succeed, otherwise: failed
+*********************************************************/
+static s32 gtp_init_ext_watchdog(struct i2c_client *client)
+{
+ u8 opr_buffer[4] = {0x80, 0x40, 0xAA, 0xAA};
+
+ struct i2c_msg msg; // in case of recursively reset by calling gtp_i2c_write
+ s32 ret = -1;
+ s32 retries = 0;
+
+ GTP_DEBUG("Init external watchdog...");
+ GTP_DEBUG_FUNC();
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = 4;
+ msg.buf = opr_buffer;
+
+ while(retries < 5)
+ {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ {
+ return 1;
+ }
+ retries++;
+ }
+ if (retries >= 5)
+ {
+ GTP_ERROR("init external watchdog failed!");
+ }
+ return 0;
+}
+
+/*******************************************************
+Function:
+ Esd protect function.
+ Added external watchdog by meta, 2013/03/07
+Input:
+ work: delayed work
+Output:
+ None.
+*******************************************************/
+static void gtp_esd_check_func(struct work_struct *work)
+{
+ s32 i;
+ s32 ret = -1;
+ struct goodix_ts_data *ts = NULL;
+ u8 test[4] = {0x80, 0x40};
+
+ GTP_DEBUG_FUNC();
+
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ if (ts->gtp_is_suspend)
+ {
+ ts->esd_running = 0;
+ GTP_INFO("Esd terminated!");
+ return;
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ ret = gtp_i2c_read(ts->client, test, 4);
+
+ GTP_DEBUG("0x8040 = 0x%02X, 0x8041 = 0x%02X", test[2], test[3]);
+ if ((ret < 0))
+ {
+ // IIC communication problem
+ continue;
+ }
+ else
+ {
+ if ((test[2] == 0xAA) || (test[3] != 0xAA))
+ {
+ // IC works abnormally..
+ i = 3;
+ break;
+ }
+ else
+ {
+ // IC works normally, Write 0x8040 0xAA, feed the dog
+ test[2] = 0xAA;
+ gtp_i2c_write(ts->client, test, 3);
+ break;
+ }
+ }
+ }
+ if (i >= 3)
+ {
+ GTP_ERROR("IC Working ABNORMALLY, Resetting Guitar...");
+ gtp_reset_guitar(ts->client, 50);
+ }
+
+ if(!ts->gtp_is_suspend)
+ {
+ queue_delayed_work(gtp_esd_check_workqueue, >p_esd_check_work, GTP_ESD_CHECK_CIRCLE);
+ }
+ else
+ {
+ GTP_INFO("Esd terminated!");
+ ts->esd_running = 0;
+ }
+ return;
+}
+#endif
+
+static const struct i2c_device_id goodix_ts_id[] = {
+ { GTP_I2C_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver goodix_ts_driver = {
+ .probe = goodix_ts_probe,
+ .remove = goodix_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = goodix_ts_early_suspend,
+ .resume = goodix_ts_late_resume,
+#endif
+ .id_table = goodix_ts_id,
+ .driver = {
+ .name = GTP_I2C_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+/*******************************************************
+Function:
+ Driver Install function.
+Input:
+ None.
+Output:
+ Executive Outcomes. 0---succeed.
+********************************************************/
+static int __devinit goodix_ts_init(void)
+{
+ s32 ret;
+
+ GTP_DEBUG_FUNC();
+ GTP_INFO("GTP driver installing...");
+ goodix_wq = create_singlethread_workqueue("goodix_wq");
+ if (!goodix_wq)
+ {
+ GTP_ERROR("Creat workqueue failed.");
+ return -ENOMEM;
+ }
+#if GTP_ESD_PROTECT
+ INIT_DELAYED_WORK(>p_esd_check_work, gtp_esd_check_func);
+ gtp_esd_check_workqueue = create_workqueue("gtp_esd_check");
+#endif
+ ret = i2c_add_driver(&goodix_ts_driver);
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Driver uninstall function.
+Input:
+ None.
+Output:
+ Executive Outcomes. 0---succeed.
+********************************************************/
+static void __exit goodix_ts_exit(void)
+{
+ GTP_DEBUG_FUNC();
+ GTP_INFO("GTP driver exited.");
+ i2c_del_driver(&goodix_ts_driver);
+ if (goodix_wq)
+ {
+ destroy_workqueue(goodix_wq);
+ }
+}
+
+late_initcall(goodix_ts_init);
+module_exit(goodix_ts_exit);
+
+MODULE_DESCRIPTION("GTP Series Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
new file mode 100644
index 0000000..e375af5
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -0,0 +1,241 @@
+/* drivers/input/touchscreen/gt9xx.h
+ *
+ * 2010 - 2013 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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 _GOODIX_GT9XX_H_
+#define _GOODIX_GT9XX_H_
+
+#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <mach/gpio.h>
+#include <linux/earlysuspend.h>
+
+struct goodix_ts_data {
+ spinlock_t irq_lock;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct hrtimer timer;
+ struct work_struct work;
+ struct early_suspend early_suspend;
+ s32 irq_is_disable;
+ s32 use_irq;
+ u16 abs_x_max;
+ u16 abs_y_max;
+ u8 max_touch_num;
+ u8 int_trigger_type;
+ u8 green_wake_mode;
+ u8 chip_type;
+ u8 enter_update;
+ u8 gtp_is_suspend;
+ u8 gtp_rawdiff_mode;
+ u8 gtp_cfg_len;
+ u8 fixed_cfg;
+ u8 esd_running;
+ u8 fw_error;
+};
+
+extern u16 show_len;
+extern u16 total_len;
+
+//***************************PART1:ON/OFF define*******************************
+#define GTP_CUSTOM_CFG 0
+#define GTP_CHANGE_X2Y 0
+#define GTP_DRIVER_SEND_CFG 1
+#define GTP_HAVE_TOUCH_KEY 0
+#define GTP_POWER_CTRL_SLEEP 0
+#define GTP_ICS_SLOT_REPORT 0
+
+#define GTP_AUTO_UPDATE 1 // auto updated by .bin file as default
+#define GTP_HEADER_FW_UPDATE 0 // auto updated by head_fw_array in gt9xx_firmware.h, function together with GTP_AUTO_UPDATE
+
+#define GTP_CREATE_WR_NODE 1
+#define GTP_ESD_PROTECT 0
+#define GTP_WITH_PEN 0
+
+#define GTP_SLIDE_WAKEUP 0
+#define GTP_DBL_CLK_WAKEUP 0 // double-click wakeup, function together with GTP_SLIDE_WAKEUP
+
+#define GTP_DEBUG_ON 1
+#define GTP_DEBUG_ARRAY_ON 0
+#define GTP_DEBUG_FUNC_ON 0
+
+//*************************** PART2:TODO define **********************************
+// STEP_1(REQUIRED): Define Configuration Information Group(s)
+// Sensor_ID Map:
+/* sensor_opt1 sensor_opt2 Sensor_ID
+ GND GND 0
+ VDDIO GND 1
+ NC GND 2
+ GND NC/300K 3
+ VDDIO NC/300K 4
+ NC NC/300K 5
+*/
+// TODO: define your own default or for Sensor_ID == 0 config here.
+// The predefined one is just a sample config, which is not suitable for your tp in most cases.
+#define CTP_CFG_GROUP1 {\
+ 0x41,0x1C,0x02,0xC0,0x03,0x0A,0x05,0x01,0x01,0x0F,\
+ 0x23,0x0F,0x5F,0x41,0x03,0x05,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x00,0x0A,\
+ 0x28,0x00,0xB8,0x0B,0x00,0x00,0x00,0x9A,0x03,0x25,\
+ 0x00,0x00,0x00,0x00,0x00,0x03,0x64,0x32,0x00,0x00,\
+ 0x00,0x32,0x8C,0x94,0x05,0x01,0x05,0x00,0x00,0x96,\
+ 0x0C,0x22,0xD8,0x0E,0x23,0x56,0x11,0x25,0xFF,0x13,\
+ 0x28,0xA7,0x15,0x2E,0x00,0x00,0x10,0x30,0x48,0x00,\
+ 0x56,0x4A,0x3A,0xFF,0xFF,0x16,0x00,0x00,0x00,0x00,\
+ 0x00,0x01,0x1B,0x14,0x0D,0x19,0x00,0x00,0x01,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x1A,0x18,0x16,0x14,0x12,0x10,0x0E,0x0C,\
+ 0x0A,0x08,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+ 0xFF,0xFF,0x1D,0x1E,0x1F,0x20,0x22,0x24,0x28,0x29,\
+ 0x0C,0x0A,0x08,0x00,0x02,0x04,0x05,0x06,0x0E,0xFF,\
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,\
+ 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x01\
+ }
+
+// TODO: define your config for Sensor_ID == 1 here, if needed
+#define CTP_CFG_GROUP2 {\
+ }
+// TODO: define your config for Sensor_ID == 2 here, if needed
+#define CTP_CFG_GROUP3 {\
+ }
+
+// TODO: define your config for Sensor_ID == 3 here, if needed
+#define CTP_CFG_GROUP4 {\
+ }
+
+// TODO: define your config for Sensor_ID == 4 here, if needed
+#define CTP_CFG_GROUP5 {\
+ }
+
+// TODO: define your config for Sensor_ID == 5 here, if needed
+#define CTP_CFG_GROUP6 {\
+ }
+
+// STEP_2(REQUIRED): Customize your I/O ports & I/O operations
+#define GTP_RST_PORT S5PV210_GPJ3(6)
+#define GTP_INT_PORT S5PV210_GPH1(3)
+#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT)
+#define GTP_INT_CFG S3C_GPIO_SFN(0xF)
+
+#define GTP_GPIO_AS_INPUT(pin) do{\
+ gpio_direction_input(pin);\
+ s3c_gpio_setpull(pin, S3C_GPIO_PULL_NONE);\
+ }while(0)
+#define GTP_GPIO_AS_INT(pin) do{\
+ GTP_GPIO_AS_INPUT(pin);\
+ s3c_gpio_cfgpin(pin, GTP_INT_CFG);\
+ }while(0)
+#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin)
+#define GTP_GPIO_OUTPUT(pin,level) gpio_direction_output(pin,level)
+#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label)
+#define GTP_GPIO_FREE(pin) gpio_free(pin)
+#define GTP_IRQ_TAB {IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_LOW, IRQ_TYPE_LEVEL_HIGH}
+
+// STEP_3(optional): Specify your special config info if needed
+#if GTP_CUSTOM_CFG
+ #define GTP_MAX_HEIGHT 800
+ #define GTP_MAX_WIDTH 480
+ #define GTP_INT_TRIGGER 0 // 0: Rising 1: Falling
+#else
+ #define GTP_MAX_HEIGHT 4096
+ #define GTP_MAX_WIDTH 4096
+ #define GTP_INT_TRIGGER 1
+#endif
+#define GTP_MAX_TOUCH 5
+#define GTP_ESD_CHECK_CIRCLE 2000 // jiffy: ms
+
+// STEP_4(optional): If keys are available and reported as keys, config your key info here
+#if GTP_HAVE_TOUCH_KEY
+ #define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK}
+#endif
+
+//***************************PART3:OTHER define*********************************
+#define GTP_DRIVER_VERSION "V1.8<2013/06/08>"
+#define GTP_I2C_NAME "Goodix-TS"
+#define GTP_POLL_TIME 10 // jiffy: ms
+#define GTP_ADDR_LENGTH 2
+#define GTP_CONFIG_MIN_LENGTH 186
+#define GTP_CONFIG_MAX_LENGTH 240
+#define FAIL 0
+#define SUCCESS 1
+#define SWITCH_OFF 0
+#define SWITCH_ON 1
+
+// Registers define
+#define GTP_READ_COOR_ADDR 0x814E
+#define GTP_REG_SLEEP 0x8040
+#define GTP_REG_SENSOR_ID 0x814A
+#define GTP_REG_CONFIG_DATA 0x8047
+#define GTP_REG_VERSION 0x8140
+
+#define RESOLUTION_LOC 3
+#define TRIGGER_LOC 8
+
+#define CFG_GROUP_LEN(p_cfg_grp) (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))
+// Log define
+#define GTP_INFO(fmt,arg...) printk("<<-GTP-INFO->> "fmt"\n",##arg)
+#define GTP_ERROR(fmt,arg...) printk("<<-GTP-ERROR->> "fmt"\n",##arg)
+#define GTP_DEBUG(fmt,arg...) do{\
+ if(GTP_DEBUG_ON)\
+ printk("<<-GTP-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
+ }while(0)
+#define GTP_DEBUG_ARRAY(array, num) do{\
+ s32 i;\
+ u8* a = array;\
+ if(GTP_DEBUG_ARRAY_ON)\
+ {\
+ printk("<<-GTP-DEBUG-ARRAY->>\n");\
+ for (i = 0; i < (num); i++)\
+ {\
+ printk("%02x ", (a)[i]);\
+ if ((i + 1 ) %10 == 0)\
+ {\
+ printk("\n");\
+ }\
+ }\
+ printk("\n");\
+ }\
+ }while(0)
+#define GTP_DEBUG_FUNC() do{\
+ if(GTP_DEBUG_FUNC_ON)\
+ printk("<<-GTP-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
+ }while(0)
+#define GTP_SWAP(x, y) do{\
+ typeof(x) z = x;\
+ x = y;\
+ y = z;\
+ }while (0)
+
+//*****************************End of Part III********************************
+
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
new file mode 100644
index 0000000..3998bf0
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_firmware.h
@@ -0,0 +1,6 @@
+// make sense only when GTP_HEADER_FW_UPDATE & GTP_AUTO_UPDATE are enabled
+// define your own firmware array here
+const unsigned char header_fw_array[] =
+{
+
+};
\ No newline at end of file
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
new file mode 100644
index 0000000..f564a6b
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c
@@ -0,0 +1,1930 @@
+/* drivers/input/touchscreen/gt9xx_update.c
+ *
+ * 2010 - 2012 Goodix Technology.
+ *
+ * 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 a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Latest Version:1.6
+ * Author: andrew@goodix.com
+ * Revision Record:
+ * V1.0:
+ * first release. By Andrew, 2012/08/31
+ * V1.2:
+ * add force update,GT9110P pid map. By Andrew, 2012/10/15
+ * V1.4:
+ * 1. add config auto update function;
+ * 2. modify enter_update_mode;
+ * 3. add update file cal checksum.
+ * By Andrew, 2012/12/12
+ * V1.6:
+ * 1. replace guitar_client with i2c_connect_client;
+ * 2. support firmware header array update.
+ * By Meta, 2013/03/11
+ */
+#include <linux/kthread.h>
+#include "gt9xx.h"
+
+#if GTP_HEADER_FW_UPDATE
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include "gt9xx_firmware.h"
+#endif
+
+#define GUP_REG_HW_INFO 0x4220
+#define GUP_REG_FW_MSG 0x41E4
+#define GUP_REG_PID_VID 0x8140
+
+#define GUP_SEARCH_FILE_TIMES 50
+#define UPDATE_FILE_PATH_2 "/data/_goodix_update_.bin"
+#define UPDATE_FILE_PATH_1 "/sdcard/_goodix_update_.bin"
+
+#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
+#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
+
+#define FW_HEAD_LENGTH 14
+#define FW_SECTION_LENGTH 0x2000
+#define FW_DSP_ISP_LENGTH 0x1000
+#define FW_DSP_LENGTH 0x1000
+#define FW_BOOT_LENGTH 0x800
+
+#define PACK_SIZE 256
+#define MAX_FRAME_CHECK_TIME 5
+
+#define _bRW_MISCTL__SRAM_BANK 0x4048
+#define _bRW_MISCTL__MEM_CD_EN 0x4049
+#define _bRW_MISCTL__CACHE_EN 0x404B
+#define _bRW_MISCTL__TMR0_EN 0x40B0
+#define _rRW_MISCTL__SWRST_B0_ 0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218
+#define _rRW_MISCTL__BOOT_CTL_ 0x5094
+
+#define FAIL 0
+#define SUCCESS 1
+
+#pragma pack(1)
+typedef struct
+{
+ u8 hw_info[4]; //hardware info//
+ u8 pid[8]; //product id //
+ u16 vid; //version id //
+}st_fw_head;
+#pragma pack()
+
+typedef struct
+{
+ u8 force_update;
+ u8 fw_flag;
+ struct file *file;
+ struct file *cfg_file;
+ st_fw_head ic_fw_msg;
+ mm_segment_t old_fs;
+}st_update_msg;
+
+st_update_msg update_msg;
+u16 show_len;
+u16 total_len;
+u8 got_file_flag = 0;
+u8 searching_file = 0;
+extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern s32 gtp_send_cfg(struct i2c_client *client);
+extern struct i2c_client * i2c_connect_client;
+extern void gtp_irq_enable(struct goodix_ts_data *ts);
+extern void gtp_irq_disable(struct goodix_ts_data *ts);
+extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
+#if GTP_ESD_PROTECT
+extern void gtp_esd_switch(struct i2c_client *, s32);
+#endif
+/*******************************************************
+Function:
+ Read data from the i2c slave device.
+Input:
+ client: i2c device.
+ buf[0~1]: read start address.
+ buf[2~len-1]: read data buffer.
+ len: GTP_ADDR_LENGTH + read bytes count
+Output:
+ numbers of i2c_msgs to transfer:
+ 2: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
+{
+ struct i2c_msg msgs[2];
+ s32 ret=-1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msgs[0].flags = !I2C_M_RD;
+ msgs[0].addr = client->addr;
+ msgs[0].len = GTP_ADDR_LENGTH;
+ msgs[0].buf = &buf[0];
+ //msgs[0].scl_rate = 300 * 1000; // for Rockchip
+
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].addr = client->addr;
+ msgs[1].len = len - GTP_ADDR_LENGTH;
+ msgs[1].buf = &buf[GTP_ADDR_LENGTH];
+ //msgs[1].scl_rate = 300 * 1000;
+
+ while(retries < 5)
+ {
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if(ret == 2)break;
+ retries++;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+Function:
+ Write data to the i2c slave device.
+Input:
+ client: i2c device.
+ buf[0~1]: write start address.
+ buf[2~len-1]: data buffer
+ len: GTP_ADDR_LENGTH + write bytes count
+Output:
+ numbers of i2c_msgs to transfer:
+ 1: succeed, otherwise: failed
+*********************************************************/
+s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
+{
+ struct i2c_msg msg;
+ s32 ret=-1;
+ s32 retries = 0;
+
+ GTP_DEBUG_FUNC();
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = buf;
+ //msg.scl_rate = 300 * 1000; // for Rockchip
+
+ while(retries < 5)
+ {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)break;
+ retries++;
+ }
+
+ return ret;
+}
+
+static s32 gup_init_panel(struct goodix_ts_data *ts)
+{
+ s32 ret = 0;
+ s32 i = 0;
+ u8 check_sum = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
+
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+ u8 cfg_info_group6[] = CTP_CFG_GROUP6;
+ u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2, cfg_info_group3,
+ cfg_info_group4, cfg_info_group5, cfg_info_group6};
+ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5),
+ CFG_GROUP_LEN(cfg_info_group6)};
+
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+ (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+ (!cfg_info_len[5]))
+ {
+ sensor_id = 0;
+ }
+ else
+ {
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
+ if (SUCCESS == ret)
+ {
+ if (sensor_id >= 0x06)
+ {
+ GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
+ return -1;
+ }
+ }
+ else
+ {
+ GTP_ERROR("Failed to get sensor_id, No config sent!");
+ return -1;
+ }
+ }
+
+ GTP_DEBUG("Sensor_ID: %d", sensor_id);
+
+ ts->gtp_cfg_len = cfg_info_len[sensor_id];
+
+ if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH)
+ {
+ GTP_ERROR("Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!", sensor_id);
+ return -1;
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, &opr_buf[0], 1);
+
+ if (ret == SUCCESS)
+ {
+ GTP_DEBUG("CFG_GROUP%d Config Version: %d, IC Config Version: %d", sensor_id+1,
+ send_cfg_buf[sensor_id][0], opr_buf[0]);
+
+ send_cfg_buf[sensor_id][0] = opr_buf[0];
+ ts->fixed_cfg = 0;
+ /*
+ if (opr_buf[0] < 90)
+ {
+ grp_cfg_version = send_cfg_buf[sensor_id][0]; // backup group config version
+ send_cfg_buf[sensor_id][0] = 0x00;
+ ts->fixed_cfg = 0;
+ }
+ else // treated as fixed config, not send config
+ {
+ GTP_INFO("Ic fixed config with config version(%d)", opr_buf[0]);
+ ts->fixed_cfg = 1;
+ }*/
+ }
+ else
+ {
+ GTP_ERROR("Failed to get ic config version!No config sent!");
+ return -1;
+ }
+
+ memset(&config[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&config[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], ts->gtp_cfg_len);
+
+ GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
+ ts->abs_x_max, ts->abs_y_max, ts->int_trigger_type);
+
+ config[RESOLUTION_LOC] = (u8)GTP_MAX_WIDTH;
+ config[RESOLUTION_LOC + 1] = (u8)(GTP_MAX_WIDTH>>8);
+ config[RESOLUTION_LOC + 2] = (u8)GTP_MAX_HEIGHT;
+ config[RESOLUTION_LOC + 3] = (u8)(GTP_MAX_HEIGHT>>8);
+
+ if (GTP_INT_TRIGGER == 0) //RISING
+ {
+ config[TRIGGER_LOC] &= 0xfe;
+ }
+ else if (GTP_INT_TRIGGER == 1) //FALLING
+ {
+ config[TRIGGER_LOC] |= 0x01;
+ }
+
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
+ {
+ check_sum += config[i];
+ }
+ config[ts->gtp_cfg_len] = (~check_sum) + 1;
+
+ GTP_DEBUG_FUNC();
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ {
+ GTP_ERROR("Send config error.");
+ }
+
+ msleep(10);
+ return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8* msg, s32 len)
+{
+ s32 i = 0;
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gup_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+ {
+ break;
+ }
+ }
+
+ if (i >= 5)
+ {
+ GTP_ERROR("Read data from 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+ s32 i = 0;
+ u8 msg[3];
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+ msg[2] = val;
+
+ for (i = 0; i < 5; i++)
+ {
+ if (gup_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+ {
+ break;
+ }
+ }
+
+ if (i >= 5)
+ {
+ GTP_ERROR("Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_get_ic_fw_msg(struct i2c_client *client)
+{
+ s32 ret = -1;
+ u8 retry = 0;
+ u8 buf[16];
+ u8 i;
+
+ // step1:get hardware info
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, &buf[GTP_ADDR_LENGTH], 4);
+ if (FAIL == ret)
+ {
+ GTP_ERROR("[get_ic_fw_msg]get hw_info failed,exit");
+ return FAIL;
+ }
+
+ // buf[2~5]: 00 06 90 00
+ // hw_info: 00 90 06 00
+ for(i=0; i<4; i++)
+ {
+ update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+ }
+ GTP_DEBUG("IC Hardware info:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
+ // step2:get firmware message
+ for(retry=0; retry<2; retry++)
+ {
+ ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("Read firmware message fail.");
+ return ret;
+ }
+
+ update_msg.force_update = buf[GTP_ADDR_LENGTH];
+ if((0xBE != update_msg.force_update)&&(!retry))
+ {
+ GTP_INFO("The check sum in ic is error.");
+ GTP_INFO("The IC will be updated by force.");
+ continue;
+ }
+ break;
+ }
+ GTP_DEBUG("IC force update flag:0x%x", update_msg.force_update);
+
+ // step3:get pid & vid
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, &buf[GTP_ADDR_LENGTH], 6);
+ if (FAIL == ret)
+ {
+ GTP_ERROR("[get_ic_fw_msg]get pid & vid failed,exit");
+ return FAIL;
+ }
+
+ memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+ memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+ GTP_DEBUG("IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+ //GT9XX PID MAPPING
+ /*|-----FLASH-----RAM-----|
+ |------918------918-----|
+ |------968------968-----|
+ |------913------913-----|
+ |------913P-----913P----|
+ |------927------927-----|
+ |------927P-----927P----|
+ |------9110-----9110----|
+ |------9110P----9111----|*/
+ if(update_msg.ic_fw_msg.pid[0] != 0)
+ {
+ if(!memcmp(update_msg.ic_fw_msg.pid, "9111", 4))
+ {
+ GTP_DEBUG("IC Mapping Product id:%s", update_msg.ic_fw_msg.pid);
+ memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+ }
+ }
+
+ update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH+4] + (buf[GTP_ADDR_LENGTH+5]<<8);
+ GTP_DEBUG("IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+ return SUCCESS;
+}
+
+s32 gup_enter_update_mode(struct i2c_client *client)
+{
+ s32 ret = -1;
+ s32 retry = 0;
+ u8 rd_buf[3];
+
+ //step1:RST output low last at least 2ms
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);
+ msleep(2);
+
+ //step2:select I2C slave addr,INT:0--0xBA;1--0x28.
+ GTP_GPIO_OUTPUT(GTP_INT_PORT, (client->addr == 0x14));
+ msleep(2);
+
+ //step3:RST output high reset guitar
+ GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
+
+ //20121211 modify start
+ msleep(5);
+ while(retry++ < 200)
+ {
+ //step4:Hold ss51 & dsp
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if(ret <= 0)
+ {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+
+ //step5:Confirm hold
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+ if(ret <= 0)
+ {
+ GTP_DEBUG("Hold ss51 & dsp I2C error,retry:%d", retry);
+ continue;
+ }
+ if(0x0C == rd_buf[GTP_ADDR_LENGTH])
+ {
+ GTP_DEBUG("Hold ss51 & dsp confirm SUCCESS");
+ break;
+ }
+ GTP_DEBUG("Hold ss51 & dsp confirm 0x4180 failed,value:%d", rd_buf[GTP_ADDR_LENGTH]);
+ }
+ if(retry >= 200)
+ {
+ GTP_ERROR("Enter update Hold ss51 failed.");
+ return FAIL;
+ }
+
+ //step6:DSP_CK and DSP_ALU_CK PowerOn
+ ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+ //20121211 modify end
+ return ret;
+}
+
+void gup_leave_update_mode(void)
+{
+ GTP_GPIO_AS_INT(GTP_INT_PORT);
+
+ GTP_DEBUG("[leave_update_mode]reset chip.");
+ gtp_reset_guitar(i2c_connect_client, 20);
+}
+
+// Get the correct nvram data
+// The correct conditions:
+// 1. the hardware info is the same
+// 2. the product id is the same
+// 3. the firmware version in update file is greater than the firmware version in ic
+// or the check sum in ic is wrong
+/* Update Conditions:
+ 1. Same hardware info
+ 2. Same PID
+ 3. File PID > IC PID
+ Force Update Conditions:
+ 1. Wrong ic firmware checksum
+ 2. INVALID IC PID or VID
+ 3. IC PID == 91XX || File PID == 91XX
+*/
+
+static u8 gup_enter_update_judge(st_fw_head *fw_head)
+{
+ u16 u16_tmp;
+ s32 i = 0;
+
+ u16_tmp = fw_head->vid;
+ fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+ GTP_DEBUG("FILE HARDWARE INFO:%02x%02x%02x%02x", fw_head->hw_info[0], fw_head->hw_info[1], fw_head->hw_info[2], fw_head->hw_info[3]);
+ GTP_DEBUG("FILE PID:%s", fw_head->pid);
+ GTP_DEBUG("FILE VID:%04x", fw_head->vid);
+
+ GTP_DEBUG("IC HARDWARE INFO:%02x%02x%02x%02x", update_msg.ic_fw_msg.hw_info[0], update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2], update_msg.ic_fw_msg.hw_info[3]);
+ GTP_DEBUG("IC PID:%s", update_msg.ic_fw_msg.pid);
+ GTP_DEBUG("IC VID:%04x", update_msg.ic_fw_msg.vid);
+
+ //First two conditions
+ if ( !memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, sizeof(update_msg.ic_fw_msg.hw_info)))
+ {
+ GTP_DEBUG("Get the same hardware info.");
+ if( update_msg.force_update != 0xBE )
+ {
+ GTP_INFO("FW chksum error,need enter update.");
+ return SUCCESS;
+ }
+
+ // 20130523 start
+ if (strlen(update_msg.ic_fw_msg.pid) < 3)
+ {
+ GTP_INFO("Illegal IC pid, need enter update");
+ return SUCCESS;
+ }
+ else
+ {
+ for (i = 0; i < 3; i++)
+ {
+ if ((update_msg.ic_fw_msg.pid[i] < 0x30) || (update_msg.ic_fw_msg.pid[i] > 0x39))
+ {
+ GTP_INFO("Illegal IC pid, out of bound, need enter update");
+ return SUCCESS;
+ }
+ }
+ }
+ // 20130523 end
+
+
+ if (( !memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, (strlen(fw_head->pid)<3?3:strlen(fw_head->pid))))||
+ (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4))||
+ (!memcmp(fw_head->pid, "91XX", 4)))
+ {
+ if(!memcmp(fw_head->pid, "91XX", 4))
+ {
+ GTP_DEBUG("Force none same pid update mode.");
+ }
+ else
+ {
+ GTP_DEBUG("Get the same pid.");
+ }
+ //The third condition
+ if (fw_head->vid > update_msg.ic_fw_msg.vid)
+ {
+
+ GTP_INFO("Need enter update.");
+ return SUCCESS;
+ }
+ GTP_ERROR("Don't meet the third condition.");
+ GTP_ERROR("File VID <= Ic VID, update aborted!");
+ }
+ else
+ {
+ GTP_ERROR("File PID != Ic PID, update aborted!");
+ }
+ }
+ else
+ {
+ GTP_ERROR("Different Hardware, update aborted!");
+ }
+ return FAIL;
+}
+
+static u8 ascii2hex(u8 a)
+{
+ s8 value = 0;
+
+ if(a >= '0' && a <= '9')
+ {
+ value = a - '0';
+ }
+ else if(a >= 'A' && a <= 'F')
+ {
+ value = a - 'A' + 0x0A;
+ }
+ else if(a >= 'a' && a <= 'f')
+ {
+ value = a - 'a' + 0x0A;
+ }
+ else
+ {
+ value = 0xff;
+ }
+
+ return value;
+}
+
+static s8 gup_update_config(struct i2c_client *client)
+{
+ s32 file_len = 0;
+ s32 ret = 0;
+ s32 i = 0;
+ s32 file_cfg_len = 0;
+ s32 chip_cfg_len = 0;
+ s32 count = 0;
+ u8 *buf;
+ u8 *pre_buf;
+ u8 *file_config;
+ //u8 checksum = 0;
+ u8 pid[8];
+
+ if(NULL == update_msg.cfg_file)
+ {
+ GTP_ERROR("[update_cfg]No need to upgrade config!");
+ return FAIL;
+ }
+ file_len = update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_END);
+
+ ret = gup_get_ic_msg(client, GUP_REG_PID_VID, pid, 6);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_cfg]Read product id & version id fail.");
+ return FAIL;
+ }
+ pid[5] = '\0';
+ GTP_DEBUG("update cfg get pid:%s", &pid[GTP_ADDR_LENGTH]);
+
+ chip_cfg_len = 186;
+ if(!memcmp(&pid[GTP_ADDR_LENGTH], "968", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "910", 3) ||
+ !memcmp(&pid[GTP_ADDR_LENGTH], "960", 3))
+ {
+ chip_cfg_len = 228;
+ }
+ GTP_DEBUG("[update_cfg]config file len:%d", file_len);
+ GTP_DEBUG("[update_cfg]need config len:%d",chip_cfg_len);
+ if((file_len+5) < chip_cfg_len*5)
+ {
+ GTP_ERROR("Config length error");
+ return -1;
+ }
+
+ buf = (u8*)kzalloc(file_len, GFP_KERNEL);
+ pre_buf = (u8*)kzalloc(file_len, GFP_KERNEL);
+ file_config = (u8*)kzalloc(chip_cfg_len + GTP_ADDR_LENGTH, GFP_KERNEL);
+ update_msg.cfg_file->f_op->llseek(update_msg.cfg_file, 0, SEEK_SET);
+
+ GTP_DEBUG("[update_cfg]Read config from file.");
+ ret = update_msg.cfg_file->f_op->read(update_msg.cfg_file, (char*)pre_buf, file_len, &update_msg.cfg_file->f_pos);
+ if(ret<0)
+ {
+ GTP_ERROR("[update_cfg]Read config file failed.");
+ goto update_cfg_file_failed;
+ }
+
+ GTP_DEBUG("[update_cfg]Delete illgal charactor.");
+ for(i=0,count=0; i<file_len; i++)
+ {
+ if (pre_buf[i] == ' ' || pre_buf[i] == '\r' || pre_buf[i] == '\n')
+ {
+ continue;
+ }
+ buf[count++] = pre_buf[i];
+ }
+
+ GTP_DEBUG("[update_cfg]Ascii to hex.");
+ file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+ file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+ for(i=0,file_cfg_len=GTP_ADDR_LENGTH; i<count; i+=5)
+ {
+ if((buf[i]=='0') && ((buf[i+1]=='x') || (buf[i+1]=='X')))
+ {
+ u8 high,low;
+ high = ascii2hex(buf[i+2]);
+ low = ascii2hex(buf[i+3]);
+
+ if((high == 0xFF) || (low == 0xFF))
+ {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ file_config[file_cfg_len++] = (high<<4) + low;
+ }
+ else
+ {
+ ret = 0;
+ GTP_ERROR("[update_cfg]Illegal config file.");
+ goto update_cfg_file_failed;
+ }
+ }
+
+// //cal checksum
+// for(i=GTP_ADDR_LENGTH; i<chip_cfg_len; i++)
+// {
+// checksum += file_config[i];
+// }
+// file_config[chip_cfg_len] = (~checksum) + 1;
+// file_config[chip_cfg_len+1] = 0x01;
+
+ GTP_DEBUG("config:");
+ GTP_DEBUG_ARRAY(file_config+2, file_cfg_len);
+
+ i = 0;
+ while(i++ < 5)
+ {
+ ret = gup_i2c_write(client, file_config, file_cfg_len);
+ if(ret > 0)
+ {
+ GTP_INFO("[update_cfg]Send config SUCCESS.");
+ break;
+ }
+ GTP_ERROR("[update_cfg]Send config i2c error.");
+ }
+
+update_cfg_file_failed:
+ kfree(pre_buf);
+ kfree(buf);
+ kfree(file_config);
+ return ret;
+}
+
+#if GTP_HEADER_FW_UPDATE
+static u8 gup_check_fs_mounted(char *path_name)
+{
+ struct path root_path;
+ struct path path;
+ int err;
+ err = kern_path("/", LOOKUP_FOLLOW, &root_path);
+
+ if (err)
+ {
+ GTP_DEBUG("\"/\" NOT Mounted: %d", err);
+ return FAIL;
+ }
+ err = kern_path(path_name, LOOKUP_FOLLOW, &path);
+
+ if (err)
+ {
+ GTP_DEBUG("/data/ NOT Mounted: %d", err);
+ return FAIL;
+ }
+
+ return SUCCESS;
+
+ /*
+ if (path.mnt->mnt_sb == root_path.mnt->mnt_sb)
+ {
+ //-- not mounted
+ return FAIL;
+ }
+ else
+ {
+ return SUCCESS;
+ }*/
+
+}
+#endif
+static u8 gup_check_update_file(struct i2c_client *client, st_fw_head* fw_head, u8* path)
+{
+ s32 ret = 0;
+ s32 i = 0;
+ s32 fw_checksum = 0;
+ u8 buf[FW_HEAD_LENGTH];
+
+ if (path)
+ {
+ GTP_DEBUG("Update File path:%s, %d", path, strlen(path));
+ update_msg.file = filp_open(path, O_RDONLY, 0);
+
+ if (IS_ERR(update_msg.file))
+ {
+ GTP_ERROR("Open update file(%s) error!", path);
+ return FAIL;
+ }
+ }
+ else
+ {
+#if GTP_HEADER_FW_UPDATE
+ for (i = 0; i < (GUP_SEARCH_FILE_TIMES); i++)
+ {
+ GTP_DEBUG("Waiting for /data mounted [%d]", i);
+
+ if (gup_check_fs_mounted("/data") == SUCCESS)
+ {
+ GTP_DEBUG("/data Mounted!");
+ break;
+ }
+ msleep(3000);
+ }
+ if (i >= (GUP_SEARCH_FILE_TIMES))
+ {
+ GTP_ERROR("Wait for /data mounted timeout!");
+ return FAIL;
+ }
+
+ // update config
+ update_msg.cfg_file = filp_open(CONFIG_FILE_PATH_1, O_RDONLY, 0);
+ if (IS_ERR(update_msg.cfg_file))
+ {
+ GTP_DEBUG("%s is unavailable", CONFIG_FILE_PATH_1);
+ }
+ else
+ {
+ GTP_INFO("Update Config File: %s", CONFIG_FILE_PATH_1);
+ ret = gup_update_config(client);
+ if(ret <= 0)
+ {
+ GTP_ERROR("Update config failed.");
+ }
+ filp_close(update_msg.cfg_file, NULL);
+ }
+
+ if (sizeof(header_fw_array) < (FW_HEAD_LENGTH+FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH))
+ {
+ GTP_ERROR("INVALID header_fw_array, check your gt9xx_firmware.h file!");
+ return FAIL;
+ }
+ update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_CREAT | O_RDWR, 0666);
+ if ((IS_ERR(update_msg.file)))
+ {
+ GTP_ERROR("Failed to Create file: %s for fw_header!", UPDATE_FILE_PATH_2);
+ return FAIL;
+ }
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ update_msg.file->f_op->write(update_msg.file, (char *)header_fw_array, sizeof(header_fw_array), &update_msg.file->f_pos);
+ filp_close(update_msg.file, NULL);
+ update_msg.file = filp_open(UPDATE_FILE_PATH_2, O_RDONLY, 0);
+#else
+ u8 fp_len = max(sizeof(UPDATE_FILE_PATH_1), sizeof(UPDATE_FILE_PATH_2));
+ u8 cfp_len = max(sizeof(CONFIG_FILE_PATH_1), sizeof(CONFIG_FILE_PATH_2));
+ u8 *search_update_path = (u8*)kzalloc(fp_len, GFP_KERNEL);
+ u8 *search_cfg_path = (u8*)kzalloc(cfp_len, GFP_KERNEL);
+ //Begin to search update file,the config file & firmware file must be in the same path,single or double.
+ searching_file = 1;
+ for (i = 0; i < GUP_SEARCH_FILE_TIMES; i++)
+ {
+ if (searching_file == 0)
+ {
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+ GTP_INFO(".bin/.cfg update file search forcely terminated!");
+ return FAIL;
+ }
+ if(i%2)
+ {
+ memcpy(search_update_path, UPDATE_FILE_PATH_1, sizeof(UPDATE_FILE_PATH_1));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_1, sizeof(CONFIG_FILE_PATH_1));
+ }
+ else
+ {
+ memcpy(search_update_path, UPDATE_FILE_PATH_2, sizeof(UPDATE_FILE_PATH_2));
+ memcpy(search_cfg_path, CONFIG_FILE_PATH_2, sizeof(CONFIG_FILE_PATH_2));
+ }
+
+ if(!(got_file_flag&0x0F))
+ {
+ update_msg.file = filp_open(search_update_path, O_RDONLY, 0);
+ if(!IS_ERR(update_msg.file))
+ {
+ GTP_DEBUG("Find the bin file");
+ got_file_flag |= 0x0F;
+ }
+ }
+ if(!(got_file_flag&0xF0))
+ {
+ update_msg.cfg_file = filp_open(search_cfg_path, O_RDONLY, 0);
+ if(!IS_ERR(update_msg.cfg_file))
+ {
+ GTP_DEBUG("Find the cfg file");
+ got_file_flag |= 0xF0;
+ }
+ }
+
+ if(got_file_flag)
+ {
+ if(got_file_flag == 0xFF)
+ {
+ break;
+ }
+ else
+ {
+ i += 4;
+ }
+ }
+ GTP_DEBUG("%3d:Searching %s %s file...", i, (got_file_flag&0x0F)?"":"bin", (got_file_flag&0xF0)?"":"cfg");
+ msleep(3000);
+ }
+ searching_file = 0;
+ kfree(search_update_path);
+ kfree(search_cfg_path);
+
+ if(!got_file_flag)
+ {
+ GTP_ERROR("Can't find update file.");
+ goto load_failed;
+ }
+
+ if(got_file_flag&0xF0)
+ {
+ GTP_DEBUG("Got the update config file.");
+ ret = gup_update_config(client);
+ if(ret <= 0)
+ {
+ GTP_ERROR("Update config failed.");
+ }
+ filp_close(update_msg.cfg_file, NULL);
+ msleep(500); //waiting config to be stored in FLASH.
+ }
+ if(got_file_flag&0x0F)
+ {
+ GTP_DEBUG("Got the update firmware file.");
+ }
+ else
+ {
+ GTP_ERROR("No need to upgrade firmware.");
+ goto load_failed;
+ }
+#endif
+ }
+
+ update_msg.old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ update_msg.file->f_op->llseek(update_msg.file, 0, SEEK_SET);
+ //update_msg.file->f_pos = 0;
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, FW_HEAD_LENGTH, &update_msg.file->f_pos);
+ if (ret < 0)
+ {
+ GTP_ERROR("Read firmware head in update file error.");
+ goto load_failed;
+ }
+ memcpy(fw_head, buf, FW_HEAD_LENGTH);
+
+ //check firmware legality
+ fw_checksum = 0;
+ for(i=0; i<FW_SECTION_LENGTH*4+FW_DSP_ISP_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH; i+=2)
+ {
+ u16 temp;
+ ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, 2, &update_msg.file->f_pos);
+ if (ret < 0)
+ {
+ GTP_ERROR("Read firmware file error.");
+ goto load_failed;
+ }
+ //GTP_DEBUG("BUF[0]:%x", buf[0]);
+ temp = (buf[0]<<8) + buf[1];
+ fw_checksum += temp;
+ }
+
+ GTP_DEBUG("firmware checksum:%x", fw_checksum&0xFFFF);
+ if(fw_checksum&0xFFFF)
+ {
+ GTP_ERROR("Illegal firmware file.");
+ goto load_failed;
+ }
+
+ return SUCCESS;
+
+load_failed:
+ set_fs(update_msg.old_fs);
+ return FAIL;
+}
+
+#if 0
+static u8 gup_check_update_header(struct i2c_client *client, st_fw_head* fw_head)
+{
+ const u8* pos;
+ int i = 0;
+ u8 mask_num = 0;
+ s32 ret = 0;
+
+ pos = HEADER_UPDATE_DATA;
+
+ memcpy(fw_head, pos, FW_HEAD_LENGTH);
+ pos += FW_HEAD_LENGTH;
+
+ ret = gup_enter_update_judge(fw_head);
+ if(SUCCESS == ret)
+ {
+ return SUCCESS;
+ }
+ return FAIL;
+}
+#endif
+
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, u16 start_addr, u16 total_length)
+{
+ s32 ret = 0;
+ u16 burn_addr = start_addr;
+ u16 frame_length = 0;
+ u16 burn_length = 0;
+ u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 retry = 0;
+
+ GTP_DEBUG("Begin burn %dk data to addr 0x%x", (total_length/1024), start_addr);
+ while(burn_length < total_length)
+ {
+ GTP_DEBUG("B/T:%04d/%04d", burn_length, total_length);
+ frame_length = ((total_length - burn_length) > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
+ wr_buf[0] = (u8)(burn_addr>>8);
+ rd_buf[0] = wr_buf[0];
+ wr_buf[1] = (u8)burn_addr;
+ rd_buf[1] = wr_buf[1];
+ memcpy(&wr_buf[GTP_ADDR_LENGTH], &burn_buf[burn_length], frame_length);
+
+ for(retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++)
+ {
+ ret = gup_i2c_write(client, wr_buf, GTP_ADDR_LENGTH + frame_length);
+ if(ret <= 0)
+ {
+ GTP_ERROR("Write frame data i2c error.");
+ continue;
+ }
+ ret = gup_i2c_read(client, rd_buf, GTP_ADDR_LENGTH + frame_length);
+ if(ret <= 0)
+ {
+ GTP_ERROR("Read back frame data i2c error.");
+ continue;
+ }
+
+ if(memcmp(&wr_buf[GTP_ADDR_LENGTH], &rd_buf[GTP_ADDR_LENGTH], frame_length))
+ {
+ GTP_ERROR("Check frame data fail,not equal.");
+ GTP_DEBUG("write array:");
+ GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], frame_length);
+ GTP_DEBUG("read array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+ continue;
+ }
+ else
+ {
+ //GTP_DEBUG("Check frame data success.");
+ break;
+ }
+ }
+ if(retry >= MAX_FRAME_CHECK_TIME)
+ {
+ GTP_ERROR("Burn frame data time out,exit.");
+ return FAIL;
+ }
+ burn_length += frame_length;
+ burn_addr += frame_length;
+ }
+ return SUCCESS;
+}
+
+static u8 gup_load_section_file(u8* buf, u16 offset, u16 length)
+{
+ s32 ret = 0;
+
+ if(update_msg.file == NULL)
+ {
+ GTP_ERROR("cannot find update file,load section file fail.");
+ return FAIL;
+ }
+ update_msg.file->f_pos = FW_HEAD_LENGTH + offset;
+
+ ret = update_msg.file->f_op->read(update_msg.file, (char*)buf, length, &update_msg.file->f_pos);
+ if(ret < 0)
+ {
+ GTP_ERROR("Read update file fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_recall_check(struct i2c_client *client, u8* chk_src, u16 start_rd_addr, u16 chk_length)
+{
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ s32 ret = 0;
+ u16 recall_addr = start_rd_addr;
+ u16 recall_length = 0;
+ u16 frame_length = 0;
+
+ while(recall_length < chk_length)
+ {
+ frame_length = ((chk_length - recall_length) > PACK_SIZE) ? PACK_SIZE : (chk_length - recall_length);
+ ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+ if(ret <= 0)
+ {
+ GTP_ERROR("recall i2c error,exit");
+ return FAIL;
+ }
+
+ if(memcmp(&rd_buf[GTP_ADDR_LENGTH], &chk_src[recall_length], frame_length))
+ {
+ GTP_ERROR("Recall frame data fail,not equal.");
+ GTP_DEBUG("chk_src array:");
+ GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+ GTP_DEBUG("recall array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+ return FAIL;
+ }
+
+ recall_length += frame_length;
+ recall_addr += frame_length;
+ }
+ GTP_DEBUG("Recall check %dk firmware success.", (chk_length/1024));
+
+ return SUCCESS;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u8 bank_cmd )
+{
+ s32 ret = 0;
+ u8 rd_buf[5];
+
+ //step1:hold ss51 & dsp
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]hold ss51 & dsp fail.");
+ return FAIL;
+ }
+
+ //step2:set scramble
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]set scramble fail.");
+ return FAIL;
+ }
+
+ //step3:select bank
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ //step4:enable accessing code
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ //step5:burn 8k fw section
+ ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_section]burn fw_section fail.");
+ return FAIL;
+ }
+
+ //step6:hold ss51 & release dsp
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]hold ss51 & release dsp fail.");
+ return FAIL;
+ }
+ //must delay
+ msleep(1);
+
+ //step7:send burn cmd to move data to flash from sram
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]send burn cmd fail.");
+ return FAIL;
+ }
+ GTP_DEBUG("[burn_fw_section]Wait for the burn is complete......");
+ do{
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]Get burn state fail");
+ return FAIL;
+ }
+ msleep(10);
+ //GTP_DEBUG("[burn_fw_section]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+ }while(rd_buf[GTP_ADDR_LENGTH]);
+
+ //step8:select bank
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]select bank %d fail.", (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ //step9:enable accessing code
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ //step10:recall 8k fw section
+ ret = gup_recall_check(client, fw_section, start_addr, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_section]recall check 8k firmware fail.");
+ return FAIL;
+ }
+
+ //step11:disable accessing code
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_section]disable accessing code fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_burn_dsp_isp(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8* fw_dsp_isp = NULL;
+ u8 retry = 0;
+
+ GTP_DEBUG("[burn_dsp_isp]Begin burn dsp isp---->>");
+
+ //step1:alloc memory
+ GTP_DEBUG("[burn_dsp_isp]step1:alloc memory");
+ while(retry++ < 5)
+ {
+ fw_dsp_isp = (u8*)kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+ if(fw_dsp_isp == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ GTP_INFO("[burn_dsp_isp]Alloc %dk byte memory success.", (FW_DSP_ISP_LENGTH/1024));
+ break;
+ }
+ }
+ if(retry >= 5)
+ {
+ GTP_ERROR("[burn_dsp_isp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ //step2:load dsp isp file data
+ GTP_DEBUG("[burn_dsp_isp]step2:load dsp isp file data");
+ ret = gup_load_section_file(fw_dsp_isp, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH+FW_BOOT_LENGTH), FW_DSP_ISP_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_dsp_isp]load firmware dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ //step3:disable wdt,clear cache enable
+ GTP_DEBUG("[burn_dsp_isp]step3:disable wdt,clear cache enable");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]disable wdt fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]clear cache enable fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step4:hold ss51 & dsp
+ GTP_DEBUG("[burn_dsp_isp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step5:set boot from sram
+ GTP_DEBUG("[burn_dsp_isp]step5:set boot from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]set boot from sram fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step6:software reboot
+ GTP_DEBUG("[burn_dsp_isp]step6:software reboot");
+ ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]software reboot fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step7:select bank2
+ GTP_DEBUG("[burn_dsp_isp]step7:select bank2");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]select bank2 fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step8:enable accessing code
+ GTP_DEBUG("[burn_dsp_isp]step8:enable accessing code");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]enable accessing code fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ //step9:burn 4k dsp_isp
+ GTP_DEBUG("[burn_dsp_isp]step9:burn 4k dsp_isp");
+ ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_dsp_isp]burn dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ //step10:set scramble
+ GTP_DEBUG("[burn_dsp_isp]step10:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_dsp_isp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = SUCCESS;
+
+exit_burn_dsp_isp:
+ kfree(fw_dsp_isp);
+ return ret;
+}
+
+static u8 gup_burn_fw_ss51(struct i2c_client *client)
+{
+ u8* fw_ss51 = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+
+ GTP_DEBUG("[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+ //step1:alloc memory
+ GTP_DEBUG("[burn_fw_ss51]step1:alloc memory");
+ while(retry++ < 5)
+ {
+ fw_ss51 = (u8*)kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if(fw_ss51 == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ GTP_INFO("[burn_fw_ss51]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if(retry >= 5)
+ {
+ GTP_ERROR("[burn_fw_ss51]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ //step2:load ss51 firmware section 1 file data
+ GTP_DEBUG("[burn_fw_ss51]step2:load ss51 firmware section 1 file data");
+ ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step3:clear control flag
+ GTP_DEBUG("[burn_fw_ss51]step3:clear control flag");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_ss51]clear control flag fail.");
+ ret = FAIL;
+ goto exit_burn_fw_ss51;
+ }
+
+ //step4:burn ss51 firmware section 1
+ GTP_DEBUG("[burn_fw_ss51]step4:burn ss51 firmware section 1");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step5:load ss51 firmware section 2 file data
+ GTP_DEBUG("[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+ ret = gup_load_section_file(fw_ss51, FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step6:burn ss51 firmware section 2
+ GTP_DEBUG("[burn_fw_ss51]step6:burn ss51 firmware section 2");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step7:load ss51 firmware section 3 file data
+ GTP_DEBUG("[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+ ret = gup_load_section_file(fw_ss51, 2*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step8:burn ss51 firmware section 3
+ GTP_DEBUG("[burn_fw_ss51]step8:burn ss51 firmware section 3");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step9:load ss51 firmware section 4 file data
+ GTP_DEBUG("[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+ ret = gup_load_section_file(fw_ss51, 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]load ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ //step10:burn ss51 firmware section 4
+ GTP_DEBUG("[burn_fw_ss51]step10:burn ss51 firmware section 4");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ ret = SUCCESS;
+
+exit_burn_fw_ss51:
+ kfree(fw_ss51);
+ return ret;
+}
+
+static u8 gup_burn_fw_dsp(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8* fw_dsp = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_dsp]Begin burn dsp firmware---->>");
+ //step1:alloc memory
+ GTP_DEBUG("[burn_fw_dsp]step1:alloc memory");
+ while(retry++ < 5)
+ {
+ fw_dsp = (u8*)kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+ if(fw_dsp == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ GTP_INFO("[burn_fw_dsp]Alloc %dk byte memory success.", (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if(retry >= 5)
+ {
+ GTP_ERROR("[burn_fw_dsp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ //step2:load firmware dsp
+ GTP_DEBUG("[burn_fw_dsp]step2:load firmware dsp");
+ ret = gup_load_section_file(fw_dsp, 4*FW_SECTION_LENGTH, FW_DSP_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_dsp]load firmware dsp fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ //step3:select bank3
+ GTP_DEBUG("[burn_fw_dsp]step3:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ //step4:hold ss51 & dsp
+ GTP_DEBUG("[burn_fw_dsp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ //step5:set scramble
+ GTP_DEBUG("[burn_fw_dsp]step5:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ //step6:release ss51 & dsp
+ GTP_DEBUG("[burn_fw_dsp]step6:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+ //must delay
+ msleep(1);
+
+ //step7:burn 4k dsp firmware
+ GTP_DEBUG("[burn_fw_dsp]step7:burn 4k dsp firmware");
+ ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_dsp]burn fw_section fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ //step8:send burn cmd to move data to flash from sram
+ GTP_DEBUG("[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]send burn cmd fail.");
+ goto exit_burn_fw_dsp;
+ }
+ GTP_DEBUG("[burn_fw_dsp]Wait for the burn is complete......");
+ do{
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_dsp]Get burn state fail");
+ goto exit_burn_fw_dsp;
+ }
+ msleep(10);
+ //GTP_DEBUG("[burn_fw_dsp]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+ }while(rd_buf[GTP_ADDR_LENGTH]);
+
+ //step9:recall check 4k dsp firmware
+ GTP_DEBUG("[burn_fw_dsp]step9:recall check 4k dsp firmware");
+ ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_dsp]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ ret = SUCCESS;
+
+exit_burn_fw_dsp:
+ kfree(fw_dsp);
+ return ret;
+}
+
+static u8 gup_burn_fw_boot(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8* fw_boot = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ GTP_DEBUG("[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+ //step1:Alloc memory
+ GTP_DEBUG("[burn_fw_boot]step1:Alloc memory");
+ while(retry++ < 5)
+ {
+ fw_boot = (u8*)kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+ if(fw_boot == NULL)
+ {
+ continue;
+ }
+ else
+ {
+ GTP_INFO("[burn_fw_boot]Alloc %dk byte memory success.", (FW_BOOT_LENGTH/1024));
+ break;
+ }
+ }
+ if(retry >= 5)
+ {
+ GTP_ERROR("[burn_fw_boot]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ //step2:load firmware bootloader
+ GTP_DEBUG("[burn_fw_boot]step2:load firmware bootloader");
+ ret = gup_load_section_file(fw_boot, (4*FW_SECTION_LENGTH+FW_DSP_LENGTH), FW_BOOT_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_boot]load firmware dsp fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ //step3:hold ss51 & dsp
+ GTP_DEBUG("[burn_fw_boot]step3:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ //step4:set scramble
+ GTP_DEBUG("[burn_fw_boot]step4:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ //step5:release ss51 & dsp
+ GTP_DEBUG("[burn_fw_boot]step5:release ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); //20121211
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+ //must delay
+ msleep(1);
+
+ //step6:select bank3
+ GTP_DEBUG("[burn_fw_boot]step6:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ //step7:burn 2k bootloader firmware
+ GTP_DEBUG("[burn_fw_boot]step7:burn 2k bootloader firmware");
+ ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_boot]burn fw_section fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ //step7:send burn cmd to move data to flash from sram
+ GTP_DEBUG("[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]send burn cmd fail.");
+ goto exit_burn_fw_boot;
+ }
+ GTP_DEBUG("[burn_fw_boot]Wait for the burn is complete......");
+ do{
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]Get burn state fail");
+ goto exit_burn_fw_boot;
+ }
+ msleep(10);
+ //GTP_DEBUG("[burn_fw_boot]Get burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+ }while(rd_buf[GTP_ADDR_LENGTH]);
+
+ //step8:recall check 2k bootloader firmware
+ GTP_DEBUG("[burn_fw_boot]step8:recall check 2k bootloader firmware");
+ ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[burn_fw_boot]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ //step9:enable download DSP code
+ GTP_DEBUG("[burn_fw_boot]step9:enable download DSP code ");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]enable download DSP code fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ //step10:release ss51 & hold dsp
+ GTP_DEBUG("[burn_fw_boot]step10:release ss51 & hold dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+ if(ret <= 0)
+ {
+ GTP_ERROR("[burn_fw_boot]release ss51 & hold dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ ret = SUCCESS;
+
+exit_burn_fw_boot:
+ kfree(fw_boot);
+ return ret;
+}
+
+s32 gup_update_proc(void *dir)
+{
+ s32 ret = 0;
+ u8 retry = 0;
+ st_fw_head fw_head;
+ struct goodix_ts_data *ts = NULL;
+
+ GTP_DEBUG("[update_proc]Begin update ......");
+
+ show_len = 1;
+ total_len = 100;
+ if(dir == NULL)
+ {
+ msleep(3000); //wait main thread to be completed
+ }
+
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ if (searching_file)
+ {
+ searching_file = 0; // exit .bin update file searching
+ GTP_INFO("Exiting searching .bin update file...");
+ while ((show_len != 200) && (show_len != 100)) // wait for auto update quitted completely
+ {
+ msleep(100);
+ }
+ }
+
+ update_msg.file = NULL;
+ ret = gup_check_update_file(i2c_connect_client, &fw_head, (u8*)dir); //20121211
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]check update file fail.");
+ goto file_fail;
+ }
+
+ //gtp_reset_guitar(i2c_connect_client, 20);
+ ret = gup_get_ic_fw_msg(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]get ic message fail.");
+ goto file_fail;
+ }
+
+ ret = gup_enter_update_judge(&fw_head);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]Check *.bin file fail.");
+ goto file_fail;
+ }
+
+ ts->enter_update = 1;
+ gtp_irq_disable(ts);
+#if GTP_ESD_PROTECT
+ gtp_esd_switch(ts->client, SWITCH_OFF);
+#endif
+ ret = gup_enter_update_mode(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]enter update mode fail.");
+ goto update_fail;
+ }
+
+ while(retry++ < 5)
+ {
+ show_len = 10;
+ total_len = 100;
+ ret = gup_burn_dsp_isp(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]burn dsp isp fail.");
+ continue;
+ }
+
+ show_len += 10;
+ ret = gup_burn_fw_ss51(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]burn ss51 firmware fail.");
+ continue;
+ }
+
+ show_len += 40;
+ ret = gup_burn_fw_dsp(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]burn dsp firmware fail.");
+ continue;
+ }
+
+ show_len += 20;
+ ret = gup_burn_fw_boot(i2c_connect_client);
+ if(FAIL == ret)
+ {
+ GTP_ERROR("[update_proc]burn bootloader firmware fail.");
+ continue;
+ }
+ show_len += 10;
+ GTP_INFO("[update_proc]UPDATE SUCCESS.");
+ break;
+ }
+ if(retry >= 5)
+ {
+ GTP_ERROR("[update_proc]retry timeout,UPDATE FAIL.");
+ goto update_fail;
+ }
+
+ GTP_DEBUG("[update_proc]leave update mode.");
+ gup_leave_update_mode();
+
+ msleep(100);
+// GTP_DEBUG("[update_proc]send config.");
+// ret = gtp_send_cfg(i2c_connect_client);
+// if(ret < 0)
+// {
+// GTP_ERROR("[update_proc]send config fail.");
+// }
+ if (ts->fw_error)
+ {
+ GTP_INFO("firmware error auto update, resent config!");
+ gup_init_panel(ts);
+ }
+ show_len = 100;
+ total_len = 100;
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
+#if GTP_ESD_PROTECT
+ gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+ filp_close(update_msg.file, NULL);
+ return SUCCESS;
+
+update_fail:
+ ts->enter_update = 0;
+ gtp_irq_enable(ts);
+
+#if GTP_ESD_PROTECT
+ gtp_esd_switch(ts->client, SWITCH_ON);
+#endif
+
+file_fail:
+ if(update_msg.file && !IS_ERR(update_msg.file))
+ {
+ filp_close(update_msg.file, NULL);
+ }
+ show_len = 200;
+ total_len = 100;
+ return FAIL;
+}
+
+#if GTP_AUTO_UPDATE
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+ struct task_struct *thread = NULL;
+
+ GTP_INFO("Ready to run update thread.");
+ thread = kthread_run(gup_update_proc, (void*)NULL, "guitar_update");
+ if (IS_ERR(thread))
+ {
+ GTP_ERROR("Failed to create update thread.\n");
+ return -1;
+ }
+
+ return 0;
+}
+#endif
\ No newline at end of file
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index b896f65..a1453ae 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -372,7 +372,9 @@
* @torch_enable - enable flash LED torch mode
* @flash_reg_get - flash regulator attached or not
* @flash_on - flash status, on or off
+ * @torch_on - torch status, on or off
* @flash_boost_reg - boost regulator for flash
+ * @torch_boost_reg - boost regulator for torch
*/
struct flash_config_data {
u8 current_prgm;
@@ -389,7 +391,9 @@
bool torch_enable;
bool flash_reg_get;
bool flash_on;
+ bool torch_on;
struct regulator *flash_boost_reg;
+ struct regulator *torch_boost_reg;
};
/**
@@ -733,9 +737,40 @@
return 0;
}
-static int qpnp_flash_set(struct qpnp_led_data *led)
+static int qpnp_torch_regulator_operate(struct qpnp_led_data *led, bool on)
{
int rc;
+
+ if (!on)
+ goto regulator_turn_off;
+
+ if (!led->flash_cfg->torch_on) {
+ rc = regulator_enable(led->flash_cfg->torch_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Regulator enable failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->torch_on = true;
+ }
+ return 0;
+
+regulator_turn_off:
+ if (led->flash_cfg->torch_on) {
+ rc = regulator_disable(led->flash_cfg->torch_boost_reg);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Regulator disable failed(%d)\n", rc);
+ return rc;
+ }
+ led->flash_cfg->torch_on = false;
+ }
+ return 0;
+}
+
+static int qpnp_flash_set(struct qpnp_led_data *led)
+{
+ int rc, error;
int val = led->cdev.brightness;
if (led->flash_cfg->torch_enable)
@@ -753,13 +788,21 @@
/* Set led current */
if (val > 0) {
if (led->flash_cfg->torch_enable) {
+ rc = qpnp_torch_regulator_operate(led, true);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led,
FLASH_LED_UNLOCK_SECURE(led->base),
FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -768,7 +811,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Torch reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -778,7 +821,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -789,7 +832,7 @@
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_torch_set;
}
qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base),
@@ -799,16 +842,16 @@
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ FLASH_ENABLE_MASK, FLASH_ENABLE_MODULE);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
} else {
rc = qpnp_flash_regulator_operate(led, true);
@@ -816,7 +859,7 @@
dev_err(&led->spmi_dev->dev,
"Flash regulator operate failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set flash safety timer */
@@ -828,7 +871,7 @@
dev_err(&led->spmi_dev->dev,
"Safety timer reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set max current */
@@ -839,7 +882,7 @@
dev_err(&led->spmi_dev->dev,
"Max current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Set clamp current */
@@ -851,7 +894,7 @@
dev_err(&led->spmi_dev->dev,
"Clamp current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
/* Write 0x80 to MODULE_ENABLE before writing 0xE0
@@ -864,7 +907,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -874,7 +917,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Current reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -885,7 +928,7 @@
dev_err(&led->spmi_dev->dev,
"2nd Current reg write failed(%d)\n",
rc);
- return rc;
+ goto error_flash_set;
}
rc = qpnp_led_masked_write(led,
@@ -894,7 +937,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
- return rc;
+ goto error_flash_set;
}
}
@@ -906,7 +949,10 @@
dev_err(&led->spmi_dev->dev,
"LED %d strobe reg write failed(%d)\n",
led->id, rc);
- return rc;
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
}
} else {
rc = qpnp_led_masked_write(led,
@@ -916,10 +962,38 @@
dev_err(&led->spmi_dev->dev,
"LED %d strobe reg write failed(%d)\n",
led->id, rc);
- return rc;
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
}
}
} else {
+ rc = qpnp_led_masked_write(led,
+ FLASH_LED_STROBE_CTRL(led->base),
+ FLASH_STROBE_MASK,
+ FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "LED %d flash write failed(%d)\n", led->id, rc);
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
+ }
+
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MASK,
+ FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ if (led->flash_cfg->torch_enable)
+ goto error_torch_set;
+ else
+ goto error_flash_set;
+ }
+
if (led->flash_cfg->torch_enable) {
rc = qpnp_led_masked_write(led,
FLASH_LED_UNLOCK_SECURE(led->base),
@@ -927,7 +1001,7 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Secure reg write failed(%d)\n", rc);
- return rc;
+ goto error_torch_set;
}
rc = qpnp_led_masked_write(led,
@@ -937,40 +1011,48 @@
if (rc) {
dev_err(&led->spmi_dev->dev,
"Torch reg write failed(%d)\n", rc);
+ goto error_torch_set;
+ }
+
+ rc = qpnp_torch_regulator_operate(led, false);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n",
+ rc);
return rc;
}
- }
-
- rc = qpnp_led_masked_write(led,
- FLASH_LED_STROBE_CTRL(led->base),
- FLASH_STROBE_MASK,
- FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "LED %d flash write failed(%d)\n", led->id, rc);
- return rc;
- }
-
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MASK,
- FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
-
- rc = qpnp_flash_regulator_operate(led, false);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Flash regulator operate failed(%d)\n", rc);
- return rc;
+ } else {
+ rc = qpnp_flash_regulator_operate(led, false);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n",
+ rc);
+ return rc;
+ }
}
}
qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs));
return 0;
+
+error_torch_set:
+ error = qpnp_torch_regulator_operate(led, false);
+ if (error) {
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator operate failed(%d)\n", rc);
+ return error;
+ }
+ return rc;
+
+error_flash_set:
+ error = qpnp_flash_regulator_operate(led, false);
+ if (error) {
+ dev_err(&led->spmi_dev->dev,
+ "Flash regulator operate failed(%d)\n", rc);
+ return error;
+ }
+ return rc;
}
static int qpnp_kpdbl_set(struct qpnp_led_data *led)
@@ -1997,6 +2079,18 @@
return rc;
}
+ /* Disable flash LED module */
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
+ if (led->flash_cfg->torch_enable)
+ return 0;
+
/* Set headroom */
rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base),
FLASH_HEADROOM_MASK, led->flash_cfg->headroom);
@@ -2056,15 +2150,6 @@
return rc;
}
- /* Disable flash LED module */
- rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
- if (rc) {
- dev_err(&led->spmi_dev->dev,
- "Enable reg write failed(%d)\n", rc);
- return rc;
- }
-
led->flash_cfg->strobe_type = 0;
/* dump flash registers */
@@ -2393,7 +2478,7 @@
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
"Regulator get failed(%d)\n", rc);
- return rc;
+ goto error_get_flash_reg;
}
led->flash_cfg->flash_reg_get = true;
*reg_set = true;
@@ -2412,7 +2497,7 @@
rc = PTR_ERR(led->flash_cfg->flash_boost_reg);
dev_err(&led->spmi_dev->dev,
"Regulator get failed(%d)\n", rc);
- return rc;
+ goto error_get_flash_reg;
}
led->flash_cfg->flash_reg_get = true;
*reg_set = true;
@@ -2426,16 +2511,32 @@
led->flash_cfg->torch_enable =
of_property_read_bool(node, "qcom,torch-enable");
+ if (led->flash_cfg->torch_enable) {
+ led->flash_cfg->torch_boost_reg =
+ regulator_get(&led->spmi_dev->dev, "torch_boost");
+ if (IS_ERR(led->flash_cfg->torch_boost_reg)) {
+ rc = PTR_ERR(led->flash_cfg->torch_boost_reg);
+ dev_err(&led->spmi_dev->dev,
+ "Torch regulator get failed(%d)\n", rc);
+ goto error_get_torch_reg;
+ }
+ }
+
rc = of_property_read_u32(node, "qcom,current", &val);
if (!rc) {
- if (led->flash_cfg->torch_enable)
+ if (led->flash_cfg->torch_enable) {
led->flash_cfg->current_prgm = (val *
TORCH_MAX_LEVEL / led->max_current);
+ return 0;
+ }
else
led->flash_cfg->current_prgm = (val *
FLASH_MAX_LEVEL / led->max_current);
} else
- return -EINVAL;
+ if (led->flash_cfg->torch_enable)
+ goto error_get_torch_reg;
+ else
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,headroom", &val);
if (!rc)
@@ -2443,7 +2544,7 @@
else if (rc == -EINVAL)
led->flash_cfg->headroom = HEADROOM_500mV;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,duration", &val);
if (!rc)
@@ -2451,7 +2552,7 @@
else if (rc == -EINVAL)
led->flash_cfg->duration = FLASH_DURATION_200ms;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,clamp-curr", &val);
if (!rc)
@@ -2460,7 +2561,7 @@
else if (rc == -EINVAL)
led->flash_cfg->clamp_curr = FLASH_CLAMP_200mA;
else
- return rc;
+ goto error_get_flash_reg;
rc = of_property_read_u32(node, "qcom,startup-dly", &val);
if (!rc)
@@ -2468,12 +2569,20 @@
else if (rc == -EINVAL)
led->flash_cfg->startup_dly = DELAY_128us;
else
- return rc;
+ goto error_get_flash_reg;
led->flash_cfg->safety_timer =
of_property_read_bool(node, "qcom,safety-timer");
return 0;
+
+error_get_torch_reg:
+ regulator_put(led->flash_cfg->torch_boost_reg);
+
+error_get_flash_reg:
+ regulator_put(led->flash_cfg->flash_boost_reg);
+ return rc;
+
}
static int __devinit qpnp_get_config_pwm(struct pwm_config_data *pwm_cfg,
@@ -3065,6 +3174,9 @@
if (led_array[i].flash_cfg->flash_reg_get)
regulator_put(led_array[i].flash_cfg-> \
flash_boost_reg);
+ if (led_array[i].flash_cfg->torch_enable)
+ regulator_put(led_array[i].flash_cfg->\
+ torch_boost_reg);
sysfs_remove_group(&led_array[i].cdev.dev->kobj,
&led_attr_group);
break;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index c70e151..0313161 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -353,6 +353,7 @@
set_fmt_fail:
kzfree(sp->vb2_q.drv_priv);
+ sp->vb2_q.drv_priv = NULL;
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index aa6f034..2ea4388 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -501,7 +501,8 @@
(int) buf_cmd.vaddr, buf_cmd.y_len);
buf_p->y_buffer_addr = msm_jpeg_platform_v2p(pgmn_dev, buf_cmd.fd,
- buf_cmd.y_len + buf_cmd.cbcr_len + buf_cmd.pln2_len,
+ buf_cmd.y_len + buf_cmd.cbcr_len +
+ buf_cmd.pln2_len + buf_cmd.offset,
&buf_p->file, &buf_p->handle, pgmn_dev->domain_num) +
buf_cmd.offset + buf_cmd.y_off;
buf_p->y_len = buf_cmd.y_len;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index 4fa3085..7f4f231 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -292,7 +292,7 @@
static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *c_ctrl)
{
- uint32_t rc = 0;
+ int32_t rc = 0;
uint32_t val = 0;
int32_t read_words = 0, exp_words = 0;
int32_t index = 0, first_byte = 0;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
index ac697fb..c713c85 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_flash.h
@@ -19,7 +19,7 @@
#include <media/msm_cam_sensor.h>
#include "msm_sd.h"
-#define MAX_LED_TRIGGERS 2
+#define MAX_LED_TRIGGERS 3
struct msm_led_flash_ctrl_t;
@@ -38,10 +38,14 @@
struct msm_sd_subdev msm_sd;
struct platform_device *pdev;
struct msm_flash_fn_t *func_tbl;
- const char *led_trigger_name[MAX_LED_TRIGGERS];
- struct led_trigger *led_trigger[MAX_LED_TRIGGERS];
- uint32_t op_current[MAX_LED_TRIGGERS];
+ const char *flash_trigger_name[MAX_LED_TRIGGERS];
+ struct led_trigger *flash_trigger[MAX_LED_TRIGGERS];
+ uint32_t flash_op_current[MAX_LED_TRIGGERS];
+ const char *torch_trigger_name;
+ struct led_trigger *torch_trigger;
+ uint32_t torch_op_current;
void *data;
+ uint32_t num_sources;
};
int32_t msm_led_flash_create_v4lsubdev(struct platform_device *pdev,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
index c6f1f72..1b0ec44 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_led_trigger.c
@@ -46,29 +46,45 @@
{
int rc = 0;
struct msm_camera_led_cfg_t *cfg = (struct msm_camera_led_cfg_t *)data;
+ uint32_t i;
CDBG("called led_state %d\n", cfg->cfgtype);
- if (!fctrl->led_trigger[0]) {
+ if (!fctrl) {
pr_err("failed\n");
return -EINVAL;
}
+
switch (cfg->cfgtype) {
case MSM_CAMERA_LED_OFF:
- led_trigger_event(fctrl->led_trigger[0], 0);
+ for (i = 0; i < fctrl->num_sources; i++)
+ if (fctrl->flash_trigger[i])
+ led_trigger_event(fctrl->flash_trigger[i], 0);
+ if (fctrl->torch_trigger)
+ led_trigger_event(fctrl->torch_trigger, 0);
break;
case MSM_CAMERA_LED_LOW:
- led_trigger_event(fctrl->led_trigger[0],
- fctrl->op_current[0] / 2);
+ if (fctrl->torch_trigger)
+ led_trigger_event(fctrl->torch_trigger,
+ fctrl->torch_op_current);
break;
case MSM_CAMERA_LED_HIGH:
- led_trigger_event(fctrl->led_trigger[0], fctrl->op_current[0]);
+ if (fctrl->torch_trigger)
+ led_trigger_event(fctrl->torch_trigger, 0);
+ for (i = 0; i < fctrl->num_sources; i++)
+ if (fctrl->flash_trigger[i])
+ led_trigger_event(fctrl->flash_trigger[i],
+ fctrl->flash_op_current[i]);
break;
case MSM_CAMERA_LED_INIT:
case MSM_CAMERA_LED_RELEASE:
- led_trigger_event(fctrl->led_trigger[0], 0);
+ for (i = 0; i < fctrl->num_sources; i++)
+ if (fctrl->flash_trigger[i])
+ led_trigger_event(fctrl->flash_trigger[i], 0);
+ if (fctrl->torch_trigger)
+ led_trigger_event(fctrl->torch_trigger, 0);
break;
default:
@@ -109,6 +125,7 @@
}
fctrl.pdev = pdev;
+ fctrl.num_sources = 0;
rc = of_property_read_u32(of_node, "cell-index", &pdev->id);
if (rc < 0) {
@@ -124,6 +141,7 @@
pr_err("failed\n");
return -EINVAL;
}
+ fctrl.num_sources = count;
for (i = 0; i < count; i++) {
flash_src_node = of_parse_phandle(of_node,
"qcom,flash-source", i);
@@ -134,17 +152,18 @@
rc = of_property_read_string(flash_src_node,
"linux,default-trigger",
- &fctrl.led_trigger_name[i]);
+ &fctrl.flash_trigger_name[i]);
if (rc < 0) {
pr_err("failed\n");
of_node_put(flash_src_node);
continue;
}
- CDBG("default trigger %s\n", fctrl.led_trigger_name[i]);
+ CDBG("default trigger %s\n",
+ fctrl.flash_trigger_name[i]);
rc = of_property_read_u32(flash_src_node,
- "qcom,current", &fctrl.op_current[i]);
+ "qcom,current", &fctrl.flash_op_current[i]);
if (rc < 0) {
pr_err("failed rc %d\n", rc);
of_node_put(flash_src_node);
@@ -153,10 +172,41 @@
of_node_put(flash_src_node);
- CDBG("max_current[%d] %d\n", i, fctrl.op_current[i]);
+ CDBG("max_current[%d] %d\n",
+ i, fctrl.flash_op_current[i]);
- led_trigger_register_simple(fctrl.led_trigger_name[i],
- &fctrl.led_trigger[i]);
+ led_trigger_register_simple(fctrl.flash_trigger_name[i],
+ &fctrl.flash_trigger[i]);
+ }
+
+ /* Torch source */
+ flash_src_node = of_parse_phandle(of_node, "qcom,torch-source",
+ 0);
+ if (flash_src_node) {
+ rc = of_property_read_string(flash_src_node,
+ "linux,default-trigger",
+ &fctrl.torch_trigger_name);
+ if (rc < 0) {
+ pr_err("failed\n");
+ } else {
+ CDBG("default trigger %s\n",
+ fctrl.torch_trigger_name);
+
+ rc = of_property_read_u32(flash_src_node,
+ "qcom,current",
+ &fctrl.torch_op_current);
+ if (rc < 0) {
+ pr_err("failed rc %d\n", rc);
+ } else {
+ CDBG("torch max_current %d\n",
+ fctrl.torch_op_current);
+
+ led_trigger_register_simple(
+ fctrl.torch_trigger_name,
+ &fctrl.torch_trigger);
+ }
+ }
+ of_node_put(flash_src_node);
}
}
rc = msm_led_flash_create_v4lsubdev(pdev, &fctrl);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 7897068..cddca74 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -683,6 +683,18 @@
.qmenu = perf_level,
.step = 0,
},
+ {
+ .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
+ .name = "Intra Refresh CIR MBS",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 0,
+ .maximum = MAX_INTRA_REFRESH_MBS,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ .cluster = MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH,
+ }
};
#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls)
@@ -1641,8 +1653,8 @@
air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
- property_id =
- HAL_PARAM_VENC_INTRA_REFRESH;
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
intra_refresh.air_mbs = ctrl->val;
intra_refresh.mode = ir_mode->val;
intra_refresh.air_ref = air_ref->val;
@@ -1658,8 +1670,8 @@
air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS);
- property_id =
- HAL_PARAM_VENC_INTRA_REFRESH;
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
intra_refresh.air_ref = ctrl->val;
intra_refresh.air_mbs = air_mbs->val;
intra_refresh.mode = ir_mode->val;
@@ -1676,8 +1688,7 @@
air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
- property_id =
- HAL_PARAM_VENC_INTRA_REFRESH;
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
intra_refresh.cir_mbs = ctrl->val;
intra_refresh.air_mbs = air_mbs->val;
@@ -1687,6 +1698,22 @@
pdata = &intra_refresh;
break;
}
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: {
+ struct v4l2_ctrl *air_mbs, *air_ref;
+
+ air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS);
+ air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF);
+
+ property_id = HAL_PARAM_VENC_INTRA_REFRESH;
+
+ intra_refresh.cir_mbs = ctrl->val;
+ intra_refresh.air_mbs = air_mbs->val;
+ intra_refresh.air_ref = air_ref->val;
+ intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC;
+
+ pdata = &intra_refresh;
+ break;
+ }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
property_id =
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL;
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index b9eb8f9..de6f1d5 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -126,6 +126,11 @@
struct rds_grp_data rds_buf);
static void hci_ev_ert(struct iris_device *radio);
static int update_spur_table(struct iris_device *radio);
+static int initialise_recv(struct iris_device *radio);
+static int initialise_trans(struct iris_device *radio);
+static int is_enable_rx_possible(struct iris_device *radio);
+static int is_enable_tx_possible(struct iris_device *radio);
+
static struct v4l2_queryctrl iris_v4l2_queryctrl[] = {
{
.id = V4L2_CID_AUDIO_VOLUME,
@@ -1633,13 +1638,16 @@
__u8 status = *((__u8 *) skb->data);
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (status)
- return;
- if ((radio->mode != FM_CALIB) && (radio->mode != FM_OFF))
+ if ((radio->mode == FM_TURNING_OFF) && (status == 0)) {
iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
- radio->mode = FM_OFF;
-
- radio_hci_req_complete(hdev, status);
+ radio_hci_req_complete(hdev, status);
+ radio->mode = FM_OFF;
+ } else if (radio->mode == FM_CALIB) {
+ radio_hci_req_complete(hdev, status);
+ } else if ((radio->mode == FM_RECV) || (radio->mode == FM_TRANS)) {
+ iris_q_event(radio, IRIS_EVT_RADIO_DISABLED);
+ radio->mode = FM_OFF;
+ }
}
static void hci_cc_conf_rsp(struct radio_hci_dev *hdev, struct sk_buff *skb)
@@ -1673,11 +1681,18 @@
struct hci_fm_conf_rsp *rsp = (void *)skb->data;
struct iris_device *radio = video_get_drvdata(video_get_dev());
- if (rsp->status)
+ if (rsp->status) {
+ radio_hci_req_complete(hdev, rsp->status);
return;
- if (radio->mode != FM_CALIB)
- iris_q_event(radio, IRIS_EVT_RADIO_READY);
+ }
+ if (radio->mode == FM_RECV_TURNING_ON) {
+ radio->mode = FM_RECV;
+ iris_q_event(radio, IRIS_EVT_RADIO_READY);
+ } else if (radio->mode == FM_TRANS_TURNING_ON) {
+ radio->mode = FM_TRANS;
+ iris_q_event(radio, IRIS_EVT_RADIO_READY);
+ }
radio_hci_req_complete(hdev, rsp->status);
}
@@ -2695,7 +2710,9 @@
radio->fm_hdev);
if (retval < 0)
FMDERR("Disable Failed after calibration %d", retval);
- radio->mode = FM_TURNING_OFF;
+ else
+ radio->mode = FM_OFF;
+
return retval;
}
static int iris_vidioc_g_ctrl(struct file *file, void *priv,
@@ -3177,82 +3194,60 @@
case V4L2_CID_PRIVATE_IRIS_STATE:
switch (ctrl->value) {
case FM_RECV:
+ if (is_enable_rx_possible(radio) != 0)
+ return -EINVAL;
+ radio->mode = FM_RECV_TURNING_ON;
retval = hci_cmd(HCI_FM_ENABLE_RECV_CMD,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Error while enabling RECV FM"
" %d\n", retval);
+ radio->mode = FM_OFF;
return retval;
+ } else {
+ initialise_recv(radio);
}
- radio->mode = FM_RECV;
- radio->mute_mode.soft_mute = CTRL_ON;
- retval = hci_set_fm_mute_mode(
- &radio->mute_mode,
- radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Failed to enable Smute\n");
- return retval;
- }
- radio->stereo_mode.stereo_mode = CTRL_OFF;
- radio->stereo_mode.sig_blend = CTRL_ON;
- radio->stereo_mode.intf_blend = CTRL_ON;
- radio->stereo_mode.most_switch = CTRL_ON;
- retval = hci_set_fm_stereo_mode(
- &radio->stereo_mode,
- radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Failed to set stereo mode\n");
- return retval;
- }
- radio->event_mask = SIG_LEVEL_INTR |
- RDS_SYNC_INTR | AUDIO_CTRL_INTR;
- retval = hci_conf_event_mask(&radio->event_mask,
- radio->fm_hdev);
- if (retval < 0) {
- FMDERR("Enable Async events failed");
- return retval;
- }
- retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD,
- radio->fm_hdev);
- if (retval < 0)
- FMDERR("Failed to get the Recv Config\n");
break;
case FM_TRANS:
+ if (!is_enable_tx_possible(radio) != 0)
+ return -EINVAL;
+ radio->mode = FM_TRANS_TURNING_ON;
retval = hci_cmd(HCI_FM_ENABLE_TRANS_CMD,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Error while enabling TRANS FM"
" %d\n", retval);
+ radio->mode = FM_OFF;
return retval;
+ } else {
+ initialise_trans(radio);
}
- radio->mode = FM_TRANS;
- retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
- if (retval < 0)
- FMDERR("get frequency failed %d\n", retval);
break;
case FM_OFF:
radio->spur_table_size = 0;
switch (radio->mode) {
case FM_RECV:
+ radio->mode = FM_TURNING_OFF;
retval = hci_cmd(HCI_FM_DISABLE_RECV_CMD,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Err on disable recv FM"
" %d\n", retval);
+ radio->mode = FM_RECV;
return retval;
}
- radio->mode = FM_TURNING_OFF;
break;
case FM_TRANS:
+ radio->mode = FM_TURNING_OFF;
retval = hci_cmd(HCI_FM_DISABLE_TRANS_CMD,
radio->fm_hdev);
if (retval < 0) {
FMDERR("Err disabling trans FM"
" %d\n", retval);
+ radio->mode = FM_TRANS;
return retval;
}
- radio->mode = FM_TURNING_OFF;
break;
default:
retval = -EINVAL;
@@ -4132,6 +4127,73 @@
return 0;
}
+static int initialise_recv(struct iris_device *radio)
+{
+ int retval;
+
+ radio->mute_mode.soft_mute = CTRL_ON;
+ retval = hci_set_fm_mute_mode(&radio->mute_mode,
+ radio->fm_hdev);
+
+ if (retval < 0) {
+ FMDERR("Failed to enable Smute\n");
+ return retval;
+ }
+
+ radio->stereo_mode.stereo_mode = CTRL_OFF;
+ radio->stereo_mode.sig_blend = CTRL_ON;
+ radio->stereo_mode.intf_blend = CTRL_ON;
+ radio->stereo_mode.most_switch = CTRL_ON;
+ retval = hci_set_fm_stereo_mode(&radio->stereo_mode,
+ radio->fm_hdev);
+
+ if (retval < 0) {
+ FMDERR("Failed to set stereo mode\n");
+ return retval;
+ }
+
+ radio->event_mask = SIG_LEVEL_INTR | RDS_SYNC_INTR | AUDIO_CTRL_INTR;
+ retval = hci_conf_event_mask(&radio->event_mask, radio->fm_hdev);
+ if (retval < 0) {
+ FMDERR("Enable Async events failed");
+ return retval;
+ }
+
+ retval = hci_cmd(HCI_FM_GET_RECV_CONF_CMD, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("Failed to get the Recv Config\n");
+ return retval;
+}
+
+static int initialise_trans(struct iris_device *radio)
+{
+
+ int retval = hci_cmd(HCI_FM_GET_TX_CONFIG, radio->fm_hdev);
+ if (retval < 0)
+ FMDERR("get frequency failed %d\n", retval);
+
+ return retval;
+}
+
+static int is_enable_rx_possible(struct iris_device *radio)
+{
+ int retval = 1;
+
+ if (radio->mode == FM_OFF || radio->mode == FM_RECV)
+ retval = 0;
+
+ return retval;
+}
+
+static int is_enable_tx_possible(struct iris_device *radio)
+{
+ int retval = 1;
+
+ if (radio->mode == FM_OFF || radio->mode == FM_TRANS)
+ retval = 0;
+
+ return retval;
+}
static const struct v4l2_ioctl_ops iris_ioctl_ops = {
.vidioc_querycap = iris_vidioc_querycap,
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 3d0abce..1eebe61 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -470,7 +470,7 @@
found = wcd9xxx_check_codec_type(wcd9xxx, &version);
if (!found) {
ret = -ENODEV;
- goto err_irq;
+ goto err;
} else {
wcd9xxx->codec_type = found;
wcd9xxx->version = version;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b750602..0987b6b 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -890,8 +890,8 @@
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
- case QSEE_RPMB_PROVISION_KEY_COMMAND:
- case QSEE_RPMB_ERASE_COMMAND:
+ case QSEOS_RPMB_PROVISION_KEY_COMMAND:
+ case QSEOS_RPMB_ERASE_COMMAND:
if (__qseecom_process_rpmb_svc_cmd(data, &req,
&send_svc_ireq))
return -EINVAL;
diff --git a/drivers/net/ethernet/msm/msm_rmnet_bam.c b/drivers/net/ethernet/msm/msm_rmnet_bam.c
index 3f3d76a..44f86dd 100644
--- a/drivers/net/ethernet/msm/msm_rmnet_bam.c
+++ b/drivers/net/ethernet/msm/msm_rmnet_bam.c
@@ -62,8 +62,9 @@
#define DEVICE_ID_INVALID -1
-#define DEVICE_INACTIVE 0
+#define DEVICE_INACTIVE 2
#define DEVICE_ACTIVE 1
+#define DEVICE_UNINITIALIZED 0
#define HEADROOM_FOR_BAM 8 /* for mux header */
#define HEADROOM_FOR_QOS 8
@@ -394,7 +395,7 @@
DBG0("[%s] __rmnet_open()\n", dev->name);
- if (!p->device_up) {
+ if (p->device_up == DEVICE_UNINITIALIZED) {
r = msm_bam_dmux_open(p->ch_id, dev, bam_notify);
if (r < 0) {
@@ -436,7 +437,7 @@
struct rmnet_private *p = netdev_priv(dev);
int rc = 0;
- if (p->device_up) {
+ if (p->device_up == DEVICE_ACTIVE) {
/* do not close rmnet port once up, this causes
remote side to hang if tried to open again */
p->device_up = DEVICE_INACTIVE;
@@ -906,6 +907,7 @@
p->ch_id = n;
p->waiting_for_ul_skb = NULL;
p->in_reset = 0;
+ p->device_up = DEVICE_UNINITIALIZED;
spin_lock_init(&p->lock);
spin_lock_init(&p->tx_queue_lock);
#ifdef CONFIG_MSM_RMNET_DEBUG
@@ -971,6 +973,7 @@
p->ch_id = n+BAM_DMUX_DATA_REV_RMNET_0;
p->waiting_for_ul_skb = NULL;
p->in_reset = 0;
+ p->device_up = DEVICE_UNINITIALIZED;
spin_lock_init(&p->lock);
spin_lock_init(&p->tx_queue_lock);
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 657fc2f..1262306 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -81,9 +81,16 @@
#define PRONTO_PMU_SPARE_OFFSET 0x1088
-#define PRONTO_PMU_GDSCR_OFFSET 0x0024
-#define PRONTO_PMU_GDSCR_SW_COLLAPSE BIT(0)
-#define PRONTO_PMU_GDSCR_HW_CTRL BIT(1)
+#define PRONTO_PMU_COM_GDSCR_OFFSET 0x0024
+#define PRONTO_PMU_COM_GDSCR_SW_COLLAPSE BIT(0)
+#define PRONTO_PMU_COM_GDSCR_HW_CTRL BIT(1)
+
+#define PRONTO_PMU_WLAN_BCR_OFFSET 0x0050
+#define PRONTO_PMU_WLAN_BCR_BLK_ARES BIT(0)
+
+#define PRONTO_PMU_WLAN_GDSCR_OFFSET 0x0054
+#define PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE BIT(0)
+
#define PRONTO_PMU_CBCR_OFFSET 0x0008
#define PRONTO_PMU_CBCR_CLK_EN BIT(0)
@@ -118,6 +125,9 @@
#define MSM_PRONTO_PLL_BASE 0xfb21b1c0
#define PRONTO_PLL_STATUS_OFFSET 0x1c
+#define MSM_PRONTO_TXP_PHY_ABORT 0xfb080488
+#define MSM_PRONTO_BRDG_ERR_SRC 0xfb080fb0
+
#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
@@ -296,6 +306,8 @@
void __iomem *pronto_ccpu_base;
void __iomem *pronto_saw2_base;
void __iomem *pronto_pll_base;
+ void __iomem *wlan_tx_phy_aborts;
+ void __iomem *wlan_brdg_err_source;
void __iomem *fiq_reg;
int ssr_boot;
int nv_downloaded;
@@ -435,14 +447,14 @@
void wcnss_pronto_log_debug_regs(void)
{
void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
- u32 reg = 0;
+ u32 reg = 0, reg2 = 0;
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: PRONTO_PMU_SPARE %08x\n", __func__, reg);
- reg_addr = penv->msm_wcnss_base + PRONTO_PMU_GDSCR_OFFSET;
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
reg >>= 31;
@@ -451,7 +463,8 @@
__func__);
return;
}
- reg &= ~(PRONTO_PMU_GDSCR_SW_COLLAPSE | PRONTO_PMU_GDSCR_HW_CTRL);
+ reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
+ | PRONTO_PMU_COM_GDSCR_HW_CTRL);
writel_relaxed(reg, reg_addr);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CBCR_OFFSET;
@@ -557,6 +570,26 @@
reg = readl_relaxed(tst_addr);
pr_info_ratelimited("%s: CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_GDSCR_OFFSET;
+ reg2 = readl_relaxed(reg_addr);
+
+ if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
+ (reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE)) {
+ pr_info_ratelimited("%s: Cannot log, wlan domain is power collapsed\n",
+ __func__);
+ return;
+ }
+
+ reg = readl_relaxed(penv->wlan_tx_phy_aborts);
+ pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+
+ reg = readl_relaxed(penv->wlan_brdg_err_source);
+ pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -1716,6 +1749,21 @@
goto fail_ioremap6;
}
+ penv->wlan_tx_phy_aborts = ioremap(MSM_PRONTO_TXP_PHY_ABORT,
+ SZ_8);
+ if (!penv->wlan_tx_phy_aborts) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wlan TX PHY failed\n", __func__);
+ goto fail_ioremap7;
+ }
+ penv->wlan_brdg_err_source = ioremap(MSM_PRONTO_BRDG_ERR_SRC,
+ SZ_8);
+ if (!penv->wlan_brdg_err_source) {
+ ret = -ENOMEM;
+ pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
+ goto fail_ioremap8;
+ }
+
}
/* trigger initialization of the WCNSS */
@@ -1732,6 +1780,12 @@
fail_pil:
if (penv->riva_ccu_base)
iounmap(penv->riva_ccu_base);
+ if (penv->wlan_brdg_err_source)
+ iounmap(penv->wlan_brdg_err_source);
+fail_ioremap8:
+ if (penv->wlan_tx_phy_aborts)
+ iounmap(penv->wlan_tx_phy_aborts);
+fail_ioremap7:
if (penv->pronto_pll_base)
iounmap(penv->pronto_pll_base);
fail_ioremap6:
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index e832716..87c7c30 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -49,6 +49,7 @@
#define MAX_QCA_REG (116)
static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr);
struct qca199x_dev {
wait_queue_head_t read_wq;
@@ -167,6 +168,8 @@
count = MAX_BUFFER_SIZE;
mutex_lock(&qca199x_dev->read_mutex);
+ memset(tmp, 0, sizeof(tmp));
+ memset(len, 0, sizeof(len));
dmode = device_mode.handle_flavour;
/* FTM-RAW-I2C RD/WR MODE - Special Case */
if ((dmode == UNSOLICITED_FTM_RAW_MODE) ||
@@ -199,20 +202,25 @@
/* NORMAL NCI Behaviour */
/* Read the header */
ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
- if (ret != PAYLOAD_HEADER_LENGTH)
+ if (ret != PAYLOAD_HEADER_LENGTH) {
+ total = 0;
goto err;
+ }
length = len[PAYLOAD_HEADER_LENGTH - 1];
-
+ if (length == 0)
+ total = 0;
/** make sure full packet fits in the buffer **/
if ((length > 0) && ((length + PAYLOAD_HEADER_LENGTH) <= count)) {
/* Read the packet */
ret = i2c_master_recv(qca199x_dev->client, tmp, (length +
PAYLOAD_HEADER_LENGTH));
- if (ret < 0)
+ if (ret < 0) {
+ total = 0;
goto err;
+ }
total = (length + PAYLOAD_HEADER_LENGTH);
}
- mutex_unlock(&qca199x_dev->read_mutex);
+
if (total > 0) {
if ((total > count) || copy_to_user(buf, tmp, total)) {
dev_err(&qca199x_dev->client->dev,
@@ -221,6 +229,7 @@
total = -EFAULT;
}
}
+ mutex_unlock(&qca199x_dev->read_mutex);
err:
if (ret < 0)
mutex_unlock(&qca199x_dev->read_mutex);
@@ -375,6 +384,7 @@
goto err_req;
}
gpio_set_value(qca199x_dev->dis_gpio, 0);
+ msleep(20);
} else if (arg == 1) {
gpio_set_value(qca199x_dev->dis_gpio, 0);
r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
@@ -385,12 +395,20 @@
goto err_req;
}
gpio_set_value(qca199x_dev->dis_gpio, 1);
+ usleep(1000);
} else if (arg == 2) {
- msleep(20);
+ r = nfcc_initialise(qca199x_dev->client, 0xE);
+ if (r) {
+ dev_err(&qca199x_dev->client->dev,
+ "nfc-nci probe: request nfcc initialise failed\n");
+ goto err_req;
+ }
} else if (arg == 3) {
msleep(20);
} else if (arg == 4) {
+ mutex_lock(&qca199x_dev->read_mutex);
nfcc_wake(NFCC_WAKE, filp);
+ mutex_unlock(&qca199x_dev->read_mutex);
} else if (arg == 5) {
nfcc_wake(NFCC_SLEEP, filp);
} else {
@@ -568,7 +586,7 @@
return r;
}
-int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
+static int nfcc_initialise(struct i2c_client *client, unsigned short curr_addr)
{
int r = 0;
unsigned char raw_1p8_CONTROL_011[] = {0x11, XTAL_CLOCK};
@@ -764,9 +782,9 @@
dev_err(&client->dev, "dis gpio not provided\n");
goto err_irq;
}
- gpio_set_value(qca199x_dev->dis_gpio, 1);
+ gpio_set_value(platform_data->dis_gpio, 1);/* HPD */
msleep(20);
- gpio_set_value(qca199x_dev->dis_gpio, 0);
+ gpio_set_value(platform_data->dis_gpio, 0);/* ULPM */
nfc_clk = clk_get(&client->dev, "ref_clk");
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6ccfd29..4f10cf8 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -81,6 +81,7 @@
u32 d_type;
bool enhd_pipe;
+bool imem;
static void sps_device_de_init(void);
@@ -2430,13 +2431,16 @@
resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (resource) {
+ imem = true;
sps->pipemem_phys_base = resource->start;
sps->pipemem_size = resource_size(resource);
SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
sps->pipemem_phys_base,
sps->pipemem_size);
- } else
+ } else {
+ imem = false;
SPS_DBG("sps:No pipe memory on this target.\n");
+ }
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index faa1618..34a2001 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -109,7 +109,7 @@
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
int min_alloc_order = 8;
- if ((d_type == 0) || (d_type == 2)) {
+ if ((d_type == 0) || (d_type == 2) || imem) {
iomem_phys = pipemem_phys_base;
iomem_size = pipemem_size;
@@ -136,7 +136,7 @@
return -ENOMEM;
}
- if ((d_type == 0) || (d_type == 2)) {
+ if ((d_type == 0) || (d_type == 2) || imem) {
res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
if (res)
return res;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index f65fef7..353ece6 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -50,6 +50,7 @@
extern u32 d_type;
extern bool enhd_pipe;
+extern bool imem;
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 408681c..8bb4f90 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -162,6 +162,11 @@
struct work_struct finish_suspend_work;
};
+struct usb_bam_hsic_host_info {
+ struct device *dev;
+ bool in_lpm;
+};
+
static spinlock_t usb_bam_ipa_handshake_info_lock;
static struct usb_bam_ipa_handshake_info info;
static spinlock_t usb_bam_peer_handshake_info_lock;
@@ -169,8 +174,7 @@
static spinlock_t usb_bam_lock; /* Protect ctx and usb_bam_connections */
static struct usb_bam_pipe_connect *usb_bam_connections;
static struct usb_bam_ctx_type ctx;
-
-static struct device *hsic_host_dev;
+static struct usb_bam_hsic_host_info hsic_host_info;
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
@@ -184,15 +188,16 @@
pr_debug("%s: Getting hsic device %x\n", __func__,
(int)dev);
pm_runtime_get(dev);
- } else if (hsic_host_dev) {
+ } else if (hsic_host_info.dev) {
pr_debug("%s: Putting hsic device %x\n", __func__,
- (int)hsic_host_dev);
+ (int)hsic_host_info.dev);
/* Just free previous device*/
info.in_lpm[HSIC_BAM] = true;
- pm_runtime_put(hsic_host_dev);
+ pm_runtime_put(hsic_host_info.dev);
}
- hsic_host_dev = dev;
+ hsic_host_info.dev = dev;
+ hsic_host_info.in_lpm = false;
}
static int get_bam_type_from_core_name(const char *name)
@@ -847,18 +852,24 @@
return;
}
+/**
+ * usb_bam_resume_hsic_host: vote for hsic host core resume.
+ * In addition also resume all hsic pipes that are connected to
+ * the ipa peer bam.
+ *
+ * NOTE: This function should be called in a context that hold
+ * usb_bam_lock.
+ */
static void usb_bam_resume_hsic_host(void)
{
int i;
struct usb_bam_pipe_connect *pipe_iter;
- spin_lock(&usb_bam_lock);
-
/* Exit from "full suspend" in case of hsic host */
- if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+ if (hsic_host_info.dev && info.in_lpm[HSIC_BAM]) {
pr_debug("%s: Getting hsic device %x\n", __func__,
- (int)hsic_host_dev);
- pm_runtime_get(hsic_host_dev);
+ (int)hsic_host_info.dev);
+ pm_runtime_get(hsic_host_info.dev);
info.in_lpm[HSIC_BAM] = false;
for (i = 0; i < ctx.max_connections; i++) {
@@ -873,8 +884,6 @@
}
}
}
-
- spin_unlock(&usb_bam_lock);
}
static int cons_request_resource(enum usb_bam cur_bam)
@@ -905,16 +914,26 @@
break;
case HSIC_BAM:
+ /*
+ * Vote for hsic resume, however the core
+ * resume may not be completed yet or on the other hand
+ * hsic core might already be resumed, due to a vote
+ * by other driver, in this case we will just renew our
+ * vote here.
+ */
+ usb_bam_resume_hsic_host();
- usb_bam_resume_hsic_host();
+ /*
+ * Return sucess if there are pipes connected
+ * and hsic core is actually not in lpm.
+ * If in lpm, grant will occur on resume
+ * finish (see msm_bam_hsic_notify_on_resume)
+ */
+ if (ctx.pipes_enabled_per_bam[cur_bam] &&
+ !hsic_host_info.in_lpm) {
+ ret = 0;
+ }
- /*
- * Return sucess if there are pipes connected
- * and not in lpm
- */
- if (ctx.pipes_enabled_per_bam[cur_bam] &&
- !info.in_lpm[cur_bam])
- ret = 0;
break;
case SSUSB_BAM:
default:
@@ -926,6 +945,7 @@
if (ret == -EINPROGRESS)
pr_debug("%s: EINPROGRESS on cons_request", __func__);
+
return ret;
}
@@ -968,10 +988,10 @@
* Allow to go to lpm for now. Actual state will be checked
* in msm_bam_hsic_lpm_ok() just before going to lpm.
*/
- if (hsic_host_dev && !info.in_lpm[HSIC_BAM]) {
+ if (hsic_host_info.dev && !info.in_lpm[HSIC_BAM]) {
pr_debug("%s: Putting hsic device %x\n", __func__,
- (int)hsic_host_dev);
- pm_runtime_put(hsic_host_dev);
+ (int)hsic_host_info.dev);
+ pm_runtime_put(hsic_host_info.dev);
info.in_lpm[HSIC_BAM] = true;
}
}
@@ -1315,6 +1335,8 @@
void msm_bam_wait_for_hsic_prod_granted(void)
{
+ spin_lock(&usb_bam_lock);
+
ctx.is_bam_inactivity[HSIC_BAM] = false;
/* Get back to resume state including wakeup ipa */
@@ -1322,10 +1344,19 @@
/* Ensure getting the producer resource */
wait_for_prod_granted(HSIC_BAM);
+
+ spin_unlock(&usb_bam_lock);
}
void msm_bam_hsic_notify_on_resume(void)
{
+ spin_lock(&usb_bam_lock);
+
+ hsic_host_info.in_lpm = false;
+
+ /* HSIC resume completed. Notify CONS grant if CONS was requested */
+ notify_usb_connected(HSIC_BAM);
+
/*
* This function is called to notify the usb bam driver
* that the hsic core and hsic bam hw are fully resumed
@@ -1334,6 +1365,8 @@
*/
if (ctx.inactivity_timer_ms[HSIC_BAM])
usb_bam_set_inactivity_timer(HSIC_BAM);
+
+ spin_unlock(&usb_bam_lock);
}
bool msm_bam_hsic_lpm_ok(void)
@@ -1341,7 +1374,7 @@
int i;
struct usb_bam_pipe_connect *pipe_iter;
- if (hsic_host_dev) {
+ if (hsic_host_info.dev) {
pr_debug("%s: Starting hsic full suspend sequence\n",
__func__);
@@ -1363,7 +1396,7 @@
/* HSIC host will go now to lpm */
pr_debug("%s: vote for suspend hsic %x\n",
- __func__, (int)hsic_host_dev);
+ __func__, (int)hsic_host_info.dev);
for (i = 0; i < ctx.max_connections; i++) {
pipe_iter =
@@ -1379,6 +1412,8 @@
}
}
+ hsic_host_info.in_lpm = true;
+
spin_unlock(&usb_bam_lock);
return true;
}
@@ -1392,7 +1427,7 @@
info.cur_cons_state[HSIC_BAM],
info.cur_prod_state[HSIC_BAM],
info.in_lpm[HSIC_BAM]);
- pm_runtime_get(hsic_host_dev);
+ pm_runtime_get(hsic_host_info.dev);
info.in_lpm[HSIC_BAM] = false;
spin_unlock(&usb_bam_lock);
} else
@@ -1469,11 +1504,11 @@
sps_device_reset(ctx.h_bam[cur_bam]);
/* On re-connect assume out from lpm for HSIC BAM */
- if (cur_bam == HSIC_BAM && hsic_host_dev &&
+ if (cur_bam == HSIC_BAM && hsic_host_info.dev &&
info.in_lpm[HSIC_BAM]) {
pr_debug("%s: Getting hsic device %x\n",
- __func__, (int)hsic_host_dev);
- pm_runtime_get(hsic_host_dev);
+ __func__, (int)hsic_host_info.dev);
+ pm_runtime_get(hsic_host_info.dev);
}
/* On re-connect assume out from lpm for all BAMs */
@@ -1583,8 +1618,10 @@
* until we complete releasing the hsic consumer and producer
* resources against the ipa resource manager.
*/
+ spin_lock(&usb_bam_lock);
if (pipe_connect->bam_type == HSIC_BAM)
usb_bam_resume_hsic_host();
+ spin_unlock(&usb_bam_lock);
/* Notify about wakeup / activity of the bam */
if (event_info->callback)
@@ -1660,12 +1697,12 @@
* If consumer is up, we will wait to the release consumer
* notification.
*/
- if (hsic_host_dev &&
+ if (hsic_host_info.dev &&
info.cur_cons_state[HSIC_BAM] ==
IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
pr_debug("%s: Putting hsic device %x\n", __func__,
- (int)hsic_host_dev);
- pm_runtime_put(hsic_host_dev);
+ (int)hsic_host_info.dev);
+ pm_runtime_put(hsic_host_info.dev);
info.in_lpm[HSIC_BAM] = true;
}
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 0883312..7f77b75 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -102,6 +102,7 @@
#define BAT_IF_BTC_CTRL 0x49
#define USB_OCP_THR 0x52
#define USB_OCP_CLR 0x53
+#define BAT_IF_TEMP_STATUS 0x09
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -1442,7 +1443,7 @@
get_prop_batt_status(struct qpnp_chg_chip *chip)
{
int rc;
- u8 chgr_sts;
+ u8 chgr_sts, bat_if_sts;
if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
@@ -1455,9 +1456,15 @@
return POWER_SUPPLY_CHARGE_TYPE_NONE;
}
- if (chgr_sts & TRKL_CHG_ON_IRQ)
+ rc = qpnp_chg_read(chip, &bat_if_sts, INT_RT_STS(chip->bat_if_base), 1);
+ if (rc) {
+ pr_err("failed to read bat_if sts %d\n", rc);
+ return POWER_SUPPLY_CHARGE_TYPE_NONE;
+ }
+
+ if (chgr_sts & TRKL_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
- if (chgr_sts & FAST_CHG_ON_IRQ)
+ if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
return POWER_SUPPLY_STATUS_DISCHARGING;
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 43d17c2..b46bbaf 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,6 +25,14 @@
tristate "Android log driver"
default n
+config LOGCAT_SIZE
+ int "Adjust android log buffer sizes"
+ default 256
+ depends on ANDROID_LOGGER
+ help
+ Set logger buffer size. Enter a number greater than zero.
+ Any value less than 256 is recommended. Reduce value to save kernel static memory size.
+
config ANDROID_PERSISTENT_RAM
bool
depends on HAVE_MEMBLOCK
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index e1e886c..267a8ec 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -29,6 +29,10 @@
#include <asm/ioctls.h>
+#ifndef CONFIG_LOGCAT_SIZE
+#define CONFIG_LOGCAT_SIZE 256
+#endif
+
/*
* struct logger_log - represents a specific log, such as 'main' or 'radio'
*
@@ -728,10 +732,10 @@
.size = SIZE, \
};
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 64*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 64*1024)
+DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, CONFIG_LOGCAT_SIZE*1024)
+DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, CONFIG_LOGCAT_SIZE*1024)
static struct logger_log *get_log_from_minor(int minor)
{
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..8c3b291 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -37,7 +37,8 @@
#define MAX_RAILS 5
static struct msm_thermal_data msm_thermal_info;
-static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
+static uint32_t limited_max_freq = UINT_MAX;
+static uint32_t limited_min_freq;
static struct delayed_work check_temp_work;
static bool core_control_enabled;
static uint32_t cpus_offlined;
@@ -139,6 +140,25 @@
#define PSM_REG_MODE_FROM_ATTRIBS(attr) \
(container_of(attr, struct psm_rail, mode_attr));
+
+static int msm_thermal_cpufreq_callback(struct notifier_block *nfb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+
+ switch (event) {
+ case CPUFREQ_INCOMPATIBLE:
+ cpufreq_verify_within_limits(policy, limited_min_freq,
+ limited_max_freq);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block msm_thermal_cpufreq_notifier = {
+ .notifier_call = msm_thermal_cpufreq_callback,
+};
+
/* If freq table exists, then we can send freq request */
static int check_freq_table(void)
{
@@ -159,37 +179,26 @@
{
int cpu = 0;
int ret = 0;
- struct cpufreq_policy *policy = NULL;
if (!freq_table_get) {
ret = check_freq_table();
if (ret) {
- pr_err("%s:Fail to get freq table\n", __func__);
+ pr_err("%s:Fail to get freq table\n", KBUILD_MODNAME);
return ret;
}
}
/* If min is larger than allowed max */
- if (min != MSM_CPUFREQ_NO_LIMIT &&
- min > table[limit_idx_high].frequency)
- min = table[limit_idx_high].frequency;
+ min = min(min, table[limit_idx_high].frequency);
- for_each_possible_cpu(cpu) {
- ret = msm_cpufreq_set_freq_limits(cpu, min, limited_max_freq);
- if (ret) {
- pr_err("%s:Fail to set limits for cpu%d\n",
- __func__, cpu);
- return ret;
- }
+ limited_min_freq = min;
- if (cpu_online(cpu)) {
- policy = cpufreq_cpu_get(cpu);
- if (!policy)
- continue;
- cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_L);
- cpufreq_cpu_put(policy);
- }
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
return ret;
}
@@ -584,26 +593,19 @@
{
int ret = 0;
- ret = msm_cpufreq_set_freq_limits(cpu, MSM_CPUFREQ_NO_LIMIT, max_freq);
- if (ret)
- return ret;
-
- limited_max_freq = max_freq;
- if (max_freq != MSM_CPUFREQ_NO_LIMIT)
+ if (max_freq != UINT_MAX)
pr_info("%s: Limiting cpu%d max frequency to %d\n",
KBUILD_MODNAME, cpu, max_freq);
else
pr_info("%s: Max frequency reset for cpu%d\n",
KBUILD_MODNAME, cpu);
-
- if (cpu_online(cpu)) {
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (!policy)
- return ret;
- ret = cpufreq_driver_target(policy, policy->cur,
- CPUFREQ_RELATION_H);
- cpufreq_cpu_put(policy);
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
return ret;
}
@@ -764,7 +766,6 @@
static void __ref do_freq_control(long temp)
{
- int ret = 0;
int cpu = 0;
uint32_t max_freq = limited_max_freq;
@@ -784,7 +785,7 @@
limit_idx += msm_thermal_info.freq_step;
if (limit_idx >= limit_idx_high) {
limit_idx = limit_idx_high;
- max_freq = MSM_CPUFREQ_NO_LIMIT;
+ max_freq = UINT_MAX;
} else
max_freq = table[limit_idx].frequency;
}
@@ -792,17 +793,13 @@
if (max_freq == limited_max_freq)
return;
+ limited_max_freq = max_freq;
/* Update new limits */
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.freq_control_mask & BIT(cpu)))
continue;
- ret = update_cpu_max_freq(cpu, max_freq);
- if (ret)
- pr_debug(
- "%s: Unable to limit cpu%d max freq to %d\n",
- KBUILD_MODNAME, cpu, max_freq);
+ update_cpu_max_freq(cpu, max_freq);
}
-
}
static void __ref check_temp(struct work_struct *work)
@@ -909,12 +906,17 @@
cancel_delayed_work(&check_temp_work);
flush_scheduled_work();
- if (limited_max_freq == MSM_CPUFREQ_NO_LIMIT)
+ if (limited_max_freq == UINT_MAX)
return;
- for_each_possible_cpu(cpu) {
- update_cpu_max_freq(cpu, MSM_CPUFREQ_NO_LIMIT);
+ limited_max_freq = UINT_MAX;
+ get_online_cpus();
+ for_each_online_cpu(cpu) {
+ if (cpufreq_update_policy(cpu))
+ pr_info("%s: Unable to update policy for cpu:%d\n",
+ KBUILD_MODNAME, cpu);
}
+ put_online_cpus();
}
static int __ref set_enabled(const char *val, const struct kernel_param *kp)
@@ -926,7 +928,7 @@
disable_msm_thermal();
else
pr_info("%s: no action for enabled = %d\n",
- KBUILD_MODNAME, enabled);
+ KBUILD_MODNAME, enabled);
pr_info("%s: enabled = %d\n", KBUILD_MODNAME, enabled);
@@ -1190,6 +1192,11 @@
return -EINVAL;
enabled = 1;
+ ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier,
+ CPUFREQ_POLICY_NOTIFIER);
+ if (ret)
+ pr_err("%s: cannot register cpufreq notifier\n",
+ KBUILD_MODNAME);
if (num_possible_cpus() > 1)
core_control_enabled = 1;
INIT_DELAYED_WORK(&check_temp_work, check_temp);
@@ -1505,7 +1512,7 @@
key = "qcom,freq-req";
rails[i].freq_req = of_property_read_bool(child_node, key);
if (rails[i].freq_req)
- rails[i].min_level = MSM_CPUFREQ_NO_LIMIT;
+ rails[i].min_level = 0;
else {
key = "qcom,min-level";
ret = of_property_read_u32(child_node, key,
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index d1b911a..bccc504 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -626,6 +626,7 @@
struct usb_function *f)
{
struct diag_context *ctxt = func_to_diag(f);
+ unsigned long flags;
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
@@ -643,7 +644,9 @@
ctxt->ch->priv_usb = NULL;
list_del(&ctxt->list_item);
/* Free any pending USB requests from last session */
+ spin_lock_irqsave(&ctxt->lock, flags);
free_reqs(ctxt);
+ spin_unlock_irqrestore(&ctxt->lock, flags);
kfree(ctxt);
}
diff --git a/include/linux/stk3x1x.h b/include/linux/stk3x1x.h
index 33625bd..d9d2cf6 100644
--- a/include/linux/stk3x1x.h
+++ b/include/linux/stk3x1x.h
@@ -23,6 +23,7 @@
uint16_t ps_thd_l;
int int_pin;
uint32_t transmittance;
+ uint32_t int_flags;
};
#endif /* __STK3X1X_H__ */
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 419e055..d28a8c0 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -627,7 +627,9 @@
FM_TRANS,
FM_RESET,
FM_CALIB,
- FM_TURNING_OFF
+ FM_TURNING_OFF,
+ FM_RECV_TURNING_ON,
+ FM_TRANS_TURNING_ON,
};
enum emphasis_type {
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 0be6f11..b1dd350 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -266,6 +266,12 @@
quiet_cmd_dtc = DTC $@
cmd_dtc = $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 $(DTC_FLAGS) -d $(depfile) $<
+# cat
+# ---------------------------------------------------------------------------
+# Concatentate multiple files together
+quiet_cmd_cat = CAT $@
+cmd_cat = (cat $(filter-out FORCE,$^) > $@) || (rm -f $@; false)
+
# Bzip2
# ---------------------------------------------------------------------------
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 46b0a91..8844b21 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -1157,6 +1157,16 @@
"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
};
+/*
+ * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
+ * cause any issue to select the right input, but it eliminates that lineout
+ * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
+ * sequence for lineout.
+ */
+static const char * const rx_rdac4_text[] = {
+ "ZERO", "RX3", "RX2"
+};
+
static const struct soc_enum rx_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
@@ -1194,6 +1204,10 @@
SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
iir1_inp1_text);
+static const struct soc_enum rx_rdac4_enum =
+ SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
+ rx_rdac4_text);
+
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -1221,6 +1235,9 @@
static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+static const struct snd_kcontrol_new rx_dac4_mux =
+ SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+
static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1312,6 +1329,10 @@
SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
};
+static const struct snd_kcontrol_new spkr_switch[] = {
+ SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
+};
+
static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -1791,13 +1812,6 @@
return 0;
}
-static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
- return 0;
-}
-
static const struct snd_soc_dapm_route audio_map[] = {
{"RX_I2S_CLK", NULL, "CDC_CONN"},
{"I2S RX1", NULL, "RX_I2S_CLK"},
@@ -1837,11 +1851,15 @@
{"LINEOUT PA", NULL, "CP"},
{"LINEOUT PA", NULL, "LINEOUT DAC"},
+ {"LINEOUT DAC", NULL, "RDAC4 MUX"},
+
+ {"RDAC4 MUX", "RX2", "RX2 CHAIN"},
+ {"RDAC4 MUX", "RX3", "RX3 CHAIN"},
{"CP", NULL, "CP_REGULATOR"},
{"CP", NULL, "RX_BIAS"},
{"SPK PA", NULL, "SPK DAC"},
- {"SPK DAC", NULL, "RX3 CHAIN"},
+ {"SPK DAC", "Switch", "RX3 CHAIN"},
{"RX1 CHAIN", NULL, "RX1 CLK"},
{"RX2 CHAIN", NULL, "RX2 CLK"},
@@ -2270,6 +2288,9 @@
msm8x10_wcd_hphr_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
+ spkr_switch, ARRAY_SIZE(spkr_switch)),
+
/* Speaker */
SND_SOC_DAPM_OUTPUT("LINEOUT"),
SND_SOC_DAPM_OUTPUT("SPK_OUT"),
@@ -2289,10 +2310,6 @@
msm8x10_wcd_lineout_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
- msm8x10_wcd_spk_dac_event,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
-
SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -2340,6 +2357,8 @@
&rx1_mix2_inp1_mux),
SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
&rx2_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
+ &rx_dac4_mux),
SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
ON_DEMAND_MICBIAS, 0,
@@ -2512,6 +2531,8 @@
/* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
{MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
+ /* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
+ {MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
};
static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index ff190cd..af2c53e 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -4589,7 +4589,7 @@
struct wcd9xxx_mbhc *mbhc)
{
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
- 0x0C, 0x04);
+ 0x04, 0x04);
snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
}
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 6fc8e13..7820cd0 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -33,6 +33,7 @@
#include <linux/pm_runtime.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
+#include <linux/input.h>
#include "wcd9320.h"
#include "wcd9306.h"
#include "wcd9xxx-mbhc.h"
@@ -90,6 +91,22 @@
#define WCD9XXX_MEAS_DELTA_MAX_MV 50
#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
+
+/*
+ * Invalid voltage range for the detection
+ * of plug type with current source
+ */
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV 110
+#define WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV 265
+
+/*
+ * Threshold used to detect euro headset
+ * with current source
+ */
+#define WCD9XXX_CS_GM_SWAP_THRES_MIN_MV 10
+#define WCD9XXX_CS_GM_SWAP_THRES_MAX_MV 40
+
+#define WCD9XXX_MBHC_NSC_CS 9
#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
@@ -101,6 +118,11 @@
#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_DEFAULT 28
+#define WCD9XXX_V_CS_HS_MAX 500
+#define WCD9XXX_V_CS_NO_MIC 5
+#define WCD9XXX_MB_MEAS_DELTA_MAX_MV 80
+#define WCD9XXX_CS_MEAS_DELTA_MAX_MV 10
+
static bool detect_use_vddio_switch = true;
struct wcd9xxx_mbhc_detect {
@@ -110,6 +132,7 @@
bool swap_gnd;
bool vddio;
bool hwvalue;
+ bool mic_bias;
/* internal purpose from here */
bool _above_no_mic;
bool _below_v_hs_max;
@@ -969,7 +992,7 @@
}
static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
- u16 bias_value, s16 z)
+ u16 bias_value, s16 z, u32 micb_mv)
{
s16 value, mb;
s32 mv;
@@ -977,10 +1000,10 @@
value = bias_value;
if (dce) {
mb = (mbhc->mbhc_data.dce_mb);
- mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+ mv = (value - z) * (s32)micb_mv / (mb - z);
} else {
mb = (mbhc->mbhc_data.sta_mb);
- mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
+ mv = (value - z) * (s32)micb_mv / (mb - z);
}
return mv;
@@ -991,11 +1014,13 @@
{
s16 z;
z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
- return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
+ return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z,
+ mbhc->mbhc_data.micb_mv);
}
/* called only from interrupt which is under codec_resource_lock acquisition */
-static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
+static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc,
+ bool is_cs_enable)
{
struct snd_soc_codec *codec = mbhc->codec;
short bias_value;
@@ -1047,7 +1072,8 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
- wcd9xxx_calibrate_hs_polling(mbhc);
+ if (!is_cs_enable)
+ wcd9xxx_calibrate_hs_polling(mbhc);
/* don't flip override */
bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
@@ -1143,6 +1169,158 @@
return status;
}
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_cs_find_plug_type(struct wcd9xxx_mbhc *mbhc,
+ struct wcd9xxx_mbhc_detect *dt, const int size,
+ bool highhph,
+ unsigned long event_state)
+{
+ int i;
+ int vdce, mb_mv;
+ int ch, sz, delta_thr;
+ int minv = 0, maxv = INT_MIN;
+ struct wcd9xxx_mbhc_detect *d = dt;
+ struct wcd9xxx_mbhc_detect *dprev = d, *dmicbias = NULL, *dgnd = NULL;
+ enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+
+ const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
+ WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+ s16 hs_max, no_mic, dce_z;
+
+ pr_debug("%s: enter\n", __func__);
+ pr_debug("%s: event_state 0x%lx\n", __func__, event_state);
+
+ sz = size - 1;
+ for (i = 0, d = dt, ch = 0; i < sz; i++, d++) {
+ if (d->mic_bias) {
+ dce_z = mbhc->mbhc_data.dce_z;
+ mb_mv = mbhc->mbhc_data.micb_mv;
+ hs_max = plug_type->v_hs_max;
+ no_mic = plug_type->v_no_mic;
+ } else {
+ dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+ mb_mv = VDDIO_MICBIAS_MV;
+ hs_max = WCD9XXX_V_CS_HS_MAX;
+ no_mic = WCD9XXX_V_CS_NO_MIC;
+ }
+
+ vdce = __wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce,
+ dce_z, (u32)mb_mv);
+
+ d->_vdces = vdce;
+ if (d->_vdces < no_mic)
+ d->_type = PLUG_TYPE_HEADPHONE;
+ else if (d->_vdces >= hs_max)
+ d->_type = PLUG_TYPE_HIGH_HPH;
+ else
+ d->_type = PLUG_TYPE_HEADSET;
+
+ pr_debug("%s: DCE #%d, %04x, V %04d(%04d), HPHL %d TYPE %d\n",
+ __func__, i, d->dce, vdce, d->_vdces,
+ d->hphl_status & 0x01,
+ d->_type);
+
+ ch += d->hphl_status & 0x01;
+ if (!d->swap_gnd && !d->mic_bias) {
+ if (maxv < d->_vdces)
+ maxv = d->_vdces;
+ if (!minv || minv > d->_vdces)
+ minv = d->_vdces;
+ }
+ if ((!d->mic_bias &&
+ (d->_vdces >= WCD9XXX_CS_MEAS_INVALD_RANGE_LOW_MV &&
+ d->_vdces <= WCD9XXX_CS_MEAS_INVALD_RANGE_HIGH_MV)) ||
+ (d->mic_bias &&
+ (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+ d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV))) {
+ pr_debug("%s: within invalid range\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
+ }
+
+ if (event_state & (1 << MBHC_EVENT_PA_HPHL)) {
+ pr_debug("%s: HPHL PA was ON\n", __func__);
+ } else if (ch != sz && ch > 0) {
+ pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
+
+ delta_thr = highhph ? WCD9XXX_MB_MEAS_DELTA_MAX_MV :
+ WCD9XXX_CS_MEAS_DELTA_MAX_MV;
+
+ for (i = 0, d = dt; i < sz; i++, d++) {
+ if ((i > 0) && !d->mic_bias && !d->swap_gnd &&
+ (d->_type != dprev->_type)) {
+ pr_debug("%s: Invalid, inconsistent types\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
+
+ if (!d->swap_gnd && !d->mic_bias &&
+ (abs(minv - d->_vdces) > delta_thr ||
+ abs(maxv - d->_vdces) > delta_thr)) {
+ pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
+ __func__, d->_vdces, minv, maxv);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ } else if (d->swap_gnd) {
+ dgnd = d;
+ }
+
+ if (!d->mic_bias && !d->swap_gnd)
+ dprev = d;
+ else if (d->mic_bias)
+ dmicbias = d;
+ }
+ if (dgnd && dt->_type != PLUG_TYPE_HEADSET &&
+ dt->_type != dgnd->_type) {
+ pr_debug("%s: Invalid, inconsistent types\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ goto exit;
+ }
+
+ type = dt->_type;
+ if (dmicbias) {
+ if (dmicbias->_type == PLUG_TYPE_HEADSET &&
+ (dt->_type == PLUG_TYPE_HIGH_HPH ||
+ dt->_type == PLUG_TYPE_HEADSET)) {
+ type = PLUG_TYPE_HEADSET;
+ if (dt->_type == PLUG_TYPE_HIGH_HPH) {
+ pr_debug("%s: Headset with threshold on MIC detected\n",
+ __func__);
+ if (mbhc->mbhc_cfg->micbias_enable_flags &
+ (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
+ mbhc->micbias_enable = true;
+ }
+ }
+ }
+
+ if (!(event_state & (1UL << MBHC_EVENT_PA_HPHL))) {
+ if (((type == PLUG_TYPE_HEADSET ||
+ type == PLUG_TYPE_HEADPHONE) && ch != sz)) {
+ pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
+ __func__, type);
+ type = PLUG_TYPE_INVALID;
+ }
+ }
+ if (type == PLUG_TYPE_HEADSET && dgnd && !dgnd->mic_bias) {
+ if ((dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MIN_MV <
+ minv) &&
+ (dgnd->_vdces + WCD9XXX_CS_GM_SWAP_THRES_MAX_MV >
+ maxv))
+ type = PLUG_TYPE_GND_MIC_SWAP;
+ else if (dgnd->_type != PLUG_TYPE_HEADSET) {
+ pr_debug("%s: Invalid, inconsistent types\n", __func__);
+ type = PLUG_TYPE_INVALID;
+ }
+ }
+exit:
+ pr_debug("%s: Plug type %d detected\n", __func__, type);
+ return type;
+}
+
/*
* wcd9xxx_find_plug_type : Find out and return the best plug type with given
* list of wcd9xxx_mbhc_detect structure.
@@ -1328,6 +1506,112 @@
return 0;
}
+void wcd9xxx_turn_onoff_current_source(struct wcd9xxx_mbhc *mbhc, bool on,
+ bool highhph)
+{
+
+ struct snd_soc_codec *codec;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
+ const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
+ WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
+
+ btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+ codec = mbhc->codec;
+
+ if (on) {
+ pr_debug("%s: enabling current source\n", __func__);
+ /* Nsc to 9 */
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x78, 0x48);
+ /* pull down diode bit to 0 */
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+ 0x01, 0x00);
+ /*
+ * Keep the low power insertion/removal
+ * detection (reg 0x3DD) disabled
+ */
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL,
+ 0x01, 0x00);
+ /*
+ * Enable the Mic Bias current source
+ * Write bits[6:5] of register MICB_2_MBHC to 0x3 (V_20_UA)
+ * Write bit[7] of register MICB_2_MBHC to 1
+ * (INS_DET_ISRC_EN__ENABLE)
+ * MICB_2_MBHC__SCHT_TRIG_EN to 1
+ */
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+ 0xF0, 0xF0);
+ /* Disconnect MBHC Override from MicBias and LDOH */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x00);
+ } else {
+ pr_debug("%s: disabling current source\n", __func__);
+ /* Connect MBHC Override from MicBias and LDOH */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 0x10, 0x10);
+ /* INS_DET_ISRC_CTL to acdb value */
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
+ 0x60, plug_det->mic_current << 5);
+ if (!highhph) {
+ /* INS_DET_ISRC_EN__ENABLE to 0 */
+ snd_soc_update_bits(codec,
+ mbhc->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x00);
+ /* MICB_2_MBHC__SCHT_TRIG_EN to 0 */
+ snd_soc_update_bits(codec,
+ mbhc->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x00);
+ }
+ /* Nsc to acdb value */
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+ btn_det->mbhc_nsc << 3);
+ }
+}
+
+static enum wcd9xxx_mbhc_plug_type
+wcd9xxx_codec_cs_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
+{
+ struct snd_soc_codec *codec = mbhc->codec;
+ struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
+ enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
+ int i;
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+
+ BUG_ON(NUM_DCE_PLUG_INS_DETECT < 4);
+
+ rt[0].swap_gnd = false;
+ rt[0].vddio = false;
+ rt[0].hwvalue = true;
+ rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
+ rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, true);
+ rt[0].mic_bias = false;
+
+ for (i = 1; i < NUM_DCE_PLUG_INS_DETECT - 1; i++) {
+ rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 3);
+ rt[i].mic_bias = ((i == NUM_DCE_PLUG_INS_DETECT - 4) &&
+ highhph);
+ rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
+ if (rt[i].swap_gnd)
+ wcd9xxx_codec_hphr_gnd_switch(codec, true);
+
+ if (rt[i].mic_bias)
+ wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
+ rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, !highhph, true);
+ if (rt[i].mic_bias)
+ wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+ if (rt[i].swap_gnd)
+ wcd9xxx_codec_hphr_gnd_switch(codec, false);
+ }
+
+ type = wcd9xxx_cs_find_plug_type(mbhc, rt, ARRAY_SIZE(rt), highhph,
+ mbhc->event_state);
+
+ pr_debug("%s: plug_type:%d\n", __func__, type);
+
+ return type;
+}
+
static enum wcd9xxx_mbhc_plug_type
wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
{
@@ -1364,7 +1648,7 @@
(void) wcd9xxx_pull_down_micbias(mbhc,
WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
- rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
+ rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc, false);
rt[0].swap_gnd = false;
rt[0].vddio = false;
rt[0].hwvalue = true;
@@ -1634,14 +1918,23 @@
{
enum wcd9xxx_mbhc_plug_type plug_type;
struct snd_soc_codec *codec = mbhc->codec;
+ bool current_source_enable;
pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+ current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_INSERTION)) != 0);
- wcd9xxx_turn_onoff_override(codec, true);
- plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
- wcd9xxx_turn_onoff_override(codec, false);
+ if (current_source_enable) {
+ wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+ plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
+ wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+ } else {
+ wcd9xxx_turn_onoff_override(codec, true);
+ plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+ wcd9xxx_turn_onoff_override(codec, false);
+ }
if (wcd9xxx_swch_level_remove(mbhc)) {
pr_debug("%s: Switch level is low when determining plug\n",
@@ -1671,26 +1964,9 @@
/* called under codec_resource_lock acquisition */
static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
{
- struct snd_soc_codec *codec = mbhc->codec;
- const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
- WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
-
pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
- /*
- * Turn on the override,
- * wcd9xxx_mbhc_setup_hs_polling requires override on
- */
- wcd9xxx_turn_onoff_override(codec, true);
- if (plug_det->t_ins_complete > 20)
- msleep(plug_det->t_ins_complete);
- else
- usleep_range(plug_det->t_ins_complete * 1000,
- plug_det->t_ins_complete * 1000);
- /* Turn off the override */
- wcd9xxx_turn_onoff_override(codec, false);
-
if (wcd9xxx_swch_level_remove(mbhc))
pr_debug("%s: Switch level low when determining plug\n",
__func__);
@@ -1739,14 +2015,21 @@
}
}
-static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv)
+static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv,
+ bool cs_enable)
{
const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
- return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
- && (mic_mv < v_hs_max)) ? true : false;
+ if (cs_enable)
+ return ((mic_mv > WCD9XXX_V_CS_NO_MIC) &&
+ (mic_mv < WCD9XXX_V_CS_HS_MAX)) ? true : false;
+ else
+ return (!(mic_mv > WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
+ mic_mv < WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) &&
+ (mic_mv > plug_type->v_no_mic) &&
+ (mic_mv < v_hs_max)) ? true : false;
}
/*
@@ -1761,6 +2044,13 @@
s32 mic_mv[NUM_DCE_PLUG_DETECT];
short mb_v[NUM_DCE_PLUG_DETECT];
unsigned long retry = 0, timeout;
+ bool cs_enable;
+
+ cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+
+ if (cs_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, true, false);
timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
while (!(timedout = time_after(jiffies, timeout))) {
@@ -1780,11 +2070,28 @@
break;
}
- for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
- mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1, true);
- mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1 , mb_v[i]);
- pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
- __func__, retry, mic_mv[i], mb_v[i]);
+ if (cs_enable) {
+ for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = __wcd9xxx_codec_sta_dce(mbhc, 1,
+ true, true);
+ mic_mv[i] = __wcd9xxx_codec_sta_dce_v(mbhc,
+ true,
+ mb_v[i],
+ mbhc->mbhc_data.dce_nsc_cs_z,
+ (u32)VDDIO_MICBIAS_MV);
+ pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+ __func__, retry, mic_mv[i], mb_v[i]);
+ }
+ } else {
+ for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1,
+ true);
+ mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1,
+ mb_v[i]);
+ pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+ __func__, retry, mic_mv[i],
+ mb_v[i]);
+ }
}
if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -1799,7 +2106,7 @@
}
for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
- if (!is_valid_mic_voltage(mbhc, mic_mv[i]))
+ if (!is_valid_mic_voltage(mbhc, mic_mv[i], cs_enable))
break;
if (i == NUM_DCE_PLUG_DETECT) {
@@ -1810,6 +2117,9 @@
}
}
+ if (cs_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
if (timedout)
pr_debug("%s: Microphone did not settle in %d seconds\n",
__func__, HS_DETECT_PLUG_TIME_MS);
@@ -1828,12 +2138,15 @@
/* called only from interrupt which is under codec_resource_lock acquisition */
static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
{
- s16 dce;
+ s16 dce, dcez;
unsigned long timeout;
bool removed = true;
struct snd_soc_codec *codec = mbhc->codec;
const struct wcd9xxx_mbhc_general_cfg *generic =
WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
+ bool cs_enable;
+ s16 cur_v_ins_h;
+ u32 mb_mv;
pr_debug("%s: enter\n", __func__);
if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
@@ -1847,13 +2160,32 @@
usleep_range(generic->t_shutdown_plug_rem,
generic->t_shutdown_plug_rem);
+ cs_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_REMOVAL)) != 0);
+ if (cs_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, true, false);
+
timeout = jiffies + msecs_to_jiffies(FAKE_REMOVAL_MIN_PERIOD_MS);
do {
- dce = wcd9xxx_codec_sta_dce(mbhc, 1, true);
+ if (cs_enable) {
+ dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
+ dcez = mbhc->mbhc_data.dce_nsc_cs_z;
+ mb_mv = VDDIO_MICBIAS_MV;
+ } else {
+ dce = wcd9xxx_codec_sta_dce(mbhc, 1, true);
+ dcez = mbhc->mbhc_data.dce_z;
+ mb_mv = mbhc->mbhc_data.micb_mv;
+ }
+
pr_debug("%s: DCE 0x%x,%d\n", __func__, dce,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, dce));
- if (dce <
- wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
+ __wcd9xxx_codec_sta_dce_v(mbhc, true, dce,
+ dcez, mb_mv));
+
+ cur_v_ins_h = cs_enable ? (s16) mbhc->mbhc_data.v_cs_ins_h :
+ (wcd9xxx_get_current_v(mbhc,
+ WCD9XXX_CURRENT_V_INS_H));
+
+ if (dce < cur_v_ins_h) {
removed = false;
break;
}
@@ -1861,6 +2193,9 @@
pr_debug("%s: headset %sactually removed\n", __func__,
removed ? "" : "not ");
+ if (cs_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, false, false);
+
if (removed) {
if (mbhc->mbhc_cfg->detect_extn_cable) {
if (!wcd9xxx_swch_level_remove(mbhc)) {
@@ -2069,22 +2404,29 @@
}
static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
- enum meas_type dce, s16 vin_mv)
+ enum meas_type dce, s16 vin_mv,
+ bool cs_enable)
{
s16 diff, zero;
u32 mb_mv, in;
u16 value;
+ s16 dce_z;
mb_mv = mbhc->mbhc_data.micb_mv;
+ dce_z = mbhc->mbhc_data.dce_z;
if (mb_mv == 0) {
pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
return -EINVAL;
}
+ if (cs_enable) {
+ mb_mv = VDDIO_MICBIAS_MV;
+ dce_z = mbhc->mbhc_data.dce_nsc_cs_z;
+ }
if (dce) {
- diff = (mbhc->mbhc_data.dce_mb) - (mbhc->mbhc_data.dce_z);
- zero = (mbhc->mbhc_data.dce_z);
+ diff = (mbhc->mbhc_data.dce_mb) - (dce_z);
+ zero = (dce_z);
} else {
diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
zero = (mbhc->mbhc_data.sta_z);
@@ -2111,9 +2453,9 @@
plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max, false);
mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max, false);
mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
@@ -2122,9 +2464,9 @@
adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
true);
mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max, false);
mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max, false);
mbhc->mbhc_data.v_inval_ins_low =
scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
false);
@@ -2132,6 +2474,11 @@
scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
false);
}
+ mbhc->mbhc_data.v_cs_ins_h = wcd9xxx_codec_v_sta_dce(mbhc, DCE,
+ WCD9XXX_V_CS_HS_MAX,
+ true);
+ pr_debug("%s: v_ins_h for current source: 0x%x\n", __func__,
+ mbhc->mbhc_data.v_cs_ins_h);
btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
MBHC_BTN_DET_V_BTN_HIGH);
@@ -2146,13 +2493,17 @@
scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT],
+ false);
mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT],
+ false);
mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO],
+ false);
mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
- wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
+ wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO],
+ false);
mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
@@ -2162,7 +2513,7 @@
mbhc->mbhc_data.v_brl = BUTTON_MIN;
mbhc->mbhc_data.v_no_mic =
- wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic);
+ wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic, false);
pr_debug("%s: leave\n", __func__);
}
@@ -2176,6 +2527,16 @@
mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
}
+/*
+ * Mic Bias Enable Decision
+ * Return true if high_hph_cnt is a power of 2 (!= 2)
+ * otherwise return false
+ */
+static bool wcd9xxx_mbhc_enable_mb_decision(int high_hph_cnt)
+{
+ return (high_hph_cnt > 2) && !(high_hph_cnt & (high_hph_cnt - 1));
+}
+
static void wcd9xxx_correct_swch_plug(struct work_struct *work)
{
struct wcd9xxx_mbhc *mbhc;
@@ -2183,13 +2544,17 @@
enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
unsigned long timeout;
int retry = 0, pt_gnd_mic_swap_cnt = 0;
+ int highhph_cnt = 0;
bool correction = false;
- bool wrk_complete = true;
+ bool current_source_enable;
+ bool wrk_complete = true, highhph = false;
pr_debug("%s: enter\n", __func__);
mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
codec = mbhc->codec;
+ current_source_enable = ((mbhc->mbhc_cfg->cs_enable_flags &
+ (1 << MBHC_CS_ENABLE_POLLING)) != 0);
wcd9xxx_onoff_ext_mclk(mbhc, true);
@@ -2203,7 +2568,11 @@
* DAPM doesn't use any MBHC block as this work only runs with
* headphone detection.
*/
- wcd9xxx_turn_onoff_override(codec, true);
+ if (current_source_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, true,
+ false);
+ else
+ wcd9xxx_turn_onoff_override(codec, true);
timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
while (!time_after(jiffies, timeout)) {
@@ -2224,11 +2593,20 @@
/* can race with removal interrupt */
WCD9XXX_BCL_LOCK(mbhc->resmgr);
- plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
+ if (current_source_enable)
+ plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc,
+ highhph);
+ else
+ plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
__func__, retry, mbhc->current_plug, plug_type);
+
+ highhph_cnt = (plug_type == PLUG_TYPE_HIGH_HPH) ?
+ (highhph_cnt + 1) :
+ 0;
+ highhph = wcd9xxx_mbhc_enable_mb_decision(highhph_cnt);
if (plug_type == PLUG_TYPE_INVALID) {
pr_debug("Invalid plug in attempt # %d\n", retry);
if (!mbhc->mbhc_cfg->detect_extn_cable &&
@@ -2274,8 +2652,12 @@
pt_gnd_mic_swap_cnt = 0;
WCD9XXX_BCL_LOCK(mbhc->resmgr);
- /* Turn off override */
- wcd9xxx_turn_onoff_override(codec, false);
+ /* Turn off override/current source */
+ if (current_source_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, false,
+ false);
+ else
+ wcd9xxx_turn_onoff_override(codec, false);
/*
* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
*/
@@ -2288,15 +2670,19 @@
}
}
- if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ highhph = false;
+ if (wrk_complete && plug_type == PLUG_TYPE_HIGH_HPH) {
pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
__func__);
WCD9XXX_BCL_LOCK(mbhc->resmgr);
wcd9xxx_find_plug_and_report(mbhc, plug_type);
+ highhph = true;
WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
}
- /* Turn off override */
- if (!correction)
+
+ if (!correction && current_source_enable)
+ wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
+ else if (!correction)
wcd9xxx_turn_onoff_override(codec, false);
wcd9xxx_onoff_ext_mclk(mbhc, false);
@@ -2565,11 +2951,11 @@
pr_debug("%s: reprogram vb1hu/vbrh to %dmv\n", __func__, mv);
/* update LSB first so mbhc hardware block doesn't see too low value */
- v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv);
+ v_b1_hu = wcd9xxx_codec_v_sta_dce(mbhc, STA, mv, false);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
(v_b1_hu >> 8) & 0xFF);
- v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv);
+ v_brh = wcd9xxx_codec_v_sta_dce(mbhc, DCE, mv, false);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
(v_brh >> 8) & 0xFF);
@@ -2641,14 +3027,15 @@
pr_debug("%s: Button is released without resume",
__func__);
wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
- stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+ mbhc->mbhc_data.micb_mv);
if (vddio)
stamv_s = scale_v_micb_vddio(mbhc, stamv,
false);
else
stamv_s = stamv;
mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
- dce_z);
+ dce_z, mbhc->mbhc_data.micb_mv);
mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
false) : mv[0];
btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
@@ -2664,7 +3051,8 @@
wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
- stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z,
+ mbhc->mbhc_data.micb_mv);
if (vddio)
stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
else
@@ -2673,7 +3061,8 @@
sta & 0xFFFF, stamv, stamv_s);
/* determine pressed button */
- mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+ mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z,
+ mbhc->mbhc_data.micb_mv);
mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
@@ -2682,7 +3071,8 @@
btn = btnmeas[0];
for (meas = 1; (n_btn_meas && d->n_btn_meas &&
(meas < (d->n_btn_meas + 1))); meas++) {
- mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
+ mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z,
+ mbhc->mbhc_data.micb_mv);
mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
mv[meas];
btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
@@ -2924,7 +3314,7 @@
static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
{
u8 cfilt_mode;
- u16 reg0, reg1;
+ u16 reg0, reg1, reg2;
struct snd_soc_codec *codec = mbhc->codec;
pr_debug("%s: enter\n", __func__);
@@ -2987,10 +3377,26 @@
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
+
+ /* compute dce_z for current source */
+ reg2 = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL);
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
+ WCD9XXX_MBHC_NSC_CS << 3);
+
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
+ mbhc->mbhc_data.dce_nsc_cs_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true,
+ false);
+ pr_debug("%s: dce_z with nsc cs: 0x%x\n", __func__,
+ mbhc->mbhc_data.dce_nsc_cs_z);
+
+ snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, reg2);
+
/* STA measurement for 0 voltage */
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
+
/* Restore registers */
snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
@@ -4009,6 +4415,15 @@
return ret;
}
+ ret = snd_jack_set_key(mbhc->button_jack.jack,
+ SND_JACK_BTN_0,
+ KEY_MEDIA);
+ if (ret) {
+ pr_err("%s: Failed to set code for btn-0\n",
+ __func__);
+ return ret;
+ }
+
INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
wcd9xxx_mbhc_fw_read);
INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 0599ccb..88c911f 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -43,6 +43,7 @@
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
+ u16 dce_nsc_cs_z;
u16 dce_mb;
u16 sta_z;
u16 sta_mb;
@@ -59,6 +60,7 @@
u16 v_no_mic;
s16 v_inval_ins_low;
s16 v_inval_ins_high;
+ u16 v_cs_ins_h;
};
enum wcd9xxx_mbhc_plug_type {
@@ -83,6 +85,12 @@
MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
};
+enum wcd9xx_mbhc_cs_enable_bits {
+ MBHC_CS_ENABLE_POLLING,
+ MBHC_CS_ENABLE_INSERTION,
+ MBHC_CS_ENABLE_REMOVAL,
+};
+
enum wcd9xxx_mbhc_state {
MBHC_STATE_NONE = -1,
MBHC_STATE_POTENTIAL,
@@ -210,6 +218,7 @@
unsigned long micbias_enable_flags;
/* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
bool (*swap_gnd_mic) (struct snd_soc_codec *);
+ unsigned long cs_enable_flags;
};
struct wcd9xxx_cfilt_mode {
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index d3ba3d5..19d717e 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -83,6 +83,9 @@
.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
.insert_detect = true,
.swap_gnd_mic = NULL,
+ .cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+ 1 << MBHC_CS_ENABLE_INSERTION |
+ 1 << MBHC_CS_ENABLE_REMOVAL),
};
struct msm_auxpcm_gpio {
@@ -788,7 +791,7 @@
S(c[1], 124);
S(nc, 1);
S(n_meas, 5);
- S(mbhc_nsc, 11);
+ S(mbhc_nsc, 10);
S(n_btn_meas, 1);
S(n_btn_con, 2);
S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
@@ -1146,6 +1149,22 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA9,
},
+ {
+ .name = "VoLTE",
+ .stream_name = "VoLTE",
+ .cpu_dai_name = "VoLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_VOLTE,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index b28f0f49..769b8eb 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -133,6 +133,9 @@
.micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
.insert_detect = true,
.swap_gnd_mic = NULL,
+ .cs_enable_flags = (1 << MBHC_CS_ENABLE_POLLING |
+ 1 << MBHC_CS_ENABLE_INSERTION |
+ 1 << MBHC_CS_ENABLE_REMOVAL),
};
struct msm_auxpcm_gpio {
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 340d3db..9150751 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -180,6 +180,39 @@
return 0;
}
+static const char *const btsco_rate_text[] = {"8000", "16000"};
+static const struct soc_enum msm_btsco_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
+};
+
+static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_btsco_rate = %d", __func__, msm_btsco_rate);
+
+ ucontrol->value.integer.value[0] = msm_btsco_rate;
+ return 0;
+}
+
+static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 8000:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 16000:
+ msm_btsco_rate = BTSCO_RATE_16KHZ;
+ break;
+ default:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ }
+
+ pr_debug("%s: msm_btsco_rate = %d\n", __func__, msm_btsco_rate);
+ return 0;
+}
+
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -318,6 +351,11 @@
return ret;
}
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
@@ -334,6 +372,11 @@
snd_soc_dapm_enable_pin(dapm, "Lineout amp");
snd_soc_dapm_sync(dapm);
+ ret = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_jack_new(codec, "Headset Jack",
SND_JACK_HEADSET, &hs_jack);
if (ret) {
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 1685894..d9c1210 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -19,7 +19,6 @@
enum {
RX_CAL,
TX_CAL,
- AANC_TX_CAL,
MAX_AUDPROC_TYPES
};
diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
index 58ea36d..113d85f 100644
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.h
@@ -223,7 +223,7 @@
DOLBY_PARAM_VEN_LENGTH)
#define DOLBY_PARAM_INT_ENDP_LENGTH 1
-#define DOLBY_PARAM_PAYLOAD_SIZE 4
+#define DOLBY_PARAM_PAYLOAD_SIZE 3
#define DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM 329
#define DOLBY_NUM_ENDP_DEPENDENT_PARAMS 1
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index df0fa6a..b1f968d 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -35,6 +35,16 @@
#define INVALID_COPP_ID 0xFF
#define ADM_GET_PARAMETER_LENGTH 350
+
+enum {
+ ADM_RX_AUDPROC_CAL,
+ ADM_TX_AUDPROC_CAL,
+ ADM_RX_AUDVOL_CAL,
+ ADM_TX_AUDVOL_CAL,
+ ADM_CUSTOM_TOP_CAL,
+ ADM_MAX_CAL_TYPES
+};
+
struct adm_ctl {
void *apr;
atomic_t copp_id[AFE_MAX_PORTS];
@@ -48,10 +58,7 @@
struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
-/* 0 - (MAX_AUDPROC_TYPES -1): audproc handles */
-/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1): audvol handles */
-/* + 1 for custom ADM topology */
- atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
+ atomic_t mem_map_cal_handles[ADM_MAX_CAL_TYPES];
atomic_t mem_map_cal_index;
int set_custom_topology;
@@ -626,7 +633,7 @@
if (this_adm.set_custom_topology) {
/* specific index 4 for adm topology memory */
- atomic_set(&this_adm.mem_map_cal_index, 4);
+ atomic_set(&this_adm.mem_map_cal_index, ADM_CUSTOM_TOP_CAL);
/* Only call this once */
this_adm.set_custom_topology = 0;
@@ -656,7 +663,8 @@
adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
adm_top.payload_addr_lsw = cal_block.cal_paddr;
adm_top.payload_addr_msw = 0;
- adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+ adm_top.mem_map_handle =
+ atomic_read(&this_adm.mem_map_cal_handles[ADM_CUSTOM_TOP_CAL]);
adm_top.payload_size = cal_block.cal_size;
atomic_set(&this_adm.copp_stat[index], 0);
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 1810770..6dfe5b3 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -25,6 +25,14 @@
#include "audio_acdb.h"
+enum {
+ AFE_RX_CAL,
+ AFE_TX_CAL,
+ AFE_AANC_TX_CAL,
+ MAX_AFE_CAL_TYPES
+};
+
+
struct afe_ctl {
void *apr;
atomic_t state;
@@ -39,8 +47,8 @@
void *rx_private_data;
uint32_t mmap_handle;
- struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
- atomic_t mem_map_cal_handles[MAX_AUDPROC_TYPES];
+ struct acdb_cal_block afe_cal_addr[MAX_AFE_CAL_TYPES];
+ atomic_t mem_map_cal_handles[MAX_AFE_CAL_TYPES];
atomic_t mem_map_cal_index;
u16 dtmf_gen_rx_portid;
struct afe_spkr_prot_calib_get_resp calib_data;
@@ -94,7 +102,7 @@
pr_debug("q6afe: reset event = %d %d apr[%p]\n",
data->reset_event, data->reset_proc, this_afe.apr);
- for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+ for (i = 0; i < MAX_AFE_CAL_TYPES; i++) {
this_afe.afe_cal_addr[i].cal_paddr = 0;
this_afe.afe_cal_addr[i].cal_size = 0;
}
@@ -384,7 +392,7 @@
u32 handle;
pr_debug("%s: path %d\n", __func__, path);
- if (path == AANC_TX_CAL) {
+ if (path == AFE_AANC_TX_CAL) {
get_aanc_cal(&cal_block);
} else {
get_afe_cal(path, &cal_block);
@@ -600,10 +608,10 @@
if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX) {
afe_send_cal_spkr_prot_tx(port_id);
- afe_send_cal_block(TX_CAL, port_id);
+ afe_send_cal_block(AFE_TX_CAL, port_id);
} else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) {
afe_send_cal_spkr_prot_rx(port_id);
- afe_send_cal_block(RX_CAL, port_id);
+ afe_send_cal_block(AFE_RX_CAL, port_id);
}
}
@@ -1149,7 +1157,7 @@
__func__, ret);
goto fail_cmd;
}
- afe_send_cal_block(AANC_TX_CAL, tx_port_id);
+ afe_send_cal_block(AFE_AANC_TX_CAL, tx_port_id);
fail_cmd:
return ret;
diff --git a/sound/soc/msm/qdsp6v2/q6lsm.c b/sound/soc/msm/qdsp6v2/q6lsm.c
index c5483ee..aec048e 100644
--- a/sound/soc/msm/qdsp6v2/q6lsm.c
+++ b/sound/soc/msm/qdsp6v2/q6lsm.c
@@ -735,7 +735,7 @@
int rc = -EINVAL;
if (!client)
- goto fail;
+ return rc;
mutex_lock(&client->cmd_lock);
if (!client->sound_model.data) {
@@ -744,7 +744,6 @@
if (IS_ERR_OR_NULL(client->sound_model.client)) {
pr_err("%s: ION create client for AUDIO failed\n",
__func__);
- mutex_unlock(&client->cmd_lock);
goto fail;
}
client->sound_model.handle =
@@ -753,7 +752,6 @@
if (IS_ERR_OR_NULL(client->sound_model.handle)) {
pr_err("%s: ION memory allocation for AUDIO failed\n",
__func__);
- mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -764,7 +762,6 @@
if (rc) {
pr_err("%s: ION get physical mem failed, rc%d\n",
__func__, rc);
- mutex_unlock(&client->cmd_lock);
goto fail;
}
@@ -773,7 +770,6 @@
client->sound_model.handle);
if (IS_ERR_OR_NULL(client->sound_model.data)) {
pr_err("%s: ION memory mapping failed\n", __func__);
- mutex_unlock(&client->cmd_lock);
goto fail;
}
memset(client->sound_model.data, 0, len);
@@ -789,11 +785,13 @@
&client->sound_model.mem_map_handle);
if (rc < 0) {
pr_err("%s:CMD Memory_map_regions failed\n", __func__);
- goto fail;
+ goto exit;
}
return 0;
fail:
+ mutex_unlock(&client->cmd_lock);
+exit:
q6lsm_snd_model_buf_free(client);
return rc;
}