Merge "msm: spm: Replace msm_spm_apcs_set_vdd with msm_spm_set_vdd"
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index a696746..b1c4ebb 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -181,6 +181,9 @@
- regulator-name: A string used as a descriptive name
for the boost regulator.
+ qcom,batfet:
+ - regulator-name: A string used as a descriptive name
+ for the batfet regulator.
Example:
pm8941-chg {
spmi-dev-container;
@@ -309,6 +312,10 @@
regulator-name = "8941_smbb_boost";
};
+ &pm8941_chg_batif {
+ regulator-name = "batfet";
+ };
+
&pm8941_chg_otg {
regulator-name = "8941_smbb_otg";
};
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 9319163..6e4f7fc 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -665,6 +665,7 @@
- qcom,cdc-us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
- qcom,cdc-lineout-spkr-gpios : GPIO which controls external PAs to enable Lineout1/2 speaker
- qcom,cdc-vdd-spkr-gpios : GPIO which controls PA for VDD speaker
+- qcom,headset-jack-type-NC: Set if the headset jack type is NC (Normally Closed)
Example:
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 69b2cd2..58fc698 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -290,6 +290,14 @@
timer counter page should be mapped by the kernel. User-space apps
will read directly from the page at this address.
+config ARCH_RANDOM
+ bool "SOC specific random number generation"
+ help
+ Allow the kernel to use an architecture specific implementation for
+ random number generation
+
+ If unsure, say N
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/arm/boot/dts/apq8026-v1-mtp.dts b/arch/arm/boot/dts/apq8026-v1-mtp.dts
index 7900ddf..87a0271 100644
--- a/arch/arm/boot/dts/apq8026-v1-mtp.dts
+++ b/arch/arm/boot/dts/apq8026-v1-mtp.dts
@@ -22,8 +22,8 @@
};
&cci {
- /* Rotate rear camera to 0 degrees */
+ /* Rotate rear camera to 180 degrees */
qcom,camera@6f {
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <180>;
};
};
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
new file mode 100644
index 0000000..103da50
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1300mah.dtsi
@@ -0,0 +1,105 @@
+/* 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.
+ */
+
+qcom,qrd-4v2-1300mah-data {
+ qcom,fcc-mah = <1300>;
+ qcom,default-rbatt-mohm = <172>;
+ qcom,rbatt-capacitive-mohm = <0>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <100>;
+
+ qcom,rbatt-sf-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <604 192 100 79 71>,
+ <605 192 100 79 71>,
+ <641 205 103 81 72>,
+ <641 221 108 84 75>,
+ <622 238 115 87 77>,
+ <612 254 123 92 79>,
+ <605 252 137 96 83>,
+ <607 219 154 104 87>,
+ <613 202 135 109 89>,
+ <626 200 106 90 77>,
+ <656 201 101 82 75>,
+ <684 204 100 84 77>,
+ <710 211 100 85 79>,
+ <747 224 106 89 82>,
+ <806 241 116 90 80>,
+ <905 260 119 87 77>,
+ <1046 291 113 87 77>,
+ <1309 329 116 90 79>,
+ <1476 300 126 97 83>,
+ <1598 311 127 98 84>,
+ <1771 323 130 99 85>,
+ <1984 342 136 101 86>,
+ <2438 368 140 101 86>,
+ <3381 388 137 100 84>,
+ <4913 414 141 99 86>,
+ <6979 468 155 104 90>,
+ <9968 565 192 113 98>,
+ <16163 833 350 140 120>,
+ <36511 6483 4872 472 1095>;
+ };
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-data = <1343 1353 1408 1345 1342>;
+ };
+
+ qcom,pc-temp-ocv-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <4177 4174 4199 4167 4162>,
+ <4107 4112 4141 4109 4106>,
+ <4058 4064 4091 4061 4059>,
+ <3996 4015 4044 4017 4015>,
+ <3947 3975 4001 3978 3976>,
+ <3909 3939 3962 3943 3940>,
+ <3874 3901 3926 3911 3907>,
+ <3845 3858 3892 3882 3878>,
+ <3821 3826 3851 3849 3846>,
+ <3801 3804 3815 3810 3808>,
+ <3788 3789 3793 3789 3787>,
+ <3778 3780 3778 3776 3773>,
+ <3769 3776 3770 3767 3764>,
+ <3757 3772 3766 3762 3757>,
+ <3740 3765 3762 3754 3744>,
+ <3714 3747 3750 3739 3724>,
+ <3668 3706 3717 3710 3697>,
+ <3602 3644 3662 3662 3654>,
+ <3533 3571 3601 3607 3605>,
+ <3518 3557 3583 3592 3590>,
+ <3500 3543 3565 3576 3574>,
+ <3478 3528 3546 3559 3557>,
+ <3451 3506 3521 3538 3534>,
+ <3417 3473 3481 3505 3496>,
+ <3377 3423 3424 3454 3444>,
+ <3327 3361 3351 3391 3380>,
+ <3261 3279 3258 3310 3297>,
+ <3165 3165 3138 3198 3182>,
+ <3000 3000 3000 3000 3000>;
+ };
+};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
index 5b7cc79..0b3fec4 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35521-720p-video.dtsi
@@ -61,7 +61,7 @@
29 01 00 00 00 00 03 D6 44 44
29 01 00 00 00 00 0D D7 00 00 00 00 00 00 00 00 00 00 00 00
29 01 00 00 00 00 0E D8 00 00 00 00 00 00 00 00 00 00 00 00 00
- 29 01 00 00 00 00 03 D9 00 28
+ 29 01 00 00 00 00 03 D9 03 06
29 01 00 00 00 00 03 E5 00 FF
29 01 00 00 00 00 05 E6 F3 EC E7 DF
29 01 00 00 00 00 0B E7 F3 D9 CC CD B3 A6 99 99 99 95
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index e4fc96c..049c71a 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -863,6 +863,18 @@
linux,name = "led:flash_1";
qcom,current = <625>;
};
- };
+
+ pm8226_torch: qcom,flash_torch {
+ qcom,max-current = <200>;
+ qcom,default-state = "off";
+ linux,default-trigger =
+ "torch_trigger";
+ label = "flash";
+ qcom,id = <1>;
+ linux,name = "led:flash_torch";
+ qcom,current = <120>;
+ qcom,torch-enable;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
index f807814..5d7a7ec 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-cdp.dtsi
@@ -18,6 +18,7 @@
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,torch-source = <&pm8226_torch>;
};
};
@@ -38,7 +39,7 @@
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <180>;
qcom,sensor-name = "ov8825";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
index 56e8a09..5d1e1c8 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-mtp.dtsi
@@ -18,6 +18,7 @@
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,torch-source = <&pm8226_torch>;
};
};
@@ -38,7 +39,7 @@
qcom,csid-sd-index = <0>;
qcom,actuator-src = <&actuator0>;
qcom,led-flash-src = <&led_flash0>;
- qcom,mount-angle = <90>;
+ qcom,mount-angle = <270>;
qcom,sensor-name = "ov8825";
cam_vdig-supply = <&pm8226_l5>;
cam_vana-supply = <&pm8226_l19>;
diff --git a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
index 64e4b6e..5822a4a 100644
--- a/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi
@@ -18,6 +18,7 @@
compatible = "qcom,camera-led-flash";
qcom,flash-type = <1>;
qcom,flash-source = <&pm8226_flash0 &pm8226_flash1>;
+ qcom,torch-source = <&pm8226_torch>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index 79476ea..cada48e 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -35,8 +35,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,power-down;
- synaptics,disable-gpios;
};
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index 8fc2c7b..d02549d 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -35,8 +35,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,power-down;
- synaptics,disable-gpios;
};
};
@@ -464,6 +462,11 @@
&pm8226_bms {
status = "ok";
+ qcom,enable-fcc-learning;
+ qcom,min-fcc-learning-soc = <20>;
+ qcom,min-fcc-ocv-pc = <30>;
+ qcom,min-fcc-learning-samples = <5>;
+ qcom,fcc-resolution = <10>;
};
&pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index 6e5bc54..5e769a7 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -30,8 +30,6 @@
synaptics,irq-gpio = <&msmgpio 17 0x2008>;
synaptics,button-map = <139 102 158>;
synaptics,i2c-pull-up;
- synaptics,power-down;
- synaptics,disable-gpios;
};
focaltech@38 {
compatible = "focaltech,5x06";
@@ -366,6 +364,11 @@
status = "okay";
qcom,batt-type = <4>;
qcom,max-voltage-uv = <4350000>;
+ qcom,enable-fcc-learning;
+ qcom,min-fcc-learning-soc = <20>;
+ qcom,min-fcc-ocv-pc = <30>;
+ qcom,min-fcc-learning-samples = <5>;
+ qcom,fcc-resolution = <10>;
};
&pm8226_chg {
diff --git a/arch/arm/boot/dts/msm8226-v1-mtp.dts b/arch/arm/boot/dts/msm8226-v1-mtp.dts
index 6f03dca..c32adbe 100644
--- a/arch/arm/boot/dts/msm8226-v1-mtp.dts
+++ b/arch/arm/boot/dts/msm8226-v1-mtp.dts
@@ -25,8 +25,8 @@
};
&cci {
- /* Rotate rear camera to 0 degrees */
+ /* Rotate rear camera to 180 degrees */
qcom,camera@6f {
- qcom,mount-angle = <0>;
+ qcom,mount-angle = <180>;
};
};
diff --git a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
index 1cbf00d..59de631 100644
--- a/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v1-qrd-skuf.dts
@@ -113,6 +113,12 @@
status = "disabled";
};
};
+
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "disabled";
+ };
+ };
};
&pm8226_mpps {
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 9e98681..7aadd71 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -35,3 +35,7 @@
&pm8226_bms {
qcom,use-external-rsense;
};
+
+&pm8226_iadc {
+ qcom,rsense = <10000000>;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index fba41e5..76a3cc7 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -114,6 +114,12 @@
status = "disabled";
};
};
+
+ qcom,pm8226@1 {
+ qcom,leds@d800 {
+ status = "disabled";
+ };
+ };
};
&pm8226_mpps {
diff --git a/arch/arm/boot/dts/msm8610-cdp.dtsi b/arch/arm/boot/dts/msm8610-cdp.dtsi
index bfccb78..8403dfd 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -140,6 +140,11 @@
msm8x10_wcd_codec@0d{
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
+
+ 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>;
+
cdc-vdda-cp-supply = <&pm8110_s4>;
qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
@@ -217,10 +222,9 @@
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
qcom,pwm-channel = <0>;
- qcom,pwm-us = <14>;
+ qcom,pwm-us = <27>;
qcom,vin-ctrl = <0x03>;
qcom,mode = "pwm";
- qcom,min-brightness = <19>;
};
};
};
@@ -238,8 +242,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-mtp.dtsi b/arch/arm/boot/dts/msm8610-mtp.dtsi
index 349c8f7..7e80d19 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -178,6 +178,11 @@
msm8x10_wcd_codec@0d{
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
+
+ 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>;
+
cdc-vdda-cp-supply = <&pm8110_s4>;
qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
@@ -255,10 +260,9 @@
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
qcom,pwm-channel = <0>;
- qcom,pwm-us = <14>;
+ qcom,pwm-us = <27>;
qcom,vin-ctrl = <0x03>;
qcom,mode = "pwm";
- qcom,min-brightness = <19>;
};
};
};
@@ -276,8 +280,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
index e73573a..bdcb285 100644
--- a/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd-camera-sensor.dtsi
@@ -18,7 +18,7 @@
qcom,slave-id = <0x40 0x04 0xc0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <270>;
+ qcom,mount-angle = <90>;
qcom,sensor-name = "hi256";
cam_vdig-supply = <&pm8110_l2>;
cam_vana-supply = <&pm8110_l19>;
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index 49068b5..2d29d30 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -149,6 +149,11 @@
msm8x10_wcd_codec@0d{
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
+
+ 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>;
+
cdc-vdda-cp-supply = <&pm8110_s4>;
qcom,cdc-vdda-cp-voltage = <1800000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
@@ -226,10 +231,9 @@
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x10>;
qcom,pwm-channel = <0>;
- qcom,pwm-us = <14>;
+ qcom,pwm-us = <27>;
qcom,vin-ctrl = <0x03>;
qcom,mode = "pwm";
- qcom,min-brightness = <19>;
};
};
};
@@ -247,8 +251,6 @@
&sdhc_1 {
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <200 400000>;
diff --git a/arch/arm/boot/dts/msm8610-sim.dts b/arch/arm/boot/dts/msm8610-sim.dts
index 7c57fe6..33176b9 100644
--- a/arch/arm/boot/dts/msm8610-sim.dts
+++ b/arch/arm/boot/dts/msm8610-sim.dts
@@ -30,6 +30,11 @@
msm8x10_wcd_codec@0d{
compatible = "qcom,msm8x10-wcd-i2c";
reg = <0x0d>;
+
+ 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>;
+
cdc-vdda-cp-supply = <&pm8110_s4>;
qcom,cdc-vdda-cp-voltage = <2150000 2150000>;
qcom,cdc-vdda-cp-current = <650000>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d54245c..8239feb 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -69,6 +69,15 @@
qcom,direct-connect-irqs = <8>;
};
+ wcd9xxx_intc: wcd9xxx_irq {
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&intc>;
+ interrupts = <0 31 0>;
+ interrupt-names = "cdc-int";
+ };
+
qcom,mpm2-sleep-counter@fc4a3000 {
compatible = "qcom,mpm2-sleep-counter";
reg = <0xfc4a3000 0x1000>;
@@ -257,8 +266,6 @@
interrupt-names = "core_irq", "bam_irq";
vdd-supply = <&pm8110_l17>;
- qcom,vdd-always-on;
- qcom,vdd-lpm-sup;
qcom,vdd-voltage-level = <2900000 2900000>;
qcom,vdd-current-level = <9000 400000>;
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index ca20e04..63fd82b 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -60,7 +60,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index d8ae340..7d1562b 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -60,7 +60,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 8591812..2b76ba8 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -62,7 +62,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
@@ -71,7 +71,6 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
-CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 20938d5..aec5ce2 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -59,7 +59,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 7901e93..6ad1b12 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -68,7 +68,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 8520f23..4937a64 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -68,7 +68,7 @@
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
-CONFIG_MSM_ADSP_LOADER=m
+CONFIG_MSM_ADSP_LOADER=y
CONFIG_MSM_OCMEM=y
CONFIG_MSM_OCMEM_LOCAL_POWER_CTRL=y
CONFIG_MSM_OCMEM_DEBUG=y
diff --git a/arch/arm/include/asm/archrandom.h b/arch/arm/include/asm/archrandom.h
new file mode 100644
index 0000000..5530d45
--- /dev/null
+++ b/arch/arm/include/asm/archrandom.h
@@ -0,0 +1,20 @@
+/* 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 ARM_ASM_ARCHRANDOM_H
+#define ARM_ASM_ARCHRANDOM_H
+
+extern int arch_get_random_long(unsigned long *v);
+extern int arch_get_random_int(unsigned int *v);
+
+#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 5c0d2cf..87e3e5b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2626,7 +2626,7 @@
config MSM_ADSP_LOADER
tristate "ADSP loader support"
select SND_SOC_MSM_APRV2_INTF
- depends on MSM_AUDIO_QDSP6V2 && m
+ depends on MSM_AUDIO_QDSP6V2
help
Enable ADSP image loader.
The ADSP loader brings ADSP out of reset
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 12ffa66..89eb589 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -431,3 +431,4 @@
obj-$(CONFIG_WALL_CLK) += wallclk.o
obj-$(CONFIG_WALL_CLK_SYSFS) += wallclk_sysfs.o
+obj-$(CONFIG_ARCH_RANDOM) += early_random.o
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index bfd8e38..dc9c13d 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -511,6 +511,62 @@
},
};
+static struct gpiomux_setting interrupt_gpio_active = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pullup = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting interrupt_gpio_suspend_pulldown = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = {
+ {
+ .gpio = 77, /* NFC_IRQ */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &interrupt_gpio_active,
+ [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+ },
+ },
+ {
+ .gpio = 78, /*ETH_INT */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &interrupt_gpio_active,
+ [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+ },
+ },
+ {
+ .gpio = 80, /*ALSP_INT */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &interrupt_gpio_active,
+ [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
+ },
+ },
+ {
+ .gpio = 81, /*ACCEL_INT1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &interrupt_gpio_active,
+ [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+ },
+ },
+ {
+ .gpio = 82, /*ACCEL_INT2 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &interrupt_gpio_active,
+ [GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pulldown,
+ },
+ },
+};
+
void __init msm8610_init_gpiomux(void)
{
int rc;
@@ -539,4 +595,7 @@
msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
msm_gpiomux_install(msm_gpio_int_configs,
ARRAY_SIZE(msm_gpio_int_configs));
+ if (of_board_is_qrd())
+ msm_gpiomux_install(msm_interrupt_configs,
+ ARRAY_SIZE(msm_interrupt_configs));
}
diff --git a/arch/arm/mach-msm/early_random.c b/arch/arm/mach-msm/early_random.c
new file mode 100644
index 0000000..e315b86
--- /dev/null
+++ b/arch/arm/mach-msm/early_random.c
@@ -0,0 +1,83 @@
+/* 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 <mach/scm.h>
+
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+#define TZ_SVC_CRYPTO 10
+#define PRNG_CMD_ID 0x01
+
+static int use_arch_random = 1;
+struct tz_prng_data {
+ uint8_t *out_buf;
+ uint32_t out_buf_sz;
+} __packed;
+
+DEFINE_SCM_BUFFER(common_scm_buf)
+DEFINE_MUTEX(arch_random_lock);
+#define RANDOM_BUFFER_SIZE PAGE_SIZE
+char random_buffer[RANDOM_BUFFER_SIZE] __aligned(PAGE_SIZE);
+
+int arch_get_random_common(void *v, size_t size)
+{
+ struct tz_prng_data data;
+ int ret;
+ u32 resp;
+
+ if (!use_arch_random)
+ return 0;
+
+ if (size > sizeof(random_buffer))
+ return 0;
+
+ mutex_lock(&arch_random_lock);
+ data.out_buf = (uint8_t *) virt_to_phys(random_buffer);
+ data.out_buf_sz = size;
+
+ ret = scm_call_noalloc(TZ_SVC_CRYPTO, PRNG_CMD_ID, &data,
+ sizeof(data), &resp, sizeof(resp),
+ common_scm_buf, SCM_BUFFER_SIZE(common_scm_buf));
+ if (!ret) {
+ dmac_inv_range(random_buffer, random_buffer +
+ RANDOM_BUFFER_SIZE);
+ outer_inv_range(
+ (unsigned long) virt_to_phys(random_buffer),
+ (unsigned long) virt_to_phys(random_buffer) +
+ RANDOM_BUFFER_SIZE);
+ memcpy(v, random_buffer, size);
+ }
+ mutex_unlock(&arch_random_lock);
+ return !ret;
+}
+
+int arch_get_random_long(unsigned long *v)
+{
+ return arch_get_random_common(v, sizeof(unsigned long));
+}
+
+int arch_get_random_int(unsigned int *v)
+{
+ return arch_get_random_common(v, sizeof(unsigned int));
+}
+
+int arch_random_init(void)
+{
+ use_arch_random = 0;
+
+ return 0;
+}
+module_init(arch_random_init);
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 4186603..539dcf6 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -26,10 +26,22 @@
#define SCM_SVC_ES 0x10
#define SCM_SVC_TZSCHEDULER 0xFC
+#define DEFINE_SCM_BUFFER(__n) \
+static char __n[PAGE_SIZE] __aligned(PAGE_SIZE);
+
+#define SCM_BUFFER_SIZE(__buf) sizeof(__buf)
+
+#define SCM_BUFFER_PHYS(__buf) virt_to_phys(__buf)
+
#ifdef CONFIG_MSM_SCM
extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
void *resp_buf, size_t resp_len);
+extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+ size_t cmd_len, void *resp_buf, size_t resp_len,
+ void *scm_buf, size_t scm_buf_size);
+
+
extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
extern s32 scm_call_atomic3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3);
@@ -50,6 +62,13 @@
return 0;
}
+static inline int scm_call_noalloc(u32 svc_id, u32 cmd_id,
+ const void *cmd_buf, size_t cmd_len, void *resp_buf,
+ size_t resp_len, void *scm_buf, size_t scm_buf_size)
+{
+ return 0;
+}
+
static inline s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
{
return 0;
diff --git a/arch/arm/mach-msm/mpm-of.c b/arch/arm/mach-msm/mpm-of.c
index a0746f9..e364393 100644
--- a/arch/arm/mach-msm/mpm-of.c
+++ b/arch/arm/mach-msm/mpm-of.c
@@ -219,12 +219,16 @@
hlist_for_each_entry(node, elem, &irq_hash[hashfn(d->hwirq)], node) {
if ((node->hwirq == d->hwirq)
&& (d->domain == node->domain)) {
- /* Update the linux irq mapping */
- msm_mpm_irqs_m2a[node->pin] = d->irq;
+ /*
+ * Update the linux irq mapping. No update required for
+ * bypass interrupts
+ */
+ if (node->pin != 0xff)
+ msm_mpm_irqs_m2a[node->pin] = d->irq;
break;
}
}
- return node ? node->pin : 0;
+ return elem ? node->pin : 0;
}
static int msm_mpm_enable_irq_exclusive(
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index e74fdf9..0506e7e 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -20,39 +20,60 @@
#include <mach/subsystem_restart.h>
#include <mach/qdsp6v2/apr.h>
#include <linux/of_device.h>
+#include <linux/sysfs.h>
#define Q6_PIL_GET_DELAY_MS 100
+#define BOOT_CMD 1
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count);
struct adsp_loader_private {
void *pil_h;
+ struct kobject *boot_adsp_obj;
+ struct attribute_group *attr_group;
};
-static int adsp_loader_probe(struct platform_device *pdev)
+static struct kobj_attribute adsp_boot_attribute =
+ __ATTR(boot, 0220, NULL, adsp_boot_store);
+
+static struct attribute *attrs[] = {
+ &adsp_boot_attribute.attr,
+ NULL,
+};
+
+static struct platform_device *adsp_private;
+
+static void adsp_loader_do(struct platform_device *pdev)
{
- struct adsp_loader_private *priv;
- int rc = 0;
+
+ struct adsp_loader_private *priv = NULL;
+
const char *adsp_dt = "qcom,adsp-state";
+ int rc = 0;
u32 adsp_state;
rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
if (rc) {
dev_err(&pdev->dev,
"%s: ADSP state = %x\n", __func__, adsp_state);
- return rc;
+ return;
}
if (adsp_state == APR_SUBSYS_DOWN) {
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ if (pdev) {
+ priv = platform_get_drvdata(pdev);
+ } else {
+ pr_err("%s: Private data get failed\n", __func__);
+ goto fail;
+ }
- platform_set_drvdata(pdev, priv);
priv->pil_h = subsystem_get("adsp");
if (IS_ERR(priv->pil_h)) {
- pr_err("%s: pil get adsp failed, error:%d\n",
- __func__, rc);
- devm_kfree(&pdev->dev, priv);
+ pr_err("%s: pil get failed,\n",
+ __func__);
goto fail;
}
@@ -60,25 +81,123 @@
apr_set_q6_state(APR_SUBSYS_LOADED);
} else if (adsp_state == APR_SUBSYS_LOADED) {
dev_dbg(&pdev->dev,
- "%s:MDM9x25 ADSP state = %x\n", __func__, adsp_state);
+ "%s: ADSP state = %x\n", __func__, adsp_state);
apr_set_q6_state(APR_SUBSYS_LOADED);
}
- /* Query for MMPM API */
pr_info("%s: Q6/ADSP image is loaded\n", __func__);
+ return;
fail:
- return rc;
+
+ pr_err("%s: Q6/ADSP image loading failed\n", __func__);
+ return;
+}
+
+
+static ssize_t adsp_boot_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int boot = 0;
+ sscanf(buf, "%du", &boot);
+
+ if (boot == BOOT_CMD) {
+ pr_debug("%s:going to call adsp_loader_do", __func__);
+ adsp_loader_do(adsp_private);
+ }
+ return count;
+}
+
+static int adsp_loader_init_sysfs(struct platform_device *pdev)
+{
+ int ret = -EINVAL;
+ struct adsp_loader_private *priv = NULL;
+ adsp_private = NULL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ pr_err("%s: memory alloc failed\n", __func__);
+ ret = -ENOMEM;
+ goto error_return;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ priv->pil_h = NULL;
+ priv->boot_adsp_obj = NULL;
+ priv->attr_group = devm_kzalloc(&pdev->dev,
+ sizeof(*(priv->attr_group)),
+ GFP_KERNEL);
+ if (!priv->attr_group) {
+ pr_err("%s: malloc attr_group failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error_return;
+ }
+
+ priv->attr_group->attrs = attrs;
+
+ priv->boot_adsp_obj = kobject_create_and_add("boot_adsp", kernel_kobj);
+ if (!priv->boot_adsp_obj) {
+ pr_err("%s: sysfs create and add failed\n",
+ __func__);
+ ret = -ENOMEM;
+ goto error_return;
+ }
+
+ ret = sysfs_create_group(priv->boot_adsp_obj, priv->attr_group);
+ if (ret) {
+ pr_err("%s: sysfs create group failed %d\n", \
+ __func__, ret);
+ goto error_return;
+ }
+
+ adsp_private = pdev;
+
+ return 0;
+
+error_return:
+
+ if (priv->boot_adsp_obj) {
+ kobject_del(priv->boot_adsp_obj);
+ priv->boot_adsp_obj = NULL;
+ }
+
+ return ret;
}
static int adsp_loader_remove(struct platform_device *pdev)
{
- struct adsp_loader_private *priv;
+ struct adsp_loader_private *priv = NULL;
priv = platform_get_drvdata(pdev);
- if (priv != NULL)
+
+ if (!priv)
+ return 0;
+
+ if (priv->pil_h) {
subsystem_put(priv->pil_h);
- pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
+ priv->pil_h = NULL;
+ }
+
+ if (priv->boot_adsp_obj) {
+ sysfs_remove_group(priv->boot_adsp_obj, priv->attr_group);
+ kobject_del(priv->boot_adsp_obj);
+ priv->boot_adsp_obj = NULL;
+ }
+
+ return 0;
+}
+
+static int adsp_loader_probe(struct platform_device *pdev)
+{
+ int ret = adsp_loader_init_sysfs(pdev);
+ if (ret != 0) {
+ pr_err("%s: Error in initing sysfs\n", __func__);
+ return ret;
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
index f4eb318..caeb79d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -262,6 +262,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
index 056a161..fc023c1 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrnb.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -120,6 +120,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_amrnb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
index 54ca4e8..256da4d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwb.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -122,6 +122,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_amrwb_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
index 2889c14..902e06d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_amrwbplus.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -199,6 +199,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
config_debug_fs(audio);
pr_debug("%s: AMRWBPLUS dec success mode[%d]session[%d]\n", __func__,
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
index 261642c..3498e69 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_evrc.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -128,6 +128,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_evrc_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
index ebcca3c..d2f0270 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mp3.c
@@ -128,6 +128,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_mp3_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index 8153145..0a8ce8e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -282,6 +282,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
index 69a9fcb..4993226 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_qcelp.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -133,6 +133,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_qcelp_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 8baac01..a1463bc 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1095,6 +1095,7 @@
int rc = 0;
int i;
struct audio_aio_event *e_node = NULL;
+ struct list_head *ptr, *next;
/* Settings will be re-config at AUDIO_SET_CONFIG,
* but at least we need to have initial config
@@ -1147,28 +1148,35 @@
else {
pr_err("%s[%p]:event pkt alloc failed\n",
__func__, audio);
- break;
+ rc = -ENOMEM;
+ goto cleanup;
}
}
audio->client = msm_audio_ion_client_create(UINT_MAX,
"Audio_Dec_Client");
if (IS_ERR_OR_NULL(audio->client)) {
pr_err("Unable to create ION client\n");
- rc = -EACCES;
- goto fail;
+ rc = -ENOMEM;
+ goto cleanup;
}
pr_debug("Ion client create in audio_aio_open %p", audio->client);
rc = register_volume_listener(audio);
if (rc < 0)
- goto fail;
+ goto ion_cleanup;
return 0;
-
+ion_cleanup:
+ msm_audio_ion_client_destroy(audio->client);
+ audio->client = NULL;
+cleanup:
+ list_for_each_safe(ptr, next, &audio->free_event_queue) {
+ e_node = list_first_entry(&audio->free_event_queue,
+ struct audio_aio_event, list);
+ list_del(&e_node->list);
+ kfree(e_node);
+ }
fail:
- q6asm_audio_client_free(audio->ac);
- kfree(audio->codec_cfg);
- kfree(audio);
return rc;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
index 1d1da1a..5e3de86 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -167,6 +167,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
index 2b2d772..ce49cac 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -227,6 +227,10 @@
goto fail;
}
rc = audio_aio_open(audio, file);
+ if (rc < 0) {
+ pr_err("audio_aio_open rc=%d\n", rc);
+ goto fail;
+ }
#ifdef CONFIG_DEBUG_FS
snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index e9f44e3..266b759 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -31,6 +31,9 @@
static DEFINE_MUTEX(scm_lock);
+#define SCM_BUF_LEN(__cmd_size, __resp_size) \
+ (sizeof(struct scm_command) + sizeof(struct scm_response) + \
+ __cmd_size + __resp_size)
/**
* struct scm_command - one SCM command buffer
* @len: total available memory for command and response
@@ -76,42 +79,6 @@
};
/**
- * alloc_scm_command() - Allocate an SCM command
- * @cmd_size: size of the command buffer
- * @resp_size: size of the response buffer
- *
- * Allocate an SCM command, including enough room for the command
- * and response headers as well as the command and response buffers.
- *
- * Returns a valid &scm_command on success or %NULL if the allocation fails.
- */
-static struct scm_command *alloc_scm_command(size_t cmd_size, size_t resp_size)
-{
- struct scm_command *cmd;
- size_t len = sizeof(*cmd) + sizeof(struct scm_response) + cmd_size +
- resp_size;
-
- cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
- if (cmd) {
- cmd->len = len;
- cmd->buf_offset = offsetof(struct scm_command, buf);
- cmd->resp_hdr_offset = cmd->buf_offset + cmd_size;
- }
- return cmd;
-}
-
-/**
- * free_scm_command() - Free an SCM command
- * @cmd: command to free
- *
- * Free an SCM command.
- */
-static inline void free_scm_command(struct scm_command *cmd)
-{
- kfree(cmd);
-}
-
-/**
* scm_command_to_response() - Get a pointer to a scm_response
* @cmd: command
*
@@ -224,6 +191,92 @@
}
/**
+ * scm_call_common() - Send an SCM command
+ * @svc_id: service identifier
+ * @cmd_id: command identifier
+ * @cmd_buf: command buffer
+ * @cmd_len: length of the command buffer
+ * @resp_buf: response buffer
+ * @resp_len: length of the response buffer
+ * @scm_buf: internal scm structure used for passing data
+ * @scm_buf_len: length of the internal scm structure
+ *
+ * Core function to scm call. Initializes the given cmd structure with
+ * appropriate values and makes the actual scm call. Validation of cmd
+ * pointer and length must occur in the calling function.
+ *
+ * Returns the appropriate error code from the scm call
+ */
+
+static int scm_call_common(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+ size_t cmd_len, void *resp_buf, size_t resp_len,
+ struct scm_command *scm_buf,
+ size_t scm_buf_length)
+{
+ int ret;
+ struct scm_response *rsp;
+ unsigned long start, end;
+
+ scm_buf->len = scm_buf_length;
+ scm_buf->buf_offset = offsetof(struct scm_command, buf);
+ scm_buf->resp_hdr_offset = scm_buf->buf_offset + cmd_len;
+ scm_buf->id = (svc_id << 10) | cmd_id;
+
+ if (cmd_buf)
+ memcpy(scm_get_command_buffer(scm_buf), cmd_buf, cmd_len);
+
+ mutex_lock(&scm_lock);
+ ret = __scm_call(scm_buf);
+ mutex_unlock(&scm_lock);
+ if (ret)
+ return ret;
+
+ rsp = scm_command_to_response(scm_buf);
+ start = (unsigned long)rsp;
+
+ do {
+ scm_inv_range(start, start + sizeof(*rsp));
+ } while (!rsp->is_complete);
+
+ end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
+ scm_inv_range(start, end);
+
+ if (resp_buf)
+ memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
+
+ return ret;
+}
+
+/**
+ * scm_call_noalloc - Send an SCM command
+ *
+ * Same as scm_call except clients pass in a buffer (@scm_buf) to be used for
+ * scm internal structures. The buffer should be allocated with
+ * DEFINE_SCM_BUFFER to account for the proper alignment and size.
+ */
+int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
+ size_t cmd_len, void *resp_buf, size_t resp_len,
+ void *scm_buf, size_t scm_buf_len)
+{
+ int ret;
+ size_t len = SCM_BUF_LEN(cmd_len, resp_len);
+
+ if (cmd_len > scm_buf_len || resp_len > scm_buf_len ||
+ len > scm_buf_len)
+ return -EINVAL;
+
+ if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE))
+ return -EINVAL;
+
+ memset(scm_buf, 0, scm_buf_len);
+
+ ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+ resp_len, scm_buf, len);
+ return ret;
+
+}
+
+/**
* scm_call() - Send an SCM command
* @svc_id: service identifier
* @cmd_id: command identifier
@@ -244,39 +297,20 @@
int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
void *resp_buf, size_t resp_len)
{
- int ret;
struct scm_command *cmd;
- struct scm_response *rsp;
- unsigned long start, end;
+ int ret;
+ size_t len = SCM_BUF_LEN(cmd_len, resp_len);
- cmd = alloc_scm_command(cmd_len, resp_len);
+ if (cmd_len > len || resp_len > len)
+ return -EINVAL;
+
+ cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
if (!cmd)
return -ENOMEM;
- cmd->id = (svc_id << 10) | cmd_id;
- if (cmd_buf)
- memcpy(scm_get_command_buffer(cmd), cmd_buf, cmd_len);
-
- mutex_lock(&scm_lock);
- ret = __scm_call(cmd);
- mutex_unlock(&scm_lock);
- if (ret)
- goto out;
-
- rsp = scm_command_to_response(cmd);
- start = (unsigned long)rsp;
-
- do {
- scm_inv_range(start, start + sizeof(*rsp));
- } while (!rsp->is_complete);
-
- end = (unsigned long)scm_get_response_buffer(rsp) + resp_len;
- scm_inv_range(start, end);
-
- if (resp_buf)
- memcpy(resp_buf, scm_get_response_buffer(rsp), resp_len);
-out:
- free_scm_command(cmd);
+ ret = scm_call_common(svc_id, cmd_id, cmd_buf, cmd_len, resp_buf,
+ resp_len, cmd, len);
+ kfree(cmd);
return ret;
}
EXPORT_SYMBOL(scm_call);
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index d500c0a..3225817 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -45,6 +45,8 @@
#define tmc_writel(drvdata, val, off) __raw_writel((val), drvdata->base + off)
#define tmc_readl(drvdata, off) __raw_readl(drvdata->base + off)
+#define tmc_readl_no_log(drvdata, off) __raw_readl_no_log(drvdata->base + off)
+
#define TMC_LOCK(drvdata) \
do { \
mb(); \
@@ -651,7 +653,7 @@
bufp = drvdata->buf;
while (1) {
for (i = 0; i < memwords; i++) {
- read_data = tmc_readl(drvdata, TMC_RRD);
+ read_data = tmc_readl_no_log(drvdata, TMC_RRD);
if (read_data == 0xFFFFFFFF)
goto out;
memcpy(bufp, &read_data, BYTES_PER_WORD);
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 0c398c4..b5945da 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -240,6 +240,7 @@
#define A3XX_PC_PERFCOUNTER1_SELECT 0xC49
#define A3XX_PC_PERFCOUNTER2_SELECT 0xC4A
#define A3XX_PC_PERFCOUNTER3_SELECT 0xC4B
+#define A3XX_GRAS_TSE_DEBUG_ECO 0xC81
#define A3XX_GRAS_PERFCOUNTER0_SELECT 0xC88
#define A3XX_GRAS_PERFCOUNTER1_SELECT 0xC89
#define A3XX_GRAS_PERFCOUNTER2_SELECT 0xC8A
@@ -269,8 +270,10 @@
#define A3XX_GRAS_CL_USER_PLANE_Z5 0xCB6
#define A3XX_GRAS_CL_USER_PLANE_W5 0xCB7
#define A3XX_RB_GMEM_BASE_ADDR 0xCC0
+#define A3XX_RB_DEBUG_ECO_CONTROLS_ADDR 0xCC1
#define A3XX_RB_PERFCOUNTER0_SELECT 0xCC6
#define A3XX_RB_PERFCOUNTER1_SELECT 0xCC7
+#define A3XX_RB_FRAME_BUFFER_DIMENSION 0xCE0
#define A3XX_HLSQ_PERFCOUNTER0_SELECT 0xE00
#define A3XX_HLSQ_PERFCOUNTER1_SELECT 0xE01
#define A3XX_HLSQ_PERFCOUNTER2_SELECT 0xE02
@@ -308,6 +311,9 @@
#define A3XX_GRAS_CL_CLIP_CNTL 0x2040
#define A3XX_GRAS_CL_GB_CLIP_ADJ 0x2044
#define A3XX_GRAS_CL_VPORT_XOFFSET 0x2048
+#define A3XX_GRAS_CL_VPORT_XSCALE 0x2049
+#define A3XX_GRAS_CL_VPORT_YOFFSET 0x204A
+#define A3XX_GRAS_CL_VPORT_YSCALE 0x204B
#define A3XX_GRAS_CL_VPORT_ZOFFSET 0x204C
#define A3XX_GRAS_CL_VPORT_ZSCALE 0x204D
#define A3XX_GRAS_SU_POINT_MINMAX 0x2068
@@ -323,30 +329,75 @@
#define A3XX_RB_MODE_CONTROL 0x20C0
#define A3XX_RB_RENDER_CONTROL 0x20C1
#define A3XX_RB_MSAA_CONTROL 0x20C2
+#define A3XX_RB_ALPHA_REFERENCE 0x20C3
#define A3XX_RB_MRT_CONTROL0 0x20C4
#define A3XX_RB_MRT_BUF_INFO0 0x20C5
+#define A3XX_RB_MRT_BUF_BASE0 0x20C6
#define A3XX_RB_MRT_BLEND_CONTROL0 0x20C7
+#define A3XX_RB_MRT_CONTROL1 0x20C8
+#define A3XX_RB_MRT_BUF_INFO1 0x20C9
+#define A3XX_RB_MRT_BUF_BASE1 0x20CA
#define A3XX_RB_MRT_BLEND_CONTROL1 0x20CB
+#define A3XX_RB_MRT_CONTROL2 0x20CC
+#define A3XX_RB_MRT_BUF_INFO2 0x20CD
+#define A3XX_RB_MRT_BUF_BASE2 0x20CE
#define A3XX_RB_MRT_BLEND_CONTROL2 0x20CF
+#define A3XX_RB_MRT_CONTROL3 0x20D0
+#define A3XX_RB_MRT_BUF_INFO3 0x20D1
+#define A3XX_RB_MRT_BUF_BASE3 0x20D2
#define A3XX_RB_MRT_BLEND_CONTROL3 0x20D3
#define A3XX_RB_BLEND_RED 0x20E4
+#define A3XX_RB_BLEND_GREEN 0x20E5
+#define A3XX_RB_BLEND_BLUE 0x20E6
+#define A3XX_RB_BLEND_ALPHA 0x20E7
+#define A3XX_RB_CLEAR_COLOR_DW0 0x20E8
+#define A3XX_RB_CLEAR_COLOR_DW1 0x20E9
+#define A3XX_RB_CLEAR_COLOR_DW2 0x20EA
+#define A3XX_RB_CLEAR_COLOR_DW3 0x20EB
#define A3XX_RB_COPY_CONTROL 0x20EC
+#define A3XX_RB_COPY_DEST_BASE 0x20ED
+#define A3XX_RB_COPY_DEST_PITCH 0x20EE
#define A3XX_RB_COPY_DEST_INFO 0x20EF
#define A3XX_RB_DEPTH_CONTROL 0x2100
+#define A3XX_RB_DEPTH_CLEAR 0x2101
+#define A3XX_RB_DEPTH_BUF_INFO 0x2102
+#define A3XX_RB_DEPTH_BUF_PITCH 0x2103
#define A3XX_RB_STENCIL_CONTROL 0x2104
+#define A3XX_RB_STENCIL_CLEAR 0x2105
+#define A3XX_RB_STENCIL_BUF_INFO 0x2106
+#define A3XX_RB_STENCIL_BUF_PITCH 0x2107
+#define A3XX_RB_STENCIL_REF_MASK 0x2108
+#define A3XX_RB_STENCIL_REF_MASK_BF 0x2109
+#define A3XX_RB_LRZ_VSC_CONTROL 0x210C
+#define A3XX_RB_WINDOW_OFFSET 0x210E
+#define A3XX_RB_SAMPLE_COUNT_CONTROL 0x2110
+#define A3XX_RB_SAMPLE_COUNT_ADDR 0x2111
+#define A3XX_RB_Z_CLAMP_MIN 0x2114
+#define A3XX_RB_Z_CLAMP_MAX 0x2115
#define A3XX_PC_VSTREAM_CONTROL 0x21E4
#define A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x21EA
#define A3XX_PC_PRIM_VTX_CNTL 0x21EC
#define A3XX_PC_RESTART_INDEX 0x21ED
#define A3XX_HLSQ_CONTROL_0_REG 0x2200
+#define A3XX_HLSQ_CONTROL_1_REG 0x2201
+#define A3XX_HLSQ_CONTROL_2_REG 0x2202
+#define A3XX_HLSQ_CONTROL_3_REG 0x2203
#define A3XX_HLSQ_VS_CONTROL_REG 0x2204
+#define A3XX_HLSQ_FS_CONTROL_REG 0x2205
+#define A3XX_HLSQ_CONST_VSPRESV_RANGE_REG 0x2206
#define A3XX_HLSQ_CONST_FSPRESV_RANGE_REG 0x2207
#define A3XX_HLSQ_CL_NDRANGE_0_REG 0x220A
+#define A3XX_HLSQ_CL_NDRANGE_1_REG 0x220B
#define A3XX_HLSQ_CL_NDRANGE_2_REG 0x220C
+#define A3XX_HLSQ_CL_NDRANGE_3_REG 0x220D
+#define A3XX_HLSQ_CL_NDRANGE_4_REG 0x220E
+#define A3XX_HLSQ_CL_NDRANGE_5_REG 0x220F
+#define A3XX_HLSQ_CL_NDRANGE_6_REG 0x2210
#define A3XX_HLSQ_CL_CONTROL_0_REG 0x2211
#define A3XX_HLSQ_CL_CONTROL_1_REG 0x2212
#define A3XX_HLSQ_CL_KERNEL_CONST_REG 0x2214
#define A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x2215
+#define A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x2216
#define A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x2217
#define A3XX_HLSQ_CL_WG_OFFSET_REG 0x221A
#define A3XX_VFD_CONTROL_0 0x2240
@@ -363,10 +414,21 @@
#define A3XX_SP_VS_CTRL_REG0 0x22C4
#define A3XX_SP_VS_CTRL_REG1 0x22C5
#define A3XX_SP_VS_PARAM_REG 0x22C6
+#define A3XX_SP_VS_OUT_REG_0 0x22C7
+#define A3XX_SP_VS_OUT_REG_1 0x22C8
+#define A3XX_SP_VS_OUT_REG_2 0x22C9
+#define A3XX_SP_VS_OUT_REG_3 0x22CA
+#define A3XX_SP_VS_OUT_REG_4 0x22CB
+#define A3XX_SP_VS_OUT_REG_5 0x22CC
+#define A3XX_SP_VS_OUT_REG_6 0x22CD
#define A3XX_SP_VS_OUT_REG_7 0x22CE
#define A3XX_SP_VS_VPC_DST_REG_0 0x22D0
+#define A3XX_SP_VS_VPC_DST_REG_1 0x22D1
+#define A3XX_SP_VS_VPC_DST_REG_2 0x22D2
+#define A3XX_SP_VS_VPC_DST_REG_3 0x22D3
#define A3XX_SP_VS_OBJ_OFFSET_REG 0x22D4
#define A3XX_SP_VS_OBJ_START_REG 0x22D5
+#define A3XX_SP_VS_PVT_MEM_PARAM_REG 0x22D6
#define A3XX_SP_VS_PVT_MEM_ADDR_REG 0x22D7
#define A3XX_SP_VS_PVT_MEM_SIZE_REG 0x22D8
#define A3XX_SP_VS_LENGTH_REG 0x22DF
@@ -374,13 +436,19 @@
#define A3XX_SP_FS_CTRL_REG1 0x22E1
#define A3XX_SP_FS_OBJ_OFFSET_REG 0x22E2
#define A3XX_SP_FS_OBJ_START_REG 0x22E3
+#define A3XX_SP_FS_PVT_MEM_PARAM_REG 0x22E4
#define A3XX_SP_FS_PVT_MEM_ADDR_REG 0x22E5
#define A3XX_SP_FS_PVT_MEM_SIZE_REG 0x22E6
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_0 0x22E8
#define A3XX_SP_FS_FLAT_SHAD_MODE_REG_1 0x22E9
#define A3XX_SP_FS_OUTPUT_REG 0x22EC
#define A3XX_SP_FS_MRT_REG_0 0x22F0
+#define A3XX_SP_FS_MRT_REG_1 0x22F1
+#define A3XX_SP_FS_MRT_REG_2 0x22F2
+#define A3XX_SP_FS_MRT_REG_3 0x22F3
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_0 0x22F4
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_1 0x22F5
+#define A3XX_SP_FS_IMAGE_OUTPUT_REG_2 0x22F6
#define A3XX_SP_FS_IMAGE_OUTPUT_REG_3 0x22F7
#define A3XX_SP_FS_LENGTH_REG 0x22FF
#define A3XX_TPL1_TP_VS_TEX_OFFSET 0x2340
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index b964620..2a6fe62 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -71,6 +71,8 @@
| (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \
| (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
static const struct kgsl_functable adreno_functable;
static struct adreno_device device_3d0 = {
@@ -100,6 +102,13 @@
.iomemname = KGSL_3D0_REG_MEMORY,
.shadermemname = KGSL_3D0_SHADER_MEMORY,
.ftbl = &adreno_functable,
+ .cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+ .ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+ .drv_log = KGSL_LOG_LEVEL_DEFAULT,
+ .mem_log = KGSL_LOG_LEVEL_DEFAULT,
+ .pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+ .ft_log = KGSL_LOG_LEVEL_DEFAULT,
+ .pm_dump_enable = 0,
},
.gmem_base = 0,
.gmem_size = SZ_256K,
@@ -117,13 +126,7 @@
* If the values of these registers are same after
* KGSL_TIMEOUT_PART time, GPU hang is reported in
* kernel log.
- * *****ALERT******ALERT********ALERT*************
- * Order of registers below is important, registers
- * from LONG_IB_DETECT_REG_INDEX_START to
- * LONG_IB_DETECT_REG_INDEX_END are used in long ib detection.
*/
-#define LONG_IB_DETECT_REG_INDEX_START 1
-#define LONG_IB_DETECT_REG_INDEX_END 5
unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT];
@@ -631,36 +634,44 @@
kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
+ kgsl_mmu_unmap(pagetable, &adreno_dev->pwron_fixup);
+
kgsl_mmu_unmap(pagetable, &device->mmu.setstate_memory);
}
static int adreno_setup_pt(struct kgsl_device *device,
struct kgsl_pagetable *pagetable)
{
- int result = 0;
+ int result;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
result = kgsl_mmu_map_global(pagetable, &rb->buffer_desc);
- if (result)
- goto error;
- result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
- if (result)
- goto unmap_buffer_desc;
+ if (!result)
+ result = kgsl_mmu_map_global(pagetable, &rb->memptrs_desc);
- result = kgsl_mmu_map_global(pagetable, &device->memstore);
- if (result)
- goto unmap_memptrs_desc;
+ if (!result)
+ result = kgsl_mmu_map_global(pagetable, &device->memstore);
- result = kgsl_mmu_map_global(pagetable,
- &adreno_dev->profile.shared_buffer);
- if (result)
- goto unmap_profile_shared;
+ if (!result)
+ result = kgsl_mmu_map_global(pagetable,
+ &adreno_dev->profile.shared_buffer);
- result = kgsl_mmu_map_global(pagetable, &device->mmu.setstate_memory);
- if (result)
- goto unmap_memstore_desc;
+ if (!result)
+ result = kgsl_mmu_map_global(pagetable,
+ &adreno_dev->pwron_fixup);
+
+
+ if (!result)
+ result = kgsl_mmu_map_global(pagetable,
+ &device->mmu.setstate_memory);
+
+ if (result) {
+ /* On error clean up what we have wrought */
+ adreno_cleanup_pt(device, pagetable);
+ return result;
+ }
/*
* Set the mpu end to the last "normal" global memory we use.
@@ -669,22 +680,8 @@
*/
device->mh.mpu_range = device->mmu.setstate_memory.gpuaddr +
device->mmu.setstate_memory.size;
- return result;
-unmap_profile_shared:
- kgsl_mmu_unmap(pagetable, &adreno_dev->profile.shared_buffer);
-
-unmap_memstore_desc:
- kgsl_mmu_unmap(pagetable, &device->memstore);
-
-unmap_memptrs_desc:
- kgsl_mmu_unmap(pagetable, &rb->memptrs_desc);
-
-unmap_buffer_desc:
- kgsl_mmu_unmap(pagetable, &rb->buffer_desc);
-
-error:
- return result;
+ return 0;
}
static unsigned int _adreno_iommu_setstate_v0(struct kgsl_device *device,
@@ -1693,6 +1690,10 @@
/* Power down the device */
kgsl_pwrctrl_disable(device);
+ /* Certain targets need the fixup. You know who you are */
+ if (adreno_is_a330v2(adreno_dev))
+ adreno_a3xx_pwron_fixup_init(adreno_dev);
+
return 0;
}
@@ -1715,6 +1716,9 @@
/* Power up the device */
kgsl_pwrctrl_enable(device);
+ /* Set the bit to indicate that we've just powered on */
+ set_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv);
+
/* Set up a2xx special case */
if (adreno_is_a2xx(adreno_dev)) {
/*
@@ -3326,6 +3330,9 @@
if (kgsl_gpuaddr_in_memdesc(&device->memstore, gpuaddr, size))
return &device->memstore;
+ if (kgsl_gpuaddr_in_memdesc(&adreno_dev->pwron_fixup, gpuaddr, size))
+ return &adreno_dev->pwron_fixup;
+
if (kgsl_gpuaddr_in_memdesc(&device->mmu.setstate_memory, gpuaddr,
size))
return &device->mmu.setstate_memory;
@@ -3553,7 +3560,6 @@
struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
unsigned int fast_hang_detected = 1;
- unsigned int long_ib_detected = 1;
unsigned int i;
static unsigned long next_hang_detect_time;
static unsigned int prev_global_ts;
@@ -3566,9 +3572,6 @@
if (!adreno_dev->fast_hang_detect)
fast_hang_detected = 0;
- if (!adreno_dev->long_ib_detect)
- long_ib_detected = 0;
-
if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
return 0;
@@ -3653,17 +3656,8 @@
}
}
for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
- if (curr_reg_val[i] != prev_reg_val[i]) {
+ if (curr_reg_val[i] != prev_reg_val[i])
fast_hang_detected = 0;
-
- /* Check for long IB here */
- if ((i >=
- LONG_IB_DETECT_REG_INDEX_START)
- &&
- (i <=
- LONG_IB_DETECT_REG_INDEX_END))
- long_ib_detected = 0;
- }
}
if (fast_hang_detected) {
@@ -3685,15 +3679,12 @@
pid_name, curr_context->ib_gpu_time_used,
curr_global_ts+1);
- if ((long_ib_detected) &&
+ if ((adreno_dev->long_ib_detect) &&
(!(curr_context->flags &
- CTXT_FLAGS_NO_FAULT_TOLERANCE))) {
- curr_context->ib_gpu_time_used +=
- KGSL_TIMEOUT_PART;
- if (curr_context->ib_gpu_time_used >
- KGSL_TIMEOUT_LONG_IB_DETECTION) {
- if (adreno_dev->long_ib_ts !=
- curr_global_ts) {
+ CTXT_FLAGS_NO_FAULT_TOLERANCE)) &&
+ (curr_context->ib_gpu_time_used >
+ KGSL_TIMEOUT_LONG_IB_DETECTION) &&
+ (adreno_dev->long_ib_ts != curr_global_ts)) {
KGSL_FT_ERR(device,
"Proc %s, ctxt_id %d ts %d"
"used GPU for %d ms long ib "
@@ -3710,8 +3701,6 @@
curr_context->ib_gpu_time_used =
0;
return 1;
- }
- }
}
}
} else {
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 72f15e7..9a070a6 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -40,6 +40,7 @@
#define KGSL_CMD_FLAGS_INTERNAL_ISSUE 0x00000002
#define KGSL_CMD_FLAGS_GET_INT 0x00000004
#define KGSL_CMD_FLAGS_PROFILE 0x00000008
+#define KGSL_CMD_FLAGS_PWRON_FIXUP 0x00000010
#define KGSL_CMD_FLAGS_EOF 0x00000100
/* Command identifiers */
@@ -52,6 +53,7 @@
#define KGSL_NOP_IB_IDENTIFIER 0x20F20F20
#define KGSL_START_OF_PROFILE_IDENTIFIER 0x2DEFADE1
#define KGSL_END_OF_PROFILE_IDENTIFIER 0x2DEFADE2
+#define KGSL_PWRON_FIXUP_IDENTIFIER 0x2AFAFAFA
#ifdef CONFIG_MSM_SCM
#define ADRENO_DEFAULT_PWRSCALE_POLICY (&kgsl_pwrscale_policy_tz)
@@ -100,6 +102,7 @@
struct adreno_device {
struct kgsl_device dev; /* Must be first field in this struct */
+ unsigned long priv;
unsigned int chip_id;
enum adreno_gpurev gpurev;
unsigned long gmem_base;
@@ -136,6 +139,19 @@
unsigned int ocmem_base;
unsigned int gpu_cycles;
struct adreno_profile profile;
+ struct kgsl_memdesc pwron_fixup;
+ unsigned int pwron_fixup_dwords;
+};
+
+/**
+ * enum adreno_device_flags - Private flags for the adreno_device
+ * @ADRENO_DEVICE_PWRON - Set during init after a power collapse
+ * @ADRENO_DEVICE_PWRON_FIXUP - Set if the target requires the shader fixup
+ * after power collapse
+ */
+enum adreno_device_flags {
+ ADRENO_DEVICE_PWRON = 0,
+ ADRENO_DEVICE_PWRON_FIXUP = 1,
};
#define PERFCOUNTER_FLAG_NONE 0x0
@@ -436,6 +452,7 @@
int adreno_soft_reset(struct kgsl_device *device);
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev);
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index d96965c..f9110ea 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2510,6 +2510,478 @@
}
}
+static const unsigned int _a3xx_pwron_fixup_fs_instructions[] = {
+ 0x00000000, 0x302CC300, 0x00000000, 0x302CC304,
+ 0x00000000, 0x302CC308, 0x00000000, 0x302CC30C,
+ 0x00000000, 0x302CC310, 0x00000000, 0x302CC314,
+ 0x00000000, 0x302CC318, 0x00000000, 0x302CC31C,
+ 0x00000000, 0x302CC320, 0x00000000, 0x302CC324,
+ 0x00000000, 0x302CC328, 0x00000000, 0x302CC32C,
+ 0x00000000, 0x302CC330, 0x00000000, 0x302CC334,
+ 0x00000000, 0x302CC338, 0x00000000, 0x302CC33C,
+ 0x00000000, 0x00000400, 0x00020000, 0x63808003,
+ 0x00060004, 0x63828007, 0x000A0008, 0x6384800B,
+ 0x000E000C, 0x6386800F, 0x00120010, 0x63888013,
+ 0x00160014, 0x638A8017, 0x001A0018, 0x638C801B,
+ 0x001E001C, 0x638E801F, 0x00220020, 0x63908023,
+ 0x00260024, 0x63928027, 0x002A0028, 0x6394802B,
+ 0x002E002C, 0x6396802F, 0x00320030, 0x63988033,
+ 0x00360034, 0x639A8037, 0x003A0038, 0x639C803B,
+ 0x003E003C, 0x639E803F, 0x00000000, 0x00000400,
+ 0x00000003, 0x80D60003, 0x00000007, 0x80D60007,
+ 0x0000000B, 0x80D6000B, 0x0000000F, 0x80D6000F,
+ 0x00000013, 0x80D60013, 0x00000017, 0x80D60017,
+ 0x0000001B, 0x80D6001B, 0x0000001F, 0x80D6001F,
+ 0x00000023, 0x80D60023, 0x00000027, 0x80D60027,
+ 0x0000002B, 0x80D6002B, 0x0000002F, 0x80D6002F,
+ 0x00000033, 0x80D60033, 0x00000037, 0x80D60037,
+ 0x0000003B, 0x80D6003B, 0x0000003F, 0x80D6003F,
+ 0x00000000, 0x03000000, 0x00000000, 0x00000000,
+};
+
+/**
+ * adreno_a3xx_pwron_fixup_init() - Initalize a special command buffer to run a
+ * post-power collapse shader workaround
+ * @adreno_dev: Pointer to a adreno_device struct
+ *
+ * Some targets require a special workaround shader to be executed after
+ * power-collapse. Construct the IB once at init time and keep it
+ * handy
+ *
+ * Returns: 0 on success or negative on error
+ */
+int adreno_a3xx_pwron_fixup_init(struct adreno_device *adreno_dev)
+{
+ unsigned int *cmds;
+ int count = ARRAY_SIZE(_a3xx_pwron_fixup_fs_instructions);
+ int ret;
+
+ /* Return if the fixup is already in place */
+ if (test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+ return 0;
+
+ ret = kgsl_allocate_contiguous(&adreno_dev->pwron_fixup, PAGE_SIZE);
+
+ if (ret)
+ return ret;
+
+ adreno_dev->pwron_fixup.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
+ cmds = adreno_dev->pwron_fixup.hostptr;
+
+ *cmds++ = cp_type0_packet(A3XX_UCHE_CACHE_INVALIDATE0_REG, 2);
+ *cmds++ = 0x00000000;
+ *cmds++ = 0x90000000;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+ *cmds++ = A3XX_RBBM_CLOCK_CTL;
+ *cmds++ = 0xFFFCFFFF;
+ *cmds++ = 0x00010000;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+ *cmds++ = 0x1E000150;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+ *cmds++ = 0x1E000150;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+ *cmds++ = 0x1E000150;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_1_REG, 1);
+ *cmds++ = 0x00000040;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_2_REG, 1);
+ *cmds++ = 0x80000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_3_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_VS_CONTROL_REG, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_FS_CONTROL_REG, 1);
+ *cmds++ = 0x0D001002;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_VSPRESV_RANGE_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONST_FSPRESV_RANGE_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_0_REG, 1);
+ *cmds++ = 0x00401101;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_1_REG, 1);
+ *cmds++ = 0x00000400;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_2_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_3_REG, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_4_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_5_REG, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_NDRANGE_6_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_1_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_CONST_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_X_REG, 1);
+ *cmds++ = 0x00000010;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_WG_OFFSET_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_SP_CTRL_REG, 1);
+ *cmds++ = 0x00040000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG0, 1);
+ *cmds++ = 0x0000000A;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_CTRL_REG1, 1);
+ *cmds++ = 0x00000001;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PARAM_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_4, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_5, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_6, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OUT_REG_7, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_VPC_DST_REG_3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_OFFSET_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_OBJ_START_REG, 1);
+ *cmds++ = 0x00000004;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_PARAM_REG, 1);
+ *cmds++ = 0x04008001;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_ADDR_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_VS_LENGTH_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG0, 1);
+ *cmds++ = 0x0DB0400A;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_CTRL_REG1, 1);
+ *cmds++ = 0x00300402;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_OFFSET_REG, 1);
+ *cmds++ = 0x00010000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_OBJ_START_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_PARAM_REG, 1);
+ *cmds++ = 0x04008001;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_ADDR_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_PVT_MEM_SIZE_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_FLAT_SHAD_MODE_REG_1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_OUTPUT_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_MRT_REG_3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_IMAGE_OUTPUT_REG_3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_SP_FS_LENGTH_REG, 1);
+ *cmds++ = 0x0000000D;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_CLIP_CNTL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_GB_CLIP_ADJ, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XOFFSET, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_XSCALE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YOFFSET, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_YSCALE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZOFFSET, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_VPORT_ZSCALE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X4, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y4, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z4, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W4, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_X5, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Y5, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_Z5, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_CL_USER_PLANE_W5, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_MINMAX, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SU_POINT_SIZE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_OFFSET, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SU_POLY_OFFSET_SCALE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SU_MODE_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SC_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_TL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SC_SCREEN_SCISSOR_BR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_BR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_SC_WINDOW_SCISSOR_TL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_TSE_DEBUG_ECO, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER1_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER2_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_GRAS_PERFCOUNTER3_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MODE_CONTROL, 1);
+ *cmds++ = 0x00008000;
+ *cmds++ = cp_type0_packet(A3XX_RB_RENDER_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MSAA_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_ALPHA_REFERENCE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_CONTROL3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_INFO3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BUF_BASE3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_MRT_BLEND_CONTROL3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_BLEND_RED, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_BLEND_GREEN, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_BLEND_BLUE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_BLEND_ALPHA, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW0, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW1, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW2, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_CLEAR_COLOR_DW3, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_COPY_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_BASE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_PITCH, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_COPY_DEST_INFO, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_DEPTH_CLEAR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_INFO, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_DEPTH_BUF_PITCH, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_CLEAR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_INFO, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_BUF_PITCH, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_STENCIL_REF_MASK_BF, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_LRZ_VSC_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_WINDOW_OFFSET, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_CONTROL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_SAMPLE_COUNT_ADDR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MIN, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_Z_CLAMP_MAX, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_GMEM_BASE_ADDR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_DEBUG_ECO_CONTROLS_ADDR, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER0_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_PERFCOUNTER1_SELECT, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_RB_FRAME_BUFFER_DIMENSION, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+ *cmds++ = (1 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+ (0 << CP_LOADSTATE_STATESRC_SHIFT) |
+ (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+ (1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+ *cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT) |
+ (0 << CP_LOADSTATE_EXTSRCADDR_SHIFT);
+ *cmds++ = 0x00400000;
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+ *cmds++ = (2 << CP_LOADSTATE_DSTOFFSET_SHIFT) |
+ (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+ (1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+ *cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+ *cmds++ = 0x00400220;
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_LOAD_STATE, 4);
+ *cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+ (1 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+ *cmds++ = (1 << CP_LOADSTATE_STATETYPE_SHIFT);
+ *cmds++ = 0x00000000;
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_LOAD_STATE, 2 + count);
+ *cmds++ = (6 << CP_LOADSTATE_STATEBLOCKID_SHIFT) |
+ (13 << CP_LOADSTATE_NUMOFUNITS_SHIFT);
+ *cmds++ = 0x00000000;
+
+ memcpy(cmds, _a3xx_pwron_fixup_fs_instructions, count << 2);
+
+ cmds += count;
+
+ *cmds++ = cp_type3_packet(CP_EXEC_CL, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CL_CONTROL_0_REG, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type0_packet(A3XX_HLSQ_CONTROL_0_REG, 1);
+ *cmds++ = 0x1E000150;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
+ *cmds++ = 0x1E000050;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_REG_RMW, 3);
+ *cmds++ = A3XX_RBBM_CLOCK_CTL;
+ *cmds++ = 0xFFFCFFFF;
+ *cmds++ = 0x00000000;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+
+ /*
+ * Remember the number of dwords in the command buffer for when we
+ * program the indirect buffer call in the ringbuffer
+ */
+ adreno_dev->pwron_fixup_dwords =
+ (cmds - (unsigned int *) adreno_dev->pwron_fixup.hostptr);
+
+ /* Mark the flag in ->priv to show that we have the fix */
+ set_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv);
+ return 0;
+}
+
static int a3xx_rb_init(struct adreno_device *adreno_dev,
struct adreno_ringbuffer *rb)
{
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index f449870..d1e2b43 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -177,6 +177,8 @@
/* Load a buffer with pre-fetch enabled */
#define CP_INDIRECT_BUFFER_PFE 0x3F
+#define CP_EXEC_CL 0x31
+
#define CP_LOADSTATE_DSTOFFSET_SHIFT 0x00000000
#define CP_LOADSTATE_STATESRC_SHIFT 0x00000010
#define CP_LOADSTATE_STATEBLOCKID_SHIFT 0x00000013
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index b8cf21f..947324b 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -644,6 +644,10 @@
if (profile_ready)
total_sizedwords += 6; /* space for pre_ib and post_ib */
+ /* Add space for the power on shader fixup if we need it */
+ if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP)
+ total_sizedwords += 5;
+
ringcmds = adreno_ringbuffer_allocspace(rb, context, total_sizedwords);
if (!ringcmds)
return -ENOSPC;
@@ -660,6 +664,18 @@
KGSL_CMD_INTERNAL_IDENTIFIER);
}
+ if (flags & KGSL_CMD_FLAGS_PWRON_FIXUP) {
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu, cp_nop_packet(1));
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ KGSL_PWRON_FIXUP_IDENTIFIER);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ CP_HDR_INDIRECT_BUFFER_PFD);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ adreno_dev->pwron_fixup.gpuaddr);
+ GSL_RB_WRITE(rb->device, ringcmds, rcmd_gpu,
+ adreno_dev->pwron_fixup_dwords);
+ }
+
/* Add any IB required for profiling if it is enabled */
if (profile_ready)
adreno_profile_preib_processing(rb->device, context->base.id,
@@ -1143,6 +1159,10 @@
adreno_drawctxt_switch(adreno_dev, drawctxt, flags);
+ if (test_and_clear_bit(ADRENO_DEVICE_PWRON, &adreno_dev->priv) &&
+ test_bit(ADRENO_DEVICE_PWRON_FIXUP, &adreno_dev->priv))
+ flags |= KGSL_CMD_FLAGS_PWRON_FIXUP;
+
if (drawctxt->flags & CTXT_FLAGS_USER_GENERATED_TS) {
if (timestamp_cmp(drawctxt->timestamp, *timestamp) >= 0) {
KGSL_DRV_ERR(device,
@@ -1158,7 +1178,7 @@
ret = adreno_ringbuffer_addcmds(&adreno_dev->ringbuffer,
drawctxt,
- (flags & KGSL_CMD_FLAGS_EOF),
+ flags,
&link[0], (cmds - link));
if (ret)
goto done;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 9ab8d22..e623515 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -19,7 +19,6 @@
#include "kgsl_sharedmem.h"
/*default log levels is error for everything*/
-#define KGSL_LOG_LEVEL_DEFAULT 3
#define KGSL_LOG_LEVEL_MAX 7
struct dentry *kgsl_debugfs_dir;
@@ -180,13 +179,6 @@
if (!device->d_debugfs || IS_ERR(device->d_debugfs))
return;
- device->cmd_log = KGSL_LOG_LEVEL_DEFAULT;
- device->ctxt_log = KGSL_LOG_LEVEL_DEFAULT;
- device->drv_log = KGSL_LOG_LEVEL_DEFAULT;
- device->mem_log = KGSL_LOG_LEVEL_DEFAULT;
- device->pwr_log = KGSL_LOG_LEVEL_DEFAULT;
- device->ft_log = KGSL_LOG_LEVEL_DEFAULT;
-
debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
&cmd_log_fops);
debugfs_create_file("log_level_ctxt", 0644, device->d_debugfs, device,
@@ -215,7 +207,6 @@
&pm_regs_enabled_fops);
debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
&pm_ib_enabled_fops);
- device->pm_dump_enable = 0;
debugfs_create_file("enable", 0644, pm_d_debugfs, device,
&pm_enabled_fops);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 1a95761..6faf0bf 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1442,6 +1442,8 @@
case KGSL_STATE_ACTIVE:
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
break;
+ case KGSL_STATE_INIT:
+ break;
default:
KGSL_PWR_WARN(device, "unhandled state %s\n",
kgsl_pwrstate_to_str(device->state));
@@ -1537,10 +1539,13 @@
if ((atomic_read(&device->active_cnt) == 0) &&
(device->state != KGSL_STATE_ACTIVE)) {
- mutex_unlock(&device->mutex);
- wait_for_completion(&device->hwaccess_gate);
- wait_for_completion(&device->ft_gate);
- mutex_lock(&device->mutex);
+
+ if (device->state != KGSL_STATE_DUMP_AND_FT) {
+ mutex_unlock(&device->mutex);
+ wait_for_completion(&device->hwaccess_gate);
+ wait_for_completion(&device->ft_gate);
+ mutex_lock(&device->mutex);
+ }
/* Stop the idle timer */
del_timer_sync(&device->idle_timer);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index 883417f..103a751 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -124,6 +124,8 @@
| (MMU_CONFIG << MH_MMU_CONFIG__TC_R_CLNT_BEHAVIOR__SHIFT) \
| (MMU_CONFIG << MH_MMU_CONFIG__PA_W_CLNT_BEHAVIOR__SHIFT))
+#define KGSL_LOG_LEVEL_DEFAULT 3
+
static const struct kgsl_functable z180_functable;
static struct z180_device device_2d0 = {
@@ -149,6 +151,13 @@
},
.iomemname = KGSL_2D0_REG_MEMORY,
.ftbl = &z180_functable,
+ .cmd_log = KGSL_LOG_LEVEL_DEFAULT,
+ .ctxt_log = KGSL_LOG_LEVEL_DEFAULT,
+ .drv_log = KGSL_LOG_LEVEL_DEFAULT,
+ .mem_log = KGSL_LOG_LEVEL_DEFAULT,
+ .pwr_log = KGSL_LOG_LEVEL_DEFAULT,
+ .ft_log = KGSL_LOG_LEVEL_DEFAULT,
+ .pm_dump_enable = 0,
},
.cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
};
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index 2a5fea7..385947f 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -32,14 +32,12 @@
#define SHOW_PROGRESS
#define MAX_FIRMWARE_ID_LEN 10
#define FORCE_UPDATE false
+#define DO_LOCKDOWN false
#define INSIDE_FIRMWARE_UPDATE
#define FW_IMAGE_OFFSET 0x100
-
-#define BOOTLOADER_ID_OFFSET 0
-#define FLASH_PROPERTIES_OFFSET 2
-#define BLOCK_SIZE_OFFSET 3
-#define FW_BLOCK_COUNT_OFFSET 5
+/* 0 to ignore flash block check to speed up flash time */
+#define CHECK_FLASH_BLOCK_STATUS 1
#define REG_MAP (1 << 0)
#define UNLOCKED (1 << 1)
@@ -49,9 +47,6 @@
#define HAS_DISP_CONFIG (1 << 5)
#define HAS_CTRL1 (1 << 6)
-#define BLOCK_NUMBER_OFFSET 0
-#define BLOCK_DATA_OFFSET 2
-
#define RMI4_INFO_MAX_LEN 200
#define RMI4_STORE_TS_INFO(buf, id, rev, fw_ver) \
@@ -70,6 +65,7 @@
enum flash_command {
CMD_WRITE_FW_BLOCK = 0x2,
CMD_ERASE_ALL = 0x3,
+ CMD_WRITE_LOCKDOWN_BLOCK = 0x4,
CMD_READ_CONFIG_BLOCK = 0x5,
CMD_WRITE_CONFIG_BLOCK = 0x6,
CMD_ERASE_CONFIG = 0x7,
@@ -91,6 +87,23 @@
OPTION_CONTAIN_BOOTLOADER = 1,
};
+enum flash_offset {
+ OFFSET_BOOTLOADER_ID,
+ OFFSET_FLASH_PROPERTIES,
+ OFFSET_BLOCK_SIZE,
+ OFFSET_FW_BLOCK_COUNT,
+ OFFSET_BLOCK_NUMBER,
+ OFFSET_BLOCK_DATA,
+ OFFSET_FLASH_CONTROL,
+ OFFSET_FLASH_STATUS
+};
+
+enum flash_update_mode {
+ NORMAL = 1,
+ FORCE = 2,
+ LOCKDOWN = 8
+};
+
#define SLEEP_MODE_NORMAL (0x00)
#define SLEEP_MODE_SENSOR_SLEEP (0x01)
#define SLEEP_MODE_RESERVED0 (0x02)
@@ -101,9 +114,7 @@
#define ERASE_WAIT_MS (5 * 1000)
#define RESET_WAIT_MS (500)
-#define POLLING_MODE 0
-
-#define SLEEP_TIME_US 50
+#define SLEEP_TIME_US 100
static int fwu_wait_for_idle(int timeout_ms);
@@ -141,7 +152,8 @@
};
};
-struct image_header {
+struct image_content {
+ bool is_contain_build_info;
unsigned int checksum;
unsigned int image_size;
unsigned int config_size;
@@ -152,7 +164,10 @@
u16 package_id;
u16 package_revision_id;
unsigned int firmware_id;
- bool is_contain_build_info;
+ const unsigned char *firmware_data;
+ const unsigned char *config_data;
+ const unsigned char *lockdown_data;
+ unsigned short lockdown_block_count;
};
struct pdt_properties {
@@ -194,11 +209,28 @@
struct f34_flash_control {
union {
+ /* version 0 */
struct {
- unsigned char command:4;
+ unsigned char command_v0:4;
unsigned char status:3;
unsigned char program_enabled:1;
} __packed;
+ /* version 1 */
+ struct {
+ unsigned char command_v1:6;
+ unsigned char reserved:2;
+ } __packed;
+ unsigned char data[1];
+ };
+};
+
+struct f34_flash_status {
+ union {
+ struct {
+ unsigned char status:6;
+ unsigned char reserved:1;
+ unsigned char program_enabled:1;
+ } __packed;
unsigned char data[1];
};
};
@@ -222,6 +254,9 @@
struct synaptics_rmi4_fwu_handle {
bool initialized;
bool force_update;
+ bool do_lockdown;
+ bool interrupt_flag;
+ bool polling_mode;
char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
unsigned int image_size;
unsigned int data_pos;
@@ -233,31 +268,33 @@
unsigned char *read_config_buf;
const unsigned char *firmware_data;
const unsigned char *config_data;
+ const unsigned char *lockdown_data;
unsigned short block_size;
unsigned short fw_block_count;
unsigned short config_block_count;
+ unsigned short lockdown_block_count;
unsigned short perm_config_block_count;
unsigned short bl_config_block_count;
unsigned short disp_config_block_count;
unsigned short config_size;
unsigned short config_area;
- unsigned short addr_f34_flash_control;
unsigned short addr_f01_interrupt_register;
+ const unsigned char *data_buffer;
struct synaptics_rmi4_fn_desc f01_fd;
struct synaptics_rmi4_fn_desc f34_fd;
struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
struct synaptics_rmi4_data *rmi4_data;
- struct f34_flash_control flash_control;
struct f34_flash_properties flash_properties;
struct workqueue_struct *fwu_workqueue;
struct delayed_work fwu_work;
- char firmware_name[NAME_BUFFER_SIZE];
+ char image_name[NAME_BUFFER_SIZE];
+ struct image_content image_content;
char *ts_info;
};
static struct synaptics_rmi4_fwu_handle *fwu;
-static struct completion remove_complete;
+DECLARE_COMPLETION(fwu_remove_complete);
static unsigned int extract_uint(const unsigned char *ptr)
{
@@ -295,42 +332,80 @@
pkg_id[3] << 8 | pkg_id[2], build_id);
}
-static void parse_header(struct image_header *header,
- const unsigned char *fw_image)
+static void parse_header(void)
{
- struct image_header_data *data = (struct image_header_data *)fw_image;
- header->checksum = extract_uint(data->file_checksum);
- header->bootloader_version = data->bootloader_version;
- header->image_size = extract_uint(data->firmware_size);
- header->config_size = extract_uint(data->config_size);
- memcpy(header->product_id, data->product_id,
+ struct image_content *img = &fwu->image_content;
+ struct image_header_data *data =
+ (struct image_header_data *)fwu->data_buffer;
+ img->checksum = extract_uint(data->file_checksum);
+ img->bootloader_version = data->bootloader_version;
+ img->image_size = extract_uint(data->firmware_size);
+ img->config_size = extract_uint(data->config_size);
+ memcpy(img->product_id, data->product_id,
sizeof(data->product_id));
- header->product_id[sizeof(data->product_id)] = 0;
+ img->product_id[sizeof(data->product_id)] = 0;
- memcpy(header->product_info, data->product_info,
+ img->product_id[sizeof(data->product_info)] = 0;
+ memcpy(img->product_info, data->product_info,
sizeof(data->product_info));
- header->is_contain_build_info =
+ img->is_contain_build_info =
(data->options_firmware_id == (1 << OPTION_BUILD_INFO));
- if (header->is_contain_build_info) {
- header->package_id = (data->pkg_id_rev_msb << 8) |
+
+ if (img->is_contain_build_info) {
+ img->firmware_id = extract_uint(data->firmware_id);
+ img->package_id = (data->pkg_id_rev_msb << 8) |
data->pkg_id_lsb;
- header->package_revision_id = (data->pkg_id_rev_msb << 8) |
+ img->package_revision_id = (data->pkg_id_rev_msb << 8) |
data->pkg_id_rev_lsb;
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s Package ID %d Rev %d\n", __func__,
- header->package_id, header->package_revision_id);
+ img->package_id, img->package_revision_id);
- header->firmware_id = extract_uint(data->firmware_id);
+ img->firmware_id = extract_uint(data->firmware_id);
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s Firwmare build id %d\n", __func__,
- header->firmware_id);
+ img->firmware_id);
}
dev_dbg(&fwu->rmi4_data->i2c_client->dev,
"Firwmare size %d, config size %d\n",
- header->image_size,
- header->config_size);
+ img->image_size,
+ img->config_size);
+
+ /* get UI firmware offset */
+ if (img->image_size)
+ img->firmware_data = fwu->data_buffer + FW_IMAGE_OFFSET;
+ /* get config offset*/
+ if (img->config_size)
+ img->config_data = fwu->data_buffer + FW_IMAGE_OFFSET +
+ img->image_size;
+ /* get lockdown offset*/
+ switch (img->bootloader_version) {
+ case 3:
+ case 4:
+ img->lockdown_block_count = 4;
+ break;
+ case 5:
+ case 6:
+ img->lockdown_block_count = 5;
+ break;
+ default:
+ dev_warn(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Not support lockdown in " \
+ "bootloader version V%d\n",
+ __func__, img->bootloader_version);
+ img->lockdown_data = NULL;
+ }
+
+ img->lockdown_data = fwu->data_buffer +
+ FW_IMAGE_OFFSET -
+ img->lockdown_block_count * fwu->block_size;
+
+ fwu->lockdown_block_count = img->lockdown_block_count;
+ fwu->lockdown_data = img->lockdown_data;
+ fwu->config_data = img->config_data;
+ fwu->firmware_data = img->firmware_data;
return;
}
@@ -352,6 +427,62 @@
return 0;
}
+static unsigned short fwu_get_address(enum flash_offset type)
+{
+ int offset;
+ unsigned short addr = 0;
+ struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
+
+ switch (type) {
+ case OFFSET_BOOTLOADER_ID:
+ offset = 0;
+ addr = fwu->f34_fd.query_base_addr + offset;
+ break;
+ case OFFSET_FLASH_PROPERTIES:
+ offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+ addr = fwu->f34_fd.query_base_addr + offset;
+ break;
+ case OFFSET_BLOCK_SIZE:
+ offset = ((fwu->f34_fd.version == 0) ? 3 : 2);
+ addr = fwu->f34_fd.query_base_addr + offset;
+ break;
+ case OFFSET_FW_BLOCK_COUNT:
+ offset = ((fwu->f34_fd.version == 0) ? 5 : 3);
+ addr = fwu->f34_fd.query_base_addr + offset;
+ break;
+ case OFFSET_BLOCK_NUMBER:
+ offset = 0;
+ addr = fwu->f34_fd.data_base_addr + offset;
+ break;
+ case OFFSET_BLOCK_DATA:
+ offset = ((fwu->f34_fd.version == 0) ? 2 : 1);
+ addr = fwu->f34_fd.data_base_addr + offset;
+ break;
+ case OFFSET_FLASH_CONTROL:
+ offset = ((fwu->f34_fd.version == 0) ?
+ 2 + (fwu->block_size) : 2);
+ addr = fwu->f34_fd.data_base_addr + offset;
+ break;
+ case OFFSET_FLASH_STATUS:
+ if (fwu->f34_fd.version == 1) {
+ offset = 3;
+ addr = fwu->f34_fd.data_base_addr + offset;
+ } else if (fwu->f34_fd.version == 0) {
+ dev_warn(&i2c_client->dev,
+ "%s: F$34 version 0 does not contain " \
+ "flash status register\n",
+ __func__);
+ }
+ break;
+ default:
+ dev_err(&i2c_client->dev,
+ "%s: Unknown flash offset (%d)\n",
+ __func__, type);
+ break;
+ }
+ return addr;
+}
+
static int fwu_read_f34_queries(void)
{
int retval;
@@ -360,7 +491,7 @@
struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->f34_fd.query_base_addr + BOOTLOADER_ID_OFFSET,
+ fwu_get_address(OFFSET_BOOTLOADER_ID),
fwu->bootloader_id,
sizeof(fwu->bootloader_id));
if (retval < 0) {
@@ -371,7 +502,7 @@
}
retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->f34_fd.query_base_addr + FLASH_PROPERTIES_OFFSET,
+ fwu_get_address(OFFSET_FLASH_PROPERTIES),
fwu->flash_properties.data,
sizeof(fwu->flash_properties.data));
if (retval < 0) {
@@ -397,7 +528,7 @@
count += 2;
retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->f34_fd.query_base_addr + BLOCK_SIZE_OFFSET,
+ fwu_get_address(OFFSET_BLOCK_SIZE),
buf,
2);
if (retval < 0) {
@@ -410,13 +541,13 @@
batohs(&fwu->block_size, &(buf[0]));
retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->f34_fd.query_base_addr + FW_BLOCK_COUNT_OFFSET,
+ fwu_get_address(OFFSET_FW_BLOCK_COUNT),
buf,
count);
if (retval < 0) {
dev_err(&i2c_client->dev,
- "%s: Failed to read block count info\n",
- __func__);
+ "%s: Failed to read block count info\n",
+ __func__);
return retval;
}
@@ -438,9 +569,6 @@
if (fwu->flash_properties.has_display_config)
batohs(&fwu->disp_config_block_count, &(buf[count]));
- fwu->addr_f34_flash_control = fwu->f34_fd.data_base_addr +
- BLOCK_DATA_OFFSET +
- fwu->block_size;
return 0;
}
@@ -461,18 +589,36 @@
return interrupt_status;
}
-static int fwu_read_f34_flash_status(void)
+static int fwu_read_f34_flash_status(unsigned char *status)
{
int retval;
- retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->addr_f34_flash_control,
- fwu->flash_control.data,
- sizeof(fwu->flash_control.data));
- if (retval < 0) {
- dev_err(&fwu->rmi4_data->i2c_client->dev,
+ struct f34_flash_control flash_control;
+ struct f34_flash_status flash_status;
+
+ if (fwu->f34_fd.version == 1) {
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu_get_address(OFFSET_FLASH_STATUS),
+ flash_status.data,
+ sizeof(flash_status.data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Failed to read flash status\n",
__func__);
- return retval;
+ return -EIO;
+ }
+ *status = flash_status.status;
+ } else {
+ retval = fwu->fn_ptr->read(fwu->rmi4_data,
+ fwu_get_address(OFFSET_FLASH_CONTROL),
+ flash_control.data,
+ sizeof(flash_control.data));
+ if (retval < 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Failed to read flash status\n",
+ __func__);
+ return -EIO;
+ }
+ *status = flash_control.status;
}
return 0;
}
@@ -492,22 +638,27 @@
__func__);
return retval;
}
+
+ fwu->polling_mode = false;
+
return 0;
}
static int fwu_write_f34_command(unsigned char cmd)
{
int retval;
+ struct f34_flash_control flash_control;
- fwu->flash_control.data[0] = cmd;
+ flash_control.data[0] = cmd;
+ fwu->interrupt_flag = false;
retval = fwu->fn_ptr->write(fwu->rmi4_data,
- fwu->addr_f34_flash_control,
- fwu->flash_control.data,
- sizeof(fwu->flash_control.data));
+ fwu_get_address(OFFSET_FLASH_CONTROL),
+ flash_control.data,
+ sizeof(flash_control.data));
if (retval < 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Failed to write command 0x%02x\n",
- __func__, fwu->flash_control.data[0]);
+ __func__, flash_control.data[0]);
return retval;
}
return 0;
@@ -518,18 +669,21 @@
int count = 0;
int timeout_count = ((timeout_ms * 1000) / SLEEP_TIME_US) + 1;
do {
- #if POLLING_MODE
- fwu_read_f34_flash_status();
- #endif
- if (fwu->flash_control.command == 0x00)
+ if (fwu->interrupt_flag)
return 0;
-
- usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 100);
+ if (fwu->polling_mode)
+ if (fwu->intr_mask & fwu_read_interrupt_status())
+ return 0;
+ usleep_range(SLEEP_TIME_US, SLEEP_TIME_US + 1);
} while (count++ < timeout_count);
- fwu_read_f34_flash_status();
- if (fwu->flash_control.command == 0x00)
+ if (fwu->intr_mask & fwu_read_interrupt_status()) {
+ fwu->polling_mode = true;
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Switch to polling mode\n",
+ __func__);
return 0;
+ }
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Timed out waiting for idle status\n",
@@ -538,7 +692,7 @@
return -ETIMEDOUT;
}
-static enum flash_area fwu_go_nogo(struct image_header *header)
+static enum flash_area fwu_go_nogo(void)
{
int retval = 0;
int index = 0;
@@ -554,30 +708,53 @@
enum flash_area flash_area = NONE;
struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
struct f01_device_status f01_device_status;
+ struct image_content *img = &fwu->image_content;
if (fwu->force_update) {
flash_area = UI_FIRMWARE;
goto exit;
}
- if (header->is_contain_build_info) {
+ if (img->is_contain_build_info) {
/* if package id does not match, do not update firmware */
fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f01_fd.query_base_addr + 17,
pkg_id,
sizeof(pkg_id));
- if (header->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
+ if (img->package_id != ((pkg_id[1] << 8) | pkg_id[0])) {
flash_area = MISMATCH;
goto exit;
}
- if (header->package_revision_id !=
+ if (img->package_revision_id !=
((pkg_id[3] << 8) | pkg_id[2])) {
flash_area = MISMATCH;
goto exit;
}
}
+ /* check firmware size */
+ if (fwu->fw_block_count*fwu->block_size != img->image_size) {
+ dev_err(&i2c_client->dev,
+ "%s: firmware size of device (%d) != .img (%d)\n",
+ __func__,
+ fwu->config_block_count * fwu->block_size,
+ img->image_size);
+ flash_area = NONE;
+ goto exit;
+ }
+
+ /* check config size */
+ if (fwu->config_block_count*fwu->block_size != img->config_size) {
+ dev_err(&i2c_client->dev,
+ "%s: config size of device (%d) != .img (%d)\n",
+ __func__,
+ fwu->config_block_count * fwu->block_size,
+ img->config_size);
+ flash_area = NONE;
+ goto exit;
+ }
+
retval = fwu_read_f01_device_status(&f01_device_status);
if (retval < 0) {
flash_area = NONE;
@@ -608,14 +785,21 @@
deviceFirmwareID = extract_uint(firmware_id);
/* .img firmware id */
- if (header->is_contain_build_info) {
+ if (img->is_contain_build_info) {
dev_err(&i2c_client->dev,
"%s: Image option contains build info.\n",
__func__);
- imageFirmwareID = header->firmware_id;
+ imageFirmwareID = img->firmware_id;
} else {
- strptr = strnstr(fwu->firmware_name, "PR",
- sizeof(fwu->firmware_name));
+ if (!fwu->image_name) {
+ dev_info(&i2c_client->dev,
+ "%s: Unknown image file name\n",
+ __func__);
+ flash_area = UI_FIRMWARE;
+ goto exit;
+ }
+ strptr = strnstr(fwu->image_name, "PR",
+ sizeof(fwu->image_name));
if (!strptr) {
dev_err(&i2c_client->dev,
"No valid PR number (PRxxxxxxx)" \
@@ -771,21 +955,41 @@
unsigned char command)
{
int retval;
+ unsigned char flash_status;
unsigned char block_offset[] = {0, 0};
unsigned short block_num;
+ unsigned short addr_block_data = fwu_get_address(OFFSET_BLOCK_DATA);
+ unsigned short addr_block_num = fwu_get_address(OFFSET_BLOCK_NUMBER);
struct i2c_client *i2c_client = fwu->rmi4_data->i2c_client;
#ifdef SHOW_PROGRESS
- unsigned int progress = (command == CMD_WRITE_CONFIG_BLOCK) ?
- 10 : 100;
+ unsigned int progress;
+ unsigned char command_str[10];
+ switch (command) {
+ case CMD_WRITE_CONFIG_BLOCK:
+ progress = 10;
+ strlcpy(command_str, "config", 10);
+ break;
+ case CMD_WRITE_FW_BLOCK:
+ progress = 100;
+ strlcpy(command_str, "firmware", 10);
+ break;
+ case CMD_WRITE_LOCKDOWN_BLOCK:
+ progress = 1;
+ strlcpy(command_str, "lockdown", 10);
+ break;
+ default:
+ progress = 1;
+ strlcpy(command_str, "unknown", 10);
+ break;
+ }
#endif
dev_dbg(&i2c_client->dev,
"%s: Start to update %s blocks\n",
__func__,
- command == CMD_WRITE_CONFIG_BLOCK ?
- "config" : "firmware");
+ command_str);
retval = fwu->fn_ptr->write(fwu->rmi4_data,
- fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+ addr_block_num,
block_offset,
sizeof(block_offset));
if (retval < 0) {
@@ -801,12 +1005,11 @@
dev_info(&i2c_client->dev,
"%s: update %s %3d / %3d\n",
__func__,
- command == CMD_WRITE_CONFIG_BLOCK ?
- "config" : "firmware",
+ command_str,
block_num, block_cnt);
#endif
retval = fwu->fn_ptr->write(fwu->rmi4_data,
- fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ addr_block_data,
block_ptr,
fwu->block_size);
if (retval < 0) {
@@ -832,21 +1035,28 @@
return retval;
}
- if (fwu->flash_control.status != 0x00) {
+ #if CHECK_FLASH_BLOCK_STATUS
+ retval = fwu_read_f34_flash_status(&flash_status);
+ if (retval < 0) {
dev_err(&i2c_client->dev,
- "%s: Flash block %d failed, status 0x%02X\n",
- __func__, block_num, retval);
+ "%s: Failed to read flash status (block %d)\n",
+ __func__, block_num);
return retval;
}
-
+ if (flash_status != 0x00) {
+ dev_err(&i2c_client->dev,
+ "%s: Flash block %d failed, status 0x%02X\n",
+ __func__, block_num, flash_status);
+ return -EINVAL;
+ }
+ #endif
block_ptr += fwu->block_size;
}
#ifdef SHOW_PROGRESS
dev_info(&i2c_client->dev,
"%s: update %s %3d / %3d\n",
__func__,
- command == CMD_WRITE_CONFIG_BLOCK ?
- "config" : "firmware",
+ command_str,
block_cnt, block_cnt);
#endif
return 0;
@@ -864,6 +1074,12 @@
fwu->config_block_count, CMD_WRITE_CONFIG_BLOCK);
}
+static int fwu_write_lockdown_block(void)
+{
+ return fwu_write_blocks((unsigned char *)fwu->lockdown_data,
+ fwu->lockdown_block_count, CMD_WRITE_LOCKDOWN_BLOCK);
+}
+
static int fwu_write_bootloader_id(void)
{
int retval;
@@ -874,7 +1090,7 @@
fwu->bootloader_id[1]);
retval = fwu->fn_ptr->write(fwu->rmi4_data,
- fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ fwu_get_address(OFFSET_BLOCK_DATA),
fwu->bootloader_id,
sizeof(fwu->bootloader_id));
if (retval < 0) {
@@ -887,7 +1103,7 @@
return 0;
}
-static int fwu_enter_flash_prog(void)
+static int fwu_enter_flash_prog(bool force)
{
int retval;
struct f01_device_status f01_device_status;
@@ -961,63 +1177,7 @@
__func__);
return retval;
}
-
- return retval;
-}
-
-static int fwu_do_reflash(void)
-{
- int retval;
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- return retval;
-
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Entered flash prog mode\n",
- __func__);
-
- retval = fwu_write_bootloader_id();
- if (retval < 0)
- return retval;
-
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Bootloader ID written\n",
- __func__);
-
- retval = fwu_write_f34_command(CMD_ERASE_ALL);
- if (retval < 0)
- return retval;
-
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Erase all command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS);
- if (retval < 0)
- return retval;
-
- if (fwu->flash_control.status != 0x00) {
- dev_err(&fwu->rmi4_data->i2c_client->dev,
- "%s: Erase all command failed, status 0x%02X\n",
- __func__, retval);
- return -1;
- }
-
- if (fwu->firmware_data) {
- retval = fwu_write_firmware();
- if (retval < 0)
- return retval;
- pr_notice("%s: Firmware programmed\n", __func__);
- }
-
- if (fwu->config_data) {
- retval = fwu_write_configuration();
- if (retval < 0)
- return retval;
- pr_notice("%s: Configuration programmed\n", __func__);
- }
-
+ fwu->polling_mode = false;
return retval;
}
@@ -1025,7 +1185,7 @@
{
int retval;
- retval = fwu_enter_flash_prog();
+ retval = fwu_enter_flash_prog(false);
if (retval < 0)
return retval;
@@ -1087,42 +1247,38 @@
static int fwu_start_write_config(void)
{
int retval;
- struct image_header header;
+ int block_count;
switch (fwu->config_area) {
case UI_CONFIG_AREA:
+ block_count = fwu->config_block_count;
break;
case PERM_CONFIG_AREA:
if (!fwu->flash_properties.has_perm_config)
return -EINVAL;
+ block_count = fwu->perm_config_block_count;
break;
case BL_CONFIG_AREA:
if (!fwu->flash_properties.has_bl_config)
return -EINVAL;
+ block_count = fwu->bl_config_block_count;
break;
case DISP_CONFIG_AREA:
if (!fwu->flash_properties.has_display_config)
return -EINVAL;
+ block_count = fwu->disp_config_block_count;
break;
default:
return -EINVAL;
}
- if (fwu->ext_data_source)
- fwu->config_data = fwu->ext_data_source;
- else
- return -EINVAL;
-
- if (fwu->config_area == UI_CONFIG_AREA) {
- parse_header(&header, fwu->ext_data_source);
-
- if (header.config_size) {
- fwu->config_data = fwu->ext_data_source +
- FW_IMAGE_OFFSET +
- header.image_size;
- } else {
- return -EINVAL;
- }
+ if (fwu->image_size == block_count*fwu->block_size) {
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s: write config from config file\n",
+ __func__);
+ fwu->config_data = fwu->data_buffer;
+ } else {
+ parse_header();
}
pr_notice("%s: Start of write config process\n", __func__);
@@ -1141,6 +1297,58 @@
return retval;
}
+static int fwu_do_write_lockdown(bool reset)
+{
+ int retval;
+
+ pr_notice("%s: Start of lockdown process\n", __func__);
+
+ retval = fwu_enter_flash_prog(false);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Entered flash prog mode\n",
+ __func__);
+
+ if (fwu->flash_properties.unlocked == 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Device has been locked!\n",
+ __func__);
+ if (reset)
+ goto exit;
+ else
+ return -EINVAL;
+ }
+
+ retval = fwu_write_lockdown_block();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s:Lockdown device\n",
+ __func__);
+
+exit:
+ if (reset)
+ retval = fwu->rmi4_data->reset_device(fwu->rmi4_data);
+ else
+ retval = fwu_enter_flash_prog(true);
+
+ if (retval < 0)
+ return retval;
+
+ pr_notice("%s: End of lockdown process\n", __func__);
+
+ return retval;
+}
+
+static int fwu_start_write_lockdown(void)
+{
+ parse_header();
+ return fwu_do_write_lockdown(true);
+}
+
static int fwu_do_read_config(void)
{
int retval;
@@ -1149,14 +1357,6 @@
unsigned short block_count;
unsigned short index = 0;
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- goto exit;
-
- dev_dbg(&fwu->rmi4_data->i2c_client->dev,
- "%s: Entered flash prog mode\n",
- __func__);
-
switch (fwu->config_area) {
case UI_CONFIG_AREA:
block_count = fwu->config_block_count;
@@ -1195,7 +1395,7 @@
block_offset[1] |= (fwu->config_area << 5);
retval = fwu->fn_ptr->write(fwu->rmi4_data,
- fwu->f34_fd.data_base_addr + BLOCK_NUMBER_OFFSET,
+ fwu_get_address(OFFSET_BLOCK_NUMBER),
block_offset,
sizeof(block_offset));
if (retval < 0) {
@@ -1223,7 +1423,7 @@
}
retval = fwu->fn_ptr->read(fwu->rmi4_data,
- fwu->f34_fd.data_base_addr + BLOCK_DATA_OFFSET,
+ fwu_get_address(OFFSET_BLOCK_DATA),
&fwu->read_config_buf[index],
fwu->block_size);
if (retval < 0) {
@@ -1237,7 +1437,71 @@
}
exit:
- fwu->rmi4_data->reset_device(fwu->rmi4_data);
+ return retval;
+}
+
+static int fwu_do_reflash(void)
+{
+ int retval;
+ unsigned char flash_status;
+
+ if (fwu->do_lockdown) {
+ retval = fwu_do_write_lockdown(false);
+ if (retval < 0)
+ dev_warn(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Skip lockdown process.\n",
+ __func__);
+ }
+ retval = fwu_enter_flash_prog(false);
+ if (retval < 0)
+ return retval;
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Entered flash prog mode\n",
+ __func__);
+
+ retval = fwu_write_bootloader_id();
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Bootloader ID written\n",
+ __func__);
+
+ retval = fwu_write_f34_command(CMD_ERASE_ALL);
+ if (retval < 0)
+ return retval;
+
+ dev_dbg(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Erase all command written\n",
+ __func__);
+
+ retval = fwu_wait_for_idle(ERASE_WAIT_MS);
+ if (retval < 0)
+ return retval;
+
+ retval = fwu_read_f34_flash_status(&flash_status);
+ if (retval < 0)
+ return retval;
+ if (flash_status != 0x00) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Erase all command failed, status 0x%02X\n",
+ __func__, flash_status);
+ return -EINVAL;
+ }
+
+ if (fwu->firmware_data) {
+ retval = fwu_write_firmware();
+ if (retval < 0)
+ return retval;
+ pr_notice("%s: Firmware programmed\n", __func__);
+ }
+
+ if (fwu->config_data) {
+ retval = fwu_write_configuration();
+ if (retval < 0)
+ return retval;
+ pr_notice("%s: Configuration programmed\n", __func__);
+ }
return retval;
}
@@ -1245,45 +1509,47 @@
static int fwu_start_reflash(void)
{
int retval = 0;
- struct image_header header;
- const unsigned char *fw_image;
const struct firmware *fw_entry = NULL;
struct f01_device_status f01_device_status;
enum flash_area flash_area;
pr_notice("%s: Start of reflash process\n", __func__);
- if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) == 0) {
- dev_err(&fwu->rmi4_data->i2c_client->dev,
- "Firmware image name not given, skipping update\n");
- return 0;
- }
-
- if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
- NAME_BUFFER_SIZE) {
- dev_err(&fwu->rmi4_data->i2c_client->dev,
- "Firmware image name exceeds max length (%d), " \
- "skipping update\n", NAME_BUFFER_SIZE);
- return 0;
- }
-
if (fwu->ext_data_source)
- fw_image = fwu->ext_data_source;
+ dev_info(&fwu->rmi4_data->i2c_client->dev,
+ "%s Load .img file from commandline.\n",
+ __func__);
else {
- snprintf(fwu->firmware_name, NAME_BUFFER_SIZE, "%s",
+ if (strnlen(fwu->rmi4_data->fw_image_name,
+ NAME_BUFFER_SIZE) == 0) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "Firmware image name not given, "\
+ "skipping update\n");
+ return 0;
+ }
+
+ if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) ==
+ NAME_BUFFER_SIZE) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "Firmware image name exceeds max length " \
+ "(%d), skipping update\n", NAME_BUFFER_SIZE);
+ return 0;
+ }
+
+ snprintf(fwu->image_name, NAME_BUFFER_SIZE, "%s",
fwu->rmi4_data->fw_image_name);
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s: Requesting firmware image %s\n",
- __func__, fwu->firmware_name);
+ __func__, fwu->image_name);
retval = request_firmware(&fw_entry,
- fwu->firmware_name,
+ fwu->image_name,
&fwu->rmi4_data->i2c_client->dev);
if (retval != 0) {
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Firmware image %s not available\n",
__func__,
- fwu->firmware_name);
+ fwu->image_name);
return -EINVAL;
}
@@ -1291,22 +1557,20 @@
"%s: Firmware image size = %d\n",
__func__, fw_entry->size);
- fw_image = fw_entry->data;
+ fwu->data_buffer = fw_entry->data;
}
- parse_header(&header, fw_image);
+ parse_header();
+ flash_area = fwu_go_nogo();
- if (header.image_size)
- fwu->firmware_data = fw_image + FW_IMAGE_OFFSET;
- if (header.config_size) {
- fwu->config_data = fw_image + FW_IMAGE_OFFSET +
- header.image_size;
+ if (fwu->rmi4_data->sensor_sleep) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Sensor sleeping\n",
+ __func__);
+ retval = -ENODEV;
+ goto exit;
}
-
- if (fwu->ext_data_source)
- flash_area = UI_FIRMWARE;
- else
- flash_area = fwu_go_nogo(&header);
+ fwu->rmi4_data->stay_awake = true;
switch (flash_area) {
case NONE:
@@ -1326,14 +1590,14 @@
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Unknown flash area\n",
__func__);
+ retval = -EINVAL;
goto exit;
}
- if (retval < 0) {
+ if (retval < 0)
dev_err(&fwu->rmi4_data->i2c_client->dev,
"%s: Failed to do reflash\n",
__func__);
- }
/* reset device */
fwu_reset_device();
@@ -1353,8 +1617,6 @@
dev_info(&fwu->rmi4_data->i2c_client->dev,
"%s: Device is in flash prog mode 0x%02X\n",
__func__, f01_device_status.status_code);
- retval = 0;
- goto exit;
}
exit:
@@ -1362,10 +1624,11 @@
release_firmware(fw_entry);
pr_notice("%s: End of reflash process\n", __func__);
+ fwu->rmi4_data->stay_awake = false;
return retval;
}
-int synaptics_fw_updater(unsigned char *fw_data)
+int synaptics_fw_updater(void)
{
int retval;
@@ -1383,7 +1646,6 @@
return -EBUSY;
}
- fwu->ext_data_source = fw_data;
fwu->config_area = UI_CONFIG_AREA;
retval = fwu_start_reflash();
@@ -1421,12 +1683,13 @@
(const void *)buf,
count);
+ fwu->data_buffer = fwu->ext_data_source;
fwu->data_pos += count;
return count;
}
-static ssize_t fwu_sysfs_fw_name_store(struct device *dev,
+static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
@@ -1450,7 +1713,7 @@
return count;
}
-static ssize_t fwu_sysfs_fw_name_show(struct device *dev,
+static ssize_t fwu_sysfs_image_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
@@ -1476,9 +1739,11 @@
retval = -EINVAL;
goto exit;
}
+ if (LOCKDOWN)
+ fwu->do_lockdown = true;
fwu->force_update = true;
- retval = synaptics_fw_updater(fwu->ext_data_source);
+ retval = synaptics_fw_updater();
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
"%s: Failed to do reflash\n",
@@ -1491,6 +1756,8 @@
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->force_update = FORCE_UPDATE;
+ fwu->do_lockdown = DO_LOCKDOWN;
return retval;
}
@@ -1506,15 +1773,58 @@
goto exit;
}
+ if (input & LOCKDOWN) {
+ fwu->do_lockdown = true;
+ input &= ~LOCKDOWN;
+ }
+
+ if ((input != NORMAL) && (input != FORCE)) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (input == FORCE)
+ fwu->force_update = true;
+
+ retval = synaptics_fw_updater();
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to do reflash\n",
+ __func__);
+ goto exit;
+ }
+
+ retval = count;
+
+exit:
+ kfree(fwu->ext_data_source);
+ fwu->ext_data_source = NULL;
+ fwu->force_update = FORCE_UPDATE;
+ fwu->do_lockdown = DO_LOCKDOWN;
+ return retval;
+}
+
+static ssize_t fwu_sysfs_write_lockdown_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval;
+ unsigned int input;
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+
+ if (sscanf(buf, "%u", &input) != 1) {
+ retval = -EINVAL;
+ goto exit;
+ }
+
if (input != 1) {
retval = -EINVAL;
goto exit;
}
- retval = synaptics_fw_updater(fwu->ext_data_source);
+ retval = fwu_start_write_lockdown();
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
- "%s: Failed to do reflash\n",
+ "%s: Failed to write lockdown block\n",
__func__);
goto exit;
}
@@ -1524,6 +1834,8 @@
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->force_update = FORCE_UPDATE;
+ fwu->do_lockdown = DO_LOCKDOWN;
return retval;
}
@@ -1714,7 +2026,7 @@
unsigned char intr_mask)
{
if (fwu->intr_mask & intr_mask)
- fwu_read_f34_flash_status();
+ fwu->interrupt_flag = true;
return;
}
@@ -1731,8 +2043,8 @@
static struct device_attribute attrs[] = {
__ATTR(fw_name, S_IRUGO | S_IWUSR | S_IWGRP,
- fwu_sysfs_fw_name_show,
- fwu_sysfs_fw_name_store),
+ fwu_sysfs_image_name_show,
+ fwu_sysfs_image_name_store),
__ATTR(force_update_fw, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_force_reflash_store),
@@ -1742,6 +2054,9 @@
__ATTR(writeconfig, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_write_config_store),
+ __ATTR(writelockdown, S_IWUGO,
+ synaptics_rmi4_show_error,
+ fwu_sysfs_write_lockdown_store),
__ATTR(readconfig, S_IRUGO | S_IWUSR | S_IWGRP,
synaptics_rmi4_show_error,
fwu_sysfs_read_config_store),
@@ -1851,6 +2166,9 @@
fwu->initialized = true;
fwu->force_update = FORCE_UPDATE;
+ fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->initialized = true;
+ fwu->polling_mode = false;
retval = sysfs_create_bin_file(&rmi4_data->i2c_client->dev.kobj,
&dev_attr_data);
@@ -1900,24 +2218,23 @@
msecs_to_jiffies(1000));
#endif
- init_completion(&remove_complete);
-
return 0;
exit_free_ts_info:
debugfs_remove(temp);
exit_remove_attrs:
-for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
-}
+ for (attr_count--; attr_count >= 0; attr_count--) {
+ sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
+ &attrs[attr_count].attr);
+ }
-sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+ sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
exit_free_mem:
kfree(fwu->fn_ptr);
exit_free_fwu:
kfree(fwu);
+ fwu = NULL;
exit:
return 0;
@@ -1934,10 +2251,11 @@
&attrs[attr_count].attr);
}
+ kfree(fwu->read_config_buf);
kfree(fwu->fn_ptr);
kfree(fwu);
- complete(&remove_complete);
+ complete(&fwu_remove_complete);
return;
}
@@ -1957,7 +2275,7 @@
synaptics_rmi4_fwu_init,
synaptics_rmi4_fwu_remove,
synaptics_rmi4_fwu_attn);
- wait_for_completion(&remove_complete);
+ wait_for_completion(&fwu_remove_complete);
return;
}
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 0b234ce..f8ab5f4 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -93,6 +93,8 @@
#define RMI4_I2C_LPM_LOAD_UA 10
#define RMI4_GPIO_SLEEP_LOW_US 10000
+#define F12_FINGERS_TO_SUPPORT 10
+#define MAX_F11_TOUCH_WIDTH 15
static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data,
@@ -168,6 +170,131 @@
};
};
+struct synaptics_rmi4_f12_query_5 {
+ union {
+ struct {
+ unsigned char size_of_query6;
+ struct {
+ unsigned char ctrl0_is_present:1;
+ unsigned char ctrl1_is_present:1;
+ unsigned char ctrl2_is_present:1;
+ unsigned char ctrl3_is_present:1;
+ unsigned char ctrl4_is_present:1;
+ unsigned char ctrl5_is_present:1;
+ unsigned char ctrl6_is_present:1;
+ unsigned char ctrl7_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl8_is_present:1;
+ unsigned char ctrl9_is_present:1;
+ unsigned char ctrl10_is_present:1;
+ unsigned char ctrl11_is_present:1;
+ unsigned char ctrl12_is_present:1;
+ unsigned char ctrl13_is_present:1;
+ unsigned char ctrl14_is_present:1;
+ unsigned char ctrl15_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl16_is_present:1;
+ unsigned char ctrl17_is_present:1;
+ unsigned char ctrl18_is_present:1;
+ unsigned char ctrl19_is_present:1;
+ unsigned char ctrl20_is_present:1;
+ unsigned char ctrl21_is_present:1;
+ unsigned char ctrl22_is_present:1;
+ unsigned char ctrl23_is_present:1;
+ } __packed;
+ struct {
+ unsigned char ctrl24_is_present:1;
+ unsigned char ctrl25_is_present:1;
+ unsigned char ctrl26_is_present:1;
+ unsigned char ctrl27_is_present:1;
+ unsigned char ctrl28_is_present:1;
+ unsigned char ctrl29_is_present:1;
+ unsigned char ctrl30_is_present:1;
+ unsigned char ctrl31_is_present:1;
+ } __packed;
+ };
+ unsigned char data[5];
+ };
+};
+
+struct synaptics_rmi4_f12_query_8 {
+ union {
+ struct {
+ unsigned char size_of_query9;
+ struct {
+ unsigned char data0_is_present:1;
+ unsigned char data1_is_present:1;
+ unsigned char data2_is_present:1;
+ unsigned char data3_is_present:1;
+ unsigned char data4_is_present:1;
+ unsigned char data5_is_present:1;
+ unsigned char data6_is_present:1;
+ unsigned char data7_is_present:1;
+ } __packed;
+ struct {
+ unsigned char data8_is_present:1;
+ unsigned char data9_is_present:1;
+ unsigned char data10_is_present:1;
+ unsigned char data11_is_present:1;
+ unsigned char data12_is_present:1;
+ unsigned char data13_is_present:1;
+ unsigned char data14_is_present:1;
+ unsigned char data15_is_present:1;
+ } __packed;
+ };
+ unsigned char data[3];
+ };
+};
+
+struct synaptics_rmi4_f12_ctrl_8 {
+ union {
+ struct {
+ unsigned char max_x_coord_lsb;
+ unsigned char max_x_coord_msb;
+ unsigned char max_y_coord_lsb;
+ unsigned char max_y_coord_msb;
+ unsigned char rx_pitch_lsb;
+ unsigned char rx_pitch_msb;
+ unsigned char tx_pitch_lsb;
+ unsigned char tx_pitch_msb;
+ unsigned char low_rx_clip;
+ unsigned char high_rx_clip;
+ unsigned char low_tx_clip;
+ unsigned char high_tx_clip;
+ unsigned char num_of_rx;
+ unsigned char num_of_tx;
+ };
+ unsigned char data[14];
+ };
+};
+
+struct synaptics_rmi4_f12_ctrl_23 {
+ union {
+ struct {
+ unsigned char obj_type_enable;
+ unsigned char max_reported_objects;
+ };
+ unsigned char data[2];
+ };
+};
+
+struct synaptics_rmi4_f12_finger_data {
+ unsigned char object_type_and_status;
+ unsigned char x_lsb;
+ unsigned char x_msb;
+ unsigned char y_lsb;
+ unsigned char y_msb;
+#ifdef REPORT_2D_Z
+ unsigned char z;
+#endif
+#ifdef REPORT_2D_W
+ unsigned char wx;
+ unsigned char wy;
+#endif
+};
+
struct synaptics_rmi4_f1a_query {
union {
struct {
@@ -223,6 +350,13 @@
struct synaptics_rmi4_f1a_control button_control;
};
+struct synaptics_rmi4_f12_extra_data {
+ unsigned char data1_offset;
+ unsigned char data15_offset;
+ unsigned char data15_size;
+ unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
+};
+
struct synaptics_rmi4_exp_fn {
enum exp_fn fn_type;
bool inserted;
@@ -360,8 +494,8 @@
retval = synaptics_rmi4_reset_device(rmi4_data);
if (retval < 0) {
dev_err(dev,
- "%s: Failed to issue reset command, error = %d\n",
- __func__, retval);
+ "%s: Failed to issue reset command, error = %d\n",
+ __func__, retval);
return retval;
}
@@ -817,10 +951,7 @@
if (!touch_count)
input_mt_sync(rmi4_data->input_dev);
#else
- /* sync after groups of events */
- #ifdef KERNEL_ABOVE_3_7
- input_mt_sync_frame(rmi4_data->input_dev);
- #endif
+ input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
#endif
input_sync(rmi4_data->input_dev);
@@ -828,6 +959,125 @@
return touch_count;
}
+ /**
+ * synaptics_rmi4_f12_abs_report()
+ *
+ * Called by synaptics_rmi4_report_touch() when valid Function $12
+ * finger data has been detected.
+ *
+ * This function reads the Function $12 data registers, determines the
+ * status of each finger supported by the Function, processes any
+ * necessary coordinate manipulation, reports the finger data to
+ * the input subsystem, and returns the number of fingers detected.
+ */
+static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler)
+{
+ int retval;
+ unsigned char touch_count = 0; /* number of touch points */
+ unsigned char finger;
+ unsigned char fingers_to_process;
+ unsigned char finger_status;
+ unsigned char size_of_2d_data;
+ unsigned short data_addr;
+ int x;
+ int y;
+ int wx;
+ int wy;
+ struct synaptics_rmi4_f12_extra_data *extra_data;
+ struct synaptics_rmi4_f12_finger_data *data;
+ struct synaptics_rmi4_f12_finger_data *finger_data;
+
+ fingers_to_process = fhandler->num_of_data_points;
+ data_addr = fhandler->full_addr.data_base;
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+ size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ data_addr + extra_data->data1_offset,
+ (unsigned char *)fhandler->data,
+ fingers_to_process * size_of_2d_data);
+ if (retval < 0)
+ return 0;
+
+ data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
+
+ for (finger = 0; finger < fingers_to_process; finger++) {
+ finger_data = data + finger;
+ finger_status = finger_data->object_type_and_status & MASK_2BIT;
+
+ /*
+ * Each 2-bit finger status field represents the following:
+ * 00 = finger not present
+ * 01 = finger present and data accurate
+ * 10 = finger present but data may be inaccurate
+ * 11 = reserved
+ */
+#ifdef TYPE_B_PROTOCOL
+ input_mt_slot(rmi4_data->input_dev, finger);
+ input_mt_report_slot_state(rmi4_data->input_dev,
+ MT_TOOL_FINGER, finger_status != 0);
+#endif
+
+ if (finger_status) {
+ x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
+ y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
+#ifdef REPORT_2D_W
+ wx = finger_data->wx;
+ wy = finger_data->wy;
+#endif
+
+ if (rmi4_data->board->x_flip)
+ x = rmi4_data->sensor_max_x - x;
+ if (rmi4_data->board->y_flip)
+ y = rmi4_data->sensor_max_y - y;
+
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Finger %d:\n"
+ "status = 0x%02x\n"
+ "x = %d\n"
+ "y = %d\n"
+ "wx = %d\n"
+ "wy = %d\n",
+ __func__, finger,
+ finger_status,
+ x, y, wx, wy);
+
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, 1);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, 1);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_POSITION_Y, y);
+#ifdef REPORT_2D_W
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MAJOR, max(wx, wy));
+ input_report_abs(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, min(wx, wy));
+#endif
+#ifndef TYPE_B_PROTOCOL
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ touch_count++;
+ }
+ }
+
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOUCH, touch_count > 0);
+ input_report_key(rmi4_data->input_dev,
+ BTN_TOOL_FINGER, touch_count > 0);
+#ifndef TYPE_B_PROTOCOL
+ if (!touch_count)
+ input_mt_sync(rmi4_data->input_dev);
+#endif
+ input_mt_report_pointer_emulation(rmi4_data->input_dev, false);
+ input_sync(rmi4_data->input_dev);
+
+ return touch_count;
+}
+
static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn *fhandler)
{
@@ -955,6 +1205,16 @@
rmi4_data->fingers_on_2d = false;
break;
+ case SYNAPTICS_RMI4_F12:
+ touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
+ fhandler);
+
+ if (touch_count_2d)
+ rmi4_data->fingers_on_2d = true;
+ else
+ rmi4_data->fingers_on_2d = false;
+ break;
+
case SYNAPTICS_RMI4_F1A:
synaptics_rmi4_f1a_report(rmi4_data, fhandler);
break;
@@ -1045,6 +1305,7 @@
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
static int synaptics_rmi4_parse_dt(struct device *dev,
struct synaptics_rmi4_platform_data *rmi4_pdata)
{
@@ -1127,6 +1388,13 @@
}
return 0;
}
+#else
+static inline int synaptics_rmi4_parse_dt(struct device *dev,
+ struct synaptics_rmi4_platform_data *rmi4_pdata)
+{
+ return 0;
+}
+#endif
/**
* synaptics_rmi4_irq_enable()
@@ -1237,6 +1505,8 @@
rmi4_data->sensor_max_x,
rmi4_data->sensor_max_y);
+ rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
+
fhandler->intr_reg_num = (intr_count + 7) / 8;
if (fhandler->intr_reg_num != 0)
fhandler->intr_reg_num -= 1;
@@ -1257,6 +1527,212 @@
return retval;
}
+static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
+ unsigned short ctrl28)
+{
+ int retval;
+ static unsigned short ctrl_28_address;
+
+ if (ctrl28)
+ ctrl_28_address = ctrl28;
+
+ retval = synaptics_rmi4_i2c_write(rmi4_data,
+ ctrl_28_address,
+ &rmi4_data->report_enable,
+ sizeof(rmi4_data->report_enable));
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+ /**
+ * synaptics_rmi4_f12_init()
+ *
+ * Called by synaptics_rmi4_query_device().
+ *
+ * This funtion parses information from the Function 12 registers and
+ * determines the number of fingers supported, offset to the data1
+ * register, x and y data ranges, offset to the associated interrupt
+ * status register, interrupt bit mask, and allocates memory resources
+ * for finger data acquisition.
+ */
+static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
+ struct synaptics_rmi4_fn *fhandler,
+ struct synaptics_rmi4_fn_desc *fd,
+ unsigned int intr_count)
+{
+ int retval;
+ unsigned char ii;
+ unsigned char intr_offset;
+ unsigned char size_of_2d_data;
+ unsigned char size_of_query8;
+ unsigned char ctrl_8_offset;
+ unsigned char ctrl_23_offset;
+ unsigned char ctrl_28_offset;
+ unsigned char num_of_fingers;
+ struct synaptics_rmi4_f12_extra_data *extra_data;
+ struct synaptics_rmi4_f12_query_5 query_5;
+ struct synaptics_rmi4_f12_query_8 query_8;
+ struct synaptics_rmi4_f12_ctrl_8 ctrl_8;
+ struct synaptics_rmi4_f12_ctrl_23 ctrl_23;
+
+ fhandler->fn_number = fd->fn_number;
+ fhandler->num_of_data_sources = fd->intr_src_count;
+ fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
+ size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 5,
+ query_5.data,
+ sizeof(query_5.data));
+ if (retval < 0)
+ return retval;
+
+ ctrl_8_offset = query_5.ctrl0_is_present +
+ query_5.ctrl1_is_present +
+ query_5.ctrl2_is_present +
+ query_5.ctrl3_is_present +
+ query_5.ctrl4_is_present +
+ query_5.ctrl5_is_present +
+ query_5.ctrl6_is_present +
+ query_5.ctrl7_is_present;
+
+ ctrl_23_offset = ctrl_8_offset +
+ query_5.ctrl8_is_present +
+ query_5.ctrl9_is_present +
+ query_5.ctrl10_is_present +
+ query_5.ctrl11_is_present +
+ query_5.ctrl12_is_present +
+ query_5.ctrl13_is_present +
+ query_5.ctrl14_is_present +
+ query_5.ctrl15_is_present +
+ query_5.ctrl16_is_present +
+ query_5.ctrl17_is_present +
+ query_5.ctrl18_is_present +
+ query_5.ctrl19_is_present +
+ query_5.ctrl20_is_present +
+ query_5.ctrl21_is_present +
+ query_5.ctrl22_is_present;
+
+ ctrl_28_offset = ctrl_23_offset +
+ query_5.ctrl23_is_present +
+ query_5.ctrl24_is_present +
+ query_5.ctrl25_is_present +
+ query_5.ctrl26_is_present +
+ query_5.ctrl27_is_present;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_23_offset,
+ ctrl_23.data,
+ sizeof(ctrl_23.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum number of fingers supported */
+ fhandler->num_of_data_points = min(ctrl_23.max_reported_objects,
+ (unsigned char)F12_FINGERS_TO_SUPPORT);
+
+ num_of_fingers = fhandler->num_of_data_points;
+ rmi4_data->num_of_fingers = num_of_fingers;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 7,
+ &size_of_query8,
+ sizeof(size_of_query8));
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.query_base + 8,
+ query_8.data,
+ size_of_query8);
+ if (retval < 0)
+ return retval;
+
+ /* Determine the presence of the Data0 register */
+ extra_data->data1_offset = query_8.data0_is_present;
+
+ if ((size_of_query8 >= 3) && (query_8.data15_is_present)) {
+ extra_data->data15_offset = query_8.data0_is_present +
+ query_8.data1_is_present +
+ query_8.data2_is_present +
+ query_8.data3_is_present +
+ query_8.data4_is_present +
+ query_8.data5_is_present +
+ query_8.data6_is_present +
+ query_8.data7_is_present +
+ query_8.data8_is_present +
+ query_8.data9_is_present +
+ query_8.data10_is_present +
+ query_8.data11_is_present +
+ query_8.data12_is_present +
+ query_8.data13_is_present +
+ query_8.data14_is_present;
+ extra_data->data15_size = (num_of_fingers + 7) / 8;
+ } else {
+ extra_data->data15_size = 0;
+ }
+
+ rmi4_data->report_enable = RPT_DEFAULT;
+#ifdef REPORT_2D_Z
+ rmi4_data->report_enable |= RPT_Z;
+#endif
+#ifdef REPORT_2D_W
+ rmi4_data->report_enable |= (RPT_WX | RPT_WY);
+#endif
+
+ retval = synaptics_rmi4_f12_set_enables(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_28_offset);
+ if (retval < 0)
+ return retval;
+
+ retval = synaptics_rmi4_i2c_read(rmi4_data,
+ fhandler->full_addr.ctrl_base + ctrl_8_offset,
+ ctrl_8.data,
+ sizeof(ctrl_8.data));
+ if (retval < 0)
+ return retval;
+
+ /* Maximum x and y */
+ rmi4_data->sensor_max_x =
+ ((unsigned short)ctrl_8.max_x_coord_lsb << 0) |
+ ((unsigned short)ctrl_8.max_x_coord_msb << 8);
+ rmi4_data->sensor_max_y =
+ ((unsigned short)ctrl_8.max_y_coord_lsb << 0) |
+ ((unsigned short)ctrl_8.max_y_coord_msb << 8);
+ dev_dbg(&rmi4_data->i2c_client->dev,
+ "%s: Function %02x max x = %d max y = %d\n",
+ __func__, fhandler->fn_number,
+ rmi4_data->sensor_max_x,
+ rmi4_data->sensor_max_y);
+
+ rmi4_data->num_of_rx = ctrl_8.num_of_rx;
+ rmi4_data->num_of_tx = ctrl_8.num_of_tx;
+ rmi4_data->max_touch_width = max(rmi4_data->num_of_rx,
+ rmi4_data->num_of_tx);
+
+ fhandler->intr_reg_num = (intr_count + 7) / 8;
+ if (fhandler->intr_reg_num != 0)
+ fhandler->intr_reg_num -= 1;
+
+ /* Set an enable bit for each data source */
+ intr_offset = intr_count % 8;
+ fhandler->intr_mask = 0;
+ for (ii = intr_offset;
+ ii < ((fd->intr_src_count & MASK_3BIT) +
+ intr_offset);
+ ii++)
+ fhandler->intr_mask |= 1 << ii;
+
+ /* Allocate memory for finger data storage space */
+ fhandler->data_size = num_of_fingers * size_of_2d_data;
+ fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
+
+ return retval;
+}
+
static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn *fhandler)
{
@@ -1601,6 +2077,26 @@
return retval;
break;
+ case SYNAPTICS_RMI4_F12:
+ if (rmi_fd.intr_src_count == 0)
+ break;
+
+ retval = synaptics_rmi4_alloc_fh(&fhandler,
+ &rmi_fd, page_number);
+ if (retval < 0) {
+ dev_err(&rmi4_data->i2c_client->dev,
+ "%s: Failed to alloc for F%d\n",
+ __func__,
+ rmi_fd.fn_number);
+ return retval;
+ }
+
+ retval = synaptics_rmi4_f12_init(rmi4_data,
+ fhandler, &rmi_fd, intr_count);
+ if (retval < 0)
+ return retval;
+ break;
+
case SYNAPTICS_RMI4_F1A:
if (rmi_fd.intr_src_count == 0)
break;
@@ -1744,6 +2240,7 @@
{
int retval;
struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_fn *next_fhandler;
struct synaptics_rmi4_device_info *rmi;
rmi = &(rmi4_data->rmi4_mod_info);
@@ -1757,11 +2254,14 @@
}
if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ list_for_each_entry_safe(fhandler, next_fhandler,
+ &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
synaptics_rmi4_f1a_kfree(fhandler);
- else
+ else {
kfree(fhandler->data);
+ kfree(fhandler->extra);
+ }
kfree(fhandler);
}
}
@@ -2125,6 +2625,7 @@
unsigned char attr_count;
struct synaptics_rmi4_f1a_handle *f1a;
struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_fn *next_fhandler;
struct synaptics_rmi4_data *rmi4_data;
struct synaptics_rmi4_device_info *rmi;
struct synaptics_rmi4_platform_data *platform_data =
@@ -2260,7 +2761,10 @@
#ifdef REPORT_2D_W
input_set_abs_params(rmi4_data->input_dev,
ABS_MT_TOUCH_MAJOR, 0,
- MAX_ABS_MT_TOUCH_MAJOR, 0, 0);
+ rmi4_data->max_touch_width, 0, 0);
+ input_set_abs_params(rmi4_data->input_dev,
+ ABS_MT_TOUCH_MINOR, 0,
+ rmi4_data->max_touch_width, 0, 0);
#endif
#ifdef TYPE_B_PROTOCOL
@@ -2381,11 +2885,14 @@
err_register_input:
if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ list_for_each_entry_safe(fhandler, next_fhandler,
+ &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
synaptics_rmi4_f1a_kfree(fhandler);
- else
+ else {
kfree(fhandler->data);
+ kfree(fhandler->extra);
+ }
kfree(fhandler);
}
}
@@ -2421,6 +2928,7 @@
{
unsigned char attr_count;
struct synaptics_rmi4_fn *fhandler;
+ struct synaptics_rmi4_fn *next_fhandler;
struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
struct synaptics_rmi4_device_info *rmi;
@@ -2444,11 +2952,14 @@
input_unregister_device(rmi4_data->input_dev);
if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
+ list_for_each_entry_safe(fhandler, next_fhandler,
+ &rmi->support_fn_list, link) {
if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
synaptics_rmi4_f1a_kfree(fhandler);
- else
+ else {
kfree(fhandler->data);
+ kfree(fhandler->extra);
+ }
kfree(fhandler);
}
}
@@ -2591,6 +3102,11 @@
container_of(h, struct synaptics_rmi4_data,
early_suspend);
+ if (rmi4_data->stay_awake)
+ rmi4_data->staying_awake = true;
+ else
+ rmi4_data->staying_awake = false;
+
rmi4_data->touch_stopped = true;
wake_up(&rmi4_data->wait);
synaptics_rmi4_irq_enable(rmi4_data, false);
@@ -2617,6 +3133,9 @@
container_of(h, struct synaptics_rmi4_data,
early_suspend);
+ if (rmi4_data->staying_awake)
+ return;
+
if (rmi4_data->full_pm_cycle)
synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
@@ -2761,6 +3280,12 @@
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
int retval;
+ if (rmi4_data->stay_awake) {
+ rmi4_data->staying_awake = true;
+ return 0;
+ } else
+ rmi4_data->staying_awake = false;
+
if (rmi4_data->suspended) {
dev_info(dev, "Already in suspend state\n");
return 0;
@@ -2812,6 +3337,9 @@
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
int retval;
+ if (rmi4_data->staying_awake)
+ return 0;
+
if (!rmi4_data->suspended) {
dev_info(dev, "Already in awake state\n");
return 0;
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.h b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
index 5f6d6ce..677a2fe 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.h
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.h
@@ -45,6 +45,7 @@
#define SYNAPTICS_RMI4_F01 (0x01)
#define SYNAPTICS_RMI4_F11 (0x11)
+#define SYNAPTICS_RMI4_F12 (0x12)
#define SYNAPTICS_RMI4_F1A (0x1a)
#define SYNAPTICS_RMI4_F34 (0x34)
#define SYNAPTICS_RMI4_F54 (0x54)
@@ -69,7 +70,7 @@
#define MASK_2BIT 0x03
#define MASK_1BIT 0x01
-#define NAME_BUFFER_SIZE 128
+#define NAME_BUFFER_SIZE 256
/*
* struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
@@ -85,9 +86,12 @@
unsigned char cmd_base_addr;
unsigned char ctrl_base_addr;
unsigned char data_base_addr;
- unsigned char intr_src_count;
+ unsigned char intr_src_count:3;
+ unsigned char reserved_b3_b4:2;
+ unsigned char version:2;
+ unsigned char reserved_b7:1;
unsigned char fn_number;
-};
+} __packed;
/*
* synaptics_rmi4_fn_full_addr - full 16-bit base addresses
@@ -129,6 +133,7 @@
struct list_head link;
int data_size;
void *data;
+ void *extra;
};
/*
@@ -214,6 +219,8 @@
unsigned char num_of_rx;
unsigned char num_of_tx;
unsigned char num_of_fingers;
+ unsigned char max_touch_width;
+ unsigned char report_enable;
unsigned char intr_mask[MAX_INTR_REGISTERS];
unsigned short num_of_intr_regs;
unsigned short f01_query_base_addr;
@@ -232,6 +239,8 @@
bool fw_updating;
bool suspended;
wait_queue_head_t wait;
+ bool stay_awake;
+ bool staying_awake;
int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
unsigned char *data, unsigned short length);
int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/hi256.c b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
index 73226ed..3288e9c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/hi256.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/hi256.c
@@ -151,7 +151,7 @@
{0x03, 0x00},
{0x10, 0x13},
- {0x11, 0x93},
+ {0x11, 0x90}, /* no H/V flip */
{0x12, 0x00},
{0x0b, 0xaa},
{0x0c, 0xaa},
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index ef2c12a..1dba2b6 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -32,6 +32,7 @@
HFI_H264_PROFILE_CONSTRAINED_BASE,
[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
HFI_H264_PROFILE_CONSTRAINED_HIGH,
+ [ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
};
static int entropy_mode[] = {
diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c
index 653ba46..8350dde 100644
--- a/drivers/media/platform/msm/vidc/hfi_response_handler.c
+++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c
@@ -78,6 +78,26 @@
return vidc_err;
}
+static int sanitize_session_pkt(struct list_head *sessions,
+ struct hal_session *sess, struct mutex *session_lock)
+{
+ struct hal_session *session;
+ int invalid = 1;
+ if (session_lock) {
+ mutex_lock(session_lock);
+ list_for_each_entry(session, sessions, list) {
+ if (session == sess) {
+ invalid = 0;
+ break;
+ }
+ }
+ mutex_unlock(session_lock);
+ }
+ if (invalid)
+ dprintk(VIDC_WARN, "Invalid session from FW: %p\n", sess);
+ return invalid;
+}
+
static void hfi_process_sess_evt_seq_changed(
msm_vidc_callback callback, u32 device_id,
struct hfi_msg_event_notify_packet *pkt)
@@ -1115,9 +1135,11 @@
u32 hfi_process_msg_packet(
msm_vidc_callback callback, u32 device_id,
- struct vidc_hal_msg_pkt_hdr *msg_hdr)
+ struct vidc_hal_msg_pkt_hdr *msg_hdr,
+ struct list_head *sessions, struct mutex *session_lock)
{
u32 rc = 0;
+ struct hal_session *sess;
if (!callback || !msg_hdr || msg_hdr->size <
VIDC_IFACEQ_MIN_PKT_SIZE) {
dprintk(VIDC_ERR, "hal_process_msg_packet:bad"
@@ -1126,10 +1148,19 @@
return rc;
}
+#define SANITIZE_SESSION_PKT(msg_pkt) ({ \
+ sess = (struct hal_session *) \
+ (((struct vidc_hal_session_cmd_pkt *) \
+ msg_pkt)->session_id); \
+ if (sanitize_session_pkt(sessions, sess, session_lock)) \
+ break; \
+ })
+
dprintk(VIDC_INFO, "Received: 0x%x in ", msg_hdr->packet);
rc = (u32) msg_hdr->packet;
switch (msg_hdr->packet) {
case HFI_MSG_EVENT_NOTIFY:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_event_notify(callback, device_id,
(struct hfi_msg_event_notify_packet *) msg_hdr);
break;
@@ -1141,6 +1172,7 @@
case HFI_MSG_SYS_IDLE:
break;
case HFI_MSG_SYS_SESSION_INIT_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_init_done(callback, device_id,
(struct hfi_msg_sys_session_init_done_packet *)
msg_hdr);
@@ -1151,44 +1183,53 @@
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_END_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_end_done(callback, device_id,
(struct hfi_msg_sys_session_end_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_LOAD_RESOURCES_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_load_res_done(callback, device_id,
(struct hfi_msg_session_load_resources_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_START_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_start_done(callback, device_id,
(struct hfi_msg_session_start_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_STOP_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_stop_done(callback, device_id,
(struct hfi_msg_session_stop_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_EMPTY_BUFFER_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_etb_done(callback, device_id,
(struct hfi_msg_session_empty_buffer_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_FILL_BUFFER_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_ftb_done(callback, device_id, msg_hdr);
break;
case HFI_MSG_SESSION_FLUSH_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_flush_done(callback, device_id,
(struct hfi_msg_session_flush_done_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_PROPERTY_INFO:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_prop_info(callback, device_id,
(struct hfi_msg_session_property_info_packet *)
msg_hdr);
break;
case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_rel_res_done(callback, device_id,
(struct hfi_msg_session_release_resources_done_packet *)
msg_hdr);
@@ -1199,18 +1240,21 @@
msg_hdr);
break;
case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_get_seq_hdr_done(
callback, device_id, (struct
hfi_msg_session_get_sequence_header_done_packet*)
msg_hdr);
break;
case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_rel_buf_done(
callback, device_id, (struct
hfi_msg_session_release_buffers_done_packet*)
msg_hdr);
break;
case HFI_MSG_SYS_SESSION_ABORT_DONE:
+ SANITIZE_SESSION_PKT(msg_hdr);
hfi_process_session_abort_done(callback, device_id, (struct
hfi_msg_sys_session_abort_done_packet*) msg_hdr);
break;
@@ -1218,5 +1262,6 @@
dprintk(VIDC_DBG, "UNKNOWN_MSG_TYPE : %d", msg_hdr->packet);
break;
}
+#undef SANITIZE_SESSION_PKT
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index cddca74..dcf5a0e 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -87,6 +87,14 @@
"High Latency",
};
+static const char *const vp8_profile_level[] = {
+ "Unused",
+ "0.0",
+ "1.0",
+ "2.0",
+ "3.0",
+};
+
static const char *const mpeg_video_vidc_extradata[] = {
"Extradata none",
"Extradata MB Quantization",
@@ -125,7 +133,8 @@
MSM_VENC_CTRL_CLUSTER_INTRA_REFRESH = 1 << 7,
MSM_VENC_CTRL_CLUSTER_BITRATE = 1 << 8,
MSM_VENC_CTRL_CLUSTER_TIMING = 1 << 9,
- MSM_VENC_CTRL_CLUSTER_MAX = 1 << 10,
+ MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL = 1 << 10,
+ MSM_VENC_CTRL_CLUSTER_MAX = 1 << 11,
};
static struct msm_vidc_ctrl msm_venc_ctrls[] = {
@@ -362,6 +371,21 @@
.cluster = MSM_VENC_CTRL_CLUSTER_H263_PROFILE_LEVEL,
},
{
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ .name = "VP8 Profile Level",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
+ ),
+ .qmenu = vp8_profile_level,
+ .cluster = MSM_VENC_CTRL_CLUSTER_VP8_PROFILE_LEVEL,
+ },
+ {
.id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION,
.name = "Rotation",
.type = V4L2_CTRL_TYPE_MENU,
@@ -1171,6 +1195,21 @@
default:
goto unknown_value;
}
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ switch (value) {
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0:
+ return HAL_VPX_PROFILE_VERSION_0;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1:
+ return HAL_VPX_PROFILE_VERSION_1;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2:
+ return HAL_VPX_PROFILE_VERSION_2;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3:
+ return HAL_VPX_PROFILE_VERSION_3;
+ case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED:
+ return HAL_VPX_PROFILE_UNUSED;
+ default:
+ goto unknown_value;
+ }
}
unknown_value:
@@ -1477,6 +1516,15 @@
ctrl->val);
pdata = &profile_level;
break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ property_id =
+ HAL_PARAM_PROFILE_LEVEL_CURRENT;
+ profile_level.profile = venc_v4l2_to_hal(
+ V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
+ ctrl->val);
+ profile_level.level = HAL_VPX_PROFILE_UNUSED;
+ pdata = &profile_level;
+ break;
case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION:
property_id =
HAL_CONFIG_VPE_OPERATIONS;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9194d46..91fc9d0 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -824,10 +824,18 @@
(u32)fill_buf_done->packet_buffer1);
if (vb) {
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
vb->v4l2_planes[0].reserved[2] = fill_buf_done->start_x_coord;
vb->v4l2_planes[0].reserved[3] = fill_buf_done->start_y_coord;
vb->v4l2_planes[0].reserved[4] = fill_buf_done->frame_width;
vb->v4l2_planes[0].reserved[5] = fill_buf_done->frame_height;
+ if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO, "fbd:data_offset overflow length\n");
+ if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length)
+ dprintk(VIDC_INFO, "fbd:bytesused overflow length\n");
+ if ((u8 *)vb->v4l2_planes[0].m.userptr !=
+ response->input_done.packet_buffer)
+ dprintk(VIDC_INFO, "fbd:Unexpected buffer address\n");
if (!(fill_buf_done->flags1 &
HAL_BUFFERFLAG_TIMESTAMPINVALID) &&
fill_buf_done->filled_len1) {
@@ -880,8 +888,9 @@
msm_vidc_debugfs_update(inst,
MSM_VIDC_DEBUGFS_EVENT_FBD);
- dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+ dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
vb->v4l2_planes[0].bytesused,
+ vb->v4l2_planes[0].data_offset,
vb->v4l2_buf.flags);
mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -908,6 +917,7 @@
vb = list_first_entry(&q->vb2_bufq.queued_list,
struct vb2_buffer, queued_entry);
vb->v4l2_planes[0].bytesused = 0;
+ vb->v4l2_planes[0].data_offset = 0;
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
mutex_lock(&q->lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -939,12 +949,14 @@
}
vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ vb->v4l2_planes[0].data_offset = fill_buf_done->offset1;
vb->v4l2_buf.flags = V4L2_QCOM_BUF_FLAG_CODECCONFIG;
vb->v4l2_buf.timestamp = ns_to_timeval(0);
- dprintk(VIDC_DBG, "Filled length = %d; flags %x\n",
+ dprintk(VIDC_DBG, "Filled length = %d; offset = %d; flags %x\n",
vb->v4l2_planes[0].bytesused,
+ vb->v4l2_planes[0].data_offset,
vb->v4l2_buf.flags);
mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
@@ -2348,6 +2360,7 @@
queued_entry);
if (vb) {
vb->v4l2_planes[0].bytesused = 0;
+ vb->v4l2_planes[0].data_offset = 0;
mutex_lock(&inst->bufq[CAPTURE_PORT].lock);
vb2_buffer_done(vb,
VB2_BUF_STATE_DONE);
@@ -2365,6 +2378,7 @@
queued_entry);
if (vb) {
vb->v4l2_planes[0].bytesused = 0;
+ vb->v4l2_planes[0].data_offset = 0;
mutex_lock(&inst->bufq[OUTPUT_PORT].lock);
vb2_buffer_done(vb,
VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 44c9613..7c99ec3 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -184,7 +184,8 @@
if (!rc)
hfi_process_msg_packet(device->callback,
device->device_id,
- (struct vidc_hal_msg_pkt_hdr *) packet);
+ (struct vidc_hal_msg_pkt_hdr *) packet,
+ &device->sess_head, &device->session_lock);
} while (!rc);
if (rc != -ENODATA)
@@ -483,6 +484,7 @@
}
INIT_LIST_HEAD(&dev->sess_head);
+ mutex_init(&dev->session_lock);
if (!dev->event_queue.buffer) {
rc = q6_init_event_queue(dev);
@@ -566,7 +568,9 @@
rc = -EBADE;
goto err_session_init;
}
+ mutex_lock(&dev->session_lock);
list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
return new_session;
err_session_init:
@@ -629,7 +633,11 @@
sess_close = session;
dprintk(VIDC_DBG, "deleted the session: 0x%x",
sess_close->session_id);
+ mutex_lock(&((struct q6_hfi_device *)
+ sess_close->device)->session_lock);
list_del(&sess_close->list);
+ mutex_unlock(&((struct q6_hfi_device *)
+ sess_close->device)->session_lock);
kfree(sess_close);
return 0;
}
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 67aed5a..5f48a51 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -52,6 +52,7 @@
struct q6_resources resources;
struct msm_vidc_platform_resources *res;
void *apr;
+ struct mutex session_lock;
};
struct q6_apr_cmd_sys_init_packet {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 5416210..99c51bf 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1045,6 +1045,7 @@
INIT_LIST_HEAD(&dev->sess_head);
mutex_init(&dev->read_lock);
mutex_init(&dev->write_lock);
+ mutex_init(&dev->session_lock);
venus_hfi_set_registers(dev);
if (!dev->hal_client) {
@@ -1484,7 +1485,10 @@
else if (session_type == 2)
new_session->is_decoder = 1;
new_session->device = dev;
+
+ mutex_lock(&dev->session_lock);
list_add_tail(&new_session->list, &dev->sess_head);
+ mutex_unlock(&dev->session_lock);
if (create_pkt_cmd_sys_session_init(&pkt, (u32)new_session,
session_type, codec_type)) {
@@ -1554,7 +1558,11 @@
sess_close = session;
dprintk(VIDC_DBG, "deleted the session: 0x%p",
sess_close);
+ mutex_lock(&((struct venus_hfi_device *)
+ sess_close->device)->session_lock);
list_del(&sess_close->list);
+ mutex_unlock(&((struct venus_hfi_device *)
+ sess_close->device)->session_lock);
kfree(sess_close);
return 0;
}
@@ -1985,7 +1993,8 @@
while (!venus_hfi_iface_msgq_read(device, packet)) {
rc = hfi_process_msg_packet(device->callback,
device->device_id,
- (struct vidc_hal_msg_pkt_hdr *) packet);
+ (struct vidc_hal_msg_pkt_hdr *) packet,
+ &device->sess_head, &device->session_lock);
if (rc == HFI_MSG_EVENT_NOTIFY)
venus_hfi_process_msg_event_notify(
device, (void *)packet);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h
index a59a053..44cdf31 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.h
+++ b/drivers/media/platform/msm/vidc/venus_hfi.h
@@ -188,6 +188,7 @@
struct mutex read_lock;
struct mutex write_lock;
struct mutex clock_lock;
+ struct mutex session_lock;
msm_vidc_callback callback;
struct vidc_mem_addr iface_q_table;
struct vidc_mem_addr qdss;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 874738b..5059273 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -832,6 +832,7 @@
};
u32 hfi_process_msg_packet(msm_vidc_callback callback,
- u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr);
+ u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
+ struct list_head *sessions, struct mutex *session_lock);
#endif
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 3222ea0..4a8d974 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -595,6 +595,8 @@
case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: return "Intra Refresh AIR MBS";
case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: return "Intra Refresh AIR REF";
case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: return "Intra Refresh CIR MBS";
+ case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
+ return "VP8 Profile Level";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c99bed1..75a76c0 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -75,11 +75,14 @@
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
-obj-$(CONFIG_WCD9310_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9304_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9320_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-obj-$(CONFIG_WCD9306_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
-
+obj-$(CONFIG_WCD9310_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o \
+ wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9304_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o \
+ wcd9xxx-slimslave.o wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9320_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\
+ wcd9xxx-core-resource.o
+obj-$(CONFIG_WCD9306_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o\
+ wcd9xxx-slimslave.o wcd9xxx-core-resource.o
ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
diff --git a/drivers/mfd/wcd9xxx-core-resource.c b/drivers/mfd/wcd9xxx-core-resource.c
new file mode 100644
index 0000000..1791d72
--- /dev/null
+++ b/drivers/mfd/wcd9xxx-core-resource.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
+
+
+static enum wcd9xxx_intf_status wcd9xxx_intf = -1;
+
+int wcd9xxx_core_irq_init(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ int ret = 0;
+
+ if (wcd9xxx_core_res->irq != 1) {
+ ret = wcd9xxx_irq_init(wcd9xxx_core_res);
+ if (ret)
+ pr_err("IRQ initialization failed\n");
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_irq_init);
+
+int wcd9xxx_initialize_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ unsigned int irq,
+ unsigned int irq_base)
+{
+ wcd9xxx_core_res->irq = irq;
+ wcd9xxx_core_res->irq_base = irq_base;
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_initialize_irq);
+
+int wcd9xxx_core_res_init(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ int num_irqs, int num_irq_regs,
+ int (*codec_read)(struct wcd9xxx_core_resource*, unsigned short),
+ int (*codec_write)(struct wcd9xxx_core_resource*, unsigned short, u8),
+ int (*codec_bulk_read) (struct wcd9xxx_core_resource*, unsigned short,
+ int, u8*))
+{
+ mutex_init(&wcd9xxx_core_res->pm_lock);
+ wcd9xxx_core_res->wlock_holders = 0;
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+ init_waitqueue_head(&wcd9xxx_core_res->pm_wq);
+ pm_qos_add_request(&wcd9xxx_core_res->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ wcd9xxx_core_res->codec_reg_read = codec_read;
+ wcd9xxx_core_res->codec_reg_write = codec_write;
+ wcd9xxx_core_res->codec_bulk_read = codec_bulk_read;
+ wcd9xxx_core_res->num_irqs = num_irqs;
+ wcd9xxx_core_res->num_irq_regs = num_irq_regs;
+
+ pr_info("%s: num_irqs = %d, num_irq_regs = %d\n",
+ __func__, wcd9xxx_core_res->num_irqs,
+ wcd9xxx_core_res->num_irq_regs);
+
+ return 0;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_init);
+
+void wcd9xxx_core_res_deinit(struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ pm_qos_remove_request(&wcd9xxx_core_res->pm_qos_req);
+ mutex_destroy(&wcd9xxx_core_res->pm_lock);
+ wcd9xxx_core_res->codec_reg_read = NULL;
+ wcd9xxx_core_res->codec_reg_write = NULL;
+ wcd9xxx_core_res->codec_bulk_read = NULL;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_deinit);
+
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ enum wcd9xxx_pm_state o,
+ enum wcd9xxx_pm_state n)
+{
+ enum wcd9xxx_pm_state old;
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ old = wcd9xxx_core_res->pm_state;
+ if (old == o)
+ wcd9xxx_core_res->pm_state = n;
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+ return old;
+}
+EXPORT_SYMBOL(wcd9xxx_pm_cmpxchg);
+
+int wcd9xxx_core_res_suspend(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res,
+ pm_message_t pmesg)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ /*
+ * pm_qos_update_request() can be called after this suspend chain call
+ * started. thus suspend can be called while lock is being held
+ */
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_SLEEPABLE) {
+ pr_debug("%s: suspending system, state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_ASLEEP;
+ } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_AWAKE) {
+ /*
+ * unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
+ * then set to WCD9XXX_PM_ASLEEP
+ */
+ pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+ if (!(wait_event_timeout(wcd9xxx_core_res->pm_wq,
+ wcd9xxx_pm_cmpxchg(wcd9xxx_core_res,
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_ASLEEP) ==
+ WCD9XXX_PM_SLEEPABLE,
+ HZ))) {
+ pr_debug("%s: suspend failed state %d, wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ ret = -EBUSY;
+ } else {
+ pr_debug("%s: done, state %d, wlock %d\n", __func__,
+ wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ } else if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_warn("%s: system is already suspended, state %d, wlock %dn",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_suspend);
+
+int wcd9xxx_core_res_resume(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res)
+{
+ int ret = 0;
+
+ pr_debug("%s: enter\n", __func__);
+ mutex_lock(&wcd9xxx_core_res->pm_lock);
+ if (wcd9xxx_core_res->pm_state == WCD9XXX_PM_ASLEEP) {
+ pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
+ wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ wcd9xxx_core_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+ } else {
+ pr_warn("%s: system is already awake, state %d wlock %d\n",
+ __func__, wcd9xxx_core_res->pm_state,
+ wcd9xxx_core_res->wlock_holders);
+ }
+ mutex_unlock(&wcd9xxx_core_res->pm_lock);
+ wake_up_all(&wcd9xxx_core_res->pm_wq);
+
+ return ret;
+}
+EXPORT_SYMBOL(wcd9xxx_core_res_resume);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
+{
+ return wcd9xxx_intf;
+}
+EXPORT_SYMBOL(wcd9xxx_get_intf_type);
+
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status intf_status)
+{
+ wcd9xxx_intf = intf_status;
+}
+EXPORT_SYMBOL(wcd9xxx_set_intf_type);
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 9c35a55..d718c40 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -19,6 +19,7 @@
#include <linux/mfd/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9xxx/pdata.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
@@ -45,6 +46,9 @@
#define WCD9XXX_I2C_DIGITAL_1 2
#define WCD9XXX_I2C_DIGITAL_2 3
+#define ONDEMAND_REGULATOR true
+#define STATIC_REGULATOR (!ONDEMAND_REGULATOR)
+
/* Number of return values needs to be checked for each
* registration of Slimbus of I2C bus for each codec
*/
@@ -65,7 +69,6 @@
static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev);
struct wcd9xxx_i2c wcd9xxx_modules[MAX_WCD9XXX_DEVICE];
-static int wcd9xxx_intf = -1;
static int wcd9xxx_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface_reg)
@@ -89,7 +92,9 @@
return 0;
}
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg)
+static int __wcd9xxx_reg_read(
+ struct wcd9xxx *wcd9xxx,
+ unsigned short reg)
{
u8 val;
int ret;
@@ -103,7 +108,16 @@
else
return val;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_read);
+
+int wcd9xxx_reg_read(
+ struct wcd9xxx_core_resource *core_res,
+ unsigned short reg)
+{
+ struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+ return __wcd9xxx_reg_read(wcd9xxx, reg);
+
+}
+EXPORT_SYMBOL(wcd9xxx_reg_read);
static int wcd9xxx_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg)
@@ -122,8 +136,9 @@
return wcd9xxx->write_dev(wcd9xxx, reg, bytes, src, interface_reg);
}
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
- u8 val)
+static int __wcd9xxx_reg_write(
+ struct wcd9xxx *wcd9xxx,
+ unsigned short reg, u8 val)
{
int ret;
@@ -133,7 +148,15 @@
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_reg_write);
+
+int wcd9xxx_reg_write(
+ struct wcd9xxx_core_resource *core_res,
+ unsigned short reg, u8 val)
+{
+ struct wcd9xxx *wcd9xxx = (struct wcd9xxx *) core_res->parent;
+ return __wcd9xxx_reg_write(wcd9xxx, reg, val);
+}
+EXPORT_SYMBOL(wcd9xxx_reg_write);
static u8 wcd9xxx_pgd_la;
static u8 wcd9xxx_inf_la;
@@ -152,7 +175,7 @@
else
return val;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_read);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_read);
int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
u8 val)
@@ -165,37 +188,54 @@
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_interface_reg_write);
+EXPORT_SYMBOL(wcd9xxx_interface_reg_write);
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int count, u8 *buf)
+static int __wcd9xxx_bulk_read(
+ struct wcd9xxx *wcd9xxx,
+ unsigned short reg,
+ int count, u8 *buf)
{
int ret;
mutex_lock(&wcd9xxx->io_lock);
-
ret = wcd9xxx_read(wcd9xxx, reg, count, buf, false);
-
mutex_unlock(&wcd9xxx->io_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_read);
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
+int wcd9xxx_bulk_read(
+ struct wcd9xxx_core_resource *core_res,
+ unsigned short reg,
+ int count, u8 *buf)
+{
+ struct wcd9xxx *wcd9xxx =
+ (struct wcd9xxx *) core_res->parent;
+ return __wcd9xxx_bulk_read(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_read);
+
+static int __wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
int count, u8 *buf)
{
int ret;
mutex_lock(&wcd9xxx->io_lock);
-
ret = wcd9xxx_write(wcd9xxx, reg, count, buf, false);
-
mutex_unlock(&wcd9xxx->io_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_bulk_write);
+
+int wcd9xxx_bulk_write(
+ struct wcd9xxx_core_resource *core_res,
+ unsigned short reg, int count, u8 *buf)
+{
+ struct wcd9xxx *wcd9xxx =
+ (struct wcd9xxx *) core_res->parent;
+ return __wcd9xxx_bulk_write(wcd9xxx, reg, count, buf);
+}
+EXPORT_SYMBOL(wcd9xxx_bulk_write);
static int wcd9xxx_slim_read_device(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *dest, bool interface)
@@ -334,19 +374,19 @@
static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
{
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x4);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 0);
usleep_range(5000, 5000);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_CDC_CTL, 3);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 3);
}
static void wcd9xxx_bring_down(struct wcd9xxx *wcd9xxx)
{
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x7);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x6);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0xe);
+ __wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_LEAKAGE_CTL, 0x8);
}
static int wcd9xxx_reset(struct wcd9xxx *wcd9xxx)
@@ -385,13 +425,13 @@
int i, rc;
const struct wcd9xxx_codec_type *c, *d = NULL;
- rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
+ rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_0,
sizeof(wcd9xxx->id_minor),
(u8 *)&wcd9xxx->id_minor);
if (rc < 0)
goto exit;
- rc = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
+ rc = __wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_CHIP_ID_BYTE_2,
sizeof(wcd9xxx->id_major),
(u8 *)&wcd9xxx->id_major);
if (rc < 0)
@@ -431,7 +471,8 @@
if (d->version > -1) {
*version = d->version;
} else {
- rc = wcd9xxx_reg_read(wcd9xxx, WCD9XXX_A_CHIP_VERSION);
+ rc = __wcd9xxx_reg_read(wcd9xxx,
+ WCD9XXX_A_CHIP_VERSION);
if (rc < 0) {
d = NULL;
goto exit;
@@ -447,24 +488,94 @@
return d;
}
+static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
+{
+ return (wcd9xxx->codec_type->num_irqs / 8) +
+ ((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+}
+
+/*
+ * Interrupt table for v1 corresponds to newer version
+ * codecs (wcd9304 and wcd9310)
+ */
+static const struct intr_data intr_tbl_v1[] = {
+ {WCD9XXX_IRQ_SLIMBUS, false},
+ {WCD9XXX_IRQ_MBHC_INSERTION, true},
+ {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+ {WCD9XXX_IRQ_MBHC_RELEASE, true},
+ {WCD9XXX_IRQ_MBHC_PRESS, true},
+ {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+ {WCD9XXX_IRQ_MBHC_REMOVAL, true},
+ {WCD9XXX_IRQ_BG_PRECHARGE, false},
+ {WCD9XXX_IRQ_PA1_STARTUP, false},
+ {WCD9XXX_IRQ_PA2_STARTUP, false},
+ {WCD9XXX_IRQ_PA3_STARTUP, false},
+ {WCD9XXX_IRQ_PA4_STARTUP, false},
+ {WCD9XXX_IRQ_PA5_STARTUP, false},
+ {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+ {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+ {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+ {WCD9320_IRQ_EAR_PA_STARTUP, false},
+ {WCD9XXX_IRQ_RESERVED_0, false},
+ {WCD9XXX_IRQ_RESERVED_1, false},
+};
+
+/*
+ * Interrupt table for v2 corresponds to newer version
+ * codecs (wcd9320 and wcd9306)
+ */
+static const struct intr_data intr_tbl_v2[] = {
+ {WCD9XXX_IRQ_SLIMBUS, false},
+ {WCD9XXX_IRQ_MBHC_INSERTION, true},
+ {WCD9XXX_IRQ_MBHC_POTENTIAL, true},
+ {WCD9XXX_IRQ_MBHC_RELEASE, true},
+ {WCD9XXX_IRQ_MBHC_PRESS, true},
+ {WCD9XXX_IRQ_MBHC_SHORT_TERM, true},
+ {WCD9XXX_IRQ_MBHC_REMOVAL, true},
+ {WCD9320_IRQ_MBHC_JACK_SWITCH, true},
+ {WCD9306_IRQ_MBHC_JACK_SWITCH, true},
+ {WCD9XXX_IRQ_BG_PRECHARGE, false},
+ {WCD9XXX_IRQ_PA1_STARTUP, false},
+ {WCD9XXX_IRQ_PA2_STARTUP, false},
+ {WCD9XXX_IRQ_PA3_STARTUP, false},
+ {WCD9XXX_IRQ_PA4_STARTUP, false},
+ {WCD9XXX_IRQ_PA5_STARTUP, false},
+ {WCD9XXX_IRQ_MICBIAS1_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS2_PRECHARGE, false},
+ {WCD9XXX_IRQ_MICBIAS3_PRECHARGE, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, false},
+ {WCD9XXX_IRQ_EAR_PA_OCPL_FAULT, false},
+ {WCD9XXX_IRQ_HPH_L_PA_STARTUP, false},
+ {WCD9XXX_IRQ_HPH_R_PA_STARTUP, false},
+ {WCD9320_IRQ_EAR_PA_STARTUP, false},
+ {WCD9XXX_IRQ_RESERVED_0, false},
+ {WCD9XXX_IRQ_RESERVED_1, false},
+ {WCD9XXX_IRQ_MAD_AUDIO, false},
+ {WCD9XXX_IRQ_MAD_BEACON, false},
+ {WCD9XXX_IRQ_MAD_ULTRASOUND, false},
+ {WCD9XXX_IRQ_SPEAKER_CLIPPING, false},
+ {WCD9XXX_IRQ_VBAT_MONITOR_ATTACK, false},
+ {WCD9XXX_IRQ_VBAT_MONITOR_RELEASE, false},
+ {WCD9XXX_IRQ_RESERVED_2, false},
+};
+
static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
{
- int ret;
+ int ret = 0;
u8 version;
const struct wcd9xxx_codec_type *found;
+ struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
mutex_init(&wcd9xxx->io_lock);
mutex_init(&wcd9xxx->xfer_lock);
- mutex_init(&wcd9xxx->pm_lock);
- wcd9xxx->wlock_holders = 0;
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- init_waitqueue_head(&wcd9xxx->pm_wq);
- pm_qos_add_request(&wcd9xxx->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
dev_set_drvdata(wcd9xxx->dev, wcd9xxx);
-
wcd9xxx_bring_up(wcd9xxx);
found = wcd9xxx_check_codec_type(wcd9xxx, &version);
@@ -476,27 +587,46 @@
wcd9xxx->version = version;
}
- if (wcd9xxx->irq != -1) {
- ret = wcd9xxx_irq_init(wcd9xxx);
- if (ret) {
- pr_err("IRQ initialization failed\n");
- goto err;
- }
+ core_res->parent = wcd9xxx;
+ core_res->dev = wcd9xxx->dev;
+
+ if (wcd9xxx->codec_type->id_major == TABLA_MAJOR
+ || wcd9xxx->codec_type->id_major == SITAR_MAJOR) {
+ core_res->intr_table = intr_tbl_v1;
+ core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v1);
+ } else {
+ core_res->intr_table = intr_tbl_v2;
+ core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v2);
}
+ wcd9xxx_core_res_init(&wcd9xxx->core_res,
+ wcd9xxx->codec_type->num_irqs,
+ wcd9xxx_num_irq_regs(wcd9xxx),
+ wcd9xxx_reg_read, wcd9xxx_reg_write,
+ wcd9xxx_bulk_read);
+
+ if (wcd9xxx_core_irq_init(&wcd9xxx->core_res))
+ goto err;
+
ret = mfd_add_devices(wcd9xxx->dev, -1, found->dev, found->size,
NULL, 0);
if (ret != 0) {
dev_err(wcd9xxx->dev, "Failed to add children: %d\n", ret);
goto err_irq;
}
+
+ ret = device_init_wakeup(wcd9xxx->dev, true);
+ if (ret) {
+ dev_err(wcd9xxx->dev, "Device wakeup init failed: %d\n", ret);
+ goto err_irq;
+ }
+
return ret;
err_irq:
- wcd9xxx_irq_exit(wcd9xxx);
+ wcd9xxx_irq_exit(&wcd9xxx->core_res);
err:
wcd9xxx_bring_down(wcd9xxx);
- pm_qos_remove_request(&wcd9xxx->pm_qos_req);
- mutex_destroy(&wcd9xxx->pm_lock);
+ wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
return ret;
@@ -504,14 +634,14 @@
static void wcd9xxx_device_exit(struct wcd9xxx *wcd9xxx)
{
- wcd9xxx_irq_exit(wcd9xxx);
+ device_init_wakeup(wcd9xxx->dev, false);
+ wcd9xxx_irq_exit(&wcd9xxx->core_res);
wcd9xxx_bring_down(wcd9xxx);
wcd9xxx_free_reset(wcd9xxx);
- mutex_destroy(&wcd9xxx->pm_lock);
- pm_qos_remove_request(&wcd9xxx->pm_qos_req);
+ wcd9xxx_core_res_deinit(&wcd9xxx->core_res);
mutex_destroy(&wcd9xxx->io_lock);
mutex_destroy(&wcd9xxx->xfer_lock);
- if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
slim_remove_device(wcd9xxx->slim_slave);
kfree(wcd9xxx);
}
@@ -736,13 +866,6 @@
kfree(wcd9xxx->supplies);
}
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void)
-{
- return wcd9xxx_intf;
-}
-
-EXPORT_SYMBOL_GPL(wcd9xxx_get_intf_type);
-
struct wcd9xxx_i2c *get_i2c_wcd9xxx_device_info(u16 reg)
{
u16 mask = 0x0f00;
@@ -894,13 +1017,16 @@
int ret = 0;
int wcd9xx_index = 0;
struct device *dev;
+ int intf_type;
- pr_debug("%s: interface status %d\n", __func__, wcd9xxx_intf);
- if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
+ intf_type = wcd9xxx_get_intf_type();
+
+ pr_debug("%s: interface status %d\n", __func__, intf_type);
+ if (intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
dev_dbg(&client->dev, "%s:Codec is detected in slimbus mode\n",
__func__);
return -ENODEV;
- } else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+ } else if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
ret = wcd9xxx_i2c_get_client_index(client, &wcd9xx_index);
if (ret != 0)
dev_err(&client->dev, "%s: I2C set codec I2C\n"
@@ -912,7 +1038,7 @@
wcd9xxx_modules[wcd9xx_index].client = client;
}
return ret;
- } else if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_PROBING) {
+ } else if (intf_type == WCD9XXX_INTERFACE_TYPE_PROBING) {
dev = &client->dev;
if (client->dev.of_node) {
dev_dbg(&client->dev, "%s:Platform data\n"
@@ -979,10 +1105,9 @@
wcd9xxx_modules[wcd9xx_index].client = client;
wcd9xxx->read_dev = wcd9xxx_i2c_read;
wcd9xxx->write_dev = wcd9xxx_i2c_write;
- if (!wcd9xxx->dev->of_node) {
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
- }
+ if (!wcd9xxx->dev->of_node)
+ wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+ pdata->irq, pdata->irq_base);
ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
@@ -998,7 +1123,7 @@
if (val != wcd9xxx->codec_type->i2c_chip_status)
pr_err("%s: unknown chip status 0x%x\n", __func__, val);
- wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_I2C;
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
return ret;
} else
@@ -1277,17 +1402,18 @@
}
ret = wcd9xxx_process_supplies(dev, pdata, static_prop_name,
- static_cnt, false, 0);
+ static_cnt, STATIC_REGULATOR, 0);
if (ret)
goto err;
ret = wcd9xxx_process_supplies(dev, pdata, ond_prop_name,
- ond_cnt, true, static_cnt);
+ ond_cnt, ONDEMAND_REGULATOR, static_cnt);
if (ret)
goto err;
ret = wcd9xxx_process_supplies(dev, pdata, cp_supplies_name,
- cp_supplies_cnt, false, static_cnt + ond_cnt);
+ cp_supplies_cnt, ONDEMAND_REGULATOR,
+ static_cnt + ond_cnt);
if (ret)
goto err;
@@ -1380,8 +1506,11 @@
struct wcd9xxx *wcd9xxx;
struct wcd9xxx_pdata *pdata;
int ret = 0;
+ int intf_type;
- if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_I2C) {
+ intf_type = wcd9xxx_get_intf_type();
+
+ if (intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
dev_dbg(&slim->dev, "%s:Codec is detected in I2C mode\n",
__func__);
return -ENODEV;
@@ -1459,10 +1588,9 @@
wcd9xxx->write_dev = wcd9xxx_slim_write_device;
wcd9xxx_pgd_la = wcd9xxx->slim->laddr;
wcd9xxx->slim_slave = &pdata->slimbus_slave_device;
- if (!wcd9xxx->dev->of_node) {
- wcd9xxx->irq = pdata->irq;
- wcd9xxx->irq_base = pdata->irq_base;
- }
+ if (!wcd9xxx->dev->of_node)
+ wcd9xxx_initialize_irq(&wcd9xxx->core_res,
+ pdata->irq, pdata->irq_base);
ret = slim_add_device(slim->ctrl, wcd9xxx->slim_slave);
if (ret) {
@@ -1480,7 +1608,7 @@
goto err_slim_add;
}
wcd9xxx_inf_la = wcd9xxx->slim_slave->laddr;
- wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_SLIMBUS;
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_SLIMBUS);
ret = wcd9xxx_device_init(wcd9xxx);
if (ret) {
@@ -1534,29 +1662,10 @@
return 0;
}
-static int wcd9xxx_resume(struct wcd9xxx *wcd9xxx)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- mutex_lock(&wcd9xxx->pm_lock);
- if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_debug("%s: resuming system, state %d, wlock %d\n", __func__,
- wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- } else {
- pr_warn("%s: system is already awake, state %d wlock %d\n",
- __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- }
- mutex_unlock(&wcd9xxx->pm_lock);
- wake_up_all(&wcd9xxx->pm_wq);
-
- return ret;
-}
-
static int wcd9xxx_device_up(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
+ struct wcd9xxx_core_resource *wcd9xxx_res = &wcd9xxx->core_res;
if (wcd9xxx->slim_device_bootup) {
wcd9xxx->slim_device_bootup = false;
@@ -1567,86 +1676,60 @@
pr_err("%s: Resetting Codec failed\n", __func__);
wcd9xxx_bring_up(wcd9xxx);
- wcd9xxx->post_reset(wcd9xxx);
+ ret = wcd9xxx_irq_init(wcd9xxx_res);
+ if (ret) {
+ pr_err("%s: wcd9xx_irq_init failed : %d\n", __func__, ret);
+ } else {
+ if (wcd9xxx->post_reset)
+ ret = wcd9xxx->post_reset(wcd9xxx);
+ }
return ret;
}
static int wcd9xxx_slim_device_up(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+ dev_dbg(wcd9xxx->dev, "%s: device up\n", __func__);
return wcd9xxx_device_up(wcd9xxx);
}
+static int wcd9xxx_slim_device_down(struct slim_device *sldev)
+{
+ struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
+
+ wcd9xxx_irq_exit(&wcd9xxx->core_res);
+ if (wcd9xxx->dev_down)
+ wcd9xxx->dev_down(wcd9xxx);
+ dev_dbg(wcd9xxx->dev, "%s: device down\n", __func__);
+ return 0;
+}
+
static int wcd9xxx_slim_resume(struct slim_device *sldev)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
- return wcd9xxx_resume(wcd9xxx);
+ return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
}
static int wcd9xxx_i2c_resume(struct i2c_client *i2cdev)
{
struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
if (wcd9xxx)
- return wcd9xxx_resume(wcd9xxx);
+ return wcd9xxx_core_res_resume(&wcd9xxx->core_res);
else
return 0;
}
-static int wcd9xxx_suspend(struct wcd9xxx *wcd9xxx, pm_message_t pmesg)
-{
- int ret = 0;
-
- pr_debug("%s: enter\n", __func__);
- /*
- * pm_qos_update_request() can be called after this suspend chain call
- * started. thus suspend can be called while lock is being held
- */
- mutex_lock(&wcd9xxx->pm_lock);
- if (wcd9xxx->pm_state == WCD9XXX_PM_SLEEPABLE) {
- pr_debug("%s: suspending system, state %d, wlock %d\n",
- __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- wcd9xxx->pm_state = WCD9XXX_PM_ASLEEP;
- } else if (wcd9xxx->pm_state == WCD9XXX_PM_AWAKE) {
- /* unlock to wait for pm_state == WCD9XXX_PM_SLEEPABLE
- * then set to WCD9XXX_PM_ASLEEP */
- pr_debug("%s: waiting to suspend system, state %d, wlock %d\n",
- __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- mutex_unlock(&wcd9xxx->pm_lock);
- if (!(wait_event_timeout(wcd9xxx->pm_wq,
- wcd9xxx_pm_cmpxchg(wcd9xxx,
- WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_ASLEEP) ==
- WCD9XXX_PM_SLEEPABLE,
- HZ))) {
- pr_debug("%s: suspend failed state %d, wlock %d\n",
- __func__, wcd9xxx->pm_state,
- wcd9xxx->wlock_holders);
- ret = -EBUSY;
- } else {
- pr_debug("%s: done, state %d, wlock %d\n", __func__,
- wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- }
- mutex_lock(&wcd9xxx->pm_lock);
- } else if (wcd9xxx->pm_state == WCD9XXX_PM_ASLEEP) {
- pr_warn("%s: system is already suspended, state %d, wlock %dn",
- __func__, wcd9xxx->pm_state, wcd9xxx->wlock_holders);
- }
- mutex_unlock(&wcd9xxx->pm_lock);
-
- return ret;
-}
-
static int wcd9xxx_slim_suspend(struct slim_device *sldev, pm_message_t pmesg)
{
struct wcd9xxx *wcd9xxx = slim_get_devicedata(sldev);
- return wcd9xxx_suspend(wcd9xxx, pmesg);
+ return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
}
static int wcd9xxx_i2c_suspend(struct i2c_client *i2cdev, pm_message_t pmesg)
{
struct wcd9xxx *wcd9xxx = dev_get_drvdata(&i2cdev->dev);
if (wcd9xxx)
- return wcd9xxx_suspend(wcd9xxx, pmesg);
+ return wcd9xxx_core_res_suspend(&wcd9xxx->core_res, pmesg);
else
return 0;
}
@@ -1733,6 +1816,7 @@
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
+ .device_down = wcd9xxx_slim_device_down,
};
static const struct slim_device_id tapan_slimtest_id[] = {
@@ -1751,6 +1835,7 @@
.resume = wcd9xxx_slim_resume,
.suspend = wcd9xxx_slim_suspend,
.device_up = wcd9xxx_slim_device_up,
+ .device_down = wcd9xxx_slim_device_down,
};
static struct i2c_device_id wcd9xxx_id_table[] = {
@@ -1800,7 +1885,7 @@
int ret[NUM_WCD9XXX_REG_RET];
int i = 0;
- wcd9xxx_intf = WCD9XXX_INTERFACE_TYPE_PROBING;
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
ret[0] = slim_driver_register(&tabla_slim_driver);
if (ret[0])
@@ -1844,6 +1929,7 @@
static void __exit wcd9xxx_exit(void)
{
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
}
module_exit(wcd9xxx_exit);
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 062351d..dc32efd 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -15,10 +15,9 @@
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
-#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
-#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
#include <linux/delay.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
@@ -40,57 +39,76 @@
};
#endif
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq);
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int irq);
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx);
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx);
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq);
+static int virq_to_phyirq(
+ struct wcd9xxx_core_resource *wcd9xxx_res, int virq);
+static int phyirq_to_virq(
+ struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res);
+static void wcd9xxx_irq_put_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res);
+static int wcd9xxx_map_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res, int irq);
static void wcd9xxx_irq_lock(struct irq_data *data)
{
- struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- mutex_lock(&wcd9xxx->irq_lock);
+ struct wcd9xxx_core_resource *wcd9xxx_res =
+ irq_data_get_irq_chip_data(data);
+ mutex_lock(&wcd9xxx_res->irq_lock);
}
static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
{
- struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
+ struct wcd9xxx_core_resource *wcd9xxx_res =
+ irq_data_get_irq_chip_data(data);
int i;
- if (ARRAY_SIZE(wcd9xxx->irq_masks_cur) > WCD9XXX_NUM_IRQ_REGS ||
- ARRAY_SIZE(wcd9xxx->irq_masks_cache) > WCD9XXX_NUM_IRQ_REGS) {
+ if ((ARRAY_SIZE(wcd9xxx_res->irq_masks_cur) >
+ WCD9XXX_MAX_IRQ_REGS) ||
+ (ARRAY_SIZE(wcd9xxx_res->irq_masks_cache) >
+ WCD9XXX_MAX_IRQ_REGS)) {
pr_err("%s: Array Size out of bound\n", __func__);
return;
}
+ if (!wcd9xxx_res->codec_reg_write) {
+ pr_err("%s: Codec reg write callback function not defined\n",
+ __func__);
+ return;
+ }
- for (i = 0; i < ARRAY_SIZE(wcd9xxx->irq_masks_cur); i++) {
+ for (i = 0; i < ARRAY_SIZE(wcd9xxx_res->irq_masks_cur); i++) {
/* If there's been a change in the mask write it back
* to the hardware.
*/
- if (wcd9xxx->irq_masks_cur[i] != wcd9xxx->irq_masks_cache[i]) {
- wcd9xxx->irq_masks_cache[i] = wcd9xxx->irq_masks_cur[i];
- wcd9xxx_reg_write(wcd9xxx,
+ if (wcd9xxx_res->irq_masks_cur[i] !=
+ wcd9xxx_res->irq_masks_cache[i]) {
+
+ wcd9xxx_res->irq_masks_cache[i] =
+ wcd9xxx_res->irq_masks_cur[i];
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MASK0 + i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_res->irq_masks_cur[i]);
}
}
- mutex_unlock(&wcd9xxx->irq_lock);
+ mutex_unlock(&wcd9xxx_res->irq_lock);
}
static void wcd9xxx_irq_enable(struct irq_data *data)
{
- struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
- wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
+ struct wcd9xxx_core_resource *wcd9xxx_res =
+ irq_data_get_irq_chip_data(data);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+ wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)] &=
~(BYTE_BIT_MASK(wcd9xxx_irq));
}
static void wcd9xxx_irq_disable(struct irq_data *data)
{
- struct wcd9xxx *wcd9xxx = irq_data_get_irq_chip_data(data);
- int wcd9xxx_irq = virq_to_phyirq(wcd9xxx, data->irq);
- wcd9xxx->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
+ struct wcd9xxx_core_resource *wcd9xxx_res =
+ irq_data_get_irq_chip_data(data);
+ int wcd9xxx_irq = virq_to_phyirq(wcd9xxx_res, data->irq);
+ wcd9xxx_res->irq_masks_cur[BIT_BYTE(wcd9xxx_irq)]
|= BYTE_BIT_MASK(wcd9xxx_irq);
}
@@ -108,21 +126,8 @@
.irq_mask = wcd9xxx_irq_mask,
};
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
- enum wcd9xxx_pm_state o,
- enum wcd9xxx_pm_state n)
-{
- enum wcd9xxx_pm_state old;
- mutex_lock(&wcd9xxx->pm_lock);
- old = wcd9xxx->pm_state;
- if (old == o)
- wcd9xxx->pm_state = n;
- mutex_unlock(&wcd9xxx->pm_lock);
- return old;
-}
-EXPORT_SYMBOL_GPL(wcd9xxx_pm_cmpxchg);
-
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx)
+bool wcd9xxx_lock_sleep(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
enum wcd9xxx_pm_state os;
@@ -138,164 +143,154 @@
* As interrupt line is still active, codec will have another IRQ to
* retry shortly.
*/
- mutex_lock(&wcd9xxx->pm_lock);
- if (wcd9xxx->wlock_holders++ == 0) {
+ mutex_lock(&wcd9xxx_res->pm_lock);
+ if (wcd9xxx_res->wlock_holders++ == 0) {
pr_debug("%s: holding wake lock\n", __func__);
- pm_qos_update_request(&wcd9xxx->pm_qos_req,
+ pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
msm_cpuidle_get_deep_idle_latency());
}
- mutex_unlock(&wcd9xxx->pm_lock);
- if (!wait_event_timeout(wcd9xxx->pm_wq,
- ((os = wcd9xxx_pm_cmpxchg(wcd9xxx, WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_AWAKE)) ==
- WCD9XXX_PM_SLEEPABLE ||
- (os == WCD9XXX_PM_AWAKE)),
+ mutex_unlock(&wcd9xxx_res->pm_lock);
+ os = wcd9xxx_pm_cmpxchg(wcd9xxx_res,
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_AWAKE);
+ if (!wait_event_timeout(wcd9xxx_res->pm_wq,
+ (os == WCD9XXX_PM_SLEEPABLE ||
+ os == WCD9XXX_PM_AWAKE),
msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
__func__,
- WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
- wcd9xxx->wlock_holders);
- wcd9xxx_unlock_sleep(wcd9xxx);
+ WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx_res->pm_state,
+ wcd9xxx_res->wlock_holders);
+ wcd9xxx_unlock_sleep(wcd9xxx_res);
return false;
}
- wake_up_all(&wcd9xxx->pm_wq);
+ wake_up_all(&wcd9xxx_res->pm_wq);
return true;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_lock_sleep);
+EXPORT_SYMBOL(wcd9xxx_lock_sleep);
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_unlock_sleep(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
- mutex_lock(&wcd9xxx->pm_lock);
- if (--wcd9xxx->wlock_holders == 0) {
+ mutex_lock(&wcd9xxx_res->pm_lock);
+ if (--wcd9xxx_res->wlock_holders == 0) {
pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
- __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+ __func__, wcd9xxx_res->pm_state, WCD9XXX_PM_SLEEPABLE);
/*
* if wcd9xxx_lock_sleep failed, pm_state would be still
* WCD9XXX_PM_ASLEEP, don't overwrite
*/
- if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
- wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
- pm_qos_update_request(&wcd9xxx->pm_qos_req,
+ if (likely(wcd9xxx_res->pm_state == WCD9XXX_PM_AWAKE))
+ wcd9xxx_res->pm_state = WCD9XXX_PM_SLEEPABLE;
+ pm_qos_update_request(&wcd9xxx_res->pm_qos_req,
PM_QOS_DEFAULT_VALUE);
}
- mutex_unlock(&wcd9xxx->pm_lock);
- wake_up_all(&wcd9xxx->pm_wq);
+ mutex_unlock(&wcd9xxx_res->pm_lock);
+ wake_up_all(&wcd9xxx_res->pm_wq);
}
-EXPORT_SYMBOL_GPL(wcd9xxx_unlock_sleep);
+EXPORT_SYMBOL(wcd9xxx_unlock_sleep);
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *wcd9xxx_res)
{
- mutex_lock(&wcd9xxx->nested_irq_lock);
+ mutex_lock(&wcd9xxx_res->nested_irq_lock);
}
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *wcd9xxx_res)
{
- mutex_unlock(&wcd9xxx->nested_irq_lock);
+ mutex_unlock(&wcd9xxx_res->nested_irq_lock);
}
-static bool wcd9xxx_is_mbhc_irq(struct wcd9xxx *wcd9xxx, int irqbit)
-{
- if ((irqbit <= WCD9XXX_IRQ_MBHC_INSERTION) &&
- (irqbit >= WCD9XXX_IRQ_MBHC_REMOVAL))
- return true;
- else if (wcd9xxx->codec_type->id_major == TAIKO_MAJOR &&
- irqbit == WCD9320_IRQ_MBHC_JACK_SWITCH)
- return true;
- else if (wcd9xxx->codec_type->id_major == TAPAN_MAJOR &&
- irqbit == WCD9306_IRQ_MBHC_JACK_SWITCH)
- return true;
- else
- return false;
-}
-static void wcd9xxx_irq_dispatch(struct wcd9xxx *wcd9xxx, int irqbit)
+static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
+ struct intr_data *irqdata)
{
- if (wcd9xxx_is_mbhc_irq(wcd9xxx, irqbit)) {
- wcd9xxx_nested_irq_lock(wcd9xxx);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit),
- BYTE_BIT_MASK(irqbit));
- if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
- handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
- wcd9xxx_nested_irq_unlock(wcd9xxx);
- } else {
- wcd9xxx_nested_irq_lock(wcd9xxx);
- handle_nested_irq(phyirq_to_virq(wcd9xxx, irqbit));
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0 +
- BIT_BYTE(irqbit),
- BYTE_BIT_MASK(irqbit));
- if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
- wcd9xxx_nested_irq_unlock(wcd9xxx);
+ int irqbit = irqdata->intr_num;
+ if (!wcd9xxx_res->codec_reg_write) {
+ pr_err("%s: codec read/write callback not defined\n",
+ __func__);
+ return;
}
-}
-static int wcd9xxx_num_irq_regs(const struct wcd9xxx *wcd9xxx)
-{
- return (wcd9xxx->codec_type->num_irqs / 8) +
- ((wcd9xxx->codec_type->num_irqs % 8) ? 1 : 0);
+ if (irqdata->clear_first) {
+ wcd9xxx_nested_irq_lock(wcd9xxx_res);
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
+
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_MODE, 0x02);
+ handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+ wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+ } else {
+ wcd9xxx_nested_irq_lock(wcd9xxx_res);
+ handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
+ BYTE_BIT_MASK(irqbit));
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_MODE, 0x02);
+
+ wcd9xxx_nested_irq_unlock(wcd9xxx_res);
+ }
}
static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
{
int ret;
int i;
+ struct intr_data irqdata;
char linebuf[128];
- struct wcd9xxx *wcd9xxx = data;
- int num_irq_regs = wcd9xxx_num_irq_regs(wcd9xxx);
- u8 status[num_irq_regs], status1[num_irq_regs];
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 1);
+ struct wcd9xxx_core_resource *wcd9xxx_res = data;
+ int num_irq_regs = wcd9xxx_res->num_irq_regs;
+ u8 status[num_irq_regs], status1[num_irq_regs];
- if (unlikely(wcd9xxx_lock_sleep(wcd9xxx) == false)) {
- dev_err(wcd9xxx->dev, "Failed to hold suspend\n");
+ if (unlikely(wcd9xxx_lock_sleep(wcd9xxx_res) == false)) {
+ dev_err(wcd9xxx_res->dev, "Failed to hold suspend\n");
return IRQ_NONE;
}
- ret = wcd9xxx_bulk_read(wcd9xxx, WCD9XXX_A_INTR_STATUS0,
+
+ if (!wcd9xxx_res->codec_bulk_read) {
+ dev_err(wcd9xxx_res->dev,
+ "%s: Codec Bulk Register read callback not supplied\n",
+ __func__);
+ goto err_disable_irq;
+ }
+
+ ret = wcd9xxx_res->codec_bulk_read(wcd9xxx_res,
+ WCD9XXX_A_INTR_STATUS0,
num_irq_regs, status);
+
if (ret < 0) {
- dev_err(wcd9xxx->dev, "Failed to read interrupt status: %d\n",
- ret);
- dev_err(wcd9xxx->dev, "Disable irq %d\n", wcd9xxx->irq);
- disable_irq_wake(wcd9xxx->irq);
- disable_irq_nosync(wcd9xxx->irq);
- wcd9xxx_unlock_sleep(wcd9xxx);
- return IRQ_NONE;
+ dev_err(wcd9xxx_res->dev,
+ "Failed to read interrupt status: %d\n", ret);
+ goto err_disable_irq;
}
/* Apply masking */
for (i = 0; i < num_irq_regs; i++)
- status[i] &= ~wcd9xxx->irq_masks_cur[i];
+ status[i] &= ~wcd9xxx_res->irq_masks_cur[i];
memcpy(status1, status, sizeof(status1));
/* Find out which interrupt was triggered and call that interrupt's
* handler function
- */
- if (status[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &
- BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS)) {
- wcd9xxx_irq_dispatch(wcd9xxx, WCD9XXX_IRQ_SLIMBUS);
- status1[BIT_BYTE(WCD9XXX_IRQ_SLIMBUS)] &=
- ~BYTE_BIT_MASK(WCD9XXX_IRQ_SLIMBUS);
- }
-
- /* Since codec has only one hardware irq line which is shared by
+ *
+ * Since codec has only one hardware irq line which is shared by
* codec's different internal interrupts, so it's possible master irq
* handler dispatches multiple nested irq handlers after breaking
- * order. Dispatch MBHC interrupts order to follow MBHC state
- * machine's order */
- for (i = WCD9XXX_IRQ_MBHC_INSERTION;
- i >= WCD9XXX_IRQ_MBHC_REMOVAL; i--) {
- if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
- wcd9xxx_irq_dispatch(wcd9xxx, i);
- status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
- }
- }
- for (i = WCD9XXX_IRQ_BG_PRECHARGE; i < wcd9xxx->codec_type->num_irqs;
- i++) {
- if (status[BIT_BYTE(i)] & BYTE_BIT_MASK(i)) {
- wcd9xxx_irq_dispatch(wcd9xxx, i);
- status1[BIT_BYTE(i)] &= ~BYTE_BIT_MASK(i);
+ * order. Dispatch interrupts in the order that is maintained by
+ * the interrupt table.
+ */
+ for (i = 0; i < wcd9xxx_res->intr_table_size; i++) {
+ irqdata = wcd9xxx_res->intr_table[i];
+ if (status[BIT_BYTE(irqdata.intr_num)] &
+ BYTE_BIT_MASK(irqdata.intr_num)) {
+ wcd9xxx_irq_dispatch(wcd9xxx_res, &irqdata);
+ status1[BIT_BYTE(irqdata.intr_num)] &=
+ ~BYTE_BIT_MASK(irqdata.intr_num);
}
}
@@ -319,45 +314,58 @@
}
memset(status, 0xff, num_irq_regs);
- wcd9xxx_bulk_write(wcd9xxx, WCD9XXX_A_INTR_CLEAR0,
+ wcd9xxx_bulk_write(wcd9xxx_res, WCD9XXX_A_INTR_CLEAR0,
num_irq_regs, status);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MODE, 0x02);
+ wcd9xxx_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_MODE, 0x02);
}
- wcd9xxx_unlock_sleep(wcd9xxx);
+ wcd9xxx_unlock_sleep(wcd9xxx_res);
return IRQ_HANDLED;
+
+err_disable_irq:
+ dev_err(wcd9xxx_res->dev,
+ "Disable irq %d\n", wcd9xxx_res->irq);
+
+ disable_irq_wake(wcd9xxx_res->irq);
+ disable_irq_nosync(wcd9xxx_res->irq);
+ wcd9xxx_unlock_sleep(wcd9xxx_res);
+ return IRQ_NONE;
}
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data)
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+ int irq, void *data)
{
- free_irq(phyirq_to_virq(wcd9xxx, irq), data);
+ free_irq(phyirq_to_virq(wcd9xxx_res, irq), data);
}
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
{
- enable_irq(phyirq_to_virq(wcd9xxx, irq));
+ enable_irq(phyirq_to_virq(wcd9xxx_res, irq));
}
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
{
- disable_irq_nosync(phyirq_to_virq(wcd9xxx, irq));
+ disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq));
}
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq)
+void wcd9xxx_disable_irq_sync(
+ struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
{
- disable_irq(phyirq_to_virq(wcd9xxx, irq));
+ disable_irq(phyirq_to_virq(wcd9xxx_res, irq));
}
-static int wcd9xxx_irq_setup_downstream_irq(struct wcd9xxx *wcd9xxx)
+static int wcd9xxx_irq_setup_downstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
int irq, virq, ret;
pr_debug("%s: enter\n", __func__);
- for (irq = 0; irq < wcd9xxx->codec_type->num_irqs; irq++) {
+ for (irq = 0; irq < wcd9xxx_res->num_irqs; irq++) {
/* Map OF irq */
- virq = wcd9xxx_map_irq(wcd9xxx, irq);
+ virq = wcd9xxx_map_irq(wcd9xxx_res, irq);
pr_debug("%s: irq %d -> %d\n", __func__, irq, virq);
if (virq == NO_IRQ) {
pr_err("%s, No interrupt specifier for irq %d\n",
@@ -365,14 +373,14 @@
return NO_IRQ;
}
- ret = irq_set_chip_data(virq, wcd9xxx);
+ ret = irq_set_chip_data(virq, wcd9xxx_res);
if (ret) {
pr_err("%s: Failed to configure irq %d (%d)\n",
__func__, irq, ret);
return ret;
}
- if (wcd9xxx->irq_level_high[irq])
+ if (wcd9xxx_res->irq_level_high[irq])
irq_set_chip_and_handler(virq, &wcd9xxx_irq_chip,
handle_level_irq);
else
@@ -387,91 +395,100 @@
return 0;
}
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx)
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
{
int i, ret;
- u8 irq_level[wcd9xxx_num_irq_regs(wcd9xxx)];
+ u8 irq_level[wcd9xxx_res->num_irq_regs];
- mutex_init(&wcd9xxx->irq_lock);
- mutex_init(&wcd9xxx->nested_irq_lock);
+ mutex_init(&wcd9xxx_res->irq_lock);
+ mutex_init(&wcd9xxx_res->nested_irq_lock);
- wcd9xxx->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx);
- if (!wcd9xxx->irq) {
+ wcd9xxx_res->irq = wcd9xxx_irq_get_upstream_irq(wcd9xxx_res);
+ if (!wcd9xxx_res->irq) {
pr_warn("%s: irq driver is not yet initialized\n", __func__);
- mutex_destroy(&wcd9xxx->irq_lock);
- mutex_destroy(&wcd9xxx->nested_irq_lock);
+ mutex_destroy(&wcd9xxx_res->irq_lock);
+ mutex_destroy(&wcd9xxx_res->nested_irq_lock);
return -EPROBE_DEFER;
}
- pr_debug("%s: probed irq %d\n", __func__, wcd9xxx->irq);
+ pr_debug("%s: probed irq %d\n", __func__, wcd9xxx_res->irq);
/* Setup downstream IRQs */
- ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx);
+ ret = wcd9xxx_irq_setup_downstream_irq(wcd9xxx_res);
if (ret) {
pr_err("%s: Failed to setup downstream IRQ\n", __func__);
- wcd9xxx_irq_put_upstream_irq(wcd9xxx);
- mutex_destroy(&wcd9xxx->irq_lock);
- mutex_destroy(&wcd9xxx->nested_irq_lock);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+ mutex_destroy(&wcd9xxx_res->irq_lock);
+ mutex_destroy(&wcd9xxx_res->nested_irq_lock);
return ret;
}
/* All other wcd9xxx interrupts are edge triggered */
- wcd9xxx->irq_level_high[0] = true;
+ wcd9xxx_res->irq_level_high[0] = true;
/* mask all the interrupts */
- memset(irq_level, 0, wcd9xxx_num_irq_regs(wcd9xxx));
- for (i = 0; i < wcd9xxx->codec_type->num_irqs; i++) {
- wcd9xxx->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
- wcd9xxx->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+ memset(irq_level, 0, wcd9xxx_res->num_irq_regs);
+ for (i = 0; i < wcd9xxx_res->num_irqs; i++) {
+ wcd9xxx_res->irq_masks_cur[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
+ wcd9xxx_res->irq_masks_cache[BIT_BYTE(i)] |= BYTE_BIT_MASK(i);
irq_level[BIT_BYTE(i)] |=
- wcd9xxx->irq_level_high[i] << (i % BITS_PER_BYTE);
+ wcd9xxx_res->irq_level_high[i] << (i % BITS_PER_BYTE);
}
- for (i = 0; i < wcd9xxx_num_irq_regs(wcd9xxx); i++) {
+ if (!wcd9xxx_res->codec_reg_write) {
+ dev_err(wcd9xxx_res->dev,
+ "%s: Codec Register write callback not defined\n",
+ __func__);
+ ret = -EINVAL;
+ goto fail_irq_init;
+ }
+
+ for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
/* Initialize interrupt mask and level registers */
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_LEVEL0 + i,
- irq_level[i]);
- wcd9xxx_reg_write(wcd9xxx, WCD9XXX_A_INTR_MASK0 + i,
- wcd9xxx->irq_masks_cur[i]);
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_LEVEL0 + i,
+ irq_level[i]);
+ wcd9xxx_res->codec_reg_write(wcd9xxx_res,
+ WCD9XXX_A_INTR_MASK0 + i,
+ wcd9xxx_res->irq_masks_cur[i]);
}
- ret = request_threaded_irq(wcd9xxx->irq, NULL, wcd9xxx_irq_thread,
+ ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "wcd9xxx", wcd9xxx);
+ "wcd9xxx", wcd9xxx_res);
if (ret != 0)
- dev_err(wcd9xxx->dev, "Failed to request IRQ %d: %d\n",
- wcd9xxx->irq, ret);
+ dev_err(wcd9xxx_res->dev, "Failed to request IRQ %d: %d\n",
+ wcd9xxx_res->irq, ret);
else {
- ret = enable_irq_wake(wcd9xxx->irq);
- if (ret == 0) {
- ret = device_init_wakeup(wcd9xxx->dev, 1);
- if (ret) {
- dev_err(wcd9xxx->dev, "Failed to init device"
- "wakeup : %d\n", ret);
- disable_irq_wake(wcd9xxx->irq);
- }
- } else
- dev_err(wcd9xxx->dev, "Failed to set wake interrupt on"
- " IRQ %d: %d\n", wcd9xxx->irq, ret);
+ ret = enable_irq_wake(wcd9xxx_res->irq);
if (ret)
- free_irq(wcd9xxx->irq, wcd9xxx);
+ dev_err(wcd9xxx_res->dev,
+ "Failed to set wake interrupt on IRQ %d: %d\n",
+ wcd9xxx_res->irq, ret);
+ if (ret)
+ free_irq(wcd9xxx_res->irq, wcd9xxx_res);
}
- if (ret) {
- pr_err("%s: Failed to init wcd9xxx irq\n", __func__);
- wcd9xxx_irq_put_upstream_irq(wcd9xxx);
- mutex_destroy(&wcd9xxx->irq_lock);
- mutex_destroy(&wcd9xxx->nested_irq_lock);
- }
+ if (ret)
+ goto fail_irq_init;
return ret;
+
+fail_irq_init:
+ dev_err(wcd9xxx_res->dev,
+ "%s: Failed to init wcd9xxx irq\n", __func__);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
+ mutex_destroy(&wcd9xxx_res->irq_lock);
+ mutex_destroy(&wcd9xxx_res->nested_irq_lock);
+ return ret;
}
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq, irq_handler_t handler,
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *wcd9xxx_res,
+ int irq, irq_handler_t handler,
const char *name, void *data)
{
int virq;
- virq = phyirq_to_virq(wcd9xxx, irq);
+ virq = phyirq_to_virq(wcd9xxx_res, irq);
/*
* ARM needs us to explicitly flag the IRQ as valid
@@ -487,43 +504,52 @@
name, data);
}
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx)
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res)
{
- if (wcd9xxx->irq) {
- disable_irq_wake(wcd9xxx->irq);
- free_irq(wcd9xxx->irq, wcd9xxx);
+ dev_dbg(wcd9xxx_res->dev, "%s: Cleaning up irq %d\n", __func__,
+ wcd9xxx_res->irq);
+
+ if (wcd9xxx_res->irq) {
+ disable_irq_wake(wcd9xxx_res->irq);
+ free_irq(wcd9xxx_res->irq, wcd9xxx_res);
/* Release parent's of node */
- wcd9xxx_irq_put_upstream_irq(wcd9xxx);
- device_init_wakeup(wcd9xxx->dev, 0);
+ wcd9xxx_irq_put_upstream_irq(wcd9xxx_res);
}
- mutex_destroy(&wcd9xxx->irq_lock);
- mutex_destroy(&wcd9xxx->nested_irq_lock);
+ mutex_destroy(&wcd9xxx_res->irq_lock);
+ mutex_destroy(&wcd9xxx_res->nested_irq_lock);
}
#ifndef CONFIG_OF
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(
+ struct wcd9xxx_core_resource *wcd9xxx_res,
+ int offset)
{
- return wcd9xxx->irq_base + offset;
+ return wcd9xxx_res->irq_base + offset;
}
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(
+ struct wcd9xxx_core_resource *wcd9xxx_res,
+ int virq)
{
- return virq - wcd9xxx->irq_base;
+ return virq - wcd9xxx_res->irq_base;
}
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
- return wcd9xxx->irq;
+ return wcd9xxx_res->irq;
}
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
/* Do nothing */
}
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_core_res, int irq)
{
- return phyirq_to_virq(wcd9xxx, irq);
+ return phyirq_to_virq(wcd9xxx_core_res, irq);
}
#else
int __init wcd9xxx_irq_of_init(struct device_node *node,
@@ -555,12 +581,12 @@
}
static struct wcd9xxx_irq_drv_data *
-wcd9xxx_get_irq_drv_d(const struct wcd9xxx *wcd9xxx)
+wcd9xxx_get_irq_drv_d(const struct wcd9xxx_core_resource *wcd9xxx_res)
{
struct device_node *pnode;
struct irq_domain *domain;
- pnode = of_irq_find_parent(wcd9xxx->dev->of_node);
+ pnode = of_irq_find_parent(wcd9xxx_res->dev->of_node);
/* Shouldn't happen */
if (unlikely(!pnode))
return NULL;
@@ -569,11 +595,11 @@
return (struct wcd9xxx_irq_drv_data *)domain->host_data;
}
-static int phyirq_to_virq(struct wcd9xxx *wcd9xxx, int offset)
+static int phyirq_to_virq(struct wcd9xxx_core_resource *wcd9xxx_res, int offset)
{
struct wcd9xxx_irq_drv_data *data;
- data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
if (!data) {
pr_warn("%s: not registered to interrupt controller\n",
__func__);
@@ -582,21 +608,22 @@
return irq_linear_revmap(data->domain, offset);
}
-static int virq_to_phyirq(struct wcd9xxx *wcd9xxx, int virq)
+static int virq_to_phyirq(struct wcd9xxx_core_resource *wcd9xxx_res, int virq)
{
struct irq_data *irq_data = irq_get_irq_data(virq);
return irq_data->hwirq;
}
-static unsigned int wcd9xxx_irq_get_upstream_irq(struct wcd9xxx *wcd9xxx)
+static unsigned int wcd9xxx_irq_get_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
struct wcd9xxx_irq_drv_data *data;
/* Hold parent's of node */
- if (!of_node_get(of_irq_find_parent(wcd9xxx->dev->of_node)))
+ if (!of_node_get(of_irq_find_parent(wcd9xxx_res->dev->of_node)))
return -EINVAL;
- data = wcd9xxx_get_irq_drv_d(wcd9xxx);
+ data = wcd9xxx_get_irq_drv_d(wcd9xxx_res);
if (!data) {
pr_err("%s: interrupt controller is not registerd\n", __func__);
return 0;
@@ -606,15 +633,16 @@
return data->irq;
}
-static void wcd9xxx_irq_put_upstream_irq(struct wcd9xxx *wcd9xxx)
+static void wcd9xxx_irq_put_upstream_irq(
+ struct wcd9xxx_core_resource *wcd9xxx_res)
{
/* Hold parent's of node */
- of_node_put(of_irq_find_parent(wcd9xxx->dev->of_node));
+ of_node_put(of_irq_find_parent(wcd9xxx_res->dev->of_node));
}
-static int wcd9xxx_map_irq(struct wcd9xxx *wcd9xxx, int irq)
+static int wcd9xxx_map_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq)
{
- return of_irq_to_resource(wcd9xxx->dev->of_node, irq, NULL);
+ return of_irq_to_resource(wcd9xxx_res->dev->of_node, irq, NULL);
}
static int __devinit wcd9xxx_irq_probe(struct platform_device *pdev)
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index 2fdc427..b77c826 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -31,6 +31,8 @@
#define QPNP_LPG_CHANNEL_BASE "qpnp-lpg-channel-base"
#define QPNP_LPG_LUT_BASE "qpnp-lpg-lut-base"
+#define QPNP_PWM_MODE_ONLY_SUB_TYPE 0x0B
+
/* LPG Control for LPG_PATTERN_CONFIG */
#define QPNP_RAMP_DIRECTION_SHIFT 4
#define QPNP_RAMP_DIRECTION_MASK 0x10
@@ -51,10 +53,13 @@
#define QPNP_SET_PWM_CLK_SUB_TYPE(val, clk, pwm_size) \
do { \
val = (clk + 1) & QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE; \
- val |= ((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
- QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE; \
+ val |= (((pwm_size > 6 ? QPNP_PWM_SIZE_9_BIT_SUB_TYPE : 0) << \
+ QPNP_PWM_SIZE_SHIFT_SUB_TYPE) & QPNP_PWM_SIZE_MASK_SUB_TYPE); \
} while (0)
+#define QPNP_GET_PWM_SIZE_SUB_TYPE(reg) ((reg & QPNP_PWM_SIZE_MASK_SUB_TYPE) \
+ >> QPNP_PWM_SIZE_SHIFT_SUB_TYPE)
+
#define QPNP_PWM_SIZE_SHIFT 4
#define QPNP_PWM_SIZE_MASK 0x30
#define QPNP_PWM_FREQ_CLK_SELECT_MASK 0x03
@@ -361,6 +366,9 @@
#define QPNP_DISABLE_LPG_MODE qpnp_set_control(0, 0, 0, 0, 1)
#define QPNP_IS_PWM_CONFIG_SELECTED(val) (val & QPNP_PWM_SRC_SELECT_MASK)
+#define QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE 0x80
+#define QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE 0x0
+#define QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE 0x80
static inline void qpnp_convert_to_lut_flags(int *flags,
struct qpnp_lut_config *l_config)
@@ -581,14 +589,16 @@
struct qpnp_lpg_chip *chip = pwm->chip;
struct qpnp_pwm_config *pwm_config = &pwm->pwm_config;
- if (chip->sub_type == 0x0B)
+ if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
QPNP_SET_PWM_CLK_SUB_TYPE(val, pwm_config->period.clk,
pwm_config->period.pwm_size);
- else
+ mask = QPNP_PWM_SIZE_MASK_SUB_TYPE |
+ QPNP_PWM_FREQ_CLK_SELECT_MASK_SUB_TYPE;
+ } else {
QPNP_SET_PWM_CLK(val, pwm_config->period.clk,
pwm_config->period.pwm_size);
-
- mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+ mask = QPNP_PWM_SIZE_MASK | QPNP_PWM_FREQ_CLK_SELECT_MASK;
+ }
qpnp_lpg_save(&chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK],
mask, val);
@@ -612,9 +622,14 @@
struct qpnp_lpg_config *lpg_config = &chip->lpg_config;
int rc;
- pwm_size = QPNP_GET_PWM_SIZE(
+ if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+ pwm_size = QPNP_GET_PWM_SIZE_SUB_TYPE(
+ chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) ?
+ QPNP_MAX_PWM_BIT_SIZE : QPNP_MIN_PWM_BIT_SIZE;
+ else
+ pwm_size = QPNP_GET_PWM_SIZE(
chip->qpnp_lpg_registers[QPNP_LPG_PWM_SIZE_CLK]) +
- QPNP_MIN_PWM_BIT_SIZE;
+ QPNP_MIN_PWM_BIT_SIZE;
max_pwm_value = (1 << pwm_size) - 1;
@@ -643,13 +658,14 @@
if (rc)
return rc;
- if (chip->sub_type == 0x0B) {
+ if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
value = QPNP_PWM_SYNC_VALUE & QPNP_PWM_SYNC_MASK;
rc = spmi_ext_register_writel(chip->spmi_dev->ctrl,
chip->spmi_dev->sid,
SPMI_LPG_REG_ADDR(lpg_config->base_addr,
SPMI_LPG_PWM_SYNC), &value, 1);
}
+
return rc;
}
@@ -710,6 +726,9 @@
struct qpnp_lpg_chip *chip = pwm->chip;
u8 value, mask;
+ if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE)
+ return 0;
+
value = QPNP_ENABLE_PWM_CONTROL;
mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
@@ -1007,14 +1026,24 @@
u8 value, mask;
int rc;
- if (state == QPNP_PWM_ENABLE)
- value = qpnp_enable_pwm_mode(&pwm->pwm_config);
- else
- value = QPNP_DISABLE_PWM_MODE;
+ if (chip->sub_type == QPNP_PWM_MODE_ONLY_SUB_TYPE) {
+ if (state == QPNP_PWM_ENABLE)
+ value = QPNP_ENABLE_PWM_MODE_ONLY_SUB_TYPE;
+ else
+ value = QPNP_DISABLE_PWM_MODE_ONLY_SUB_TYPE;
- mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
- QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
- QPNP_PWM_EN_RAMP_GEN_MASK;
+ mask = QPNP_PWM_MODE_ONLY_ENABLE_DISABLE_MASK_SUB_TYPE;
+ } else {
+ if (state == QPNP_PWM_ENABLE)
+ value = qpnp_enable_pwm_mode(&pwm->pwm_config);
+ else
+ value = QPNP_DISABLE_PWM_MODE;
+
+ mask = QPNP_EN_PWM_HIGH_MASK | QPNP_EN_PWM_LO_MASK |
+ QPNP_EN_PWM_OUTPUT_MASK | QPNP_PWM_SRC_SELECT_MASK |
+ QPNP_PWM_EN_RAMP_GEN_MASK;
+ }
+
rc = qpnp_lpg_save_and_write(value, mask,
&pwm->chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL],
@@ -1164,7 +1193,8 @@
spin_lock_irqsave(&pwm->chip->lpg_lock, flags);
if (QPNP_IS_PWM_CONFIG_SELECTED(
- chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+ chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+ chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
rc = qpnp_lpg_configure_pwm_state(pwm, QPNP_PWM_ENABLE);
} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
rc = qpnp_lpg_configure_lut_state(pwm, QPNP_LUT_ENABLE);
@@ -1329,7 +1359,8 @@
if (pwm_config->in_use) {
if (QPNP_IS_PWM_CONFIG_SELECTED(
- chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL])) {
+ chip->qpnp_lpg_registers[QPNP_ENABLE_CONTROL]) ||
+ chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED) {
rc = qpnp_lpg_configure_pwm_state(pwm,
QPNP_PWM_DISABLE);
} else if (!(chip->flags & QPNP_PWM_LUT_NOT_SUPPORTED)) {
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index a87ade3..158b5bd 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -3048,6 +3048,8 @@
int status = get_battery_status(chip);
if (chip->battery_status != status) {
+ pr_debug("status = %d, shadow status = %d\n",
+ status, chip->battery_status);
if (status == POWER_SUPPLY_STATUS_CHARGING) {
pr_debug("charging started\n");
charging_began(chip);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 2ad0926..552f0c0 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -86,6 +86,7 @@
#define CHGR_STATUS 0x09
#define CHGR_BAT_IF_VCP 0x42
#define CHGR_BAT_IF_BATFET_CTRL1 0x90
+#define CHGR_BAT_IF_SPARE 0xDF
#define CHGR_MISC_BOOT_DONE 0x42
#define CHGR_BUCK_PSTG_CTRL 0x73
#define CHGR_BUCK_COMPARATOR_OVRIDE_1 0xEB
@@ -208,7 +209,7 @@
#define POWER_STAGE_WA BIT(2)
struct qpnp_chg_irq {
- unsigned int irq;
+ int irq;
unsigned long disabled;
};
@@ -287,7 +288,6 @@
struct qpnp_chg_irq chg_failed;
struct qpnp_chg_irq chg_vbatdet_lo;
struct qpnp_chg_irq batt_pres;
- struct qpnp_chg_irq vchg_loop;
struct qpnp_chg_irq batt_temp_ok;
bool bat_is_cool;
bool bat_is_warm;
@@ -338,9 +338,10 @@
struct work_struct adc_disable_work;
struct delayed_work arb_stop_work;
struct delayed_work eoc_work;
- struct wake_lock eoc_wake_lock;
+ struct work_struct soc_check_work;
struct qpnp_chg_regulator otg_vreg;
struct qpnp_chg_regulator boost_vreg;
+ struct qpnp_chg_regulator batfet_vreg;
struct qpnp_vadc_chip *vadc_dev;
struct qpnp_adc_tm_chip *adc_tm_dev;
struct mutex jeita_configure_lock;
@@ -968,17 +969,6 @@
qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev, &chip->adc_param);
}
-static irqreturn_t
-qpnp_chg_buck_vchg_loop_irq_handler(int irq, void *_chip)
-{
- struct qpnp_chg_chip *chip = _chip;
-
- if (chip->bat_if_base)
- power_supply_changed(&chip->batt_psy);
-
- return IRQ_HANDLED;
-}
-
#define EOC_CHECK_PERIOD_MS 10000
static irqreturn_t
qpnp_chg_vbatdet_lo_irq_handler(int irq, void *_chip)
@@ -997,17 +987,20 @@
if (!chip->charging_disabled && (chg_sts & FAST_CHG_ON_IRQ)) {
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
- wake_lock(&chip->eoc_wake_lock);
- qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
- } else {
- qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ pm_stay_awake(chip->dev);
}
+ qpnp_chg_disable_irq(&chip->chg_vbatdet_lo);
+ pr_debug("psy changed usb_psy\n");
power_supply_changed(chip->usb_psy);
- if (chip->dc_chgpth_base)
+ if (chip->dc_chgpth_base) {
+ pr_debug("psy changed dc_psy\n");
power_supply_changed(&chip->dc_psy);
- if (chip->bat_if_base)
+ }
+ if (chip->bat_if_base) {
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
+ }
return IRQ_HANDLED;
}
@@ -1074,11 +1067,13 @@
chip->usb_present = usb_present;
if (!usb_present) {
qpnp_chg_usb_suspend_enable(chip, 1);
- chip->chg_done = false;
+ if (!qpnp_chg_is_dc_chg_plugged_in(chip))
+ chip->chg_done = false;
chip->prev_usb_max_ma = -EINVAL;
} else {
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ schedule_work(&chip->soc_check_work);
}
power_supply_set_present(chip->usb_psy, chip->usb_present);
@@ -1096,6 +1091,7 @@
batt_temp_good = qpnp_chg_is_batt_temp_ok(chip);
pr_debug("batt-temp triggered: %d\n", batt_temp_good);
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
return IRQ_HANDLED;
}
@@ -1111,14 +1107,16 @@
if (chip->batt_present ^ batt_present) {
chip->batt_present = batt_present;
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
+ pr_debug("psy changed usb_psy\n");
power_supply_changed(chip->usb_psy);
- if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
&& batt_present) {
pr_debug("enabling vadc notifications\n");
schedule_work(&chip->adc_measure_work);
- } else if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ } else if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
&& !batt_present) {
schedule_work(&chip->adc_disable_work);
pr_debug("disabling vadc notifications\n");
@@ -1139,12 +1137,16 @@
if (chip->dc_present ^ dc_present) {
chip->dc_present = dc_present;
- if (!dc_present)
+ if (!dc_present && !qpnp_chg_is_usb_chg_plugged_in(chip)) {
chip->chg_done = false;
- else
+ } else {
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ schedule_work(&chip->soc_check_work);
+ }
+ pr_debug("psy changed dc_psy\n");
power_supply_changed(&chip->dc_psy);
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
}
@@ -1167,11 +1169,16 @@
if (rc)
pr_err("Failed to write chg_fail clear bit!\n");
- if (chip->bat_if_base)
+ if (chip->bat_if_base) {
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
+ }
+ pr_debug("psy changed usb_psy\n");
power_supply_changed(chip->usb_psy);
- if (chip->dc_chgpth_base)
+ if (chip->dc_chgpth_base) {
+ pr_debug("psy changed dc_psy\n");
power_supply_changed(&chip->dc_psy);
+ }
return IRQ_HANDLED;
}
@@ -1183,8 +1190,10 @@
pr_debug("TRKL IRQ triggered\n");
chip->chg_done = false;
- if (chip->bat_if_base)
+ if (chip->bat_if_base) {
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
+ }
return IRQ_HANDLED;
}
@@ -1202,21 +1211,31 @@
pr_debug("FAST_CHG IRQ triggered\n");
chip->chg_done = false;
- if (chip->bat_if_base)
+ if (chip->bat_if_base) {
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
+ }
+
+ pr_debug("psy changed usb_psy\n");
power_supply_changed(chip->usb_psy);
- if (chip->dc_chgpth_base)
+
+ if (chip->dc_chgpth_base) {
+ pr_debug("psy changed dc_psy\n");
power_supply_changed(&chip->dc_psy);
+ }
+
if (chip->resuming_charging) {
chip->resuming_charging = false;
qpnp_chg_set_appropriate_vbatdet(chip);
}
+ if (!chip->charging_disabled) {
+ schedule_delayed_work(&chip->eoc_work,
+ msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
+ pm_stay_awake(chip->dev);
+ }
+
qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
- if (chgr_sts & FAST_CHG_ON_IRQ)
- qpnp_chg_enable_irq(&chip->vchg_loop);
- else
- qpnp_chg_disable_irq(&chip->vchg_loop);
return IRQ_HANDLED;
}
@@ -1568,19 +1587,26 @@
get_prop_capacity(struct qpnp_chg_chip *chip)
{
union power_supply_propval ret = {0,};
+ int battery_status, charger_in;
if (chip->use_default_batt_values || !get_prop_batt_present(chip))
return DEFAULT_CAPACITY;
if (chip->bms_psy) {
chip->bms_psy->get_property(chip->bms_psy,
- POWER_SUPPLY_PROP_CAPACITY, &ret);
- if (get_prop_batt_status(chip) == POWER_SUPPLY_STATUS_FULL
+ POWER_SUPPLY_PROP_CAPACITY, &ret);
+ battery_status = get_prop_batt_status(chip);
+ charger_in = qpnp_chg_is_usb_chg_plugged_in(chip) ||
+ qpnp_chg_is_dc_chg_plugged_in(chip);
+
+ if (battery_status != POWER_SUPPLY_STATUS_CHARGING
+ && charger_in
&& !chip->resuming_charging
&& !chip->charging_disabled
&& chip->soc_resume_limit
&& ret.intval <= chip->soc_resume_limit) {
- pr_debug("resuming charging at %d%% soc\n", ret.intval);
+ pr_debug("resuming charging at %d%% soc\n",
+ ret.intval);
chip->resuming_charging = true;
qpnp_chg_set_appropriate_vbatdet(chip);
qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -1703,6 +1729,7 @@
skip_set_iusb_max:
pr_debug("end of power supply changed\n");
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
}
@@ -2249,6 +2276,63 @@
.list_voltage = qpnp_chg_regulator_boost_list_voltage,
};
+#define BATFET_LPM_MASK 0xC0
+#define BATFET_LPM 0x40
+#define BATFET_NO_LPM 0x00
+static int
+qpnp_chg_regulator_batfet_enable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + CHGR_BAT_IF_SPARE,
+ BATFET_LPM_MASK, BATFET_NO_LPM, 1);
+ if (rc)
+ pr_err("failed to write to batt_if rc=%d\n", rc);
+ return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_disable(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int rc;
+
+ rc = qpnp_chg_masked_write(chip,
+ chip->bat_if_base + CHGR_BAT_IF_SPARE,
+ BATFET_LPM_MASK, BATFET_LPM, 1);
+ if (rc)
+ pr_err("failed to write to batt_if rc=%d\n", rc);
+ return rc;
+}
+
+static int
+qpnp_chg_regulator_batfet_is_enabled(struct regulator_dev *rdev)
+{
+ struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int rc;
+ u8 reg;
+
+ rc = qpnp_chg_read(chip, ®,
+ chip->bat_if_base + CHGR_BAT_IF_SPARE, 1);
+ if (rc) {
+ pr_err("failed to read batt_if rc=%d\n", rc);
+ return rc;
+ }
+
+ if (reg && BATFET_LPM_MASK == BATFET_NO_LPM)
+ return 1;
+
+ return 0;
+}
+
+static struct regulator_ops qpnp_chg_batfet_vreg_ops = {
+ .enable = qpnp_chg_regulator_batfet_enable,
+ .disable = qpnp_chg_regulator_batfet_disable,
+ .is_enabled = qpnp_chg_regulator_batfet_is_enabled,
+};
+
#define MIN_DELTA_MV_TO_INCREASE_VDD_MAX 13
#define MAX_DELTA_VDD_MAX_MV 30
static void
@@ -2275,6 +2359,7 @@
}
#define CONSECUTIVE_COUNT 3
+#define VBATDET_MAX_ERR_MV 50
static void
qpnp_eoc_work(struct work_struct *work)
{
@@ -2282,10 +2367,12 @@
struct qpnp_chg_chip *chip = container_of(dwork,
struct qpnp_chg_chip, eoc_work);
static int count;
+ static int vbat_low_count;
int ibat_ma, vbat_mv, rc = 0;
u8 batt_sts = 0, buck_sts = 0, chg_sts = 0;
+ bool vbat_lower_than_vbatdet;
- wake_lock(&chip->eoc_wake_lock);
+ pm_stay_awake(chip->dev);
qpnp_chg_charge_en(chip, !chip->charging_disabled);
rc = qpnp_chg_read(chip, &batt_sts, INT_RT_STS(chip->bat_if_base), 1);
@@ -2323,11 +2410,24 @@
pr_debug("ibat_ma = %d vbat_mv = %d term_current_ma = %d\n",
ibat_ma, vbat_mv, chip->term_current);
- if ((!(chg_sts & VBAT_DET_LOW_IRQ)) && (vbat_mv <
- (chip->max_voltage_mv - chip->resume_delta_mv))) {
- pr_debug("woke up too early\n");
- qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
- goto stop_eoc;
+ vbat_lower_than_vbatdet = !(chg_sts & VBAT_DET_LOW_IRQ);
+ if (vbat_lower_than_vbatdet && vbat_mv <
+ (chip->max_voltage_mv - chip->resume_delta_mv
+ - VBATDET_MAX_ERR_MV)) {
+ vbat_low_count++;
+ pr_debug("woke up too early vbat_mv = %d, max_mv = %d, resume_mv = %d tolerance_mv = %d low_count = %d\n",
+ vbat_mv, chip->max_voltage_mv,
+ chip->resume_delta_mv,
+ VBATDET_MAX_ERR_MV, vbat_low_count);
+ if (vbat_low_count >= CONSECUTIVE_COUNT) {
+ pr_debug("woke up too early stopping\n");
+ qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
+ goto stop_eoc;
+ } else {
+ goto check_again_later;
+ }
+ } else {
+ vbat_low_count = 0;
}
if (buck_sts & VDD_LOOP_IRQ)
@@ -2345,8 +2445,13 @@
} else {
if (count == CONSECUTIVE_COUNT) {
pr_info("End of Charging\n");
- qpnp_chg_charge_en(chip, 0);
chip->chg_done = true;
+ qpnp_chg_charge_en(chip, 0);
+ /* sleep for a second before enabling */
+ msleep(2000);
+ qpnp_chg_charge_en(chip,
+ !chip->charging_disabled);
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
qpnp_chg_enable_irq(&chip->chg_vbatdet_lo);
goto stop_eoc;
@@ -2357,16 +2462,27 @@
}
} else {
pr_debug("not charging\n");
- goto stop_eoc;
+ goto stop_eoc;
}
+check_again_later:
schedule_delayed_work(&chip->eoc_work,
msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
return;
stop_eoc:
+ vbat_low_count = 0;
count = 0;
- wake_unlock(&chip->eoc_wake_lock);
+ pm_relax(chip->dev);
+}
+
+static void
+qpnp_chg_soc_check_work(struct work_struct *work)
+{
+ struct qpnp_chg_chip *chip = container_of(work,
+ struct qpnp_chg_chip, soc_check_work);
+
+ get_prop_capacity(chip);
}
#define HYSTERISIS_DECIDEGC 20
@@ -2737,6 +2853,7 @@
return -EINVAL;
}
+ pr_debug("psy changed dc_psy\n");
power_supply_changed(&chip->dc_psy);
return rc;
}
@@ -2759,8 +2876,17 @@
break;
case POWER_SUPPLY_PROP_CHARGING_ENABLED:
chip->charging_disabled = !(val->intval);
- qpnp_chg_charge_en(chip, !chip->charging_disabled);
- qpnp_chg_force_run_on_batt(chip, chip->charging_disabled);
+ if (chip->charging_disabled) {
+ /* disable charging */
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_force_run_on_batt(chip,
+ chip->charging_disabled);
+ } else {
+ /* enable charging */
+ qpnp_chg_force_run_on_batt(chip,
+ chip->charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ }
break;
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
qpnp_batt_system_temp_level_set(chip, val->intval);
@@ -2775,6 +2901,7 @@
return -EINVAL;
}
+ pr_debug("psy changed batt_psy\n");
power_supply_changed(&chip->batt_psy);
return rc;
}
@@ -2908,7 +3035,7 @@
rc |= devm_request_irq(chip->dev,
chip->chg_vbatdet_lo.irq,
qpnp_chg_vbatdet_lo_irq_handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_RISING,
"vbat-det-lo", chip);
if (rc < 0) {
pr_err("Can't request %d vbat-det-lo: %d\n",
@@ -2966,24 +3093,6 @@
case SMBB_BUCK_SUBTYPE:
case SMBBP_BUCK_SUBTYPE:
case SMBCL_BUCK_SUBTYPE:
- chip->vchg_loop.irq = spmi_get_irq_byname(spmi,
- spmi_resource, "vchg-loop");
- if (chip->vchg_loop.irq < 0) {
- pr_err("Unable to get vchg-loop irq\n");
- return rc;
- }
- rc = devm_request_irq(chip->dev, chip->vchg_loop.irq,
- qpnp_chg_buck_vchg_loop_irq_handler,
- IRQF_TRIGGER_RISING,
- "vchg-loop", chip);
- if (rc < 0) {
- pr_err("Can't request %d vchg-loop irq: %d\n",
- chip->vchg_loop.irq, rc);
- return rc;
- }
-
- enable_irq_wake(chip->vchg_loop.irq);
- qpnp_chg_disable_irq(&chip->vchg_loop);
break;
case SMBB_USB_CHGPTH_SUBTYPE:
@@ -3230,6 +3339,32 @@
pr_debug("failed to force on VREF_BAT_THM rc=%d\n", rc);
return rc;
}
+
+ init_data = of_get_regulator_init_data(chip->dev,
+ spmi_resource->of_node);
+
+ if (init_data->constraints.name) {
+ rdesc = &(chip->batfet_vreg.rdesc);
+ rdesc->owner = THIS_MODULE;
+ rdesc->type = REGULATOR_VOLTAGE;
+ rdesc->ops = &qpnp_chg_batfet_vreg_ops;
+ rdesc->name = init_data->constraints.name;
+
+ init_data->constraints.valid_ops_mask
+ |= REGULATOR_CHANGE_STATUS;
+
+ chip->batfet_vreg.rdev = regulator_register(rdesc,
+ chip->dev, init_data, chip,
+ spmi_resource->of_node);
+ if (IS_ERR(chip->batfet_vreg.rdev)) {
+ rc = PTR_ERR(chip->batfet_vreg.rdev);
+ chip->batfet_vreg.rdev = NULL;
+ if (rc != -EPROBE_DEFER)
+ pr_err("batfet reg failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
break;
case SMBB_USB_CHGPTH_SUBTYPE:
case SMBBP_USB_CHGPTH_SUBTYPE:
@@ -3435,7 +3570,7 @@
}
/* Look up JEITA compliance parameters if cool and warm temp provided */
- if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
+ if (chip->cool_bat_decidegc || chip->warm_bat_decidegc) {
chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg");
if (IS_ERR(chip->adc_tm_dev)) {
rc = PTR_ERR(chip->adc_tm_dev);
@@ -3573,11 +3708,11 @@
if (rc != -EPROBE_DEFER)
pr_err("vadc property missing\n");
goto fail_chg_enable;
+ }
rc = qpnp_chg_load_battery_data(chip);
if (rc)
goto fail_chg_enable;
- }
}
}
@@ -3637,16 +3772,6 @@
0xff,
0x00, 1);
- rc = qpnp_chg_masked_write(chip,
- chip->buck_base + SEC_ACCESS,
- 0xFF,
- 0xA5, 1);
-
- rc = qpnp_chg_masked_write(chip,
- chip->buck_base + BUCK_TEST_SMBC_MODES,
- 0xFF,
- 0x80, 1);
-
if (chip->duty_cycle_100p) {
rc = qpnp_buck_set_100_duty_cycle_enable(chip,
1);
@@ -3748,10 +3873,9 @@
qpnp_bat_if_adc_disable_work);
}
- wake_lock_init(&chip->eoc_wake_lock,
- WAKE_LOCK_SUSPEND, "qpnp-chg-eoc-lock");
INIT_DELAYED_WORK(&chip->eoc_work, qpnp_eoc_work);
INIT_DELAYED_WORK(&chip->arb_stop_work, qpnp_arb_stop_work);
+ INIT_WORK(&chip->soc_check_work, qpnp_chg_soc_check_work);
if (chip->dc_chgpth_base) {
chip->dc_psy.name = "qpnp-dc";
@@ -3787,7 +3911,7 @@
}
}
- if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
&& chip->bat_if_base) {
chip->adc_param.low_temp = chip->cool_bat_decidegc;
chip->adc_param.high_temp = chip->warm_bat_decidegc;
@@ -3823,8 +3947,8 @@
goto unregister_dc_psy;
}
- qpnp_chg_usb_usbin_valid_irq_handler(USBIN_VALID_IRQ, chip);
- qpnp_chg_dc_dcin_valid_irq_handler(DCIN_VALID_IRQ, chip);
+ qpnp_chg_usb_usbin_valid_irq_handler(chip->usbin_valid.irq, chip);
+ qpnp_chg_dc_dcin_valid_irq_handler(chip->dcin_valid.irq, chip);
power_supply_set_present(chip->usb_psy,
qpnp_chg_is_usb_chg_plugged_in(chip));
@@ -3861,7 +3985,7 @@
qpnp_charger_remove(struct spmi_device *spmi)
{
struct qpnp_chg_chip *chip = dev_get_drvdata(&spmi->dev);
- if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+ if ((chip->cool_bat_decidegc || chip->warm_bat_decidegc)
&& chip->batt_present) {
qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
&chip->adc_param);
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 205bf37..0c9959c 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -998,7 +998,6 @@
container_of(qmi, struct msm_slim_ctrl, qmi);
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
- int i;
ngd_slim_enable(dev, false);
/* disconnect BAM pipes */
@@ -1007,14 +1006,9 @@
if (dev->use_tx_msgqs == MSM_MSGQ_ENABLED)
dev->use_tx_msgqs = MSM_MSGQ_DOWN;
msm_slim_sps_exit(dev, false);
- mutex_lock(&ctrl->m_ctrl);
/* device up should be called again after SSR */
list_for_each_entry(sbdev, &ctrl->devs, dev_list)
- sbdev->notified = false;
- /* invalidate logical addresses */
- for (i = 0; i < ctrl->num_dev; i++)
- ctrl->addrt[i].valid = false;
- mutex_unlock(&ctrl->m_ctrl);
+ slim_report_absent(sbdev);
pr_info("SLIM ADSP SSR (DOWN) done");
}
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index 201470f..b074289 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -286,20 +286,41 @@
.release = slim_dev_release,
};
-static void slim_report_present(struct work_struct *work)
+static void slim_report(struct work_struct *work)
{
u8 laddr;
- int ret;
+ int ret, i;
struct slim_driver *sbdrv;
struct slim_device *sbdev =
container_of(work, struct slim_device, wd);
- if (sbdev->notified || !sbdev->dev.driver)
+ struct slim_controller *ctrl = sbdev->ctrl;
+ if (!sbdev->dev.driver)
+ return;
+ /* check if device-up or down needs to be called */
+ mutex_lock(&ctrl->m_ctrl);
+ /* address no longer valid, means device reported absent */
+ for (i = 0; i < ctrl->num_dev; i++) {
+ if (sbdev->laddr == ctrl->addrt[i].laddr &&
+ ctrl->addrt[i].valid == false &&
+ sbdev->notified)
+ break;
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+ sbdrv = to_slim_driver(sbdev->dev.driver);
+ if (i < ctrl->num_dev) {
+ sbdev->notified = false;
+ if (sbdrv->device_down)
+ sbdrv->device_down(sbdev);
+ return;
+ }
+ if (sbdev->notified)
return;
ret = slim_get_logical_addr(sbdev, sbdev->e_addr, 6, &laddr);
- sbdrv = to_slim_driver(sbdev->dev.driver);
- if (!ret && sbdrv->device_up) {
- sbdev->notified = true;
- sbdrv->device_up(sbdev);
+ if (!ret) {
+ if (sbdrv)
+ sbdev->notified = true;
+ if (sbdrv->device_up)
+ sbdrv->device_up(sbdev);
}
}
@@ -322,7 +343,7 @@
INIT_LIST_HEAD(&sbdev->mark_define);
INIT_LIST_HEAD(&sbdev->mark_suspend);
INIT_LIST_HEAD(&sbdev->mark_removal);
- INIT_WORK(&sbdev->wd, slim_report_present);
+ INIT_WORK(&sbdev->wd, slim_report);
mutex_lock(&ctrl->m_ctrl);
list_add_tail(&sbdev->dev_list, &ctrl->devs);
mutex_unlock(&ctrl->m_ctrl);
@@ -604,6 +625,31 @@
EXPORT_SYMBOL_GPL(slim_add_numbered_controller);
/*
+ * slim_report_absent: Controller calls this function when a device
+ * reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev)
+{
+ struct slim_controller *ctrl;
+ int i;
+ if (!sbdev)
+ return;
+ ctrl = sbdev->ctrl;
+ if (!ctrl)
+ return;
+ /* invalidate logical addresses */
+ mutex_lock(&ctrl->m_ctrl);
+ for (i = 0; i < ctrl->num_dev; i++) {
+ if (sbdev->laddr == ctrl->addrt[i].laddr)
+ ctrl->addrt[i].valid = false;
+ }
+ mutex_unlock(&ctrl->m_ctrl);
+ queue_work(ctrl->wq, &sbdev->wd);
+}
+EXPORT_SYMBOL(slim_report_absent);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 25b4b5e..4512d02 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2664,7 +2664,6 @@
struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
struct platform_device *pdev, struct msm_spi *dd)
{
- int i;
struct msm_spi_platform_data *pdata;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -2725,10 +2724,6 @@
pdata->use_bam = false;
}
}
-
- for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
- dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
-
return pdata;
}
@@ -2834,10 +2829,12 @@
i + ARRAY_SIZE(spi_rsrcs));
dd->cs_gpios[i].gpio_num = resource ?
resource->start : -1;
- dd->cs_gpios[i].valid = 0;
}
}
+ for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+ dd->cs_gpios[i].valid = 0;
+
dd->pdata = pdata;
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!resource) {
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 0a41ef8..44d81c8 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -166,9 +166,10 @@
spin_lock(&mdss_lock);
hw = mdss_irq_handlers[hw_ndx];
+ spin_unlock(&mdss_lock);
+
if (hw)
rc = hw->irq_handler(irq, hw->ptr);
- spin_unlock(&mdss_lock);
return rc;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_video.c b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
index 6fb8883..3f3e51c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_video.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_video.c
@@ -479,9 +479,9 @@
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 1);
wmb();
- rc = wait_for_completion_interruptible_timeout(&ctx->vsync_comp,
+ rc = wait_for_completion_timeout(&ctx->vsync_comp,
usecs_to_jiffies(VSYNC_TIMEOUT_US));
- WARN(rc <= 0, "timeout (%d) enabling timegen on ctl=%d\n",
+ WARN(rc == 0, "timeout (%d) enabling timegen on ctl=%d\n",
rc, ctl->num);
ctx->timegen_en = true;
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
index 0a37573..ff977a9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -345,12 +345,12 @@
if (ctx->comp_cnt == 0)
return rc;
- rc = wait_for_completion_interruptible_timeout(&ctx->wb_comp,
+ rc = wait_for_completion_timeout(&ctx->wb_comp,
KOFF_TIMEOUT);
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
NULL, NULL);
- if (rc <= 0) {
+ if (rc == 0) {
rc = -ENODEV;
WARN(1, "writeback kickoff timed out (%d) ctl=%d\n",
rc, ctl->num);
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 0c74137..72288c2 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -533,11 +533,11 @@
goto kickoff_fail;
}
- ret = wait_for_completion_interruptible_timeout(&comp, KOFF_TIMEOUT);
- if (ret <= 0) {
+ ret = wait_for_completion_timeout(&comp, KOFF_TIMEOUT);
+ if (ret == 0)
WARN(1, "wfd kick off time out=%d ctl=%d", ret, ctl->num);
+ else
ret = 0;
- }
if (wb && node) {
mutex_lock(&wb->lock);
diff --git a/include/linux/mfd/wcd9xxx/core-resource.h b/include/linux/mfd/wcd9xxx/core-resource.h
new file mode 100644
index 0000000..442496e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/core-resource.h
@@ -0,0 +1,137 @@
+/* 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 __MFD_CORE_RESOURCE_H__
+#define __MFD_CORE_RESOURCE_H__
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pm_qos.h>
+
+#define WCD9XXX_MAX_IRQ_REGS 4
+#define WCD9XXX_MAX_NUM_IRQS (WCD9XXX_MAX_IRQ_REGS * 8)
+
+struct intr_data {
+ int intr_num;
+ bool clear_first;
+};
+
+enum wcd9xxx_pm_state {
+ WCD9XXX_PM_SLEEPABLE,
+ WCD9XXX_PM_AWAKE,
+ WCD9XXX_PM_ASLEEP,
+};
+
+enum wcd9xxx_intf_status {
+ WCD9XXX_INTERFACE_TYPE_PROBING,
+ WCD9XXX_INTERFACE_TYPE_SLIMBUS,
+ WCD9XXX_INTERFACE_TYPE_I2C,
+};
+
+struct wcd9xxx_core_resource {
+ struct mutex irq_lock;
+ struct mutex nested_irq_lock;
+
+ enum wcd9xxx_pm_state pm_state;
+ struct mutex pm_lock;
+ /* pm_wq notifies change of pm_state */
+ wait_queue_head_t pm_wq;
+ struct pm_qos_request pm_qos_req;
+ int wlock_holders;
+
+
+ /* holds the table of interrupts per codec */
+ const struct intr_data *intr_table;
+ int intr_table_size;
+ unsigned int irq_base;
+ unsigned int irq;
+ u8 irq_masks_cur[WCD9XXX_MAX_IRQ_REGS];
+ u8 irq_masks_cache[WCD9XXX_MAX_IRQ_REGS];
+ bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
+ int num_irqs;
+ int num_irq_regs;
+
+ /* Callback functions to read/write codec registers */
+ int (*codec_reg_read) (struct wcd9xxx_core_resource *,
+ unsigned short);
+ int (*codec_reg_write) (struct wcd9xxx_core_resource *,
+ unsigned short, u8);
+ int (*codec_bulk_read) (struct wcd9xxx_core_resource *,
+ unsigned short, int, u8 *);
+
+ /* Pointer to parent container data structure */
+ void *parent;
+
+ struct device *dev;
+};
+
+extern int wcd9xxx_core_res_init(
+ struct wcd9xxx_core_resource*,
+ int, int,
+ int (*codec_read)(struct wcd9xxx_core_resource *, unsigned short),
+ int (*codec_write)(struct wcd9xxx_core_resource *, unsigned short, u8),
+ int (*codec_bulk_read) (struct wcd9xxx_core_resource *, unsigned short,
+ int, u8 *));
+
+extern void wcd9xxx_core_res_deinit(
+ struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_res_suspend(
+ struct wcd9xxx_core_resource *,
+ pm_message_t);
+
+extern int wcd9xxx_core_res_resume(
+ struct wcd9xxx_core_resource *);
+
+extern int wcd9xxx_core_irq_init(
+ struct wcd9xxx_core_resource*);
+
+extern int wcd9xxx_initialize_irq(
+ struct wcd9xxx_core_resource*,
+ unsigned int,
+ unsigned int);
+
+enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
+void wcd9xxx_set_intf_type(enum wcd9xxx_intf_status);
+
+bool wcd9xxx_lock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_unlock_sleep(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_lock(struct wcd9xxx_core_resource *);
+void wcd9xxx_nested_irq_unlock(struct wcd9xxx_core_resource *);
+enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(
+ struct wcd9xxx_core_resource *,
+ enum wcd9xxx_pm_state,
+ enum wcd9xxx_pm_state);
+
+int wcd9xxx_request_irq(struct wcd9xxx_core_resource *, int,
+ irq_handler_t, const char *, void *);
+
+void wcd9xxx_free_irq(struct wcd9xxx_core_resource *, int, void*);
+void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *, int);
+void wcd9xxx_disable_irq_sync(struct wcd9xxx_core_resource *, int);
+int wcd9xxx_reg_read(struct wcd9xxx_core_resource *,
+ unsigned short);
+int wcd9xxx_reg_write(struct wcd9xxx_core_resource *,
+ unsigned short, u8);
+int wcd9xxx_bulk_read(struct wcd9xxx_core_resource *,
+ unsigned short, int, u8 *);
+int wcd9xxx_bulk_write(struct wcd9xxx_core_resource*,
+ unsigned short, int, u8*);
+int wcd9xxx_irq_init(struct wcd9xxx_core_resource *);
+void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_resume(
+ struct wcd9xxx_core_resource *);
+int wcd9xxx_core_res_suspend(
+ struct wcd9xxx_core_resource *,
+ pm_message_t);
+#endif
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index d54bf42..c2ad2b4 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -14,12 +14,10 @@
#define __MFD_TABLA_CORE_H__
#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/pm_qos.h>
#include <linux/platform_device.h>
#include <linux/of_irq.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
-#define WCD9XXX_NUM_IRQ_REGS 4
#define WCD9XXX_SLIM_NUM_PORT_REG 3
#define TABLA_VERSION_1_0 0
@@ -90,6 +88,7 @@
WCD9XXX_IRQ_VBAT_MONITOR_ATTACK,
WCD9XXX_IRQ_VBAT_MONITOR_RELEASE,
WCD9XXX_NUM_IRQS,
+ WCD9XXX_IRQ_RESERVED_2 = WCD9XXX_NUM_IRQS,
};
enum {
@@ -99,17 +98,6 @@
TAPAN_NUM_IRQS = WCD9XXX_NUM_IRQS,
};
-
-#define MAX(X, Y) (((int)X) >= ((int)Y) ? (X) : (Y))
-#define WCD9XXX_MAX_NUM_IRQS (MAX(MAX(TABLA_NUM_IRQS, SITAR_NUM_IRQS), \
- TAIKO_NUM_IRQS))
-
-enum wcd9xxx_pm_state {
- WCD9XXX_PM_SLEEPABLE,
- WCD9XXX_PM_AWAKE,
- WCD9XXX_PM_ASLEEP,
-};
-
/*
* data structure for Slimbus and I2S channel.
* Some of fields are only used in smilbus mode
@@ -145,12 +133,6 @@
wait_queue_head_t dai_wait;
};
-enum wcd9xxx_intf_status {
- WCD9XXX_INTERFACE_TYPE_PROBING,
- WCD9XXX_INTERFACE_TYPE_SLIMBUS,
- WCD9XXX_INTERFACE_TYPE_I2C,
-};
-
#define WCD9XXX_CH(xport, xshift) \
{.port = xport, .shift = xshift}
@@ -178,8 +160,6 @@
struct slim_device *slim_slave;
struct mutex io_lock;
struct mutex xfer_lock;
- struct mutex irq_lock;
- struct mutex nested_irq_lock;
u8 version;
int reset_gpio;
@@ -188,6 +168,7 @@
int bytes, void *dest, bool interface_reg);
int (*write_dev)(struct wcd9xxx *wcd9xxx, unsigned short reg,
int bytes, void *src, bool interface_reg);
+ int (*dev_down)(struct wcd9xxx *wcd9xxx);
int (*post_reset)(struct wcd9xxx *wcd9xxx);
void *ssr_priv;
@@ -196,21 +177,11 @@
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
- enum wcd9xxx_pm_state pm_state;
- struct mutex pm_lock;
- /* pm_wq notifies change of pm_state */
- wait_queue_head_t pm_wq;
- struct pm_qos_request pm_qos_req;
- int wlock_holders;
+ struct wcd9xxx_core_resource core_res;
u16 id_minor;
u16 id_major;
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[WCD9XXX_NUM_IRQ_REGS];
- u8 irq_masks_cache[WCD9XXX_NUM_IRQ_REGS];
- bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
/* Slimbus or I2S port */
u32 num_rx_port;
u32 num_tx_port;
@@ -221,36 +192,11 @@
const struct wcd9xxx_codec_type *codec_type;
};
-int wcd9xxx_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
-int wcd9xxx_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
- u8 val);
int wcd9xxx_interface_reg_read(struct wcd9xxx *wcd9xxx, unsigned short reg);
int wcd9xxx_interface_reg_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
u8 val);
-int wcd9xxx_bulk_read(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int count, u8 *buf);
-int wcd9xxx_bulk_write(struct wcd9xxx *wcd9xxx, unsigned short reg,
- int count, u8 *buf);
-int wcd9xxx_irq_init(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_irq_exit(struct wcd9xxx *wcd9xxx);
int wcd9xxx_get_logical_addresses(u8 *pgd_la, u8 *inf_la);
-enum wcd9xxx_intf_status wcd9xxx_get_intf_type(void);
-bool wcd9xxx_lock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_unlock_sleep(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_lock(struct wcd9xxx *wcd9xxx);
-void wcd9xxx_nested_irq_unlock(struct wcd9xxx *wcd9xxx);
-enum wcd9xxx_pm_state wcd9xxx_pm_cmpxchg(struct wcd9xxx *wcd9xxx,
- enum wcd9xxx_pm_state o,
- enum wcd9xxx_pm_state n);
-
-int wcd9xxx_request_irq(struct wcd9xxx *wcd9xxx, int irq,
- irq_handler_t handler, const char *name, void *data);
-
-void wcd9xxx_free_irq(struct wcd9xxx *wcd9xxx, int irq, void *data);
-void wcd9xxx_enable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq(struct wcd9xxx *wcd9xxx, int irq);
-void wcd9xxx_disable_irq_sync(struct wcd9xxx *wcd9xxx, int irq);
#if defined(CONFIG_WCD9310_CODEC) || \
defined(CONFIG_WCD9304_CODEC) || \
defined(CONFIG_WCD9320_CODEC) || \
@@ -271,9 +217,9 @@
u8 reg_val;
if (core) {
- reg_val = wcd9xxx_reg_read(core, reg);
+ reg_val = wcd9xxx_reg_read(&core->core_res, reg);
reg_val = (reg_val & ~mask) | (val & mask);
- wcd9xxx_reg_write(core, reg, reg_val);
+ wcd9xxx_reg_write(&core->core_res, reg, reg_val);
}
}
#endif
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 132135e..cba4394 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -581,6 +581,11 @@
* @shutdown: Standard shutdown callback used during powerdown/halt.
* @suspend: Standard suspend callback used during system suspend
* @resume: Standard resume callback used during system resume
+ * @device_up: This callback is called when the device reports present and
+ * gets a logical address assigned to it
+ * @device_down: This callback is called when device reports absent, or the
+ * bus goes down. Device will report present when bus is up and
+ * device_up callback will be called again when that happens
* @driver: Slimbus device drivers should initialize name and owner field of
* this structure
* @id_table: List of slimbus devices supported by this driver
@@ -593,6 +598,8 @@
pm_message_t pmesg);
int (*resume)(struct slim_device *sldev);
int (*device_up)(struct slim_device *sldev);
+ int (*device_down)
+ (struct slim_device *sldev);
struct device_driver driver;
const struct slim_device_id *id_table;
@@ -1022,6 +1029,13 @@
u8 e_len, u8 *laddr, bool valid);
/*
+ * slim_report_absent: Controller calls this function when a device
+ * reports absent, OR when the device cannot be communicated with
+ * @sbdev: Device that cannot be reached, or that sent report absent
+ */
+void slim_report_absent(struct slim_device *sbdev);
+
+/*
* slim_msg_response: Deliver Message response received from a device to the
* framework.
* @ctrl: Controller handle
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 101325e..f6b93ff 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1874,6 +1874,16 @@
V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1,
};
+#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \
+ (V4L2_CID_MPEG_MSM_VIDC_BASE+32)
+enum v4l2_mpeg_vidc_video_vp8_profile_level {
+ V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2,
+ V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3,
+};
+
/* Camera class control IDs */
#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/sound/core.h b/include/sound/core.h
index bc05668..5b9969e 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -134,6 +134,9 @@
wait_queue_head_t shutdown_sleep;
struct device *dev; /* device assigned to this card */
struct device *card_dev; /* cardX object for sysfs */
+ int offline; /* if this sound card is offline */
+ unsigned long offline_change;
+ wait_queue_head_t offline_poll_wait;
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
@@ -295,6 +298,8 @@
int snd_component_add(struct snd_card *card, const char *component);
int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
+void snd_card_change_online_state(struct snd_card *card, int online);
+bool snd_card_is_online_state(struct snd_card *card);
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
diff --git a/include/sound/soc.h b/include/sound/soc.h
index e134dfd..b1e536d 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -426,6 +426,9 @@
struct snd_ac97_bus_ops *ops, int num);
void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card,
+ int online);
+
/*
*Controls
*/
diff --git a/init/main.c b/init/main.c
index 737ab05..b2fc496 100644
--- a/init/main.c
+++ b/init/main.c
@@ -477,11 +477,6 @@
smp_setup_processor_id();
debug_objects_early_init();
- /*
- * Set up the the initial canary ASAP:
- */
- boot_init_stack_canary();
-
cgroup_init_early();
local_irq_disable();
@@ -496,6 +491,10 @@
page_address_init();
printk(KERN_NOTICE "%s", linux_banner);
setup_arch(&command_line);
+ /*
+ * Set up the the initial canary ASAP:
+ */
+ boot_init_stack_canary();
mm_init_owner(&init_mm, &init_task);
mm_init_cpumask(&init_mm);
setup_command_line(command_line);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d9c4b64..5256d44 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5202,9 +5202,6 @@
*/
rq->stop = NULL;
- /* Ensure any throttled groups are reachable by pick_next_task */
- unthrottle_offline_cfs_rqs(rq);
-
for ( ; ; ) {
/*
* There's this thread running, bail when that's the only
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5d6ab86..2e98983 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2060,7 +2060,7 @@
hrtimer_cancel(&cfs_b->slack_timer);
}
-void unthrottle_offline_cfs_rqs(struct rq *rq)
+static void unthrottle_offline_cfs_rqs(struct rq *rq)
{
struct cfs_rq *cfs_rq;
@@ -2114,7 +2114,7 @@
return NULL;
}
static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {}
-void unthrottle_offline_cfs_rqs(struct rq *rq) {}
+static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {}
#endif /* CONFIG_CFS_BANDWIDTH */
@@ -5186,6 +5186,9 @@
static void rq_offline_fair(struct rq *rq)
{
update_sysctl();
+
+ /* Ensure any throttled groups are reachable by pick_next_task */
+ unthrottle_offline_cfs_rqs(rq);
}
#endif /* CONFIG_SMP */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 8f32475..be427c5 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -685,6 +685,7 @@
* runtime - in which case borrowing doesn't make sense.
*/
rt_rq->rt_runtime = RUNTIME_INF;
+ rt_rq->rt_throttled = 0;
raw_spin_unlock(&rt_rq->rt_runtime_lock);
raw_spin_unlock(&rt_b->rt_runtime_lock);
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 5370bcb..55f6d9c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1155,7 +1155,6 @@
extern void init_cfs_rq(struct cfs_rq *cfs_rq);
extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
-extern void unthrottle_offline_cfs_rqs(struct rq *rq);
extern void account_cfs_bandwidth_used(int enabled, int was_enabled);
diff --git a/sound/core/init.c b/sound/core/init.c
index f300bd3..6559a40 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -55,6 +55,8 @@
module_param_array(slots, charp, NULL, 0444);
MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
+#define SND_CARD_STATE_MAX_LEN 16
+
/* return non-zero if the given index is reserved for the given
* module via slots option
*/
@@ -104,10 +106,40 @@
snd_iprintf(buffer, "%s\n", entry->card->id);
}
+static int snd_card_state_read(struct snd_info_entry *entry,
+ void *file_private_data, struct file *file,
+ char __user *buf, size_t count, loff_t pos)
+{
+ int len;
+ char buffer[SND_CARD_STATE_MAX_LEN];
+
+ /* make sure offline is updated prior to wake up */
+ rmb();
+ len = snprintf(buffer, sizeof(buffer), "%s\n",
+ entry->card->offline ? "OFFLINE" : "ONLINE");
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static unsigned int snd_card_state_poll(struct snd_info_entry *entry,
+ void *private_data, struct file *file,
+ poll_table *wait)
+{
+ poll_wait(file, &entry->card->offline_poll_wait, wait);
+ if (xchg(&entry->card->offline_change, 0))
+ return POLLIN | POLLPRI | POLLRDNORM;
+ else
+ return 0;
+}
+
+static struct snd_info_entry_ops snd_card_state_proc_ops = {
+ .read = snd_card_state_read,
+ .poll = snd_card_state_poll,
+};
+
static inline int init_info_for_card(struct snd_card *card)
{
int err;
- struct snd_info_entry *entry;
+ struct snd_info_entry *entry, *entry_state;
if ((err = snd_info_card_register(card)) < 0) {
snd_printd("unable to create card info\n");
@@ -123,6 +155,24 @@
entry = NULL;
}
card->proc_id = entry;
+
+ entry_state = snd_info_create_card_entry(card, "state",
+ card->proc_root);
+ if (entry_state == NULL) {
+ snd_printd("unable to create card entry state\n");
+ card->proc_id = NULL;
+ return err;
+ }
+ entry_state->size = SND_CARD_STATE_MAX_LEN;
+ entry_state->content = SNDRV_INFO_CONTENT_DATA;
+ entry_state->c.ops = &snd_card_state_proc_ops;
+ err = snd_info_register(entry_state);
+ if (err < 0) {
+ snd_printd("unable to register card entry state\n");
+ card->proc_id = NULL;
+ return err;
+ }
+
return 0;
}
#else /* !CONFIG_PROC_FS */
@@ -216,6 +266,7 @@
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
+ init_waitqueue_head(&card->offline_poll_wait);
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
@@ -909,6 +960,35 @@
EXPORT_SYMBOL(snd_card_file_remove);
+/**
+ * snd_card_change_online_state - mark card's online/offline state
+ * @card: Card to mark
+ * @online: whether online of offline
+ *
+ * Mutes the DAI DAC.
+ */
+void snd_card_change_online_state(struct snd_card *card, int online)
+{
+ snd_printd("snd card %s state change %d -> %d\n",
+ card->shortname, !card->offline, online);
+ card->offline = !online;
+ /* make sure offline is updated prior to wake up */
+ wmb();
+ xchg(&card->offline_change, 1);
+ wake_up_interruptible(&card->offline_poll_wait);
+}
+EXPORT_SYMBOL(snd_card_change_online_state);
+
+/**
+ * snd_card_is_online_state - return true if card is online state
+ * @card: Card to query
+ */
+bool snd_card_is_online_state(struct snd_card *card)
+{
+ return !card->offline;
+}
+EXPORT_SYMBOL(snd_card_is_online_state);
+
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index c0469e3..56cd5e6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -165,7 +165,7 @@
obj-$(CONFIG_SND_SOC_CS8427) += snd-soc-cs8427.o
obj-$(CONFIG_SND_SOC_WCD9320) += snd-soc-wcd9320.o
obj-$(CONFIG_SND_SOC_WCD9306) += snd-soc-wcd9306.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
-obj-$(CONFIG_SND_SOC_MSM8X10_WCD) += snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o
+obj-$(CONFIG_SND_SOC_MSM8X10_WCD) += snd-soc-msm8x10-wcd.o wcd9xxx-resmgr.o wcd9xxx-mbhc.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 66b0094..bd4f926 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -27,7 +27,6 @@
#include <linux/i2c.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
-#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/pdata.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -62,6 +61,7 @@
#define MAX_MSM8X10_WCD_DEVICE 4
#define CODEC_DT_MAX_PROP_SIZE 40
#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
+#define HELICON_MCLK_CLK_9P6MHZ 9600000
enum {
MSM8X10_WCD_I2C_TOP_LEVEL = 0,
@@ -160,15 +160,14 @@
u32 adc_count;
u32 rx_bias_count;
s32 dmic_1_2_clk_cnt;
- enum msm8x10_wcd_bandgap_type bandgap_type;
- bool mclk_enabled;
- bool clock_active;
- bool config_mode_active;
- bool mbhc_polling_active;
struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
- struct mutex codec_resource_lock;
/* resmgr module */
struct wcd9xxx_resmgr resmgr;
+ /* mbhc module */
+ struct wcd9xxx_mbhc mbhc;
+
+ struct delayed_work hs_detect_work;
+ struct wcd9xxx_mbhc_config *mbhc_cfg;
};
static unsigned short rx_digital_gain_reg[] = {
@@ -344,12 +343,21 @@
return msm8x10_wcd_i2c_write_device(reg, src, bytes);
}
-static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
- u16 reg, unsigned int *val)
+static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
+{
+ if (reg >= 0x3C0 && reg <= 0x3DF)
+ reg = reg & 0x00FF;
+ return reg;
+}
+
+static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
+ unsigned short reg)
{
int ret = -EINVAL;
u8 temp;
+ reg = msm8x10_wcd_mask_reg(reg);
+
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
@@ -357,16 +365,62 @@
else if (MSM8X10_WCD_IS_DINO_REG(reg))
ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
mutex_unlock(&msm8x10_wcd->io_lock);
- *val = temp;
+
+ if (ret < 0) {
+ dev_err(msm8x10_wcd->dev,
+ "%s: codec read failed for reg 0x%x\n",
+ __func__, reg);
+ return ret;
+ } else {
+ dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
+ temp, reg);
+ }
+
+ return temp;
+}
+
+int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
+ unsigned short reg)
+{
+ struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+ return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_read);
+
+static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
+ unsigned short reg, int count, u8 *buf)
+{
+ int ret = -EINVAL;
+ mutex_lock(&msm8x10_wcd->io_lock);
+ if (MSM8X10_WCD_IS_HELICON_REG(reg))
+ ret = msm8x10_wcd_i2c_read(reg, count, buf);
+ else if (MSM8X10_WCD_IS_DINO_REG(reg))
+ ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
+ count, buf);
+ mutex_unlock(&msm8x10_wcd->io_lock);
+
+ if (ret < 0)
+ dev_err(msm8x10_wcd->dev,
+ "%s: codec bulk read failed\n", __func__);
return ret;
}
+int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
+ unsigned short reg, int count, u8 *buf)
+{
+ struct msm8x10_wcd *msm8x10_wcd =
+ (struct msm8x10_wcd *) core_res->parent;
+ return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
+}
+EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
-static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
- u8 val)
+static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
+ unsigned short reg, u8 val)
{
int ret = -EINVAL;
+ reg = msm8x10_wcd_mask_reg(reg);
+
/* check if use I2C interface for Helicon or AHB for Dino */
mutex_lock(&msm8x10_wcd->io_lock);
if (MSM8X10_WCD_IS_HELICON_REG(reg))
@@ -375,9 +429,26 @@
ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
mutex_unlock(&msm8x10_wcd->io_lock);
+ if (ret < 0)
+ dev_err(msm8x10_wcd->dev,
+ "%s: codec write to reg 0x%x failed\n",
+ __func__, reg);
+ else
+ dev_dbg(msm8x10_wcd->dev,
+ "%s: Codec reg 0x%x written with value 0x%x\n",
+ __func__, reg, val);
+
return ret;
}
+int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
+ unsigned short reg, u8 val)
+{
+ struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
+ return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
+}
+EXPORT_SYMBOL(msm8x10_wcd_reg_write);
+
static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
{
bool rtn = false;
@@ -451,7 +522,7 @@
reg, ret);
}
- return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
+ return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
}
static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
@@ -477,7 +548,7 @@
reg, ret);
}
- ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
+ val = __msm8x10_wcd_reg_read(codec->control_data, reg);
return val;
}
@@ -1531,7 +1602,6 @@
snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
- snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20100);
@@ -1544,7 +1614,6 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
- snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
break;
}
return 0;
@@ -1796,12 +1865,6 @@
/* Let MBHC module know PA turned off */
wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
- /*
- * schedule work is required because at the time HPH PA DAPM
- * event callback is called by DAPM framework, CODEC dapm mutex
- * would have been locked while snd_soc_jack_report also
- * attempts to acquire same lock.
- */
dev_dbg(codec->dev,
"%s: sleep 10 ms after %s PA disable.\n", __func__,
w->name);
@@ -1981,88 +2044,6 @@
substream->name, substream->stream);
}
-static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
- int enable)
-{
- if (enable) {
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
- 0x01, 0x01);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
- 0x03, 0x03);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
- 0x0f, 0x0d);
- } else {
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
- 0x0f, 0x00);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
- 0x03, 0x00);
- }
- return 0;
-}
-
-static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
- *codec)
-{
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
- 0x80);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
- 0x04);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
- 0x01);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
- 0x00);
-}
-
-static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
- enum msm8x10_wcd_bandgap_type choice)
-{
- struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
-
- /* TODO lock resources accessed by audio streams and threaded
- * interrupt handlers
- */
-
- dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
- __func__, choice,
- msm8x10_wcd->bandgap_type);
-
- if (msm8x10_wcd->bandgap_type == choice)
- return;
-
- if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
- (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
- msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
- } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
- /* bandgap mode becomes fast,
- * mclk should be off or clk buff source souldn't be VBG
- * Let's turn off mclk always */
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
- 0x2, 0x2);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
- 0x80, 0x80);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
- 0x4, 0x4);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
- 0x01, 0x01);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
- 0x80, 0x00);
- } else if ((msm8x10_wcd->bandgap_type ==
- MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
- (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
- snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
- usleep_range(100, 100);
- msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
- } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
- snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
- } else {
- dev_err(codec->dev,
- "%s: Error, Invalid bandgap settings\n", __func__);
- }
- msm8x10_wcd->bandgap_type = choice;
-}
-
int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
int mclk_enable, bool dapm)
{
@@ -2070,28 +2051,21 @@
dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
__func__, mclk_enable, dapm);
- if (dapm)
- MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
+
+ WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
+
if (mclk_enable) {
- msm8x10_wcd->mclk_enabled = true;
- msm8x10_wcd_codec_enable_bandgap(codec,
- MSM8X10_WCD_BANDGAP_AUDIO_MODE);
- msm8x10_wcd_codec_enable_clock_block(codec, 1);
+ wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
+ wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
+ WCD9XXX_CLK_MCLK);
} else {
- if (!msm8x10_wcd->mclk_enabled) {
- if (dapm)
- MSM8X10_WCD_RELEASE_LOCK(
- msm8x10_wcd->codec_resource_lock);
- dev_err(codec->dev, "Error, MCLK already diabled\n");
- return -EINVAL;
- }
- msm8x10_wcd->mclk_enabled = false;
- msm8x10_wcd_codec_enable_clock_block(codec, 0);
- msm8x10_wcd_codec_enable_bandgap(codec,
- MSM8X10_WCD_BANDGAP_OFF);
+ wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
+ WCD9XXX_CLK_MCLK);
+ wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
+ WCD9XXX_BANDGAP_AUDIO_MODE);
}
- if (dapm)
- MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
+ WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
return 0;
}
@@ -2513,7 +2487,7 @@
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
/* Enable pulldown to reduce leakage */
- MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
@@ -2527,6 +2501,10 @@
/* Always set TXD_CLK_EN bit to reduce the leakage */
MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
+
+ /* Always disable clock gating for MCLK to mbhc clock gate */
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
+ MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
};
static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
@@ -2577,9 +2555,118 @@
msm8x10_wcd_codec_reg_init_val[i].val);
}
-int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
- struct msm8x10_wcd_mbhc_config *mbhc_cfg)
+static void msm8x10_wcd_enable_mux_bias_block(
+ struct snd_soc_codec *codec)
{
+ snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
+ 0x80, 0x00);
+}
+
+static void msm8x10_wcd_put_cfilt_fast_mode(
+ struct snd_soc_codec *codec,
+ struct wcd9xxx_mbhc *mbhc)
+{
+ snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
+ 0x30, 0x30);
+}
+
+static void msm8x10_wcd_codec_specific_cal_setup(
+ struct snd_soc_codec *codec,
+ struct wcd9xxx_mbhc *mbhc)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
+ 0xE0, 0xE0);
+}
+
+static int msm8x10_wcd_get_jack_detect_irq(
+ struct snd_soc_codec *codec)
+{
+ return MSM8X10_WCD_IRQ_MBHC_HS_DET;
+}
+
+static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
+ struct wcd9xxx_mbhc *mbhc, bool fast)
+{
+ struct snd_soc_codec *codec = mbhc->codec;
+ struct wcd9xxx_cfilt_mode cfilt_mode;
+
+ if (fast)
+ cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
+ else
+ cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
+
+ cfilt_mode.cur_mode_val =
+ snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+ cfilt_mode.reg_mask = 0x30;
+ return cfilt_mode;
+}
+
+static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
+ struct wcd9xxx_mbhc *mbhc)
+{
+ snd_soc_update_bits(codec,
+ mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
+}
+
+static void msm8x10_wcd_free_irq(struct wcd9xxx_mbhc *mbhc)
+{
+ struct msm8x10_wcd *msm8x10_wcd = mbhc->codec->control_data;
+ struct wcd9xxx_core_resource *core_res =
+ &msm8x10_wcd->wcd9xxx_res;
+ wcd9xxx_free_irq(core_res, MSM8X10_WCD_IRQ_MBHC_HS_DET, mbhc);
+}
+
+enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
+{
+ return WCD9XXX_CDC_TYPE_HELICON;
+}
+
+static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
+}
+
+static const struct wcd9xxx_mbhc_cb mbhc_cb = {
+ .enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
+ .cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
+ .codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
+ .jack_detect_irq = msm8x10_wcd_get_jack_detect_irq,
+ .switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
+ .select_cfilt = msm8x10_wcd_select_cfilt,
+ .free_irq = msm8x10_wcd_free_irq,
+ .get_cdc_type = msm8x10_wcd_get_cdc_type,
+ .enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
+};
+
+static void delayed_hs_detect_fn(struct work_struct *work)
+{
+ struct delayed_work *delayed_work;
+ struct msm8x10_wcd_priv *wcd_priv;
+
+ delayed_work = to_delayed_work(work);
+ wcd_priv = container_of(delayed_work, struct msm8x10_wcd_priv,
+ hs_detect_work);
+
+ if (!wcd_priv) {
+ pr_err("%s: Invalid private data for codec\n", __func__);
+ return;
+ }
+
+ wcd9xxx_mbhc_start(&wcd_priv->mbhc, wcd_priv->mbhc_cfg);
+}
+
+
+int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
+ struct wcd9xxx_mbhc_config *mbhc_cfg)
+{
+ struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
+
+ wcd->mbhc_cfg = mbhc_cfg;
+ schedule_delayed_work(&wcd->hs_detect_work,
+ msecs_to_jiffies(5000));
return 0;
}
EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
@@ -2659,10 +2746,14 @@
{
struct msm8x10_wcd_priv *msm8x10_wcd_priv;
struct msm8x10_wcd *msm8x10_wcd;
- int i;
+ struct wcd9xxx_core_resource *core_res;
+ int i, ret = 0;
+
dev_dbg(codec->dev, "%s()\n", __func__);
- msm8x10_wcd_priv = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+ msm8x10_wcd_priv = devm_kzalloc(codec->dev,
+ sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
+
if (!msm8x10_wcd_priv) {
dev_err(codec->dev, "Failed to allocate private data\n");
return -ENOMEM;
@@ -2683,6 +2774,21 @@
msm8x10_wcd = codec->control_data;
msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
MSM8X10_DINO_CODEC_REG_SIZE);
+ INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
+ delayed_hs_detect_fn);
+
+ /* codec resmgr module init */
+ msm8x10_wcd = codec->control_data;
+ core_res = &msm8x10_wcd->wcd9xxx_res;
+ ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
+ codec, core_res, NULL, NULL,
+ WCD9XXX_CDC_TYPE_HELICON);
+ if (ret) {
+ dev_err(codec->dev,
+ "%s: wcd9xxx init failed %d\n",
+ __func__, ret);
+ goto exit_probe;
+ }
msm8x10_wcd_bringup(codec);
msm8x10_wcd_codec_init_reg(codec);
@@ -2697,12 +2803,15 @@
codec->control_data,
on_demand_supply_name[ON_DEMAND_MICBIAS]);
atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
- msm8x10_wcd_priv->mclk_enabled = false;
- msm8x10_wcd_priv->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
- msm8x10_wcd_priv->clock_active = false;
- msm8x10_wcd_priv->config_mode_active = false;
- msm8x10_wcd_priv->mbhc_polling_active = false;
- mutex_init(&msm8x10_wcd_priv->codec_resource_lock);
+
+ ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
+ &msm8x10_wcd_priv->resmgr,
+ codec, NULL, &mbhc_cb,
+ HELICON_MCLK_CLK_9P6MHZ, false);
+ if (ret) {
+ pr_err("%s: Failed to initialize mbhc\n", __func__);
+ goto exit_probe;
+ }
registered_codec = codec;
adsp_state_notifier =
@@ -2715,13 +2824,16 @@
return -ENOMEM;
}
return 0;
+
+exit_probe:
+ return ret;
+
}
static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
{
struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
-
pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
@@ -2920,13 +3032,38 @@
{
mutex_init(&msm8x10->io_lock);
mutex_init(&msm8x10->xfer_lock);
- mutex_init(&msm8x10->pm_lock);
- msm8x10->wlock_holders = 0;
msm8x10_wcd_pads_config();
msm8x10_wcd_clk_init();
return 0;
}
+static struct intr_data interrupt_table[] = {
+ {MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
+ {MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
+ {MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
+ {MSM8X10_WCD_IRQ_MBHC_PRESS, true},
+ {MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
+ {MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
+ {MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
+ {MSM8X10_WCD_IRQ_RESERVED_0, false},
+ {MSM8X10_WCD_IRQ_PA_STARTUP, false},
+ {MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
+ {MSM8X10_WCD_IRQ_RESERVED_1, false},
+ {MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
+ {MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
+ {MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
+ {MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
+ {MSM8X10_WCD_IRQ_RESERVED_2, false},
+ {MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
+ {MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
+ {MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
+ {MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
+ {MSM8X10_WCD_IRQ_RESERVED_3, false},
+ {MSM8X10_WCD_IRQ_RESERVED_4, false},
+ {MSM8X10_WCD_IRQ_RESERVED_5, false},
+ {MSM8X10_WCD_IRQ_RESERVED_6, false},
+};
+
static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -2936,6 +3073,7 @@
static int device_id;
struct device *dev;
enum apr_subsys_state q6_state;
+ struct wcd9xxx_core_resource *core_res;
dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
__func__, __LINE__, client->addr, device_id);
@@ -2995,8 +3133,8 @@
}
msm8x10->dev = &client->dev;
- msm8x10->read_dev = msm8x10_wcd_reg_read;
- msm8x10->write_dev = msm8x10_wcd_reg_write;
+ msm8x10->read_dev = __msm8x10_wcd_reg_read;
+ msm8x10->write_dev = __msm8x10_wcd_reg_write;
ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
if (ret) {
dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
@@ -3020,15 +3158,37 @@
goto err_supplies;
}
dev_set_drvdata(&client->dev, msm8x10);
+ core_res = &msm8x10->wcd9xxx_res;
+ core_res->parent = msm8x10;
+ core_res->dev = msm8x10->dev;
+ core_res->intr_table = interrupt_table;
+ core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
+
+ wcd9xxx_core_res_init(core_res,
+ MSM8X10_WCD_NUM_IRQS,
+ MSM8X10_WCD_NUM_IRQ_REGS,
+ msm8x10_wcd_reg_read,
+ msm8x10_wcd_reg_write,
+ msm8x10_wcd_bulk_read);
+ if (wcd9xxx_core_irq_init(core_res)) {
+ dev_err(msm8x10->dev,
+ "%s: irq initialization failed\n", __func__);
+ } else {
+ dev_info(msm8x10->dev,
+ "%s: irq initialization passed\n", __func__);
+ }
+
ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
msm8x10_wcd_i2s_dai,
ARRAY_SIZE(msm8x10_wcd_i2s_dai));
- if (ret)
+ if (ret) {
dev_err(&client->dev,
"%s:snd_soc_register_codec failed with error %d\n",
__func__, ret);
- else
+ } else {
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
goto rtn;
+ }
err_supplies:
msm8x10_wcd_disable_supplies(msm8x10, pdata);
@@ -3040,7 +3200,6 @@
static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
{
- mutex_destroy(&msm8x10->pm_lock);
mutex_destroy(&msm8x10->io_lock);
mutex_destroy(&msm8x10->xfer_lock);
kfree(msm8x10);
@@ -3084,6 +3243,7 @@
int ret;
pr_debug("%s:\n", __func__);
+ wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
if (ret != 0)
pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
diff --git a/sound/soc/codecs/msm8x10-wcd.h b/sound/soc/codecs/msm8x10-wcd.h
index 44cdab9..5f67cba 100644
--- a/sound/soc/codecs/msm8x10-wcd.h
+++ b/sound/soc/codecs/msm8x10-wcd.h
@@ -168,31 +168,6 @@
MSM8X10_WCD_MICBIAS1 = 0,
};
-struct msm8x10_wcd_mbhc_config {
- struct snd_soc_jack *headset_jack;
- struct snd_soc_jack *button_jack;
- bool read_fw_bin;
- /*
- * void* calibration contains:
- * struct msm8x10_wcd_mbhc_general_cfg generic;
- * struct msm8x10_wcd_mbhc_plug_detect_cfg plug_det;
- * struct msm8x10_wcd_mbhc_plug_type_cfg plug_type;
- * struct msm8x10_wcd_mbhc_btn_detect_cfg btn_det;
- * struct msm8x10_wcd_mbhc_imped_detect_cfg imped_det;
- * Note: various size depends on btn_det->num_btn
- */
- void *calibration;
- enum msm8x10_wcd_micbias_num micbias;
- int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
- unsigned int mclk_rate;
- unsigned int gpio;
- unsigned int gpio_irq;
- int gpio_level_insert;
- bool detect_extn_cable;
- /* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
- bool (*swap_gnd_mic) (struct snd_soc_codec *);
-};
-
enum msm8x10_wcd_pm_state {
MSM8X10_WCD_PM_SLEEPABLE,
MSM8X10_WCD_PM_AWAKE,
@@ -203,40 +178,29 @@
struct device *dev;
struct mutex io_lock;
struct mutex xfer_lock;
- struct mutex irq_lock;
u8 version;
int reset_gpio;
int (*read_dev)(struct msm8x10_wcd *msm8x10,
- unsigned short reg, unsigned int *val);
+ unsigned short reg);
int (*write_dev)(struct msm8x10_wcd *msm8x10,
unsigned short reg, u8 val);
u32 num_of_supplies;
struct regulator_bulk_data *supplies;
- enum msm8x10_wcd_pm_state pm_state;
- struct mutex pm_lock;
- /* pm_wq notifies change of pm_state */
- wait_queue_head_t pm_wq;
- struct pm_qos_request pm_qos_req;
- int wlock_holders;
-
u8 idbyte[4];
- unsigned int irq_base;
- unsigned int irq;
- u8 irq_masks_cur[MSM8X10_WCD_NUM_IRQ_REGS];
- u8 irq_masks_cache[MSM8X10_WCD_NUM_IRQ_REGS];
- bool irq_level_high[MSM8X10_WCD_NUM_IRQS];
int num_irqs;
u32 mclk_rate;
char __iomem *pdino_base;
+
+ struct wcd9xxx_core_resource wcd9xxx_res;
};
extern int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
bool dapm);
extern int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
- struct msm8x10_wcd_mbhc_config *mbhc_cfg);
+ struct wcd9xxx_mbhc_config *mbhc_cfg);
#endif
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 58ea22d..a68722c 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -3961,8 +3961,10 @@
{
short bias_value;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
sitar_turn_onoff_rel_detection(codec, false);
@@ -4103,11 +4105,12 @@
{
int r = 0;
struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
/* if scheduled mbhc_btn_dwork is canceled from here,
* we have to unlock from here instead btn_work */
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
r = 1;
}
return r;
@@ -4171,12 +4174,14 @@
short bias_value;
int dce_mv, sta_mv;
struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
pr_debug("%s:\n", __func__);
delayed_work = to_delayed_work(work);
sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
core = dev_get_drvdata(sitar->codec->dev->parent);
+ core_res = &core->core_res;
if (sitar) {
if (sitar->mbhc_cfg.button_jack) {
@@ -4198,7 +4203,7 @@
}
pr_debug("%s: leave\n", __func__);
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
@@ -4212,11 +4217,13 @@
u32 dce_wait, sta_wait;
u8 *n_cic;
void *calibration;
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
sitar = snd_soc_codec_get_drvdata(codec);
calibration = sitar->mbhc_cfg.calibration;
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
sitar_turn_onoff_rel_detection(codec, false);
/* First compute the DCE / STA wait times
@@ -4707,22 +4714,28 @@
/* should be called under interrupt context that hold suspend */
static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
{
+ struct wcd9xxx *core = sitar->codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
+
pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
sitar->hs_detect_work_stop = false;
- wcd9xxx_lock_sleep(sitar->codec->control_data);
+ wcd9xxx_lock_sleep(core_res);
schedule_work(&sitar->hs_correct_plug_work);
}
/* called under codec_resource_lock acquisition */
static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
{
+ struct wcd9xxx *core = sitar->codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
+
pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
sitar->hs_detect_work_stop = true;
wmb();
SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
- wcd9xxx_unlock_sleep(sitar->codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
}
@@ -4737,9 +4750,13 @@
short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
unsigned long timeout;
+ struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
codec = sitar->codec;
+ core = sitar->codec->control_data;
+ core_res = &core->core_res;
pr_debug("%s: enter\n", __func__);
sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -4815,7 +4832,7 @@
sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
pr_debug("%s: leave\n", __func__);
/* unlock sleep */
- wcd9xxx_unlock_sleep(sitar->codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
/* called under codec_resource_lock acquisition */
@@ -4966,8 +4983,10 @@
{
int r = IRQ_HANDLED;
struct snd_soc_codec *codec = data;
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
- if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+ if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
pr_warn("%s(): Failed to hold suspend\n", __func__);
r = IRQ_NONE;
} else {
@@ -5181,6 +5200,7 @@
short btnmeas[d->n_btn_meas + 1];
struct snd_soc_codec *codec = priv->codec;
struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
int n_btn_meas = d->n_btn_meas;
u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
@@ -5271,12 +5291,12 @@
}
mask = sitar_get_button_mask(btn);
priv->buttons_pressed |= mask;
- wcd9xxx_lock_sleep(core);
+ wcd9xxx_lock_sleep(core_res);
if (schedule_delayed_work(&priv->mbhc_btn_dwork,
msecs_to_jiffies(400)) == 0) {
WARN(1, "Button pressed twice without release"
"event\n");
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
} else {
pr_debug("%s: bogus button press, too short press?\n",
@@ -5386,11 +5406,16 @@
{
struct sitar_priv *sitar = data;
struct snd_soc_codec *codec;
+ struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
pr_info("%s: received HPHL OCP irq\n", __func__);
if (sitar) {
codec = sitar->codec;
+ core = codec->control_data;
+ core_res = &core->core_res;
+
if ((sitar->hphlocp_cnt < SITAR_OCP_ATTEMPT) &&
(!sitar->hphrocp_cnt)) {
pr_info("%s: retry\n", __func__);
@@ -5400,7 +5425,7 @@
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
0x10);
} else {
- wcd9xxx_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
sitar->hph_status |= SND_JACK_OC_HPHL;
if (sitar->mbhc_cfg.headset_jack)
@@ -5420,11 +5445,16 @@
{
struct sitar_priv *sitar = data;
struct snd_soc_codec *codec;
+ struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
pr_info("%s: received HPHR OCP irq\n", __func__);
if (sitar) {
codec = sitar->codec;
+ core = codec->control_data;
+ core_res = &core->core_res;
+
if ((sitar->hphrocp_cnt < SITAR_OCP_ATTEMPT) &&
(!sitar->hphlocp_cnt)) {
pr_info("%s: retry\n", __func__);
@@ -5434,7 +5464,7 @@
snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
0x10);
} else {
- wcd9xxx_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
sitar->hph_status |= SND_JACK_OC_HPHR;
if (sitar->mbhc_cfg.headset_jack)
@@ -5454,10 +5484,12 @@
{
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
pr_debug("%s: enter\n", __func__);
SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
@@ -5847,9 +5879,11 @@
int i;
u8 sitar_version;
void *ptr = NULL;
+ struct wcd9xxx_core_resource *core_res;
codec->control_data = dev_get_drvdata(codec->dev->parent);
core = codec->control_data;
+ core_res = &core->core_res;
sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
if (!sitar) {
@@ -5951,7 +5985,7 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_INSERTION,
sitar_hs_insert_irq, "Headset insert detect", sitar);
if (ret) {
@@ -5959,9 +5993,9 @@
WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_REMOVAL,
sitar_hs_remove_irq, "Headset remove detect", sitar);
if (ret) {
@@ -5970,7 +6004,7 @@
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_POTENTIAL,
sitar_dce_handler, "DC Estimation detect", sitar);
if (ret) {
@@ -5979,7 +6013,7 @@
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_RELEASE,
sitar_release_handler,
"Button Release detect", sitar);
@@ -5989,7 +6023,7 @@
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
sitar_slimbus_irq, "SLIMBUS Slave", sitar);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6002,7 +6036,7 @@
SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
sitar_hphl_ocp_irq,
"HPH_L OCP detect", sitar);
@@ -6011,10 +6045,10 @@
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
sitar_hphr_ocp_irq, "HPH_R OCP detect",
sitar);
@@ -6023,7 +6057,7 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
codec->ignore_pmdown_time = 1;
@@ -6034,19 +6068,19 @@
return ret;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
sitar);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
sitar);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
sitar);
err_insert_irq:
kfree(ptr);
@@ -6059,12 +6093,15 @@
static int sitar_codec_remove(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, sitar);
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
+
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
sitar);
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, sitar);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
sitar);
SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_disable_clock_block(codec);
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index c0448f2..fa44b72 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -2977,6 +2977,7 @@
unsigned int value)
{
int ret;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
if (reg == SND_SOC_NOPM)
return 0;
@@ -2990,13 +2991,14 @@
reg, ret);
}
- return wcd9xxx_reg_write(codec->control_data, reg, value);
+ return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
}
static unsigned int tapan_read(struct snd_soc_codec *codec,
unsigned int reg)
{
unsigned int val;
int ret;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
if (reg == SND_SOC_NOPM)
return 0;
@@ -3013,7 +3015,7 @@
reg, ret);
}
- val = wcd9xxx_reg_read(codec->control_data, reg);
+ val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
return val;
}
@@ -4815,8 +4817,10 @@
{
int ret = 0;
struct snd_soc_codec *codec = tapan->codec;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
tapan_slimbus_irq, "SLIMBUS Slave", tapan);
if (ret)
pr_err("%s: Failed to request irq %d\n", __func__,
@@ -4830,7 +4834,9 @@
static void tapan_cleanup_irqs(struct tapan_priv *tapan)
{
struct snd_soc_codec *codec = tapan->codec;
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tapan);
}
@@ -4874,6 +4880,8 @@
cfilt_mode.cur_mode_val =
snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
+ cfilt_mode.reg_mask = 0x30;
+
return cfilt_mode;
}
@@ -4885,8 +4893,15 @@
static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
{
- void *cdata = mbhc->codec->control_data;
- wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+ struct wcd9xxx *wcd9xxx = mbhc->codec->control_data;
+ struct wcd9xxx_core_resource *core_res =
+ &wcd9xxx->core_res;
+ wcd9xxx_free_irq(core_res, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
+}
+
+enum wcd9xxx_cdc_type tapan_get_cdc_type(void)
+{
+ return WCD9XXX_CDC_TYPE_TAPAN;
}
static const struct wcd9xxx_mbhc_cb mbhc_cb = {
@@ -4897,6 +4912,7 @@
.switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
.select_cfilt = tapan_select_cfilt,
.free_irq = tapan_free_irq,
+ .get_cdc_type = tapan_get_cdc_type,
};
int tapan_hs_detect(struct snd_soc_codec *codec,
@@ -4905,7 +4921,17 @@
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
}
-EXPORT_SYMBOL_GPL(tapan_hs_detect);
+EXPORT_SYMBOL(tapan_hs_detect);
+
+static int tapan_device_down(struct wcd9xxx *wcd9xxx)
+{
+ struct snd_soc_codec *codec;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ snd_soc_card_change_online_state(codec->card, 0);
+
+ return 0;
+}
static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
@@ -4916,8 +4942,10 @@
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
tapan = snd_soc_codec_get_drvdata(codec);
- mutex_lock(&codec->mutex);
+ snd_soc_card_change_online_state(codec->card, 1);
+
+ mutex_lock(&codec->mutex);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
kfree(codec->reg_cache);
@@ -4957,6 +4985,12 @@
pr_err("%s: mbhc init failed %d\n", __func__, ret);
else
wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
+
+ tapan_cleanup_irqs(tapan);
+ ret = tapan_setup_irqs(tapan);
+ if (ret)
+ pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
mutex_unlock(&codec->mutex);
return ret;
}
@@ -4965,9 +4999,12 @@
};
static int wcd9xxx_ssr_register(struct wcd9xxx *control,
- int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+ int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+ int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+ void *priv)
{
- control->post_reset = post_reset_cb;
+ control->dev_down = device_down_cb;
+ control->post_reset = device_up_cb;
control->ssr_priv = priv;
return 0;
}
@@ -4989,10 +5026,12 @@
static void tapan_enable_config_rco(struct wcd9xxx *core, bool enable)
{
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
+
if (enable) {
/* Enable RC Oscillator */
wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0x00);
- wcd9xxx_reg_write(core, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
+ wcd9xxx_reg_write(core_res, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
usleep_range(5, 5);
wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
@@ -5001,7 +5040,7 @@
usleep_range(20, 20);
wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
/* Enable MCLK and wait 1ms till it gets enabled */
- wcd9xxx_reg_write(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+ wcd9xxx_reg_write(core_res, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
usleep_range(1000, 1000);
/* Enable CLK BUFF and wait for 1.2ms */
wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
@@ -5029,6 +5068,7 @@
bool ret = true;
unsigned long timeout;
bool timedout;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
if (!core) {
dev_err(cdc_dev, "%s: core not initialized\n", __func__);
@@ -5038,18 +5078,19 @@
tapan_enable_config_rco(core, 1);
if (sensed == false) {
- reg_val = wcd9xxx_reg_read(core, TAPAN_A_QFUSE_CTL);
- wcd9xxx_reg_write(core, TAPAN_A_QFUSE_CTL, (reg_val | 0x03));
+ reg_val = wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_CTL);
+ wcd9xxx_reg_write(core_res, TAPAN_A_QFUSE_CTL,
+ (reg_val | 0x03));
}
timeout = jiffies + HZ;
do {
- if ((wcd9xxx_reg_read(core, TAPAN_A_QFUSE_STATUS)))
+ if ((wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_STATUS)))
break;
} while (!(timedout = time_after(jiffies, timeout)));
- if (wcd9xxx_reg_read(core, TAPAN_A_QFUSE_DATA_OUT1) ||
- wcd9xxx_reg_read(core, TAPAN_A_QFUSE_DATA_OUT2)) {
+ if (wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT1) ||
+ wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT2)) {
dev_info(cdc_dev, "%s: wcd9302 detected\n", __func__);
ret = false;
} else
@@ -5069,11 +5110,13 @@
int ret = 0;
int i, rco_clk_rate;
void *ptr = NULL;
+ struct wcd9xxx_core_resource *core_res;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
- wcd9xxx_ssr_register(control, tapan_post_reset_cb, (void *)codec);
+ wcd9xxx_ssr_register(control, tapan_device_down,
+ tapan_post_reset_cb, (void *)codec);
dev_info(codec->dev, "%s()\n", __func__);
@@ -5093,9 +5136,10 @@
/* codec resmgr module init */
wcd9xxx = codec->control_data;
+ core_res = &wcd9xxx->core_res;
pdata = dev_get_platdata(codec->dev->parent);
- ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
- &tapan_reg_address);
+ ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
+ &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
if (ret) {
pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
return ret;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 212924fd..673b634 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -5949,11 +5949,12 @@
{
int r = 0;
struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
/* if scheduled mbhc_btn_dwork is canceled from here,
* we have to unlock from here instead btn_work */
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
r = 1;
}
return r;
@@ -6332,12 +6333,14 @@
short bias_value;
int dce_mv, sta_mv;
struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
pr_debug("%s:\n", __func__);
delayed_work = to_delayed_work(work);
tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
core = dev_get_drvdata(tabla->codec->dev->parent);
+ core_res = &core->core_res;
if (tabla) {
if (tabla->mbhc_cfg.button_jack) {
@@ -6360,7 +6363,7 @@
}
pr_debug("%s: leave\n", __func__);
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
static u16 tabla_get_cfilt_reg(struct snd_soc_codec *codec, u8 cfilt)
@@ -6816,6 +6819,7 @@
short btnmeas[d->n_btn_meas + 1];
struct snd_soc_codec *codec = priv->codec;
struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
int n_btn_meas = d->n_btn_meas;
u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
@@ -6917,12 +6921,12 @@
tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
mask = tabla_get_button_mask(btn);
priv->buttons_pressed |= mask;
- wcd9xxx_lock_sleep(core);
+ wcd9xxx_lock_sleep(core_res);
if (schedule_delayed_work(&priv->mbhc_btn_dwork,
msecs_to_jiffies(400)) == 0) {
WARN(1, "Button pressed twice without release"
"event\n");
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
} else {
pr_debug("%s: bogus button press, too short press?\n",
@@ -7248,9 +7252,11 @@
static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla,
struct work_struct *correct_plug_work)
{
+ struct wcd9xxx *core = tabla->codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
tabla->hs_detect_work_stop = false;
- wcd9xxx_lock_sleep(tabla->codec->control_data);
+ wcd9xxx_lock_sleep(core_res);
schedule_work(correct_plug_work);
}
@@ -7258,13 +7264,15 @@
static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla,
struct work_struct *correct_plug_work)
{
+ struct wcd9xxx *core = tabla->codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
tabla->hs_detect_work_stop = true;
wmb();
TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
if (cancel_work_sync(correct_plug_work)) {
pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
- wcd9xxx_unlock_sleep(tabla->codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
}
@@ -7470,9 +7478,13 @@
bool correction = false;
enum tabla_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
unsigned long timeout;
+ struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
codec = tabla->codec;
+ core = tabla->codec->control_data;
+ core_res = &core->core_res;
pr_debug("%s: enter\n", __func__);
tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
@@ -7581,7 +7593,7 @@
pr_debug("%s: leave current_plug(%d)\n",
__func__, tabla->current_plug);
/* unlock sleep */
- wcd9xxx_unlock_sleep(tabla->codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
/* called under codec_resource_lock acquisition */
@@ -7738,6 +7750,7 @@
int ret;
struct snd_soc_codec *codec = priv->codec;
struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
/* Cancel possibly running hs_detect_work */
@@ -7766,12 +7779,12 @@
} else if (is_mb_trigger && !is_removal) {
pr_debug("%s: Waiting for Headphone left trigger\n",
__func__);
- wcd9xxx_lock_sleep(core);
+ wcd9xxx_lock_sleep(core_res);
if (schedule_delayed_work(&priv->mbhc_insert_dwork,
usecs_to_jiffies(1000000)) == 0) {
pr_err("%s: mbhc_insert_dwork is already scheduled\n",
__func__);
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
false);
@@ -7781,7 +7794,7 @@
pr_debug("%s: Complete plug insertion, Detecting plug "
"type\n", __func__);
tabla_codec_detect_plug_type(codec);
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
} else {
wcd9xxx_enable_irq(codec->control_data,
WCD9XXX_IRQ_MBHC_INSERTION);
@@ -8058,11 +8071,13 @@
struct tabla_priv *tabla;
struct snd_soc_codec *codec;
struct wcd9xxx *tabla_core;
+ struct wcd9xxx_core_resource *core_res;
dwork = to_delayed_work(work);
tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
codec = tabla->codec;
tabla_core = dev_get_drvdata(codec->dev->parent);
+ core_res = &tabla_core->core_res;
pr_debug("%s:\n", __func__);
@@ -8073,7 +8088,7 @@
wcd9xxx_disable_irq_sync(codec->control_data,
WCD9XXX_IRQ_MBHC_INSERTION);
tabla_codec_detect_plug_type(codec);
- wcd9xxx_unlock_sleep(tabla_core);
+ wcd9xxx_unlock_sleep(core_res);
}
static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
@@ -8090,7 +8105,7 @@
usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
- wcd9xxx_nested_irq_lock(core);
+ wcd9xxx_nested_irq_lock(&core->core_res);
TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
/* cancel pending button press */
@@ -8163,7 +8178,7 @@
tabla->in_gpio_handler = false;
TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
- wcd9xxx_nested_irq_unlock(core);
+ wcd9xxx_nested_irq_unlock(&core->core_res);
pr_debug("%s: leave\n", __func__);
}
@@ -8172,8 +8187,10 @@
int r = IRQ_HANDLED;
struct snd_soc_codec *codec = data;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx *core = codec->control_data;
+ struct wcd9xxx_core_resource *core_res = &core->core_res;
- if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+ if (unlikely(wcd9xxx_lock_sleep(core_res) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
/*
* Give up this IRQ for now and resend this IRQ so IRQ can be
@@ -8186,7 +8203,7 @@
r = IRQ_NONE;
} else {
tabla_hs_gpio_handler(codec);
- wcd9xxx_unlock_sleep(codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
return r;
@@ -8200,6 +8217,8 @@
int retry = 0;
enum tabla_mbhc_plug_type plug_type;
bool is_headset = false;
+ struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
pr_debug("%s(): Poll Microphone voltage for %d seconds\n",
__func__, TABLA_HS_DETECT_PLUG_TIME_MS / 1000);
@@ -8207,6 +8226,8 @@
tabla = container_of(work, struct tabla_priv,
hs_correct_plug_work_nogpio);
codec = tabla->codec;
+ core = codec->control_data;
+ core_res = &core->core_res;
/* Make sure the MBHC mux is connected to MIC Path */
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
@@ -8261,7 +8282,7 @@
tabla_codec_cleanup_hs_polling(codec);
tabla_codec_enable_hs_detect(codec, 0, 0, false);
}
- wcd9xxx_unlock_sleep(codec->control_data);
+ wcd9xxx_unlock_sleep(core_res);
}
static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
@@ -8933,9 +8954,11 @@
int ret = 0;
int i;
void *ptr = NULL;
+ struct wcd9xxx_core_resource *core_res;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
+ core_res = &control->core_res;
tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
if (!tabla) {
@@ -9049,7 +9072,7 @@
snd_soc_dapm_sync(dapm);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_INSERTION,
tabla_hs_insert_irq, "Headset insert detect", tabla);
if (ret) {
@@ -9057,9 +9080,9 @@
WCD9XXX_IRQ_MBHC_INSERTION);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_REMOVAL,
tabla_hs_remove_irq,
"Headset remove detect", tabla);
@@ -9069,7 +9092,7 @@
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_MBHC_POTENTIAL,
tabla_dce_handler, "DC Estimation detect",
tabla);
@@ -9079,7 +9102,7 @@
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
tabla_release_handler,
"Button Release detect", tabla);
if (ret) {
@@ -9088,7 +9111,7 @@
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
tabla_slimbus_irq, "SLIMBUS Slave", tabla);
if (ret) {
pr_err("%s: Failed to request irq %d\n", __func__,
@@ -9097,10 +9120,10 @@
}
for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
- wcd9xxx_interface_reg_write(codec->control_data,
- TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+ wcd9xxx_interface_reg_write(control,
+ TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
tabla_hphl_ocp_irq,
"HPH_L OCP detect", tabla);
@@ -9109,9 +9132,9 @@
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
- ret = wcd9xxx_request_irq(codec->control_data,
+ ret = wcd9xxx_request_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
tabla_hphr_ocp_irq,
"HPH_R OCP detect", tabla);
@@ -9120,7 +9143,7 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
/*
* Register suspend lock and notifier to resend edge triggered
@@ -9151,19 +9174,19 @@
return ret;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(codec->control_data,
+ wcd9xxx_free_irq(core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tabla);
err_slimbus_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
err_release_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
tabla);
err_potential_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
err_remove_irq:
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
tabla);
err_insert_irq:
err_pdata:
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index c27e085..6e500f5 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -4051,6 +4051,7 @@
unsigned int value)
{
int ret;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
if (reg == SND_SOC_NOPM)
return 0;
@@ -4064,7 +4065,7 @@
reg, ret);
}
- return wcd9xxx_reg_write(codec->control_data, reg, value);
+ return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
}
static unsigned int taiko_read(struct snd_soc_codec *codec,
unsigned int reg)
@@ -4072,6 +4073,8 @@
unsigned int val;
int ret;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+
if (reg == SND_SOC_NOPM)
return 0;
@@ -4087,7 +4090,7 @@
reg, ret);
}
- val = wcd9xxx_reg_read(codec->control_data, reg);
+ val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
return val;
}
@@ -6151,8 +6154,11 @@
{
int ret = 0;
struct snd_soc_codec *codec = taiko->codec;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ struct wcd9xxx_core_resource *core_res =
+ &wcd9xxx->core_res;
- ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
taiko_slimbus_irq, "SLIMBUS Slave", taiko);
if (ret)
pr_err("%s: Failed to request irq %d\n", __func__,
@@ -6166,8 +6172,11 @@
static void taiko_cleanup_irqs(struct taiko_priv *taiko)
{
struct snd_soc_codec *codec = taiko->codec;
+ struct wcd9xxx *wcd9xxx = codec->control_data;
+ struct wcd9xxx_core_resource *core_res =
+ &wcd9xxx->core_res;
- wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, taiko);
}
int taiko_hs_detect(struct snd_soc_codec *codec,
@@ -6180,7 +6189,7 @@
taiko->mbhc_started = true;
return rc;
}
-EXPORT_SYMBOL_GPL(taiko_hs_detect);
+EXPORT_SYMBOL(taiko_hs_detect);
void taiko_event_register(
int (*machine_event_cb)(struct snd_soc_codec *codec,
@@ -6190,7 +6199,7 @@
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
taiko->machine_codec_event_cb = machine_event_cb;
}
-EXPORT_SYMBOL_GPL(taiko_event_register);
+EXPORT_SYMBOL(taiko_event_register);
static void taiko_init_slim_slave_cfg(struct snd_soc_codec *codec)
{
@@ -6212,6 +6221,16 @@
pr_debug("%s: slimbus logical address 0x%llx\n", __func__, eaddr);
}
+static int taiko_device_down(struct wcd9xxx *wcd9xxx)
+{
+ struct snd_soc_codec *codec;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ snd_soc_card_change_online_state(codec->card, 0);
+
+ return 0;
+}
+
static int taiko_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
@@ -6221,8 +6240,10 @@
codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
taiko = snd_soc_codec_get_drvdata(codec);
- mutex_lock(&codec->mutex);
+ snd_soc_card_change_online_state(codec->card, 1);
+
+ mutex_lock(&codec->mutex);
if (codec->reg_def_copy) {
pr_debug("%s: Update ASOC cache", __func__);
kfree(codec->reg_cache);
@@ -6267,6 +6288,11 @@
}
taiko->machine_codec_event_cb(codec, WCD9XXX_CODEC_EVENT_CODEC_UP);
+ taiko_cleanup_irqs(taiko);
+ ret = taiko_setup_irqs(taiko);
+ if (ret)
+ pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
+
mutex_unlock(&codec->mutex);
return ret;
}
@@ -6309,9 +6335,12 @@
};
static int wcd9xxx_ssr_register(struct wcd9xxx *control,
- int (*post_reset_cb)(struct wcd9xxx *wcd9xxx), void *priv)
+ int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
+ int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
+ void *priv)
{
- control->post_reset = post_reset_cb;
+ control->dev_down = device_down_cb;
+ control->post_reset = device_up_cb;
control->ssr_priv = priv;
return 0;
}
@@ -6392,11 +6421,13 @@
int i, rco_clk_rate;
void *ptr = NULL;
struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+ struct wcd9xxx_core_resource *core_res;
codec->control_data = dev_get_drvdata(codec->dev->parent);
control = codec->control_data;
- wcd9xxx_ssr_register(control, taiko_post_reset_cb, (void *)codec);
+ wcd9xxx_ssr_register(control, taiko_device_down,
+ taiko_post_reset_cb, (void *)codec);
dev_info(codec->dev, "%s()\n", __func__);
@@ -6416,9 +6447,10 @@
/* codec resmgr module init */
wcd9xxx = codec->control_data;
+ core_res = &wcd9xxx->core_res;
pdata = dev_get_platdata(codec->dev->parent);
- ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, wcd9xxx, pdata,
- &taiko_reg_address);
+ ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, core_res, pdata,
+ &taiko_reg_address, WCD9XXX_CDC_TYPE_TAIKO);
if (ret) {
pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
goto err_init;
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 7820cd0..903b239 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
@@ -257,6 +258,17 @@
pr_debug("%s: leave\n", __func__);
}
+static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
+ unsigned int cfilt_mv)
+{
+ if (mbhc->mbhc_cb &&
+ mbhc->mbhc_cb->get_cdc_type() ==
+ WCD9XXX_CDC_TYPE_HELICON)
+ return 0x18;
+
+ return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
+}
+
/*
* called under codec_resource_lock acquisition
* return old status
@@ -290,7 +302,7 @@
wcd9xxx_turn_onoff_override(codec, true);
/* Adjust threshold if Mic Bias voltage changes */
if (d->micb_mv != VDDIO_MICBIAS_MV) {
- cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+ cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
VDDIO_MICBIAS_MV);
usleep_range(10000, 10000);
snd_soc_update_bits(codec,
@@ -342,7 +354,7 @@
/* Reprogram thresholds */
if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val =
- wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
+ __wcd9xxx_resmgr_get_k_val(mbhc,
d->micb_mv);
snd_soc_update_bits(codec,
mbhc->mbhc_bias_regs.cfilt_val,
@@ -452,7 +464,7 @@
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_cal_btn_det_mp);
+EXPORT_SYMBOL(wcd9xxx_mbhc_cal_btn_det_mp);
static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
@@ -487,34 +499,36 @@
{
struct snd_soc_codec *codec = mbhc->codec;
struct wcd9xxx_cfilt_mode cfilt_mode;
- u8 reg_mode_val, cur_mode_val;
if (mbhc->mbhc_cb && mbhc->mbhc_cb->switch_cfilt_mode) {
cfilt_mode = mbhc->mbhc_cb->switch_cfilt_mode(mbhc, fast);
- reg_mode_val = cfilt_mode.reg_mode_val;
- cur_mode_val = cfilt_mode.cur_mode_val;
} else {
if (fast)
- reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
+ cfilt_mode.reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
else
- reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
+ cfilt_mode.reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
- cur_mode_val =
+ cfilt_mode.reg_mask = 0x40;
+ cfilt_mode.cur_mode_val =
snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
}
- if (cur_mode_val != reg_mode_val) {
+
+ if (cfilt_mode.cur_mode_val
+ != cfilt_mode.reg_mode_val) {
if (mbhc->polling_active)
wcd9xxx_pause_hs_polling(mbhc);
snd_soc_update_bits(codec,
mbhc->mbhc_bias_regs.cfilt_ctl,
- 0x40, reg_mode_val);
+ cfilt_mode.reg_mask,
+ cfilt_mode.reg_mode_val);
if (mbhc->polling_active)
wcd9xxx_start_hs_polling(mbhc);
pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
- cur_mode_val, reg_mode_val);
+ cfilt_mode.cur_mode_val,
+ cfilt_mode.reg_mode_val);
} else {
pr_debug("%s: CFILT Value is already %x\n",
- __func__, cur_mode_val);
+ __func__, cfilt_mode.cur_mode_val);
}
}
@@ -556,7 +570,7 @@
mbhc->hphlocp_cnt = 0;
else
mbhc->hphrocp_cnt = 0;
- wcd9xxx_enable_irq(codec->control_data, irq);
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res, irq);
}
}
@@ -578,6 +592,18 @@
unsigned int cfilt;
struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
+ if (mbhc->mbhc_cb &&
+ mbhc->mbhc_cb->get_cdc_type() ==
+ WCD9XXX_CDC_TYPE_HELICON) {
+ micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
+ micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
+ micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
+ micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
+ micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
+ mbhc->mbhc_data.micb_mv = 1800;
+ return;
+ }
+
switch (mbhc->mbhc_cfg->micbias) {
case MBHC_MICBIAS1:
cfilt = pdata->micbias.bias1_cfilt_sel;
@@ -685,7 +711,7 @@
if (r)
/* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
* we have to unlock from here instead btn_work */
- wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+ wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
return r;
}
@@ -836,8 +862,10 @@
pr_debug("%s: Enabling micbias\n", __func__);
mbhc->micbias_enable_cb(mbhc->codec, true);
}
+
if (mbhc->impedance_detect)
wcd9xxx_detect_impedance(mbhc, &mbhc->zl, &mbhc->zr);
+
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -857,7 +885,7 @@
pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
mbhc->hs_detect_work_stop = false;
- wcd9xxx_lock_sleep(mbhc->resmgr->core);
+ wcd9xxx_lock_sleep(mbhc->resmgr->core_res);
schedule_work(work);
}
@@ -873,7 +901,7 @@
if (cancel_work_sync(work)) {
pr_debug("%s: correct_plug_swch is canceled\n",
__func__);
- wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+ wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
}
WCD9XXX_BCL_LOCK(mbhc->resmgr);
}
@@ -882,8 +910,8 @@
{
int r;
int vddio_k, mb_k;
- 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);
+ vddio_k = __wcd9xxx_resmgr_get_k_val(mbhc, VDDIO_MICBIAS_MV);
+ mb_k = __wcd9xxx_resmgr_get_k_val(mbhc, mbhc->mbhc_data.micb_mv);
if (tovddio)
r = v * (vddio_k + 4) / (mb_k + 4);
else
@@ -939,7 +967,7 @@
short bias_value;
struct snd_soc_codec *codec = mbhc->codec;
- wcd9xxx_disable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
if (noreldetection)
wcd9xxx_turn_onoff_rel_detection(codec, false);
@@ -980,7 +1008,7 @@
if (noreldetection)
wcd9xxx_turn_onoff_rel_detection(codec, true);
- wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
return bias_value;
}
@@ -1796,12 +1824,12 @@
if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
/* called by interrupt */
if (!is_clk_active(codec)) {
- wcd9xxx_resmgr_enable_config_mode(codec, 1);
+ wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 1);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
0x06, 0);
usleep_range(generic->t_shutdown_plug_rem,
generic->t_shutdown_plug_rem);
- wcd9xxx_resmgr_enable_config_mode(codec, 0);
+ wcd9xxx_resmgr_enable_config_mode(mbhc->resmgr, 0);
} else
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
0x06, 0);
@@ -1833,7 +1861,7 @@
snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
0x3, mbhc->mbhc_cfg->micbias);
- wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
pr_debug("%s: leave\n", __func__);
@@ -2297,7 +2325,7 @@
pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_LOCK(mbhc->resmgr);
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_INSERTION);
is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
0x10);
@@ -2343,7 +2371,7 @@
mbhc->buttons_pressed);
pr_debug("%s: leave\n", __func__);
- wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+ wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
}
static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
@@ -2351,12 +2379,12 @@
struct delayed_work *dwork;
struct wcd9xxx_mbhc *mbhc;
struct snd_soc_codec *codec;
- struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
dwork = to_delayed_work(work);
mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
codec = mbhc->codec;
- core = mbhc->resmgr->core;
+ core_res = mbhc->resmgr->core_res;
pr_debug("%s:\n", __func__);
@@ -2364,9 +2392,9 @@
snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- wcd9xxx_disable_irq_sync(core, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq_sync(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
wcd9xxx_mbhc_detect_plug_type(mbhc);
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
@@ -2702,7 +2730,7 @@
}
pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
/* unlock sleep */
- wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+ wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
}
static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
@@ -2797,13 +2825,13 @@
struct wcd9xxx_mbhc *mbhc = data;
pr_debug("%s: enter\n", __func__);
- if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core) == false)) {
+ if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core_res) == false)) {
pr_warn("%s: failed to hold suspend\n", __func__);
r = IRQ_NONE;
} else {
/* Call handler */
wcd9xxx_swch_irq_handler(mbhc);
- wcd9xxx_unlock_sleep(mbhc->resmgr->core);
+ wcd9xxx_unlock_sleep(mbhc->resmgr->core_res);
}
pr_debug("%s: leave %d\n", __func__, r);
@@ -2979,7 +3007,7 @@
short dce[d->n_btn_meas + 1], sta;
s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
struct snd_soc_codec *codec = mbhc->codec;
- struct wcd9xxx *core = mbhc->resmgr->core;
+ struct wcd9xxx_core_resource *core_res = mbhc->resmgr->core_res;
int n_btn_meas = d->n_btn_meas;
void *calibration = mbhc->mbhc_cfg->calibration;
@@ -3119,11 +3147,11 @@
mask = wcd9xxx_get_button_mask(btn);
mbhc->buttons_pressed |= mask;
- wcd9xxx_lock_sleep(core);
+ wcd9xxx_lock_sleep(core_res);
if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
msecs_to_jiffies(400)) == 0) {
WARN(1, "Button pressed twice without release event\n");
- wcd9xxx_unlock_sleep(core);
+ wcd9xxx_unlock_sleep(core_res);
}
} else {
pr_debug("%s: bogus button press, too short press?\n",
@@ -3207,7 +3235,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
0x10, 0x10);
} else {
- wcd9xxx_disable_irq(codec->control_data,
+ wcd9xxx_disable_irq(mbhc->resmgr->core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
mbhc->hph_status |= SND_JACK_OC_HPHL;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -3237,7 +3265,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
0x10);
} else {
- wcd9xxx_disable_irq(mbhc->resmgr->core,
+ wcd9xxx_disable_irq(mbhc->resmgr->core_res,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
mbhc->hph_status |= SND_JACK_OC_HPHR;
wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
@@ -3318,7 +3346,7 @@
struct snd_soc_codec *codec = mbhc->codec;
pr_debug("%s: enter\n", __func__);
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_disable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
wcd9xxx_turn_onoff_rel_detection(codec, false);
/* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
@@ -3449,7 +3477,7 @@
0x80, 0x80);
usleep_range(100, 100);
- wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
wcd9xxx_turn_onoff_rel_detection(codec, true);
pr_debug("%s: leave\n", __func__);
@@ -3492,9 +3520,14 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
btn_det->mbhc_nsc << 3);
- if (mbhc->resmgr->reg_addr->micb_4_mbhc)
- snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
- 0x03, MBHC_MICBIAS2);
+ if (mbhc->mbhc_cb &&
+ mbhc->mbhc_cb->get_cdc_type() !=
+ WCD9XXX_CDC_TYPE_HELICON) {
+ if (mbhc->resmgr->reg_addr->micb_4_mbhc)
+ snd_soc_update_bits(codec,
+ mbhc->resmgr->reg_addr->micb_4_mbhc,
+ 0x03, MBHC_MICBIAS2);
+ }
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
@@ -3510,8 +3543,8 @@
static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
{
int ret = 0;
- void *core = mbhc->resmgr->core;
struct snd_soc_codec *codec = mbhc->codec;
+ void *core_res = mbhc->resmgr->core_res;
int jack_irq;
if (mbhc->mbhc_cb && mbhc->mbhc_cb->jack_detect_irq)
@@ -3540,7 +3573,7 @@
snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
1 << 1, 1 << 1);
- ret = wcd9xxx_request_irq(core, jack_irq,
+ ret = wcd9xxx_request_irq(core_res, jack_irq,
wcd9xxx_mech_plug_detect_irq,
"Jack Detect",
mbhc);
@@ -3575,9 +3608,9 @@
if (!IS_ERR_VALUE(ret)) {
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
0x10);
- wcd9xxx_enable_irq(codec->control_data,
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res,
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
- wcd9xxx_enable_irq(codec->control_data,
+ wcd9xxx_enable_irq(mbhc->resmgr->core_res,
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
/* Initialize mechanical mbhc */
@@ -3798,6 +3831,14 @@
snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
0x40, WCD9XXX_CFILT_FAST_MODE);
+ /*
+ * If codec has specific clock gating for MBHC,
+ * remove the clock gate
+ */
+ if (mbhc->mbhc_cb &&
+ mbhc->mbhc_cb->enable_clock_gate)
+ mbhc->mbhc_cb->enable_clock_gate(mbhc->codec, true);
+
if (!mbhc->mbhc_cfg->read_fw_bin)
rc = wcd9xxx_init_and_calibrate(mbhc);
else
@@ -3807,7 +3848,7 @@
pr_debug("%s: leave %d\n", __func__, rc);
return rc;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_start);
+EXPORT_SYMBOL(wcd9xxx_mbhc_start);
static enum wcd9xxx_micbias_num
wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
@@ -4374,7 +4415,7 @@
bool impedance_det_en)
{
int ret;
- void *core;
+ void *core_res;
pr_debug("%s: enter\n", __func__);
memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
@@ -4441,18 +4482,18 @@
wcd9xxx_init_debugfs(mbhc);
- core = mbhc->resmgr->core;
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_INSERTION,
+ core_res = mbhc->resmgr->core_res;
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION,
wcd9xxx_hs_insert_irq,
"Headset insert detect", mbhc);
if (ret) {
- pr_err("%s: Failed to request irq %d\n", __func__,
- WCD9XXX_IRQ_MBHC_INSERTION);
+ pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
+ WCD9XXX_IRQ_MBHC_INSERTION, ret);
goto err_insert_irq;
}
- wcd9xxx_disable_irq(core, WCD9XXX_IRQ_MBHC_INSERTION);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION);
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL,
wcd9xxx_hs_remove_irq,
"Headset remove detect", mbhc);
if (ret) {
@@ -4461,7 +4502,7 @@
goto err_remove_irq;
}
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL,
wcd9xxx_dce_handler, "DC Estimation detect",
mbhc);
if (ret) {
@@ -4470,7 +4511,7 @@
goto err_potential_irq;
}
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_RELEASE,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE,
wcd9xxx_release_handler,
"Button Release detect", mbhc);
if (ret) {
@@ -4479,7 +4520,7 @@
goto err_release_irq;
}
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
mbhc);
if (ret) {
@@ -4487,9 +4528,9 @@
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
goto err_hphl_ocp_irq;
}
- wcd9xxx_disable_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
- ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
+ ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
mbhc);
if (ret) {
@@ -4497,7 +4538,7 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
goto err_hphr_ocp_irq;
}
- wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
+ wcd9xxx_disable_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
wcd9xxx_regmgr_cond_register(resmgr, 1 << WCD9XXX_COND_HPH_MIC |
1 << WCD9XXX_COND_HPH);
@@ -4506,43 +4547,44 @@
return ret;
err_hphr_ocp_irq:
- wcd9xxx_free_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
err_hphl_ocp_irq:
- wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
err_release_irq:
- wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
err_potential_irq:
- wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
err_remove_irq:
- wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
err_insert_irq:
wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
pr_debug("%s: leave ret %d\n", __func__, ret);
return ret;
}
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_init);
+EXPORT_SYMBOL(wcd9xxx_mbhc_init);
void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
{
- void *cdata = mbhc->codec->control_data;
+ struct wcd9xxx_core_resource *core_res =
+ mbhc->resmgr->core_res;
wcd9xxx_regmgr_cond_deregister(mbhc->resmgr, 1 << WCD9XXX_COND_HPH_MIC |
1 << WCD9XXX_COND_HPH);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->free_irq)
mbhc->mbhc_cb->free_irq(mbhc);
else
- wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH,
+ wcd9xxx_free_irq(core_res, WCD9320_IRQ_MBHC_JACK_SWITCH,
mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
- wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
+ wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
if (mbhc->mbhc_fw)
release_firmware(mbhc->mbhc_fw);
@@ -4551,7 +4593,7 @@
wcd9xxx_cleanup_debugfs(mbhc);
}
-EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
+EXPORT_SYMBOL(wcd9xxx_mbhc_deinit);
MODULE_DESCRIPTION("wcd9xxx MBHC module");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 88c911f..104c488 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -224,6 +224,7 @@
struct wcd9xxx_cfilt_mode {
u8 reg_mode_val;
u8 cur_mode_val;
+ u8 reg_mask;
};
struct wcd9xxx_mbhc_cb {
@@ -236,6 +237,8 @@
bool);
void (*select_cfilt) (struct snd_soc_codec *, struct wcd9xxx_mbhc *);
void (*free_irq) (struct wcd9xxx_mbhc *);
+ enum wcd9xxx_cdc_type (*get_cdc_type) (void);
+ void (*enable_clock_gate) (struct snd_soc_codec *, bool);
};
struct wcd9xxx_mbhc {
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 9633cc0..95244c0 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -33,6 +33,7 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include "wcd9xxx-resmgr.h"
+#include "msm8x10_wcd_registers.h"
static char wcd9xxx_event_string[][64] = {
"WCD9XXX_EVENT_INVALID",
@@ -168,7 +169,9 @@
* mclk should be off or clk buff source souldn't be VBG
* Let's turn off mclk always
*/
- WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
wcd9xxx_enable_bg(resmgr);
/* Notify bandgap mode change */
wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_BG_MBHC_ON);
@@ -188,11 +191,13 @@
wcd9xxx_resmgr_notifier_call(resmgr,
WCD9XXX_EVENT_PRE_MCLK_OFF);
/* Disable clock */
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
- usleep_range(50, 50);
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
- usleep_range(50, 50);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
+ usleep_range(50, 50);
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
+ usleep_range(50, 50);
+ }
/* Notify */
if (resmgr->clk_type == WCD9XXX_CLK_RCO)
wcd9xxx_resmgr_notifier_call(resmgr,
@@ -375,8 +380,10 @@
}
}
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable)
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable)
{
+ struct snd_soc_codec *codec = resmgr->codec;
+
pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0);
@@ -388,10 +395,20 @@
usleep_range(10, 10);
snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0);
usleep_range(10000, 10000);
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+ 0x08, 0x08);
+ else
+ snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x20, 0x20);
} else {
snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0);
snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0);
+ if (resmgr->codec_type == WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x20, 0x00);
}
return 0;
@@ -403,38 +420,60 @@
struct snd_soc_codec *codec = resmgr->codec;
pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
/* transit to RCO requires mclk off */
- WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ WARN_ON(snd_soc_read(codec, WCD9XXX_A_CLK_BUFF_EN2) & (1 << 2));
+
if (config_mode) {
/* Notify */
wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON);
/* enable RCO and switch to it */
- wcd9xxx_resmgr_enable_config_mode(codec, 1);
- snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
+ wcd9xxx_resmgr_enable_config_mode(resmgr, 1);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
usleep_range(1000, 1000);
} else {
/* Notify */
wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_MCLK_ON);
/* switch to MCLK */
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x00);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+ 0x08, 0x00);
+ } else {
+ snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
+ 0x03, 0x03);
+ snd_soc_update_bits(codec,
+ MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
+ 0x0f, 0x0d);
+ }
/* if RCO is enabled, switch from it */
if (snd_soc_read(codec, WCD9XXX_A_RC_OSC_FREQ) & 0x80) {
- snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
- wcd9xxx_resmgr_enable_config_mode(codec, 0);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_write(codec, WCD9XXX_A_CLK_BUFF_EN2,
+ 0x02);
+ wcd9xxx_resmgr_enable_config_mode(resmgr, 0);
}
/* clk source to ext clk and clk buff ref to VBG */
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x0C, 0x04);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON)
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1,
+ 0x0C, 0x04);
}
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
- /* sleep time required by codec hardware to enable clock buffer */
- usleep_range(1000, 1200);
-
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
-
- /* on MCLK */
- snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+ if (resmgr->codec_type != WCD9XXX_CDC_TYPE_HELICON) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
+ /* sleep required by codec hardware to enable clock buffer */
+ usleep_range(1000, 1200);
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
+ /* on MCLK */
+ snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ } else {
+ snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
+ 0x01, 0x01);
+ }
usleep_range(50, 50);
/* Notify */
@@ -493,7 +532,7 @@
WCD9XXX_A_RC_OSC_FREQ) & 0x80));
/* disable clock block */
wcd9xxx_disable_clock_block(resmgr);
- /* switch to RCO */
+ /* switch to MCLK */
wcd9xxx_enable_clock_block(resmgr, 0);
resmgr->clk_type = WCD9XXX_CLK_MCLK;
}
@@ -797,9 +836,10 @@
int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
struct snd_soc_codec *codec,
- struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_core_resource *core_res,
struct wcd9xxx_pdata *pdata,
- struct wcd9xxx_reg_address *reg_addr)
+ struct wcd9xxx_reg_address *reg_addr,
+ enum wcd9xxx_cdc_type cdc_type)
{
WARN(ARRAY_SIZE(wcd9xxx_event_string) != WCD9XXX_EVENT_LAST + 1,
"Event string table isn't up to date!, %d != %d\n",
@@ -807,8 +847,9 @@
resmgr->bandgap_type = WCD9XXX_BANDGAP_OFF;
resmgr->codec = codec;
+ resmgr->codec_type = cdc_type;
/* This gives access of core handle to lock/unlock suspend */
- resmgr->core = wcd9xxx;
+ resmgr->core_res = core_res;
resmgr->pdata = pdata;
resmgr->reg_addr = reg_addr;
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index e6a8f5d..7fb5820 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -13,6 +13,7 @@
#define __WCD9XXX_COMMON_H__
#include <linux/notifier.h>
+#include <linux/mfd/wcd9xxx/core-resource.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
enum wcd9xxx_bandgap_type {
@@ -21,6 +22,13 @@
WCD9XXX_BANDGAP_MBHC_MODE,
};
+enum wcd9xxx_cdc_type {
+ WCD9XXX_CDC_TYPE_INVALID = 0,
+ WCD9XXX_CDC_TYPE_TAIKO,
+ WCD9XXX_CDC_TYPE_TAPAN,
+ WCD9XXX_CDC_TYPE_HELICON,
+};
+
enum wcd9xxx_clock_type {
WCD9XXX_CLK_OFF,
WCD9XXX_CLK_RCO,
@@ -102,7 +110,7 @@
struct wcd9xxx_resmgr {
struct snd_soc_codec *codec;
- struct wcd9xxx *core;
+ struct wcd9xxx_core_resource *core_res;
u32 rx_bias_count;
@@ -146,16 +154,20 @@
*/
struct mutex codec_resource_lock;
struct mutex codec_bg_clk_lock;
+
+ enum wcd9xxx_cdc_type codec_type;
};
int wcd9xxx_resmgr_init(struct wcd9xxx_resmgr *resmgr,
struct snd_soc_codec *codec,
- struct wcd9xxx *wcd9xxx,
+ struct wcd9xxx_core_resource *core_res,
struct wcd9xxx_pdata *pdata,
- struct wcd9xxx_reg_address *reg_addr);
+ struct wcd9xxx_reg_address *reg_addr,
+ enum wcd9xxx_cdc_type cdc_type);
void wcd9xxx_resmgr_deinit(struct wcd9xxx_resmgr *resmgr);
-int wcd9xxx_resmgr_enable_config_mode(struct snd_soc_codec *codec, int enable);
+int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr,
+ int enable);
void wcd9xxx_resmgr_enable_rx_bias(struct wcd9xxx_resmgr *resmgr, u32 enable);
void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr,
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index 7871900..bc36aae 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -39,12 +39,14 @@
#define EXT_CLASS_D_DIS_DELAY 3000
#define EXT_CLASS_D_DELAY_DELTA 2000
+#define CDC_EXT_CLK_RATE 9600000
+#define WCD9XXX_MBHC_DEF_BUTTONS 8
+#define WCD9XXX_MBHC_DEF_RLOADS 5
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
static int msm_proxy_rx_ch = 2;
-static struct snd_soc_jack hs_jack;
static struct platform_device *spdev;
static int ext_spk_amp_gpio = -1;
@@ -55,6 +57,23 @@
static int msm_sec_mi2s_rx_ch = 1;
static int msm_pri_mi2s_tx_ch = 1;
+static void *def_msm8x10_wcd_mbhc_cal(void);
+static int msm8x10_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_MICBIAS1,
+ .mclk_cb_fn = msm8x10_enable_codec_ext_clk,
+ .mclk_rate = CDC_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 0,
+ .detect_extn_cable = false,
+ .insert_detect = true,
+ .swap_gnd_mic = NULL,
+};
+
/*
* There is limitation for the clock root selection from
* either MI2S or DIG_CODEC.
@@ -450,6 +469,19 @@
pr_debug("%s(),dev_name%s\n", __func__, dev_name(cpu_dai->dev));
msm8x10_ext_spk_power_amp_init();
+
+ mbhc_cfg.calibration = def_msm8x10_wcd_mbhc_cal();
+ if (mbhc_cfg.calibration) {
+ ret = msm8x10_wcd_hs_detect(codec, &mbhc_cfg);
+ if (ret) {
+ pr_err("%s: msm8x10_wcd_hs_detect failed\n", __func__);
+ goto exit;
+ }
+ } else {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
snd_soc_dapm_new_controls(dapm, msm8x10_dapm_widgets,
ARRAY_SIZE(msm8x10_dapm_widgets));
@@ -461,14 +493,92 @@
if (ret < 0)
return ret;
- ret = snd_soc_jack_new(codec, "Headset Jack",
- SND_JACK_HEADSET, &hs_jack);
- if (ret)
- pr_err("%s: Failed to create headset jack\n", __func__);
+exit:
+ if (gpio_is_valid(ext_spk_amp_gpio))
+ gpio_free(ext_spk_amp_gpio);
return ret;
}
+static void *def_msm8x10_wcd_mbhc_cal(void)
+{
+ void *msm8x10_wcd_cal;
+ struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
+ u16 *btn_low, *btn_high;
+ u8 *n_ready, *n_cic, *gain;
+
+ msm8x10_wcd_cal = kzalloc(WCD9XXX_MBHC_CAL_SIZE(
+ WCD9XXX_MBHC_DEF_BUTTONS,
+ WCD9XXX_MBHC_DEF_RLOADS),
+ GFP_KERNEL);
+ if (!msm8x10_wcd_cal) {
+ pr_err("%s: out of memory\n", __func__);
+ return NULL;
+ }
+
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_GENERAL_PTR(msm8x10_wcd_cal)->X) = (Y))
+ S(t_ldoh, 100);
+ S(t_bg_fast_settle, 100);
+ S(t_shutdown_plug_rem, 255);
+ S(mbhc_nsa, 2);
+ S(mbhc_navg, 128);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_PLUG_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+ S(mic_current, MSM8X10_WCD_PID_MIC_5_UA);
+ S(hph_current, MSM8X10_WCD_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(msm8x10_wcd_cal)->X) = (Y))
+ S(v_no_mic, 30);
+ S(v_hs_max, 1650);
+#undef S
+#define S(X, Y) ((WCD9XXX_MBHC_CAL_BTN_DET_PTR(msm8x10_wcd_cal)->X) = (Y))
+ S(c[0], 62);
+ S(c[1], 124);
+ S(nc, 1);
+ S(n_meas, 5);
+ S(mbhc_nsc, 10);
+ 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(msm8x10_wcd_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] = 10;
+ btn_low[1] = 11;
+ btn_high[1] = 52;
+ btn_low[2] = 53;
+ btn_high[2] = 94;
+ btn_low[3] = 95;
+ btn_high[3] = 133;
+ btn_low[4] = 134;
+ btn_high[4] = 171;
+ btn_low[5] = 172;
+ btn_high[5] = 208;
+ btn_low[6] = 209;
+ btn_high[6] = 244;
+ btn_low[7] = 245;
+ btn_high[7] = 330;
+ 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] = 14;
+
+ return msm8x10_wcd_cal;
+}
+
static int msm_proxy_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -896,6 +1006,9 @@
goto err1;
}
atomic_set(&mclk_rsc_ref, 0);
+ mbhc_cfg.gpio_level_insert = of_property_read_bool(pdev->dev.of_node,
+ "qcom,headset-jack-type-NC");
+
spdev = pdev;
ret = snd_soc_register_card(card);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 36a4ba4..de98feb 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2024,6 +2024,10 @@
{
unsigned int ret;
+ if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+ dev_err(codec->dev, "read 0x%02x while offline\n", reg);
+ return -ENODEV;
+ }
ret = codec->read(codec, reg);
dev_dbg(codec->dev, "read %x => %x\n", reg, ret);
trace_snd_soc_reg_read(codec, reg, ret);
@@ -2035,6 +2039,10 @@
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
+ if (unlikely(!snd_card_is_online_state(codec->card->snd_card))) {
+ dev_err(codec->dev, "write 0x%02x while offline\n", reg);
+ return -ENODEV;
+ }
dev_dbg(codec->dev, "write %x = %x\n", reg, val);
trace_snd_soc_reg_write(codec, reg, val);
return codec->write(codec, reg, val);
@@ -3541,6 +3549,17 @@
}
/**
+ * snd_soc_card_change_online_state - Mark if soc card is online/offline
+ *
+ * @soc_card : soc_card to mark
+ */
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, int online)
+{
+ snd_card_change_online_state(soc_card->snd_card, online);
+}
+EXPORT_SYMBOL(snd_soc_card_change_online_state);
+
+/**
* snd_soc_register_codec - Register a codec with the ASoC core
*
* @codec: codec to register