Merge "arm/dt: msm8974: add audio driver machine for APQ8074"
diff --git a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
index 439418d..04310ec 100644
--- a/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
+++ b/Documentation/devicetree/bindings/arm/msm/cpr-regulator.txt
@@ -12,9 +12,10 @@
Required properties:
- compatible: Must be "qcom,cpr-regulator"
-- reg: Register addresses for RBCPR and efuse
-- reg-names: Register names. Must be "rbcpr", "pvs_efuse"
- and "cpr_efuse"
+- reg: Register addresses for RBCPR, RBCPR clock
+ select, PVS eFuse and CPR eFuse
+- reg-names: Register names. Must be "rbcpr", "rbcpr_clk",
+ "pvs_efuse" and "cpr_efuse"
- regulator-name: A string used to describe the regulator
- interrupts: Interrupt line from RBCPR to interrupt controller.
- regulator-min-microvolt: Minimum corner value as min constraint, which
diff --git a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
index c1b79ae..6dac1b7 100644
--- a/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
+++ b/Documentation/devicetree/bindings/arm/msm/memory-reserve.txt
@@ -69,3 +69,20 @@
This region is assumed to be a part of a separate hole that has been removed
and this binding specifies the fixed location and size of the region within
that hole.
+
+
+Some drivers may only wish to reserve memory from the system. Reserved memory
+is still tracked internally by the Linux page allocator. The memory is reserved
+from the buddy allocator at bootup but may be freed back at a later point in
+time with memblock_free and free_bootmem_late.
+
+Required parameters:
+-qcom,memblock-reserve: base and size of block to be reserved. Drivers should
+call memblock_is_reserved before attempting to use the base address to ensure
+the memory was completely reserved.
+
+ qcom,a-driver {
+ compatible = "qcom,a-driver";
+ /* reserve a 4MB region @ 0x200000 for use later */
+ qcom,memblock-reserve = <0x200000 0x400000>;
+ };
diff --git a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
index ed45979..b3f1aef 100644
--- a/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
+++ b/Documentation/devicetree/bindings/iommu/msm_iommu_v1.txt
@@ -28,7 +28,10 @@
- compatible : "qcom,msm-smmu-v1-ctx"
- reg : offset and length of the register set for the context bank.
- - interrupts : should contain the context bank interrupt.
+ - interrupts : should contain the context bank interrupt. If this is
+ a secure context bank, this should be a list of 2 3-tuples where
+ the first is the non-secure interrupt, and the second is the
+ secure interrupt.
- qcom,iommu-ctx-sids : List of stream identifiers associated with this
translation context.
- label : Name of the context bank
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 74ea2cd..946391d 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -467,6 +467,12 @@
- qcom,headset-jack-type-NO: Adjust GPIO level based on the headset jack type.
+
+* APQ8074 ASoC Machine driver
+
+Required properties:
+- compatible : "qcom,apq8074-audio-taiko"
+
Example:
sound {
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index b0d6b4d..a3a9935 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -40,8 +40,15 @@
DATA GPIO PAD.
- qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
SOFs. Software workarounds are required for the same.
+- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
+ to 64 bits
+- qcom,enable_hbm: if present host bus manager is enabled.
+- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
+ up to 3 usb packets from each QH.
- hsic,consider-ipa-handshake: If present then hsic low power mode is
depend on suitable handshake with the IPA peer.
+- qcom,ahb-async-bridge-bypass: if present AHB ASYNC bridge will be bypassed such that
+ the bridge on the slave AHB is always used.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index de1577d..fbe2d25 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -121,11 +121,6 @@
Optional properties :
- qcom,usb2-enable-hsphy2: If present, select second PHY for USB operation.
-- qcom,pool-64-bit-align: If present then the pool's memory will be aligned
- to 64 bits
-- qcom,enable_hbm: if present host bus manager is enabled.
-- qcom,disable-park-mode: if present park mode is enabled. Park mode enables executing
- up to 3 usb packets from each QH.
Example MSM HSUSB EHCI controller device node :
ehci: qcom,ehci-host@f9a55000 {
diff --git a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
index 6df1efe..d0bbc47 100644
--- a/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
+++ b/Documentation/devicetree/bindings/wcnss/wcnss-wlan.txt
@@ -18,12 +18,14 @@
- qcom,iris-vddpa-supply : regulator to supply RF PA.
- qcom,iris-vdddig-supply : regulator to supply RF digital(BT/FM).
- gpios: gpio numbers to configure 5-wire interface of WLAN connectivity
-- qcom,has_48mhz_xo: boolean flag to determine the usage of 24MHz XO from RF
-- qcom,has_pronto_hw: boolean flag to determine the revId of the WLAN subsystem
+- qcom,has-48mhz-xo: boolean flag to determine the usage of 24MHz XO from RF
+- qcom,has-pronto-hw: boolean flag to determine the revId of the WLAN subsystem
Optional properties:
-- qcom,has_autodetect_xo: boolean flag to determine whether Iris XO auto detect
+- qcom,has-autodetect-xo: boolean flag to determine whether Iris XO auto detect
should be performed during boot up.
+- qcom,wlan-rx-buff-count: WLAN RX buffer count is a configurable value,
+using a smaller count for this buffer will reduce the memory usage.
Example:
@@ -45,6 +47,6 @@
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>,
<&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 5700b8d..8e4f368 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -11,9 +11,10 @@
*/
/include/ "dsi-panel-sharp-qhd-video.dtsi"
+/include/ "msm8974-camera-sensor-dragonboard.dtsi"
/include/ "msm8974-leds.dtsi"
-/ {
+&soc {
serial@f991e000 {
status = "ok";
};
@@ -539,12 +540,12 @@
qcom,cs-out-en;
qcom,op-fdbck = <1>;
qcom,default-state = "on";
- qcom,max-current = <25>;
+ qcom,max-current = <20>;
qcom,ctrl-delay-us = <0>;
qcom,boost-curr-lim = <3>;
qcom,cp-sel = <0>;
qcom,switch-freq = <2>;
- qcom,ovp-val = <2>;
+ qcom,ovp-val = <1>;
qcom,num-strings = <1>;
qcom,id = <0>;
};
@@ -555,25 +556,25 @@
&pm8941_chg {
status = "ok";
- qcom,chg-charging-disabled;
+ qcom,charging-disabled;
- qcom,chg-chgr@1000 {
+ qcom,chgr@1000 {
status = "ok";
};
- qcom,chg-buck@1100 {
+ qcom,buck@1100 {
status = "ok";
};
- qcom,chg-usb-chgpth@1300 {
+ qcom,usb-chgpth@1300 {
status = "ok";
};
- qcom,chg-dc-chgpth@1400 {
+ qcom,dc-chgpth@1400 {
status = "ok";
};
- qcom,chg-boost@1500 {
+ qcom,boost@1500 {
status = "ok";
};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index 4dea9e0..946b54d 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -130,6 +130,15 @@
reg = <0xfc580000 0x17c>;
interrupts = <0 243 0>;
};
+
+ qcom,wdt@f9017000 {
+ compatible = "qcom,msm-watchdog";
+ reg = <0xf9017000 0x1000>;
+ interrupts = <0 3 0>, <0 4 0>;
+ qcom,bark-time = <11000>;
+ qcom,pet-time = <10000>;
+ qcom,ipi-ping;
+ };
};
&gdsc_venus {
@@ -144,10 +153,6 @@
status = "ok";
};
-&gdsc_vfe {
- status = "ok";
-};
-
&gdsc_oxili_gx {
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm-iommu-v1.dtsi b/arch/arm/boot/dts/msm-iommu-v1.dtsi
index ab46861..d497259 100644
--- a/arch/arm/boot/dts/msm-iommu-v1.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v1.dtsi
@@ -183,7 +183,7 @@
qcom,iommu-ctx@fd931000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd931000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <1>;
label = "mdp_1";
qcom,secure-context;
@@ -192,7 +192,7 @@
qcom,iommu-ctx@fd932000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfd932000 0x1000>;
- interrupts = <0 47 0>;
+ interrupts = <0 47 0>, <0 46 0>;
qcom,iommu-ctx-sids = <>;
label = "mdp_2";
qcom,secure-context;
@@ -295,7 +295,7 @@
venus_cp: qcom,iommu-ctx@fdc8d000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8d000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84 0x85>;
label = "venus_cp";
qcom,secure-context;
@@ -304,7 +304,7 @@
venus_fw: qcom,iommu-ctx@fdc8e000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8e000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0xc0 0xc6>;
label = "venus_fw";
qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 128d90c..234353f 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -415,6 +415,15 @@
qcom,adc-vdd-reference = <1800>;
};
+ qcom,temp-alarm@2400 {
+ compatible = "qcom,qpnp-temp-alarm";
+ reg = <0x2400 0x100>;
+ interrupts = <0x0 0x24 0x0>;
+ label = "pm8226_tz";
+ qcom,channel-num = <8>;
+ qcom,threshold-set = <0>;
+ };
+
qcom,pm8226_rtc {
spmi-dev-container;
compatible = "qcom,qpnp-rtc";
diff --git a/arch/arm/boot/dts/msm8226-cdp.dts b/arch/arm/boot/dts/msm8226-cdp.dts
index 6bbdf9f..da517eb 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dts
+++ b/arch/arm/boot/dts/msm8226-cdp.dts
@@ -12,8 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-cdp.dtsi"
+/include/ "msm8226-cdp.dtsi"
/ {
model = "Qualcomm MSM 8226 CDP";
@@ -23,375 +22,3 @@
<159 1 0>,
<198 1 0>;
};
-
-&soc {
- serial@f991f000 {
- status = "ok";
- };
-
- qcom,mdss_dsi_nt35590_720p_video {
- status = "ok";
- };
-
- i2c@f9927000 { /* BLSP1 QUP5 */
- synaptics@20 {
- compatible = "synaptics,rmi4";
- reg = <0x20>;
- interrupt-parent = <&msmgpio>;
- interrupts = <17 0x2008>;
- vdd-supply = <&pm8226_l19>;
- vcc_i2c-supply = <&pm8226_lvs1>;
- synaptics,reset-gpio = <&msmgpio 16 0x00>;
- synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
- synaptics,i2c-pull-up;
- synaptics,reg-en;
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_focus {
- label = "camera_focus";
- gpios = <&msmgpio 108 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&msmgpio 107 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&msmgpio 106 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@3 {
- compatible = "micrel,ks8851";
- reg = <3>;
- interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&msmgpio 114 0>;
- vdd-io-supply = <&pm8226_lvs1>;
- vdd-phy-supply = <&pm8226_lvs1>;
- };
- };
-
- sound {
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "SPK_OUT", "MCLK",
- "SPK_OUT", "EXT_VDD_SPKR",
- "AMIC1", "MIC BIAS1 Internal1",
- "MIC BIAS1 Internal1", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCRight Headset Mic",
- "AMIC5", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic",
- "DMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic1",
- "DMIC2", "MIC BIAS1 External",
- "MIC BIAS1 External", "Digital Mic2",
- "DMIC3", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic3",
- "DMIC4", "MIC BIAS3 External",
- "MIC BIAS3 External", "Digital Mic4";
-
- qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
- qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
- qcom,headset-jack-type-NO;
- };
-};
-
-&sdcc1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "disabled";
-};
-
-&sdhc_1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "ok";
-};
-
-&sdcc2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,xpc;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- qcom,current-limit = <600>;
-
- #address-cells = <0>;
- interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "disabled";
-};
-
-&sdhc_2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
- #address-cells = <0>;
- interrupt-parent = <&sdhc_2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 221 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "hc_irq", "pwr_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "ok";
-};
-
-&spmi_bus {
- qcom,pm8226@0 {
- qcom,leds@a100 {
- status = "okay";
- qcom,led_mpp_2 {
- label = "mpp";
- linux,name = "button-backlight";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "manual";
- qcom,source-sel = <1>;
- qcom,mode-ctrl = <0x60>;
- };
- };
-
- qcom,leds@a300 {
- status = "okay";
- qcom,led_mpp_4 {
- label = "mpp";
- linux,name = "green";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "lpg";
- qcom,source-sel = <8>;
- qcom,mode-ctrl = <0x60>;
- qcom,pwm-channel = <0>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
-
- qcom,leds@a500 {
- status = "okay";
- qcom,led_mpp_6 {
- label = "mpp";
- linux,name = "red";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode-ctrl = <0x60>;
- qcom,source-sel = <10>;
- qcom,mode = "lpg";
- qcom,pwm-channel = <5>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
- };
-
- qcom,pm8226@1 {
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <0>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
- };
- };
-};
-
-&pm8226_gpios {
- gpio@c000 { /* GPIO 1 */
- /* XO_PMIC_CDC_MCLK enable for tapan codec */
- qcom,mode = <1>; /* Digital output */
- qcom,output-type = <0>; /* CMOS logic */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
- qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
- qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
- qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
- qcom,master-en = <1>; /* Enable GPIO */
- };
-
- gpio@c100 { /* GPIO 2 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <3>;
- qcom,out-strength = <3>;
- qcom,src-sel = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@c200 { /* GPIO 3 */
- };
-
- gpio@c300 { /* GPIO 4 */
- };
-
- gpio@c400 { /* GPIO 5 */
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-};
-
-&pm8226_mpps {
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- };
-
- mpp@a500 { /* MPP 6 */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&pm8226_chg {
- qcom,charging-disabled;
- qcom,use-default-batt-values;
-};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
new file mode 100644
index 0000000..01677ff
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -0,0 +1,386 @@
+/* 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/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-cdp.dtsi"
+
+&soc {
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,reg-en;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 108 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 107 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 106 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 Internal1",
+ "MIC BIAS1 Internal1", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCRight Headset Mic",
+ "AMIC5", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic",
+ "DMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic1",
+ "DMIC2", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Digital Mic2",
+ "DMIC3", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic3",
+ "DMIC4", "MIC BIAS3 External",
+ "MIC BIAS3 External", "Digital Mic4";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ qcom,headset-jack-type-NO;
+ };
+};
+
+&sdcc1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "disabled";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <600>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "disabled";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <0>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <3>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&pm8226_chg {
+ qcom,charging-disabled;
+ qcom,use-default-batt-values;
+};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dts b/arch/arm/boot/dts/msm8226-mtp.dts
index 967eb82..2881274 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-mtp.dts
@@ -12,8 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-mtp.dtsi"
+/include/ "msm8226-mtp.dtsi"
/ {
model = "Qualcomm MSM 8226 MTP";
@@ -23,413 +22,3 @@
<159 8 0>,
<198 8 0>;
};
-
-&soc {
- serial@f991f000 {
- status = "ok";
- };
-
- qcom,mdss_dsi_nt35590_720p_video {
- status = "ok";
- };
-
- i2c@f9927000 { /* BLSP1 QUP5 */
- synaptics@20 {
- compatible = "synaptics,rmi4";
- reg = <0x20>;
- interrupt-parent = <&msmgpio>;
- interrupts = <17 0x2008>;
- vdd-supply = <&pm8226_l19>;
- vcc_i2c-supply = <&pm8226_lvs1>;
- synaptics,reset-gpio = <&msmgpio 16 0x00>;
- synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
- synaptics,i2c-pull-up;
- synaptics,reg-en;
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_focus {
- label = "camera_focus";
- gpios = <&msmgpio 108 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&msmgpio 107 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&msmgpio 106 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@3 {
- compatible = "micrel,ks8851";
- reg = <3>;
- interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&msmgpio 114 0>;
- vdd-io-supply = <&pm8226_lvs1>;
- vdd-phy-supply = <&pm8226_lvs1>;
- };
- };
-
- sound {
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "SPK_OUT", "MCLK",
- "SPK_OUT", "EXT_VDD_SPKR",
- "AMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS1 External",
- "MIC BIAS1 External", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic";
-
- qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
- qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
- };
-};
-
-&sdcc1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "disabled";
-};
-
-&sdhc_1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "ok";
-};
-
-&sdcc2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,xpc;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "disabled";
-};
-
-&sdhc_2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
- #address-cells = <0>;
- interrupt-parent = <&sdhc_2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 221 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "hc_irq", "pwr_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "ok";
-};
-
-&spmi_bus {
- qcom,pm8226@0 {
- qcom,leds@a100 {
- status = "okay";
- qcom,led_mpp_2 {
- label = "mpp";
- linux,name = "button-backlight";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "manual";
- qcom,source-sel = <1>;
- qcom,mode-ctrl = <0x60>;
- };
- };
-
- qcom,leds@a300 {
- status = "okay";
- qcom,led_mpp_4 {
- label = "mpp";
- linux,name = "green";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "lpg";
- qcom,source-sel = <8>;
- qcom,mode-ctrl = <0x60>;
- qcom,pwm-channel = <0>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
-
- qcom,leds@a500 {
- status = "okay";
- qcom,led_mpp_6 {
- label = "mpp";
- linux,name = "red";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode-ctrl = <0x60>;
- qcom,source-sel = <10>;
- qcom,mode = "lpg";
- qcom,pwm-channel = <5>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
- };
-
- qcom,pm8226@1 {
- qcom,leds@d300 {
- status = "okay";
- };
-
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <0>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
- };
- };
-};
-
-&pm8226_gpios {
- gpio@c000 { /* GPIO 1 */
- /* XO_PMIC_CDC_MCLK enable for tapan codec */
- qcom,mode = <1>; /* Digital output */
- qcom,output-type = <0>; /* CMOS logic */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
- qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
- qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
- qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
- qcom,master-en = <1>; /* Enable GPIO */
- };
-
- gpio@c100 { /* GPIO 2 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <3>;
- qcom,out-strength = <3>;
- qcom,src-sel = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@c200 { /* GPIO 3 */
- };
-
- gpio@c300 { /* GPIO 4 */
- };
-
- gpio@c400 { /* GPIO 5 */
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-};
-
-&pm8226_mpps {
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- /* PA_THERM0 config */
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <0>; /* AMUX 5 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
-
- mpp@a500 { /* MPP 6 */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- /* PA_THERM1 config */
- qcom,mode = <4>; /* AIN input */
- qcom,invert = <1>; /* Enable MPP */
- qcom,ain-route = <3>; /* AMUX 8 */
- qcom,master-en = <1>;
- qcom,src-sel = <0>; /* Function constant */
- };
-};
-
-&pm8226_vadc {
- chan@14 {
- label = "pa_therm0";
- reg = <0x14>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-
- chan@17 {
- label = "pa_therm1";
- reg = <0x17>;
- qcom,decimation = <0>;
- qcom,pre-div-channel-scaling = <0>;
- qcom,calibration-type = "ratiometric";
- qcom,scale-function = <2>;
- qcom,hw-settle-time = <2>;
- qcom,fast-avg-setup = <0>;
- };
-};
-
-&pm8226_bms {
- status = "ok";
-};
-
-&pm8226_chg {
- qcom,charging-disabled;
-};
-
-&slim_msm {
- tapan_codec {
- qcom,cdc-micbias1-ext-cap;
- qcom,cdc-micbias2-ext-cap;
- };
-};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
new file mode 100644
index 0000000..af443d5
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -0,0 +1,424 @@
+/* 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/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-mtp.dtsi"
+
+&soc {
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,reg-en;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 108 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 107 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 106 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
+};
+
+&sdcc1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "disabled";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <600>; #address-cells = <0>; interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "disabled";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
+ qcom,pm8226@1 {
+ qcom,leds@d300 {
+ status = "okay";
+ };
+
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <0>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+ };
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <3>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ /* PA_THERM0 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <0>; /* AMUX 5 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ /* PA_THERM1 config */
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ };
+};
+
+&pm8226_vadc {
+ chan@14 {
+ label = "pa_therm0";
+ reg = <0x14>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+
+ chan@17 {
+ label = "pa_therm1";
+ reg = <0x17>;
+ qcom,decimation = <0>;
+ qcom,pre-div-channel-scaling = <0>;
+ qcom,calibration-type = "ratiometric";
+ qcom,scale-function = <2>;
+ qcom,hw-settle-time = <2>;
+ qcom,fast-avg-setup = <0>;
+ };
+};
+
+&pm8226_bms {
+ status = "ok";
+};
+
+&pm8226_chg {
+ qcom,charging-disabled;
+};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias2-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dts b/arch/arm/boot/dts/msm8226-qrd.dts
index f6e8f8b..e364de7 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dts
+++ b/arch/arm/boot/dts/msm8226-qrd.dts
@@ -12,8 +12,7 @@
/dts-v1/;
/include/ "msm8226.dtsi"
-/include/ "dsi-panel-nt35590-720p-video.dtsi"
-/include/ "msm8226-camera-sensor-qrd.dtsi"
+/include/ "msm8226-qrd.dtsi"
/ {
model = "Qualcomm MSM 8226 QRD";
@@ -23,391 +22,3 @@
<159 11 0>,
<198 11 0>;
};
-
-&soc {
- serial@f991f000 {
- status = "ok";
- };
-
- qcom,mdss_dsi_nt35590_720p_video {
- status = "ok";
- };
-
- i2c@f9927000 { /* BLSP1 QUP5 */
- synaptics@20 {
- compatible = "synaptics,rmi4";
- reg = <0x20>;
- interrupt-parent = <&msmgpio>;
- interrupts = <17 0x2008>;
- vdd-supply = <&pm8226_l19>;
- vcc_i2c-supply = <&pm8226_lvs1>;
- synaptics,reset-gpio = <&msmgpio 16 0x00>;
- synaptics,irq-gpio = <&msmgpio 17 0x2008>;
- synaptics,button-map = <139 102 158>;
- synaptics,i2c-pull-up;
- synaptics,reg-en;
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- input-name = "gpio-keys";
-
- camera_focus {
- label = "camera_focus";
- gpios = <&msmgpio 108 0x1>;
- linux,input-type = <1>;
- linux,code = <0x210>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- camera_snapshot {
- label = "camera_snapshot";
- gpios = <&msmgpio 107 0x1>;
- linux,input-type = <1>;
- linux,code = <0x2fe>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
-
- vol_up {
- label = "volume_up";
- gpios = <&msmgpio 106 0x1>;
- linux,input-type = <1>;
- linux,code = <115>;
- gpio-key,wakeup;
- debounce-interval = <15>;
- };
- };
-
- spi@f9923000 {
- ethernet-switch@3 {
- compatible = "micrel,ks8851";
- reg = <3>;
- interrupt-parent = <&msmgpio>;
- interrupts = <0 115 0>;
- spi-max-frequency = <4800000>;
- rst-gpio = <&msmgpio 114 0>;
- vdd-io-supply = <&pm8226_lvs1>;
- vdd-phy-supply = <&pm8226_lvs1>;
- };
- };
-
- sound {
- qcom,audio-routing =
- "RX_BIAS", "MCLK",
- "LDO_H", "MCLK",
- "SPK_OUT", "MCLK",
- "SPK_OUT", "EXT_VDD_SPKR",
- "AMIC1", "MIC BIAS1 External",
- "MIC BIAS1 External", "Handset Mic",
- "AMIC2", "MIC BIAS2 External",
- "MIC BIAS2 External", "Headset Mic",
- "AMIC3", "MIC BIAS1 External",
- "MIC BIAS1 External", "ANCRight Headset Mic",
- "AMIC4", "MIC BIAS2 External",
- "MIC BIAS2 External", "ANCLeft Headset Mic";
-
- qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
- qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
- };
-};
-
-&sdcc1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "disabled";
-};
-
-&sdhc_1 {
- vdd-supply = <&pm8226_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <800 500000>;
-
- vdd-io-supply = <&pm8226_l6>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-voltage-level = <1800000 1800000>;
- qcom,vdd-io-current-level = <250 154000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
- qcom,nonremovable;
-
- status = "ok";
-};
-
-&sdcc2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sup-voltages = <2950 2950>;
-
- qcom,xpc;
- qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
- qcom,current-limit = <600>;
-
- #address-cells = <0>;
- interrupt-parent = <&sdcc2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 220 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "core_irq", "bam_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "disabled";
-};
-
-&sdhc_2 {
- vdd-supply = <&pm8226_l18>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <9000 800000>;
-
- vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <6 22000>;
-
- qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
- qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
- qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
-
- qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
-
- #address-cells = <0>;
- interrupt-parent = <&sdhc_2>;
- interrupts = <0 1 2>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0xffffffff>;
- interrupt-map = <0 &intc 0 125 0
- 1 &intc 0 221 0
- 2 &msmgpio 38 0x3>;
- interrupt-names = "hc_irq", "pwr_irq", "status_irq";
- cd-gpios = <&msmgpio 38 0x1>;
-
- status = "ok";
-};
-
-&spmi_bus {
- qcom,pm8226@0 {
- qcom,leds@a100 {
- status = "okay";
- qcom,led_mpp_2 {
- label = "mpp";
- linux,name = "button-backlight";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "manual";
- qcom,source-sel = <1>;
- qcom,mode-ctrl = <0x60>;
- };
- };
-
- qcom,leds@a300 {
- status = "okay";
- qcom,led_mpp_4 {
- label = "mpp";
- linux,name = "green";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode = "lpg";
- qcom,source-sel = <8>;
- qcom,mode-ctrl = <0x60>;
- qcom,pwm-channel = <0>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
-
- qcom,leds@a500 {
- status = "okay";
- qcom,led_mpp_6 {
- label = "mpp";
- linux,name = "red";
- linux,default-trigger = "none";
- qcom,default-state = "off";
- qcom,max-current = <40>;
- qcom,current-setting = <5>;
- qcom,id = <6>;
- qcom,mode-ctrl = <0x60>;
- qcom,source-sel = <10>;
- qcom,mode = "lpg";
- qcom,pwm-channel = <5>;
- qcom,start-idx = <1>;
- qcom,duty-pcts = [00 00 00 00 64
- 64 00 00 00 00];
- };
- };
- };
-
- qcom,pm8226@1 {
- qcom,leds@d300 {
- status = "okay";
- };
-
- qcom,leds@d800 {
- status = "okay";
- qcom,wled_0 {
- label = "wled";
- linux,name = "wled:backlight";
- linux,default-trigger = "bkl-trigger";
- qcom,cs-out-en;
- qcom,op-fdbck = <1>;
- qcom,default-state = "on";
- qcom,max-current = <25>;
- qcom,ctrl-delay-us = <0>;
- qcom,boost-curr-lim = <3>;
- qcom,cp-sel = <0>;
- qcom,switch-freq = <2>;
- qcom,ovp-val = <0>;
- qcom,num-strings = <1>;
- qcom,id = <0>;
- };
- };
-
- qcom,vibrator@c000 {
- status = "okay";
- qcom,vib-timeout-ms = <15000>;
- qcom,vib-vtg-level-mV = <3100>;
- };
-
- };
-};
-
-&pm8226_bms {
- status = "okay";
- qcom,batt-type = <4>;
- qcom,max-voltage-uv = <4350000>;
-};
-
-&pm8226_chg {
- status = "okay";
- qcom,chg-vddmax-mv = <4350>;
- qcom,chg-vddsafe-mv = <4350>;
-};
-
-&pm8226_gpios {
- gpio@c000 { /* GPIO 1 */
- /* XO_PMIC_CDC_MCLK enable for tapan codec */
- qcom,mode = <1>; /* Digital output */
- qcom,output-type = <0>; /* CMOS logic */
- qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
- qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
- qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
- qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
- qcom,master-en = <1>; /* Enable GPIO */
- };
-
- gpio@c100 { /* GPIO 2 */
- qcom,mode = <1>;
- qcom,output-type = <0>;
- qcom,pull = <5>;
- qcom,vin-sel = <3>;
- qcom,out-strength = <3>;
- qcom,src-sel = <2>;
- qcom,master-en = <1>;
- };
-
- gpio@c200 { /* GPIO 3 */
- };
-
- gpio@c300 { /* GPIO 4 */
- };
-
- gpio@c400 { /* GPIO 5 */
- };
-
- gpio@c500 { /* GPIO 6 */
- };
-
- gpio@c600 { /* GPIO 7 */
- };
-
- gpio@c700 { /* GPIO 8 */
- };
-};
-
-&pm8226_mpps {
- mpp@a000 { /* MPP 1 */
- };
-
- mpp@a100 { /* MPP 2 */
- };
-
- mpp@a200 { /* MPP 3 */
- };
-
- mpp@a300 { /* MPP 4 */
- };
-
- mpp@a400 { /* MPP 5 */
- };
-
- mpp@a500 { /* MPP 6 */
- };
-
- mpp@a600 { /* MPP 7 */
- };
-
- mpp@a700 { /* MPP 8 */
- };
-};
-
-&slim_msm {
- tapan_codec {
- qcom,cdc-micbias1-ext-cap;
- };
-
-};
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
new file mode 100644
index 0000000..3c70368
--- /dev/null
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -0,0 +1,402 @@
+/* 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/ "dsi-panel-nt35590-720p-video.dtsi"
+/include/ "msm8226-camera-sensor-qrd.dtsi"
+
+&soc {
+ serial@f991f000 {
+ status = "ok";
+ };
+
+ qcom,mdss_dsi_nt35590_720p_video {
+ status = "ok";
+ };
+
+ i2c@f9927000 { /* BLSP1 QUP5 */
+ synaptics@20 {
+ compatible = "synaptics,rmi4";
+ reg = <0x20>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ vdd-supply = <&pm8226_l19>;
+ vcc_i2c-supply = <&pm8226_lvs1>;
+ synaptics,reset-gpio = <&msmgpio 16 0x00>;
+ synaptics,irq-gpio = <&msmgpio 17 0x2008>;
+ synaptics,button-map = <139 102 158>;
+ synaptics,i2c-pull-up;
+ synaptics,reg-en;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&msmgpio 108 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&msmgpio 107 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&msmgpio 106 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
+
+ spi@f9923000 {
+ ethernet-switch@3 {
+ compatible = "micrel,ks8851";
+ reg = <3>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <0 115 0>;
+ spi-max-frequency = <4800000>;
+ rst-gpio = <&msmgpio 114 0>;
+ vdd-io-supply = <&pm8226_lvs1>;
+ vdd-phy-supply = <&pm8226_lvs1>;
+ };
+ };
+
+ sound {
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "LDO_H", "MCLK",
+ "SPK_OUT", "MCLK",
+ "SPK_OUT", "EXT_VDD_SPKR",
+ "AMIC1", "MIC BIAS1 External",
+ "MIC BIAS1 External", "Handset Mic",
+ "AMIC2", "MIC BIAS2 External",
+ "MIC BIAS2 External", "Headset Mic",
+ "AMIC3", "MIC BIAS1 External",
+ "MIC BIAS1 External", "ANCRight Headset Mic",
+ "AMIC4", "MIC BIAS2 External",
+ "MIC BIAS2 External", "ANCLeft Headset Mic";
+
+ qcom,cdc-mclk-gpios = <&pm8226_gpios 1 0>;
+ qcom,cdc-vdd-spkr-gpios = <&pm8226_gpios 2 0>;
+ };
+};
+
+&sdcc1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "disabled";
+};
+
+&sdhc_1 {
+ vdd-supply = <&pm8226_l17>;
+ qcom,vdd-always-on;
+ qcom,vdd-lpm-sup;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <800 500000>;
+
+ vdd-io-supply = <&pm8226_l6>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <250 154000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+ qcom,nonremovable;
+
+ status = "ok";
+};
+
+&sdcc2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+ qcom,sup-voltages = <2950 2950>;
+
+ qcom,xpc;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+ qcom,current-limit = <600>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdcc2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 220 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "core_irq", "bam_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "disabled";
+};
+
+&sdhc_2 {
+ vdd-supply = <&pm8226_l18>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
+
+ vdd-io-supply = <&pm8226_l21>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
+
+ qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-pull-off = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */
+ qcom,pad-drv-on = <0x4 0x4 0x4>; /* 10mA, 10mA, 10mA */
+ qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
+
+ qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
+
+ #address-cells = <0>;
+ interrupt-parent = <&sdhc_2>;
+ interrupts = <0 1 2>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0xffffffff>;
+ interrupt-map = <0 &intc 0 125 0
+ 1 &intc 0 221 0
+ 2 &msmgpio 38 0x3>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&msmgpio 38 0x1>;
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8226@0 {
+ qcom,leds@a100 {
+ status = "okay";
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "button-backlight";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ status = "okay";
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "lpg";
+ qcom,source-sel = <8>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,pwm-channel = <0>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+
+ qcom,leds@a500 {
+ status = "okay";
+ qcom,led_mpp_6 {
+ label = "mpp";
+ linux,name = "red";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode-ctrl = <0x60>;
+ qcom,source-sel = <10>;
+ qcom,mode = "lpg";
+ qcom,pwm-channel = <5>;
+ qcom,start-idx = <1>;
+ qcom,duty-pcts = [00 00 00 00 64
+ 64 00 00 00 00];
+ };
+ };
+ };
+
+ qcom,pm8226@1 {
+ qcom,leds@d300 {
+ status = "okay";
+ };
+
+ qcom,leds@d800 {
+ status = "okay";
+ qcom,wled_0 {
+ label = "wled";
+ linux,name = "wled:backlight";
+ linux,default-trigger = "bkl-trigger";
+ qcom,cs-out-en;
+ qcom,op-fdbck = <1>;
+ qcom,default-state = "on";
+ qcom,max-current = <25>;
+ qcom,ctrl-delay-us = <0>;
+ qcom,boost-curr-lim = <3>;
+ qcom,cp-sel = <0>;
+ qcom,switch-freq = <2>;
+ qcom,ovp-val = <0>;
+ qcom,num-strings = <1>;
+ qcom,id = <0>;
+ };
+ };
+
+ qcom,vibrator@c000 {
+ status = "okay";
+ qcom,vib-timeout-ms = <15000>;
+ qcom,vib-vtg-level-mV = <3100>;
+ };
+
+ };
+};
+
+&pm8226_bms {
+ status = "okay";
+ qcom,batt-type = <4>;
+ qcom,max-voltage-uv = <4350000>;
+};
+
+&pm8226_chg {
+ status = "okay";
+ qcom,chg-vddmax-mv = <4350>;
+ qcom,chg-vddsafe-mv = <4350>;
+};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ /* XO_PMIC_CDC_MCLK enable for tapan codec */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS logic */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO*/
+ qcom,vin-sel = <3>; /* QPNP_PIN_VIN3 */
+ qcom,out-strength = <3>;/* QPNP_PIN_OUT_STRENGTH_HIGH */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ qcom,mode = <1>;
+ qcom,output-type = <0>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <3>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+&slim_msm {
+ tapan_codec {
+ qcom,cdc-micbias1-ext-cap;
+ };
+
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 6aeaf49..a7dc865 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -30,8 +30,9 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
- reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+ <0xfc4bc450 16>;
+ reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 9d51204..273121b 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -329,7 +329,7 @@
qcom,cdc-micbias-ldoh-v = <0x3>;
qcom,cdc-micbias-cfilt1-mv = <1800>;
- qcom,cdc-micbias-cfilt2-mv = <1800>;
+ qcom,cdc-micbias-cfilt2-mv = <2700>;
qcom,cdc-micbias-cfilt3-mv = <1800>;
qcom,cdc-micbias1-cfilt-sel = <0x0>;
@@ -547,8 +547,8 @@
qcom,iris-vdddig-supply = <&pm8226_l24>;
gpios = <&msmgpio 40 0>, <&msmgpio 41 0>, <&msmgpio 42 0>, <&msmgpio 43 0>, <&msmgpio 44 0>;
- qcom,has_pronto_hw;
- qcom,has_autodetect_xo;
+ qcom,has-pronto-hw;
+ qcom,has-autodetect-xo;
};
qcom,msm-adsp-sensors {
diff --git a/arch/arm/boot/dts/msm8610-regulator.dtsi b/arch/arm/boot/dts/msm8610-regulator.dtsi
index a90f053..2c17780 100644
--- a/arch/arm/boot/dts/msm8610-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8610-regulator.dtsi
@@ -30,8 +30,9 @@
apc_vreg_corner: regulator@f9018000 {
status = "okay";
compatible = "qcom,cpr-regulator";
- reg = <0xf9018000 0x1000>, <0xfc4b80b0 8>, <0xfc4bc450 16>;
- reg-names = "rbcpr", "pvs_efuse", "cpr_efuse";
+ reg = <0xf9018000 0x1000>, <0xf9011064 4>, <0xfc4b80b0 8>,
+ <0xfc4bc450 16>;
+ reg-names = "rbcpr", "rbcpr_clk", "pvs_efuse", "cpr_efuse";
interrupts = <0 15 0>;
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 689392c..474f809 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -668,7 +668,8 @@
qcom,iris-vdddig-supply = <&pm8110_l5>;
gpios = <&msmgpio 23 0>, <&msmgpio 24 0>, <&msmgpio 25 0>, <&msmgpio 26 0>, <&msmgpio 27 0>;
- qcom,has_pronto_hw;
+ qcom,has-pronto-hw;
+ qcom,wlan-rx-buff-count = <256>;
};
qcom,mss@fc880000 {
diff --git a/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
new file mode 100644
index 0000000..e84a47d
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974-camera-sensor-dragonboard.dtsi
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2012-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.
+ */
+
+&cci {
+
+ actuator0: qcom,actuator@18 {
+ cell-index = <0>;
+ reg = <0x18 0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ actuator1: qcom,actuator@36 {
+ cell-index = <1>;
+ reg = <0x36>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ };
+
+ qcom,camera@6e {
+ compatible = "qcom,s5k3l1yx";
+ reg = <0x6e 0x0>;
+ qcom,slave-id = <0x6e 0x0 0x3121>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,actuator-src = <&actuator0>;
+ qcom,sensor-name = "s5k3l1yx";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ 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 = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ 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 = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ 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 = <0>;
+ qcom,sensor-name = "imx135";
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ cam_vaf-supply = <&pm8941_l23>;
+ 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 = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-max-voltage = <1225000 0 2850000 3000000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 15 0>,
+ <&msmgpio 90 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ 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 = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@6c {
+ compatible = "qcom,ov2720";
+ reg = <0x6c 0x0>;
+ qcom,slave-id = <0x6c 0x300A 0x2720>;
+ qcom,csiphy-sd-index = <2>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <180>;
+ qcom,sensor-name = "ov2720";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 17 0>,
+ <&msmgpio 18 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x7>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ };
+
+ qcom,camera@90 {
+ compatible = "qcom,mt9m114";
+ reg = <0x90 0x0>;
+ qcom,slave-id = <0x90 0x0 0x2481>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <0>;
+ qcom,sensor-name = "mt9m114";
+ cam_vdig-supply = <&pm8941_l3>;
+ cam_vana-supply = <&pm8941_l17>;
+ cam_vio-supply = <&pm8941_lvs3>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio";
+ qcom,cam-vreg-type = <0 0 1>;
+ qcom,cam-vreg-min-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-max-voltage = <1225000 2850000 0>;
+ qcom,cam-vreg-op-mode = <105000 80000 0>;
+ qcom,gpio-no-mux = <0>;
+ gpios = <&msmgpio 16 0>,
+ <&msmgpio 94 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-req-tbl-num = <0 1>;
+ qcom,gpio-req-tbl-flags = <1 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK",
+ "CAM_RESET1";
+ qcom,gpio-set-tbl-num = <1 1>;
+ qcom,gpio-set-tbl-flags = <0 2>;
+ qcom,gpio-set-tbl-delay = <1000 4000>;
+ qcom,csi-lane-assign = <0x4320>;
+ qcom,csi-lane-mask = <0x3>;
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index b30d65c..fa8c240 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -406,6 +406,29 @@
<85 512 40000 160000>;
};
};
+
+ wlan0: qca,wlan {
+ compatible = "qca,ar6004-hsic";
+ qcom,msm-bus,name = "wlan";
+ qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+ qca,wifi-vddpa-supply = <&pm8941_l19>;
+ qca,wifi-vddio-supply = <&pm8941_l10>;
+ qcom,msm-bus,num-cases = <5>;
+ qcom,msm-bus,active-only = <0>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <85 512 0 0>,
+ <85 512 40000 160000>,
+ <85 512 40000 320000>,
+ <85 512 40000 480000>,
+ <85 512 40000 800000>;
+ };
+
+ wlan_sdio:qca,wlan_sdio {
+ compatible = "qca,ar6004-sdio";
+ qcom,msm-bus,name = "wlan_sdio";
+ qca,wifi-chip-pwd-supply = <&ath_chip_pwd_l>;
+ };
};
&mdss_fb0 {
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index b5652d1..64eff43 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -78,7 +78,7 @@
venus_sec_pixel: qcom,iommu-ctx@fdc8f000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc8f000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x85>;
label = "venus_sec_pixel";
qcom,secure-context;
@@ -87,7 +87,7 @@
venus_sec_non_pixel: qcom,iommu-ctx@fdc90000 {
compatible = "qcom,msm-smmu-v1-ctx";
reg = <0xfdc90000 0x1000>;
- interrupts = <0 42 0>;
+ interrupts = <0 42 0>, <0 43 0>;
qcom,iommu-ctx-sids = <0x87 0xA0>;
label = "venus_sec_non_pixel";
qcom,secure-context;
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4367807..9045aa7 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -645,7 +645,9 @@
elemental-addr = [00 01 A0 00 17 02];
interrupt-parent = <&wcd9xxx_intc>;
- interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29
+ 30>;
qcom,cdc-reset-gpio = <&msmgpio 63 0>;
@@ -1213,8 +1215,8 @@
qcom,iris-vdddig-supply = <&pm8941_l3>;
gpios = <&msmgpio 36 0>, <&msmgpio 37 0>, <&msmgpio 38 0>, <&msmgpio 39 0>, <&msmgpio 40 0>;
- qcom,has_48mhz_xo;
- qcom,has_pronto_hw;
+ qcom,has-48mhz-xo;
+ qcom,has-pronto-hw;
};
qcom,ocmem@fdd00000 {
diff --git a/arch/arm/boot/dts/msm9625-coresight.dtsi b/arch/arm/boot/dts/msm9625-coresight.dtsi
index 9b18b72..bde734e 100644
--- a/arch/arm/boot/dts/msm9625-coresight.dtsi
+++ b/arch/arm/boot/dts/msm9625-coresight.dtsi
@@ -34,6 +34,8 @@
coresight-id = <1>;
coresight-name = "coresight-tpiu";
coresight-nr-inports = <1>;
+
+ vdd-supply = <&ext_2p95v>;
};
replicator: replicator@fc31c000 {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index bb1ea3d..c865c58 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -191,6 +191,7 @@
qcom,pool-64-bit-align;
qcom,enable-hbm;
hsic,consider-ipa-handshake;
+ qcom,ahb-async-bridge-bypass;
};
qcom,usbbam@f9a44000 {
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
new file mode 100644
index 0000000..7bf54ce
--- /dev/null
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -0,0 +1,387 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_ARCH_MSM=y
+CONFIG_ARCH_MSM8226=y
+# CONFIG_MSM_STACKED_MEMORY is not set
+CONFIG_CPU_HAS_L2_PMU=y
+# CONFIG_MSM_FIQ_SUPPORT is not set
+# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_BAM_DMUX=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SMP2P_TEST=y
+CONFIG_MSM_IPC_LOGGING=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_SYSMON_COMM=y
+CONFIG_MSM_PIL_LPASS_QDSP6V5=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_VENUS=y
+CONFIG_MSM_PIL_PRONTO=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_DIRECT_SCLK_ACCESS=y
+CONFIG_MSM_WATCHDOG_V2=y
+CONFIG_MSM_MEMORY_DUMP=y
+CONFIG_MSM_DLOAD_MODE=y
+CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_OCMEM=y
+CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
+CONFIG_MSM_OCMEM_DEBUG=y
+CONFIG_MSM_OCMEM_NONSECURE=y
+CONFIG_MSM_OCMEM_POWER_DISABLE=y
+CONFIG_SENSORS_ADSP=y
+CONFIG_MSM_RTB=y
+CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_CLS_FW=y
+CONFIG_BT=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=y
+CONFIG_BT_HCISMD=y
+CONFIG_CFG80211=y
+CONFIG_NL80211_TESTMODE=y
+CONFIG_CMA=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_MSM_RMNET is not set
+CONFIG_MSM_RMNET_BAM=y
+CONFIG_WCNSS_CORE=y
+CONFIG_WCNSS_CORE_PRONTO=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=m
+CONFIG_SERIAL_MSM_HSL=y
+CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QUP=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_SPMI=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_MSM_QPNP_INT=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_CHARGER=y
+CONFIG_QPNP_BMS=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_SENSORS_QPNP_ADC_CURRENT=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_TSENS8974=y
+CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_WCD9306_CODEC=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+# CONFIG_MSM_CAMERA is not set
+CONFIG_OV8825=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_CPP=y
+CONFIG_MSM_CCI=y
+CONFIG_MSM_CSI30_HEADER=y
+CONFIG_MSM_CSIPHY=y
+CONFIG_MSM_CSID=y
+CONFIG_MSM_ISPIF=y
+CONFIG_MSMB_CAMERA=y
+CONFIG_OV9724=y
+CONFIG_MSMB_JPEG=y
+CONFIG_SWITCH=y
+CONFIG_MSM_WFD=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_VIDEOBUF2_MSM_MEM=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_RADIO_IRIS=y
+CONFIG_RADIO_IRIS_TRANSPORT=m
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_MSM_KGSL=y
+CONFIG_FB=y
+CONFIG_FB_MSM=y
+# CONFIG_FB_MSM_BACKLIGHT is not set
+CONFIG_FB_MSM_MDSS=y
+CONFIG_FB_MSM_MDSS_WRITEBACK=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8226=y
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_DEBUG_FS=y
+CONFIG_USB_CI13XXX_MSM=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_MMC=y
+CONFIG_MMC_PERF_PROFILING=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_EMBEDDED_SDIO=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=m
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_MSM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_MSM_SPS_SUPPORT=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_MSM is not set
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_SPS=y
+CONFIG_USB_BAM=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_PWM=y
+CONFIG_QPNP_POWER_ON=y
+CONFIG_MSM_IOMMU=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_TMC=y
+CONFIG_CORESIGHT_TPIU=y
+CONFIG_CORESIGHT_FUNNEL=y
+CONFIG_CORESIGHT_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_ETM=y
+CONFIG_CORESIGHT_EVENT=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAIL_PAGE_ALLOC=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_USER=y
+CONFIG_KEYS=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=y
+CONFIG_QPNP_VIBRATOR=y
+CONFIG_QSEECOM=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_QCRYPTO=m
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 7bf54ce..7991f02 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -205,6 +205,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
CONFIG_WCNSS_CORE=y
@@ -248,6 +249,7 @@
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9306_CODEC=y
CONFIG_REGULATOR_STUB=y
@@ -384,4 +386,4 @@
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
-CONFIG_CRYPTO_DEV_QCEDEV=m
\ No newline at end of file
+CONFIG_CRYPTO_DEV_QCEDEV=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 368078e..73bf4f9 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -273,7 +273,6 @@
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
CONFIG_SWITCH=y
-CONFIG_MSM_WFD=y
CONFIG_MSM_VIDC_V4L2=y
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_V4L_PLATFORM_DRIVERS=y
@@ -357,7 +356,6 @@
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
-CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_KEYS=y
CONFIG_CRYPTO_MD4=y
@@ -367,4 +365,4 @@
CONFIG_CRC_CCITT=y
CONFIG_QPNP_VIBRATOR=y
CONFIG_QSEECOM=y
-CONFIG_IOSCHED_TEST=y
\ No newline at end of file
+CONFIG_IOSCHED_TEST=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 72032dc..b933faa 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -368,6 +368,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 091cdd9..cfdbb29a 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -374,6 +374,7 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
+CONFIG_SND_SOC_APQ8074=y
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 5a85f14..71f4827 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -23,6 +23,7 @@
extern void disable_hlt(void);
extern void enable_hlt(void);
+extern int get_hlt(void);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index bee7f9d..24bc80b 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -26,6 +26,18 @@
void __init early_init_dt_add_memory_arch(u64 base, u64 size)
{
+#ifndef CONFIG_ARM_LPAE
+ if (base > ((phys_addr_t)~0)) {
+ pr_crit("Ignoring memory at 0x%08llx due to lack of LPAE support\n",
+ base);
+ return;
+ }
+
+ if (size > ((phys_addr_t)~0))
+ size = ((phys_addr_t)~0);
+
+ /* arm_add_memory() already checks for the case of base + size > 4GB */
+#endif
arm_add_memory(base, size);
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index e7a9237..fe97ff2 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -86,6 +86,12 @@
EXPORT_SYMBOL(enable_hlt);
+int get_hlt(void)
+{
+ return hlt_counter;
+}
+EXPORT_SYMBOL(get_hlt);
+
static int __init nohlt_setup(char *__unused)
{
hlt_counter = 1;
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index fa3344d..87eeb7f 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -111,31 +111,15 @@
obj-$(CONFIG_MSM_IPC_LOGGING) += ipc_logging_debug.o
endif
obj-y += socinfo.o
-ifndef CONFIG_ARCH_MSM8960
-ifndef CONFIG_ARCH_MSM8X60
-ifndef CONFIG_ARCH_APQ8064
-ifndef CONFIG_ARCH_MSM8974
-ifndef CONFIG_ARCH_MSM8226
-ifndef CONFIG_ARCH_MSM9625
-ifndef CONFIG_ARCH_MPQ8092
-ifndef CONFIG_ARCH_MSM8610
-ifndef CONFIG_ARCH_APQ8084
-ifndef CONFIG_ARCH_MSMKRYPTON
-ifndef CONFIG_ARCH_FSM9900
-ifndef CONFIG_ARCH_MSMSAMARIUM
- obj-y += nand_partitions.o
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
-endif
+obj-$(CONFIG_ARCH_MSM7X01A) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X25) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X30) += nand_partitions.o
+obj-$(CONFIG_ARCH_QSD8X50) += nand_partitions.o
+obj-$(CONFIG_ARCH_FSM9XXX) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM9615) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM8625) += nand_partitions.o
+obj-$(CONFIG_ARCH_MSM7X27A) += nand_partitions.o
obj-$(CONFIG_MSM_SDIO_TTY) += sdio_tty.o
obj-$(CONFIG_MSM_SMD_TTY) += smd_tty.o
obj-$(CONFIG_MSM_SMD_QMI) += smd_qmi.o
@@ -310,6 +294,7 @@
obj-$(CONFIG_ARCH_MSM9625) += gdsc.o
obj-$(CONFIG_ARCH_MSM8226) += gdsc.o
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
+obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
obj-$(CONFIG_ARCH_MSM8974) += krait-regulator.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
@@ -319,7 +304,7 @@
obj-$(CONFIG_ARCH_MPQ8092) += board-8092.o board-8092-gpiomux.o
obj-$(CONFIG_ARCH_MPQ8092) += clock-8092.o
obj-$(CONFIG_ARCH_MSM8226) += board-8226.o board-8226-gpiomux.o
-obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8226.o
+obj-$(CONFIG_ARCH_MSM8226) += clock-local2.o clock-pll.o clock-8226.o clock-rpm.o clock-voter.o clock-mdss-8974.o
obj-$(CONFIG_ARCH_MSM8226) += acpuclock-8226.o acpuclock-cortex.o
obj-$(CONFIG_ARCH_MSM8610) += board-8610.o board-8610-gpiomux.o
obj-$(CONFIG_ARCH_MSM8610) += clock-local2.o clock-pll.o clock-8610.o clock-rpm.o clock-voter.o
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 593e2b1..8303992 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -75,7 +75,7 @@
static struct gpiomux_setting lcd_en_sus_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_DOWN,
+ .pull = GPIOMUX_PULL_UP,
};
static struct gpiomux_setting gpio_keys_active = {
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index 1f0d328..3e1efaf 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -1789,27 +1790,73 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
+struct clk_ops clk_ops_pixel_clock;
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &xo.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8226.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -1819,7 +1866,7 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8226.c,
.dbg_name = "pclk0_clk_src",
.ops = &clk_ops_pixel,
VDD_DIG_FMAX_MAP2(LOW, 83330000, NOMINAL, 166670000),
@@ -2006,7 +2053,7 @@
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8226.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -2017,7 +2064,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8226.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP2(LOW, 62500000, NOMINAL, 125000000),
@@ -3465,6 +3512,13 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8226.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8226.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8226.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8226.c, ""),
+ CLK_LOOKUP("", byte_mux_8226.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8226.c, ""),
};
static struct clk_lookup msm_clocks_8226_rumi[] = {
@@ -3600,6 +3654,10 @@
vfe0_clk_src.c.fmax = camss_vfe_vfe0_fmax_v2;
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 53e35ef..3aef106 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -24,6 +24,7 @@
#include <mach/rpm-regulator-smd.h>
#include <mach/socinfo.h>
#include <mach/rpm-smd.h>
+#include <mach/clock-generic.h>
#include "clock-local2.h"
#include "clock-pll.h"
@@ -784,6 +785,7 @@
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(pnoc_pm_clk, &pnoc_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);
@@ -3011,26 +3013,9 @@
},
};
-static struct branch_clk mdss_ahb_clk;
-static struct clk dsipll0_byte_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_byte_clk_src",
- .ops = &clk_ops_dsi_byte_pll,
- CLK_INIT(dsipll0_byte_clk_src),
-};
-
-static struct clk dsipll0_pixel_clk_src = {
- .depends = &mdss_ahb_clk.c,
- .parent = &cxo_clk_src.c,
- .dbg_name = "dsipll0_pixel_clk_src",
- .ops = &clk_ops_dsi_pixel_pll,
- CLK_INIT(dsipll0_pixel_clk_src),
-};
-
static struct clk_freq_tbl byte_freq_tbl[] = {
{
- .src_clk = &dsipll0_byte_clk_src,
+ .src_clk = &byte_clk_src_8974.c,
.div_src_val = BVAL(10, 8, dsipll0_byte_mm_source_val),
},
F_END
@@ -3041,7 +3026,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte0_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3055,7 +3040,7 @@
.current_freq = byte_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_byte_clk_src,
+ .parent = &byte_clk_src_8974.c,
.dbg_name = "byte1_clk_src",
.ops = &clk_ops_byte,
VDD_DIG_FMAX_MAP3(LOW, 93800000, NOMINAL, 187500000,
@@ -3235,10 +3220,73 @@
},
};
+struct clk_ops clk_ops_pixel_clock;
+
+static long round_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ return (src_rate * frac_num[i]) / frac_den[i];
+ }
+
+ return -EINVAL;
+}
+
+
+static int set_rate_pixel(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+ int frac_num[] = {3, 2, 4, 1};
+ int frac_den[] = {8, 9, 9, 1};
+ int delta = 100000;
+ int i, rc;
+
+ for (i = 0; i < ARRAY_SIZE(frac_num); i++) {
+ unsigned long request = (rate * frac_den[i]) / frac_num[i];
+ unsigned long src_rate;
+
+ src_rate = clk_round_rate(clk->parent, request);
+ if ((src_rate < (request - delta)) ||
+ (src_rate > (request + delta)))
+ continue;
+
+ rc = clk_set_rate(clk->parent, src_rate);
+ if (rc)
+ return rc;
+
+ pixel_freq->div_src_val &= ~BM(4, 0);
+ if (frac_den[i] == frac_num[i]) {
+ pixel_freq->m_val = 0;
+ pixel_freq->n_val = 0;
+ } else {
+ pixel_freq->m_val = frac_num[i];
+ pixel_freq->n_val = ~(frac_den[i] - frac_num[i]);
+ pixel_freq->d_val = ~frac_den[i];
+ }
+ set_rate_mnd(rcg, pixel_freq);
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct clk_freq_tbl pixel_freq_tbl[] = {
{
- .src_clk = &dsipll0_pixel_clk_src,
- .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val),
+ .src_clk = &pixel_clk_src_8974.c,
+ .div_src_val = BVAL(10, 8, dsipll0_pixel_mm_source_val)
+ | BVAL(4, 0, 0),
},
F_END
};
@@ -3248,9 +3296,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk0_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk0_clk_src.c),
},
@@ -3261,9 +3309,9 @@
.current_freq = pixel_freq_tbl,
.base = &virt_bases[MMSS_BASE],
.c = {
- .parent = &dsipll0_pixel_clk_src,
+ .parent = &pixel_clk_src_8974.c,
.dbg_name = "pclk1_clk_src",
- .ops = &clk_ops_pixel,
+ .ops = &clk_ops_pixel_clock,
VDD_DIG_FMAX_MAP2(LOW, 125000000, NOMINAL, 250000000),
CLK_INIT(pclk1_clk_src.c),
},
@@ -5171,6 +5219,7 @@
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_clk", pnoc_pm_clk.c, "pm_8x60"),
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"),
@@ -5252,6 +5301,14 @@
CLK_LOOKUP("krait1_m_clk", krait1_m_clk, ""),
CLK_LOOKUP("krait2_m_clk", krait2_m_clk, ""),
CLK_LOOKUP("krait3_m_clk", krait3_m_clk, ""),
+
+ /* DSI PLL clocks */
+ CLK_LOOKUP("", dsi_vco_clk_8974.c, ""),
+ CLK_LOOKUP("", analog_postdiv_clk_8974.c, ""),
+ CLK_LOOKUP("", indirect_path_div2_clk_8974.c, ""),
+ CLK_LOOKUP("", pixel_clk_src_8974.c, ""),
+ CLK_LOOKUP("", byte_mux_8974.c, ""),
+ CLK_LOOKUP("", byte_clk_src_8974.c, ""),
};
static struct pll_config_regs mmpll0_regs __initdata = {
@@ -5534,6 +5591,10 @@
qup_i2c_clks[i][0]->parent = qup_i2c_clks[i][1];
}
+ clk_ops_pixel_clock = clk_ops_pixel;
+ clk_ops_pixel_clock.set_rate = set_rate_pixel;
+ clk_ops_pixel_clock.round_rate = round_rate_pixel;
+
/*
* MDSS needs the ahb clock and needs to init before we register the
* lookup table.
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 24af44e..fd790e2 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -698,7 +698,7 @@
enum handoff pixel_rcg_handoff(struct clk *clk)
{
struct rcg_clk *rcg = to_rcg_clk(clk);
- u32 div_val, mval, nval, cfg_regval;
+ u32 div_val = 0, mval = 0, nval = 0, cfg_regval;
unsigned long pre_div_rate, parent_rate = clk_get_rate(clk->parent);
cfg_regval = readl_relaxed(CFG_RCGR_REG(rcg));
@@ -712,6 +712,15 @@
clk->rate = pre_div_rate;
+ /*
+ * Pixel clocks have one frequency entry in their frequency table.
+ * Update that entry.
+ */
+ if (rcg->current_freq) {
+ rcg->current_freq->div_src_val &= ~CFG_RCGR_DIV_MASK;
+ rcg->current_freq->div_src_val |= div_val;
+ }
+
/* If MND is used, find the rate after the MND division */
if ((cfg_regval & MND_MODE_MASK) == MND_DUAL_EDGE_MODE_BVAL) {
mval = readl_relaxed(M_REG(rcg));
@@ -719,6 +728,11 @@
if (!nval)
return HANDOFF_DISABLED_CLK;
nval = (~nval) + mval;
+ if (rcg->current_freq) {
+ rcg->current_freq->n_val = ~(nval - mval);
+ rcg->current_freq->m_val = mval;
+ rcg->current_freq->d_val = ~nval;
+ }
clk->rate = (pre_div_rate * mval) / nval;
}
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index f307a2f..cee5b8c 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -34,9 +34,9 @@
struct clk_freq_tbl {
unsigned long freq_hz;
struct clk *src_clk;
- const u32 m_val;
- const u32 n_val;
- const u32 d_val;
+ u32 m_val;
+ u32 n_val;
+ u32 d_val;
u32 div_src_val;
const unsigned sys_vdd;
};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.c b/arch/arm/mach-msm/clock-mdss-8226.c
deleted file mode 100644
index edfaf90..0000000
--- a/arch/arm/mach-msm/clock-mdss-8226.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* 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/io.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/iopoll.h>
-#include <linux/clk.h>
-
-#include <asm/processor.h>
-#include <mach/msm_iomap.h>
-#include <mach/clk-provider.h>
-
-#include "clock-mdss-8226.h"
-
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
-
-#define GDSC_PHYS 0xFD8C2304
-#define GDSC_SIZE 0x4
-
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
-
-static unsigned char *mdss_dsi_base;
-static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
-
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
-static int mdss_gdsc_enabled(void)
-{
- if (!gdsc_base)
- return 0;
-
- return !!(readl_relaxed(gdsc_base) & BIT(31));
-}
-
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_byte_clk_rate;
- } else {
- pr_err("%s: DSI PLL not configured\n", __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- return pll_pclk_rate;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- pr_debug("%s: rate=%ld\n", __func__, rate);
-
- if (pll_initialized)
- return 0;
-
- REG_W(0x70, mdss_dsi_base + 0x0230); /* LPFC1 CFG */
- REG_W(0x08, mdss_dsi_base + 0x022c); /* LPFR CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0204); /* postDiv1 */
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x03, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
- REG_W(0x0b, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- REG_W(0x00, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- REG_W(0x6c, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- REG_W(0x31, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x15, mdss_dsi_base + 0x0234); /* LPFC2 CFG */
-
- REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- REG_W(0x60, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- REG_W(0xdd, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
-
- REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
- REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- /*
- * Add hardware recommended delays after toggling the
- * software reset bit off and back on.
- */
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(300);
-}
-
-static void mdss_dsi_pll_enable_casem(void)
-{
- int i;
-
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; (i < 3) && !mdss_dsi_check_pll_lock(); i++) {
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- }
-
- if (pll_initialized)
- pr_debug("%s: PLL Locked after %d attempts\n", __func__, i);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casef1(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_cased(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casec(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static void mdss_dsi_pll_enable_casee(void)
-{
- /*
- * Add hardware recommended delays between register writes for
- * the updates to take effect. These delays are necessary for the
- * PLL to successfully lock.
- */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(200);
- REG_W(0x0d, mdss_dsi_base + 0x0220); /* GLB CFG */
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- if (mdss_dsi_check_pll_lock())
- pr_debug("%s: PLL Locked\n", __func__);
- else
- pr_debug("%s: PLL failed to lock\n", __func__);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- /*
- * Try all PLL power-up sequences one-by-one until
- * PLL lock is detected
- */
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casem();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_cased();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casef1();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casec();
- if (pll_initialized)
- goto pll_locked;
-
- mdss_dsi_uniphy_pll_sw_reset();
- mdss_dsi_pll_enable_casee();
- if (pll_initialized)
- goto pll_locked;
-
- pr_err("%s: DSI PLL failed to Lock\n", __func__);
- return -EINVAL;
-
-pll_locked:
- pr_debug("%s: PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: PLL disabled\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 59000000;
- dsi_pll_rate = 59000000;
- pll_byte_clk_rate = 59000000;
- pll_pclk_rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-/* todo: Adjust these values appropriately */
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled()) {
- clk_prepare_enable(mdss_dsi_ahb_clk);
- if (mdss_dsi_check_pll_lock()) {
- c->rate = 117000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
-};
-
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
-};
diff --git a/arch/arm/mach-msm/clock-mdss-8226.h b/arch/arm/mach-msm/clock-mdss-8226.h
deleted file mode 100644
index dcf4f92..0000000
--- a/arch/arm/mach-msm/clock-mdss-8226.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 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_MDSS_8226
-#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226
-
-extern struct clk_ops clk_ops_dsi_byte_pll;
-extern struct clk_ops clk_ops_dsi_pixel_pll;
-
-void mdss_clk_ctrl_pre_init(struct clk *ahb_clk);
-void mdss_clk_ctrl_post_init(void);
-
-#endif /* __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8226 */
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 17a6801..1245287 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -21,17 +21,21 @@
#include <asm/processor.h>
#include <mach/msm_iomap.h>
#include <mach/clk-provider.h>
+#include <mach/clk.h>
+#include <mach/clock-generic.h>
#include "clock-mdss-8974.h"
-#define REG_R(addr) readl_relaxed(addr)
-#define REG_W(data, addr) writel_relaxed(data, addr)
+#define REG_R(addr) readl_relaxed(addr)
+#define REG_W(data, addr) writel_relaxed(data, addr)
+#define DSS_REG_W(base, offset, data) REG_W((data), (base) + (offset))
+#define DSS_REG_R(base, offset) REG_R((base) + (offset))
#define GDSC_PHYS 0xFD8C2304
#define GDSC_SIZE 0x4
-#define DSI_PHY_PHYS 0xFD922800
-#define DSI_PHY_SIZE 0x00000800
+#define DSI_PHY_PHYS 0xFD922A00
+#define DSI_PHY_SIZE 0x000000D4
#define HDMI_PHY_PHYS 0xFD922500
#define HDMI_PHY_SIZE 0x0000007C
@@ -100,45 +104,60 @@
#define HDMI_UNI_PLL_CAL_CFG11 (0x0098)
#define HDMI_UNI_PLL_STATUS (0x00C0)
-#define VCO_CLK 424000000
+#define DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x00000000)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x00000004)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG (0x00000008)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x0000000C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG (0x00000010)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG (0x00000014)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_DMUX_CFG (0x00000018)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_AMUX_CFG (0x0000001C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x00000020)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x00000024)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x00000028)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG (0x0000002C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG (0x00000030)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG (0x00000034)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x00000038)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x0000003C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x00000040)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x00000044)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x00000048)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG0 (0x0000004C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG1 (0x00000050)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG2 (0x00000054)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_SSC_CFG3 (0x00000058)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG0 (0x0000005C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG1 (0x00000060)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x00000064)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x00000068)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x0000006C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x00000070)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x00000074)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3 (0x00000078)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4 (0x0000007C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG5 (0x00000080)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x00000084)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x00000088)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x0000008C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x00000090)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x00000094)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x00000098)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG (0x0000009C)
+#define DSI_0_PHY_PLL_UNIPHY_PLL_STATUS (0x000000C0)
+
+#define PLL_POLL_MAX_READS 10
+#define PLL_POLL_TIMEOUT_US 50
+
+static long vco_cached_rate;
static unsigned char *mdss_dsi_base;
static unsigned char *gdsc_base;
-static int pll_byte_clk_rate;
-static int pll_pclk_rate;
-static int pll_initialized;
-static struct clk *mdss_dsi_ahb_clk;
-static unsigned long dsi_pll_rate;
+static struct clk *mdss_ahb_clk;
static void __iomem *hdmi_phy_base;
static void __iomem *hdmi_phy_pll_base;
static unsigned hdmi_pll_on;
-void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
-{
- BUG_ON(ahb_clk == NULL);
-
- gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
- if (!gdsc_base)
- pr_err("%s: unable to remap gdsc base", __func__);
-
- mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
- if (!mdss_dsi_base)
- pr_err("%s: unable to remap dsi base", __func__);
-
- mdss_dsi_ahb_clk = ahb_clk;
-
- hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
- if (!hdmi_phy_base)
- pr_err("%s: unable to ioremap hdmi phy base", __func__);
-
- hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
- if (!hdmi_phy_pll_base)
- pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
-}
-
-#define PLL_POLL_MAX_READS 10
-#define PLL_POLL_TIMEOUT_US 50
-
static int mdss_gdsc_enabled(void)
{
if (!gdsc_base)
@@ -147,297 +166,13 @@
return !!(readl_relaxed(gdsc_base) & BIT(31));
}
-static int mdss_dsi_check_pll_lock(void)
-{
- u32 status;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- /* poll for PLL ready status */
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & BIT(0)) == 1),
- PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pll_initialized = 0;
- } else {
- pll_initialized = 1;
- }
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return pll_initialized;
-}
-
-static long mdss_dsi_pll_byte_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_byte_clk_rate;
- else {
- pr_err("%s: DSI PLL not configured\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static long mdss_dsi_pll_pixel_round_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized)
- return pll_pclk_rate;
- else {
- pr_err("%s: Configure Byte clk first\n",
- __func__);
- return -EINVAL;
- }
-}
-
-static int mdss_dsi_pll_pixel_set_rate(struct clk *c, unsigned long rate)
-{
- if (pll_initialized) {
- pll_pclk_rate = rate;
- pr_debug("%s: pll_pclk_rate=%d\n", __func__, pll_pclk_rate);
- return 0;
- } else {
- pr_err("%s: Configure Byte clk first\n", __func__);
- return -EINVAL;
- }
-}
-
-static int __mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int pll_divcfg1, pll_divcfg2;
- int half_bitclk_rate;
-
- pr_debug("%s:\n", __func__);
- if (pll_initialized)
- return 0;
-
- half_bitclk_rate = rate * 4;
-
- pll_divcfg1 = (VCO_CLK / half_bitclk_rate) - 2;
-
- /* Configuring the VCO to 424 Mhz */
- /* Configuring the half rate Bit clk to 212 Mhz */
-
- pll_divcfg2 = 3; /* ByteClk is 1/4 the half-bitClk rate */
-
- /* Configure the Loop filter */
- /* Loop filter resistance value */
- REG_W(0x08, mdss_dsi_base + 0x022c);
- /* Loop filter capacitance values : c1 and c2 */
- REG_W(0x70, mdss_dsi_base + 0x0230);
- REG_W(0x15, mdss_dsi_base + 0x0234);
-
- REG_W(0x02, mdss_dsi_base + 0x0208); /* ChgPump */
- REG_W(pll_divcfg1, mdss_dsi_base + 0x0204); /* postDiv1 */
- REG_W(pll_divcfg2, mdss_dsi_base + 0x0224); /* postDiv2 */
- REG_W(0x05, mdss_dsi_base + 0x0228); /* postDiv3 */
-
- REG_W(0x2b, mdss_dsi_base + 0x0278); /* Cal CFG3 */
- REG_W(0x66, mdss_dsi_base + 0x027c); /* Cal CFG4 */
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDET CFG2 */
-
- REG_W(0x0a, mdss_dsi_base + 0x023c); /* SDM CFG1 */
- REG_W(0xab, mdss_dsi_base + 0x0240); /* SDM CFG2 */
- REG_W(0x0a, mdss_dsi_base + 0x0244); /* SDM CFG3 */
- REG_W(0x00, mdss_dsi_base + 0x0248); /* SDM CFG4 */
-
- REG_W(0x01, mdss_dsi_base + 0x0200); /* REFCLK CFG */
- REG_W(0x00, mdss_dsi_base + 0x0214); /* PWRGEN CFG */
- REG_W(0x71, mdss_dsi_base + 0x020c); /* VCOLPF CFG */
- REG_W(0x02, mdss_dsi_base + 0x0210); /* VREG CFG */
- REG_W(0x00, mdss_dsi_base + 0x0238); /* SDM CFG0 */
-
- REG_W(0x5f, mdss_dsi_base + 0x028c); /* CAL CFG8 */
- REG_W(0xa8, mdss_dsi_base + 0x0294); /* CAL CFG10 */
- REG_W(0x01, mdss_dsi_base + 0x0298); /* CAL CFG11 */
- REG_W(0x0a, mdss_dsi_base + 0x026c); /* CAL CFG0 */
- REG_W(0x30, mdss_dsi_base + 0x0284); /* CAL CFG6 */
- REG_W(0x00, mdss_dsi_base + 0x0288); /* CAL CFG7 */
- REG_W(0x00, mdss_dsi_base + 0x0290); /* CAL CFG9 */
- REG_W(0x20, mdss_dsi_base + 0x029c); /* EFUSE CFG */
-
- dsi_pll_rate = rate;
- pll_byte_clk_rate = rate;
-
- pr_debug("%s: PLL initialized. bcl=%d\n", __func__, pll_byte_clk_rate);
- pll_initialized = 1;
-
- return 0;
-}
-
-static int mdss_dsi_pll_byte_set_rate(struct clk *c, unsigned long rate)
-{
- int ret;
-
- clk_prepare_enable(mdss_dsi_ahb_clk);
- ret = __mdss_dsi_pll_byte_set_rate(c, rate);
- clk_disable_unprepare(mdss_dsi_ahb_clk);
-
- return ret;
-}
-
-static void mdss_dsi_uniphy_pll_lock_detect_setting(void)
-{
- REG_W(0x04, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(100);
- REG_W(0x05, mdss_dsi_base + 0x0264); /* LKDetect CFG2 */
- udelay(500);
-}
-
-static void mdss_dsi_uniphy_pll_sw_reset(void)
-{
- REG_W(0x01, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
- REG_W(0x00, mdss_dsi_base + 0x0268); /* PLL TEST CFG */
- udelay(1);
-}
-
-static int __mdss_dsi_pll_enable(struct clk *c)
-{
- u32 status;
- u32 max_reads, timeout_us;
- int i;
-
- if (!pll_initialized) {
- if (dsi_pll_rate)
- __mdss_dsi_pll_byte_set_rate(c, dsi_pll_rate);
- else
- pr_err("%s: Calling clk_en before set_rate\n",
- __func__);
- }
-
- mdss_dsi_uniphy_pll_sw_reset();
- /* PLL power up */
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
-
- for (i = 0; i < 3; i++) {
- mdss_dsi_uniphy_pll_lock_detect_setting();
- /* poll for PLL ready status */
- max_reads = 5;
- timeout_us = 100;
- if (readl_poll_timeout_noirq((mdss_dsi_base + 0x02c0),
- status,
- ((status & 0x01) == 1),
- max_reads, timeout_us)) {
- pr_debug("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- pr_debug("%s:Trying to power UP PLL again\n",
- __func__);
- } else
- break;
-
- mdss_dsi_uniphy_pll_sw_reset();
- udelay(1000);
- /* Add HW recommended delay between
- register writes for the update to propagate */
- REG_W(0x01, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x05, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x07, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(1000);
- REG_W(0x0f, mdss_dsi_base + 0x0220); /* GLB CFG */
- udelay(2000);
-
- }
-
- if ((status & 0x01) != 1) {
- pr_err("%s: DSI PLL status=%x failed to Lock\n",
- __func__, status);
- return -EINVAL;
- }
-
- pr_debug("%s: **** PLL Lock success\n", __func__);
-
- return 0;
-}
-
-static void __mdss_dsi_pll_disable(void)
-{
- writel_relaxed(0x00, mdss_dsi_base + 0x0220); /* GLB CFG */
- pr_debug("%s: **** disable pll Initialize\n", __func__);
- pll_initialized = 0;
-}
-
-static DEFINE_SPINLOCK(dsipll_lock);
-static int dsipll_refcount;
-
-static void mdss_dsi_pll_disable(struct clk *c)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (WARN(dsipll_refcount == 0, "DSI PLL clock is unbalanced"))
- goto out;
- if (dsipll_refcount == 1)
- __mdss_dsi_pll_disable();
- dsipll_refcount--;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
-}
-
-static int mdss_dsi_pll_enable(struct clk *c)
-{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&dsipll_lock, flags);
- if (dsipll_refcount == 0) {
- ret = __mdss_dsi_pll_enable(c);
- if (ret < 0)
- goto out;
- }
- dsipll_refcount++;
-out:
- spin_unlock_irqrestore(&dsipll_lock, flags);
- return ret;
-}
-
-static enum handoff mdss_dsi_pll_byte_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 52954560;
- dsi_pll_rate = 52954560;
- pll_byte_clk_rate = 52954560;
- pll_pclk_rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
-static enum handoff mdss_dsi_pll_pixel_handoff(struct clk *c)
-{
- if (mdss_gdsc_enabled() && mdss_dsi_check_pll_lock()) {
- c->rate = 105000000;
- dsipll_refcount++;
- return HANDOFF_ENABLED_CLK;
- }
-
- return HANDOFF_DISABLED_CLK;
-}
-
void hdmi_pll_disable(void)
{
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
REG_W(0x0, hdmi_phy_pll_base + HDMI_UNI_PLL_GLB_CFG);
udelay(5);
REG_W(0x0, hdmi_phy_base + HDMI_PHY_GLB_CFG);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 0;
} /* hdmi_pll_disable */
@@ -447,7 +182,7 @@
u32 status;
u32 max_reads, timeout_us;
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
/* Global Enable */
REG_W(0x81, hdmi_phy_base + HDMI_PHY_GLB_CFG);
/* Power up power gen */
@@ -473,7 +208,7 @@
pr_err("%s: hdmi phy pll status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy pll is locked\n", __func__);
@@ -487,11 +222,11 @@
pr_err("%s: hdmi phy status=%x failed to Lock\n",
__func__, status);
hdmi_pll_disable();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
return -EINVAL;
}
pr_debug("%s: hdmi phy is locked\n", __func__);
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
hdmi_pll_on = 1;
@@ -507,7 +242,7 @@
set_power_dwn = 1;
}
- clk_enable(mdss_dsi_ahb_clk);
+ clk_enable(mdss_ahb_clk);
pr_debug("%s: rate=%ld\n", __func__, rate);
switch (rate) {
case 0:
@@ -922,7 +657,7 @@
/* Make sure writes complete before disabling iface clock */
mb();
- clk_disable(mdss_dsi_ahb_clk);
+ clk_disable(mdss_ahb_clk);
if (set_power_dwn)
hdmi_pll_enable();
@@ -930,18 +665,977 @@
return 0;
} /* hdmi_pll_set_rate */
-struct clk_ops clk_ops_dsi_pixel_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_pixel_set_rate,
- .round_rate = mdss_dsi_pll_pixel_round_rate,
- .handoff = mdss_dsi_pll_pixel_handoff,
+/* Auto PLL calibaration */
+int mdss_ahb_clk_enable(int enable)
+{
+ int rc = 0;
+
+ /* todo: Ideally, we should enable/disable GDSC whenever we are
+ * attempting to enable/disable MDSS AHB clock.
+ * For now, just return error if GDSC is not enabled.
+ */
+ if (!mdss_gdsc_enabled())
+ return -EPERM;
+
+ if (enable)
+ rc = clk_prepare_enable(mdss_ahb_clk);
+ else
+ clk_disable_unprepare(mdss_ahb_clk);
+
+ return rc;
+}
+
+int set_byte_mux_sel(struct mux_clk *clk, int sel)
+{
+ pr_debug("%s: byte mux set to %s mode\n", __func__,
+ sel ? "indirect" : "direct");
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG,
+ (sel << 1));
+ return 0;
+}
+
+int get_byte_mux_sel(struct mux_clk *clk)
+{
+ int mux_mode;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 0;
+ }
+
+ mux_mode = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VREG_CFG)
+ & BIT(1);
+ pr_debug("%s: byte mux mode = %s", __func__,
+ mux_mode ? "indirect" : "direct");
+
+ mdss_ahb_clk_enable(0);
+ return !!mux_mode;
+}
+
+static inline struct dsi_pll_vco_clk *to_vco_clk(struct clk *clk)
+{
+ return container_of(clk, struct dsi_pll_vco_clk, c);
+}
+
+/*
+ * When the display is turned off, the display registers are wiped out.
+ * Temporarily use the prepare ops to restore the register values.
+ *
+*/
+int div_prepare(struct clk *c)
+{
+ struct div_clk *div = to_div_clk(c);
+ /* Restore the divider's value */
+ return div->ops->set_div(div, div->div);
+}
+
+int mux_prepare(struct clk *c)
+{
+ struct mux_clk *mux = to_mux_clk(c);
+ int i, rc, sel = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ for (i = 0; i < mux->num_parents; i++)
+ if (mux->parents[i].src == c->parent) {
+ sel = mux->parents[i].sel;
+ break;
+ }
+
+ if (i == mux->num_parents) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ /* Restore the mux source select value */
+ rc = mux->ops->set_mux_sel(mux, sel);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+static int fixed_4div_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int fixed_4div_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int digital_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG,
+ (div - 1));
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int digital_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG);
+ mdss_ahb_clk_enable(0);
+ return div + 1;
+}
+
+static int analog_set_div(struct div_clk *clk, int div)
+{
+ int rc = 0;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG,
+ div - 1);
+
+ mdss_ahb_clk_enable(0);
+ return 0;
+}
+
+static int analog_get_div(struct div_clk *clk)
+{
+ int div = 0;
+
+ if (mdss_ahb_clk_enable(1)) {
+ pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+ return 1;
+ }
+ div = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1;
+ mdss_ahb_clk_enable(0);
+ return div;
+}
+
+static int dsi_pll_lock_status(void)
+{
+ u32 status;
+ int pll_locked = 0;
+
+ /* poll for PLL ready status */
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & BIT(0)) == 1),
+ PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pll_locked = 0;
+ } else {
+ pll_locked = 1;
+ }
+
+ return pll_locked;
+}
+
+static void dsi_pll_software_reset(void)
+{
+ /*
+ * Add HW recommended delays after toggling the software
+ * reset bit off and back on.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00);
+ udelay(1000);
+}
+
+static int dsi_pll_enable_seq_m(void)
+{
+ int i = 0;
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ do {
+ pll_locked = dsi_pll_lock_status();
+ if (!pll_locked) {
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+ i++;
+ }
+ } while ((i < 3) && !pll_locked);
+
+ if (pll_locked)
+ pr_debug("%s: PLL Locked at attempt #%d\n", __func__, i);
+ else
+ pr_debug("%s: PLL failed to lock after %d attempt(s)\n",
+ __func__, i);
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_d(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_f1(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_c(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_e(void)
+{
+ int pll_locked = 0;
+
+ dsi_pll_software_reset();
+
+ /*
+ * Add hardware recommended delays between register writes for
+ * the updates to take effect. These delays are necessary for the
+ * PLL to successfully lock
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(200);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0d);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ pll_locked = dsi_pll_lock_status();
+ pr_debug("%s: PLL status = %s\n", __func__,
+ pll_locked ? "Locked" : "Unlocked");
+
+ return pll_locked ? 0 : -EINVAL;
+}
+
+static int dsi_pll_enable_seq_8974(void)
+{
+ int i, rc = 0;
+ u32 status, max_reads, timeout_us;
+
+ dsi_pll_software_reset();
+
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f);
+ udelay(1000);
+
+ for (i = 0; i < 3; i++) {
+ /* DSI Uniphy lock detect setting */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x04);
+ udelay(100);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2,
+ 0x05);
+ udelay(500);
+ /* poll for PLL ready status */
+ max_reads = 5;
+ timeout_us = 100;
+ if (readl_poll_timeout_noirq((mdss_dsi_base +
+ DSI_0_PHY_PLL_UNIPHY_PLL_STATUS),
+ status,
+ ((status & 0x01) == 1),
+ max_reads, timeout_us)) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ pr_debug("%s:Trying to power UP PLL again\n",
+ __func__);
+ } else {
+ break;
+ }
+
+ dsi_pll_software_reset();
+ /*
+ * PLL power up sequence.
+ * Add necessary delays recommeded by hardware.
+ */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7);
+ udelay(1000);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf);
+ udelay(2000);
+
+ }
+
+ if ((status & 0x01) != 1) {
+ pr_debug("%s: DSI PLL status=%x failed to Lock\n",
+ __func__, status);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ pr_debug("%s: DSI PLL Lock success\n", __func__);
+
+error:
+ return rc;
+}
+
+static int vco_enable(struct clk *c)
+{
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Try all enable sequences until one succeeds */
+ for (i = 0; i < vco->pll_en_seq_cnt; i++) {
+ rc = vco->pll_enable_seqs[i]();
+ pr_debug("%s: DSI PLL %s after sequence #%d\n", __func__,
+ rc ? "unlocked" : "locked", i + 1);
+ if (!rc)
+ break;
+ }
+ clk_disable(mdss_ahb_clk);
+
+ if (rc)
+ pr_err("%s: DSI PLL failed to lock\n", __func__);
+
+ return rc;
+}
+
+static void vco_disable(struct clk *c)
+{
+ int rc = 0;
+
+ rc = clk_enable(mdss_ahb_clk);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return;
+ }
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00);
+
+ clk_disable(mdss_ahb_clk);
+ pr_debug("%s: DSI PLL Disabled\n", __func__);
+ return;
+}
+
+static int vco_set_rate(struct clk *c, unsigned long rate)
+{
+ s64 vco_clk_rate = rate;
+ s32 rem;
+ s64 refclk_cfg, frac_n_mode, ref_doubler_en_b;
+ s64 ref_clk_to_pll, div_fbx1000, frac_n_value;
+ s64 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3;
+ s64 gen_vco_clk, cal_cfg10, cal_cfg11;
+ u32 res;
+ int i, rc = 0;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Configure the Loop filter resistance */
+ for (i = 0; i < vco->lpfr_lut_size; i++)
+ if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate)
+ break;
+ if (i == vco->lpfr_lut_size) {
+ pr_err("%s: unable to get loop filter resistance. vco=%ld\n",
+ __func__, rate);
+ rc = -EINVAL;
+ goto error;
+ }
+ res = vco->lpfr_lut[i].r;
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFR_CFG, res);
+
+ /* Loop filter capacitance values : c1 and c2 */
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15);
+
+ div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem);
+ if (rem) {
+ refclk_cfg = 0x1;
+ frac_n_mode = 1;
+ ref_doubler_en_b = 0;
+ } else {
+ refclk_cfg = 0x0;
+ frac_n_mode = 0;
+ ref_doubler_en_b = 1;
+ }
+
+ pr_debug("%s:refclk_cfg = %lld\n", __func__, refclk_cfg);
+
+ ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (refclk_cfg))
+ + (ref_doubler_en_b * vco->ref_clk_rate));
+ div_fbx1000 = div_s64((vco_clk_rate * 1000), ref_clk_to_pll);
+
+ div_s64_rem(div_fbx1000, 1000, &rem);
+ frac_n_value = div_s64((rem * (1 << 16)), 1000);
+ gen_vco_clk = div_s64(div_fbx1000 * ref_clk_to_pll, 1000);
+
+ pr_debug("%s:ref_clk_to_pll = %lld\n", __func__, ref_clk_to_pll);
+ pr_debug("%s:div_fb = %lld\n", __func__, div_fbx1000);
+ pr_debug("%s:frac_n_value = %lld\n", __func__, frac_n_value);
+
+ pr_debug("%s:Generated VCO Clock: %lld\n", __func__, gen_vco_clk);
+ rem = 0;
+ if (frac_n_mode) {
+ sdm_cfg0 = (0x0 << 5);
+ sdm_cfg0 |= (0x0 & 0x3f);
+ sdm_cfg1 = (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem);
+ sdm_cfg2 = rem;
+ } else {
+ sdm_cfg0 = (0x1 << 5);
+ sdm_cfg0 |= (div_s64(div_fbx1000, 1000) & 0x3f) - 1;
+ sdm_cfg1 = (0x0 & 0x3f);
+ sdm_cfg2 = 0;
+ sdm_cfg3 = 0;
+ }
+
+ pr_debug("%s: sdm_cfg0=%lld\n", __func__, sdm_cfg0);
+ pr_debug("%s: sdm_cfg1=%lld\n", __func__, sdm_cfg1);
+ pr_debug("%s: sdm_cfg2=%lld\n", __func__, sdm_cfg2);
+ pr_debug("%s: sdm_cfg3=%lld\n", __func__, sdm_cfg3);
+
+ cal_cfg11 = div_s64_rem(gen_vco_clk, 256 * 1000000, &rem);
+ cal_cfg10 = rem / 1000000;
+ pr_debug("%s: cal_cfg10=%lld, cal_cfg11=%lld\n", __func__,
+ cal_cfg10, cal_cfg11);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1,
+ (u32)(sdm_cfg1 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2,
+ (u32)(sdm_cfg2 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3,
+ (u32)(sdm_cfg3 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00);
+
+ /* Add hardware recommended delay for correct PLL configuration */
+ udelay(1000);
+
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG,
+ (u32)refclk_cfg);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0,
+ (u32)sdm_cfg0);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x0a);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00);
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG10,
+ (u32)(cal_cfg10 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_CAL_CFG11,
+ (u32)(cal_cfg11 & 0xff));
+ DSS_REG_W(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20);
+
+error:
+ mdss_ahb_clk_enable(0);
+ return rc;
+}
+
+/* rate is the bit clk rate */
+static long vco_round_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long rrate = rate;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+
+ if (rate < vco->min_rate)
+ rrate = vco->min_rate;
+ if (rate > vco->max_rate)
+ rrate = vco->max_rate;
+
+ return rrate;
+}
+
+static unsigned long vco_get_rate(struct clk *c)
+{
+ u32 sdm0, doubler, sdm_byp_div;
+ u64 vco_rate;
+ u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3;
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ u64 ref_clk = vco->ref_clk_rate;
+
+ /* Check to see if the ref clk doubler is enabled */
+ doubler = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_REFCLK_CFG)
+ & BIT(0);
+ ref_clk += (doubler * vco->ref_clk_rate);
+
+ /* see if it is integer mode or sdm mode */
+ sdm0 = DSS_REG_R(mdss_dsi_base, DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0);
+ if (sdm0 & BIT(6)) {
+ /* integer mode */
+ sdm_byp_div = (DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1;
+ vco_rate = ref_clk * sdm_byp_div;
+ } else {
+ /* sdm mode */
+ sdm_dc_off = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF;
+ pr_debug("%s: sdm_dc_off = %d\n", __func__, sdm_dc_off);
+ sdm2 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF;
+ sdm3 = DSS_REG_R(mdss_dsi_base,
+ DSI_0_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF;
+ sdm_freq_seed = (sdm3 << 8) | sdm2;
+ pr_debug("%s: sdm_freq_seed = %d\n", __func__, sdm_freq_seed);
+
+ vco_rate = (ref_clk * (sdm_dc_off + 1)) +
+ mult_frac(ref_clk, sdm_freq_seed, BIT(16));
+ pr_debug("%s: vco rate = %lld", __func__, vco_rate);
+ }
+
+ pr_debug("%s: returning vco rate = %lu\n", __func__,
+ (unsigned long)vco_rate);
+ return (unsigned long)vco_rate;
+}
+
+static enum handoff vco_handoff(struct clk *c)
+{
+ int rc = 0;
+ enum handoff ret = HANDOFF_DISABLED_CLK;
+
+ rc = mdss_ahb_clk_enable(1);
+ if (rc) {
+ pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+ __func__, rc);
+ return ret;
+ }
+ if (dsi_pll_lock_status()) {
+ c->rate = vco_get_rate(c);
+ ret = HANDOFF_ENABLED_CLK;
+ }
+
+ mdss_ahb_clk_enable(0);
+ return ret;
+}
+
+static int vco_prepare(struct clk *c)
+{
+ return vco_set_rate(c, vco_cached_rate);
+}
+
+static void vco_unprepare(struct clk *c)
+{
+ vco_cached_rate = c->rate;
+}
+
+/* Op structures */
+
+static struct clk_ops clk_ops_dsi_vco = {
+ .enable = vco_enable,
+ .disable = vco_disable,
+ .set_rate = vco_set_rate,
+ .round_rate = vco_round_rate,
+ .handoff = vco_handoff,
+ .prepare = vco_prepare,
+ .unprepare = vco_unprepare,
};
-struct clk_ops clk_ops_dsi_byte_pll = {
- .enable = mdss_dsi_pll_enable,
- .disable = mdss_dsi_pll_disable,
- .set_rate = mdss_dsi_pll_byte_set_rate,
- .round_rate = mdss_dsi_pll_byte_round_rate,
- .handoff = mdss_dsi_pll_byte_handoff,
+static struct clk_div_ops fixed_2div_ops;
+
+static struct clk_div_ops fixed_4div_ops = {
+ .set_div = fixed_4div_set_div,
+ .get_div = fixed_4div_get_div,
};
+
+static struct clk_div_ops analog_postdiv_ops = {
+ .set_div = analog_set_div,
+ .get_div = analog_get_div,
+};
+
+static struct clk_div_ops digital_postdiv_ops = {
+ .set_div = digital_set_div,
+ .get_div = digital_get_div,
+};
+
+struct clk_mux_ops byte_mux_ops = {
+ .set_mux_sel = set_byte_mux_sel,
+ .get_mux_sel = get_byte_mux_sel,
+};
+
+struct clk_ops byte_mux_clk_ops;
+
+static struct clk_ops pixel_clk_src_ops;
+static struct clk_ops byte_clk_src_ops;
+static struct clk_ops analog_potsdiv_clk_ops;
+
+/* Display clocks */
+
+struct dsi_pll_vco_clk dsi_vco_clk_8226 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 6,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_m,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_d,
+ .pll_enable_seqs[3] = dsi_pll_enable_seq_f1,
+ .pll_enable_seqs[4] = dsi_pll_enable_seq_c,
+ .pll_enable_seqs[5] = dsi_pll_enable_seq_e,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8226.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8226.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8226 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8226.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8226.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8226 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8226.c),
+ },
+};
+
+struct mux_clk byte_mux_8226 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8226.c, 0},
+ {&indirect_path_div2_clk_8226.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8226.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8226.c),
+ },
+};
+
+struct div_clk byte_clk_src_8226 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8226.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8226.c),
+ },
+};
+
+struct dsi_pll_vco_clk dsi_vco_clk_8974 = {
+ .ref_clk_rate = 19200000,
+ .min_rate = 350000000,
+ .max_rate = 750000000,
+ .pll_en_seq_cnt = 3,
+ .pll_enable_seqs[0] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[1] = dsi_pll_enable_seq_8974,
+ .pll_enable_seqs[2] = dsi_pll_enable_seq_8974,
+ .lpfr_lut_size = 10,
+ .lpfr_lut = (struct lpfr_cfg[]){
+ {479500000, 8},
+ {480000000, 11},
+ {575500000, 8},
+ {576000000, 12},
+ {610500000, 8},
+ {659500000, 9},
+ {671500000, 10},
+ {672000000, 14},
+ {708500000, 10},
+ {750000000, 11},
+ },
+ .c = {
+ .dbg_name = "dsi_vco_clk",
+ .ops = &clk_ops_dsi_vco,
+ CLK_INIT(dsi_vco_clk_8974.c),
+ },
+};
+
+struct div_clk analog_postdiv_clk_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &analog_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "analog_postdiv_clk",
+ .ops = &analog_potsdiv_clk_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(analog_postdiv_clk_8974.c),
+ },
+};
+
+struct div_clk indirect_path_div2_clk_8974 = {
+ .ops = &fixed_2div_ops,
+ .div = 2,
+ .c = {
+ .parent = &analog_postdiv_clk_8974.c,
+ .dbg_name = "indirect_path_div2_clk",
+ .ops = &clk_ops_div,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(indirect_path_div2_clk_8974.c),
+ },
+};
+
+struct div_clk pixel_clk_src_8974 = {
+ .max_div = 255,
+ .min_div = 1,
+ .ops = &digital_postdiv_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "pixel_clk_src",
+ .ops = &pixel_clk_src_ops,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(pixel_clk_src_8974.c),
+ },
+};
+
+struct mux_clk byte_mux_8974 = {
+ .num_parents = 2,
+ .parents = (struct clk_src[]){
+ {&dsi_vco_clk_8974.c, 0},
+ {&indirect_path_div2_clk_8974.c, 1},
+ },
+ .ops = &byte_mux_ops,
+ .c = {
+ .parent = &dsi_vco_clk_8974.c,
+ .dbg_name = "byte_mux",
+ .ops = &byte_mux_clk_ops,
+ CLK_INIT(byte_mux_8974.c),
+ },
+};
+
+struct div_clk byte_clk_src_8974 = {
+ .ops = &fixed_4div_ops,
+ .min_div = 4,
+ .max_div = 4,
+ .c = {
+ .parent = &byte_mux_8974.c,
+ .dbg_name = "byte_clk_src",
+ .ops = &byte_clk_src_ops,
+ CLK_INIT(byte_clk_src_8974.c),
+ },
+};
+
+void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
+{
+ BUG_ON(ahb_clk == NULL);
+
+ gdsc_base = ioremap(GDSC_PHYS, GDSC_SIZE);
+ if (!gdsc_base)
+ pr_err("%s: unable to remap gdsc base", __func__);
+
+ mdss_dsi_base = ioremap(DSI_PHY_PHYS, DSI_PHY_SIZE);
+ if (!mdss_dsi_base)
+ pr_err("%s: unable to remap dsi base", __func__);
+
+ mdss_ahb_clk = ahb_clk;
+
+ hdmi_phy_base = ioremap(HDMI_PHY_PHYS, HDMI_PHY_SIZE);
+ if (!hdmi_phy_base)
+ pr_err("%s: unable to ioremap hdmi phy base", __func__);
+
+ hdmi_phy_pll_base = ioremap(HDMI_PHY_PLL_PHYS, HDMI_PHY_PLL_SIZE);
+ if (!hdmi_phy_pll_base)
+ pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
+
+ pixel_clk_src_ops = clk_ops_slave_div;
+ pixel_clk_src_ops.prepare = div_prepare;
+
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = div_prepare;
+
+ analog_potsdiv_clk_ops = clk_ops_div;
+ analog_potsdiv_clk_ops.prepare = div_prepare;
+
+ byte_mux_clk_ops = clk_ops_gen_mux;
+ byte_mux_clk_ops.prepare = mux_prepare;
+}
+
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index e242669..9fd3026 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -13,6 +13,10 @@
#ifndef __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
#define __ARCH_ARM_MACH_MSM_CLOCK_MDSS_8974
+#include <linux/clk.h>
+
+#define MAX_DSI_PLL_EN_SEQS 10
+
extern struct clk_ops clk_ops_dsi_byte_pll;
extern struct clk_ops clk_ops_dsi_pixel_pll;
@@ -22,4 +26,35 @@
void hdmi_pll_disable(void);
int hdmi_pll_set_rate(unsigned long rate);
+struct lpfr_cfg {
+ unsigned long vco_rate;
+ u32 r;
+};
+
+struct dsi_pll_vco_clk {
+ unsigned long ref_clk_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS])(void);
+ u32 pll_en_seq_cnt;
+ struct lpfr_cfg *lpfr_lut;
+ u32 lpfr_lut_size;
+
+ struct clk c;
+};
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8974;
+extern struct div_clk analog_postdiv_clk_8974;
+extern struct div_clk indirect_path_div2_clk_8974;
+extern struct div_clk pixel_clk_src_8974;
+extern struct mux_clk byte_mux_8974;
+extern struct div_clk byte_clk_src_8974;
+
+extern struct dsi_pll_vco_clk dsi_vco_clk_8226;
+extern struct div_clk analog_postdiv_clk_8226;
+extern struct div_clk indirect_path_div2_clk_8226;
+extern struct div_clk pixel_clk_src_8226;
+extern struct mux_clk byte_mux_8226;
+extern struct div_clk byte_clk_src_8226;
+
#endif
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index e51a1f5..e647d1d 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -114,6 +114,11 @@
#define CPR_NUM_RING_OSC 8
#define CPR_NUM_SAVE_REGS 10
+/* RBCPR Clock Control Register */
+#define RBCPR_CLK_SEL_MASK BIT(0)
+#define RBCPR_CLK_SEL_19P2_MHZ 0
+#define RBCPR_CLK_SEL_AHB_CLK BIT(0)
+
/* CPR eFuse parameters */
#define CPR_FUSE_TARGET_QUOT_BITS 12
#define CPR_FUSE_TARGET_QUOT_BITS_MASK ((1<<CPR_FUSE_TARGET_QUOT_BITS)-1)
@@ -180,6 +185,7 @@
unsigned int cpr_irq;
void __iomem *rbcpr_base;
+ phys_addr_t rbcpr_clk_addr;
struct mutex cpr_mutex;
int ceiling_volt[CPR_CORNER_MAX];
@@ -815,10 +821,23 @@
#define cpr_regulator_resume NULL
#endif
-static void cpr_config(struct cpr_regulator *cpr_vreg)
+static int cpr_config(struct cpr_regulator *cpr_vreg)
{
int i;
- u32 val, gcnt;
+ u32 val, gcnt, reg;
+ void __iomem *rbcpr_clk;
+
+ /* Use 19.2 MHz clock for CPR. */
+ rbcpr_clk = ioremap(cpr_vreg->rbcpr_clk_addr, 4);
+ if (!rbcpr_clk) {
+ pr_err("Unable to map rbcpr_clk\n");
+ return -EINVAL;
+ }
+ reg = readl_relaxed(rbcpr_clk);
+ reg &= ~RBCPR_CLK_SEL_MASK;
+ reg |= RBCPR_CLK_SEL_19P2_MHZ & RBCPR_CLK_SEL_MASK;
+ writel_relaxed(reg, rbcpr_clk);
+ iounmap(rbcpr_clk);
/* Disable interrupt and CPR */
cpr_write(cpr_vreg, REG_RBIF_IRQ_EN(cpr_vreg->irq_line), 0);
@@ -888,6 +907,8 @@
cpr_corner_save(cpr_vreg, CPR_CORNER_SVS);
cpr_corner_save(cpr_vreg, CPR_CORNER_NORMAL);
cpr_corner_save(cpr_vreg, CPR_CORNER_TURBO);
+
+ return 0;
}
static int __init cpr_pvs_init(struct cpr_regulator *cpr_vreg)
@@ -1199,6 +1220,13 @@
}
cpr_vreg->cpr_fuse_addr = res->start;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rbcpr_clk");
+ if (!res || !res->start) {
+ pr_err("missing rbcpr_clk address: res=%p\n", res);
+ return -EINVAL;
+ }
+ cpr_vreg->rbcpr_clk_addr = res->start;
+
rc = cpr_init_cpr_efuse(cpr_vreg);
if (rc)
return rc;
@@ -1227,7 +1255,9 @@
}
/* Configure CPR HW but keep it disabled */
- cpr_config(cpr_vreg);
+ rc = cpr_config(cpr_vreg);
+ if (rc)
+ return rc;
rc = request_threaded_irq(cpr_vreg->cpr_irq, NULL, cpr_irq_handler,
IRQF_TRIGGER_RISING, "cpr", cpr_vreg);
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
index decf9bb..70c696c 100644
--- a/arch/arm/mach-msm/include/mach/iommu.h
+++ b/arch/arm/mach-msm/include/mach/iommu.h
@@ -186,6 +186,22 @@
int attach_count;
};
+struct msm_iommu_context_regs {
+ uint32_t far;
+ uint32_t par;
+ uint32_t fsr;
+ uint32_t fsynr0;
+ uint32_t fsynr1;
+ uint32_t ttbr0;
+ uint32_t ttbr1;
+ uint32_t sctlr;
+ uint32_t actlr;
+ uint32_t prrr;
+ uint32_t nmrr;
+};
+
+void print_ctx_regs(struct msm_iommu_context_regs *regs);
+
/*
* Interrupt handler for the IOMMU context fault interrupt. Hooking the
* interrupt is not supported in the API yet, but this will print an error
@@ -193,6 +209,7 @@
*/
irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id);
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id);
enum {
PROC_APPS,
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 733f5a9..f97d5e4 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -39,12 +39,16 @@
};
#endif
+/*
+ * Ordered by when processors adopted the SMSM protocol. May not be 1-to-1
+ * with SMEM PIDs, despite initial expectations.
+ */
enum {
SMSM_APPS = SMEM_APPS,
SMSM_MODEM = SMEM_MODEM,
SMSM_Q6 = SMEM_Q6,
- SMSM_DSPS = SMEM_DSPS,
- SMSM_WCNSS = SMEM_WCNSS,
+ SMSM_WCNSS,
+ SMSM_DSPS,
};
extern uint32_t SMSM_NUM_HOSTS;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 7fb2c88..f736b30 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -562,6 +562,7 @@
{
msm_shared_ram_phys = MPQ8092_MSM_SHARED_RAM_PHYS;
msm_map_io(mpq8092_io_desc, ARRAY_SIZE(mpq8092_io_desc));
+ of_scan_flat_dt(msm_scan_dt_map_imem, NULL);
}
#endif /* CONFIG_ARCH_MPQ8092 */
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index d7d3081..7a7fb99 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -315,6 +315,8 @@
unsigned long memory_remove_prop_length;
unsigned long memory_size_prop_length;
unsigned int *memory_size_prop;
+ unsigned int *memory_reserve_prop;
+ unsigned long memory_reserve_prop_length;
unsigned int memory_size;
unsigned int memory_start;
int ret;
@@ -326,7 +328,11 @@
"qcom,memblock-remove",
&memory_remove_prop_length);
- if (memory_name_prop || memory_remove_prop) {
+ memory_reserve_prop = of_get_flat_dt_prop(node,
+ "qcom,memblock-reserve",
+ &memory_reserve_prop_length);
+
+ if (memory_name_prop || memory_remove_prop || memory_reserve_prop) {
if (!check_for_compat(node))
goto out;
} else {
@@ -365,7 +371,7 @@
if (memory_remove_prop) {
if (memory_remove_prop_length != (2*sizeof(unsigned int))) {
WARN(1, "Memory remove malformed\n");
- goto out;
+ goto mem_reserve;
}
memory_start = be32_to_cpu(memory_remove_prop[0]);
@@ -380,6 +386,26 @@
memory_start, memory_start+memory_size);
}
+mem_reserve:
+
+ if (memory_reserve_prop) {
+ if (memory_reserve_prop_length != (2*sizeof(unsigned int))) {
+ WARN(1, "Memory reserve malformed\n");
+ goto out;
+ }
+
+ memory_start = be32_to_cpu(memory_reserve_prop[0]);
+ memory_size = be32_to_cpu(memory_reserve_prop[1]);
+
+ ret = memblock_reserve(memory_start, memory_size);
+ if (ret)
+ WARN(1, "Failed to reserve memory %x-%x\n",
+ memory_start, memory_start+memory_size);
+ else
+ pr_info("Node %s memblock_reserve memory %x-%x\n",
+ uname, memory_start, memory_start+memory_size);
+ }
+
out:
return 0;
}
diff --git a/arch/arm/mach-msm/nohlt.c b/arch/arm/mach-msm/nohlt.c
index e598ed0..94cbc4b 100644
--- a/arch/arm/mach-msm/nohlt.c
+++ b/arch/arm/mach-msm/nohlt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009, 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
@@ -28,11 +28,18 @@
return 0;
}
-DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, NULL, set_nohalt, "%llu\n");
+static int get_nohalt(void *data, u64 *val)
+{
+ *val = (unsigned int)get_hlt();
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(nohalt_ops, get_nohalt, set_nohalt, "%llu\n");
static int __init init_hlt_debug(void)
{
- debugfs_create_file("nohlt", 0200, NULL, NULL, &nohalt_ops);
+ debugfs_create_file("nohlt", 0600, NULL, NULL, &nohalt_ops);
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
index 21c4e1e..a3fd6b2 100644
--- a/arch/arm/mach-msm/ocmem_sched.c
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -1060,13 +1060,6 @@
goto invalid_op_error;
}
- region = create_region();
-
- if (!region) {
- pr_err("ocmem: Unable to create region\n");
- goto invalid_op_error;
- }
-
retry = false;
pr_debug("ocmem: do_allocate: %s request %p size %lx\n",
@@ -1081,6 +1074,14 @@
overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
if (overlap_r == NULL) {
+
+ region = create_region();
+
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto invalid_op_error;
+ }
+
/* no conflicting regions, schedule this region */
rc = zone->z_ops->allocate(zone, sz, &alloc_addr);
@@ -1176,7 +1177,6 @@
trigger_eviction:
pr_debug("Trigger eviction of region %p\n", overlap_r);
- destroy_region(region);
return OP_EVICT;
err_not_supported:
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 19b5671..6cd6ffe 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -176,12 +176,25 @@
static int pil_lpass_reset_trusted(struct pil_desc *pil)
{
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ int ret;
+
+ ret = clk_prepare_enable(drv->axi_clk);
+ if (ret)
+ return ret;
return pas_auth_and_reset(PAS_Q6);
}
static int pil_lpass_shutdown_trusted(struct pil_desc *pil)
{
- return pas_shutdown(PAS_Q6);
+ struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ int ret;
+
+ ret = pas_shutdown(PAS_Q6);
+ if (ret)
+ return ret;
+ clk_disable_unprepare(drv->axi_clk);
+ return 0;
}
static struct pil_reset_ops pil_lpass_ops_trusted = {
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 4a54dd4..9d6f176 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/regulator/krait-regulator.h>
#include <linux/cpu.h>
+#include <linux/clk.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <mach/system.h>
@@ -131,6 +132,7 @@
static bool msm_no_ramp_down_pc;
static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
static bool msm_pm_pc_reset_timer;
+static struct clk *pnoc_clk;
static int msm_pm_get_pc_mode(struct device_node *node,
const char *key, uint32_t *pc_mode_val)
@@ -884,7 +886,11 @@
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
collapsed = msm_pm_power_collapse_standalone(true);
- exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
+ else
+ exit_stat
+ = MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE;
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
@@ -894,7 +900,11 @@
collapsed = msm_pm_power_collapse(true);
timer_halted = true;
- exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ if (collapsed)
+ exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ else
+ exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
+
msm_pm_timer_exit_idle(timer_halted);
break;
@@ -1048,6 +1058,7 @@
int ret = -ENODEV;
uint32_t power;
uint32_t msm_pm_max_sleep_time = 0;
+ int collapsed = 0;
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: power collapse\n", __func__);
@@ -1071,7 +1082,7 @@
msm_pm_max_sleep_time,
rs_limits, false, true);
if (!ret) {
- int collapsed = msm_pm_power_collapse(false);
+ collapsed = msm_pm_power_collapse(false);
if (pm_sleep_ops.exit_sleep) {
pm_sleep_ops.exit_sleep(rs_limits,
false, true, collapsed);
@@ -1082,7 +1093,10 @@
__func__);
}
time = msm_pm_timer_exit_suspend(time, period);
- msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ if (collapsed)
+ msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
+ else
+ msm_pm_add_stat(MSM_PM_STAT_FAILED_SUSPEND, time);
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: standalone power collapse\n", __func__);
@@ -1110,9 +1124,24 @@
pm_sleep_ops = *ops;
}
+int msm_suspend_prepare(void)
+{
+ if (pnoc_clk != NULL)
+ clk_disable_unprepare(pnoc_clk);
+ return 0;
+}
+
+void msm_suspend_wake(void)
+{
+ if (pnoc_clk != NULL)
+ clk_prepare_enable(pnoc_clk);
+}
+
static const struct platform_suspend_ops msm_pm_ops = {
.enter = msm_pm_enter,
.valid = suspend_valid_only_mem,
+ .prepare_late = msm_suspend_prepare,
+ .wake = msm_suspend_wake,
};
static int __devinit msm_pm_snoc_client_probe(struct platform_device *pdev)
@@ -1595,6 +1624,18 @@
return rc;
}
+ pnoc_clk = clk_get_sys("pm_8x60", "bus_clk");
+
+ if (IS_ERR(pnoc_clk))
+ pnoc_clk = NULL;
+ else {
+ clk_set_rate(pnoc_clk, 19200000);
+ rc = clk_prepare_enable(pnoc_clk);
+
+ if (rc)
+ pr_err("%s: PNOC clock enable failed\n", __func__);
+ }
+
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index a177593..4649390 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -73,7 +73,6 @@
#endif
#define MODULE_NAME "msm_smd"
-#define SMEM_VERSION 0x000B
#define SMD_VERSION 0x00020000
#define SMSM_SNAPSHOT_CNT 64
#define SMSM_SNAPSHOT_SIZE ((SMSM_NUM_ENTRIES + 1) * 4)
@@ -3802,6 +3801,9 @@
{
int ret;
+ if (!smem_initialized_check())
+ return -ENODEV;
+
SMD_INFO("smd probe\n");
INIT_WORK(&probe_work, smd_channel_probe_worker);
diff --git a/arch/arm/mach-msm/smem.c b/arch/arm/mach-msm/smem.c
index 2204609..bbb6ce0 100644
--- a/arch/arm/mach-msm/smem.c
+++ b/arch/arm/mach-msm/smem.c
@@ -35,6 +35,10 @@
#define OVERFLOW_ADD_UNSIGNED(type, a, b) \
(((type)~0 - (a)) < (b) ? true : false)
+#define MODEM_SBL_VERSION_INDEX 7
+#define SMEM_VERSION_INFO_SIZE (32 * 4)
+#define SMEM_VERSION 0x000B
+
enum {
MSM_SMEM_DEBUG = 1U << 0,
MSM_SMEM_INFO = 1U << 1,
@@ -57,6 +61,7 @@
static void *smem_ramdump_dev;
static DEFINE_MUTEX(spinlock_init_lock);
+static DEFINE_SPINLOCK(smem_init_check_lock);
struct restart_notifier_block {
unsigned processor;
@@ -187,12 +192,48 @@
}
EXPORT_SYMBOL(smem_alloc);
-void *smem_find(unsigned id, unsigned size_in)
+static void *__smem_get_entry(unsigned id, unsigned *size, bool skip_init_check)
+{
+ struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
+ struct smem_heap_entry *toc = shared->heap_toc;
+ int use_spinlocks = spinlocks_initialized;
+ void *ret = 0;
+ unsigned long flags = 0;
+
+ if (!skip_init_check && !smem_initialized_check())
+ return ret;
+
+ if (id >= SMEM_NUM_ITEMS)
+ return ret;
+
+ if (use_spinlocks)
+ remote_spin_lock_irqsave(&remote_spinlock, flags);
+ /* toc is in device memory and cannot be speculatively accessed */
+ if (toc[id].allocated) {
+ phys_addr_t phys_base;
+
+ *size = toc[id].size;
+ barrier();
+
+ phys_base = toc[id].reserved & BASE_ADDR_MASK;
+ if (!phys_base)
+ phys_base = (phys_addr_t)msm_shared_ram_phys;
+ ret = smem_phys_to_virt(phys_base, toc[id].offset);
+ } else {
+ *size = 0;
+ }
+ if (use_spinlocks)
+ remote_spin_unlock_irqrestore(&remote_spinlock, flags);
+
+ return ret;
+}
+
+static void *__smem_find(unsigned id, unsigned size_in, bool skip_init_check)
{
unsigned size;
void *ptr;
- ptr = smem_get_entry(id, &size);
+ ptr = __smem_get_entry(id, &size, skip_init_check);
if (!ptr)
return 0;
@@ -205,6 +246,11 @@
return ptr;
}
+
+void *smem_find(unsigned id, unsigned size_in)
+{
+ return __smem_find(id, size_in, false);
+}
EXPORT_SYMBOL(smem_find);
/* smem_alloc2 returns the pointer to smem item. If it is not allocated,
@@ -218,10 +264,8 @@
void *ret = NULL;
int rc;
- if (!shared->heap_info.initialized) {
- pr_err("%s: smem heap info not initialized\n", __func__);
+ if (!smem_initialized_check())
return NULL;
- }
if (id >= SMEM_NUM_ITEMS)
return NULL;
@@ -268,35 +312,7 @@
void *smem_get_entry(unsigned id, unsigned *size)
{
- struct smem_shared *shared = (void *) MSM_SHARED_RAM_BASE;
- struct smem_heap_entry *toc = shared->heap_toc;
- int use_spinlocks = spinlocks_initialized;
- void *ret = 0;
- unsigned long flags = 0;
-
- if (id >= SMEM_NUM_ITEMS)
- return ret;
-
- if (use_spinlocks)
- remote_spin_lock_irqsave(&remote_spinlock, flags);
- /* toc is in device memory and cannot be speculatively accessed */
- if (toc[id].allocated) {
- phys_addr_t phys_base;
-
- *size = toc[id].size;
- barrier();
-
- phys_base = toc[id].reserved & BASE_ADDR_MASK;
- if (!phys_base)
- phys_base = (phys_addr_t)msm_shared_ram_phys;
- ret = smem_phys_to_virt(phys_base, toc[id].offset);
- } else {
- *size = 0;
- }
- if (use_spinlocks)
- remote_spin_unlock_irqrestore(&remote_spinlock, flags);
-
- return ret;
+ return __smem_get_entry(id, size, false);
}
EXPORT_SYMBOL(smem_get_entry);
@@ -341,6 +357,62 @@
return rc;
}
+/**
+ * smem_initialized_check - Reentrant check that smem has been initialized
+ *
+ * @returns: true if initialized, false if not.
+ */
+bool smem_initialized_check(void)
+{
+ static int checked;
+ static int is_inited;
+ unsigned long flags;
+ struct smem_shared *smem;
+ int *version_array;
+
+ if (likely(checked)) {
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ spin_lock_irqsave(&smem_init_check_lock, flags);
+ if (checked) {
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ if (unlikely(!is_inited))
+ pr_err("%s: smem not initialized\n", __func__);
+ return is_inited;
+ }
+
+ smem = (void *)MSM_SHARED_RAM_BASE;
+
+ if (smem->heap_info.initialized != 1)
+ goto failed;
+ if (smem->heap_info.reserved != 0)
+ goto failed;
+
+ version_array = __smem_find(SMEM_VERSION_INFO, SMEM_VERSION_INFO_SIZE,
+ true);
+ if (version_array == NULL)
+ goto failed;
+ if (version_array[MODEM_SBL_VERSION_INDEX] != SMEM_VERSION << 16)
+ goto failed;
+
+ is_inited = 1;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ return is_inited;
+
+failed:
+ is_inited = 0;
+ checked = 1;
+ spin_unlock_irqrestore(&smem_init_check_lock, flags);
+ pr_err("%s: bootloader failure detected, shared memory not inited\n",
+ __func__);
+ return is_inited;
+}
+EXPORT_SYMBOL(smem_initialized_check);
+
static int restart_notifier_cb(struct notifier_block *this,
unsigned long code,
void *data)
diff --git a/arch/arm/mach-msm/smem_private.h b/arch/arm/mach-msm/smem_private.h
index b631e7c..c4f9a77 100644
--- a/arch/arm/mach-msm/smem_private.h
+++ b/arch/arm/mach-msm/smem_private.h
@@ -71,4 +71,6 @@
* spinlock init code appears non-reentrant
*/
int init_smem_remote_spinlock(void);
+
+bool smem_initialized_check(void);
#endif /* _ARCH_ARM_MACH_MSM_SMEM_PRIVATE_H_ */
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index b956649..8e507ff 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -427,8 +427,10 @@
ret = wait_for_completion_timeout(&subsys->err_ready,
msecs_to_jiffies(10000));
- if (!ret)
+ if (!ret) {
+ pr_err("[%s]: Error ready timed out\n", subsys->desc->name);
return -ETIMEDOUT;
+ }
return 0;
}
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 9a43ea4..156a2a5 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-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
@@ -351,6 +351,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
return 4;
case MDP_Y_CBCR_H2V2:
@@ -407,6 +408,7 @@
case MDP_RGBA_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_RGB_888:
case MDP_RGB_565:
case MDP_BGR_565:
@@ -811,6 +813,7 @@
break;
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
CLR_R, 8),
MSM_ROTATOR_SRC_UNPACK_PATTERN1);
@@ -1118,6 +1121,7 @@
case MDP_XRGB_8888:
case MDP_BGRA_8888:
case MDP_RGBX_8888:
+ case MDP_BGRX_8888:
case MDP_YCBCR_H1V1:
case MDP_YCRCB_H1V1:
rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
@@ -1275,6 +1279,7 @@
case MDP_XRGB_8888:
case MDP_RGBX_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
is_rgb = 1;
info.dst.format = info.src.format;
break;
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index af53543..5051a3a 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-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
@@ -42,7 +42,7 @@
struct ota_dev_control;
struct ota_async_req {
- struct list_head list;
+ struct list_head rlist;
struct completion complete;
int err;
enum qce_ota_oper_enum op;
@@ -52,7 +52,7 @@
struct qce_f8_multi_pkt_req f8_mp_req;
} req;
- struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
};
/*
@@ -68,19 +68,29 @@
/* misc device */
struct miscdevice miscdevice;
+ struct list_head ready_commands;
+ unsigned magic;
+ struct list_head qce_dev;
+ spinlock_t lock;
+ struct mutex register_lock;
+ bool registered;
+ uint32_t total_units;
+};
+struct ota_qce_dev {
+ struct list_head qlist;
/* qce handle */
void *qce;
/* platform device */
struct platform_device *pdev;
- unsigned magic;
-
- struct list_head ready_commands;
struct ota_async_req *active_command;
- spinlock_t lock;
struct tasklet_struct done_tasklet;
+ struct ota_dev_control *podev;
+ uint32_t unit;
+ u32 totalReq;
+ u32 errReq;
};
#define OTA_MAGIC 0x4f544143
@@ -89,7 +99,7 @@
unsigned cmd, unsigned long arg);
static int qcota_open(struct inode *inode, struct file *file);
static int qcota_release(struct inode *inode, struct file *file);
-static int start_req(struct ota_dev_control *podev);
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq);
static const struct file_operations qcota_fops = {
.owner = THIS_MODULE,
@@ -98,35 +108,15 @@
.release = qcota_release,
};
-static struct ota_dev_control qcota_dev[] = {
- {
- .miscdevice = {
+static struct ota_dev_control qcota_dev = {
+ .miscdevice = {
.minor = MISC_DYNAMIC_MINOR,
.name = "qcota0",
.fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
},
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota1",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- },
- {
- .miscdevice = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "qcota2",
- .fops = &qcota_fops,
- },
- .magic = OTA_MAGIC,
- }
+ .magic = OTA_MAGIC,
};
-#define MAX_OTA_DEVICE ARRAY_SIZE(qcota_dev)
-
#define DEBUG_MAX_FNAME 16
#define DEBUG_MAX_RW_BUF 1024
@@ -141,27 +131,22 @@
u32 f9_op_success;
u32 f9_op_fail;
};
-static struct qcota_stat _qcota_stat[MAX_OTA_DEVICE];
+static struct qcota_stat _qcota_stat;
static struct dentry *_debug_dent;
static char _debug_read_buf[DEBUG_MAX_RW_BUF];
-static int _debug_qcota[MAX_OTA_DEVICE];
+static int _debug_qcota;
-static struct ota_dev_control *qcota_minor_to_control(unsigned n)
+static struct ota_dev_control *qcota_control(void)
{
- int i;
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- if (qcota_dev[i].miscdevice.minor == n)
- return &qcota_dev[i];
- }
- return NULL;
+ return &qcota_dev;
}
static int qcota_open(struct inode *inode, struct file *file)
{
struct ota_dev_control *podev;
- podev = qcota_minor_to_control(MINOR(inode->i_rdev));
+ podev = qcota_control();
if (podev == NULL) {
pr_err("%s: no such device %d\n", __func__,
MINOR(inode->i_rdev));
@@ -191,38 +176,52 @@
static void req_done(unsigned long data)
{
- struct ota_dev_control *podev = (struct ota_dev_control *)data;
+ struct ota_qce_dev *pqce = (struct ota_qce_dev *)data;
+ struct ota_dev_control *podev = pqce->podev;
struct ota_async_req *areq;
unsigned long flags;
struct ota_async_req *new_req = NULL;
int ret = 0;
+
spin_lock_irqsave(&podev->lock, flags);
- areq = podev->active_command;
- podev->active_command = NULL;
+
+ areq = pqce->active_command;
+ if (unlikely(areq == NULL))
+ pr_err("ota_crypto: req_done, no active request\n");
+ pqce->active_command = NULL;
again:
if (!list_empty(&podev->ready_commands)) {
new_req = container_of(podev->ready_commands.next,
- struct ota_async_req, list);
- list_del(&new_req->list);
- podev->active_command = new_req;
+ struct ota_async_req, rlist);
+ list_del(&new_req->rlist);
+ pqce->active_command = new_req;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
new_req->err = 0;
- ret = start_req(podev);
- }
+ ret = start_req(pqce, new_req); /* start a new request */
- spin_unlock_irqrestore(&podev->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&podev->lock, flags);
+ };
- if (areq)
+ if (areq) {
complete(&areq->complete);
-
- if (new_req && ret) {
- complete(&new_req->complete);
- spin_lock_irqsave(&podev->lock, flags);
- podev->active_command = NULL;
areq = NULL;
+ };
+
+ /* if error from issuing request */
+ if (unlikely(new_req && ret)) {
+ new_req->err = ret;
+ complete(&new_req->complete);
ret = 0;
new_req = NULL;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+
+ /* try to get next new request */
goto again;
}
@@ -233,64 +232,61 @@
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
areq->req.f9_req.mac_i = (uint32_t) icv;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else
areq->err = 0;
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
static void f8_cb(void *cookie, unsigned char *icv, unsigned char *iv,
int ret)
{
struct ota_async_req *areq = (struct ota_async_req *) cookie;
- struct ota_dev_control *podev;
- struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
- podev = areq->podev;
- pstat = &_qcota_stat[podev->pdev->id];
+ pqce = areq->pqce;
- if (ret)
+ if (ret) {
+ pqce->errReq++;
areq->err = -ENXIO;
- else
+ } else {
areq->err = 0;
+ }
- tasklet_schedule(&podev->done_tasklet);
-};
+ tasklet_schedule(&pqce->done_tasklet);
+}
-static int start_req(struct ota_dev_control *podev)
+static int start_req(struct ota_qce_dev *pqce, struct ota_async_req *areq)
{
- struct ota_async_req *areq;
struct qce_f9_req *pf9;
struct qce_f8_multi_pkt_req *p_mp_f8;
struct qce_f8_req *pf8;
int ret = 0;
- /* start the command on the podev->active_command */
- areq = podev->active_command;
- areq->podev = podev;
+ /* command should be on the podev->active_command */
+ areq->pqce = pqce;
switch (areq->op) {
case QCE_OTA_F8_OPER:
pf8 = &areq->req.f8_req;
- ret = qce_f8_req(podev->qce, pf8, areq, f8_cb);
+ ret = qce_f8_req(pqce->qce, pf8, areq, f8_cb);
break;
case QCE_OTA_MPKT_F8_OPER:
p_mp_f8 = &areq->req.f8_mp_req;
- ret = qce_f8_multi_pkt_req(podev->qce, p_mp_f8, areq, f8_cb);
+ ret = qce_f8_multi_pkt_req(pqce->qce, p_mp_f8, areq, f8_cb);
break;
case QCE_OTA_F9_OPER:
pf9 = &areq->req.f9_req;
- ret = qce_f9_req(podev->qce, pf9, areq, f9_cb);
+ ret = qce_f9_req(pqce->qce, pf9, areq, f9_cb);
break;
default:
@@ -298,32 +294,60 @@
break;
};
areq->err = ret;
+ pqce->totalReq++;
+ if (ret)
+ pqce->errReq++;
return ret;
-};
+}
+
+static struct ota_qce_dev *schedule_qce(struct ota_dev_control *podev)
+{
+ /* do this function with spinlock set */
+ struct ota_qce_dev *p;
+
+ if (unlikely(list_empty(&podev->qce_dev))) {
+ pr_err("%s: no valid qce to schedule\n", __func__);
+ return NULL;
+ }
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ if (p->active_command == NULL)
+ return p;
+ }
+ return NULL;
+}
static int submit_req(struct ota_async_req *areq, struct ota_dev_control *podev)
{
unsigned long flags;
int ret = 0;
struct qcota_stat *pstat;
+ struct ota_qce_dev *pqce;
areq->err = 0;
- spin_lock_irqsave(&podev->lock, flags);
- if (podev->active_command == NULL) {
- podev->active_command = areq;
- ret = start_req(podev);
- } else {
- list_add_tail(&areq->list, &podev->ready_commands);
- }
- if (ret != 0)
- podev->active_command = NULL;
- spin_unlock_irqrestore(&podev->lock, flags);
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce = schedule_qce(podev);
+ if (pqce) {
+ pqce->active_command = areq;
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ ret = start_req(pqce, areq);
+ if (ret != 0) {
+ spin_lock_irqsave(&podev->lock, flags);
+ pqce->active_command = NULL;
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
+
+ } else {
+ list_add_tail(&areq->rlist, &podev->ready_commands);
+ spin_unlock_irqrestore(&podev->lock, flags);
+ }
if (ret == 0)
wait_for_completion(&areq->complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (areq->op) {
case QCE_OTA_F8_OPER:
if (areq->err)
@@ -350,7 +374,7 @@
};
return areq->err;
-};
+}
static long qcota_ioctl(struct file *file,
unsigned cmd, unsigned long arg)
@@ -377,7 +401,7 @@
init_completion(&areq.complete);
- pstat = &_qcota_stat[podev->pdev->id];
+ pstat = &_qcota_stat;
switch (cmd) {
case QCOTA_F9_REQ:
@@ -523,67 +547,112 @@
int rc = 0;
struct ota_dev_control *podev;
struct ce_hw_support ce_support;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- if (pdev->id >= MAX_OTA_DEVICE) {
- pr_err("%s: device id %d exceeds allowed %d\n",
- __func__, pdev->id, MAX_OTA_DEVICE);
- return -ENOENT;
+ podev = &qcota_dev;
+ pqce = kzalloc(sizeof(*pqce), GFP_KERNEL);
+ if (!pqce) {
+ pr_err("qcota_probe: Memory allocation FAIL\n");
+ return -ENOMEM;
}
- podev = &qcota_dev[pdev->id];
-
- INIT_LIST_HEAD(&podev->ready_commands);
- podev->active_command = NULL;
- spin_lock_init(&podev->lock);
- tasklet_init(&podev->done_tasklet, req_done, (unsigned long)podev);
+ pqce->podev = podev;
+ pqce->active_command = NULL;
+ tasklet_init(&pqce->done_tasklet, req_done, (unsigned long)pqce);
/* open qce */
handle = qce_open(pdev, &rc);
if (handle == NULL) {
- pr_err("%s: device id %d, can not open qce\n",
- __func__, pdev->id);
- platform_set_drvdata(pdev, NULL);
- return rc;
+ pr_err("%s: device %s, can not open qce\n",
+ __func__, pdev->name);
+ goto err;
}
if (qce_hw_support(handle, &ce_support) < 0 ||
ce_support.ota == false) {
- pr_err("%s: device id %d, qce does not support ota capability\n",
- __func__, pdev->id);
+ pr_err("%s: device %s, qce does not support ota capability\n",
+ __func__, pdev->name);
rc = -ENODEV;
goto err;
}
- podev->qce = handle;
- podev->pdev = pdev;
- platform_set_drvdata(pdev, podev);
+ pqce->qce = handle;
+ pqce->pdev = pdev;
+ pqce->totalReq = 0;
+ pqce->errReq = 0;
+ platform_set_drvdata(pdev, pqce);
- rc = misc_register(&podev->miscdevice);
- if (rc < 0)
+ mutex_lock(&podev->register_lock);
+ rc = 0;
+ if (podev->registered == false) {
+ rc = misc_register(&podev->miscdevice);
+ if (rc == 0) {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ podev->registered = true;
+ };
+ } else {
+ pqce->unit = podev->total_units;
+ podev->total_units++;
+ }
+ mutex_unlock(&podev->register_lock);
+ if (rc) {
+ pr_err("ion: failed to register misc device.\n");
goto err;
+ }
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_add_tail(&pqce->qlist, &podev->qce_dev);
+ spin_unlock_irqrestore(&podev->lock, flags);
return 0;
err:
if (handle)
qce_close(handle);
+
platform_set_drvdata(pdev, NULL);
- podev->qce = NULL;
- podev->pdev = NULL;
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return rc;
-};
+}
static int qcota_remove(struct platform_device *pdev)
{
struct ota_dev_control *podev;
+ struct ota_qce_dev *pqce;
+ unsigned long flags;
- podev = platform_get_drvdata(pdev);
- if (!podev)
+ pqce = platform_get_drvdata(pdev);
+ if (!pqce)
return 0;
- if (podev->qce)
- qce_close(podev->qce);
+ if (pqce->qce)
+ qce_close(pqce->qce);
- if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
- misc_deregister(&podev->miscdevice);
- tasklet_kill(&podev->done_tasklet);
+ podev = pqce->podev;
+ if (!podev)
+ goto ret;
+
+ spin_lock_irqsave(&podev->lock, flags);
+ list_del(&pqce->qlist);
+ spin_unlock_irqrestore(&podev->lock, flags);
+
+ mutex_lock(&podev->register_lock);
+ if (--podev->total_units == 0) {
+ if (podev->miscdevice.minor != MISC_DYNAMIC_MINOR)
+ misc_deregister(&podev->miscdevice);
+ podev->registered = false;
+ }
+ mutex_unlock(&podev->register_lock);
+ret:
+
+ tasklet_kill(&pqce->done_tasklet);
+ kfree(pqce);
return 0;
+}
+
+static struct of_device_id qcota_match[] = {
+ { .compatible = "qcom,qcota",
+ },
+ {}
};
static struct platform_driver qcota_plat_driver = {
@@ -592,18 +661,21 @@
.driver = {
.name = "qcota",
.owner = THIS_MODULE,
+ .of_match_table = qcota_match,
},
};
-static int _disp_stats(int id)
+static int _disp_stats(void)
{
struct qcota_stat *pstat;
int len = 0;
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- pstat = &_qcota_stat[id];
+ pstat = &_qcota_stat;
len = snprintf(_debug_read_buf, DEBUG_MAX_RW_BUF - 1,
- "\nQualcomm OTA crypto accelerator %d Statistics:\n",
- id + 1);
+ "\nQualcomm OTA crypto accelerator Statistics:\n");
len += snprintf(_debug_read_buf + len, DEBUG_MAX_RW_BUF - len - 1,
" F8 request : %d\n",
@@ -635,6 +707,27 @@
" F9 operation fail : %d\n",
pstat->f9_op_fail);
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req : %d\n",
+ p->unit,
+ p->totalReq
+ );
+ len += snprintf(
+ _debug_read_buf + len,
+ DEBUG_MAX_RW_BUF - len - 1,
+ " Engine %d Req Error : %d\n",
+ p->unit,
+ p->errReq
+ );
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return len;
}
@@ -648,10 +741,9 @@
size_t count, loff_t *ppos)
{
int rc = -EINVAL;
- int qcota = *((int *) file->private_data);
int len;
- len = _disp_stats(qcota);
+ len = _disp_stats();
rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
@@ -662,12 +754,23 @@
static ssize_t _debug_stats_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
+ struct ota_dev_control *podev = &qcota_dev;
+ unsigned long flags;
+ struct ota_qce_dev *p;
- int qcota = *((int *) file->private_data);
+ memset((char *)&_qcota_stat, 0, sizeof(struct qcota_stat));
- memset((char *)&_qcota_stat[qcota], 0, sizeof(struct qcota_stat));
+ spin_lock_irqsave(&podev->lock, flags);
+
+ list_for_each_entry(p, &podev->qce_dev, qlist) {
+ p->totalReq = 0;
+ p->errReq = 0;
+ }
+
+ spin_unlock_irqrestore(&podev->lock, flags);
+
return count;
-};
+}
static const struct file_operations _debug_stats_ops = {
.open = _debug_stats_open,
@@ -679,7 +782,6 @@
{
int rc;
char name[DEBUG_MAX_FNAME];
- int i;
struct dentry *dent;
_debug_dent = debugfs_create_dir("qcota", NULL);
@@ -689,17 +791,15 @@
return PTR_ERR(_debug_dent);
}
- for (i = 0; i < MAX_OTA_DEVICE; i++) {
- snprintf(name, DEBUG_MAX_FNAME-1, "stats-%d", i+1);
- _debug_qcota[i] = i;
- dent = debugfs_create_file(name, 0644, _debug_dent,
- &_debug_qcota[i], &_debug_stats_ops);
- if (dent == NULL) {
- pr_err("qcota debugfs_create_file fail, error %ld\n",
+ snprintf(name, DEBUG_MAX_FNAME-1, "stats-0");
+ _debug_qcota = 0;
+ dent = debugfs_create_file(name, 0644, _debug_dent,
+ &_debug_qcota, &_debug_stats_ops);
+ if (dent == NULL) {
+ pr_err("qcota debugfs_create_file fail, error %ld\n",
PTR_ERR(dent));
- rc = PTR_ERR(dent);
- goto err;
- }
+ rc = PTR_ERR(dent);
+ goto err;
}
return 0;
err:
@@ -710,10 +810,20 @@
static int __init qcota_init(void)
{
int rc;
+ struct ota_dev_control *podev;
rc = _qcota_debug_init();
if (rc)
return rc;
+
+ podev = &qcota_dev;
+ INIT_LIST_HEAD(&podev->ready_commands);
+ INIT_LIST_HEAD(&podev->qce_dev);
+ spin_lock_init(&podev->lock);
+ mutex_init(&podev->register_lock);
+ podev->registered = false;
+ podev->total_units = 0;
+
return platform_driver_register(&qcota_plat_driver);
}
static void __exit qcota_exit(void)
@@ -725,7 +835,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rohit Vaswani <rvaswani@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Ota Crypto driver");
-MODULE_VERSION("1.01");
+MODULE_VERSION("1.02");
module_init(qcota_init);
module_exit(qcota_exit);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index aad2882..d0e3e34 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -2581,6 +2581,7 @@
INIT_COMPLETION(device->ft_gate);
/* Detected a hang */
+ kgsl_cffdump_hang(device->id);
/* Run fault tolerance at max power level */
curr_pwrlevel = pwr->active_pwrlevel;
kgsl_pwrctrl_pwrlevel_change(device, pwr->max_pwrlevel);
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fb31dd6..9b67c61 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -18,17 +18,18 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
-
+#include <linux/dma-buf.h>
#include <linux/vmalloc.h>
#include <linux/pm_runtime.h>
#include <linux/genlock.h>
#include <linux/rbtree.h>
#include <linux/ashmem.h>
#include <linux/major.h>
-#include <linux/msm_ion.h>
#include <linux/io.h>
#include <mach/socinfo.h>
#include <linux/mman.h>
+#include <linux/sort.h>
+#include <asm/cacheflush.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -51,7 +52,11 @@
MODULE_PARM_DESC(ksgl_mmu_type,
"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
-static struct ion_client *kgsl_ion_client;
+struct kgsl_dma_buf_meta {
+ struct dma_buf_attachment *attach;
+ struct dma_buf *dmabuf;
+ struct sg_table *table;
+};
/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
@@ -186,6 +191,14 @@
return entry;
}
+static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
+{
+ dma_buf_unmap_attachment(meta->attach, meta->table, DMA_FROM_DEVICE);
+ dma_buf_detach(meta->dmabuf, meta->attach);
+ dma_buf_put(meta->dmabuf);
+ kfree(meta);
+}
+
void
kgsl_mem_entry_destroy(struct kref *kref)
{
@@ -215,7 +228,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
}
@@ -1842,38 +1855,55 @@
#endif
static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
- struct kgsl_pagetable *pagetable, void *data)
+ struct kgsl_pagetable *pagetable, void *data,
+ struct kgsl_device *device)
{
- struct ion_handle *handle;
struct scatterlist *s;
struct sg_table *sg_table;
struct kgsl_map_user_mem *param = data;
int fd = param->fd;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attach;
+ struct kgsl_dma_buf_meta *meta;
+ int ret;
if (!param->len)
return -EINVAL;
- if (IS_ERR_OR_NULL(kgsl_ion_client))
- return -ENODEV;
+ meta = kzalloc(sizeof(*meta), GFP_KERNEL);
+ if (!meta)
+ return -ENOMEM;
- handle = ion_import_dma_buf(kgsl_ion_client, fd);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- else if (!handle)
- return -EINVAL;
+ dmabuf = dma_buf_get(fd);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ ret = PTR_ERR(dmabuf);
+ goto err1;
+ }
+
+ attach = dma_buf_attach(dmabuf, device->dev);
+ if (IS_ERR_OR_NULL(attach)) {
+ ret = PTR_ERR(attach);
+ goto err2;
+ }
+
+ meta->dmabuf = dmabuf;
+ meta->attach = attach;
entry->memtype = KGSL_MEM_ENTRY_ION;
- entry->priv_data = handle;
+ entry->priv_data = meta;
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = 0;
/* USE_CPU_MAP is not impemented for ION. */
entry->memdesc.flags &= ~KGSL_MEMFLAGS_USE_CPU_MAP;
- sg_table = ion_sg_table(kgsl_ion_client, handle);
+ sg_table = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
- if (IS_ERR_OR_NULL(sg_table))
- goto err;
+ if (IS_ERR_OR_NULL(sg_table)) {
+ ret = PTR_ERR(sg_table);
+ goto err3;
+ }
+ meta->table = sg_table;
entry->memdesc.sg = sg_table->sgl;
/* Calculate the size of the memdesc from the sglist */
@@ -1888,9 +1918,13 @@
entry->memdesc.size = PAGE_ALIGN(entry->memdesc.size);
return 0;
-err:
- ion_free(kgsl_ion_client, handle);
- return -ENOMEM;
+err3:
+ dma_buf_detach(dmabuf, attach);
+err2:
+ dma_buf_put(dmabuf);
+err1:
+ kfree(meta);
+ return ret;
}
static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
@@ -1978,7 +2012,8 @@
entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
break;
case KGSL_USER_MEM_TYPE_ION:
- result = kgsl_setup_ion(entry, private->pagetable, data);
+ result = kgsl_setup_ion(entry, private->pagetable, data,
+ dev_priv->device);
break;
default:
KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
@@ -2025,7 +2060,7 @@
fput(entry->priv_data);
break;
case KGSL_MEM_ENTRY_ION:
- ion_free(kgsl_ion_client, entry->priv_data);
+ kgsl_destroy_ion(entry->priv_data);
break;
default:
break;
@@ -2104,6 +2139,97 @@
return ret;
}
+static int mem_id_cmp(const void *_a, const void *_b)
+{
+ const unsigned int *a = _a, *b = _b;
+ int cmp = a - b;
+ return (cmp < 0) ? -1 : (cmp > 0);
+}
+
+static long
+kgsl_ioctl_gpumem_sync_cache_bulk(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ int i;
+ struct kgsl_gpumem_sync_cache_bulk *param = data;
+ struct kgsl_process_private *private = dev_priv->process_priv;
+ unsigned int id, last_id = 0, *id_list = NULL, actual_count = 0;
+ struct kgsl_mem_entry **entries = NULL;
+ long ret = 0;
+ size_t op_size = 0;
+ bool full_flush = false;
+
+ if (param->id_list == NULL || param->count == 0
+ || param->count > (UINT_MAX/sizeof(unsigned int)))
+ return -EINVAL;
+
+ id_list = kzalloc(param->count * sizeof(unsigned int), GFP_KERNEL);
+ if (id_list == NULL)
+ return -ENOMEM;
+
+ entries = kzalloc(param->count * sizeof(*entries), GFP_KERNEL);
+ if (entries == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ if (copy_from_user(id_list, param->id_list,
+ param->count * sizeof(unsigned int))) {
+ ret = -EFAULT;
+ goto end;
+ }
+ /* sort the ids so we can weed out duplicates */
+ sort(id_list, param->count, sizeof(int), mem_id_cmp, NULL);
+
+ for (i = 0; i < param->count; i++) {
+ unsigned int cachemode;
+ struct kgsl_mem_entry *entry = NULL;
+
+ id = id_list[i];
+ /* skip 0 ids or duplicates */
+ if (id == last_id)
+ continue;
+
+ entry = kgsl_sharedmem_find_id(private, id);
+ if (entry == NULL)
+ continue;
+
+ /* skip uncached memory */
+ cachemode = kgsl_memdesc_get_cachemode(&entry->memdesc);
+ if (cachemode != KGSL_CACHEMODE_WRITETHROUGH &&
+ cachemode != KGSL_CACHEMODE_WRITEBACK) {
+ kgsl_mem_entry_put(entry);
+ continue;
+ }
+
+ op_size += entry->memdesc.size;
+ entries[actual_count++] = entry;
+
+ /* If we exceed the breakeven point, flush the entire cache */
+ if (op_size >= kgsl_driver.full_cache_threshold &&
+ param->op == KGSL_GPUMEM_CACHE_FLUSH) {
+ full_flush = true;
+ break;
+ }
+ last_id = id;
+ }
+ if (full_flush) {
+ trace_kgsl_mem_sync_full_cache(actual_count, op_size,
+ param->op);
+ __cpuc_flush_kern_all();
+ }
+
+ for (i = 0; i < actual_count; i++) {
+ if (!full_flush)
+ _kgsl_gpumem_sync_cache(entries[i], param->op);
+ kgsl_mem_entry_put(entries[i]);
+ }
+end:
+ kfree(entries);
+ kfree(id_list);
+ return ret;
+}
+
/* Legacy cache function, does a flush (clean + invalidate) */
static long
@@ -2510,6 +2636,8 @@
kgsl_ioctl_gpumem_get_info, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
kgsl_ioctl_gpumem_sync_cache, 0),
+ KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
+ kgsl_ioctl_gpumem_sync_cache_bulk, 0),
};
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -2809,16 +2937,17 @@
ret = ALIGN(ret, (1 << align));
/*make sure there isn't a GPU only mapping at this address */
- if (kgsl_sharedmem_region_empty(private, ret, len))
+ if (kgsl_sharedmem_region_empty(private, ret, orig_len))
break;
- trace_kgsl_mem_unmapped_area_collision(entry, addr, len, ret);
+ trace_kgsl_mem_unmapped_area_collision(entry, addr, orig_len,
+ ret);
/*
* If we collided, bump the hint address so that
* get_umapped_area knows to look somewhere else.
*/
- addr = (addr == 0) ? ret + len : addr + len;
+ addr = (addr == 0) ? ret + orig_len : addr + orig_len;
/*
* The addr hint can be set by userspace to be near
@@ -2952,6 +3081,11 @@
.devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
.memfree_hist_mutex =
__MUTEX_INITIALIZER(kgsl_driver.memfree_hist_mutex),
+ /*
+ * Full cache flushes are faster than line by line on at least
+ * 8064 and 8974 once the region to be flushed is > 16mb.
+ */
+ .full_cache_threshold = SZ_16M,
};
EXPORT_SYMBOL(kgsl_driver);
@@ -3032,8 +3166,6 @@
if (status)
goto error;
- kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
-
/* Get starting physical address of device registers */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
device->iomemname);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index c7cbaf8..de3f619 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -134,6 +134,7 @@
unsigned int mapped_max;
unsigned int histogram[16];
} stats;
+ unsigned int full_cache_threshold;
};
extern struct kgsl_driver kgsl_driver;
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 513fb90..4fb2f87 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -242,7 +242,7 @@
list_for_each_entry(private, &kgsl_driver.process_list, list) {
- if (private->pagetable->name != id)
+ if (private->pagetable && (private->pagetable->name != id))
continue;
spin_lock(&private->mem_lock);
@@ -920,15 +920,15 @@
iommu_access_ops = get_iommu_access_ops_v0();
- if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize)
- lock_phy_addr = (iommu_access_ops->iommu_lock_initialize()
- - MSM_SHARED_RAM_BASE + msm_shared_ram_phys);
-
- if (!lock_phy_addr) {
- iommu_access_ops = NULL;
- KGSL_DRV_ERR(mmu->device,
- "GPU CPU sync lock is not supported by kernel\n");
- return -ENXIO;
+ if (iommu_access_ops && iommu_access_ops->iommu_lock_initialize) {
+ lock_phy_addr = (uint32_t)
+ iommu_access_ops->iommu_lock_initialize();
+ if (!lock_phy_addr) {
+ iommu_access_ops = NULL;
+ return status;
+ }
+ lock_phy_addr = lock_phy_addr - (uint32_t)MSM_SHARED_RAM_BASE +
+ (uint32_t)msm_shared_ram_phys;
}
/* Align the physical address to PAGE boundary and store the offset */
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 4071b37..1691762 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -234,6 +234,29 @@
return len;
}
+static int kgsl_drv_full_cache_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ unsigned int thresh;
+ ret = sscanf(buf, "%d", &thresh);
+ if (ret != 1)
+ return count;
+
+ kgsl_driver.full_cache_threshold = thresh;
+
+ return count;
+}
+
+static int kgsl_drv_full_cache_threshold_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ kgsl_driver.full_cache_threshold);
+}
+
DEVICE_ATTR(vmalloc, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(vmalloc_max, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(page_alloc, 0444, kgsl_drv_memstat_show, NULL);
@@ -243,6 +266,9 @@
DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL);
DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL);
+DEVICE_ATTR(full_cache_threshold, 0644,
+ kgsl_drv_full_cache_threshold_show,
+ kgsl_drv_full_cache_threshold_store);
static const struct device_attribute *drv_attr_list[] = {
&dev_attr_vmalloc,
@@ -254,6 +280,7 @@
&dev_attr_mapped,
&dev_attr_mapped_max,
&dev_attr_histogram,
+ &dev_attr_full_cache_threshold,
NULL
};
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 08677ef..6917883 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -539,6 +539,33 @@
)
);
+TRACE_EVENT(kgsl_mem_sync_full_cache,
+
+ TP_PROTO(unsigned int num_bufs, unsigned int bulk_size,
+ unsigned int op),
+
+ TP_ARGS(num_bufs, bulk_size, op),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, num_bufs)
+ __field(unsigned int, bulk_size)
+ __field(unsigned int, op)
+ ),
+
+ TP_fast_assign(
+ __entry->num_bufs = num_bufs;
+ __entry->bulk_size = bulk_size;
+ __entry->op = op;
+ ),
+
+ TP_printk(
+ "num_bufs=%d bulk_size=%d op=%c%c",
+ __entry->num_bufs, __entry->bulk_size,
+ (__entry->op & KGSL_GPUMEM_CACHE_CLEAN) ? 'c' : '.',
+ (__entry->op & KGSL_GPUMEM_CACHE_INV) ? 'i' : '.'
+ )
+);
+
DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
TP_PROTO(struct kgsl_device *device, struct kgsl_mem_entry *mem_entry,
diff --git a/drivers/hwmon/qpnp-adc-current.c b/drivers/hwmon/qpnp-adc-current.c
index f6ab3c2..de7b0e9 100644
--- a/drivers/hwmon/qpnp-adc-current.c
+++ b/drivers/hwmon/qpnp-adc-current.c
@@ -646,13 +646,15 @@
{
struct qpnp_iadc_drv *iadc = qpnp_iadc;
uint8_t rslt_rsense;
- int32_t rc, sign_bit = 0;
+ int32_t rc = 0, sign_bit = 0;
if (!iadc || !iadc->iadc_initialized)
return -EPROBE_DEFER;
- if (iadc->external_rsense)
+ if (iadc->external_rsense) {
*rsense = iadc->rsense;
+ return rc;
+ }
rc = qpnp_iadc_read_reg(QPNP_IADC_NOMINAL_RSENSE, &rslt_rsense);
if (rc < 0) {
diff --git a/drivers/iommu/msm_iommu-v0.c b/drivers/iommu/msm_iommu-v0.c
index 10fa5b1..eadbd64 100644
--- a/drivers/iommu/msm_iommu-v0.c
+++ b/drivers/iommu/msm_iommu-v0.c
@@ -1281,7 +1281,7 @@
return 0;
}
-static void print_ctx_regs(void __iomem *base, int ctx)
+static void __print_ctx_regs(void __iomem *base, int ctx)
{
unsigned int fsr = GET_FSR(base, ctx);
pr_err("FAR = %08x PAR = %08x\n",
@@ -1347,7 +1347,7 @@
pr_err("name = %s\n", drvdata->name);
pr_err("context = %s (%d)\n", ctx_drvdata->name, num);
pr_err("Interesting registers:\n");
- print_ctx_regs(base, num);
+ __print_ctx_regs(base, num);
}
SET_FSR(base, num, fsr);
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index f90bf6c..5ee8794 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -783,10 +783,12 @@
return 0;
}
-static void print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+void print_ctx_regs(struct msm_iommu_context_regs *regs)
{
+ uint32_t fsr = regs->fsr;
+
pr_err("FAR = %08x PAR = %08x\n",
- GET_FAR(base, ctx), GET_PAR(base, ctx));
+ regs->far, regs->par);
pr_err("FSR = %08x [%s%s%s%s%s%s%s%s%s]\n", fsr,
(fsr & 0x02) ? "TF " : "",
(fsr & 0x04) ? "AFF " : "",
@@ -799,13 +801,31 @@
(fsr & 0x80000000) ? "MULTI " : "");
pr_err("FSYNR0 = %08x FSYNR1 = %08x\n",
- GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+ regs->fsynr0, regs->fsynr1);
pr_err("TTBR0 = %08x TTBR1 = %08x\n",
- GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+ regs->ttbr0, regs->ttbr1);
pr_err("SCTLR = %08x ACTLR = %08x\n",
- GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+ regs->sctlr, regs->actlr);
pr_err("PRRR = %08x NMRR = %08x\n",
- GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+ regs->prrr, regs->nmrr);
+}
+
+static void __print_ctx_regs(void __iomem *base, int ctx, unsigned int fsr)
+{
+ struct msm_iommu_context_regs regs = {
+ .far = GET_FAR(base, ctx),
+ .par = GET_PAR(base, ctx),
+ .fsr = fsr,
+ .fsynr0 = GET_FSYNR0(base, ctx),
+ .fsynr1 = GET_FSYNR1(base, ctx),
+ .ttbr0 = GET_TTBR0(base, ctx),
+ .ttbr1 = GET_TTBR1(base, ctx),
+ .sctlr = GET_SCTLR(base, ctx),
+ .actlr = GET_ACTLR(base, ctx),
+ .prrr = GET_PRRR(base, ctx),
+ .nmrr = GET_NMRR(base, ctx),
+ };
+ print_ctx_regs(®s);
}
irqreturn_t msm_iommu_fault_handler_v2(int irq, void *dev_id)
@@ -861,7 +881,7 @@
pr_err("context = %s (%d)\n", ctx_drvdata->name,
ctx_drvdata->num);
pr_err("Interesting registers:\n");
- print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
+ __print_ctx_regs(drvdata->base, ctx_drvdata->num, fsr);
}
SET_FSR(drvdata->base, ctx_drvdata->num, fsr);
diff --git a/drivers/iommu/msm_iommu_dev-v1.c b/drivers/iommu/msm_iommu_dev-v1.c
index c0e05f4..958b7b1 100644
--- a/drivers/iommu/msm_iommu_dev-v1.c
+++ b/drivers/iommu/msm_iommu_dev-v1.c
@@ -359,7 +359,20 @@
ctx_drvdata->secure_context = of_property_read_bool(pdev->dev.of_node,
"qcom,secure-context");
- if (!ctx_drvdata->secure_context) {
+ if (ctx_drvdata->secure_context) {
+ irq = platform_get_irq(pdev, 1);
+ if (irq > 0) {
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ msm_iommu_secure_fault_handler_v2,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "msm_iommu_secure_irq", pdev);
+ if (ret) {
+ pr_err("Request IRQ %d failed with ret=%d\n",
+ irq, ret);
+ return ret;
+ }
+ }
+ } else {
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
diff --git a/drivers/iommu/msm_iommu_sec.c b/drivers/iommu/msm_iommu_sec.c
index 74d8b48..a17a4e8 100644
--- a/drivers/iommu/msm_iommu_sec.c
+++ b/drivers/iommu/msm_iommu_sec.c
@@ -38,6 +38,7 @@
/* bitmap of the page sizes currently supported */
#define MSM_IOMMU_PGSIZES (SZ_4K | SZ_64K | SZ_1M | SZ_16M)
+/* commands for SCM_SVC_MP */
#define IOMMU_SECURE_CFG 2
#define IOMMU_SECURE_PTBL_SIZE 3
#define IOMMU_SECURE_PTBL_INIT 4
@@ -47,6 +48,9 @@
#define IOMMU_SECURE_UNMAP2 0x0C
#define IOMMU_TLBINVAL_FLAG 0x00000001
+/* commands for SCM_SVC_UTIL */
+#define IOMMU_DUMP_SMMU_FAULT_REGS 0X0C
+
static struct iommu_access_ops *iommu_access_ops;
struct msm_scm_paddr_list {
@@ -73,11 +77,154 @@
unsigned int flags;
};
+struct msm_scm_fault_regs_dump {
+ uint32_t dump_size;
+ uint32_t fsr_addr;
+ uint32_t fsr;
+ uint32_t far0_addr;
+ uint32_t far0;
+ uint32_t far1_addr;
+ uint32_t far1;
+ uint32_t par0_addr;
+ uint32_t par0;
+ uint32_t par1_addr;
+ uint32_t par1;
+ uint32_t fsyn0_addr;
+ uint32_t fsyn0;
+ uint32_t fsyn1_addr;
+ uint32_t fsyn1;
+ uint32_t ttbr0_addr;
+ uint32_t ttbr0;
+ uint32_t ttbr1_addr;
+ uint32_t ttbr1;
+ uint32_t ttbcr_addr;
+ uint32_t ttbcr;
+ uint32_t sctlr_addr;
+ uint32_t sctlr;
+ uint32_t actlr_addr;
+ uint32_t actlr;
+ uint32_t prrr_addr;
+ uint32_t prrr;
+ uint32_t nmrr_addr;
+ uint32_t nmrr;
+};
+
void msm_iommu_sec_set_access_ops(struct iommu_access_ops *access_ops)
{
iommu_access_ops = access_ops;
}
+static int msm_iommu_dump_fault_regs(int smmu_id, int cb_num,
+ struct msm_scm_fault_regs_dump *regs)
+{
+ int ret;
+
+ struct msm_scm_fault_regs_dump_req {
+ uint32_t id;
+ uint32_t cb_num;
+ phys_addr_t buff;
+ uint32_t len;
+ } req_info;
+ int resp;
+
+ req_info.id = smmu_id;
+ req_info.cb_num = cb_num;
+ req_info.buff = virt_to_phys(regs);
+ req_info.len = sizeof(*regs);
+
+ ret = scm_call(SCM_SVC_UTIL, IOMMU_DUMP_SMMU_FAULT_REGS,
+ &req_info, sizeof(req_info), &resp, 1);
+
+ return ret;
+}
+
+irqreturn_t msm_iommu_secure_fault_handler_v2(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct msm_iommu_drvdata *drvdata;
+ struct msm_iommu_ctx_drvdata *ctx_drvdata;
+ struct msm_scm_fault_regs_dump *regs;
+ int tmp, ret = IRQ_HANDLED;
+
+ iommu_access_ops->iommu_lock_acquire();
+
+ BUG_ON(!pdev);
+
+ drvdata = dev_get_drvdata(pdev->dev.parent);
+ BUG_ON(!drvdata);
+
+ ctx_drvdata = dev_get_drvdata(&pdev->dev);
+ BUG_ON(!ctx_drvdata);
+
+ regs = kmalloc(sizeof(*regs), GFP_KERNEL);
+ if (!regs) {
+ pr_err("%s: Couldn't allocate memory\n", __func__);
+ goto lock_release;
+ }
+
+ if (!drvdata->ctx_attach_count) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("Power is OFF. Unable to read page fault information\n");
+ /*
+ * We cannot determine which context bank caused the issue so
+ * we just return handled here to ensure IRQ handler code is
+ * happy
+ */
+ goto free_regs;
+ }
+
+ iommu_access_ops->iommu_clk_on(drvdata);
+ tmp = msm_iommu_dump_fault_regs(drvdata->sec_id,
+ ctx_drvdata->num, regs);
+ iommu_access_ops->iommu_clk_off(drvdata);
+
+ if (tmp) {
+ pr_err("%s: Couldn't dump fault registers!\n", __func__);
+ goto free_regs;
+ } else if (regs->fsr) {
+ struct msm_iommu_context_regs ctx_regs = {
+ .far = regs->far0,
+ .par = regs->par0,
+ .fsr = regs->fsr,
+ .fsynr0 = regs->fsyn0,
+ .fsynr1 = regs->fsyn1,
+ .ttbr0 = regs->ttbr0,
+ .ttbr1 = regs->ttbr1,
+ .sctlr = regs->sctlr,
+ .actlr = regs->actlr,
+ .prrr = regs->prrr,
+ .nmrr = regs->nmrr,
+ };
+
+ if (!ctx_drvdata->attached_domain) {
+ pr_err("Bad domain in interrupt handler\n");
+ tmp = -ENOSYS;
+ } else {
+ tmp = report_iommu_fault(ctx_drvdata->attached_domain,
+ &ctx_drvdata->pdev->dev,
+ regs->far0, 0);
+ }
+
+ /* if the fault wasn't handled by someone else: */
+ if (tmp == -ENOSYS) {
+ pr_err("Unexpected IOMMU page fault from secure context bank!\n");
+ pr_err("name = %s\n", drvdata->name);
+ pr_err("context = %s (%d)\n", ctx_drvdata->name,
+ ctx_drvdata->num);
+ pr_err("Interesting registers:\n");
+ print_ctx_regs(&ctx_regs);
+ }
+ } else {
+ ret = IRQ_NONE;
+ }
+free_regs:
+ kfree(regs);
+lock_release:
+ iommu_access_ops->iommu_lock_release();
+ return ret;
+}
+
static int msm_iommu_sec_ptbl_init(void)
{
struct device_node *np;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index d56a5252..b0661dd 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -1155,6 +1155,7 @@
s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
s_ctrl->sensor_i2c_client, &s_ctrl->stop_setting);
kfree(s_ctrl->stop_setting.reg_setting);
+ s_ctrl->stop_setting.reg_setting = NULL;
}
mutex_unlock(s_ctrl->msm_sensor_mutex);
return;
@@ -1257,6 +1258,7 @@
power_setting_array->size *
sizeof(struct msm_sensor_power_setting))) {
pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(power_setting_array->power_setting);
rc = -EFAULT;
break;
}
@@ -1325,6 +1327,127 @@
kfree(reg_setting);
break;
}
+ case CFG_SLAVE_READ_I2C: {
+ struct msm_camera_i2c_read_config read_config;
+ uint16_t local_data = 0;
+ uint16_t orig_slave_addr = 0, read_slave_addr = 0;
+ if (copy_from_user(&read_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_read_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ read_slave_addr = read_config.slave_addr;
+ CDBG("%s:CFG_SLAVE_READ_I2C:", __func__);
+ CDBG("%s:slave_addr=0x%x reg_addr=0x%x, data_type=%d\n",
+ __func__, read_config.slave_addr,
+ read_config.reg_addr, read_config.data_type);
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ read_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ read_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ read_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_read(
+ s_ctrl->sensor_i2c_client,
+ read_config.reg_addr,
+ &local_data, read_config.data_type);
+ if (rc < 0) {
+ pr_err("%s:%d: i2c_read failed\n", __func__, __LINE__);
+ break;
+ }
+ if (copy_to_user((void __user *)read_config.data,
+ (void *)&local_data, sizeof(uint16_t))) {
+ pr_err("%s:%d copy failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case CFG_SLAVE_WRITE_I2C_ARRAY: {
+ struct msm_camera_i2c_array_write_config write_config;
+ struct msm_camera_i2c_reg_array *reg_setting = NULL;
+ uint16_t write_slave_addr = 0;
+ uint16_t orig_slave_addr = 0;
+
+ if (copy_from_user(&write_config,
+ (void *)cdata->cfg.setting,
+ sizeof(struct msm_camera_i2c_array_write_config))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:CFG_SLAVE_WRITE_I2C_ARRAY:", __func__);
+ CDBG("%s:slave_addr=0x%x, array_size=%d\n", __func__,
+ write_config.slave_addr,
+ write_config.conf_array.size);
+ reg_setting = kzalloc(write_config.conf_array.size *
+ (sizeof(struct msm_camera_i2c_reg_array)), GFP_KERNEL);
+ if (!reg_setting) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ rc = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(reg_setting,
+ (void *)(write_config.conf_array.reg_setting),
+ write_config.conf_array.size *
+ sizeof(struct msm_camera_i2c_reg_array))) {
+ pr_err("%s:%d failed\n", __func__, __LINE__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ write_config.conf_array.reg_setting = reg_setting;
+ write_slave_addr = write_config.slave_addr;
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->cci_client->sid;
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ write_slave_addr >> 1;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ orig_slave_addr =
+ s_ctrl->sensor_i2c_client->client->addr;
+ s_ctrl->sensor_i2c_client->client->addr =
+ write_slave_addr >> 1;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ CDBG("%s:orig_slave_addr=0x%x, new_slave_addr=0x%x",
+ __func__, orig_slave_addr,
+ write_slave_addr >> 1);
+ rc = s_ctrl->sensor_i2c_client->i2c_func_tbl->i2c_write_table(
+ s_ctrl->sensor_i2c_client, &(write_config.conf_array));
+ if (s_ctrl->sensor_i2c_client->cci_client) {
+ s_ctrl->sensor_i2c_client->cci_client->sid =
+ orig_slave_addr;
+ } else if (s_ctrl->sensor_i2c_client->client) {
+ s_ctrl->sensor_i2c_client->client->addr =
+ orig_slave_addr;
+ } else {
+ pr_err("%s: error: no i2c/cci client found.", __func__);
+ kfree(reg_setting);
+ rc = -EFAULT;
+ break;
+ }
+ kfree(reg_setting);
+ break;
+ }
case CFG_WRITE_I2C_SEQ_ARRAY: {
struct msm_camera_i2c_seq_reg_setting conf_array;
struct msm_camera_i2c_seq_reg_array *reg_setting = NULL;
@@ -1395,6 +1518,8 @@
break;
case CFG_POWER_DOWN:
+ kfree(s_ctrl->stop_setting.reg_setting);
+ s_ctrl->stop_setting.reg_setting = NULL;
if (s_ctrl->sensor_state != MSM_SENSOR_POWER_UP) {
pr_err("%s:%d failed: invalid state %d\n", __func__,
__LINE__, s_ctrl->sensor_state);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index d07387e..790bbc1 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -4055,11 +4055,13 @@
pes_event.pes_end.start_gap = 0;
pes_event.data_length = 0;
- /* Parse error indicators - TODO: these should be per filter */
+ /* Parse error indicators */
if (sts->error_indicators & SDMX_FILTER_ERR_INVALID_PES_LEN)
pes_event.pes_end.pes_length_mismatch = 1;
- if (sts->error_indicators & SDMX_FILTER_ERR_CONT_CNT_INVALID)
- pes_event.pes_end.disc_indicator_set = 0;
+ else
+ pes_event.pes_end.pes_length_mismatch = 0;
+
+ pes_event.pes_end.disc_indicator_set = 0;
pes_event.pes_end.stc = 0;
pes_event.pes_end.tei_counter = counters.transport_err_count;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 91fcdb6..fd29994 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -393,6 +393,7 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
+ struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
int rc = 0;
@@ -401,7 +402,15 @@
event_notify = (struct msm_vidc_cb_event *) response->data;
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
- event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
+ control.id =
+ V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc)
+ dprintk(VIDC_WARN,
+ "Failed to get Smooth streamng flag\n");
+ if (!rc && control.value == true)
+ event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
@@ -543,6 +552,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst = NULL ;
struct msm_vidc_core *core = NULL;
+ subsystem_crashed("venus");
if (response) {
core = get_vidc_core(response->device_id);
dprintk(VIDC_WARN, "SYS_ERROR received for core %p\n", core);
diff --git a/drivers/media/platform/msm/wfd/enc-venus-subdev.c b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
index 722aa8f..e6568f1 100644
--- a/drivers/media/platform/msm/wfd/enc-venus-subdev.c
+++ b/drivers/media/platform/msm/wfd/enc-venus-subdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <mach/iommu_domains.h>
#include <media/msm_vidc.h>
#include <media/v4l2-subdev.h>
@@ -48,6 +49,13 @@
bool callback_thread_running;
struct completion dq_complete, cmd_complete;
bool secure;
+ struct workqueue_struct *fill_buf_wq;
+};
+
+struct fill_buf_work {
+ struct venc_inst *inst;
+ struct mem_region *mregion;
+ struct work_struct work;
};
static const int subscribed_events[] = {
@@ -331,6 +339,14 @@
init_completion(&inst->dq_complete);
init_completion(&inst->cmd_complete);
mutex_init(&inst->lock);
+
+ inst->fill_buf_wq = create_singlethread_workqueue("venc_vidc_ftb_wq");
+ if (!inst->fill_buf_wq) {
+ WFD_MSG_ERR("Failed to create ftb wq\n");
+ rc = -ENOMEM;
+ goto vidc_wq_create_fail;
+ }
+
inst->vidc_context = msm_vidc_open(MSM_VIDC_CORE_0, MSM_VIDC_ENCODER);
if (!inst->vidc_context) {
WFD_MSG_ERR("Failed to create vidc context\n");
@@ -362,6 +378,8 @@
vidc_subscribe_fail:
msm_vidc_close(inst->vidc_context);
vidc_open_fail:
+ destroy_workqueue(inst->fill_buf_wq);
+vidc_wq_create_fail:
kfree(inst);
venc_open_fail:
return rc;
@@ -385,6 +403,7 @@
wait_for_completion(&inst->cmd_complete);
+ destroy_workqueue(inst->fill_buf_wq);
if (inst->callback_thread && inst->callback_thread_running)
kthread_stop(inst->callback_thread);
@@ -551,6 +570,7 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
rc = msm_vidc_streamoff(inst->vidc_context, BUF_TYPE_INPUT);
if (rc) {
WFD_MSG_ERR("Failed to streamoff vidc's input port");
@@ -938,25 +958,12 @@
return msm_vidc_s_parm(inst->vidc_context, &p);
}
-static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+static long fill_outbuf(struct venc_inst *inst, struct mem_region *mregion)
{
- struct venc_inst *inst = NULL;
- struct mem_region *mregion = NULL;
struct v4l2_buffer buffer = {0};
struct v4l2_plane plane = {0};
int index = 0, rc = 0;
- if (!sd) {
- WFD_MSG_ERR("Subdevice required for %s\n", __func__);
- return -EINVAL;
- } else if (!arg) {
- WFD_MSG_ERR("Invalid output buffer ot fill\n");
- return -EINVAL;
- }
-
- inst = (struct venc_inst *)sd->dev_priv;
- mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
-
if (!mregion) {
WFD_MSG_ERR("Output buffer not registered\n");
return -ENOENT;
@@ -994,8 +1001,77 @@
mark_index_busy(&inst->free_output_indices, index);
mutex_unlock(&inst->lock);
}
- return rc;
+ return rc;
+}
+
+static void fill_outbuf_helper(struct work_struct *work)
+{
+ int rc;
+ struct fill_buf_work *fbw =
+ container_of(work, struct fill_buf_work, work);
+
+ rc = fill_outbuf(fbw->inst, fbw->mregion);
+ if (rc) {
+ struct vb2_buffer *vb = NULL;
+
+ WFD_MSG_ERR("Failed to fill buffer async\n");
+ vb = (struct vb2_buffer *)fbw->mregion->cookie;
+ vb->v4l2_buf.flags = 0;
+ vb->v4l2_buf.timestamp = ns_to_timeval(-1);
+ vb->v4l2_planes[0].bytesused = 0;
+
+ fbw->inst->vmops.op_buffer_done(
+ fbw->inst->vmops.cbdata, rc, vb);
+ }
+
+ kfree(fbw);
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+ struct fill_buf_work *fbw;
+ struct venc_inst *inst = NULL;
+ struct mem_region *mregion;
+
+ if (!sd) {
+ WFD_MSG_ERR("Subdevice required for %s\n", __func__);
+ return -EINVAL;
+ } else if (!arg) {
+ WFD_MSG_ERR("Invalid output buffer ot fill\n");
+ return -EINVAL;
+ }
+
+ inst = (struct venc_inst *)sd->dev_priv;
+ mregion = get_registered_mregion(&inst->registered_output_bufs, arg);
+ if (!mregion) {
+ WFD_MSG_ERR("Output buffer not registered\n");
+ return -ENOENT;
+ }
+
+ fbw = kzalloc(sizeof(*fbw), GFP_KERNEL);
+ if (!fbw) {
+ WFD_MSG_ERR("Couldn't allocate memory\n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&fbw->work, fill_outbuf_helper);
+ fbw->inst = inst;
+ fbw->mregion = mregion;
+ /* XXX: The need for a wq to qbuf to vidc is necessitated as a
+ * workaround for a bug in the v4l2 framework. VIDIOC_QBUF from
+ * triggers a down_read(current->mm->mmap_sem). There is another
+ * _read(..) as msm_vidc_qbuf() depends on videobuf2 framework
+ * as well. However, a _write(..) after the first _read() by a
+ * different driver will prevent the second _read(...) from
+ * suceeding.
+ *
+ * As we can't modify the framework, we're working around by issue
+ * by queuing in a different thread effectively.
+ */
+ queue_work(inst->fill_buf_wq, &fbw->work);
+
+ return 0;
}
static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
@@ -1127,6 +1203,8 @@
inst = (struct venc_inst *)sd->dev_priv;
+ flush_workqueue(inst->fill_buf_wq);
+
enc_cmd.cmd = V4L2_ENC_QCOM_CMD_FLUSH;
enc_cmd.flags = V4L2_QCOM_CMD_FLUSH_OUTPUT |
V4L2_QCOM_CMD_FLUSH_CAPTURE;
diff --git a/drivers/media/platform/msm/wfd/wfd-ioctl.c b/drivers/media/platform/msm/wfd/wfd-ioctl.c
index d44792c..cc309aa 100644
--- a/drivers/media/platform/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/platform/msm/wfd/wfd-ioctl.c
@@ -1258,7 +1258,7 @@
WFD_MSG_DBG("yay!! got callback\n");
mutex_lock(&inst->vb2_lock);
- vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+ vb2_buffer_done(buf, status ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
mutex_unlock(&inst->vb2_lock);
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 07eb472..c60537a 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -998,27 +998,8 @@
return ret;
}
-static int __qseecom_send_cmd_req_clean_up(
- struct qseecom_send_modfd_cmd_req *req)
-{
- char *field;
- uint32_t *update;
- int ret = 0;
- int i = 0;
-
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd > 0) {
- field = (char *)req->cmd_req_buf +
- req->ifd_data[i].cmd_buf_offset;
- update = (uint32_t *) field;
- *update = 0;
- }
- }
- return ret;
-}
-
-static int __qseecom_update_with_phy_addr(
- struct qseecom_send_modfd_cmd_req *req)
+static int __qseecom_update_cmd_buf(struct qseecom_send_modfd_cmd_req *req,
+ bool cleanup)
{
struct ion_handle *ihandle;
char *field;
@@ -1057,7 +1038,11 @@
if (sg_ptr->nents == 1) {
uint32_t *update;
update = (uint32_t *) field;
- *update = (uint32_t)sg_dma_address(sg_ptr->sgl);
+ if (cleanup)
+ *update = 0;
+ else
+ *update = (uint32_t)sg_dma_address(
+ sg_ptr->sgl);
} else {
struct qseecom_sg_entry *update;
struct scatterlist *sg;
@@ -1065,9 +1050,14 @@
update = (struct qseecom_sg_entry *) field;
sg = sg_ptr->sgl;
for (j = 0; j < sg_ptr->nents; j++) {
- update->phys_addr = (uint32_t)
- sg_dma_address(sg);
- update->len = (uint32_t)sg->length;
+ if (cleanup) {
+ update->phys_addr = 0;
+ update->len = 0;
+ } else {
+ update->phys_addr = (uint32_t)
+ sg_dma_address(sg);
+ update->len = sg->length;
+ }
update++;
sg = sg_next(sg);
}
@@ -1101,15 +1091,15 @@
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
- ret = __qseecom_update_with_phy_addr(&req);
+ ret = __qseecom_update_cmd_buf(&req, false);
if (ret)
return ret;
-
ret = __qseecom_send_cmd(data, &send_cmd_req);
- __qseecom_send_cmd_req_clean_up(&req);
if (ret)
return ret;
-
+ ret = __qseecom_update_cmd_buf(&req, true);
+ if (ret)
+ return ret;
pr_debug("sending cmd_req->rsp size: %u, ptr: 0x%p\n",
req.resp_len, req.resp_buf);
return ret;
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 21e65b9..f01ddab 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3122,6 +3122,37 @@
#endif
}
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+ struct mmc_blk_data *part_md;
+ struct mmc_blk_data *md = mmc_get_drvdata(card);
+ int rc;
+
+ /* Silent the block layer */
+ if (md) {
+ rc = mmc_queue_suspend(&md->queue);
+ if (rc)
+ goto suspend_error;
+ list_for_each_entry(part_md, &md->part, part) {
+ rc = mmc_queue_suspend(&part_md->queue);
+ if (rc)
+ goto suspend_error;
+ }
+ }
+
+ /* send power off notification */
+ if (mmc_card_mmc(card)) {
+ mmc_rpm_hold(card->host, &card->dev);
+ mmc_send_long_pon(card);
+ mmc_rpm_release(card->host, &card->dev);
+ }
+ return;
+
+suspend_error:
+ pr_err("%s: mmc_queue_suspend returned error = %d",
+ mmc_hostname(card->host), rc);
+}
+
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
{
@@ -3181,6 +3212,7 @@
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
+ .shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 7b9e133..ac2ecbb 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -123,6 +123,15 @@
return 0;
}
+static void mmc_bus_shutdown(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (drv->shutdown)
+ drv->shutdown(card);
+}
+
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
@@ -153,10 +162,18 @@
{
struct mmc_card *card = mmc_dev_to_card(dev);
- if (mmc_use_core_runtime_pm(card->host))
- return 0;
- else
+ if (mmc_use_core_runtime_pm(card->host)) {
+ /*
+ * If idle time bkops is running on the card, let's not get
+ * into suspend.
+ */
+ if (mmc_card_doing_bkops(card) && mmc_card_is_prog_state(card))
+ return -EBUSY;
+ else
+ return 0;
+ } else {
return mmc_power_save_host(card->host);
+ }
}
static int mmc_runtime_resume(struct device *dev)
@@ -238,6 +255,7 @@
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
+ .shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9fc599b..3d525e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -487,11 +487,6 @@
mmc_card_clr_need_bkops(card);
mmc_card_set_doing_bkops(card);
- pr_debug("%s: %s: starting the polling thread\n",
- mmc_hostname(card->host), __func__);
- queue_work(system_nrt_wq,
- &card->bkops_info.poll_for_completion);
-
out:
mmc_release_host(card->host);
mmc_rpm_release(card->host, &card->dev);
@@ -499,81 +494,6 @@
EXPORT_SYMBOL(mmc_start_bkops);
/**
- * mmc_bkops_completion_polling() - Poll on the card status to
- * wait for the non-blocking BKOPS completion
- * @work: The completion polling work
- *
- * The on-going reading of the card status will prevent the card
- * from getting into suspend while it is in the middle of
- * performing BKOPS.
- * Since the non blocking BKOPS can be interrupted by a fetched
- * request we also check IF mmc_card_doing_bkops in each
- * iteration.
- */
-void mmc_bkops_completion_polling(struct work_struct *work)
-{
- struct mmc_card *card = container_of(work, struct mmc_card,
- bkops_info.poll_for_completion);
- unsigned long timeout_jiffies = jiffies +
- msecs_to_jiffies(BKOPS_COMPLETION_POLLING_TIMEOUT_MS);
- u32 status;
- int err;
-
- /*
- * Wait for the BKOPs to complete. Keep reading the status to prevent
- * the host from getting into suspend
- */
- do {
- mmc_rpm_hold(card->host, &card->dev);
- mmc_claim_host(card->host);
-
- if (!mmc_card_doing_bkops(card))
- goto out;
-
- err = mmc_send_status(card, &status);
- if (err) {
- pr_err("%s: error %d requesting status\n",
- mmc_hostname(card->host), err);
- goto out;
- }
-
- /*
- * Some cards mishandle the status bits, so make sure to check
- * both the busy indication and the card state.
- */
- if ((status & R1_READY_FOR_DATA) &&
- (R1_CURRENT_STATE(status) != R1_STATE_PRG)) {
- pr_debug("%s: %s: completed BKOPs, exit polling\n",
- mmc_hostname(card->host), __func__);
- mmc_card_clr_doing_bkops(card);
- card->bkops_info.sectors_changed = 0;
- goto out;
- }
-
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-
- /*
- * Sleep before checking the card status again to allow the
- * card to complete the BKOPs operation
- */
- msleep(BKOPS_COMPLETION_POLLING_INTERVAL_MS);
- } while (time_before(jiffies, timeout_jiffies));
-
- pr_err("%s: %s: exit polling due to timeout, stop bkops\n",
- mmc_hostname(card->host), __func__);
- err = mmc_stop_bkops(card);
- if (err)
- pr_err("%s: %s: mmc_stop_bkops failed, err=%d\n",
- mmc_hostname(card->host), __func__, err);
-
- return;
-out:
- mmc_release_host(card->host);
- mmc_rpm_release(card->host, &card->dev);
-}
-
-/**
* mmc_start_idle_time_bkops() - check if a non urgent BKOPS is
* needed
* @work: The idle time BKOPS work
@@ -1066,6 +986,36 @@
}
EXPORT_SYMBOL(mmc_wait_for_req);
+bool mmc_card_is_prog_state(struct mmc_card *card)
+{
+ bool rc;
+ struct mmc_command cmd;
+
+ mmc_claim_host(card->host);
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ cmd.opcode = MMC_SEND_STATUS;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ rc = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (rc) {
+ pr_err("%s: Get card status fail. rc=%d\n",
+ mmc_hostname(card->host), rc);
+ rc = false;
+ goto out;
+ }
+
+ if (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)
+ rc = true;
+ else
+ rc = false;
+out:
+ mmc_release_host(card->host);
+ return rc;
+}
+EXPORT_SYMBOL(mmc_card_is_prog_state);
+
/**
* mmc_interrupt_hpi - Issue for High priority Interrupt
* @card: the MMC card associated with the HPI transfer
@@ -1189,6 +1139,17 @@
if (!mmc_card_doing_bkops(card))
goto out;
+ /*
+ * If idle time bkops is running on the card, let's not get into
+ * suspend.
+ */
+ if (!mmc_use_core_runtime_pm(card->host) && mmc_card_doing_bkops(card)
+ && (card->host->parent->power.runtime_status == RPM_SUSPENDING)
+ && mmc_card_is_prog_state(card)) {
+ err = -EBUSY;
+ goto out;
+ }
+
err = mmc_interrupt_hpi(card);
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 6c03bfc..edd6a5d 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -253,11 +253,19 @@
* mmc_host_may_gate_card - check if this card may be gated
* @card: card to check.
*/
-static bool mmc_host_may_gate_card(struct mmc_card *card)
+bool mmc_host_may_gate_card(struct mmc_card *card)
{
/* If there is no card we may gate it */
if (!card)
return true;
+
+ /*
+ * SDIO3.0 card allows the clock to be gated off so check if
+ * that is the case or not.
+ */
+ if (mmc_card_sdio(card) && card->cccr.async_intr_sup)
+ return true;
+
/*
* Don't gate SDIO cards! These need to be clocked at all times
* since they may be independent systems generating interrupts
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 89f8c91..9b9c1ed 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -18,6 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/pm_runtime.h>
+#include <linux/reboot.h>
#include "core.h"
#include "bus.h"
@@ -900,6 +901,20 @@
return err;
}
+static int mmc_reboot_notify(struct notifier_block *notify_block,
+ unsigned long event, void *unused)
+{
+ struct mmc_card *card = container_of(
+ notify_block, struct mmc_card, reboot_notify);
+
+ if (event != SYS_RESTART)
+ card->issue_long_pon = true;
+ else
+ card->issue_long_pon = false;
+
+ return NOTIFY_OK;
+}
+
/*
* Handle the detection and initialisation of a card.
*
@@ -979,6 +994,7 @@
card->type = MMC_TYPE_MMC;
card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ card->reboot_notify.notifier_call = mmc_reboot_notify;
}
/*
@@ -1400,8 +1416,6 @@
if (card->ext_csd.bkops_en) {
INIT_DELAYED_WORK(&card->bkops_info.dw,
mmc_start_idle_time_bkops);
- INIT_WORK(&card->bkops_info.poll_for_completion,
- mmc_bkops_completion_polling);
/*
* Calculate the time to start the BKOPs checking.
@@ -1462,6 +1476,22 @@
return err;
}
+int mmc_send_long_pon(struct mmc_card *card)
+{
+ int err = 0;
+ struct mmc_host *host = card->host;
+
+ mmc_claim_host(host);
+ if (card->issue_long_pon && mmc_can_poweroff_notify(card)) {
+ err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_LONG);
+ if (err)
+ pr_warning("%s: error %d sending Long PON",
+ mmc_hostname(host), err);
+ }
+ mmc_release_host(host);
+ return err;
+}
+
/*
* Host is being removed. Free up the current card.
*/
@@ -1470,6 +1500,7 @@
BUG_ON(!host);
BUG_ON(!host->card);
+ unregister_reboot_notifier(&host->card->reboot_notify);
mmc_remove_card(host->card);
mmc_claim_host(host);
@@ -1736,6 +1767,8 @@
mmc_init_clk_scaling(host);
+ register_reboot_notifier(&host->card->reboot_notify);
+
return 0;
remove_card:
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 4e76f61..91e23ca 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -187,6 +187,23 @@
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
if (data & SDIO_DRIVE_SDTD)
card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION, 0, &data);
+ if (ret)
+ goto out;
+ if (data & SDIO_SUPPORT_ASYNC_INTR) {
+ if (card->host->caps2 &
+ MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) {
+ data |= SDIO_ENABLE_ASYNC_INTR;
+ ret = mmc_io_rw_direct(card, 1, 0,
+ SDIO_CCCR_INTERRUPT_EXTENSION,
+ data, NULL);
+ if (ret)
+ goto out;
+ card->cccr.async_intr_sup = 1;
+ }
+ }
}
/* if no uhs mode ensure we check for high speed */
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index caf5fe4..d872254 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3404,7 +3404,7 @@
else
clk |= MCI_CLK_WIDEBUS_1;
- if (msmsdcc_is_pwrsave(host))
+ if (msmsdcc_is_pwrsave(host) && mmc_host_may_gate_card(host->mmc->card))
clk |= MCI_CLK_PWRSAVE;
clk |= MCI_CLK_FLOWENA;
@@ -6147,6 +6147,7 @@
mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
+ mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
if (plat->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index a75687b..8312c16 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -103,6 +103,8 @@
#define CCU_PRONTO_LAST_ADDR1_OFFSET 0x10
#define CCU_PRONTO_LAST_ADDR2_OFFSET 0x14
+#define WCNSS_DEF_WLAN_RX_BUFF_COUNT 1024
+
#define WCNSS_CTRL_CHANNEL "WCNSS_CTRL"
#define WCNSS_MAX_FRAME_SIZE (4*1024)
#define WCNSS_VERSION_LEN 30
@@ -258,6 +260,7 @@
const struct dev_pm_ops *pm_ops;
int triggered;
int smd_channel_ready;
+ u32 wlan_rx_buff_count;
smd_channel_t *smd_ch;
unsigned char wcnss_version[WCNSS_VERSION_LEN];
unsigned char fw_major;
@@ -977,6 +980,17 @@
return -ENODEV;
}
+u32 wcnss_get_wlan_rx_buff_count(void)
+{
+ if (penv)
+ return penv->wlan_rx_buff_count;
+ else
+ return WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+
+}
+EXPORT_SYMBOL(wcnss_get_wlan_rx_buff_count);
+
+
static int wcnss_smd_tx(void *data, int len)
{
int ret = 0;
@@ -1035,6 +1049,8 @@
rc = wcnss_smd_tx(msg, rsphdr->msg_len);
if (rc < 0)
pr_err("wcnss: smd tx failed\n");
+
+ kfree(msg);
}
/* Collect calibrated data from WCNSS */
@@ -1496,7 +1512,12 @@
int size = 0;
struct resource *res;
int has_pronto_hw = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_pronto_hw");
+ "qcom,has-pronto-hw");
+
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,wlan-rx-buff-count", &penv->wlan_rx_buff_count)) {
+ penv->wlan_rx_buff_count = WCNSS_DEF_WLAN_RX_BUFF_COUNT;
+ }
/* make sure we are only triggered once */
if (penv->triggered)
@@ -1508,7 +1529,7 @@
if (WCNSS_CONFIG_UNSPECIFIED == has_48mhz_xo) {
if (has_pronto_hw) {
has_48mhz_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_48mhz_xo");
+ "qcom,has-48mhz-xo");
} else {
has_48mhz_xo = pdata->has_48mhz_xo;
}
@@ -1518,7 +1539,7 @@
if (WCNSS_CONFIG_UNSPECIFIED == has_autodetect_xo && has_pronto_hw) {
has_autodetect_xo = of_property_read_bool(pdev->dev.of_node,
- "qcom,has_autodetect_xo");
+ "qcom,has-autodetect-xo");
}
penv->thermal_mitigation = 0;
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index 7483a72..b0fb940 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -187,13 +187,6 @@
return;
switch (ep->client) {
- case IPA_CLIENT_HSIC1_CONS:
- case IPA_CLIENT_HSIC2_CONS:
- case IPA_CLIENT_HSIC3_CONS:
- case IPA_CLIENT_HSIC4_CONS:
- hol_en = ipa_ctx->hol_en;
- hol_tmr = ipa_ctx->hol_timer;
- break;
case IPA_CLIENT_A2_TETHERED_CONS:
case IPA_CLIENT_A2_EMBEDDED_CONS:
hol_en = IPA_A2_HOLB_TMR_EN;
diff --git a/drivers/platform/msm/ipa/teth_bridge.c b/drivers/platform/msm/ipa/teth_bridge.c
index add9522..93f2366 100644
--- a/drivers/platform/msm/ipa/teth_bridge.c
+++ b/drivers/platform/msm/ipa/teth_bridge.c
@@ -1683,6 +1683,12 @@
return -EINVAL;
}
+ res = teth_request_resource();
+ if (res) {
+ TETH_ERR("request_resource() failed.\n");
+ return res;
+ }
+
memcpy(&teth_ctx->aggr_params,
aggr_params,
sizeof(struct teth_aggr_params));
@@ -1693,6 +1699,8 @@
res = teth_set_aggregation();
if (res)
TETH_ERR("Failed setting aggregation params\n");
+
+ ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_BRIDGE_PROD);
TETH_DBG_FUNC_EXIT();
return res;
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 5f049a6..55cbfe9 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -171,6 +171,7 @@
static struct usb_bam_ctx_type ctx;
static struct device *hsic_host_dev;
+static bool hsic_host_dev_resumed_from_cons_request;
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
@@ -761,7 +762,7 @@
spin_lock(&usb_bam_ipa_handshake_info_lock);
/* If cable was disconnected, let disconnection seq do everything */
- if (info.disconnected) {
+ if (info.disconnected || info.cons_stopped) {
spin_unlock(&usb_bam_ipa_handshake_info_lock);
mutex_unlock(&info.suspend_resume_mutex);
pr_debug("%s: Cable disconnected\n", __func__);
@@ -771,7 +772,7 @@
/* If resume was called don't finish this work */
if (!info.bus_suspend) {
spin_unlock(&usb_bam_ipa_handshake_info_lock);
- pr_err("%s: Bus suspend in progress\n", __func__);
+ pr_err("%s: Bus resume in progress\n", __func__);
goto no_lpm;
}
spin_unlock(&usb_bam_ipa_handshake_info_lock);
@@ -897,6 +898,8 @@
break;
case HSIC_BAM:
+ hsic_host_dev_resumed_from_cons_request = true;
+
usb_bam_resume_hsic_host();
/*
@@ -946,13 +949,29 @@
}
spin_unlock(&usb_bam_lock);
- spin_lock(&usb_bam_ipa_handshake_info_lock);
- if (cur_bam == HSUSB_BAM && info.bus_suspend)
- queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend)
+ queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
- pr_debug("%s: EINPROGRESS cons_release", __func__);
- return -EINPROGRESS;
+ pr_debug("%s: EINPROGRESS cons_release", __func__);
+ return -EINPROGRESS;
+ } else if (cur_bam == HSIC_BAM) {
+
+ /*
+ * 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]) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_put(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = true;
+ }
+ }
+
+ return 0;
}
static int hsic_cons_release_resource(void)
@@ -1043,7 +1062,7 @@
pr_debug("%s: Waiting for CONS\n", __func__);
if (info.cur_cons_state[cur_bam] != IPA_RM_RESOURCE_GRANTED) {
if (!wait_for_completion_timeout(&info.cons_avail[cur_bam],
- USB_BAM_TIMEOUT*6))
+ USB_BAM_TIMEOUT))
pr_err("%s: Timeout wainting for CONS_REQUEST\n",
__func__);
pr_err("%s: Finished waiting for CONS\n", __func__);
@@ -1314,6 +1333,9 @@
void msm_bam_wait_for_hsic_prod_granted(void)
{
+ if (hsic_host_dev_resumed_from_cons_request)
+ return;
+
ctx.is_bam_inactivity[HSIC_BAM] = false;
/* Get back to resume state including wakeup ipa */
@@ -1331,8 +1353,11 @@
* and clocked on. Therefore we can now set the inactivity
* timer to the hsic bam hw.
*/
- if (ctx.inactivity_timer_ms[HSIC_BAM])
+ if (ctx.inactivity_timer_ms[HSIC_BAM] &&
+ !hsic_host_dev_resumed_from_cons_request)
usb_bam_set_inactivity_timer(HSIC_BAM);
+
+ hsic_host_dev_resumed_from_cons_request = false;
}
bool msm_bam_hsic_lpm_ok(void)
@@ -1345,18 +1370,6 @@
pr_debug("%s: Starting hsic full suspend sequence\n",
__func__);
- info.lpm_wait_handshake[HSIC_BAM] = true;
-
- wait_for_prod_release(HSIC_BAM);
- pr_debug("%s: complete wait on hsic producer s=%d\n",
- __func__, info.cur_prod_state[HSIC_BAM]);
-
- wait_for_cons_release(HSIC_BAM);
- pr_debug("%s: complete wait on hsic consumer s=%d\n",
- __func__, info.cur_cons_state[HSIC_BAM]);
-
- info.lpm_wait_handshake[HSIC_BAM] = false;
-
/*
* Start low power mode by releasing the device
* only in case that indeed the resources were released
@@ -1366,9 +1379,6 @@
*/
spin_lock(&usb_bam_lock);
- pr_debug("%s: goto lpm?, inactivity=%d\n",
- __func__, ctx.is_bam_inactivity[HSIC_BAM]);
-
if (info.cur_cons_state[HSIC_BAM] ==
IPA_RM_RESOURCE_RELEASED &&
info.cur_prod_state[HSIC_BAM] ==
@@ -1397,14 +1407,18 @@
return true;
}
- /* We not allow lpm, therefore renew our vote here */
+ /* We don't allow lpm, therefore renew our vote here */
if (info.in_lpm[HSIC_BAM]) {
- pr_debug("%s: Getting hsic device %x\n", __func__,
- (int)hsic_host_dev);
+ pr_err("%s: Not allow lpm while ref count=0\n",
+ __func__);
+ pr_err("%s: inactivity=%d, c_s=%d p_s=%d lpm=%d\n",
+ __func__, ctx.is_bam_inactivity[HSIC_BAM],
+ info.cur_cons_state[HSIC_BAM],
+ info.cur_prod_state[HSIC_BAM],
+ info.in_lpm[HSIC_BAM]);
pm_runtime_get(hsic_host_dev);
info.in_lpm[HSIC_BAM] = false;
spin_unlock(&usb_bam_lock);
- wait_for_prod_granted(HSIC_BAM, false);
} else
spin_unlock(&usb_bam_lock);
@@ -1652,21 +1666,28 @@
}
spin_unlock(&usb_bam_lock);
+ /* Notify about the inactivity to the USB class driver */
+ if (callback)
+ callback(param);
+
+ wait_for_prod_release(pipe_connect->bam_type);
+ pr_debug("%s: complete wait on hsic producer s=%d\n",
+ __func__, info.cur_prod_state[pipe_connect->bam_type]);
+
/*
- * Allow to go to lpm for now. Actual state will be checked
- * in msm_bam_hsic_lpm_ok() just before going to lpm.
+ * Allow to go to lpm for now if also consumer is down.
+ * If consumer is up, we will wait to the release consumer
+ * notification.
*/
- if (hsic_host_dev) {
+ if (hsic_host_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);
info.in_lpm[HSIC_BAM] = true;
}
- /* Notify about the inactivity to the USB class driver */
- if (callback)
- callback(param);
-
break;
default:
pr_err("%s: unknown usb bam event type %d\n", __func__,
@@ -1700,21 +1721,6 @@
*/
ctx.is_bam_inactivity[bam] = false;
- /*
- * In case that this wakeup event occured while we are
- * waiting to release of the resurces in order to get into
- * low power mode, just cancle the waiting.
- */
- if (info.lpm_wait_handshake[bam]) {
- pr_debug("%s: cancel waiting for lpm\n", __func__);
- if (info.cur_prod_state[bam] !=
- IPA_RM_RESOURCE_RELEASED)
- complete_all(&info.prod_released[bam]);
- if (info.cur_cons_state[bam] !=
- IPA_RM_RESOURCE_RELEASED)
- complete_all(&info.cons_released[bam]);
- }
-
queue_work(ctx.usb_bam_wq, &event_info->event_w);
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 3802858..03aa280 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -229,6 +229,7 @@
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_RESISTANCE,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
@@ -860,21 +861,23 @@
}
/**
- * calculate_cc-
+ * calculate_cc() - converts a hardware coulomb counter reading into uah
* @chip: the bms chip pointer
* @cc: the cc reading from bms h/w
- * @val: return value
- * @coulomb_counter: adjusted coulomb counter for 100%
+ * @clear_cc: whether this function should clear the hardware counter
+ * after reading
*
- * RETURNS: in val pointer coulomb counter based charger in uAh
- * (micro Amp hour)
+ * Converts the 64 bit hardware coulomb counter into microamp-hour by taking
+ * into account hardware resolution and adc errors.
+ *
+ * Return: the coulomb counter based charge in uAh (micro-amp hour)
*/
-static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
+static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc, bool clear_cc)
{
struct qpnp_iadc_calib calibration;
struct qpnp_vadc_result result;
int64_t cc_voltage_uv, cc_pvh, cc_uah;
- int ibat_ua, rc;
+ int rc;
rc = qpnp_vadc_read(DIE_TEMP, &result);
if (rc) {
@@ -882,12 +885,6 @@
return chip->software_cc_uah;
}
- rc = get_battery_current(chip, &ibat_ua);
- if (rc) {
- pr_err("could not read battery current: %d\n", rc);
- return chip->software_cc_uah;
- }
-
qpnp_iadc_get_gain_and_offset(&calibration);
pr_debug("cc = %lld, die_temp = %lld\n", cc, result.physical);
cc_voltage_uv = cc_reading_to_uv(cc);
@@ -901,9 +898,14 @@
rc = qpnp_iadc_comp_result(&cc_uah);
if (rc)
pr_debug("error compensation failed: %d\n", rc);
- chip->software_cc_uah += cc_uah;
- reset_cc(chip);
- return (int)chip->software_cc_uah;
+
+ if (clear_cc) {
+ chip->software_cc_uah += cc_uah;
+ reset_cc(chip);
+ return (int)chip->software_cc_uah;
+ } else {
+ return chip->software_cc_uah + cc_uah;
+ }
}
static int get_rbatt(struct qpnp_bms_chip *chip,
@@ -1232,7 +1234,7 @@
pr_debug("ocv_charge_uah = %uuAh\n", params->ocv_charge_uah);
/* calculate cc micro_volt_hour */
- params->cc_uah = calculate_cc(chip, raw->cc);
+ params->cc_uah = calculate_cc(chip, raw->cc, true);
pr_debug("cc_uah = %duAh raw->cc = %llx\n", params->cc_uah, raw->cc);
soc_rbatt = ((params->ocv_charge_uah - params->cc_uah) * 100)
@@ -1552,7 +1554,7 @@
struct soc_params *params, int soc,
int vbat_uv, int ibat_ua, int batt_temp)
{
- int chg_soc, batt_terminal_uv;
+ int chg_soc, soc_ibat, batt_terminal_uv, weight_ibat, weight_cc;
batt_terminal_uv = vbat_uv + VBATT_ERROR_MARGIN
+ (ibat_ua * chip->r_conn_mohm) / 1000;
@@ -1590,10 +1592,16 @@
return chip->prev_chg_soc;
}
- chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
+ soc_ibat = bound_soc(linear_interpolate(chip->soc_at_cv,
+ chip->ibat_at_cv_ua,
100, -1 * chip->chg_term_ua,
- ibat_ua);
- chg_soc = bound_soc(chg_soc);
+ ibat_ua));
+ weight_ibat = bound_soc(linear_interpolate(1, chip->soc_at_cv,
+ 100, 100, chip->prev_chg_soc));
+ weight_cc = 100 - weight_ibat;
+ chg_soc = bound_soc((soc_ibat * weight_ibat + weight_cc * soc)/100);
+ pr_debug("weight_ibat = %d, weight_cc = %d, soc_ibat = %d, soc_cc = %d\n",
+ weight_ibat, weight_cc, soc_ibat, soc);
/* always report a higher soc */
if (chg_soc > chip->prev_chg_soc) {
@@ -2349,6 +2357,20 @@
return result_ua;
}
+/* Returns coulomb counter in uAh */
+static int get_prop_bms_charge_counter(struct qpnp_bms_chip *chip)
+{
+ int64_t cc_raw;
+
+ mutex_lock(&chip->bms_output_lock);
+ lock_output_data(chip);
+ read_cc_raw(chip, &cc_raw);
+ unlock_output_data(chip);
+ mutex_unlock(&chip->bms_output_lock);
+
+ return calculate_cc(chip, cc_raw, false);
+}
+
/* Returns full charge design in uAh */
static int get_prop_bms_charge_full_design(struct qpnp_bms_chip *chip)
{
@@ -2381,6 +2403,9 @@
case POWER_SUPPLY_PROP_RESISTANCE:
val->intval = get_prop_bms_batt_resistance(chip);
break;
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ val->intval = get_prop_bms_charge_counter(chip);
+ break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index a5da421..352889d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -2363,6 +2363,7 @@
spmi_resource->of_node);
if (IS_ERR(chip->otg_vreg.rdev)) {
rc = PTR_ERR(chip->otg_vreg.rdev);
+ chip->otg_vreg.rdev = NULL;
if (rc != -EPROBE_DEFER)
pr_err("OTG reg failed, rc=%d\n", rc);
return rc;
@@ -2421,6 +2422,7 @@
spmi_resource->of_node);
if (IS_ERR(chip->boost_vreg.rdev)) {
rc = PTR_ERR(chip->boost_vreg.rdev);
+ chip->boost_vreg.rdev = NULL;
if (rc != -EPROBE_DEFER)
pr_err("boost reg failed, rc=%d\n", rc);
return rc;
@@ -2846,6 +2848,8 @@
if (chip->bat_if_base)
power_supply_unregister(&chip->batt_psy);
fail_chg_enable:
+ regulator_unregister(chip->otg_vreg.rdev);
+ regulator_unregister(chip->boost_vreg.rdev);
kfree(chip->thermal_mitigation);
kfree(chip);
dev_set_drvdata(&spmi->dev, NULL);
@@ -2863,11 +2867,8 @@
cancel_work_sync(&chip->adc_measure_work);
cancel_delayed_work_sync(&chip->eoc_work);
- if (chip->otg_vreg.rdev)
- regulator_unregister(chip->otg_vreg.rdev);
-
- if (chip->boost_vreg.rdev)
- regulator_unregister(chip->boost_vreg.rdev);
+ regulator_unregister(chip->otg_vreg.rdev);
+ regulator_unregister(chip->boost_vreg.rdev);
dev_set_drvdata(&spmi->dev, NULL);
kfree(chip);
diff --git a/drivers/rtc/alarm-dev.c b/drivers/rtc/alarm-dev.c
index bfcaebc..1d60e97 100644
--- a/drivers/rtc/alarm-dev.c
+++ b/drivers/rtc/alarm-dev.c
@@ -98,6 +98,8 @@
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
+ if (alarm_type == ANDROID_ALARM_RTC_WAKEUP)
+ set_power_on_alarm(0);
spin_unlock_irqrestore(&alarm_slock, flags);
break;
@@ -125,6 +127,10 @@
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
+ if ((alarm_type == ANDROID_ALARM_RTC_WAKEUP) &&
+ (ANDROID_ALARM_BASE_CMD(cmd) ==
+ ANDROID_ALARM_SET(0)))
+ set_power_on_alarm(new_alarm_time.tv_sec);
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 9340af7..e318ecf 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -68,6 +68,13 @@
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
+static long power_on_alarm;
+
+void set_power_on_alarm(long secs)
+{
+ power_on_alarm = secs;
+}
+
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
@@ -486,6 +493,45 @@
return 0;
}
+static void alarm_shutdown(struct platform_device *dev)
+{
+ struct timespec wall_time;
+ struct rtc_time rtc_time;
+ struct rtc_wkalrm alarm;
+ unsigned long flags;
+ long rtc_secs, alarm_delta, alarm_time;
+ int rc;
+
+ spin_lock_irqsave(&alarm_slock, flags);
+
+ if (!power_on_alarm)
+ goto disable_alarm;
+
+ rtc_read_time(alarm_rtc_dev, &rtc_time);
+ getnstimeofday(&wall_time);
+ rtc_tm_to_time(&rtc_time, &rtc_secs);
+ alarm_delta = wall_time.tv_sec - rtc_secs;
+ alarm_time = power_on_alarm - alarm_delta;
+ if (alarm_time <= rtc_secs)
+ goto disable_alarm;
+
+ rtc_time_to_tm(alarm_time, &alarm.time);
+ alarm.enabled = 1;
+ rc = rtc_set_alarm(alarm_rtc_dev, &alarm);
+ if (rc)
+ pr_alarm(ERROR, "Unable to set power-on alarm\n");
+ else
+ pr_alarm(FLOW, "Power-on alarm set to %lu\n",
+ alarm_time);
+
+ spin_unlock_irqrestore(&alarm_slock, flags);
+ return;
+
+disable_alarm:
+ rtc_alarm_irq_enable(alarm_rtc_dev, 0);
+ spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
@@ -545,6 +591,7 @@
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
+ .shutdown = alarm_shutdown,
.driver = {
.name = "alarm"
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index c5aa7e5..18dd054 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,11 +39,16 @@
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/atomic.h>
+#include <linux/pm_runtime.h>
#include <mach/msm_spi.h>
#include <mach/sps.h>
#include <mach/dma.h>
#include "spi_qsd.h"
+static int msm_spi_pm_resume_runtime(struct device *device);
+static int msm_spi_pm_suspend_runtime(struct device *device);
+
+
static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
struct platform_device *pdev)
{
@@ -859,6 +864,10 @@
u32 op, ret = IRQ_NONE;
struct msm_spi *dd = dev_id;
+ if (pm_runtime_suspended(dd->dev)) {
+ dev_warn(dd->dev, "QUP: pm runtime suspend, irq:%d\n", irq);
+ return ret;
+ }
if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
struct spi_master *master = dev_get_drvdata(dd->dev);
@@ -1705,36 +1714,22 @@
container_of(work, struct msm_spi, work_data);
unsigned long flags;
u32 status_error = 0;
- int rc = 0;
+
+ pm_runtime_get_sync(dd->dev);
mutex_lock(&dd->core_lock);
- /* Don't allow power collapse until we release mutex */
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- dd->pm_lat);
+ /*
+ * Counter-part of system-suspend when runtime-pm is not enabled.
+ * This way, resume can be left empty and device will be put in
+ * active mode only if client requests anything on the bus
+ */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi and cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(dd->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- status_error = 1;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc)
- status_error = 1;
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
- msm_spi_enable_irqs(dd);
-
if (!msm_spi_is_valid_state(dd)) {
dev_err(dd->dev, "%s: SPI operational state not valid\n",
__func__);
@@ -1742,6 +1737,7 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
+ dd->transfer_pending = 1;
while (!list_empty(&dd->queue)) {
dd->cur_msg = list_entry(dd->queue.next,
struct spi_message, queue);
@@ -1758,24 +1754,14 @@
dd->transfer_pending = 0;
spin_unlock_irqrestore(&dd->queue_lock, flags);
- msm_spi_disable_irqs(dd);
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
-
- /* Free the spi clk, miso, mosi, cs gpio */
- if (!rc && dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- if (!rc)
- msm_spi_free_gpios(dd);
-
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
- if (pm_qos_request_active(&qos_req_list))
- pm_qos_update_request(&qos_req_list,
- PM_QOS_DEFAULT_VALUE);
-
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
/* If needed, this can be done after the current message is complete,
and work can be continued upon resume. No motivation for now. */
if (dd->suspended)
@@ -1789,8 +1775,6 @@
struct spi_transfer *tr;
dd = spi_master_get_devdata(spi->master);
- if (dd->suspended)
- return -EBUSY;
if (list_empty(&msg->transfers) || !msg->complete)
return -EINVAL;
@@ -1810,11 +1794,6 @@
}
spin_lock_irqsave(&dd->queue_lock, flags);
- if (dd->suspended) {
- spin_unlock_irqrestore(&dd->queue_lock, flags);
- return -EBUSY;
- }
- dd->transfer_pending = 1;
list_add_tail(&msg->queue, &dd->queue);
spin_unlock_irqrestore(&dd->queue_lock, flags);
queue_work(dd->workqueue, &dd->work_data);
@@ -1845,7 +1824,14 @@
dd = spi_master_get_devdata(spi->master);
+ pm_runtime_get_sync(dd->dev);
+
mutex_lock(&dd->core_lock);
+
+ /* Counter-part of system-suspend when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_resume_runtime(dd->dev);
+
if (dd->suspended) {
mutex_unlock(&dd->core_lock);
return -EBUSY;
@@ -1854,27 +1840,6 @@
if (dd->use_rlock)
remote_mutex_lock(&dd->r_lock);
- /* Configure the spi clk, miso, mosi, cs gpio */
- if (dd->pdata->gpio_config) {
- rc = dd->pdata->gpio_config();
- if (rc) {
- dev_err(&spi->dev,
- "%s: error configuring GPIOs\n",
- __func__);
- rc = -ENXIO;
- goto err_setup_gpio;
- }
- }
-
- rc = msm_spi_request_gpios(dd);
- if (rc) {
- rc = -ENXIO;
- goto err_setup_gpio;
- }
-
- clk_prepare_enable(dd->clk);
- clk_prepare_enable(dd->pclk);
-
spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
if (spi->mode & SPI_CS_HIGH)
@@ -1892,18 +1857,19 @@
/* Ensure previous write completed before disabling the clocks */
mb();
- clk_disable_unprepare(dd->clk);
- clk_disable_unprepare(dd->pclk);
- /* Free the spi clk, miso, mosi, cs gpio */
- if (dd->pdata && dd->pdata->gpio_release)
- dd->pdata->gpio_release();
- msm_spi_free_gpios(dd);
-
-err_setup_gpio:
if (dd->use_rlock)
remote_mutex_unlock(&dd->r_lock);
+
+ /* Counter-part of system-resume when runtime-pm is not enabled. */
+ if (!pm_runtime_enabled(dd->dev))
+ msm_spi_pm_suspend_runtime(dd->dev);
+
mutex_unlock(&dd->core_lock);
+
+ pm_runtime_mark_last_busy(dd->dev);
+ pm_runtime_put_autosuspend(dd->dev);
+
err_setup_exit:
return rc;
}
@@ -2729,7 +2695,7 @@
clk_enabled = 0;
pclk_enabled = 0;
- dd->suspended = 0;
+ dd->suspended = 1;
dd->transfer_pending = 0;
dd->multi_xfr = 0;
dd->mode = SPI_MODE_NONE;
@@ -2745,6 +2711,10 @@
mutex_unlock(&dd->core_lock);
locked = 0;
+ pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
rc = spi_register_master(master);
if (rc)
goto err_probe_reg_master;
@@ -2762,6 +2732,7 @@
err_attrs:
spi_unregister_master(master);
err_probe_reg_master:
+ pm_runtime_disable(&pdev->dev);
err_probe_irq:
err_probe_state:
if (dd->dma_teardown)
@@ -2795,48 +2766,130 @@
}
#ifdef CONFIG_PM
-static int msm_spi_suspend(struct platform_device *pdev, pm_message_t state)
+static int msm_spi_pm_suspend_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
- unsigned long flags;
+ struct msm_spi *dd;
+ unsigned long flags;
+ dev_dbg(device, "pm_runtime: suspending...\n");
if (!master)
goto suspend_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto suspend_exit;
- /* Make sure nothing is added to the queue while we're suspending */
+ if (dd->suspended)
+ return 0;
+
+ /*
+ * Make sure nothing is added to the queue while we're
+ * suspending
+ */
spin_lock_irqsave(&dd->queue_lock, flags);
dd->suspended = 1;
spin_unlock_irqrestore(&dd->queue_lock, flags);
/* Wait for transactions to end, or time out */
- wait_event_interruptible(dd->continue_suspend, !dd->transfer_pending);
+ wait_event_interruptible(dd->continue_suspend,
+ !dd->transfer_pending);
+ msm_spi_disable_irqs(dd);
+ clk_disable_unprepare(dd->clk);
+ clk_disable_unprepare(dd->pclk);
+
+ /* Free the spi clk, miso, mosi, cs gpio */
+ if (dd->pdata && dd->pdata->gpio_release)
+ dd->pdata->gpio_release();
+
+ msm_spi_free_gpios(dd);
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ PM_QOS_DEFAULT_VALUE);
suspend_exit:
return 0;
}
-static int msm_spi_resume(struct platform_device *pdev)
+static int msm_spi_pm_resume_runtime(struct device *device)
{
+ struct platform_device *pdev = to_platform_device(device);
struct spi_master *master = platform_get_drvdata(pdev);
- struct msm_spi *dd;
+ struct msm_spi *dd;
+ int ret = 0;
+ dev_dbg(device, "pm_runtime: resuming...\n");
if (!master)
goto resume_exit;
dd = spi_master_get_devdata(master);
if (!dd)
goto resume_exit;
+ if (!dd->suspended)
+ return 0;
+
+ if (pm_qos_request_active(&qos_req_list))
+ pm_qos_update_request(&qos_req_list,
+ dd->pm_lat);
+
+ /* Configure the spi clk, miso, mosi and cs gpio */
+ if (dd->pdata->gpio_config) {
+ ret = dd->pdata->gpio_config();
+ if (ret) {
+ dev_err(dd->dev,
+ "%s: error configuring GPIOs\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ ret = msm_spi_request_gpios(dd);
+ if (ret)
+ return ret;
+
+ clk_prepare_enable(dd->clk);
+ clk_prepare_enable(dd->pclk);
+ msm_spi_enable_irqs(dd);
dd->suspended = 0;
resume_exit:
return 0;
}
+
+static int msm_spi_suspend(struct device *device)
+{
+ if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
+ struct platform_device *pdev = to_platform_device(device);
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct msm_spi *dd;
+
+ dev_dbg(device, "system suspend");
+ if (!master)
+ goto suspend_exit;
+ dd = spi_master_get_devdata(master);
+ if (!dd)
+ goto suspend_exit;
+ msm_spi_pm_suspend_runtime(device);
+ }
+suspend_exit:
+ return 0;
+}
+
+static int msm_spi_resume(struct device *device)
+{
+ /*
+ * Rely on runtime-PM to call resume in case it is enabled
+ * Even if it's not enabled, rely on 1st client transaction to do
+ * clock ON and gpio configuration
+ */
+ dev_dbg(device, "system resume");
+ return 0;
+}
#else
#define msm_spi_suspend NULL
#define msm_spi_resume NULL
+#define msm_spi_pm_suspend_runtime NULL
+#define msm_spi_pm_resume_runtime NULL
#endif /* CONFIG_PM */
static int __devexit msm_spi_remove(struct platform_device *pdev)
@@ -2850,6 +2903,8 @@
if (dd->dma_teardown)
dd->dma_teardown(dd);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_put(dd->clk);
clk_put(dd->pclk);
destroy_workqueue(dd->workqueue);
@@ -2867,14 +2922,19 @@
{}
};
+static const struct dev_pm_ops msm_spi_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msm_spi_suspend, msm_spi_resume)
+ SET_RUNTIME_PM_OPS(msm_spi_pm_suspend_runtime,
+ msm_spi_pm_resume_runtime, NULL)
+};
+
static struct platform_driver msm_spi_driver = {
.driver = {
.name = SPI_DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &msm_spi_dev_pm_ops,
.of_match_table = msm_spi_dt_match,
},
- .suspend = msm_spi_suspend,
- .resume = msm_spi_resume,
.remove = __exit_p(msm_spi_remove),
};
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 890a897..4d464c1 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1974,7 +1974,8 @@
switch (msm_uport->clk_state) {
case MSM_HS_CLK_OFF:
wake_lock(&msm_uport->dma_wake_lock);
- disable_irq_nosync(msm_uport->wakeup.irq);
+ if (use_low_power_wakeup(msm_uport))
+ disable_irq_nosync(msm_uport->wakeup.irq);
spin_unlock_irqrestore(&uport->lock, flags);
/* Vote for PNOC BUS Scaling */
@@ -2348,7 +2349,8 @@
free_uart_irq:
free_irq(uport->irq, msm_uport);
free_wake_irq:
- irq_set_irq_wake(msm_uport->wakeup.irq, 0);
+ if (use_low_power_wakeup(msm_uport))
+ irq_set_irq_wake(msm_uport->wakeup.irq, 0);
sps_disconnect_rx:
if (is_blsp_uart(msm_uport))
sps_disconnect(sps_pipe_handle_rx);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index bc1fa07..36a43c3 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -91,6 +91,7 @@
#include "u_uac1.c"
#include "f_uac1.c"
#endif
+#include "f_ncm.c"
MODULE_AUTHOR("Mike Lockwood");
MODULE_DESCRIPTION("Android Composite USB Driver");
@@ -524,7 +525,7 @@
data->opened = false;
- if (data->enabled)
+ if (data->enabled && dev)
android_disable(dev);
data->dev = NULL;
@@ -792,7 +793,103 @@
.bind_config = gps_function_bind_config,
};
+/* ncm */
+struct ncm_function_config {
+ u8 ethaddr[ETH_ALEN];
+};
+static int
+ncm_function_init(struct android_usb_function *f, struct usb_composite_dev *c)
+{
+ f->config = kzalloc(sizeof(struct ncm_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+ return 0;
+}
+
+static void ncm_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int
+ncm_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ncm_function_config *ncm = f->config;
+ int ret;
+
+ if (!ncm) {
+ pr_err("%s: ncm config is null\n", __func__);
+ return -EINVAL;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, ncm->ethaddr, "ncm");
+ if (ret) {
+ pr_err("%s: gether setup failed err:%d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = ncm_bind_config(c, ncm->ethaddr);
+ if (ret) {
+ pr_err("%s: ncm bind config failed err:%d", __func__, ret);
+ gether_cleanup();
+ return ret;
+ }
+
+ return ret;
+}
+
+static void ncm_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static ssize_t ncm_ethaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+ return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ncm->ethaddr[0], ncm->ethaddr[1], ncm->ethaddr[2],
+ ncm->ethaddr[3], ncm->ethaddr[4], ncm->ethaddr[5]);
+}
+
+static ssize_t ncm_ethaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct ncm_function_config *ncm = f->config;
+
+ if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (int *)&ncm->ethaddr[0], (int *)&ncm->ethaddr[1],
+ (int *)&ncm->ethaddr[2], (int *)&ncm->ethaddr[3],
+ (int *)&ncm->ethaddr[4], (int *)&ncm->ethaddr[5]) == 6)
+ return size;
+ return -EINVAL;
+}
+
+static DEVICE_ATTR(ncm_ethaddr, S_IRUGO | S_IWUSR, ncm_ethaddr_show,
+ ncm_ethaddr_store);
+static struct device_attribute *ncm_function_attributes[] = {
+ &dev_attr_ncm_ethaddr,
+ NULL
+};
+
+static struct android_usb_function ncm_function = {
+ .name = "ncm",
+ .init = ncm_function_init,
+ .cleanup = ncm_function_cleanup,
+ .bind_config = ncm_function_bind_config,
+ .unbind_config = ncm_function_unbind_config,
+ .attributes = ncm_function_attributes,
+};
/* ecm transport string */
static char ecm_transports[MAX_XPORT_STR_LEN];
@@ -1857,6 +1954,7 @@
&rndis_function,
&rndis_qc_function,
&ecm_function,
+ &ncm_function,
&mass_storage_function,
&accessory_function,
#ifdef CONFIG_SND_PCM
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index e48f94c..aaacd43 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -63,10 +63,10 @@
};
enum mbim_notify_state {
- NCM_NOTIFY_NONE,
- NCM_NOTIFY_CONNECT,
- NCM_NOTIFY_SPEED,
- NCM_NOTIFY_RESPONSE_AVAILABLE,
+ MBIM_NOTIFY_NONE,
+ MBIM_NOTIFY_CONNECT,
+ MBIM_NOTIFY_SPEED,
+ MBIM_NOTIFY_RESPONSE_AVAILABLE,
};
struct f_mbim {
@@ -95,7 +95,7 @@
u8 ctrl_id, data_id;
u8 data_alt_int;
- struct ndp_parser_opts *parser_opts;
+ struct mbim_ndp_parser_opts *parser_opts;
spinlock_t lock;
@@ -140,24 +140,24 @@
/*-------------------------------------------------------------------------*/
-#define NTB_DEFAULT_IN_SIZE (0x4000)
-#define NTB_OUT_SIZE (0x1000)
-#define NDP_IN_DIVISOR (0x4)
+#define MBIM_NTB_DEFAULT_IN_SIZE (0x4000)
+#define MBIM_NTB_OUT_SIZE (0x1000)
+#define MBIM_NDP_IN_DIVISOR (0x4)
#define NTB_DEFAULT_IN_SIZE_IPA (0x2000)
-#define NTB_OUT_SIZE_IPA (0x2000)
+#define MBIM_NTB_OUT_SIZE_IPA (0x2000)
-#define FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
+#define MBIM_FORMATS_SUPPORTED USB_CDC_NCM_NTB16_SUPPORTED
-static struct usb_cdc_ncm_ntb_parameters ntb_parameters = {
- .wLength = sizeof ntb_parameters,
- .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED),
- .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE),
- .wNdpInDivisor = cpu_to_le16(NDP_IN_DIVISOR),
+static struct usb_cdc_ncm_ntb_parameters mbim_ntb_parameters = {
+ .wLength = sizeof mbim_ntb_parameters,
+ .bmNtbFormatsSupported = cpu_to_le16(MBIM_FORMATS_SUPPORTED),
+ .dwNtbInMaxSize = cpu_to_le32(MBIM_NTB_DEFAULT_IN_SIZE),
+ .wNdpInDivisor = cpu_to_le16(MBIM_NDP_IN_DIVISOR),
.wNdpInPayloadRemainder = cpu_to_le16(0),
.wNdpInAlignment = cpu_to_le16(4),
- .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE),
+ .dwNtbOutMaxSize = cpu_to_le32(MBIM_NTB_OUT_SIZE),
.wNdpOutDivisor = cpu_to_le16(4),
.wNdpOutPayloadRemainder = cpu_to_le16(0),
.wNdpOutAlignment = cpu_to_le16(4),
@@ -444,7 +444,7 @@
* and switch pointers to the structures when the format is changed.
*/
-struct ndp_parser_opts {
+struct mbim_ndp_parser_opts {
u32 nth_sign;
u32 ndp_sign;
unsigned nth_size;
@@ -487,8 +487,8 @@
.next_fp_index = 2, \
}
-static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS;
-static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp16_opts = INIT_NDP16_OPTS;
+static struct mbim_ndp_parser_opts mbim_ndp32_opts = INIT_NDP32_OPTS;
static inline int mbim_lock(atomic_t *excl)
{
@@ -630,7 +630,7 @@
return 0;
}
- if (dev->not_port.notify_state != NCM_NOTIFY_RESPONSE_AVAILABLE) {
+ if (dev->not_port.notify_state != MBIM_NOTIFY_RESPONSE_AVAILABLE) {
pr_err("dev:%p state=%d, recover!!\n", dev,
dev->not_port.notify_state);
mbim_free_ctrl_pkt(cpkt);
@@ -670,12 +670,14 @@
int ret = 0;
aggr_params.dl.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.dl.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.dl.max_transfer_size_byte = ntb_parameters.dwNtbInMaxSize;
+ aggr_params.dl.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.dl.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbInMaxSize;
aggr_params.ul.aggr_prot = TETH_AGGR_PROTOCOL_MBIM;
- aggr_params.ul.max_datagrams = ntb_parameters.wNtbOutMaxDatagrams;
- aggr_params.ul.max_transfer_size_byte = ntb_parameters.dwNtbOutMaxSize;
+ aggr_params.ul.max_datagrams = mbim_ntb_parameters.wNtbOutMaxDatagrams;
+ aggr_params.ul.max_transfer_size_byte =
+ mbim_ntb_parameters.dwNtbOutMaxSize;
ret = teth_bridge_set_aggr_params(&aggr_params);
if (ret)
@@ -731,9 +733,9 @@
static inline void mbim_reset_values(struct f_mbim *mbim)
{
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
- mbim->ntb_input_size = NTB_DEFAULT_IN_SIZE;
+ mbim->ntb_input_size = MBIM_NTB_DEFAULT_IN_SIZE;
atomic_set(&mbim->online, 0);
}
@@ -809,15 +811,15 @@
switch (mbim->not_port.notify_state) {
- case NCM_NOTIFY_NONE:
+ case MBIM_NOTIFY_NONE:
if (atomic_read(&mbim->not_port.notify_count) > 0)
- pr_err("Pending notifications in NCM_NOTIFY_NONE\n");
+ pr_err("Pending notifications in MBIM_NOTIFY_NONE\n");
else
pr_debug("No pending notifications\n");
return;
- case NCM_NOTIFY_RESPONSE_AVAILABLE:
+ case MBIM_NOTIFY_RESPONSE_AVAILABLE:
pr_debug("Notification %02x sent\n", event->bNotificationType);
if (atomic_read(&mbim->not_port.notify_count) <= 0) {
@@ -874,7 +876,7 @@
case -ECONNRESET:
case -ESHUTDOWN:
/* connection gone */
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
atomic_set(&mbim->not_port.notify_count, 0);
pr_info("ESHUTDOWN/ECONNRESET, connection gone");
spin_unlock(&mbim->lock);
@@ -913,7 +915,7 @@
if (req->length == 4) {
in_size = get_unaligned_le32(req->buf);
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -921,7 +923,7 @@
ntb = (struct mbim_ntb_input_size *)req->buf;
in_size = get_unaligned_le32(&(ntb->ntb_input_size));
if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE ||
- in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) {
+ in_size > le32_to_cpu(mbim_ntb_parameters.dwNtbInMaxSize)) {
pr_err("Illegal INPUT SIZE (%d) from host\n", in_size);
goto invalid;
}
@@ -1080,9 +1082,9 @@
if (w_length == 0 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- value = w_length > sizeof ntb_parameters ?
- sizeof ntb_parameters : w_length;
- memcpy(req->buf, &ntb_parameters, value);
+ value = w_length > sizeof mbim_ntb_parameters ?
+ sizeof mbim_ntb_parameters : w_length;
+ memcpy(req->buf, &mbim_ntb_parameters, value);
break;
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
@@ -1129,7 +1131,7 @@
if (w_length < 2 || w_value != 0 || w_index != mbim->ctrl_id)
break;
- format = (mbim->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001;
+ format = (mbim->parser_opts == &mbim_ndp16_opts) ? 0 : 1;
put_unaligned_le16(format, req->buf);
value = 2;
pr_debug("NTB FORMAT: sending %d\n", format);
@@ -1145,11 +1147,11 @@
break;
switch (w_value) {
case 0x0000:
- mbim->parser_opts = &ndp16_opts;
+ mbim->parser_opts = &mbim_ndp16_opts;
pr_debug("NCM16 selected\n");
break;
case 0x0001:
- mbim->parser_opts = &ndp32_opts;
+ mbim->parser_opts = &mbim_ndp32_opts;
pr_debug("NCM32 selected\n");
break;
default:
@@ -1343,7 +1345,7 @@
mbim->data_alt_int = alt;
spin_lock(&mbim->lock);
- mbim->not_port.notify_state = NCM_NOTIFY_RESPONSE_AVAILABLE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_RESPONSE_AVAILABLE;
spin_unlock(&mbim->lock);
} else {
goto fail;
@@ -1387,7 +1389,7 @@
pr_info("SET DEVICE OFFLINE");
atomic_set(&mbim->online, 0);
- mbim->not_port.notify_state = NCM_NOTIFY_NONE;
+ mbim->not_port.notify_state = MBIM_NOTIFY_NONE;
mbim_clear_queues(mbim);
mbim_reset_function_queue(mbim);
@@ -1655,12 +1657,13 @@
mbim->xport = USB_GADGET_XPORT_BAM2BAM;
} else {
/* For IPA we use limit of 16 */
- ntb_parameters.wNtbOutMaxDatagrams = 16;
+ mbim_ntb_parameters.wNtbOutMaxDatagrams = 16;
/* For IPA this is proven to give maximum throughput */
- ntb_parameters.dwNtbInMaxSize =
+ mbim_ntb_parameters.dwNtbInMaxSize =
cpu_to_le32(NTB_DEFAULT_IN_SIZE_IPA);
- ntb_parameters.dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE_IPA);
- ntb_parameters.wNdpInDivisor = 1;
+ mbim_ntb_parameters.dwNtbOutMaxSize =
+ cpu_to_le32(MBIM_NTB_OUT_SIZE_IPA);
+ mbim_ntb_parameters.wNdpInDivisor = 1;
}
INIT_LIST_HEAD(&mbim->cpkt_req_q);
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 0c0d58a..37189d8 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -50,7 +50,7 @@
#define STATE_ERROR 4 /* error from completion routine */
/* number of tx and rx requests to allocate */
-#define TX_REQ_MAX 4
+#define MTP_TX_REQ_MAX 8
#define RX_REQ_MAX 2
#define INTR_REQ_MAX 5
@@ -70,6 +70,12 @@
unsigned int mtp_rx_req_len = MTP_BULK_BUFFER_SIZE;
module_param(mtp_rx_req_len, uint, S_IRUGO | S_IWUSR);
+unsigned int mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+module_param(mtp_tx_req_len, uint, S_IRUGO | S_IWUSR);
+
+unsigned int mtp_tx_reqs = MTP_TX_REQ_MAX;
+module_param(mtp_tx_reqs, uint, S_IRUGO | S_IWUSR);
+
static const char mtp_shortname[] = "mtp_usb";
struct mtp_dev {
@@ -488,11 +494,22 @@
ep->driver_data = dev; /* claim the endpoint */
dev->ep_intr = ep;
+retry_tx_alloc:
+ if (mtp_tx_req_len > MTP_BULK_BUFFER_SIZE)
+ mtp_tx_reqs = 4;
+
/* now allocate requests for our endpoints */
- for (i = 0; i < TX_REQ_MAX; i++) {
- req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE);
- if (!req)
- goto fail;
+ for (i = 0; i < mtp_tx_reqs; i++) {
+ req = mtp_request_new(dev->ep_in, mtp_tx_req_len);
+ if (!req) {
+ if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE)
+ goto fail;
+ while ((req = mtp_req_get(dev, &dev->tx_idle)))
+ mtp_request_free(req, dev->ep_in);
+ mtp_tx_req_len = MTP_BULK_BUFFER_SIZE;
+ mtp_tx_reqs = MTP_TX_REQ_MAX;
+ goto retry_tx_alloc;
+ }
req->complete = mtp_complete_in;
mtp_req_put(dev, &dev->tx_idle, req);
}
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index aab8ede..cdf86fd 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -24,6 +24,21 @@
#include "u_ether.h"
+#undef DBG
+#undef VDBG
+#undef ERROR
+#undef INFO
+
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARNING(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*
* This function is a "CDC Network Control Model" (CDC NCM) Ethernet link.
* NCM is intended to be used with high-speed network attachments.
@@ -124,7 +139,7 @@
#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = {
+static struct usb_interface_assoc_descriptor ncm_iad_desc = {
.bLength = sizeof ncm_iad_desc,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
@@ -138,7 +153,7 @@
/* interface descriptor: */
-static struct usb_interface_descriptor ncm_control_intf __initdata = {
+static struct usb_interface_descriptor ncm_control_intf = {
.bLength = sizeof ncm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -150,7 +165,7 @@
/* .iInterface = DYNAMIC */
};
-static struct usb_cdc_header_desc ncm_header_desc __initdata = {
+static struct usb_cdc_header_desc ncm_header_desc = {
.bLength = sizeof ncm_header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
@@ -158,7 +173,7 @@
.bcdCDC = cpu_to_le16(0x0110),
};
-static struct usb_cdc_union_desc ncm_union_desc __initdata = {
+static struct usb_cdc_union_desc ncm_union_desc = {
.bLength = sizeof(ncm_union_desc),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_UNION_TYPE,
@@ -166,8 +181,8 @@
/* .bSlaveInterface0 = DYNAMIC */
};
-static struct usb_cdc_ether_desc ecm_desc __initdata = {
- .bLength = sizeof ecm_desc,
+static struct usb_cdc_ether_desc necm_desc = {
+ .bLength = sizeof necm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
@@ -181,7 +196,7 @@
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
-static struct usb_cdc_ncm_desc ncm_desc __initdata = {
+static struct usb_cdc_ncm_desc ncm_desc = {
.bLength = sizeof ncm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_NCM_TYPE,
@@ -193,7 +208,7 @@
/* the default data interface has no endpoints ... */
-static struct usb_interface_descriptor ncm_data_nop_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_nop_intf = {
.bLength = sizeof ncm_data_nop_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -208,7 +223,7 @@
/* ... but the "real" data interface has two bulk endpoints */
-static struct usb_interface_descriptor ncm_data_intf __initdata = {
+static struct usb_interface_descriptor ncm_data_intf = {
.bLength = sizeof ncm_data_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -223,7 +238,7 @@
/* full speed support: */
-static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -233,7 +248,7 @@
.bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC,
};
-static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -241,7 +256,7 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -249,13 +264,13 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *ncm_fs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_fs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &fs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -268,7 +283,7 @@
/* high speed support: */
-static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -277,7 +292,7 @@
.wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT),
.bInterval = LOG2_STATUS_INTERVAL_MSEC + 4,
};
-static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -286,7 +301,7 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_ncm_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -295,13 +310,13 @@
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *ncm_hs_function[] __initdata = {
+static struct usb_descriptor_header *ncm_hs_function[] = {
(struct usb_descriptor_header *) &ncm_iad_desc,
/* CDC NCM control descriptors */
(struct usb_descriptor_header *) &ncm_control_intf,
(struct usb_descriptor_header *) &ncm_header_desc,
(struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
+ (struct usb_descriptor_header *) &necm_desc,
(struct usb_descriptor_header *) &ncm_desc,
(struct usb_descriptor_header *) &hs_ncm_notify_desc,
/* data interface, altsettings 0 and 1 */
@@ -316,13 +331,13 @@
#define STRING_CTRL_IDX 0
#define STRING_MAC_IDX 1
-#define STRING_DATA_IDX 2
+#define NCM_STRING_DATA_IDX 2
#define STRING_IAD_IDX 3
static struct usb_string ncm_string_defs[] = {
[STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)",
[STRING_MAC_IDX].s = NULL /* DYNAMIC */,
- [STRING_DATA_IDX].s = "CDC Network Data",
+ [NCM_STRING_DATA_IDX].s = "CDC Network Data",
[STRING_IAD_IDX].s = "CDC NCM",
{ } /* end of list */
};
@@ -1148,7 +1163,7 @@
/* ethernet function driver setup/binding */
-static int __init
+static int
ncm_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@@ -1299,7 +1314,7 @@
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
struct f_ncm *ncm;
int status;
@@ -1321,7 +1336,7 @@
status = usb_string_id(c->cdev);
if (status < 0)
return status;
- ncm_string_defs[STRING_DATA_IDX].id = status;
+ ncm_string_defs[NCM_STRING_DATA_IDX].id = status;
ncm_data_nop_intf.iInterface = status;
ncm_data_intf.iInterface = status;
@@ -1330,7 +1345,7 @@
if (status < 0)
return status;
ncm_string_defs[STRING_MAC_IDX].id = status;
- ecm_desc.iMACAddress = status;
+ necm_desc.iMACAddress = status;
/* IAD */
status = usb_string_id(c->cdev);
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index 4f9cbf1..a6b443f 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -75,6 +75,7 @@
struct usb_request *notify_req;
u8 notify_state;
bool is_open;
+ struct data_port bam_port;
};
static struct ecm_ipa_params ipa_params;
@@ -111,8 +112,9 @@
#define ECM_QC_LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */
#define ECM_QC_STATUS_BYTECOUNT 16 /* 8 byte header + data */
-/* currently only one std ecm instance is supported */
+/* Currently only one std ecm instance is supported - port index 0. */
#define ECM_QC_NO_PORTS 1
+#define ECM_QC_ACTIVE_PORT 0
/* interface descriptor: */
@@ -296,8 +298,6 @@
NULL,
};
-static struct data_port ecm_qc_bam_port;
-
static void ecm_qc_do_notify(struct f_ecm_qc *ecm)
{
struct usb_request *req = ecm->notify_req;
@@ -388,10 +388,10 @@
enum peer_bam peer_bam = (dev->xport == USB_GADGET_XPORT_BAM2BAM_IPA) ?
IPA_P_BAM : A2_P_BAM;
- ecm_qc_bam_port.cdev = cdev;
- ecm_qc_bam_port.func = &dev->port.func;
- ecm_qc_bam_port.in = dev->port.in_ep;
- ecm_qc_bam_port.out = dev->port.out_ep;
+ dev->bam_port.cdev = cdev;
+ dev->bam_port.func = &dev->port.func;
+ dev->bam_port.in = dev->port.in_ep;
+ dev->bam_port.out = dev->port.out_ep;
/* currently we use the first connection */
src_connection_idx = usb_bam_get_connection_idx(gadget->name, peer_bam,
@@ -402,7 +402,7 @@
pr_err("%s: usb_bam_get_connection_idx failed\n", __func__);
return ret;
}
- ret = bam_data_connect(&ecm_qc_bam_port, 0, dev->xport,
+ ret = bam_data_connect(&dev->bam_port, 0, dev->xport,
src_connection_idx, dst_connection_idx, USB_FUNC_ECM);
if (ret) {
pr_err("bam_data_connect failed: err:%d\n", ret);
@@ -421,7 +421,7 @@
{
pr_debug("dev:%p. Disconnect BAM.\n", dev);
- bam_data_disconnect(&ecm_qc_bam_port, 0);
+ bam_data_disconnect(&dev->bam_port, 0);
return 0;
}
@@ -656,6 +656,20 @@
}
}
+static void ecm_qc_suspend(struct usb_function *f)
+{
+ pr_debug("ecm suspended\n");
+
+ bam_data_suspend(ECM_QC_ACTIVE_PORT);
+}
+
+static void ecm_qc_resume(struct usb_function *f)
+{
+ pr_debug("ecm resumed\n");
+
+ bam_data_resume(ECM_QC_ACTIVE_PORT);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -939,6 +953,8 @@
ecm->port.func.get_alt = ecm_qc_get_alt;
ecm->port.func.setup = ecm_qc_setup;
ecm->port.func.disable = ecm_qc_disable;
+ ecm->port.func.suspend = ecm_qc_suspend;
+ ecm->port.func.resume = ecm_qc_resume;
status = usb_add_function(c, &ecm->port.func);
if (status) {
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 32d4011..7903764 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -66,10 +66,10 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
-static bool rndis_multipacket_dl_disable;
-module_param(rndis_multipacket_dl_disable, bool, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(rndis_multipacket_dl_disable,
- "Disable RNDIS Multi-packet support in DownLink");
+static unsigned int rndis_dl_max_pkt_per_xfer = 3;
+module_param(rndis_dl_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(rndis_dl_max_pkt_per_xfer,
+ "Maximum packets per transfer for DL aggregation");
static unsigned int rndis_ul_max_pkt_per_xfer = 3;
module_param(rndis_ul_max_pkt_per_xfer, uint, S_IRUGO | S_IWUSR);
@@ -488,7 +488,7 @@
__func__, buf->MaxTransferSize,
rndis->port.multi_pkt_xfer ? "enabled" :
"disabled");
- if (rndis_multipacket_dl_disable)
+ if (rndis_dl_max_pkt_per_xfer <= 1)
rndis->port.multi_pkt_xfer = 0;
}
// spin_unlock(&dev->lock);
@@ -952,6 +952,7 @@
rndis->port.wrap = rndis_add_header;
rndis->port.unwrap = rndis_rm_hdr;
rndis->port.ul_max_pkts_per_xfer = rndis_ul_max_pkt_per_xfer;
+ rndis->port.dl_max_pkts_per_xfer = rndis_dl_max_pkt_per_xfer;
rndis->port.func.name = "rndis";
rndis->port.func.strings = rndis_strings;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index dbffa4e..9961d00 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -71,6 +71,7 @@
unsigned header_len;
unsigned int ul_max_pkts_per_xfer;
+ unsigned int dl_max_pkts_per_xfer;
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
@@ -585,12 +586,12 @@
return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS;
}
-static void alloc_tx_buffer(struct eth_dev *dev)
+static int alloc_tx_buffer(struct eth_dev *dev)
{
struct list_head *act;
struct usb_request *req;
- dev->tx_req_bufsize = (TX_SKB_HOLD_THRESHOLD *
+ dev->tx_req_bufsize = (dev->dl_max_pkts_per_xfer *
(dev->net->mtu
+ sizeof(struct ethhdr)
/* size of rndis_packet_msg_type */
@@ -602,7 +603,19 @@
if (!req->buf)
req->buf = kmalloc(dev->tx_req_bufsize,
GFP_ATOMIC);
+ if (!req->buf)
+ goto free_buf;
}
+ return 0;
+
+free_buf:
+ /* tx_req_bufsize = 0 retries mem alloc on next eth_start_xmit */
+ dev->tx_req_bufsize = 0;
+ list_for_each(act, &dev->tx_reqs) {
+ req = container_of(act, struct usb_request, list);
+ kfree(req->buf);
+ }
+ return -ENOMEM;
}
static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
@@ -634,8 +647,11 @@
}
/* Allocate memory for tx_reqs to support multi packet transfer */
- if (multi_pkt_xfer && !dev->tx_req_bufsize)
- alloc_tx_buffer(dev);
+ if (multi_pkt_xfer && !dev->tx_req_bufsize) {
+ retval = alloc_tx_buffer(dev);
+ if (retval < 0)
+ return -ENOMEM;
+ }
/* apply outgoing CDC or RNDIS filters */
if (!is_promisc(cdc_filter)) {
@@ -704,7 +720,7 @@
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
- if (dev->tx_skb_hold_count < TX_SKB_HOLD_THRESHOLD) {
+ if (dev->tx_skb_hold_count < dev->dl_max_pkts_per_xfer) {
if (dev->no_tx_req_used > TX_REQ_THRESHOLD) {
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -1082,6 +1098,7 @@
dev->unwrap = link->unwrap;
dev->wrap = link->wrap;
dev->ul_max_pkts_per_xfer = link->ul_max_pkts_per_xfer;
+ dev->dl_max_pkts_per_xfer = link->dl_max_pkts_per_xfer;
spin_lock(&dev->lock);
dev->tx_skb_hold_count = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 7040ab0..05984d8 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -55,8 +55,7 @@
u32 fixed_in_len;
unsigned ul_max_pkts_per_xfer;
-/* Max number of SKB packets to be used to create Multi Packet RNDIS */
-#define TX_SKB_HOLD_THRESHOLD 3
+ unsigned dl_max_pkts_per_xfer;
bool multi_pkt_xfer;
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index caea4ef..5a34679 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -604,6 +604,11 @@
pr_debug("%s: requested ports:%d\n", __func__, count);
+ if (client_num >= NR_CTRL_CLIENTS) {
+ pr_err("%s: Invalid client:%d\n", __func__, client_num);
+ return -EINVAL;
+ }
+
if (!count || count > MAX_CTRL_PER_CLIENT) {
pr_err("%s: Invalid num of ports count:%d\n",
__func__, count);
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index a0cdde2..52b707e 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -232,7 +232,7 @@
{
unsigned avail;
char *packet;
- unsigned size = req->actual;
+ unsigned size;
unsigned n;
int ret = 0;
@@ -271,6 +271,7 @@
return -ENODEV;
}
+ size = req->actual;
packet = req->buf;
n = port->n_read;
if (n) {
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 0ea9778..c5304e1 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -1062,6 +1062,7 @@
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
int retval;
mehci->timer = USB_HS_GPTIMER_BASE;
@@ -1092,8 +1093,14 @@
/* bursts of unspecified length. */
writel_relaxed(0, USB_AHBBURST);
- /* Use the AHB transactor */
- writel_relaxed(0x08, USB_AHBMODE);
+
+ /* Use the AHB transactor and configure async bridge bypass */
+#define MSM_USB_ASYNC_BRIDGE_BYPASS BIT(31)
+ if (pdata->ahb_async_bridge_bypass)
+ writel_relaxed(0x08 | MSM_USB_ASYNC_BRIDGE_BYPASS, USB_AHBMODE);
+ else
+ writel_relaxed(0x08, USB_AHBMODE);
+
/* Disable streaming mode and select host mode */
writel_relaxed(0x13, USB_USBMODE);
@@ -1882,6 +1889,8 @@
"qcom,disable-park-mode"));
pdata->consider_ipa_handshake = (of_property_read_bool(node,
"hsic,consider-ipa-handshake"));
+ pdata->ahb_async_bridge_bypass = of_property_read_bool(node,
+ "qcom,ahb-async-bridge-bypass");
return pdata;
}
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index e46ea3b..bb5d3ca 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -104,8 +104,14 @@
kfree(panel_private->on_cmds);
kfree(panel_private->off_cmds);
+
kfree(panel_private);
panel_private = NULL;
+
+ if (bl_led_trigger) {
+ led_trigger_unregister_simple(bl_led_trigger);
+ bl_led_trigger = NULL;
+ }
}
int dsi_panel_power(int enable)
{
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 5223e66..65c9e90 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -290,12 +290,16 @@
static void mdp3_bus_scale_unregister(void)
{
int i;
+
+ if (!mdp3_res->bus_handle)
+ return;
+
for (i = 0; i < MDP3_BUS_HANDLE_MAX; i++) {
pr_debug("unregister index=%d bus_handle=%x\n",
i, mdp3_res->bus_handle[i].handle);
if (mdp3_res->bus_handle[i].handle) {
msm_bus_scale_unregister_client(
- mdp3_res->bus_handle[i].handle);
+ mdp3_res->bus_handle[i].handle);
mdp3_res->bus_handle[i].handle = 0;
}
}
@@ -484,11 +488,20 @@
static void mdp3_clk_remove(void)
{
- clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
- clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
- clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
- clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
- clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_AHB]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_AHB]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_CORE]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_CORE]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_VSYNC]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_VSYNC]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_LCDC]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_LCDC]);
+
+ if (!IS_ERR_OR_NULL(mdp3_res->clocks[MDP3_CLK_DSI]))
+ clk_put(mdp3_res->clocks[MDP3_CLK_DSI]);
}
int mdp3_clk_enable(int enable)
@@ -519,6 +532,7 @@
return ret;
}
disable_irq(mdp3_res->irq);
+ mdp3_res->irq_registered = true;
return 0;
}
@@ -556,7 +570,8 @@
struct mdp3_iommu_ctx_map *context_map;
struct mdp3_iommu_domain_map *domain_map;
- if (context >= MDP3_IOMMU_CTX_MAX)
+ if (!mdp3_res->iommu_contexts ||
+ context >= MDP3_IOMMU_CTX_MAX)
return -EINVAL;
context_map = mdp3_res->iommu_contexts + context;
@@ -595,10 +610,13 @@
mdp3_iommu_domains[i].domain_idx = domain_idx;
mdp3_iommu_domains[i].domain = msm_get_iommu_domain(domain_idx);
- if (!mdp3_iommu_domains[i].domain) {
+ if (IS_ERR_OR_NULL(mdp3_iommu_domains[i].domain)) {
pr_err("unable to get iommu domain(%d)\n",
domain_idx);
- return -EINVAL;
+ if (!mdp3_iommu_domains[i].domain)
+ return -EINVAL;
+ else
+ return PTR_ERR(mdp3_iommu_domains[i].domain);
}
iommu_set_fault_handler(mdp3_iommu_domains[i].domain,
mdp3_iommu_fault_handler,
@@ -623,10 +641,13 @@
mdp3_iommu_contexts[i].ctx =
msm_iommu_get_ctx(mdp3_iommu_contexts[i].ctx_name);
- if (!mdp3_iommu_contexts[i].ctx) {
+ if (IS_ERR_OR_NULL(mdp3_iommu_contexts[i].ctx)) {
pr_warn("unable to get iommu ctx(%s)\n",
mdp3_iommu_contexts[i].ctx_name);
- return -EINVAL;
+ if (!mdp3_iommu_contexts[i].ctx)
+ return -EINVAL;
+ else
+ return PTR_ERR(mdp3_iommu_contexts[i].ctx);
}
}
@@ -653,6 +674,19 @@
return ret;
}
+void mdp3_iommu_deinit(void)
+{
+ int i;
+
+ if (!mdp3_res->domains)
+ return;
+
+ for (i = 0; i < MDP3_IOMMU_DOMAIN_MAX; i++) {
+ if (!IS_ERR_OR_NULL(mdp3_res->domains[i].domain))
+ msm_unregister_domain(mdp3_res->domains[i].domain);
+ }
+}
+
static int mdp3_check_version(void)
{
int rc;
@@ -742,6 +776,21 @@
return rc;
}
+static void mdp3_res_deinit(void)
+{
+ mdp3_bus_scale_unregister();
+ mdp3_iommu_dettach(MDP3_IOMMU_CTX_DMA_0);
+ mdp3_iommu_deinit();
+
+ if (!IS_ERR_OR_NULL(mdp3_res->ion_client))
+ ion_client_destroy(mdp3_res->ion_client);
+
+ mdp3_clk_remove();
+
+ if (mdp3_res->irq_registered)
+ devm_free_irq(&mdp3_res->pdev->dev, mdp3_res->irq, mdp3_res);
+}
+
static int mdp3_parse_dt(struct platform_device *pdev)
{
struct resource *res;
@@ -847,7 +896,10 @@
data->srcp_ihdl = ion_import_dma_buf(iclient, img->memory_id);
if (IS_ERR_OR_NULL(data->srcp_ihdl)) {
pr_err("error on ion_import_fd\n");
- ret = PTR_ERR(data->srcp_ihdl);
+ if (!data->srcp_ihdl)
+ ret = -EINVAL;
+ else
+ ret = PTR_ERR(data->srcp_ihdl);
data->srcp_ihdl = NULL;
return ret;
}
@@ -1002,6 +1054,11 @@
probe_done:
if (IS_ERR_VALUE(rc)) {
+ mdp3_res_deinit();
+
+ if (mdp3_res->mdp_base)
+ devm_iounmap(&pdev->dev, mdp3_res->mdp_base);
+
devm_kfree(&pdev->dev, mdp3_res);
mdp3_res = NULL;
}
diff --git a/drivers/video/msm/mdss/mdp3.h b/drivers/video/msm/mdss/mdp3.h
index 878fe25..e52f7bc 100644
--- a/drivers/video/msm/mdss/mdp3.h
+++ b/drivers/video/msm/mdss/mdp3.h
@@ -119,6 +119,8 @@
u32 irq_mask;
struct mdp3_intr_cb callbacks[MDP3_MAX_INTR];
+ int irq_registered;
+
struct early_suspend suspend_handler;
};
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index b5134a7..037ab51 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -192,13 +192,9 @@
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
- rc = wait_for_completion_interruptible_timeout(
- &mdp3_session->vsync_comp,
- msecs_to_jiffies(VSYNC_PERIOD * 5));
- if (rc <= 0) {
- pr_warn("vsync wait on fb%d interrupted (%d)\n",
- mfd->index, rc);
- }
+ rc = wait_for_completion_interruptible(&mdp3_session->vsync_comp);
+ if (rc < 0)
+ return rc;
spin_lock_irqsave(&mdp3_session->vsync_lock, flag);
vsync_ticks = ktime_to_ns(mdp3_session->vsync_time);
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 0918db1..13fba26 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/debugfs.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/printk.h>
@@ -438,3 +439,151 @@
return 0;
}
+
+static struct mdss_mdp_misr_map {
+ u32 ctrl_reg;
+ u32 value_reg;
+ u32 crc_op_mode;
+ u32 crc_index;
+ u32 crc_value[MISR_CRC_BATCH_SIZE];
+} mdss_mdp_misr_table[DISPLAY_MISR_MAX] = {
+ [DISPLAY_MISR_DSI0] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI0,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI0,
+ },
+ [DISPLAY_MISR_DSI1] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_DSI1,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_DSI1,
+ },
+ [DISPLAY_MISR_EDP] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_EDP,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_EDP,
+ },
+ [DISPLAY_MISR_HDMI] = {
+ .ctrl_reg = MDSS_MDP_LP_MISR_CTRL_HDMI,
+ .value_reg = MDSS_MDP_LP_MISR_SIGN_HDMI,
+ },
+};
+
+static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id)
+{
+ struct mdss_mdp_misr_map *map;
+
+ if (block_id > DISPLAY_MISR_LCDC) {
+ pr_err("MISR Block id (%d) out of range\n", block_id);
+ return NULL;
+ }
+
+ map = mdss_mdp_misr_table + block_id;
+ if ((map->ctrl_reg == 0) || (map->value_reg == 0)) {
+ pr_err("MISR Block id (%d) config not found\n", block_id);
+ return NULL;
+ }
+
+ return map;
+}
+
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 config = 0;
+
+ map = mdss_misr_get_map(req->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", req->block_id);
+ return -EINVAL;
+ }
+
+ map->crc_op_mode = req->crc_op_mode;
+ memset(map->crc_value, 0, sizeof(map->crc_value));
+
+ pr_debug("MISR Config (BlockId %d) (Frame Count = %d)\n",
+ req->block_id, req->frame_count);
+
+ config = (MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK & req->frame_count) |
+ (MDSS_MDP_LP_MISR_CTRL_ENABLE);
+
+ writel_relaxed(MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR,
+ mdata->mdp_base + map->ctrl_reg);
+ /* ensure clear is done */
+ wmb();
+ if (MISR_OP_BM == map->crc_op_mode) {
+ writel_relaxed(MISR_CRC_BATCH_CFG,
+ mdata->mdp_base + map->ctrl_reg);
+ } else {
+ writel_relaxed(config,
+ mdata->mdp_base + map->ctrl_reg);
+
+ config = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ pr_debug("MISR_CTRL = 0x%x", config);
+ }
+ return 0;
+}
+
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status;
+ int ret = 0;
+ int i;
+
+ map = mdss_misr_get_map(resp->block_id);
+ if (!map) {
+ pr_err("Invalid MISR Block=%d\n", resp->block_id);
+ return -EINVAL;
+ }
+
+ switch (map->crc_op_mode) {
+ case MISR_OP_SFM:
+ case MISR_OP_MFM:
+ ret = readl_poll_timeout(mdata->mdp_base + map->ctrl_reg,
+ status, status & MDSS_MDP_LP_MISR_CTRL_STATUS,
+ MISR_POLL_SLEEP, MISR_POLL_TIMEOUT);
+
+ pr_debug("Status of Get MISR_CTRL = 0x%x", status);
+ if (ret == 0) {
+ resp->crc_value[0] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ pr_debug("CRC %d=0x%x\n", resp->block_id,
+ resp->crc_value[0]);
+ } else {
+ pr_warn("MISR %d busy with status 0x%x\n",
+ resp->block_id, status);
+ }
+ break;
+ case MISR_OP_BM:
+ for (i = 0; i < MISR_CRC_BATCH_SIZE; i++)
+ resp->crc_value[i] = map->crc_value[i];
+ map->crc_index = 0;
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+/* This function is expected to be called from interrupt context */
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id)
+{
+ struct mdss_mdp_misr_map *map;
+ u32 status, config;
+
+ map = mdss_misr_get_map(block_id);
+ if (!map || (map->crc_op_mode != MISR_OP_BM))
+ return;
+
+ config = MISR_CRC_BATCH_CFG;
+
+ status = readl_relaxed(mdata->mdp_base + map->ctrl_reg);
+ if (status & MDSS_MDP_LP_MISR_CTRL_STATUS) {
+ map->crc_value[map->crc_index] =
+ readl_relaxed(mdata->mdp_base + map->value_reg);
+ map->crc_index++;
+ if (map->crc_index == MISR_CRC_BATCH_SIZE)
+ map->crc_index = 0;
+ config |= MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR;
+ }
+ writel_relaxed(config, mdata->mdp_base + map->ctrl_reg);
+}
diff --git a/drivers/video/msm/mdss/mdss_debug.h b/drivers/video/msm/mdss/mdss_debug.h
index 167fa8a..29eb16c 100644
--- a/drivers/video/msm/mdss/mdss_debug.h
+++ b/drivers/video/msm/mdss/mdss_debug.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -16,24 +16,30 @@
#include "mdss.h"
+#define MISR_POLL_SLEEP 2000
+#define MISR_POLL_TIMEOUT 32000
+#define MISR_CRC_BATCH_SIZE 32
+#define MISR_CRC_BATCH_CFG 0x101
+
#ifdef CONFIG_DEBUG_FS
int mdss_debugfs_init(struct mdss_data_type *mdata);
int mdss_debugfs_remove(struct mdss_data_type *mdata);
int mdss_debug_register_base(const char *name, void __iomem *base,
size_t max_offset);
+int mdss_misr_crc_set(struct mdss_data_type *mdata, struct mdp_misr *req);
+int mdss_misr_crc_get(struct mdss_data_type *mdata, struct mdp_misr *resp);
+void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id);
#else
-static inline int mdss_debugfs_init(struct mdss_data_type *mdata)
-{
- return 0;
-}
+static inline int mdss_debugfs_init(struct mdss_data_type *mdata) { return 0; }
static inline int mdss_debugfs_remove(struct mdss_data_type *mdata)
-{
- return 0;
-}
+{ return 0; }
static inline int mdss_debug_register_base(const char *name, void __iomem *base,
- size_t max_offset)
-{
- return 0;
-}
+ size_t max_offset) { return 0; }
+static inline int mdss_misr_crc_set(struct mdss_data_type *mdata,
+ struct mdp_misr *reg) { return 0; }
+static inline int mdss_misr_crc_get(struct mdss_data_type *mdata,
+ struct mdp_misr *resp) { return 0; }
+static inline void mdss_misr_crc_collect(struct mdss_data_type *mdata,
+ int block_id) { }
#endif
#endif /* MDSS_DEBUG_H */
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index db3cecc..afabc20 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -432,42 +432,6 @@
return ret;
}
-int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
-{
- int ret = 0;
- struct mipi_panel_info *mipi;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
-
- pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
-
- if (pdata == NULL) {
- pr_err("%s: Invalid input data\n", __func__);
- return -EINVAL;
- }
-
- mipi = &pdata->panel_info.mipi;
-
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
-
- pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
- ctrl_pdata, ctrl_pdata->ndx);
-
- WARN(ctrl_pdata->panel_state != UNKNOWN_STATE,
- "incorrect panel state=%d\n", ctrl_pdata->panel_state);
-
- mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(mipi, pdata);
-
- mdss_dsi_op_mode_config(mipi->mode, pdata);
-
- ctrl_pdata->panel_state = PANEL_ON;
-
- pr_debug("%s-:End\n", __func__);
- return ret;
-}
-
-
int mdss_dsi_on(struct mdss_panel_data *pdata)
{
int ret = 0;
@@ -618,14 +582,14 @@
panel_data);
mipi = &pdata->panel_info.mipi;
- if (ctrl_pdata->panel_state != PANEL_ON) {
+ if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
ret = ctrl_pdata->on(pdata);
if (ret) {
pr_err("%s: unable to initialize the panel\n",
__func__);
return ret;
}
- ctrl_pdata->panel_state = PANEL_ON;
+ ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
mdss_dsi_op_mode_config(mipi->mode, pdata);
@@ -651,18 +615,58 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
- if (ctrl_pdata->panel_state == PANEL_ON) {
+ if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
ret = ctrl_pdata->off(pdata);
if (ret) {
pr_err("%s: Panel OFF failed\n", __func__);
return ret;
}
- ctrl_pdata->panel_state = PANEL_OFF;
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
}
pr_debug("%s-:End\n", __func__);
return ret;
}
+int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
+{
+ int ret = 0;
+ struct mipi_panel_info *mipi;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+
+ pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__);
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return -EINVAL;
+ }
+
+ mipi = &pdata->panel_info.mipi;
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ pr_debug("%s+: ctrl=%p ndx=%d\n", __func__,
+ ctrl_pdata, ctrl_pdata->ndx);
+
+ WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT),
+ "Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
+
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(mipi, pdata);
+
+ if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
+ mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ ret = mdss_dsi_unblank(pdata);
+ if (ret) {
+ pr_err("%s: unblank failed\n", __func__);
+ return ret;
+ }
+ }
+
+ pr_debug("%s-:End\n", __func__);
+ return ret;
+}
+
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@@ -684,6 +688,7 @@
rc = mdss_dsi_unblank(pdata);
break;
case MDSS_EVENT_PANEL_ON:
+ ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE)
rc = mdss_dsi_unblank(pdata);
break;
@@ -692,11 +697,13 @@
rc = mdss_dsi_blank(pdata);
break;
case MDSS_EVENT_PANEL_OFF:
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata);
rc = mdss_dsi_off(pdata);
break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE;
if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) {
rc = mdss_dsi_cont_splash_on(pdata);
} else {
@@ -712,6 +719,12 @@
case MDSS_EVENT_DSI_CMDLIST_KOFF:
mdss_dsi_cmdlist_commit(ctrl_pdata, 1);
break;
+ case MDSS_EVENT_CONT_SPLASH_BEGIN:
+ if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) {
+ /* Panel is Enabled in Bootloader */
+ rc = mdss_dsi_blank(pdata);
+ }
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -1110,6 +1123,7 @@
pr_debug("%s: pclk=%d, bclk=%d\n", __func__,
ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate);
+ ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN;
cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
"qcom,cont-splash-enabled");
if (!cont_splash_enabled) {
@@ -1139,6 +1153,8 @@
}
mdss_dsi_clk_ctrl(ctrl_pdata, 1);
+ ctrl_pdata->ctrl_state |=
+ (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE);
}
rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data));
@@ -1164,7 +1180,6 @@
ctrl_pdata->ndx = 1;
}
- ctrl_pdata->panel_state = UNKNOWN_STATE;
pr_debug("%s: Panal data initialized\n", __func__);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index c78c5cf..f612751 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -84,16 +84,14 @@
UNKNOWN_CTRL,
};
-enum dsi_ctrl_state {
+enum dsi_ctrl_op_mode {
DSI_LP_MODE,
DSI_HS_MODE,
};
-enum dsi_panel_state {
- UNKNOWN_STATE,
- PANEL_ON,
- PANEL_OFF,
-};
+#define CTRL_STATE_UNKNOWN 0x00
+#define CTRL_STATE_PANEL_INIT BIT(0)
+#define CTRL_STATE_MDP_ACTIVE BIT(1)
#define DSI_NON_BURST_SYNCH_PULSE 0
#define DSI_NON_BURST_SYNCH_EVENT 1
@@ -332,7 +330,7 @@
struct clk *byte_clk;
struct clk *esc_clk;
struct clk *pixel_clk;
- u8 panel_state;
+ u8 ctrl_state;
int irq_cnt;
int mdss_dsi_clk_on;
int rst_gpio;
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 6b0f68e..05a84e3 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -189,6 +189,12 @@
msleep(20);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
+ pr_debug("%s: Panel Not properly turned OFF\n",
+ __func__);
+ ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
+ pr_debug("%s: Reset panel done\n", __func__);
+ }
} else {
gpio_set_value((ctrl_pdata->rst_gpio), 0);
if (gpio_is_valid(ctrl_pdata->disp_en_gpio))
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e2d8cf6..5445137 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -1725,7 +1725,7 @@
if (!mdp_instance) {
pr_err("mdss mdp resource not initialized yet\n");
- return -ENODEV;
+ return -EPROBE_DEFER;
}
node = of_parse_phandle(pdev->dev.of_node, "qcom,mdss-fb-map", 0);
diff --git a/drivers/video/msm/mdss/mdss_io_util.c b/drivers/video/msm/mdss/mdss_io_util.c
index ff52e4c..809db43 100644
--- a/drivers/video/msm/mdss/mdss_io_util.c
+++ b/drivers/video/msm/mdss/mdss_io_util.c
@@ -276,15 +276,17 @@
DEV_DBG("%pS->%s: %s disable\n",
__builtin_return_address(0), __func__,
in_gpio[i].gpio_name);
-
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
}
}
return rc;
disable_gpio:
for (i--; i >= 0; i--)
- gpio_free(in_gpio[i].gpio);
+ if (in_gpio[i].gpio)
+ gpio_free(in_gpio[i].gpio);
+
return rc;
} /* msm_dss_enable_gpio */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 772545f..d8ca555 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -977,6 +977,7 @@
goto probe_done;
}
mdata->irq = res->start;
+ mdss_mdp_hw.ptr = mdata;
/*populate hw iomem base info from device tree*/
rc = mdss_mdp_parse_dt(pdev);
@@ -1023,6 +1024,7 @@
probe_done:
if (IS_ERR_VALUE(rc)) {
+ mdss_mdp_hw.ptr = NULL;
mdss_res = NULL;
mdss_mdp_pp_term(&pdev->dev);
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index f3b5acec..311b15c 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -157,6 +157,7 @@
int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
int (*wait_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*wait_pingpong) (struct mdss_mdp_ctl *ctl, void *arg);
u32 (*read_line_cnt_fnc) (struct mdss_mdp_ctl *);
int (*add_vsync_handler) (struct mdss_mdp_ctl *,
struct mdss_mdp_vsync_handler *);
@@ -436,6 +437,7 @@
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl);
int mdss_mdp_display_wakeup_time(struct mdss_mdp_ctl *ctl,
ktime_t *wakeup_time);
@@ -536,6 +538,7 @@
int mdss_panel_register_done(struct mdss_panel_data *pdata);
int mdss_mdp_limited_lut_igc_config(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback);
#define mfd_to_mdp5_data(mfd) (mfd->mdp.private1)
#define mfd_to_mdata(mfd) (((struct mdss_overlay_private *)\
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 4b763aa..5d9050c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -1442,6 +1442,27 @@
return ret;
}
+int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl)
+{
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctl->lock);
+ if (ret)
+ return ret;
+
+ if (!ctl->power_on) {
+ mutex_unlock(&ctl->lock);
+ return 0;
+ }
+
+ if (ctl->wait_pingpong)
+ ret = ctl->wait_pingpong(ctl, NULL);
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_ctl *sctl = NULL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
index 6ec5b63..741c7a7 100644
--- a/drivers/video/msm/mdss/mdss_mdp_hwio.h
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -515,4 +515,33 @@
MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
};
-#endif /* MDSS_MDP_HWIO_H */
+#define MDSS_MDP_LP_MISR_SEL 0x450
+#define MDSS_MDP_LP_MISR_CTRL_MDP 0x454
+#define MDSS_MDP_LP_MISR_CTRL_HDMI 0x458
+#define MDSS_MDP_LP_MISR_CTRL_EDP 0x45C
+#define MDSS_MDP_LP_MISR_CTRL_DSI0 0x460
+#define MDSS_MDP_LP_MISR_CTRL_DSI1 0x464
+
+#define MDSS_MDP_LP_MISR_SIGN_MDP 0x468
+#define MDSS_MDP_LP_MISR_SIGN_EDP 0x46C
+#define MDSS_MDP_LP_MISR_SIGN_HDMI 0x470
+#define MDSS_MDP_LP_MISR_SIGN_DSI0 0x474
+#define MDSS_MDP_LP_MISR_SIGN_DSI1 0x478
+
+#define MDSS_MDP_LP_MISR_CTRL_FRAME_COUNT_MASK 0xFF
+#define MDSS_MDP_LP_MISR_CTRL_ENABLE BIT(8)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS BIT(9)
+#define MDSS_MDP_LP_MISR_CTRL_STATUS_CLEAR BIT(10)
+
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_BLEND 0x08
+#define MDSS_MDP_LP_MISR_SEL_LMIX0_GC 0x09
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_BLEND 0x0A
+#define MDSS_MDP_LP_MISR_SEL_LMIX1_GC 0x0B
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_BLEND 0x0C
+#define MDSS_MDP_LP_MISR_SEL_LMIX2_GC 0x0D
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_BLEND 0x0E
+#define MDSS_MDP_LP_MISR_SEL_LMIX3_GC 0x0F
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_BLEND 0x10
+#define MDSS_MDP_LP_MISR_SEL_LMIX4_GC 0x11
+
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
index afbbe55..238170d 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c
@@ -335,32 +335,12 @@
mutex_unlock(&ctx->clk_mtx);
}
-static int mdss_mdp_cmd_wait4comp(struct mdss_mdp_ctl *ctl, void *arg)
-{
- struct mdss_mdp_cmd_ctx *ctx;
- int rc;
-
- ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
- if (!ctx) {
- pr_err("invalid ctx\n");
- return -ENODEV;
- }
-
- pr_debug("%s: intf_num=%d ctx=%p\n", __func__, ctl->intf_num, ctx);
-
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
- KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n", rc, ctl->num);
-
- return 0;
-}
-
-int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg)
{
struct mdss_mdp_cmd_ctx *ctx;
unsigned long flags;
int need_wait = 0;
- int rc;
+ int rc = 0;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
if (!ctx) {
@@ -377,11 +357,29 @@
__func__, need_wait, ctl->intf_num, ctx);
if (need_wait) {
- rc = wait_for_completion_interruptible_timeout(
+ rc = wait_for_completion_timeout(
&ctx->pp_comp, KOFF_TIMEOUT);
- WARN(rc <= 0, "cmd kickoff timed out (%d) ctl=%d\n",
+ if (rc <= 0) {
+ WARN(1, "cmd kickoff timed out (%d) ctl=%d\n",
rc, ctl->num);
+ rc = -EPERM;
+ } else
+ rc = 0;
+ }
+
+ return rc;
+}
+
+int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_cmd_ctx *ctx;
+ int rc;
+
+ ctx = (struct mdss_mdp_cmd_ctx *) ctl->priv_data;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return -ENODEV;
}
if (ctx->panel_on == 0) {
@@ -456,6 +454,12 @@
ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_OFF, NULL);
WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret);
+ ctl->stop_fnc = NULL;
+ ctl->display_fnc = NULL;
+ ctl->wait_pingpong = NULL;
+ ctl->add_vsync_handler = NULL;
+ ctl->remove_vsync_handler = NULL;
+
pr_debug("%s:-\n", __func__);
return 0;
@@ -519,7 +523,7 @@
ctl->stop_fnc = mdss_mdp_cmd_stop;
ctl->display_fnc = mdss_mdp_cmd_kickoff;
- ctl->wait_fnc = mdss_mdp_cmd_wait4comp;
+ ctl->wait_pingpong = mdss_mdp_cmd_wait4pingpong;
ctl->add_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
ctl->remove_vsync_handler = mdss_mdp_cmd_vsync_ctrl;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 72cbed9..ab028e4 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -562,6 +562,13 @@
pdata->panel_info.cont_splash_enabled = 0;
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
+ NULL);
+ if (ret) {
+ pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n",
+ __func__);
+ return ret;
+ }
mdss_mdp_ctl_write(ctl, 0, MDSS_MDP_LM_BORDER_COLOR);
off = MDSS_MDP_REG_INTF_OFFSET(ctl->intf_num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index c96464a..7c7b92b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -27,6 +27,7 @@
#include <mach/event_timer.h>
#include "mdss.h"
+#include "mdss_debug.h"
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_rotator.h"
@@ -701,6 +702,14 @@
mutex_lock(&mdp5_data->ov_lock);
mutex_lock(&mfd->lock);
+
+ ret = mdss_mdp_display_wait4pingpong(mdp5_data->ctl);
+ if (ret) {
+ mutex_unlock(&mfd->lock);
+ mutex_unlock(&mdp5_data->ov_lock);
+ return ret;
+ }
+
list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) {
struct mdss_mdp_data *buf;
if (pipe->back_buf.num_planes) {
@@ -1286,20 +1295,14 @@
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
unsigned long flags;
u64 vsync_ticks;
- unsigned long timeout;
int ret;
if (!mdp5_data->ctl || !mdp5_data->ctl->power_on)
return 0;
- timeout = msecs_to_jiffies(VSYNC_PERIOD * 5);
- ret = wait_for_completion_interruptible_timeout(&mdp5_data->vsync_comp,
- timeout);
- if (ret <= 0) {
- pr_debug("Sending current time as vsync timestamp for fb%d\n",
- mfd->index);
- mdp5_data->vsync_time = ktime_get();
- }
+ ret = wait_for_completion_interruptible(&mdp5_data->vsync_comp);
+ if (ret < 0)
+ return ret;
spin_lock_irqsave(&mdp5_data->vsync_lock, flags);
vsync_ticks = ktime_to_ns(mdp5_data->vsync_time);
@@ -1554,6 +1557,10 @@
copyback = 1;
}
break;
+ case mdp_op_calib_cfg:
+ ret = mdss_mdp_calib_config((struct mdp_calib_config_data *)
+ &mdp_pp.data.calib_cfg, ©back);
+ break;
default:
pr_err("Unsupported request to MDP_PP IOCTL.\n");
ret = -EINVAL;
@@ -1614,6 +1621,7 @@
static int mdss_fb_set_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_vic:
@@ -1623,6 +1631,11 @@
else
ret = -EINVAL;
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_set(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("unsupported request to MDP META IOCTL\n");
ret = -EINVAL;
@@ -1649,6 +1662,7 @@
static int mdss_fb_get_metadata(struct msm_fb_data_type *mfd,
struct msmfb_metadata *metadata)
{
+ struct mdss_data_type *mdata = mfd_to_mdata(mfd);
int ret = 0;
switch (metadata->op) {
case metadata_op_frame_rate:
@@ -1658,6 +1672,11 @@
case metadata_op_get_caps:
ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
break;
+ case metadata_op_crc:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+ ret = mdss_misr_crc_get(mdata, &metadata->data.misr_request);
+ break;
default:
pr_warn("Unsupported request to MDP META IOCTL.\n");
ret = -EINVAL;
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 9d28265..235d4fc 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1652,6 +1652,9 @@
(config->block >= MDP_BLOCK_MAX))
return -EINVAL;
+ if (config->len != IGC_LUT_ENTRIES)
+ return -EINVAL;
+
mutex_lock(&mdss_pp_mutex);
disp_num = config->block - MDP_LOGICAL_BLOCK_DISP_0;
@@ -3181,3 +3184,88 @@
}
return rc;
}
+
+static int is_valid_calib_addr(void *addr)
+{
+ int ret = 0;
+ unsigned int ptr;
+ ptr = (unsigned int) addr;
+ /* if request is outside the MDP reg-map or is not aligned 4 */
+ if (ptr == 0x0 || ptr > 0x5138 || ptr % 0x4)
+ goto end;
+ if (ptr >= 0x100 && ptr <= 0x5138) {
+ /* if ptr is in dspp range */
+ if (ptr >= 0x4600 && ptr <= 0x5138) {
+ /* if ptr is in dspp0 range*/
+ if (ptr >= 0x4600 && ptr <= 0x4938)
+ ptr -= 0x4600;
+ /* if ptr is in dspp1 range */
+ else if (ptr >= 0x4a00 && ptr <= 0x4d38)
+ ptr -= 0x4a00;
+ /* if ptr is in dspp2 range */
+ else if (ptr >= 0x4e00 && ptr <= 0x5138)
+ ptr -= 0x4e00;
+ /* if ptr is in pcc plane rgb coeff.range */
+ if (ptr >= 0x30 && ptr <= 0xe8)
+ ret = 1;
+ /* if ptr is in ARLUT red range */
+ else if (ptr >= 0x2b0 && ptr <= 0x2b8)
+ ret = 1;
+ /* if ptr is in PA range */
+ else if (ptr >= 0x238 && ptr <= 0x244)
+ ret = 1;
+ /* if ptr is in ARLUT green range */
+ else if (ptr >= 0x2c0 && ptr <= 0x2c8)
+ ret = 1;
+ /* if ptr is in ARLUT blue range or
+ gamut map table range */
+ else if (ptr >= 0x2d0 && ptr <= 0x338)
+ ret = 1;
+ /* if ptr is dspp0,dspp1,dspp2 op mode
+ register */
+ else if (ptr == 0)
+ ret = 1;
+ } else if (ptr >= 0x600 && ptr <= 0x608)
+ ret = 1;
+ else if (ptr >= 0x400 && ptr <= 0x408)
+ ret = 1;
+ else if ((ptr == 0x1830) || (ptr == 0x1c30) ||
+ (ptr == 0x1430) || (ptr == 0x1e38))
+ ret = 1;
+ else if ((ptr == 0x1e3c) || (ptr == 0x1e30))
+ ret = 1;
+ else if (ptr >= 0x3220 && ptr <= 0x3228)
+ ret = 1;
+ else if (ptr >= 0x3200 || ptr == 0x100)
+ ret = 1;
+ }
+end:
+ return ret;
+}
+
+
+
+
+int mdss_mdp_calib_config(struct mdp_calib_config_data *cfg, u32 *copyback)
+{
+ int ret = -1;
+ void *ptr = (void *) cfg->addr;
+
+ if (is_valid_calib_addr(ptr))
+ ret = 0;
+ else
+ return ret;
+ ptr = (void *)(((unsigned int) ptr) + (mdss_res->mdp_base));
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ if (cfg->ops & MDP_PP_OPS_READ) {
+ cfg->data = readl_relaxed(ptr);
+ *copyback = 1;
+ ret = 0;
+ } else if (cfg->ops & MDP_PP_OPS_WRITE) {
+ writel_relaxed(cfg->data, ptr);
+ ret = 0;
+ }
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index d1f0c8d..e010ba5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -27,7 +27,7 @@
#include "mdss_fb.h"
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
-
+#include "mdss_debug.h"
#define DEFAULT_FRAME_RATE 60
enum {
@@ -124,6 +124,7 @@
irqreturn_t mdss_mdp_isr(int irq, void *ptr)
{
+ struct mdss_data_type *mdata = ptr;
u32 isr, mask, hist_isr, hist_mask;
@@ -172,17 +173,25 @@
if (isr & MDSS_MDP_INTR_PING_PONG_2_RD_PTR)
mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_RD_PTR);
- if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP);
+ }
- if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_1_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI0);
+ }
- if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_2_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_DSI1);
+ }
- if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+ if (isr & MDSS_MDP_INTR_INTF_3_VSYNC) {
mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+ mdss_misr_crc_collect(mdata, DISPLAY_MISR_HDMI);
+ }
if (isr & MDSS_MDP_INTR_WB_0_DONE)
mdss_mdp_intr_done(MDP_INTR_WB_0);
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index f138420..1bf414f 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -76,8 +76,13 @@
* - negative if the configuration is invalid
* - 0 if there is no panel reconfig needed
* - 1 if reconfig is needed to take effect
+ * @MDSS_EVENT_CONT_SPLASH_BEGIN: Special event used to handle transition of
+ * display state from boot loader to panel driver.
+ * The event handler will disable the panel.
* @MDSS_EVENT_CONT_SPLASH_FINISH: Special event used to handle transition of
* display state from boot loader to panel driver.
+ * The event handler will enable the panel and
+ * vote for the display clocks.
* @MDSS_EVENT_FB_REGISTERED: Called after fb dev driver has been registered,
* panel driver gets ptr to struct fb_info which
* holds fb dev information.
@@ -96,6 +101,7 @@
MDSS_EVENT_SUSPEND,
MDSS_EVENT_RESUME,
MDSS_EVENT_CHECK_PARAMS,
+ MDSS_EVENT_CONT_SPLASH_BEGIN,
MDSS_EVENT_CONT_SPLASH_FINISH,
MDSS_EVENT_FB_REGISTERED,
MDSS_EVENT_PANEL_CLK_CTRL,
diff --git a/include/linux/android_alarm.h b/include/linux/android_alarm.h
index cbfeafc..096f777 100644
--- a/include/linux/android_alarm.h
+++ b/include/linux/android_alarm.h
@@ -70,6 +70,7 @@
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
+void set_power_on_alarm(long secs);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 9a4e61d..2cb297e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/mmc/core.h>
#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
struct mmc_cid {
unsigned int manfid;
@@ -173,7 +174,8 @@
wide_bus:1,
high_power:1,
high_speed:1,
- disable_cd:1;
+ disable_cd:1,
+ async_intr_sup:1;
};
struct sdio_cis {
@@ -276,7 +278,6 @@
* percentage of sectors that should issue check for
* BKOPS need
* @bkops_stats: BKOPS statistics
- * @poll_for_completion: Poll on BKOPS completion
* @cancel_delayed_work: A flag to indicate if the delayed work
* should be cancelled
* @sectors_changed: number of sectors written or
@@ -294,10 +295,6 @@
* is idle.
*/
#define MMC_IDLE_BKOPS_TIME_MS 200
- struct work_struct poll_for_completion;
-/* Polling timeout and interval for waiting on non-blocking BKOPs completion */
-#define BKOPS_COMPLETION_POLLING_TIMEOUT_MS (4 * 60 * 1000) /* in ms */
-#define BKOPS_COMPLETION_POLLING_INTERVAL_MS 1000 /* in ms */
bool cancel_delayed_work;
unsigned int sectors_changed;
/*
@@ -388,6 +385,8 @@
struct device_attribute rpm_attrib;
unsigned int idle_timeout;
+ struct notifier_block reboot_notify;
+ bool issue_long_pon;
};
/*
@@ -608,6 +607,7 @@
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *);
int (*resume)(struct mmc_card *);
+ void (*shutdown)(struct mmc_card *);
};
extern int mmc_register_driver(struct mmc_driver *);
@@ -619,4 +619,5 @@
struct mmc_card *card);
extern void mmc_blk_init_packed_statistics(struct mmc_card *card);
extern void mmc_blk_disable_wr_packing(struct mmc_queue *mq);
+extern int mmc_send_long_pon(struct mmc_card *card);
#endif /* LINUX_MMC_CARD_H */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 995f8a2..f548721 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -146,6 +146,7 @@
extern int mmc_stop_bkops(struct mmc_card *);
extern int mmc_read_bkops_status(struct mmc_card *);
+extern bool mmc_card_is_prog_state(struct mmc_card *);
extern struct mmc_async_req *mmc_start_req(struct mmc_host *,
struct mmc_async_req *, int *);
extern int mmc_interrupt_hpi(struct mmc_card *);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 48be19a..27b0c4b 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -292,6 +292,8 @@
#define MMC_CAP2_STOP_REQUEST (1 << 18) /* Allow stop ongoing request */
/* Use runtime PM framework provided by MMC core */
#define MMC_CAP2_CORE_RUNTIME_PM (1 << 19)
+/* Allows Asynchronous SDIO irq while card is in 4-bit mode */
+#define MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE (1 << 20)
mmc_pm_flag_t pm_caps; /* supported pm features */
int clk_requests; /* internal reference counter */
@@ -414,6 +416,7 @@
};
extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
+extern bool mmc_host_may_gate_card(struct mmc_card *);
extern int mmc_add_host(struct mmc_host *);
extern void mmc_remove_host(struct mmc_host *);
extern void mmc_free_host(struct mmc_host *);
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 58e52d4..961a4e1 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -162,6 +162,10 @@
#define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT)
#define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT)
+
+#define SDIO_CCCR_INTERRUPT_EXTENSION 0x16
+#define SDIO_SUPPORT_ASYNC_INTR (1<<0)
+#define SDIO_ENABLE_ASYNC_INTR (1<<1)
/*
* Function Basic Registers (FBR)
*/
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index e8de769..ae88807 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -781,6 +781,27 @@
#define IOCTL_KGSL_PERFCOUNTER_READ \
_IOWR(KGSL_IOC_TYPE, 0x3B, struct kgsl_perfcounter_read)
+/*
+ * struct kgsl_gpumem_sync_cache_bulk - argument to
+ * IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK
+ * @id_list: list of GPU buffer ids of the buffers to sync
+ * @count: number of GPU buffer ids in id_list
+ * @op: a mask of KGSL_GPUMEM_CACHE_* values
+ *
+ * Sync the cache for memory headed to and from the GPU. Certain
+ * optimizations can be made on the cache operation based on the total
+ * size of the working set of memory to be managed.
+ */
+struct kgsl_gpumem_sync_cache_bulk {
+ unsigned int *id_list;
+ unsigned int count;
+ unsigned int op;
+/* private: reserved for future use */
+ unsigned int __pad[2]; /* For future binary compatibility */
+};
+
+#define IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK \
+ _IOWR(KGSL_IOC_TYPE, 0x3C, struct kgsl_gpumem_sync_cache_bulk)
#ifdef __KERNEL__
#ifdef CONFIG_MSM_KGSL_DRM
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index e4df414..511c2fb 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -436,6 +436,31 @@
uint32_t *b;
};
+enum {
+ DISPLAY_MISR_EDP,
+ DISPLAY_MISR_DSI0,
+ DISPLAY_MISR_DSI1,
+ DISPLAY_MISR_HDMI,
+ DISPLAY_MISR_LCDC,
+ DISPLAY_MISR_ATV,
+ DISPLAY_MISR_DSI_CMD,
+ DISPLAY_MISR_MAX
+};
+
+enum {
+ MISR_OP_NONE,
+ MISR_OP_SFM,
+ MISR_OP_MFM,
+ MISR_OP_BM,
+ MISR_OP_MAX
+};
+
+struct mdp_misr {
+ uint32_t block_id;
+ uint32_t frame_count;
+ uint32_t crc_op_mode;
+ uint32_t crc_value[32];
+};
/*
@@ -684,6 +709,7 @@
metadata_op_vic,
metadata_op_wb_format,
metadata_op_get_caps,
+ metadata_op_crc,
metadata_op_max
};
@@ -708,6 +734,7 @@
uint32_t op;
uint32_t flags;
union {
+ struct mdp_misr misr_request;
struct mdp_blend_cfg blend_cfg;
struct mdp_mixer_cfg mixer_cfg;
uint32_t panel_frame_rate;
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 209062b..f9729c4 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -425,6 +425,7 @@
bool enable_hbm;
bool disable_park_mode;
bool consider_ipa_handshake;
+ bool ahb_async_bridge_bypass;
};
struct msm_usb_host_platform_data {
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index 2a53114..2ba585e 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -34,6 +34,7 @@
#define HAVE_WCNSS_SUSPEND_RESUME_NOTIFY 1
#define HAVE_WCNSS_RESET_INTR 1
#define HAVE_WCNSS_CAL_DOWNLOAD 1
+#define HAVE_WCNSS_RX_BUFF_COUNT 1
struct device *wcnss_wlan_get_device(void);
struct resource *wcnss_wlan_get_memory_map(struct device *dev);
@@ -69,6 +70,7 @@
int wcnss_device_ready(void);
void wcnss_riva_dump_pmic_regs(void);
int wcnss_xo_auto_detect_enabled(void);
+u32 wcnss_get_wlan_rx_buff_count(void);
#define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev)
#define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data))
diff --git a/include/media/msm_cam_sensor.h b/include/media/msm_cam_sensor.h
index 47cf184..31798d6 100644
--- a/include/media/msm_cam_sensor.h
+++ b/include/media/msm_cam_sensor.h
@@ -184,6 +184,18 @@
uint16_t delay;
};
+struct msm_camera_i2c_array_write_config {
+ struct msm_camera_i2c_reg_setting conf_array;
+ uint16_t slave_addr;
+};
+
+struct msm_camera_i2c_read_config {
+ uint16_t slave_addr;
+ uint16_t reg_addr;
+ enum msm_camera_i2c_data_type data_type;
+ uint16_t *data;
+};
+
struct msm_camera_csid_vc_cfg {
uint8_t cid;
uint8_t dt;
@@ -320,7 +332,9 @@
enum msm_sensor_cfg_type_t {
CFG_SET_SLAVE_INFO,
+ CFG_SLAVE_READ_I2C,
CFG_WRITE_I2C_ARRAY,
+ CFG_SLAVE_WRITE_I2C_ARRAY,
CFG_WRITE_I2C_SEQ_ARRAY,
CFG_POWER_UP,
CFG_POWER_DOWN,
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index f8317df..8f32475 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1604,7 +1604,6 @@
struct task_struct *next_task;
struct rq *lowest_rq;
int ret = 0;
- bool moved = false;
if (!rq->rt.overloaded)
return 0;
@@ -1674,7 +1673,6 @@
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, lowest_rq->cpu);
- moved = true;
activate_task(lowest_rq, next_task, 0);
ret = 1;
@@ -1685,11 +1683,6 @@
out:
put_task_struct(next_task);
- if (moved && task_notify_on_migrate(next_task))
- atomic_notifier_call_chain(&migration_notifier_head,
- cpu_of(lowest_rq),
- (void *)cpu_of(rq));
-
return ret;
}
@@ -1703,10 +1696,8 @@
static int pull_rt_task(struct rq *this_rq)
{
int this_cpu = this_rq->cpu, ret = 0, cpu;
- struct task_struct *p = NULL;
+ struct task_struct *p;
struct rq *src_rq;
- bool moved = false;
- int src_cpu = 0;
if (likely(!rt_overloaded(this_rq)))
return 0;
@@ -1767,10 +1758,6 @@
deactivate_task(src_rq, p, 0);
set_task_cpu(p, this_cpu);
activate_task(this_rq, p, 0);
-
- moved = true;
- src_cpu = cpu_of(src_rq);
-
/*
* We continue with the search, just in
* case there's an even higher prio task
@@ -1782,11 +1769,6 @@
double_unlock_balance(this_rq, src_rq);
}
- if (moved && task_notify_on_migrate(p))
- atomic_notifier_call_chain(&migration_notifier_head,
- this_cpu,
- (void *)src_cpu);
-
return ret;
}
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index 669f8e3..d35d8c4 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -67,14 +67,12 @@
#define TAPAN_I2S_MASTER_MODE_MASK 0x08
#define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
+#define TAPAN_MCLK_CLK_9P6MHZ 9600000
#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
-#define TAPAN_MCLK_CLK_12P288MHZ 12288000
-#define TAPAN_MCLK_CLK_9P6HZ 9600000
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -4271,9 +4269,6 @@
*/
TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
- /* not needed if MBHC is not needed */
- /* Disable TX7 internal biasing path which can cause leakage */
- TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
};
static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
@@ -4449,7 +4444,7 @@
struct wcd9xxx *wcd9xxx;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
- int i;
+ int i, rco_clk_rate;
void *ptr = NULL;
codec->control_data = dev_get_drvdata(codec->dev->parent);
@@ -4485,8 +4480,14 @@
return ret;
}
- ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAPAN);
+ if (TAPAN_IS_1_0(control->version))
+ rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
+
+ ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
+ WCD9XXX_MBHC_VERSION_TAPAN,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
return ret;
@@ -4510,7 +4511,7 @@
snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
0x01);
- } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
+ } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
}
tapan_codec_init_reg(codec);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index ab96baf..703b8b8 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -47,6 +47,8 @@
#define TAIKO_HPH_PA_SETTLE_COMP_ON 3000
#define TAIKO_HPH_PA_SETTLE_COMP_OFF 13000
+#define DAPM_MICBIAS2_EXTERNAL_STANDALONE "MIC BIAS2 External Standalone"
+
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
const struct kernel_param *kp);
@@ -320,7 +322,7 @@
#define TAIKO_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
#define TAIKO_MCLK_CLK_12P288MHZ 12288000
-#define TAIKO_MCLK_CLK_9P6HZ 9600000
+#define TAIKO_MCLK_CLK_9P6MHZ 9600000
#define TAIKO_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FORMAT_S24_LE)
@@ -469,6 +471,8 @@
s32 dmic_1_2_clk_cnt;
s32 dmic_3_4_clk_cnt;
s32 dmic_5_6_clk_cnt;
+ s32 ldo_h_users;
+ s32 micb_2_users;
u32 anc_slot;
bool anc_func;
@@ -2661,16 +2665,26 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
- if (taiko->mbhc_started &&
- taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
- micb_ctl_reg == TAIKO_A_MICB_2_CTL)
- wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
- WCD9XXX_COND_HPH_MIC,
- micb_ctl_reg, w->shift,
- false);
- else
+ if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ if (++taiko->micb_2_users == 1) {
+ if (taiko->resmgr.pdata->
+ micbias.bias2_is_headset_only)
+ wcd9xxx_resmgr_add_cond_update_bits(
+ &taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, w->shift,
+ false);
+ else
+ snd_soc_update_bits(codec, micb_ctl_reg,
+ 1 << w->shift,
+ 1 << w->shift);
+ }
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ taiko->micb_2_users);
+ } else {
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
1 << w->shift);
+ }
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20000);
@@ -2678,15 +2692,27 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
- if (taiko->mbhc_started &&
- taiko->resmgr.pdata->micbias.bias2_is_headset_only &&
- micb_ctl_reg == TAIKO_A_MICB_2_CTL)
- wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
- WCD9XXX_COND_HPH_MIC,
- micb_ctl_reg, 7, false);
- else
+ if (taiko->mbhc_started && micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ if (--taiko->micb_2_users == 0) {
+ if (taiko->resmgr.pdata->
+ micbias.bias2_is_headset_only)
+ wcd9xxx_resmgr_rm_cond_update_bits(
+ &taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, 7, false);
+ else
+ snd_soc_update_bits(codec, micb_ctl_reg,
+ 1 << w->shift, 0);
+ }
+ pr_debug("%s: micb_2_users %d\n", __func__,
+ taiko->micb_2_users);
+ WARN(taiko->micb_2_users < 0,
+ "Unexpected micbias users %d\n",
+ taiko->micb_2_users);
+ } else {
snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
0);
+ }
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
@@ -2706,6 +2732,22 @@
return 0;
}
+/* called under codec_resource_lock acquisition */
+static int taiko_enable_mbhc_micbias(struct snd_soc_codec *codec, bool enable)
+{
+ int rc;
+
+ if (enable)
+ rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ else
+ rc = snd_soc_dapm_disable_pin(&codec->dapm,
+ DAPM_MICBIAS2_EXTERNAL_STANDALONE);
+ if (!rc)
+ snd_soc_dapm_sync(&codec->dapm);
+ pr_debug("%s: leave ret %d\n", __func__, rc);
+ return rc;
+}
static void tx_hpf_corner_freq_callback(struct work_struct *work)
{
@@ -2937,18 +2979,65 @@
return 0;
}
-static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+/* called under codec_resource_lock acquisition */
+static int __taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enter\n", __func__);
switch (event) {
- case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_PRE_PMU:
+ if (++priv->ldo_h_users == 1) {
+ wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+ 1 << 7);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ /* LDO enable requires 1ms to settle down */
+ usleep_range(1000, 1000);
+ }
+ break;
case SND_SOC_DAPM_POST_PMD:
- usleep_range(1000, 1000);
+ if (--priv->ldo_h_users == 0) {
+ wcd9xxx_resmgr_get_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 1 << 7,
+ 0);
+ wcd9xxx_resmgr_put_clk_block(&priv->resmgr,
+ WCD9XXX_CLK_RCO);
+ wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ pr_debug("%s: ldo_h_users %d\n", __func__,
+ priv->ldo_h_users);
+ }
+ WARN(priv->ldo_h_users < 0, "Unexpected ldo_h users %d\n",
+ priv->ldo_h_users);
break;
}
+ pr_debug("%s: leave\n", __func__);
return 0;
}
+static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int rc;
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ WCD9XXX_BCL_LOCK(&priv->resmgr);
+ rc = __taiko_codec_enable_ldo_h(w, kcontrol, event);
+ WCD9XXX_BCL_UNLOCK(&priv->resmgr);
+ return rc;
+}
+
static int taiko_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -3696,13 +3785,15 @@
{"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
{"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
{"RX7 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP2", "IIR2", "IIR2"},
+
+ /* IIR1, IIR2 inputs to Second RX Mixer on RX1, RX2 and RX7 chains. */
{"RX1 MIX2 INP1", "IIR1", "IIR1"},
{"RX1 MIX2 INP2", "IIR1", "IIR1"},
{"RX2 MIX2 INP1", "IIR1", "IIR1"},
{"RX2 MIX2 INP2", "IIR1", "IIR1"},
{"RX7 MIX2 INP1", "IIR1", "IIR1"},
{"RX7 MIX2 INP2", "IIR1", "IIR1"},
- {"RX7 MIX1 INP2", "IIR2", "IIR2"},
{"RX1 MIX2 INP1", "IIR2", "IIR2"},
{"RX1 MIX2 INP2", "IIR2", "IIR2"},
{"RX2 MIX2 INP1", "IIR2", "IIR2"},
@@ -3780,6 +3871,13 @@
{"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR1 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR1 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR1 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR1 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR1 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR1 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR1 INP1 MUX", "RX7", "SLIM RX7"},
{"IIR2", NULL, "IIR2 INP1 MUX"},
{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -3792,6 +3890,13 @@
{"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
{"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
{"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
+ {"IIR2 INP1 MUX", "RX1", "SLIM RX1"},
+ {"IIR2 INP1 MUX", "RX2", "SLIM RX2"},
+ {"IIR2 INP1 MUX", "RX3", "SLIM RX3"},
+ {"IIR2 INP1 MUX", "RX4", "SLIM RX4"},
+ {"IIR2 INP1 MUX", "RX5", "SLIM RX5"},
+ {"IIR2 INP1 MUX", "RX6", "SLIM RX6"},
+ {"IIR2 INP1 MUX", "RX7", "SLIM RX7"},
{"MIC BIAS1 Internal1", NULL, "LDO_H"},
{"MIC BIAS1 Internal2", NULL, "LDO_H"},
@@ -3804,7 +3909,7 @@
{"MIC BIAS3 Internal2", NULL, "LDO_H"},
{"MIC BIAS3 External", NULL, "LDO_H"},
{"MIC BIAS4 External", NULL, "LDO_H"},
-
+ {DAPM_MICBIAS2_EXTERNAL_STANDALONE, NULL, "LDO_H Standalone"},
};
static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -5159,8 +5264,17 @@
SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
- SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
- taiko_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ /*
+ * DAPM 'LDO_H Standalone' is to be powered by mbhc driver after
+ * acquring codec_resource lock.
+ * So call __taiko_codec_enable_ldo_h instead and avoid deadlock.
+ */
+ SND_SOC_DAPM_SUPPLY("LDO_H Standalone", SND_SOC_NOPM, 7, 0,
+ __taiko_codec_enable_ldo_h,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
taiko_config_compander, SND_SOC_DAPM_PRE_PMU |
@@ -5265,6 +5379,10 @@
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_EXTERNAL_STANDALONE, SND_SOC_NOPM,
+ 7, 0, taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
taiko_codec_enable_micbias,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
@@ -5376,10 +5494,10 @@
/* Sidetone */
SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
- SND_SOC_DAPM_PGA("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
- SND_SOC_DAPM_PGA("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("IIR2", TAIKO_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
/* AUX PGA */
SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAIKO_A_RX_AUX_SW_CTL, 7, 0,
@@ -5623,7 +5741,7 @@
snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
/* Set the DMIC sample rate */
- if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6HZ) {
+ if (pdata->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ) {
switch (pdata->dmic_sample_rate) {
case TAIKO_DMIC_SAMPLE_RATE_2P4MHZ:
dmic_sample_rate_value = TAIKO_DMIC_SAMPLE_RATE_DIV_4;
@@ -6046,6 +6164,7 @@
int ret = 0;
struct snd_soc_codec *codec;
struct taiko_priv *taiko;
+ int rco_clk_rate;
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
taiko = snd_soc_codec_get_drvdata(codec);
@@ -6076,8 +6195,16 @@
if (taiko->mbhc_started) {
wcd9xxx_mbhc_deinit(&taiko->mbhc);
taiko->mbhc_started = false;
+
+ if (TAIKO_IS_1_0(wcd9xxx->version))
+ rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
+ taiko_enable_mbhc_micbias,
+ WCD9XXX_MBHC_VERSION_TAIKO,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
} else {
@@ -6209,7 +6336,7 @@
struct wcd9xxx *wcd9xxx;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
- int i;
+ int i, rco_clk_rate;
void *ptr = NULL;
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
@@ -6247,9 +6374,16 @@
taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
wcd9xxx_clsh_init(&taiko->clsh_d, &taiko->resmgr);
+ if (TAIKO_IS_1_0(core->version))
+ rco_clk_rate = TAIKO_MCLK_CLK_12P288MHZ;
+ else
+ rco_clk_rate = TAIKO_MCLK_CLK_9P6MHZ;
+
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec,
- WCD9XXX_MBHC_VERSION_TAIKO);
+ taiko_enable_mbhc_micbias,
+ WCD9XXX_MBHC_VERSION_TAIKO,
+ rco_clk_rate);
if (ret) {
pr_err("%s: mbhc init failed %d\n", __func__, ret);
goto err_init;
@@ -6264,11 +6398,13 @@
taiko->aux_pga_cnt = 0;
taiko->aux_l_gain = 0x1F;
taiko->aux_r_gain = 0x1F;
+ taiko->ldo_h_users = 0;
+ taiko->micb_2_users = 0;
taiko_update_reg_defaults(codec);
pr_debug("%s: MCLK Rate = %x\n", __func__, wcd9xxx->mclk_rate);
if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_12P288MHZ)
snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x0);
- else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6HZ)
+ else if (wcd9xxx->mclk_rate == TAIKO_MCLK_CLK_9P6MHZ)
snd_soc_update_bits(codec, TAIKO_A_CHIP_CTL, 0x06, 0x2);
taiko_codec_init_reg(codec);
ret = taiko_handle_pdata(taiko);
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index bfd496b..887a324 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/firmware.h>
@@ -47,7 +46,7 @@
SND_JACK_BTN_6 | SND_JACK_BTN_7)
#define NUM_DCE_PLUG_DETECT 3
-#define NUM_DCE_PLUG_INS_DETECT 4
+#define NUM_DCE_PLUG_INS_DETECT 5
#define NUM_ATTEMPTS_INSERT_DETECT 25
#define NUM_ATTEMPTS_TO_REPORT 5
@@ -75,7 +74,6 @@
#define MCLK_RATE_12288KHZ 12288000
#define MCLK_RATE_9600KHZ 9600000
-#define WCD9XXX_RCO_CLK_RATE MCLK_RATE_12288KHZ
#define DEFAULT_DCE_STA_WAIT 55
#define DEFAULT_DCE_WAIT 60000
@@ -83,20 +81,23 @@
#define VDDIO_MICBIAS_MV 1800
+#define WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US 5000
+
#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
-#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
+#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
#define WCD9XXX_MEAS_DELTA_MAX_MV 50
#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
+#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
#define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO 28
#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN 21
-static bool detect_use_vddio_switch;
+static bool detect_use_vddio_switch = true;
struct wcd9xxx_mbhc_detect {
u16 dce;
@@ -278,6 +279,11 @@
codec = mbhc->codec;
+ if (mbhc->micbias_enable) {
+ pr_debug("%s: micbias is already on\n", __func__);
+ return;
+ }
+
if (vddio_switch && !mbhc->mbhc_micbias_switched &&
(!checkpolling || mbhc->polling_active)) {
if (restartpolling)
@@ -802,6 +808,12 @@
mbhc->buttons_pressed &=
~WCD9XXX_JACK_BUTTON_MASK;
}
+
+ if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
+ pr_debug("%s: Disabling micbias\n", __func__);
+ mbhc->micbias_enable_cb(mbhc->codec, false);
+ mbhc->micbias_enable = false;
+ }
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
@@ -815,8 +827,17 @@
if (mbhc->mbhc_cfg->detect_extn_cable) {
/* Report removal of current jack type */
if (mbhc->hph_status && mbhc->hph_status != jack_type) {
+ if (mbhc->micbias_enable &&
+ mbhc->micbias_enable_cb &&
+ mbhc->hph_status == SND_JACK_HEADSET) {
+ pr_debug("%s: Disabling micbias\n",
+ __func__);
+ mbhc->micbias_enable_cb(mbhc->codec,
+ false);
+ mbhc->micbias_enable = false;
+ }
pr_debug("%s: Reporting removal (%x)\n",
- __func__, mbhc->hph_status);
+ __func__, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
mbhc->hph_status = 0;
@@ -835,6 +856,11 @@
} else if (jack_type == SND_JACK_LINEOUT) {
mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
}
+
+ if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
+ pr_debug("%s: Enabling micbias\n", __func__);
+ mbhc->micbias_enable_cb(mbhc->codec, true);
+ }
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -882,9 +908,9 @@
vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
if (tovddio)
- r = v * vddio_k / mb_k;
+ r = v * (vddio_k + 4) / (mb_k + 4);
else
- r = v * mb_k / vddio_k;
+ r = v * (mb_k + 4) / (vddio_k + 4);
return r;
}
@@ -988,19 +1014,17 @@
return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
}
-static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
- u16 bias_value)
+static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+ u16 bias_value, s16 z)
{
- s16 value, z, mb;
+ s16 value, mb;
s32 mv;
value = bias_value;
if (dce) {
- z = (mbhc->mbhc_data.dce_z);
mb = (mbhc->mbhc_data.dce_mb);
mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
} else {
- z = (mbhc->mbhc_data.sta_z);
mb = (mbhc->mbhc_data.sta_mb);
mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
}
@@ -1008,6 +1032,14 @@
return mv;
}
+static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
+ u16 bias_value)
+{
+ 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);
+}
+
/* called only from interrupt which is under codec_resource_lock acquisition */
static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
@@ -1080,7 +1112,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
- snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+ __wcd9xxx_switch_micbias(mbhc, 0, false, false);
usleep_range(generic->t_shutdown_plug_rem,
generic->t_shutdown_plug_rem);
@@ -1117,6 +1149,7 @@
static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
{
+ pr_debug("%s: vddio %d\n", __func__, on);
if (on) {
snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1 << 7, 1 << 7);
@@ -1160,7 +1193,7 @@
int ch;
enum wcd9xxx_mbhc_plug_type type;
int vdce;
- struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL;
+ struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL, *dvddio = NULL;
int maxv = 0, minv = 0;
const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
@@ -1182,7 +1215,7 @@
d->_type = PLUG_TYPE_HIGH_HPH;
ch += d->hphl_status & 0x01;
- if (!d->swap_gnd && !d->hwvalue) {
+ if (!d->swap_gnd && !d->hwvalue && !d->vddio) {
if (maxv < d->_vdces)
maxv = d->_vdces;
if (!minv || minv > d->_vdces)
@@ -1215,6 +1248,11 @@
}
for (i = 0, d = dt; i < size; i++, d++) {
+ if (d->vddio) {
+ dvddio = d;
+ continue;
+ }
+
if ((i > 0) && (d->_type != dprev->_type)) {
pr_debug("%s: Invalid, inconsistent types\n", __func__);
type = PLUG_TYPE_INVALID;
@@ -1249,11 +1287,69 @@
__func__, type);
type = PLUG_TYPE_INVALID;
}
+ if (type == PLUG_TYPE_HEADSET && dvddio) {
+ if ((dvddio->_vdces > hs_max) ||
+ (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
+ 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;
+ } else {
+ pr_debug("%s: Headset with regular MIC detected\n",
+ __func__);
+ if (mbhc->mbhc_cfg->micbias_enable_flags &
+ (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET))
+ mbhc->micbias_enable = true;
+ }
+ }
exit:
- pr_debug("%s: Plug type %d detected\n", __func__, type);
+ pr_debug("%s: Plug type %d detected, micbias_enable %d\n", __func__,
+ type, mbhc->micbias_enable);
return type;
}
+/*
+ * Pull down MBHC micbias for provided duration in microsecond.
+ */
+static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us)
+{
+ bool micbiasconn = false;
+ struct snd_soc_codec *codec = mbhc->codec;
+ const u16 ctlreg = mbhc->mbhc_bias_regs.ctl_reg;
+
+ /*
+ * Disable MBHC to micbias connection to pull down
+ * micbias and pull down micbias for a moment.
+ */
+ if ((snd_soc_read(mbhc->codec, ctlreg) & 0x01)) {
+ WARN_ONCE(1, "MBHC micbias is already pulled down unexpectedly\n");
+ return -EFAULT;
+ }
+
+ if ((snd_soc_read(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL) & 1 << 4)) {
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+ 1 << 4, 0);
+ micbiasconn = true;
+ }
+
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+
+ /*
+ * Pull down for 1ms to discharge bias. Give small margin (10us) to be
+ * able to get consistent result across DCEs.
+ */
+ usleep_range(1000, 1000 + 10);
+
+ if (micbiasconn)
+ snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
+ 1 << 4, 1 << 4);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ usleep_range(us, us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
+
+ return 0;
+}
+
static enum wcd9xxx_mbhc_plug_type
wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
{
@@ -1275,6 +1371,12 @@
plug_type_ptr =
WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
+ /*
+ * cfilter in fast mode requires 1ms to charge up and down micbias
+ * fully.
+ */
+ (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].swap_gnd = false;
@@ -1283,7 +1385,7 @@
for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
if (detect_use_vddio_switch)
- rt[i].vddio = (i == NUM_DCE_PLUG_INS_DETECT - 1);
+ rt[i].vddio = (i == 1);
else
rt[i].vddio = false;
rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
@@ -1292,6 +1394,15 @@
wcd9xxx_codec_hphr_gnd_switch(codec, true);
if (rt[i].vddio)
wcd9xxx_onoff_vddio_switch(mbhc, true);
+ /*
+ * Pull down micbias to detect headset with mic which has
+ * threshold and to have more consistent voltage measurements.
+ *
+ * cfilter in fast mode requires 1ms to charge up and down
+ * micbias fully.
+ */
+ (void) wcd9xxx_pull_down_micbias(mbhc,
+ WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
if (rt[i].vddio)
wcd9xxx_onoff_vddio_switch(mbhc, false);
@@ -1490,6 +1601,11 @@
*/
wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
msleep(100);
+
+ /* if PA is already on, switch micbias source to VDDIO */
+ if (mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
+ __wcd9xxx_switch_micbias(mbhc, 1, false, false);
wcd9xxx_start_hs_polling(mbhc);
} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
if (mbhc->mbhc_cfg->detect_extn_cable) {
@@ -1812,7 +1928,6 @@
static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
{
- bool vddio;
struct wcd9xxx_mbhc *mbhc = data;
pr_debug("%s: enter, removal interrupt\n", __func__);
@@ -1831,25 +1946,12 @@
WCD9XXX_COND_HPH, false);
}
- vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
- mbhc->mbhc_micbias_switched);
- if (vddio)
- __wcd9xxx_switch_micbias(mbhc, 0, false, true);
-
if (mbhc->mbhc_cfg->detect_extn_cable &&
!wcd9xxx_swch_level_remove(mbhc))
wcd9xxx_hs_remove_irq_noswch(mbhc);
else
wcd9xxx_hs_remove_irq_swch(mbhc);
- /*
- * if driver turned off vddio switch and headset is not removed,
- * turn on the vddio switch back, if headset is removed then vddio
- * switch is off by time now and shouldn't be turn on again from here
- */
- if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
- __wcd9xxx_switch_micbias(mbhc, 1, true, true);
-
if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
WCD9XXX_COND_HPH, true);
@@ -2457,18 +2559,45 @@
return mask;
}
+void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
+{
+ s16 reg0, reg1;
+ struct snd_soc_codec *codec = mbhc->codec;
+
+ WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
+ /* Pull down micbias to ground and disconnect vddio switch */
+ reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x81, 0x1);
+ reg1 = snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg);
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 1 << 7, 0);
+
+ /* Disconnect override from micbias */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
+ usleep_range(1000, 1000 + 1000);
+ *sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
+ *dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+ /* Connect override from micbias */
+ snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
+ /* Disable pull down micbias to ground */
+ snd_soc_write(codec, mbhc->mbhc_bias_regs.mbhc_reg, reg1);
+ snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
+}
+
irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
{
int i, mask;
- short dce, sta;
- s32 mv, mv_s, stamv_s;
bool vddio;
u8 mbhc_status;
+ s16 dce_z, sta_z;
int btn = -1, meas = 0;
struct wcd9xxx_mbhc *mbhc = data;
const struct wcd9xxx_mbhc_btn_detect_cfg *d =
WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
short btnmeas[d->n_btn_meas + 1];
+ short dce[d->n_btn_meas + 1], sta;
+ s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
+ s32 stamv, stamv_s;
struct snd_soc_codec *codec = mbhc->codec;
struct wcd9xxx *core = mbhc->resmgr->core;
int n_btn_meas = d->n_btn_meas;
@@ -2492,9 +2621,6 @@
goto done;
}
- dce = wcd9xxx_read_dce_result(codec);
- mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
-
/* If switch nterrupt already kicked in, ignore button press */
if (mbhc->in_swch_irq_handler) {
pr_debug("%s: Swtich level changed, ignore button press\n",
@@ -2506,13 +2632,10 @@
/* Measure scaled HW DCE */
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
- mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
/* Measure scaled HW STA */
+ dce[0] = wcd9xxx_read_dce_result(codec);
sta = wcd9xxx_read_sta_result(codec);
- stamv_s = wcd9xxx_codec_sta_dce_v(mbhc, 0, sta);
- if (vddio)
- stamv_s = scale_v_micb_vddio(mbhc, stamv_s, false);
if (mbhc_status != STATUS_REL_DETECTION) {
if (mbhc->mbhc_last_resume &&
!time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
@@ -2522,30 +2645,55 @@
} else {
pr_debug("%s: Button is released without resume",
__func__);
- btn = wcd9xxx_determine_button(mbhc, mv_s);
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ 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);
+ mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
+ false) : mv[0];
+ btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
btn = -1;
goto done;
}
}
+ for (meas = 1; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1)));
+ meas++)
+ dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
+
+ wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
+
+ stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
+ if (vddio)
+ stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
+ else
+ stamv_s = stamv;
pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
- sta & 0xFFFF, wcd9xxx_codec_sta_dce_v(mbhc, 0, sta), stamv_s);
+ sta & 0xFFFF, stamv, stamv_s);
/* determine pressed button */
- btnmeas[meas++] = wcd9xxx_determine_button(mbhc, mv_s);
+ mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
+ 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__,
- dce & 0xFFFF, mv, mv_s, btnmeas[meas - 1]);
+ dce[0] & 0xFFFF, mv[0], mv_s[0], btnmeas[0]);
if (n_btn_meas == 0)
btn = btnmeas[0];
- for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
- dce = wcd9xxx_codec_sta_dce(mbhc, 1, false);
- mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
- mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
-
- btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s);
+ 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_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
+ mv[meas];
+ btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
- __func__, meas, dce & 0xFFFF, mv, mv_s, btnmeas[meas]);
+ __func__, meas, dce[meas] & 0xFFFF, mv[meas],
+ mv_s[meas], btnmeas[meas]);
/*
* if large enough measurements are collected,
* start to check if last all n_btn_con measurements were
@@ -2819,9 +2967,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(WCD9XXX_MUX_SWITCH_READY_WAIT_US,
- WCD9XXX_MUX_SWITCH_READY_WAIT_US +
- WCD9XXX_USLEEP_RANGE_MARGIN_US);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
/* DCE 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);
@@ -2841,7 +2991,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(100, 100);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
@@ -2854,7 +3008,11 @@
ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
if (ret)
goto gen_err;
- usleep_range(100, 100);
+ /*
+ * Hardware that has external cap can delay mic bias ramping down up
+ * to 50ms.
+ */
+ msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
@@ -3092,8 +3250,8 @@
const s16 v_br_h =
wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
- n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
- wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
+ n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",
+ p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
@@ -3240,18 +3398,31 @@
enum wcd9xxx_micbias_num ret;
switch (event) {
case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_1_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
ret = MBHC_MICBIAS1;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_2_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
ret = MBHC_MICBIAS2;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_3_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
ret = MBHC_MICBIAS3;
break;
case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
+ case WCD9XXX_EVENT_PRE_MICBIAS_4_OFF:
+ case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
+ case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
ret = MBHC_MICBIAS4;
break;
default:
+ WARN_ONCE(1, "Cannot convert event %d to micbias\n", event);
ret = MBHC_MICBIAS_INVALID;
break;
}
@@ -3349,33 +3520,41 @@
case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
if (mbhc->mbhc_cfg->micbias ==
wcd9xxx_event_to_micbias(event) &&
- wcd9xxx_is_hph_pa_on(codec))
+ (mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
wcd9xxx_switch_micbias(mbhc, 1);
break;
/* PA usage change */
case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
+ set_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
- /* if micbias is enabled, switch to vddio */
+ /* if micbias is not enabled, switch to vddio */
wcd9xxx_switch_micbias(mbhc, 1);
break;
case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
- /* Not used now */
+ set_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
break;
case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
+ clear_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
/* if HPH PAs are off, report OCP and switch back to CFILT */
clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
if (mbhc->hph_status & SND_JACK_OC_HPHL)
hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
- wcd9xxx_switch_micbias(mbhc, 0);
+ if (!(mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ wcd9xxx_switch_micbias(mbhc, 0);
break;
case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
+ clear_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
/* if HPH PAs are off, report OCP and switch back to CFILT */
clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
if (mbhc->hph_status & SND_JACK_OC_HPHR)
hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
- wcd9xxx_switch_micbias(mbhc, 0);
+ if (!(mbhc->event_state &
+ (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
+ wcd9xxx_switch_micbias(mbhc, 0);
break;
/* Clock usage change */
case WCD9XXX_EVENT_PRE_MCLK_ON:
@@ -3406,7 +3585,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
0 << 4);
/* Re-calibrate clock rate dependent values */
- wcd9xxx_update_mbhc_clk_rate(mbhc, WCD9XXX_RCO_CLK_RATE);
+ wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->rco_clk_rate);
/* If clock source changes, stop and restart polling */
if (wcd9xxx_mbhc_polling(mbhc)) {
wcd9xxx_calibrate_hs_polling(mbhc);
@@ -3472,7 +3651,10 @@
* NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
*/
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
- struct snd_soc_codec *codec, int version)
+ struct snd_soc_codec *codec,
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
+ int version,
+ int rco_clk_rate)
{
int ret;
void *core;
@@ -3495,7 +3677,9 @@
mbhc->codec = codec;
mbhc->resmgr = resmgr;
mbhc->resmgr->mbhc = mbhc;
+ mbhc->micbias_enable_cb = micbias_enable_cb;
mbhc->mbhc_version = version;
+ mbhc->rco_clk_rate = rco_clk_rate;
if (mbhc->headset_jack.jack == NULL) {
ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 4f8f3cf..71a62b2 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -34,6 +34,12 @@
MBHC_V_IDX_NUM,
};
+enum mbhc_cal_type {
+ MBHC_CAL_MCLK,
+ MBHC_CAL_RCO,
+ MBHC_CAL_NUM,
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -78,6 +84,11 @@
MBHC_MICBIAS4,
};
+enum wcd9xx_mbhc_micbias_enable_bits {
+ MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
+ MBHC_MICBIAS_ENABLE_REGULAR_HEADSET,
+};
+
enum wcd9xxx_mbhc_state {
MBHC_STATE_NONE = -1,
MBHC_STATE_POTENTIAL,
@@ -99,6 +110,11 @@
TAIKO_NUM_CLK_FREQS,
};
+enum wcd9xxx_mbhc_event_state {
+ MBHC_EVENT_PA_HPHL,
+ MBHC_EVENT_PA_HPHR,
+};
+
struct wcd9xxx_mbhc_general_cfg {
u8 t_ldoh;
u8 t_bg_fast_settle;
@@ -196,6 +212,8 @@
int gpio_level_insert;
bool insert_detect; /* codec has own MBHC_INSERT_DETECT */
bool detect_extn_cable;
+ /* bit mask of enum wcd9xx_mbhc_micbias_enable_bits */
+ 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 *);
};
@@ -241,8 +259,13 @@
bool no_mic_headset_override;
- /* track PA/DAC state */
+ /* track PA/DAC state to sync with userspace */
unsigned long hph_pa_dac_state;
+ /*
+ * save codec's state with resmgr event notification
+ * bit flags of enum wcd9xxx_mbhc_event_state
+ */
+ unsigned long event_state;
unsigned long mbhc_last_resume; /* in jiffies */
@@ -253,8 +276,13 @@
struct notifier_block nblock;
+ bool micbias_enable;
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool);
+
enum wcd9xxx_mbhc_version mbhc_version;
+ u32 rco_clk_rate;
+
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_poke;
struct dentry *debugfs_mbhc;
@@ -319,7 +347,10 @@
int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
struct wcd9xxx_mbhc_config *mbhc_cfg);
int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
- struct snd_soc_codec *codec, int version);
+ struct snd_soc_codec *codec,
+ int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
+ int version,
+ int rco_clk_rate);
void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc);
void *wcd9xxx_mbhc_cal_btn_det_mp(
const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 60a76a2..77dbd36 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -659,7 +659,6 @@
bool set;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
set = !!test_bit(cond, &resmgr->cond_flags);
list_for_each(l, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
@@ -675,13 +674,14 @@
void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
enum wcd9xxx_resmgr_cond cond, bool set)
{
- WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
(!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
pr_debug("%s: Resource %d condition changed to %s\n", __func__,
cond, set ? "set" : "clear");
wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
}
+ mutex_unlock(&resmgr->update_bit_cond_lock);
}
int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
@@ -700,11 +700,11 @@
entry->shift = shift;
entry->invert = invert;
- WCD9XXX_BCL_LOCK(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
return 0;
}
@@ -722,7 +722,7 @@
struct wcd9xxx_resmgr_cond_entry *e = NULL;
pr_debug("%s: enter\n", __func__);
- WCD9XXX_BCL_LOCK(resmgr);
+ mutex_lock(&resmgr->update_bit_cond_lock);
list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
if (e->reg == reg && e->shift == shift && e->invert == invert) {
@@ -730,12 +730,12 @@
1 << e->shift,
e->invert << e->shift);
list_del(&e->list);
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
kfree(e);
return 0;
}
}
- WCD9XXX_BCL_UNLOCK(resmgr);
+ mutex_unlock(&resmgr->update_bit_cond_lock);
pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
__func__, e ? e->reg : 0, e ? e->shift : 0);
@@ -776,12 +776,14 @@
BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
mutex_init(&resmgr->codec_resource_lock);
+ mutex_init(&resmgr->update_bit_cond_lock);
return 0;
}
void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr)
{
+ mutex_destroy(&resmgr->update_bit_cond_lock);
mutex_destroy(&resmgr->codec_resource_lock);
}
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 8acc816..b5f950c 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -127,6 +127,7 @@
unsigned long cond_flags;
struct list_head update_bit_cond_h;
+ struct mutex update_bit_cond_lock;
/*
* Currently, only used for mbhc purpose, to protect
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 7fd62f1..40661ff 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -190,6 +190,23 @@
the machine drivers and the corresponding
DAI-links.
+config SND_SOC_APQ8074
+ tristate "SoC Machine driver for APQ8O74 boards"
+ depends on ARCH_MSM8974
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_SOC_WCD9320
+ select SND_SOC_MSM_HDMI_CODEC_RX
+ select SND_DYNAMIC_MINORS
+ select AUDIO_OCMEM
+ help
+ To add support for SoC audio on APQ8074.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine drivers and the corresponding
+ DAI-links.
+
config SND_SOC_MSM8226
tristate "SoC Machine driver for MSM8226 boards"
depends on ARCH_MSM8226
diff --git a/sound/soc/msm/Makefile b/sound/soc/msm/Makefile
index 7ab4811..e206812 100644
--- a/sound/soc/msm/Makefile
+++ b/sound/soc/msm/Makefile
@@ -84,6 +84,10 @@
snd-soc-qdsp6v2-objs := msm-dai-fe.o
obj-$(CONFIG_SND_SOC_QDSP6V2) += snd-soc-qdsp6v2.o
+# for APQ 8074 sound card driver
+snd-soc-apq8074-objs := apq8074.o
+obj-$(CONFIG_SND_SOC_APQ8074) += snd-soc-apq8074.o
+
#for MDM9625 sound card driver
snd-soc-mdm9625-objs := mdm9625.o
obj-$(CONFIG_SND_SOC_MDM9625) += snd-soc-mdm9625.o
diff --git a/sound/soc/msm/apq8074.c b/sound/soc/msm/apq8074.c
new file mode 100644
index 0000000..9a2f83b
--- /dev/null
+++ b/sound/soc/msm/apq8074.c
@@ -0,0 +1,2486 @@
+/* Copyright (c) 2012-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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/qpnp/clkdiv.h>
+#include <linux/regulator/consumer.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/jack.h>
+#include <sound/q6afe-v2.h>
+#include <asm/mach-types.h>
+#include <mach/socinfo.h>
+#include <sound/pcm_params.h>
+#include "qdsp6v2/msm-pcm-routing-v2.h"
+#include "../codecs/wcd9320.h"
+#include <linux/io.h>
+
+#define DRV_NAME "apq8074-asoc-taiko"
+
+#define APQ8074_SPK_ON 1
+#define APQ8074_SPK_OFF 0
+
+#define MSM_SLIM_0_RX_MAX_CHANNELS 2
+#define MSM_SLIM_0_TX_MAX_CHANNELS 4
+
+#define BTSCO_RATE_8KHZ 8000
+#define BTSCO_RATE_16KHZ 16000
+
+static int slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+static int hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+
+#define SAMPLING_RATE_48KHZ 48000
+#define SAMPLING_RATE_96KHZ 96000
+#define SAMPLING_RATE_192KHZ 192000
+
+static int apq8074_auxpcm_rate = 8000;
+#define LO_1_SPK_AMP 0x1
+#define LO_3_SPK_AMP 0x2
+#define LO_2_SPK_AMP 0x4
+#define LO_4_SPK_AMP 0x8
+
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
+
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
+#define TAIKO_EXT_CLK_RATE 9600000
+
+/* It takes about 13ms for Class-D PAs to ramp-up */
+#define EXT_CLASS_D_EN_DELAY 13000
+#define EXT_CLASS_D_DIS_DELAY 3000
+#define EXT_CLASS_D_DELAY_DELTA 2000
+
+/* It takes about 13ms for Class-AB PAs to ramp-up */
+#define EXT_CLASS_AB_EN_DELAY 10000
+#define EXT_CLASS_AB_DIS_DELAY 1000
+#define EXT_CLASS_AB_DELAY_DELTA 1000
+
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static inline int param_is_mask(int p)
+{
+ return ((p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) &&
+ (p <= SNDRV_PCM_HW_PARAM_LAST_MASK));
+}
+
+static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n)
+{
+ return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]);
+}
+
+static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned bit)
+{
+ if (bit >= SNDRV_MASK_MAX)
+ return;
+ if (param_is_mask(n)) {
+ struct snd_mask *m = param_to_mask(p, n);
+ m->bits[0] = 0;
+ m->bits[1] = 0;
+ m->bits[bit >> 5] |= (1 << (bit & 31));
+ }
+}
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum apq8074_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
+static void *def_taiko_mbhc_cal(void);
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm);
+
+static struct wcd9xxx_mbhc_config mbhc_cfg = {
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .micbias = MBHC_MICBIAS2,
+ .mclk_cb_fn = msm_snd_enable_codec_ext_clk,
+ .mclk_rate = TAIKO_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 1,
+ .detect_extn_cable = true,
+ .insert_detect = true,
+ .swap_gnd_mic = NULL,
+};
+
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
+struct apq8074_asoc_mach_data {
+ int mclk_gpio;
+ u32 mclk_freq;
+ int us_euro_gpio;
+ struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
+};
+
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_prim_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "qcom,prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "qcom,prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "qcom,prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "qcom,prim-auxpcm-gpio-dout"},
+};
+
+static void *lpaif_pri_muxsel_virt_addr;
+
+struct apq8074_liquid_dock_dev {
+ int dock_plug_gpio;
+ int dock_plug_irq;
+ struct snd_soc_dapm_context *dapm;
+ struct work_struct irq_work;
+};
+
+static struct apq8074_liquid_dock_dev *apq8074_liquid_dock_dev;
+static int dock_plug_det = -1;
+
+/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
+enum {
+ SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
+ SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
+ SLIM_2_RX_1 = 147, /* HDMI RX */
+ SLIM_3_RX_1 = 148, /* In-call recording RX */
+ SLIM_3_RX_2 = 149, /* In-call recording RX */
+ SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
+};
+
+static struct platform_device *spdev;
+static struct regulator *ext_spk_amp_regulator;
+static int ext_spk_amp_gpio = -1;
+static int ext_ult_spk_amp_gpio = -1;
+static int apq8074_spk_control = 1;
+static int apq8074_ext_spk_pamp;
+static int msm_slim_0_rx_ch = 1;
+static int msm_slim_0_tx_ch = 1;
+
+static int msm_btsco_rate = BTSCO_RATE_8KHZ;
+static int msm_btsco_ch = 1;
+static int msm_hdmi_rx_ch = 2;
+static int slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+static int msm_proxy_rx_ch = 2;
+
+static struct mutex cdc_mclk_mutex;
+static struct clk *codec_clk;
+static int clk_users;
+static atomic_t prim_auxpcm_rsc_ref;
+
+static int apq8074_liquid_ext_spk_power_amp_init(void)
+{
+ int ret = 0;
+
+ ext_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-spk-amp-gpio", 0);
+ if (ext_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_spk_amp_gpio, "ext_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext_spk_amp_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_spk_amp_gpio, 0);
+
+ if (ext_spk_amp_regulator == NULL) {
+ ext_spk_amp_regulator = regulator_get(&spdev->dev,
+ "qcom,ext-spk-amp");
+
+ if (IS_ERR(ext_spk_amp_regulator)) {
+ pr_err("%s: Cannot get regulator %s.\n",
+ __func__, "qcom,ext-spk-amp");
+
+ gpio_free(ext_spk_amp_gpio);
+ return PTR_ERR(ext_spk_amp_regulator);
+ }
+ }
+ }
+
+ ext_ult_spk_amp_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,ext-ult-spk-amp-gpio", 0);
+
+ if (ext_ult_spk_amp_gpio >= 0) {
+ ret = gpio_request(ext_ult_spk_amp_gpio,
+ "ext_ult_spk_amp_gpio");
+ if (ret) {
+ pr_err("%s: gpio_request failed for ext-ult_spk-amp-gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ }
+
+ return 0;
+}
+
+static void apq8074_liquid_ext_ult_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_ult_spk_amp_gpio, 1);
+ /* time takes enable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_EN_DELAY,
+ EXT_CLASS_AB_EN_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_ult_spk_amp_gpio, 0);
+ regulator_disable(ext_spk_amp_regulator);
+ /* time takes disable the external power class AB amplifier */
+ usleep_range(EXT_CLASS_AB_DIS_DELAY,
+ EXT_CLASS_AB_DIS_DELAY + EXT_CLASS_AB_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external ultrasound SPKR_DRV PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_ext_spk_power_amp_enable(u32 on)
+{
+ if (on) {
+ regulator_enable(ext_spk_amp_regulator);
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ /*time takes enable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_EN_DELAY,
+ EXT_CLASS_D_EN_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ } else {
+ gpio_direction_output(ext_spk_amp_gpio, on);
+ regulator_disable(ext_spk_amp_regulator);
+ /*time takes disable the external power amplifier*/
+ usleep_range(EXT_CLASS_D_DIS_DELAY,
+ EXT_CLASS_D_DIS_DELAY + EXT_CLASS_D_DELAY_DELTA);
+ }
+
+ pr_debug("%s: %s external speaker PAs.\n", __func__,
+ on ? "Enable" : "Disable");
+}
+
+static void apq8074_liquid_docking_irq_work(struct work_struct *work)
+{
+ struct apq8074_liquid_dock_dev *dock_dev =
+ container_of(work,
+ struct apq8074_liquid_dock_dev,
+ irq_work);
+
+ struct snd_soc_dapm_context *dapm = dock_dev->dapm;
+
+
+ mutex_lock(&dapm->codec->mutex);
+ dock_plug_det =
+ gpio_get_value(dock_dev->dock_plug_gpio);
+
+
+ if (0 == dock_plug_det) {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ } else {
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ }
+
+ mutex_unlock(&dapm->codec->mutex);
+
+}
+
+static irqreturn_t apq8074_liquid_docking_irq_handler(int irq, void *dev)
+{
+ struct apq8074_liquid_dock_dev *dock_dev = dev;
+
+ /* switch speakers should not run in interrupt context */
+ schedule_work(&dock_dev->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static int apq8074_liquid_init_docking(struct snd_soc_dapm_context *dapm)
+{
+ int ret = 0;
+ int dock_plug_gpio = 0;
+
+ /* plug in docking speaker+plug in device OR unplug one of them */
+ u32 dock_plug_irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ dock_plug_det = 0;
+ dock_plug_gpio = of_get_named_gpio(spdev->dev.of_node,
+ "qcom,dock-plug-det-irq", 0);
+
+ if (dock_plug_gpio >= 0) {
+
+ apq8074_liquid_dock_dev =
+ kzalloc(sizeof(*apq8074_liquid_dock_dev), GFP_KERNEL);
+
+ if (!apq8074_liquid_dock_dev) {
+ pr_err("apq8074_liquid_dock_dev alloc fail.\n");
+ return -ENOMEM;
+ }
+
+ apq8074_liquid_dock_dev->dock_plug_gpio = dock_plug_gpio;
+
+ ret = gpio_request(apq8074_liquid_dock_dev->dock_plug_gpio,
+ "dock-plug-det-irq");
+ if (ret) {
+ pr_err("%s:failed request apq8074_liquid_dock_plug_gpio.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ dock_plug_det =
+ gpio_get_value(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dock_plug_irq =
+ gpio_to_irq(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ apq8074_liquid_dock_dev->dapm = dapm;
+
+ ret = request_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_docking_irq_handler,
+ dock_plug_irq_flags,
+ "liquid_dock_plug_irq",
+ apq8074_liquid_dock_dev);
+
+ INIT_WORK(
+ &apq8074_liquid_dock_dev->irq_work,
+ apq8074_liquid_docking_irq_work);
+ }
+
+ return 0;
+}
+
+static int apq8074_liquid_ext_spk_power_amp_on(u32 spk)
+{
+ int rc;
+
+ if (spk & (LO_1_SPK_AMP | LO_3_SPK_AMP | LO_2_SPK_AMP | LO_4_SPK_AMP)) {
+ pr_debug("%s: External speakers are already on. spk = 0x%x\n",
+ __func__, spk);
+
+ apq8074_ext_spk_pamp |= spk;
+ if ((apq8074_ext_spk_pamp & LO_1_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_3_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_2_SPK_AMP) &&
+ (apq8074_ext_spk_pamp & LO_4_SPK_AMP))
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(1);
+ rc = 0;
+ } else {
+ pr_err("%s: Invalid external speaker ampl. spk = 0x%x\n",
+ __func__, spk);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+
+static void apq8074_ext_spk_power_amp_on(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_on(spk);
+}
+
+static void apq8074_liquid_ext_spk_power_amp_off(u32 spk)
+{
+
+ if (spk & (LO_1_SPK_AMP |
+ LO_3_SPK_AMP |
+ LO_2_SPK_AMP |
+ LO_4_SPK_AMP)) {
+
+ pr_debug("%s Left and right speakers case spk = 0x%08x",
+ __func__, spk);
+
+ if (!apq8074_ext_spk_pamp) {
+ if (ext_spk_amp_gpio >= 0 &&
+ dock_plug_det == 0)
+ apq8074_liquid_ext_spk_power_amp_enable(0);
+ apq8074_ext_spk_pamp = 0;
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void apq8074_ext_spk_power_amp_off(u32 spk)
+{
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ apq8074_liquid_ext_spk_power_amp_off(spk);
+}
+
+static void apq8074_ext_control(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ mutex_lock(&dapm->codec->mutex);
+
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ if (apq8074_spk_control == APQ8074_SPK_ON) {
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+ } else {
+ snd_soc_dapm_disable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_disable_pin(dapm, "Lineout_4 amp");
+ }
+
+ snd_soc_dapm_sync(dapm);
+ mutex_unlock(&dapm->codec->mutex);
+}
+
+static int apq8074_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: apq8074_spk_control = %d", __func__, apq8074_spk_control);
+ ucontrol->value.integer.value[0] = apq8074_spk_control;
+ return 0;
+}
+
+static int apq8074_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s()\n", __func__);
+ if (apq8074_spk_control == ucontrol->value.integer.value[0])
+ return 0;
+
+ apq8074_spk_control = ucontrol->value.integer.value[0];
+ apq8074_ext_control(codec);
+ return 1;
+}
+
+
+static int msm_ext_spkramp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ pr_debug("%s()\n", __func__);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_on(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Lineout_1 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_1_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_3 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_3_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_2 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_2_SPK_AMP);
+ else if (!strncmp(w->name, "Lineout_4 amp", 14))
+ apq8074_ext_spk_power_amp_off(LO_4_SPK_AMP);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+
+}
+
+static int msm_ext_spkramp_ultrasound_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+
+ pr_debug("%s()\n", __func__);
+
+ if (!strncmp(w->name, "SPK_ultrasound amp", 19)) {
+ if (!gpio_is_valid(ext_ult_spk_amp_gpio)) {
+ pr_err("%s: ext_ult_spk_amp_gpio isn't configured\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ apq8074_liquid_ext_ult_spk_power_amp_enable(1);
+ else
+ apq8074_liquid_ext_ult_spk_power_amp_enable(0);
+
+ } else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
+ bool dapm)
+{
+ int ret = 0;
+ pr_debug("%s: enable = %d clk_users = %d\n",
+ __func__, enable, clk_users);
+
+ mutex_lock(&cdc_mclk_mutex);
+ if (enable) {
+ if (!codec_clk) {
+ dev_err(codec->dev, "%s: did not get Taiko MCLK\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ clk_users++;
+ if (clk_users != 1)
+ goto exit;
+
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TAIKO_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ taiko_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Taiko MCLK\n", __func__);
+ clk_users--;
+ goto exit;
+ }
+ } else {
+ if (clk_users > 0) {
+ clk_users--;
+ if (clk_users == 0) {
+ taiko_mclk_enable(codec, 0, dapm);
+ clk_disable_unprepare(codec_clk);
+ }
+ } else {
+ pr_err("%s: Error releasing Taiko MCLK\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+exit:
+ mutex_unlock(&cdc_mclk_mutex);
+ return ret;
+}
+
+static int apq8074_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return msm_snd_enable_codec_ext_clk(w->codec, 1, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return msm_snd_enable_codec_ext_clk(w->codec, 0, true);
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget apq8074_dapm_widgets[] = {
+
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ apq8074_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_SPK("Lineout_1 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_3 amp", msm_ext_spkramp_event),
+
+ SND_SOC_DAPM_SPK("Lineout_2 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("Lineout_4 amp", msm_ext_spkramp_event),
+ SND_SOC_DAPM_SPK("SPK_ultrasound amp",
+ msm_ext_spkramp_ultrasound_event),
+
+ SND_SOC_DAPM_MIC("Handset Mic", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic4", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic6", NULL),
+ SND_SOC_DAPM_MIC("Analog Mic7", NULL),
+
+ SND_SOC_DAPM_MIC("Digital Mic1", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic2", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic3", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic4", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic5", NULL),
+ SND_SOC_DAPM_MIC("Digital Mic6", NULL),
+};
+
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
+static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+static const char *const proxy_rx_ch_text[] = {"One", "Two", "Three", "Four",
+ "Five", "Six", "Seven", "Eight"};
+
+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 slim0_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (slim0_rx_sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ slim0_rx_sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ slim0_rx_sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ slim0_rx_sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: slim0_rx_sample_rate = %d\n", __func__,
+ slim0_rx_sample_rate);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (slim0_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: slim0_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, slim0_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ slim0_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
+ msm_slim_0_rx_ch);
+ return 1;
+}
+
+static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
+ msm_slim_0_tx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__, msm_slim_0_tx_ch);
+ return 1;
+}
+
+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 0:
+ msm_btsco_rate = BTSCO_RATE_8KHZ;
+ break;
+ case 1:
+ 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 hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+ msm_hdmi_rx_ch);
+ ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+
+ return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+ if (msm_hdmi_rx_ch > 8) {
+ pr_err("%s: channels exceeded 8.Limiting to max channels-8\n",
+ __func__);
+ msm_hdmi_rx_ch = 8;
+ }
+ pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__, msm_hdmi_rx_ch);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
+};
+
+static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = msm_btsco_rate;
+ channels->min = channels->max = msm_btsco_ch;
+
+ return 0;
+}
+
+static int apq8074_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = apq8074_auxpcm_rate;
+ return 0;
+}
+
+static int apq8074_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ case 1:
+ apq8074_auxpcm_rate = 16000;
+ break;
+ default:
+ apq8074_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+static int msm_proxy_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ ucontrol->value.integer.value[0] = msm_proxy_rx_ch - 1;
+ return 0;
+}
+
+static int msm_proxy_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_proxy_rx_ch = ucontrol->value.integer.value[0] + 1;
+ pr_debug("%s: msm_proxy_rx_ch = %d\n", __func__,
+ msm_proxy_rx_ch);
+ return 1;
+}
+
+static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ rate->min = rate->max = apq8074_auxpcm_rate;
+ channels->min = channels->max = 1;
+
+ return 0;
+}
+
+static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s: msm_proxy_rx_ch =%d\n", __func__, msm_proxy_rx_ch);
+
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ channels->min = channels->max = msm_proxy_rx_ch;
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int msm_proxy_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ rate->min = rate->max = 48000;
+ return 0;
+}
+
+static int apq8074_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+ channels->min, channels->max);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_bit_format);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_hdmi_rx_ch;
+
+ return 0;
+}
+
+static int msm_aux_pcm_get_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+ int j;
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int msm_aux_pcm_free_gpios(struct msm_auxpcm_ctrl *auxpcm_ctrl)
+{
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int i;
+ int ret = 0;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
+}
+
+static int msm_prim_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (atomic_inc_return(&prim_auxpcm_rsc_ref) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = msm_aux_pcm_get_gpios(auxpcm_ctrl);
+ }
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
+err:
+ return ret;
+}
+
+static void msm_prim_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+
+ pr_debug("%s(): substream = %s, prim_auxpcm_rsc_ref counter = %d\n",
+ __func__, substream->name, atomic_read(&prim_auxpcm_rsc_ref));
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (atomic_dec_return(&prim_auxpcm_rsc_ref) == 0)
+ msm_aux_pcm_free_gpios(auxpcm_ctrl);
+}
+static struct snd_soc_ops msm_auxpcm_be_ops = {
+ .startup = msm_prim_auxpcm_startup,
+ .shutdown = msm_prim_auxpcm_shutdown,
+};
+
+static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ slim0_rx_bit_format);
+ rate->min = rate->max = slim0_rx_sample_rate;
+ channels->min = channels->max = msm_slim_0_rx_ch;
+
+ pr_debug("%s: format = %d, rate = %d, channels = %d\n",
+ __func__, params_format(params), params_rate(params),
+ msm_slim_0_rx_ch);
+
+ return 0;
+}
+
+static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_slim_0_tx_ch;
+
+ return 0;
+}
+
+static int msm_slim_5_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ int rc;
+ void *config;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s enter\n", __func__);
+ rate->min = rate->max = 16000;
+ channels->min = channels->max = 1;
+
+ config = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_PORT_CONFIG);
+ rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, config,
+ SLIMBUS_5_TX);
+ if (rc) {
+ pr_err("%s: Failed to set slimbus slave port config %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+
+ return 0;
+}
+
+static const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(5, slim0_tx_ch_text),
+ SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text),
+ SOC_ENUM_SINGLE_EXT(3, slim0_rx_sample_rate_text),
+ SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text),
+};
+
+static const struct snd_kcontrol_new msm_snd_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], apq8074_get_spk,
+ apq8074_set_spk),
+ SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", apq8074_auxpcm_enum[0],
+ apq8074_auxpcm_rate_get, apq8074_auxpcm_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", msm_snd_enum[3],
+ msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+ SOC_ENUM_EXT("SLIM_0_RX Format", msm_snd_enum[4],
+ slim0_rx_bit_format_get, slim0_rx_bit_format_put),
+ SOC_ENUM_EXT("SLIM_0_RX SampleRate", msm_snd_enum[5],
+ slim0_rx_sample_rate_get, slim0_rx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", msm_snd_enum[4],
+ hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
+ SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
+ msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+};
+
+static bool apq8074_swap_gnd_mic(struct snd_soc_codec *codec)
+{
+ struct snd_soc_card *card = codec->card;
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int value = gpio_get_value_cansleep(pdata->us_euro_gpio);
+ pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
+ gpio_set_value_cansleep(pdata->us_euro_gpio, !value);
+ return true;
+}
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err;
+ void *config_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Taiko SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[TAIKO_RX_MAX] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[TAIKO_TX_MAX] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+
+ pr_info("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
+
+ rtd->pmdown_time = 0;
+
+ err = snd_soc_add_codec_controls(codec, msm_snd_controls,
+ ARRAY_SIZE(msm_snd_controls));
+ if (err < 0)
+ return err;
+
+ err = apq8074_liquid_ext_spk_power_amp_init();
+ if (err) {
+ pr_err("%s: LiQUID 8974 CLASS_D PAs init failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ err = apq8074_liquid_init_docking(dapm);
+ if (err) {
+ pr_err("%s: LiQUID 8974 init Docking stat IRQ failed (%d)\n",
+ __func__, err);
+ return err;
+ }
+
+ snd_soc_dapm_new_controls(dapm, apq8074_dapm_widgets,
+ ARRAY_SIZE(apq8074_dapm_widgets));
+
+ snd_soc_dapm_enable_pin(dapm, "Lineout_1 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_3 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_2 amp");
+ snd_soc_dapm_enable_pin(dapm, "Lineout_4 amp");
+
+
+ snd_soc_dapm_sync(dapm);
+
+ codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+
+ config_data = taiko_get_afe_config(codec, AFE_CDC_REGISTERS_CONFIG);
+ err = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set codec registers config %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_SLIMBUS_SLAVE_CONFIG);
+ err = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set slimbus slave config %d\n", __func__,
+ err);
+ goto out;
+ }
+
+ config_data = taiko_get_afe_config(codec, AFE_AANC_VERSION);
+ err = afe_set_config(AFE_AANC_VERSION, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set aanc version %d\n",
+ __func__, err);
+ goto out;
+ }
+ config_data = taiko_get_afe_config(codec,
+ AFE_CDC_CLIP_REGISTERS_CONFIG);
+ if (config_data) {
+ err = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG,
+ config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set clip registers %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ config_data = taiko_get_afe_config(codec, AFE_CLIP_BANK_SEL);
+ if (config_data) {
+ err = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0);
+ if (err) {
+ pr_err("%s: Failed to set AFE bank selection %d\n",
+ __func__, err);
+ return err;
+ }
+ }
+ /* start mbhc */
+ mbhc_cfg.calibration = def_taiko_mbhc_cal();
+ if (mbhc_cfg.calibration) {
+ err = taiko_hs_detect(codec, &mbhc_cfg);
+ if (err)
+ goto out;
+ else
+ return err;
+ } else {
+ err = -ENOMEM;
+ goto out;
+ }
+out:
+ clk_put(codec_clk);
+ return err;
+}
+
+static int apq8074_snd_startup(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+ return 0;
+}
+
+static void *def_taiko_mbhc_cal(void)
+{
+ void *taiko_cal;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ taiko_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(WCD9XXX_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!taiko_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(taiko_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 4);
+ S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(taiko_cal)->X) = (Y))
+ S(mic_current, TAIKO_PID_MIC_5_UA);
+ S(hph_current, TAIKO_PID_MIC_5_UA);
+ S(t_mic_pid, 100);
+ S(t_ins_complete, 250);
+ S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(taiko_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 2400);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal)->X) = (Y))
+ S(c[0], 62);
+ S(c[1], 124);
+ S(nc, 1);
+ S(n_meas, 3);
+ S(mbhc_nsc, 11);
+ S(n_btn_meas, 1);
+ S(n_btn_con, 2);
+ S(num_btn, WCD9XXX_MBHC_DEF_BUTTONS);
+ S(v_btn_press_delta_sta, 100);
+ S(v_btn_press_delta_cic, 50);
+#undef S
+ btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(taiko_cal);
+ btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_V_BTN_LOW);
+ btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg,
+ MBHC_BTN_DET_V_BTN_HIGH);
+ btn_low[0] = -50;
+ btn_high[0] = 20;
+ btn_low[1] = 21;
+ btn_high[1] = 61;
+ btn_low[2] = 62;
+ btn_high[2] = 104;
+ btn_low[3] = 105;
+ btn_high[3] = 148;
+ btn_low[4] = 149;
+ btn_high[4] = 189;
+ btn_low[5] = 190;
+ btn_high[5] = 228;
+ btn_low[6] = 229;
+ btn_high[6] = 269;
+ btn_low[7] = 270;
+ btn_high[7] = 500;
+ n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_READY);
+ n_ready[0] = 80;
+ n_ready[1] = 68;
+ n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_N_CIC);
+ n_cic[0] = 60;
+ n_cic[1] = 47;
+ gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_cfg, MBHC_BTN_DET_GAIN);
+ gain[0] = 11;
+ gain[1] = 9;
+
+ return taiko_cal;
+}
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int user_set_tx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: rx_0_ch=%d\n", __func__, msm_slim_0_rx_ch);
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ } else {
+
+ pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
+ codec_dai->name, codec_dai->id, user_set_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ /* For tabla_tx1 case */
+ if (codec_dai->id == 1)
+ user_set_tx_ch = msm_slim_0_tx_ch;
+ /* For tabla_tx2 case */
+ else if (codec_dai->id == 3)
+ user_set_tx_ch = params_channels(params);
+ else
+ user_set_tx_ch = tx_ch_cnt;
+
+ pr_debug("%s: msm_slim_0_tx_ch(%d)user_set_tx_ch(%d)tx_ch_cnt(%d)\n",
+ __func__, msm_slim_0_tx_ch, user_set_tx_ch, tx_ch_cnt);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ user_set_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static void apq8074_snd_shudown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+}
+
+static struct snd_soc_ops apq8074_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = msm_snd_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+
+
+static int apq8074_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ num_rx_ch = params_channels(params);
+
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ } else {
+
+ num_tx_ch = params_channels(params);
+
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+
+static struct snd_soc_ops apq8074_slimbus_2_be_ops = {
+ .startup = apq8074_snd_startup,
+ .hw_params = apq8074_slimbus_2_hw_params,
+ .shutdown = apq8074_snd_shudown,
+};
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link apq8074_common_dai_links[] = {
+ /* FrontEnd DAI Links */
+ {
+ .name = "MSM8974 Media1",
+ .stream_name = "MultiMedia1",
+ .cpu_dai_name = "MultiMedia1",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
+ },
+ {
+ .name = "MSM8974 Media2",
+ .stream_name = "MultiMedia2",
+ .cpu_dai_name = "MultiMedia2",
+ .platform_name = "msm-pcm-dsp.0",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
+ },
+ {
+ .name = "Circuit-Switch Voice",
+ .stream_name = "CS-Voice",
+ .cpu_dai_name = "CS-VOICE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .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,
+ .be_id = MSM_FRONTEND_DAI_CS_VOICE,
+ },
+ {
+ .name = "MSM VoIP",
+ .stream_name = "VoIP",
+ .cpu_dai_name = "VoIP",
+ .platform_name = "msm-voip-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_VOIP,
+ },
+ {
+ .name = "MSM8974 LPA",
+ .stream_name = "LPA",
+ .cpu_dai_name = "MultiMedia3",
+ .platform_name = "msm-pcm-lpa",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
+ },
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "INT_FM Hostless",
+ .stream_name = "INT_FM Hostless",
+ .cpu_dai_name = "INT_FM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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",
+ },
+ {
+ .name = "MSM AFE-PCM RX",
+ .stream_name = "AFE-PROXY RX",
+ .cpu_dai_name = "msm-dai-q6-dev.241",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ },
+ {
+ .name = "MSM AFE-PCM TX",
+ .stream_name = "AFE-PROXY TX",
+ .cpu_dai_name = "msm-dai-q6-dev.240",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .platform_name = "msm-pcm-afe",
+ .ignore_suspend = 1,
+ },
+ {
+ .name = "MSM8974 Compr",
+ .stream_name = "COMPR",
+ .cpu_dai_name = "MultiMedia4",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
+ },
+ {
+ .name = "AUXPCM Hostless",
+ .stream_name = "AUXPCM Hostless",
+ .cpu_dai_name = "AUXPCM_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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",
+ },
+ {
+ .name = "SLIMBUS_1 Hostless",
+ .stream_name = "SLIMBUS_1 Hostless",
+ .cpu_dai_name = "SLIMBUS1_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_3 Hostless",
+ .stream_name = "SLIMBUS_3 Hostless",
+ .cpu_dai_name = "SLIMBUS3_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .name = "SLIMBUS_4 Hostless",
+ .stream_name = "SLIMBUS_4 Hostless",
+ .cpu_dai_name = "SLIMBUS4_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ {
+ .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,
+ },
+ {
+ .name = "MSM8974 LowLatency",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-pcm-dsp.1",
+ .dynamic = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5,
+ },
+ /* LSM FE */
+ {
+ .name = "Listen Audio Service",
+ .stream_name = "Listen Audio Service",
+ .cpu_dai_name = "LSM",
+ .platform_name = "msm-lsm-client",
+ .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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_LSM1,
+ },
+ /* Backend BT/FM DAI Links */
+ {
+ .name = LPASS_BE_INT_BT_SCO_RX,
+ .stream_name = "Internal BT-SCO Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12288",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_BT_SCO_TX,
+ .stream_name = "Internal BT-SCO Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12289",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
+ .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_RX,
+ .stream_name = "Internal FM Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.12292",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_INT_FM_TX,
+ .stream_name = "Internal FM Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.12293",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INT_FM_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Backend AFE DAI Links */
+ {
+ .name = LPASS_BE_AFE_PCM_RX,
+ .stream_name = "AFE Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.224",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
+ .be_hw_params_fixup = msm_proxy_rx_be_hw_params_fixup,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_AFE_PCM_TX,
+ .stream_name = "AFE Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.225",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
+ .be_hw_params_fixup = msm_proxy_tx_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* HDMI Hostless */
+ {
+ .name = "HDMI_RX_HOSTLESS",
+ .stream_name = "HDMI_RX_HOSTLESS",
+ .cpu_dai_name = "HDMI_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .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,
+ .ignore_pmdown_time = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
+ /* AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_AUXPCM_RX,
+ .stream_name = "AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.4106",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ },
+ {
+ .name = LPASS_BE_AUXPCM_TX,
+ .stream_name = "AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.4107",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
+ .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
+ .ops = &msm_auxpcm_be_ops,
+ .ignore_suspend = 1,
+ },
+ /* Backend DAI Links */
+ {
+ .name = LPASS_BE_SLIMBUS_0_RX,
+ .stream_name = "Slimbus Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16384",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ .init = &msm_audrx_init,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_pmdown_time = 1, /* dai link has playback support */
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_0_TX,
+ .stream_name = "Slimbus Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16385",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_RX,
+ .stream_name = "Slimbus1 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16386",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_1_TX,
+ .stream_name = "Slimbus1 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16387",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_RX,
+ .stream_name = "Slimbus4 Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16392",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX,
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ /* dai link has playback support */
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+ {
+ .name = LPASS_BE_SLIMBUS_4_TX,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* MAD BE */
+ {
+ .name = LPASS_BE_SLIMBUS_5_TX,
+ .stream_name = "Slimbus5 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16395",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_mad1",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_5_TX,
+ .be_hw_params_fixup = msm_slim_5_tx_be_hw_params_fixup,
+ .ops = &apq8074_be_ops,
+ },
+ /* Incall Music BACK END DAI Link */
+ {
+ .name = LPASS_BE_VOICE_PLAYBACK_TX,
+ .stream_name = "Voice Farend Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.32773",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_suspend = 1,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6-dev.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_rx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_be_ops,
+ },
+ /* Ultrasound TX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16389",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "taiko_codec",
+ .codec_dai_name = "taiko_tx2",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &apq8074_slimbus_2_be_ops,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_hdmi_dai_link[] = {
+/* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-hdmi-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = apq8074_hdmi_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
+static struct snd_soc_dai_link apq8074_dai_links[
+ ARRAY_SIZE(apq8074_common_dai_links) +
+ ARRAY_SIZE(apq8074_hdmi_dai_link)];
+
+struct snd_soc_card snd_soc_card_apq8074 = {
+ .name = "apq8074-taiko-snd-card",
+};
+
+static int apq8074_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm_auxpcm_ctrl **auxpcm_ctrl,
+ char *msm_auxpcm_gpio_name[][2])
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int auxpcm_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[auxpcm_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ auxpcm_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = auxpcm_cnt;
+ *auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
+static int apq8074_prepare_codec_mclk(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->mclk_gpio) {
+ ret = gpio_request(pdata->mclk_gpio, "TAIKO_CODEC_PMIC_MCLK");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko mclk gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int apq8074_prepare_us_euro(struct snd_soc_card *card)
+{
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ int ret;
+ if (pdata->us_euro_gpio) {
+ dev_dbg(card->dev, "%s : us_euro gpio request %d", __func__,
+ pdata->us_euro_gpio);
+ ret = gpio_request(pdata->us_euro_gpio, "TAIKO_CODEC_US_EURO");
+ if (ret) {
+ dev_err(card->dev,
+ "%s: Failed to request taiko US/EURO gpio %d error %d\n",
+ __func__, pdata->us_euro_gpio, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static __devinit int apq8074_asoc_machine_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_card_apq8074;
+ struct apq8074_asoc_mach_data *pdata;
+ int ret;
+ const char *auxpcm_pri_gpio_set = NULL;
+
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "No platform supplied from device tree\n");
+ return -EINVAL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct apq8074_asoc_mach_data), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Can't allocate apq8074_asoc_mach_data\n");
+ return -ENOMEM;
+ }
+
+ /* Parse AUXPCM info from DT */
+ ret = apq8074_dtparse_auxpcm(pdev, &pdata->pri_auxpcm_ctrl,
+ msm_prim_auxpcm_gpio_name);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, pdata);
+
+ ret = snd_soc_of_parse_card_name(card, "qcom,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card,
+ "qcom,audio-routing");
+ if (ret)
+ goto err;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "qcom,taiko-mclk-clk-freq", &pdata->mclk_freq);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,taiko-mclk-clk-freq",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+
+ if (pdata->mclk_freq != 9600000) {
+ dev_err(&pdev->dev, "unsupported taiko mclk freq %u\n",
+ pdata->mclk_freq);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pdata->mclk_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,cdc-mclk-gpios", 0);
+ if (pdata->mclk_gpio < 0) {
+ dev_err(&pdev->dev,
+ "Looking up %s property in node %s failed %d\n",
+ "qcom, cdc-mclk-gpios", pdev->dev.of_node->full_name,
+ pdata->mclk_gpio);
+ ret = -ENODEV;
+ goto err;
+ }
+
+
+ ret = apq8074_prepare_codec_mclk(card);
+ if (ret)
+ goto err;
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,hdmi-audio-rx")) {
+ dev_info(&pdev->dev, "%s(): hdmi audio support present\n",
+ __func__);
+
+ memcpy(apq8074_dai_links, apq8074_common_dai_links,
+ sizeof(apq8074_common_dai_links));
+
+ memcpy(apq8074_dai_links + ARRAY_SIZE(apq8074_common_dai_links),
+ apq8074_hdmi_dai_link, sizeof(apq8074_hdmi_dai_link));
+
+ card->dai_link = apq8074_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_dai_links);
+ } else {
+ dev_info(&pdev->dev, "%s(): No hdmi audio support\n", __func__);
+
+ card->dai_link = apq8074_common_dai_links;
+ card->num_links = ARRAY_SIZE(apq8074_common_dai_links);
+ }
+
+ pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
+ "qcom,us-euro-gpios", 0);
+ if (pdata->us_euro_gpio < 0) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,us-euro-gpios",
+ pdev->dev.of_node->full_name);
+ } else {
+ dev_dbg(&pdev->dev, "%s detected %d",
+ "qcom,us-euro-gpios", pdata->us_euro_gpio);
+ mbhc_cfg.swap_gnd_mic = apq8074_swap_gnd_mic;
+ }
+
+ ret = apq8074_prepare_us_euro(card);
+ if (ret)
+ dev_err(&pdev->dev, "apq8074_prepare_us_euro failed (%d)\n",
+ ret);
+
+ mutex_init(&cdc_mclk_mutex);
+ atomic_set(&prim_auxpcm_rsc_ref, 0);
+ spdev = pdev;
+ ext_spk_amp_regulator = NULL;
+ apq8074_liquid_dock_dev = NULL;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err;
+ }
+
+ ret = of_property_read_string(pdev->dev.of_node,
+ "qcom,prim-auxpcm-gpio-set", &auxpcm_pri_gpio_set);
+ if (ret) {
+ dev_err(&pdev->dev, "Looking up %s property in node %s failed",
+ "qcom,prim-auxpcm-gpio-set",
+ pdev->dev.of_node->full_name);
+ goto err;
+ }
+ if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-prim")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ } else if (!strcmp(auxpcm_pri_gpio_set, "prim-gpio-tert")) {
+ lpaif_pri_muxsel_virt_addr =
+ ioremap(LPAIF_TER_MODE_MUXSEL, 4);
+ } else {
+ dev_err(&pdev->dev, "Invalid value %s for AUXPCM GPIO set\n",
+ auxpcm_pri_gpio_set);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ return 0;
+
+err:
+ if (pdata->mclk_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free gpio %d\n",
+ __func__, pdata->mclk_gpio);
+ gpio_free(pdata->mclk_gpio);
+ pdata->mclk_gpio = 0;
+ }
+ if (pdata->us_euro_gpio > 0) {
+ dev_dbg(&pdev->dev, "%s free us_euro gpio %d\n",
+ __func__, pdata->us_euro_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ pdata->us_euro_gpio = 0;
+ }
+ devm_kfree(&pdev->dev, pdata);
+ return ret;
+}
+
+static int __devexit apq8074_asoc_machine_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct apq8074_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+ if (ext_spk_amp_regulator)
+ regulator_put(ext_spk_amp_regulator);
+
+ if (gpio_is_valid(ext_ult_spk_amp_gpio))
+ gpio_free(ext_ult_spk_amp_gpio);
+
+ gpio_free(pdata->mclk_gpio);
+ gpio_free(pdata->us_euro_gpio);
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ gpio_free(ext_spk_amp_gpio);
+
+ if (apq8074_liquid_dock_dev != NULL) {
+ if (apq8074_liquid_dock_dev->dock_plug_gpio)
+ gpio_free(apq8074_liquid_dock_dev->dock_plug_gpio);
+
+ if (apq8074_liquid_dock_dev->dock_plug_irq)
+ free_irq(apq8074_liquid_dock_dev->dock_plug_irq,
+ apq8074_liquid_dock_dev);
+
+ kfree(apq8074_liquid_dock_dev);
+ apq8074_liquid_dock_dev = NULL;
+ }
+
+ iounmap(lpaif_pri_muxsel_virt_addr);
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static const struct of_device_id apq8074_asoc_machine_of_match[] = {
+ { .compatible = "qcom,apq8074-audio-taiko", },
+ {},
+};
+
+static struct platform_driver apq8074_asoc_machine_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = apq8074_asoc_machine_of_match,
+ },
+ .probe = apq8074_asoc_machine_probe,
+ .remove = __devexit_p(apq8074_asoc_machine_remove),
+};
+module_platform_driver(apq8074_asoc_machine_driver);
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, apq8074_asoc_machine_of_match);
diff --git a/sound/soc/msm/msm8226.c b/sound/soc/msm/msm8226.c
index 86e3d75..da3a8e0 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -72,6 +72,7 @@
.gpio_irq = 0,
.gpio_level_insert = 0,
.detect_extn_cable = true,
+ .micbias_enable_flags = 0,
.insert_detect = true,
.swap_gnd_mic = NULL,
};
@@ -638,7 +639,7 @@
#undef S
#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(tapan_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1650);
+ S(v_hs_max, 2450);
#undef S
#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(tapan_cal)->X) = (Y))
S(c[0], 62);
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index ae92ca4..5d9aa53 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -124,6 +124,7 @@
.gpio_irq = 0,
.gpio_level_insert = 1,
.detect_extn_cable = true,
+ .micbias_enable_flags = 1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET,
.insert_detect = true,
.swap_gnd_mic = NULL,
};
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index 6bccdb7..a1c1aef 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -1059,7 +1059,7 @@
}
rc = wait_event_timeout(the_locks.flush_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("Flush cmd timeout\n");
prtd->pcm_irq_pos = 0;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
index a078042..4297ddb 100644
--- a/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-multi-ch-pcm-q6-v2.c
@@ -454,7 +454,7 @@
__func__, atomic_read(&prtd->out_count));
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
@@ -507,7 +507,7 @@
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
+ if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -546,7 +546,7 @@
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index 9899f97..4459bc8 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -364,7 +364,7 @@
pr_debug("%s\n", __func__);
rc = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("EOS cmd timeout\n");
prtd->pcm_irq_pos = 0;
}
@@ -573,7 +573,7 @@
pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
rc = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (rc < 0)
+ if (!rc)
pr_err("Flush cmd timeout\n");
prtd->pcm_irq_pos = 0;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 0592d10..0ae393c 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -410,7 +410,7 @@
__func__, atomic_read(&prtd->out_count));
ret = wait_event_timeout(the_locks.write_wait,
(atomic_read(&prtd->out_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
@@ -470,7 +470,7 @@
dir = IN;
ret = wait_event_timeout(the_locks.eos_wait,
prtd->cmd_ack, 5 * HZ);
- if (ret < 0)
+ if (!ret)
pr_err("%s: CMD_EOS failed\n", __func__);
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@@ -509,7 +509,7 @@
ret = wait_event_timeout(the_locks.read_wait,
(atomic_read(&prtd->in_count)), 5 * HZ);
- if (ret < 0) {
+ if (!ret) {
pr_debug("%s: wait_event_timeout failed\n", __func__);
goto fail;
}
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 6615940..7de058d 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -2539,7 +2539,7 @@
ret = wait_event_timeout(this_afe.wait[index],
(atomic_read(&this_afe.state) == 0),
msecs_to_jiffies(TIMEOUT_MS));
- if (ret < 0) {
+ if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
goto fail_cmd;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 26d9d48..8888e41 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -56,7 +56,7 @@
static int voice_send_disable_vocproc_cmd(struct voice_data *v);
static int voice_send_vol_index_cmd(struct voice_data *v);
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt);
+ uint32_t mem_handle);
static int voice_send_mvm_cal_network_cmd(struct voice_data *v);
static int voice_send_mvm_media_type_cmd(struct voice_data *v);
static int voice_send_cvs_data_exchange_mode_cmd(struct voice_data *v);
@@ -227,6 +227,29 @@
return (session_id == common.voice[VOC_PATH_VOICE2_PASSIVE].session_id);
}
+static bool is_other_session_active(u16 session_id)
+{
+ int i;
+ bool ret = false;
+
+ /* Check if there is other active session except the input one */
+ for (i = 0; i < MAX_VOC_SESSIONS; i++) {
+ if (common.voice[i].session_id == session_id)
+ continue;
+
+ if ((common.voice[i].voc_state == VOC_RUN) ||
+ (common.voice[i].voc_state == VOC_CHANGE) ||
+ (common.voice[i].voc_state == VOC_STANDBY)) {
+ ret = true;
+ break;
+ }
+ }
+ pr_debug("%s: ret %d\n", __func__, ret);
+
+ return ret;
+
+}
+
static int voice_apr_register(void)
{
void *modem_mvm, *modem_cvs, *modem_cvp;
@@ -676,7 +699,7 @@
cvs_handle = voice_get_cvs_handle(v);
/* MVM, CVS sessions are destroyed only for Full control sessions. */
- if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
+ if (is_voip_session(v->session_id)) {
pr_debug("%s: MVM detach stream, VOC_STATE: %d\n", __func__,
v->voc_state);
@@ -698,6 +721,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending DETACH_STREAM\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->mvm_wait,
@@ -705,9 +729,25 @@
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait event timeout\n", __func__);
+
goto fail;
}
+ /* Unmap memory */
+ if (v->shmem_info.mem_handle != 0) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ v->shmem_info.mem_handle);
+ if (ret < 0) {
+ pr_err("%s Memory_unmap for voip failed %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ v->shmem_info.mem_handle = 0;
+ }
+ }
+
+ if (is_voip_session(v->session_id) || v->voc_state == VOC_ERROR) {
/* Destroy CVS. */
pr_debug("%s: CVS destroy session\n", __func__);
@@ -726,6 +766,7 @@
if (ret < 0) {
pr_err("%s: Error %d sending CVS DESTROY\n",
__func__, ret);
+
goto fail;
}
ret = wait_event_timeout(v->cvs_wait,
@@ -739,11 +780,21 @@
cvs_handle = 0;
voice_set_cvs_handle(v, cvs_handle);
- ret = voice_send_mvm_unmap_memory_physical_cmd(v,
- NUM_OF_BUFFERS);
- if (ret < 0) {
- pr_err("%s CMD Memory_unmap_regions failed %d\n",
- __func__, ret);
+ /* Unmap physical memory for calibration */
+ pr_debug("%s: cal_mem_handle %d\n", __func__,
+ common.cal_mem_handle);
+
+ if (!is_other_session_active(v->session_id) &&
+ (common.cal_mem_handle != 0)) {
+ ret = voice_send_mvm_unmap_memory_physical_cmd(v,
+ common.cal_mem_handle);
+ if (ret < 0) {
+ pr_err("%s Fail at cal mem unmap %d\n",
+ __func__, ret);
+
+ goto fail;
+ }
+ common.cal_mem_handle = 0;
}
/* Destroy MVM. */
@@ -2673,7 +2724,7 @@
}
static int voice_send_mvm_unmap_memory_physical_cmd(struct voice_data *v,
- unsigned int bufcnt)
+ uint32_t mem_handle)
{
struct vss_imemory_cmd_unmap_t mem_unmap;
int ret = 0;
@@ -2701,7 +2752,7 @@
mem_unmap.hdr.dest_port = mvm_handle;
mem_unmap.hdr.token = 0;
mem_unmap.hdr.opcode = VSS_IMEMORY_CMD_UNMAP;
- mem_unmap.mem_handle = v->shmem_info.mem_handle;
+ mem_unmap.mem_handle = mem_handle;
pr_debug("%s: mem_handle: ox%x\n", __func__, mem_unmap.mem_handle);